📄 xfs_qm_syscalls.c
字号:
if (uflags & XFS_QUOTA_GDQ_ACCT) flags |= XFS_GQUOTA_ACCT; if (uflags & XFS_QUOTA_UDQ_ENFD) flags |= XFS_UQUOTA_ENFD; if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD)) flags |= XFS_OQUOTA_ENFD; return (flags);}STATIC uintxfs_qm_export_flags( uint flags){ uint uflags; uflags = 0; if (flags & XFS_UQUOTA_ACCT) uflags |= XFS_QUOTA_UDQ_ACCT; if (flags & XFS_PQUOTA_ACCT) uflags |= XFS_QUOTA_PDQ_ACCT; if (flags & XFS_GQUOTA_ACCT) uflags |= XFS_QUOTA_GDQ_ACCT; if (flags & XFS_UQUOTA_ENFD) uflags |= XFS_QUOTA_UDQ_ENFD; if (flags & (XFS_OQUOTA_ENFD)) { uflags |= (flags & XFS_GQUOTA_ACCT) ? XFS_QUOTA_GDQ_ENFD : XFS_QUOTA_PDQ_ENFD; } return (uflags);}/* * Go thru all the inodes in the file system, releasing their dquots. * Note that the mount structure gets modified to indicate that quotas are off * AFTER this, in the case of quotaoff. This also gets called from * xfs_rootumount. */voidxfs_qm_dqrele_all_inodes( struct xfs_mount *mp, uint flags){ xfs_inode_t *ip, *topino; uint ireclaims; vnode_t *vp; boolean_t vnode_refd; ASSERT(mp->m_quotainfo); XFS_MOUNT_ILOCK(mp);again: ip = mp->m_inodes; if (ip == NULL) { XFS_MOUNT_IUNLOCK(mp); return; } do { /* Skip markers inserted by xfs_sync */ if (ip->i_mount == NULL) { ip = ip->i_mnext; continue; } /* Root inode, rbmip and rsumip have associated blocks */ if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) { ASSERT(ip->i_udquot == NULL); ASSERT(ip->i_gdquot == NULL); ip = ip->i_mnext; continue; } vp = XFS_ITOV_NULL(ip); if (!vp) { ASSERT(ip->i_udquot == NULL); ASSERT(ip->i_gdquot == NULL); ip = ip->i_mnext; continue; } vnode_refd = B_FALSE; if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) { ireclaims = mp->m_ireclaims; topino = mp->m_inodes; vp = vn_grab(vp); if (!vp) goto again; XFS_MOUNT_IUNLOCK(mp); /* XXX restart limit ? */ xfs_ilock(ip, XFS_ILOCK_EXCL); vnode_refd = B_TRUE; } else { ireclaims = mp->m_ireclaims; topino = mp->m_inodes; XFS_MOUNT_IUNLOCK(mp); } /* * We don't keep the mountlock across the dqrele() call, * since it can take a while.. */ if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) { xfs_qm_dqrele(ip->i_udquot); ip->i_udquot = NULL; } if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) { xfs_qm_dqrele(ip->i_gdquot); ip->i_gdquot = NULL; } xfs_iunlock(ip, XFS_ILOCK_EXCL); /* * Wait until we've dropped the ilock and mountlock to * do the vn_rele. Or be condemned to an eternity in the * inactive code in hell. */ if (vnode_refd) VN_RELE(vp); XFS_MOUNT_ILOCK(mp); /* * If an inode was inserted or removed, we gotta * start over again. */ if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) { /* XXX use a sentinel */ goto again; } ip = ip->i_mnext; } while (ip != mp->m_inodes); XFS_MOUNT_IUNLOCK(mp);}/*------------------------------------------------------------------------*/#ifdef DEBUG/* * This contains all the test functions for XFS disk quotas. * Currently it does a quota accounting check. ie. it walks through * all inodes in the file system, calculating the dquot accounting fields, * and prints out any inconsistencies. */xfs_dqhash_t *qmtest_udqtab;xfs_dqhash_t *qmtest_gdqtab;int qmtest_hashmask;int qmtest_nfails;mutex_t qcheck_lock;#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \ (__psunsigned_t)(id)) & \ (qmtest_hashmask - 1))#define DQTEST_HASH(mp, id, type) ((type & XFS_DQ_USER) ? \ (qmtest_udqtab + \ DQTEST_HASHVAL(mp, id)) : \ (qmtest_gdqtab + \ DQTEST_HASHVAL(mp, id)))#define DQTEST_LIST_PRINT(l, NXT, title) \{ \ xfs_dqtest_t *dqp; int i = 0;\ cmn_err(CE_DEBUG, "%s (#%d)", title, (int) (l)->qh_nelems); \ for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \ dqp = (xfs_dqtest_t *)dqp->NXT) { \ cmn_err(CE_DEBUG, " %d. \"%d (%s)\" bcnt = %d, icnt = %d", \ ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp), \ dqp->d_bcount, dqp->d_icount); } \}typedef struct dqtest { xfs_dqmarker_t q_lists; xfs_dqhash_t *q_hash; /* the hashchain header */ xfs_mount_t *q_mount; /* filesystem this relates to */ xfs_dqid_t d_id; /* user id or group id */ xfs_qcnt_t d_bcount; /* # disk blocks owned by the user */ xfs_qcnt_t d_icount; /* # inodes owned by the user */} xfs_dqtest_t;STATIC voidxfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp){ xfs_dquot_t *d; if (((d) = (h)->qh_next)) (d)->HL_PREVP = &((dqp)->HL_NEXT); (dqp)->HL_NEXT = d; (dqp)->HL_PREVP = &((h)->qh_next); (h)->qh_next = (xfs_dquot_t *)dqp; (h)->qh_version++; (h)->qh_nelems++;}STATIC voidxfs_qm_dqtest_print( xfs_dqtest_t *d){ cmn_err(CE_DEBUG, "-----------DQTEST DQUOT----------------"); cmn_err(CE_DEBUG, "---- dquot ID = %d", d->d_id); cmn_err(CE_DEBUG, "---- fs = 0x%p", d->q_mount); cmn_err(CE_DEBUG, "---- bcount = %Lu (0x%x)", d->d_bcount, (int)d->d_bcount); cmn_err(CE_DEBUG, "---- icount = %Lu (0x%x)", d->d_icount, (int)d->d_icount); cmn_err(CE_DEBUG, "---------------------------");}STATIC voidxfs_qm_dqtest_failed( xfs_dqtest_t *d, xfs_dquot_t *dqp, char *reason, xfs_qcnt_t a, xfs_qcnt_t b, int error){ qmtest_nfails++; if (error) cmn_err(CE_DEBUG, "quotacheck failed id=%d, err=%d\nreason: %s", d->d_id, error, reason); else cmn_err(CE_DEBUG, "quotacheck failed id=%d (%s) [%d != %d]", d->d_id, reason, (int)a, (int)b); xfs_qm_dqtest_print(d); if (dqp) xfs_qm_dqprint(dqp);}STATIC intxfs_dqtest_cmp2( xfs_dqtest_t *d, xfs_dquot_t *dqp){ int err = 0; if (be64_to_cpu(dqp->q_core.d_icount) != d->d_icount) { xfs_qm_dqtest_failed(d, dqp, "icount mismatch", be64_to_cpu(dqp->q_core.d_icount), d->d_icount, 0); err++; } if (be64_to_cpu(dqp->q_core.d_bcount) != d->d_bcount) { xfs_qm_dqtest_failed(d, dqp, "bcount mismatch", be64_to_cpu(dqp->q_core.d_bcount), d->d_bcount, 0); err++; } if (dqp->q_core.d_blk_softlimit && be64_to_cpu(dqp->q_core.d_bcount) >= be64_to_cpu(dqp->q_core.d_blk_softlimit)) { if (!dqp->q_core.d_btimer && dqp->q_core.d_id) { cmn_err(CE_DEBUG, "%d [%s] [0x%p] BLK TIMER NOT STARTED", d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); err++; } } if (dqp->q_core.d_ino_softlimit && be64_to_cpu(dqp->q_core.d_icount) >= be64_to_cpu(dqp->q_core.d_ino_softlimit)) { if (!dqp->q_core.d_itimer && dqp->q_core.d_id) { cmn_err(CE_DEBUG, "%d [%s] [0x%p] INO TIMER NOT STARTED", d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); err++; } }#ifdef QUOTADEBUG if (!err) { cmn_err(CE_DEBUG, "%d [%s] [0x%p] qchecked", d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); }#endif return (err);}STATIC voidxfs_dqtest_cmp( xfs_dqtest_t *d){ xfs_dquot_t *dqp; int error; /* xfs_qm_dqtest_print(d); */ if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0, &dqp))) { xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error); return; } xfs_dqtest_cmp2(d, dqp); xfs_qm_dqput(dqp);}STATIC intxfs_qm_internalqcheck_dqget( xfs_mount_t *mp, xfs_dqid_t id, uint type, xfs_dqtest_t **O_dq){ xfs_dqtest_t *d; xfs_dqhash_t *h; h = DQTEST_HASH(mp, id, type); for (d = (xfs_dqtest_t *) h->qh_next; d != NULL; d = (xfs_dqtest_t *) d->HL_NEXT) { /* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */ if (d->d_id == id && mp == d->q_mount) { *O_dq = d; return (0); } } d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP); d->dq_flags = type; d->d_id = id; d->q_mount = mp; d->q_hash = h; xfs_qm_hashinsert(h, d); *O_dq = d; return (0);}STATIC voidxfs_qm_internalqcheck_get_dquots( xfs_mount_t *mp, xfs_dqid_t uid, xfs_dqid_t projid, xfs_dqid_t gid, xfs_dqtest_t **ud, xfs_dqtest_t **gd){ if (XFS_IS_UQUOTA_ON(mp)) xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud); if (XFS_IS_GQUOTA_ON(mp)) xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd); else if (XFS_IS_PQUOTA_ON(mp)) xfs_qm_internalqcheck_dqget(mp, projid, XFS_DQ_PROJ, gd);}STATIC voidxfs_qm_internalqcheck_dqadjust( xfs_inode_t *ip, xfs_dqtest_t *d){ d->d_icount++; d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks;}STATIC intxfs_qm_internalqcheck_adjust( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ void __user *buffer, /* not used */ int ubsize, /* not used */ void *private_data, /* not used */ xfs_daddr_t bno, /* starting block of inode cluster */ int *ubused, /* not used */ void *dip, /* not used */ int *res) /* bulkstat result code */{ xfs_inode_t *ip; xfs_dqtest_t *ud, *gd; uint lock_flags; boolean_t ipreleased; int error; ASSERT(XFS_IS_QUOTA_RUNNING(mp)); if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) { *res = BULKSTAT_RV_NOTHING; qdprintk("internalqcheck: ino=%llu, uqino=%llu, gqino=%llu\n", (unsigned long long) ino, (unsigned long long) mp->m_sb.sb_uquotino, (unsigned long long) mp->m_sb.sb_gquotino); return XFS_ERROR(EINVAL); } ipreleased = B_FALSE; again: lock_flags = XFS_ILOCK_SHARED; if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) { *res = BULKSTAT_RV_NOTHING; return (error); } if (ip->i_d.di_mode == 0) { xfs_iput_new(ip, lock_flags); *res = BULKSTAT_RV_NOTHING; return XFS_ERROR(ENOENT); } /* * This inode can have blocks after eof which can get released * when we send it to inactive. Since we don't check the dquot * until the after all our calculations are done, we must get rid * of those now. */ if (! ipreleased) { xfs_iput(ip, lock_flags); ipreleased = B_TRUE; goto again; } xfs_qm_internalqcheck_get_dquots(mp, (xfs_dqid_t) ip->i_d.di_uid, (xfs_dqid_t) ip->i_d.di_projid, (xfs_dqid_t) ip->i_d.di_gid, &ud, &gd); if (XFS_IS_UQUOTA_ON(mp)) { ASSERT(ud); xfs_qm_internalqcheck_dqadjust(ip, ud); } if (XFS_IS_OQUOTA_ON(mp)) { ASSERT(gd); xfs_qm_internalqcheck_dqadjust(ip, gd); } xfs_iput(ip, lock_flags); *res = BULKSTAT_RV_DIDONE; return (0);}/* PRIVATE, debugging */intxfs_qm_internalqcheck( xfs_mount_t *mp){ xfs_ino_t lastino; int done, count; int i; xfs_dqtest_t *d, *e; xfs_dqhash_t *h1; int error; lastino = 0; qmtest_hashmask = 32; count = 5; done = 0; qmtest_nfails = 0; if (! XFS_IS_QUOTA_ON(mp)) return XFS_ERROR(ESRCH); xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); XFS_bflush(mp->m_ddev_targp); xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); XFS_bflush(mp->m_ddev_targp); mutex_lock(&qcheck_lock, PINOD); /* There should be absolutely no quota activity while this is going on. */ qmtest_udqtab = kmem_zalloc(qmtest_hashmask * sizeof(xfs_dqhash_t), KM_SLEEP); qmtest_gdqtab = kmem_zalloc(qmtest_hashmask * sizeof(xfs_dqhash_t), KM_SLEEP); do { /* * Iterate thru all the inodes in the file system, * adjusting the corresponding dquot counters */ if ((error = xfs_bulkstat(mp, &lastino, &count, xfs_qm_internalqcheck_adjust, NULL, 0, NULL, BULKSTAT_FG_IGET, &done))) { break; } } while (! done); if (error) { cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error); } cmn_err(CE_DEBUG, "Checking results against system dquots"); for (i = 0; i < qmtest_hashmask; i++) { h1 = &qmtest_udqtab[i]; for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { xfs_dqtest_cmp(d); e = (xfs_dqtest_t *) d->HL_NEXT; kmem_free(d, sizeof(xfs_dqtest_t)); d = e; } h1 = &qmtest_gdqtab[i]; for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { xfs_dqtest_cmp(d); e = (xfs_dqtest_t *) d->HL_NEXT; kmem_free(d, sizeof(xfs_dqtest_t)); d = e; } } if (qmtest_nfails) { cmn_err(CE_DEBUG, "******** quotacheck failed ********"); cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails); } else { cmn_err(CE_DEBUG, "******** quotacheck successful! ********"); } kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); mutex_unlock(&qcheck_lock); return (qmtest_nfails);}#endif /* DEBUG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -