On Sun, 2010-09-05 at 21:44 -0400, Christoph Hellwig wrote: > There is no need to have the users and group/project quota locked at the > same time. Get rid of xfs_qm_dqget_noattach and just do a xfs_qm_dqget > inside xfs_qm_quotacheck_dqadjust for the quota we are operating on > right now. The new version of xfs_qm_quotacheck_dqadjust holds the > inode lock over it's operations, which is not a problem as it simply > increments counters and there is no concern about log contention > during mount time. This looks good. Reviewed-by: Alex Elder <aelder@xxxxxxx> > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > > Index: xfs/fs/xfs/quota/xfs_qm.c > =================================================================== > --- xfs.orig/fs/xfs/quota/xfs_qm.c 2010-09-05 17:23:15.392004632 -0300 > +++ xfs/fs/xfs/quota/xfs_qm.c 2010-09-05 22:33:14.374005609 -0300 > @@ -1199,87 +1199,6 @@ xfs_qm_list_destroy( > mutex_destroy(&(list->qh_lock)); > } > > - > -/* > - * Stripped down version of dqattach. This doesn't attach, or even look at the > - * dquots attached to the inode. The rationale is that there won't be any > - * attached at the time this is called from quotacheck. > - */ > -STATIC int > -xfs_qm_dqget_noattach( > - xfs_inode_t *ip, > - xfs_dquot_t **O_udqpp, > - xfs_dquot_t **O_gdqpp) > -{ > - int error; > - xfs_mount_t *mp; > - xfs_dquot_t *udqp, *gdqp; > - > - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); > - mp = ip->i_mount; > - udqp = NULL; > - gdqp = NULL; > - > - if (XFS_IS_UQUOTA_ON(mp)) { > - ASSERT(ip->i_udquot == NULL); > - /* > - * We want the dquot allocated if it doesn't exist. > - */ > - if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER, > - XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, > - &udqp))) { > - /* > - * Shouldn't be able to turn off quotas here. > - */ > - ASSERT(error != ESRCH); > - ASSERT(error != ENOENT); > - return error; > - } > - ASSERT(udqp); > - } > - > - if (XFS_IS_OQUOTA_ON(mp)) { > - ASSERT(ip->i_gdquot == NULL); > - if (udqp) > - xfs_dqunlock(udqp); > - error = XFS_IS_GQUOTA_ON(mp) ? > - xfs_qm_dqget(mp, ip, > - ip->i_d.di_gid, XFS_DQ_GROUP, > - XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, > - &gdqp) : > - xfs_qm_dqget(mp, ip, > - ip->i_d.di_projid, XFS_DQ_PROJ, > - XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, > - &gdqp); > - if (error) { > - if (udqp) > - xfs_qm_dqrele(udqp); > - ASSERT(error != ESRCH); > - ASSERT(error != ENOENT); > - return error; > - } > - ASSERT(gdqp); > - > - /* Reacquire the locks in the right order */ > - if (udqp) { > - if (! xfs_qm_dqlock_nowait(udqp)) { > - xfs_dqunlock(gdqp); > - xfs_dqlock(udqp); > - xfs_dqlock(gdqp); > - } > - } > - } > - > - *O_udqpp = udqp; > - *O_gdqpp = gdqp; > - > -#ifdef QUOTADEBUG > - if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp)); > - if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp)); > -#endif > - return 0; > -} > - > /* > * Create an inode and return with a reference already taken, but unlocked > * This is how we create quota inodes > @@ -1546,18 +1465,34 @@ xfs_qm_dqiterate( > > /* > * Called by dqusage_adjust in doing a quotacheck. > - * Given the inode, and a dquot (either USR or GRP, doesn't matter), > - * this updates its incore copy as well as the buffer copy. This is > - * so that once the quotacheck is done, we can just log all the buffers, > - * as opposed to logging numerous updates to individual dquots. > + * > + * Given the inode, and a dquot id this updates both the incore dqout as well > + * as the buffer copy. This is so that once the quotacheck is done, we can > + * just log all the buffers, as opposed to logging numerous updates to > + * individual dquots. > */ > -STATIC void > +STATIC int > xfs_qm_quotacheck_dqadjust( > - xfs_dquot_t *dqp, > + struct xfs_inode *ip, > + xfs_dqid_t id, > + uint type, > xfs_qcnt_t nblks, > xfs_qcnt_t rtblks) > { > - ASSERT(XFS_DQ_IS_LOCKED(dqp)); > + struct xfs_mount *mp = ip->i_mount; > + struct xfs_dquot *dqp; > + int error; > + > + error = xfs_qm_dqget(mp, ip, id, type, > + XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp); > + if (error) { > + /* > + * Shouldn't be able to turn off quotas here. > + */ > + ASSERT(error != ESRCH); > + ASSERT(error != ENOENT); > + return error; > + } > > trace_xfs_dqadjust(dqp); > > @@ -1582,11 +1517,13 @@ xfs_qm_quotacheck_dqadjust( > * There are no timers for the default values set in the root dquot. > */ > if (dqp->q_core.d_id) { > - xfs_qm_adjust_dqlimits(dqp->q_mount, &dqp->q_core); > - xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); > + xfs_qm_adjust_dqlimits(mp, &dqp->q_core); > + xfs_qm_adjust_dqtimers(mp, &dqp->q_core); > } > > dqp->dq_flags |= XFS_DQ_DIRTY; > + xfs_qm_dqput(dqp); > + return 0; > } > > STATIC int > @@ -1629,8 +1566,7 @@ xfs_qm_dqusage_adjust( > int *res) /* result code value */ > { > xfs_inode_t *ip; > - xfs_dquot_t *udqp, *gdqp; > - xfs_qcnt_t nblks, rtblks; > + xfs_qcnt_t nblks, rtblks = 0; > int error; > > ASSERT(XFS_IS_QUOTA_RUNNING(mp)); > @@ -1650,51 +1586,24 @@ xfs_qm_dqusage_adjust( > * the case in all other instances. It's OK that we do this because > * quotacheck is done only at mount time. > */ > - if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) { > + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip); > + if (error) { > *res = BULKSTAT_RV_NOTHING; > return error; > } > > - /* > - * Obtain the locked dquots. In case of an error (eg. allocation > - * fails for ENOSPC), we return the negative of the error number > - * to bulkstat, so that it can get propagated to quotacheck() and > - * making us disable quotas for the file system. > - */ > - if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) { > - xfs_iunlock(ip, XFS_ILOCK_EXCL); > - IRELE(ip); > - *res = BULKSTAT_RV_GIVEUP; > - return error; > - } > + ASSERT(ip->i_delayed_blks == 0); > > - rtblks = 0; > - if (! XFS_IS_REALTIME_INODE(ip)) { > - nblks = (xfs_qcnt_t)ip->i_d.di_nblocks; > - } else { > + if (XFS_IS_REALTIME_INODE(ip)) { > /* > * Walk thru the extent list and count the realtime blocks. > */ > - if ((error = xfs_qm_get_rtblks(ip, &rtblks))) { > - xfs_iunlock(ip, XFS_ILOCK_EXCL); > - IRELE(ip); > - if (udqp) > - xfs_qm_dqput(udqp); > - if (gdqp) > - xfs_qm_dqput(gdqp); > - *res = BULKSTAT_RV_GIVEUP; > - return error; > - } > - nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks; > + error = xfs_qm_get_rtblks(ip, &rtblks); > + if (error) > + goto error0; > } > - ASSERT(ip->i_delayed_blks == 0); > > - /* > - * We can't release the inode while holding its dquot locks. > - * The inode can go into inactive and might try to acquire the dquotlocks. > - * So, just unlock here and do a vn_rele at the end. > - */ > - xfs_iunlock(ip, XFS_ILOCK_EXCL); > + nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks; > > /* > * Add the (disk blocks and inode) resources occupied by this > @@ -1709,26 +1618,36 @@ xfs_qm_dqusage_adjust( > * and quotaoffs don't race. (Quotachecks happen at mount time only). > */ > if (XFS_IS_UQUOTA_ON(mp)) { > - ASSERT(udqp); > - xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); > - xfs_qm_dqput(udqp); > - } > - if (XFS_IS_OQUOTA_ON(mp)) { > - ASSERT(gdqp); > - xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); > - xfs_qm_dqput(gdqp); > + error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_uid, > + XFS_DQ_USER, nblks, rtblks); > + if (error) > + goto error0; > } > - /* > - * Now release the inode. This will send it to 'inactive', and > - * possibly even free blocks. > - */ > - IRELE(ip); > > - /* > - * Goto next inode. > - */ > + if (XFS_IS_GQUOTA_ON(mp)) { > + error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_gid, > + XFS_DQ_GROUP, nblks, rtblks); > + if (error) > + goto error0; > + } > + > + if (XFS_IS_PQUOTA_ON(mp)) { > + error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_projid, > + XFS_DQ_PROJ, nblks, rtblks); > + if (error) > + goto error0; > + } > + > + xfs_iunlock(ip, XFS_ILOCK_EXCL); > + IRELE(ip); > *res = BULKSTAT_RV_DIDONE; > return 0; > + > +error0: > + xfs_iunlock(ip, XFS_ILOCK_EXCL); > + IRELE(ip); > + *res = BULKSTAT_RV_GIVEUP; > + return error; > } > > /* > > _______________________________________________ > xfs mailing list > xfs@xxxxxxxxxxx > http://oss.sgi.com/mailman/listinfo/xfs kk _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs