📄 gfs_kernquota.c
字号:
* Allocate a dquot structure. If there are * no free slots in the cache, flush LRU entry from * the cache to the appropriate quota file on disk. */struct dquot *dqalloc(uid, dev) int uid; dev_t dev;{ register struct dquot *dq; register struct dqhead *dh; register struct dquot *dp; register struct quota *q; register struct mount *mp; static struct dqblk zdqb = { 0 }; struct gnode *rgp; struct gnode *trgp;#ifdef SMP_DEBUG if (smp_owner(&lk_quota) || smp_owner(&lk_dquot)) panic("dqalloc: cannot hold table locks");#endif /* * Locate inode of quotas file for * indicated file system, return * if file doesn't exist. */ GETMP(mp, dev); rgp = (struct gnode *)fref(mp, dev); if (mp->m_qinod == NULL) { if (rgp) grele(rgp); u.u_error = EINVAL; return (NODQUOT); } /* * Check the cache first. */search: smp_lock(&lk_quota, LK_RETRY); smp_lock(&lk_dquot, LK_RETRY); dh = &dqhead[DQHASH(uid, dev)]; for (dq = (DQptr)dh->dqh_forw; dq != (DQptr)dh; dq = dq->dq_forw) { if (!dquot_test_lock(dq)) { smp_unlock(&lk_dquot); smp_unlock(&lk_quota); sleep_unlock((caddr_t)dq, PINOD+1, &lk_dquotlocks); goto search; } if (dq->dq_uid != uid || dq->dq_dev != dev) { dquot_unlock(dq); continue; } /* * Cache hit with no references. Take * the structure off the free list. */ if (dq->dq_cnt++ == 0) { dp = dq->dq_freef; if (dp != NODQUOT) dp->dq_freeb = dq->dq_freeb; else dqback = dq->dq_freeb; *dq->dq_freeb = dp; dq->dq_own = NOQUOTA; } smp_unlock(&lk_quota); smp_unlock(&lk_dquot); dq->dq_flags |= DQ_HASH; if (rgp) grele(rgp); return (dq); } /* * Check free list. If table is full, pull entries * off the quota free list and flush any associated * dquot references until something frees up on the * dquot free list. */ if ((dq = dqfreel) == NODQUOT && (q = qfreelist) != NOQUOTA) { do { register struct dquot **dqq; register struct mount *mountp = mount; dqq = q->q_dq; quota_lock(q); while (dqq < &q->q_dq[NMOUNT]) { trgp = (struct gnode *)fref(mountp, NULL); if (!dquot_test_lock((*dqq))) { smp_unlock(&lk_dquotlocks); mountp++; dqq++; if (trgp) grele(trgp); continue; } if ((dq = *dqq) != NODQUOT && dq != LOSTDQUOT) { /* * Mark entry as "lost" due to * scavenging operation. */ if (dq->dq_cnt == 1) { *dqq = LOSTDQUOT; smp_unlock(&lk_quota); smp_unlock(&lk_dquot); putdq(mountp, dq, 1); dquot_unlock(dq); quota_unlock(q); if (trgp) grele(trgp); goto search; } } mountp++; dquot_unlock((*dqq)); dqq++; if (trgp) grele(trgp); } quota_unlock(q); q = q->q_freef; } while ((dq = dqfreel) == NODQUOT && q != NOQUOTA); } smp_unlock(&lk_quota); if (dq == NODQUOT) { tablefull("dquot"); u.u_error = EUSERS; smp_unlock(&lk_dquot); if (rgp) grele(rgp); return (dq); } /* * This shouldn't happen, as we sync * dquot before freeing it up. */ if (dq->dq_flags & DQ_MOD) panic("discquota"); /* * Now take the dquot off the free list, */ dp = dq->dq_freef; if (dp != NODQUOT) dp->dq_freeb = &dqfreel; dqfreel = dp; /* * and off the hash chain it was on, & onto the new one. */ dh = &dqhead[DQHASH(uid, dev)]; remque(dq); dquot_lock(dq); dq->dq_cnt = 1; dq->dq_flags = 0; dq->dq_uid = uid; dq->dq_dev = dev; dq->dq_dqb = zdqb; dq->dq_own = NOQUOTA; insque(dq, dh); smp_unlock(&lk_dquot); if (rgp) grele(rgp); return (dq);}/* * dqrele - layman's interface to putdq. */dqrele(dq) register struct dquot *dq;{ register struct mount *mp; register struct gnode *rgp; if (dq == NODQUOT || dq == LOSTDQUOT) return;#ifdef SMP_DEBUG if ((dq->dq_state & DQ_LOCK) == 0) panic("dqrele: Dquot should be locked");#endif if (dq->dq_cnt > 1) { dq->dq_cnt--; return; } /* * I/O required, find appropriate file system * to sync the quota information to. */ GETMP(mp, dq->dq_dev); rgp = (struct gnode *)fref(mp, NULL); putdq(mp, dq, 1); if (rgp) grele(rgp);}/* * Update the disc quota in the quota file. */putdq(mp, dq, free) register struct mount *mp; register struct dquot *dq;{ register struct gnode *gp; if (dq == NODQUOT || dq == LOSTDQUOT) return;#ifdef SMP_DEBUG if ((dq->dq_state & DQ_LOCK) == 0) panic("putdq: dquot must be locked"); if (smp_owner(&lk_quota) || smp_owner(&lk_dquot)) panic("putdq: cannot hold table locks");#endif if (free && dq->dq_cnt > 1) { dq->dq_cnt--; return; } /* * Disk quota not modified, just discard * or return (having adjusted the reference * count), as indicated by the "free" param. */ if ((dq->dq_flags & DQ_MOD) == 0) { if (free) { dq->dq_cnt = 0; release: smp_lock(&lk_dquot, LK_RETRY); if (dqfreel != NODQUOT) { *dqback = dq; dq->dq_freeb = dqback; } else { dqfreel = dq; dq->dq_freeb = &dqfreel; } dq->dq_freef = NODQUOT; dqback = &dq->dq_freef; smp_unlock(&lk_dquot); } return; } /* * Quota modified, write back to disk. */ if ((gp = mp->m_qinod) == NULL) panic("lost quota file"); gfs_lock(gp); (void) rdwri(UIO_WRITE, gp, (caddr_t)&dq->dq_dqb, sizeof (struct dqblk), dq->dq_uid * sizeof (struct dqblk), 1, (int *)0); gfs_unlock(gp); dq->dq_flags &= ~DQ_MOD; if (free && --dq->dq_cnt == 0) goto release;}/* * See if there is a quota struct in core for user 'uid'. */struct quota *qfind(uid) register int uid;{ register struct quota *q; register struct qhash *qh;#ifdef SMP_DEBUG if (smp_owner(&lk_quota)) panic("qfind: Cannot hold quota table lock");#endif /* * Check common cases first: asking for own quota, * or that of the super user (has reserved slot 0 * in the table). */ q = u.u_quota; if (q != NOQUOTA && q->q_uid == uid) { quota_lock(q); return (q); } if (uid == 0) { /* the second most likely case */ quota_lock(quota); return (quota); } /* * Search cache. */top: smp_lock(&lk_quota, LK_RETRY); qh = &qhash[QHASH(uid)]; for (q = (Qptr)qh->qh_forw; q != (Qptr)qh; q = q->q_forw) { if (!quota_test_lock(q)) { smp_unlock(&lk_quota); sleep_unlock((caddr_t)q, PINOD+1, &lk_quotalocks); goto top; } if (q->q_uid == uid) { smp_unlock(&lk_quota); return (q); } quota_unlock(q); } smp_unlock(&lk_quota); return (NOQUOTA);}/* * Set the quota file up for a particular file system. * Called as the result of a setquota system call. */opendq(mp, fname) register struct mount *mp; caddr_t fname;{ register struct gnode *gp; register struct quota *q; register struct nameidata *ndp = &u.u_nd; register struct dquot *dq; register int i = mp - mount;again: smp_lock(&lk_gnode, LK_RETRY); if (qactive[i].atv_cnt) { sleep_unlock((caddr_t)qactive[i].atv_cnt, PINOD+1, &lk_gnode); goto again; } if (qactive[i].atv_flag & QMP_UNSAFE) { sleep_unlock((caddr_t)qactive[i].atv_flag, PINOD+1, &lk_gnode); goto again; } qactive[i].atv_flag |= QMP_UNSAFE; smp_unlock(&lk_gnode); if (mp->m_qinod) closedq(mp, 1); ndp->ni_nameiop = LOOKUP | FOLLOW; ndp->ni_dirp = fname; gp = gfs_namei(ndp); if (gp == NULL) goto out; gfs_unlock(gp); if (gp->g_dev != mp->m_dev) { u.u_error = EACCES; goto out; } if ((gp->g_mode & GFMT) != GFREG) { u.u_error = EACCES; goto out; } /* * Flush in-core references to any previous * quota file for this file system. */ mp->m_qinod = gp; i = mp - mount; for (q = quota; q < quotaNQUOTA; q++) { quota_lock(q); if ((q->q_flags & Q_NDQ) == 0) { if (q->q_cnt == 0) q->q_dq[i] = LOSTDQUOT; else { q->q_cnt++; /* cannot be released */ dq = discquota(q->q_uid, gp); q->q_dq[i] = dq; if (dq != NODQUOT) { dq->dq_own = q; dquot_unlock(dq); } delquota(q); } } quota_unlock(q); }out: smp_lock(&lk_gnode, LK_RETRY); qactive[i].atv_flag = qactive[i].atv_cnt = 0; smp_unlock(&lk_gnode); wakeup(qactive[i].atv_flag); wakeup(qactive[i].atv_cnt);}/* * Close off disc quotas for a file system. */closedq(mp, bypass) register struct mount *mp; int bypass;{ register struct dquot *dq; register int i = mp - mount; register struct quota *q; register struct gnode *gp; if (mp->m_qinod == NULL) return;try: if (bypass == 0) { smp_lock(&lk_gnode, LK_RETRY); if (qactive[i].atv_cnt) { sleep_unlock((caddr_t)qactive[i].atv_cnt, PINOD+1, &lk_gnode); goto try; } if (qactive[i].atv_flag & QMP_UNSAFE) { sleep_unlock((caddr_t)qactive[i].atv_flag, PINOD+1, &lk_gnode); goto try; } qactive[i].atv_flag |= QMP_UNSAFE; smp_unlock(&lk_gnode); } /* * Search inode table, delete any references * to quota file being closed. */ top: smp_lock(&lk_gnode, LK_RETRY); for (gp = gnode; gp < gnodeNGNODE; gp++) { if (gp->g_dev == mp->m_dev) { if (gp->g_dquot == NODQUOT) continue; dq = gp->g_dquot; gp->g_dquot = NODQUOT; smp_unlock(&lk_gnode); dquot_lock(dq); putdq(mp, dq, 1); dquot_unlock(dq); goto top; } } smp_unlock(&lk_gnode); /* * Search quota table, flush any pending * quota info to disk and also delete * references to closing quota file. */again: smp_lock(&lk_quota, LK_RETRY); for (q = quota; q < quotaNQUOTA; q++) { if (!quota_test_lock(q)) { smp_unlock(&lk_quota); sleep_unlock((caddr_t)q, PINOD+1, &lk_quotalocks); goto again; } if (q->q_dq[i] == NODQUOT) { quota_unlock(q); continue; } if ((q->q_flags & Q_NDQ) == 0) { if (q->q_cnt) { q->q_cnt++; smp_unlock(&lk_quota); dquot_lock(q->q_dq[i]); putdq(mp, q->q_dq[i], 1); dquot_unlock(q->q_dq[i]); delquota(q); } else { smp_unlock(&lk_quota); dquot_lock(q->q_dq[i]); putdq(mp, q->q_dq[i], 1); dquot_unlock(q->q_dq[i]); } } q->q_dq[i] = NODQUOT; quota_unlock(q); goto again; } smp_unlock(&lk_quota); /* * Move all dquot's that used to refer to this quota * file of into the never-never (they will eventually * fall off the head of the free list and be re-used). */ smp_lock(&lk_dquot, LK_RETRY); for (dq = dquot; dq < dquotNDQUOT; dq++) { if (dq->dq_dev == mp->m_dev) { if (!dquot_test_lock(dq)) panic("closedq: dq should not be locked"); if (dq->dq_cnt) panic("closedq: stray dquot"); remque(dq); dq->dq_forw = dq; dq->dq_back = dq; dq->dq_dev = NODEV; dquot_unlock(dq); } } smp_unlock(&lk_dquot); grele(mp->m_qinod); mp->m_qinod = NULL; if (bypass) /* We were called by opendq */ return; smp_lock(&lk_gnode, LK_RETRY); qactive[i].atv_flag = qactive[i].atv_cnt = 0; smp_unlock(&lk_gnode); wakeup((caddr_t)qactive[i].atv_flag); wakeup((caddr_t)qactive[i].atv_cnt);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -