xfs: remove the per-filesystem list of dquots
authorChristoph Hellwig <hch@lst.de>
Wed, 14 Mar 2012 16:53:34 +0000 (11:53 -0500)
committerBen Myers <bpm@sgi.com>
Wed, 14 Mar 2012 16:53:34 +0000 (11:53 -0500)
Instead of keeping a separate per-filesystem list of dquots we can walk
the radix tree for the two places where we need to iterate all quota
structures.

Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm.h
fs/xfs/xfs_qm_syscalls.c

index 49456e555cfa920353a4472f9c36f8015ad4f58b..2896ac953ed6b26458783d519f1d841c5c28ede1 100644 (file)
  *
  * ip->i_lock
  *   qi->qi_tree_lock
- *     qi->qi_dqlist_lock
- *       dquot->q_qlock (xfs_dqlock() and friends)
- *         dquot->q_flush (xfs_dqflock() and friends)
- *         qi->qi_lru_lock
+ *     dquot->q_qlock (xfs_dqlock() and friends)
+ *       dquot->q_flush (xfs_dqflock() and friends)
+ *       qi->qi_lru_lock
  *
  * If two dquots need to be locked the order is user before group/project,
  * otherwise by the lowest id first, see xfs_dqlock2.
@@ -728,21 +727,13 @@ restart:
                goto restart;
        }
 
-       /*
-        * Attach this dquot to this filesystem's list of all dquots,
-        * kept inside the mount structure in m_quotainfo field
-        */
-       mutex_lock(&qi->qi_dqlist_lock);
-
        /*
         * We return a locked dquot to the caller, with a reference taken
         */
        xfs_dqlock(dqp);
        dqp->q_nrefs = 1;
 
-       list_add(&dqp->q_mplist, &qi->qi_dqlist);
        qi->qi_dquots++;
-       mutex_unlock(&qi->qi_dqlist_lock);
        mutex_unlock(&qi->qi_tree_lock);
 
  dqret:
@@ -1017,86 +1008,6 @@ xfs_dqlock2(
        }
 }
 
-/*
- * Take a dquot out of the mount's dqlist as well as the hashlist.  This is
- * called via unmount as well as quotaoff, and the purge will always succeed.
- */
-void
-xfs_qm_dqpurge(
-       struct xfs_dquot        *dqp)
-{
-       struct xfs_mount        *mp = dqp->q_mount;
-       struct xfs_quotainfo    *qi = mp->m_quotainfo;
-
-       xfs_dqlock(dqp);
-
-       /*
-        * If we're turning off quotas, we have to make sure that, for
-        * example, we don't delete quota disk blocks while dquots are
-        * in the process of getting written to those disk blocks.
-        * This dquot might well be on AIL, and we can't leave it there
-        * if we're turning off quotas. Basically, we need this flush
-        * lock, and are willing to block on it.
-        */
-       if (!xfs_dqflock_nowait(dqp)) {
-               /*
-                * Block on the flush lock after nudging dquot buffer,
-                * if it is incore.
-                */
-               xfs_dqflock_pushbuf_wait(dqp);
-       }
-
-       /*
-        * If we are turning this type of quotas off, we don't care
-        * about the dirty metadata sitting in this dquot. OTOH, if
-        * we're unmounting, we do care, so we flush it and wait.
-        */
-       if (XFS_DQ_IS_DIRTY(dqp)) {
-               int     error;
-
-               /*
-                * We don't care about getting disk errors here. We need
-                * to purge this dquot anyway, so we go ahead regardless.
-                */
-               error = xfs_qm_dqflush(dqp, SYNC_WAIT);
-               if (error)
-                       xfs_warn(mp, "%s: dquot %p flush failed",
-                               __func__, dqp);
-               xfs_dqflock(dqp);
-       }
-
-       ASSERT(atomic_read(&dqp->q_pincount) == 0);
-       ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
-              !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
-
-       xfs_dqfunlock(dqp);
-       xfs_dqunlock(dqp);
-
-       mutex_lock(&qi->qi_tree_lock);
-       radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
-                         be32_to_cpu(dqp->q_core.d_id));
-       mutex_unlock(&qi->qi_tree_lock);
-
-       mutex_lock(&qi->qi_dqlist_lock);
-       list_del_init(&dqp->q_mplist);
-       qi->qi_dqreclaims++;
-       qi->qi_dquots--;
-       mutex_unlock(&qi->qi_dqlist_lock);
-
-       /*
-        * We move dquots to the freelist as soon as their reference count
-        * hits zero, so it really should be on the freelist here.
-        */
-       mutex_lock(&qi->qi_lru_lock);
-       ASSERT(!list_empty(&dqp->q_lru));
-       list_del_init(&dqp->q_lru);
-       qi->qi_lru_count--;
-       XFS_STATS_DEC(xs_qm_dquot_unused);
-       mutex_unlock(&qi->qi_lru_lock);
-
-       xfs_qm_dqdestroy(dqp);
-}
-
 /*
  * Give the buffer a little push if it is incore and
  * wait on the flush lock.
index 4061f1731271584af5d80ca82d77319c15bbf2b6..ef9190bd8b300a061244d1d294a90acf39610b08 100644 (file)
@@ -38,7 +38,6 @@ struct xfs_trans;
 typedef struct xfs_dquot {
        uint             dq_flags;      /* various flags (XFS_DQ_*) */
        struct list_head q_lru;         /* global free list of dquots */
-       struct list_head q_mplist;      /* mount's list of dquots */
        struct xfs_mount*q_mount;       /* filesystem this relates to */
        struct xfs_trans*q_transp;      /* trans this belongs to currently */
        uint             q_nrefs;       /* # active refs from inodes */
@@ -143,7 +142,6 @@ extern int          xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
                                        uint, struct xfs_dquot  **);
 extern void            xfs_qm_dqdestroy(xfs_dquot_t *);
 extern int             xfs_qm_dqflush(xfs_dquot_t *, uint);
-extern void            xfs_qm_dqpurge(xfs_dquot_t *);
 extern void            xfs_qm_dqunpin_wait(xfs_dquot_t *);
 extern void            xfs_qm_adjust_dqtimers(xfs_mount_t *,
                                        xfs_disk_dquot_t *);
index bb884e701cd9ba407a09cebaa27cd453380f84aa..2f92d3b0d8a83d24085f12540124cd3aac9fdf50 100644 (file)
@@ -168,6 +168,187 @@ xfs_qm_rele_quotafs_ref(
        mutex_unlock(&xfs_Gqm_lock);
 }
 
+/*
+ * We use the batch lookup interface to iterate over the dquots as it
+ * currently is the only interface into the radix tree code that allows
+ * fuzzy lookups instead of exact matches.  Holding the lock over multiple
+ * operations is fine as all callers are used either during mount/umount
+ * or quotaoff.
+ */
+#define XFS_DQ_LOOKUP_BATCH    32
+
+STATIC int
+xfs_qm_dquot_walk(
+       struct xfs_mount        *mp,
+       int                     type,
+       int                     (*execute)(struct xfs_dquot *dqp))
+{
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       struct radix_tree_root  *tree = XFS_DQUOT_TREE(qi, type);
+       uint32_t                next_index;
+       int                     last_error = 0;
+       int                     skipped;
+       int                     nr_found;
+
+restart:
+       skipped = 0;
+       next_index = 0;
+       nr_found = 0;
+
+       while (1) {
+               struct xfs_dquot *batch[XFS_DQ_LOOKUP_BATCH];
+               int             error = 0;
+               int             i;
+
+               mutex_lock(&qi->qi_tree_lock);
+               nr_found = radix_tree_gang_lookup(tree, (void **)batch,
+                                       next_index, XFS_DQ_LOOKUP_BATCH);
+               if (!nr_found) {
+                       mutex_unlock(&qi->qi_tree_lock);
+                       break;
+               }
+
+               for (i = 0; i < nr_found; i++) {
+                       struct xfs_dquot *dqp = batch[i];
+
+                       next_index = be32_to_cpu(dqp->q_core.d_id) + 1;
+
+                       error = execute(batch[i]);
+                       if (error == EAGAIN) {
+                               skipped++;
+                               continue;
+                       }
+                       if (error && last_error != EFSCORRUPTED)
+                               last_error = error;
+               }
+
+               mutex_unlock(&qi->qi_tree_lock);
+
+               /* bail out if the filesystem is corrupted.  */
+               if (last_error == EFSCORRUPTED) {
+                       skipped = 0;
+                       break;
+               }
+       }
+
+       if (skipped) {
+               delay(1);
+               goto restart;
+       }
+
+       return last_error;
+}
+
+
+/*
+ * Purge a dquot from all tracking data structures and free it.
+ */
+STATIC int
+xfs_qm_dqpurge(
+       struct xfs_dquot        *dqp)
+{
+       struct xfs_mount        *mp = dqp->q_mount;
+       struct xfs_quotainfo    *qi = mp->m_quotainfo;
+       struct xfs_dquot        *gdqp = NULL;
+
+       xfs_dqlock(dqp);
+       if ((dqp->dq_flags & XFS_DQ_FREEING) || dqp->q_nrefs != 0) {
+               xfs_dqunlock(dqp);
+               return EAGAIN;
+       }
+
+       /*
+        * If this quota has a group hint attached, prepare for releasing it
+        * now.
+        */
+       gdqp = dqp->q_gdquot;
+       if (gdqp) {
+               xfs_dqlock(gdqp);
+               dqp->q_gdquot = NULL;
+       }
+
+       dqp->dq_flags |= XFS_DQ_FREEING;
+
+       /*
+        * If we're turning off quotas, we have to make sure that, for
+        * example, we don't delete quota disk blocks while dquots are
+        * in the process of getting written to those disk blocks.
+        * This dquot might well be on AIL, and we can't leave it there
+        * if we're turning off quotas. Basically, we need this flush
+        * lock, and are willing to block on it.
+        */
+       if (!xfs_dqflock_nowait(dqp)) {
+               /*
+                * Block on the flush lock after nudging dquot buffer,
+                * if it is incore.
+                */
+               xfs_dqflock_pushbuf_wait(dqp);
+       }
+
+       /*
+        * If we are turning this type of quotas off, we don't care
+        * about the dirty metadata sitting in this dquot. OTOH, if
+        * we're unmounting, we do care, so we flush it and wait.
+        */
+       if (XFS_DQ_IS_DIRTY(dqp)) {
+               int     error;
+
+               /*
+                * We don't care about getting disk errors here. We need
+                * to purge this dquot anyway, so we go ahead regardless.
+                */
+               error = xfs_qm_dqflush(dqp, SYNC_WAIT);
+               if (error)
+                       xfs_warn(mp, "%s: dquot %p flush failed",
+                               __func__, dqp);
+               xfs_dqflock(dqp);
+       }
+
+       ASSERT(atomic_read(&dqp->q_pincount) == 0);
+       ASSERT(XFS_FORCED_SHUTDOWN(mp) ||
+              !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL));
+
+       xfs_dqfunlock(dqp);
+       xfs_dqunlock(dqp);
+
+       radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
+                         be32_to_cpu(dqp->q_core.d_id));
+       qi->qi_dquots--;
+
+       /*
+        * We move dquots to the freelist as soon as their reference count
+        * hits zero, so it really should be on the freelist here.
+        */
+       mutex_lock(&qi->qi_lru_lock);
+       ASSERT(!list_empty(&dqp->q_lru));
+       list_del_init(&dqp->q_lru);
+       qi->qi_lru_count--;
+       XFS_STATS_DEC(xs_qm_dquot_unused);
+       mutex_unlock(&qi->qi_lru_lock);
+
+       xfs_qm_dqdestroy(dqp);
+
+       if (gdqp)
+               xfs_qm_dqput(gdqp);
+       return 0;
+}
+
+/*
+ * Purge the dquot cache.
+ */
+void
+xfs_qm_dqpurge_all(
+       struct xfs_mount        *mp,
+       uint                    flags)
+{
+       if (flags & XFS_QMOPT_UQUOTA)
+               xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge);
+       if (flags & XFS_QMOPT_GQUOTA)
+               xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge);
+       if (flags & XFS_QMOPT_PQUOTA)
+               xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_dqpurge);
+}
+
 /*
  * Just destroy the quotainfo structure.
  */
@@ -306,175 +487,6 @@ xfs_qm_unmount_quotas(
        }
 }
 
-/*
- * Flush all dquots of the given file system to disk. The dquots are
- * _not_ purged from memory here, just their data written to disk.
- */
-STATIC int
-xfs_qm_dqflush_all(
-       struct xfs_mount        *mp)
-{
-       struct xfs_quotainfo    *q = mp->m_quotainfo;
-       int                     recl;
-       struct xfs_dquot        *dqp;
-       int                     error;
-
-       if (!q)
-               return 0;
-again:
-       mutex_lock(&q->qi_dqlist_lock);
-       list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
-               xfs_dqlock(dqp);
-               if ((dqp->dq_flags & XFS_DQ_FREEING) ||
-                   !XFS_DQ_IS_DIRTY(dqp)) {
-                       xfs_dqunlock(dqp);
-                       continue;
-               }
-
-               /* XXX a sentinel would be better */
-               recl = q->qi_dqreclaims;
-               if (!xfs_dqflock_nowait(dqp)) {
-                       /*
-                        * If we can't grab the flush lock then check
-                        * to see if the dquot has been flushed delayed
-                        * write.  If so, grab its buffer and send it
-                        * out immediately.  We'll be able to acquire
-                        * the flush lock when the I/O completes.
-                        */
-                       xfs_dqflock_pushbuf_wait(dqp);
-               }
-               /*
-                * Let go of the mplist lock. We don't want to hold it
-                * across a disk write.
-                */
-               mutex_unlock(&q->qi_dqlist_lock);
-               error = xfs_qm_dqflush(dqp, 0);
-               xfs_dqunlock(dqp);
-               if (error)
-                       return error;
-
-               mutex_lock(&q->qi_dqlist_lock);
-               if (recl != q->qi_dqreclaims) {
-                       mutex_unlock(&q->qi_dqlist_lock);
-                       /* XXX restart limit */
-                       goto again;
-               }
-       }
-
-       mutex_unlock(&q->qi_dqlist_lock);
-       /* return ! busy */
-       return 0;
-}
-
-/*
- * Release the group dquot pointers the user dquots may be
- * carrying around as a hint. mplist is locked on entry and exit.
- */
-STATIC void
-xfs_qm_detach_gdquots(
-       struct xfs_mount        *mp)
-{
-       struct xfs_quotainfo    *q = mp->m_quotainfo;
-       struct xfs_dquot        *dqp, *gdqp;
-
- again:
-       ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
-       list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
-               xfs_dqlock(dqp);
-               if (dqp->dq_flags & XFS_DQ_FREEING) {
-                       xfs_dqunlock(dqp);
-                       mutex_unlock(&q->qi_dqlist_lock);
-                       delay(1);
-                       mutex_lock(&q->qi_dqlist_lock);
-                       goto again;
-               }
-
-               gdqp = dqp->q_gdquot;
-               if (gdqp)
-                       dqp->q_gdquot = NULL;
-               xfs_dqunlock(dqp);
-
-               if (gdqp)
-                       xfs_qm_dqrele(gdqp);
-       }
-}
-
-/*
- * Go through all the incore dquots of this file system and take them
- * off the mplist and hashlist, if the dquot type matches the dqtype
- * parameter. This is used when turning off quota accounting for
- * users and/or groups, as well as when the filesystem is unmounting.
- */
-STATIC int
-xfs_qm_dqpurge_int(
-       struct xfs_mount        *mp,
-       uint                    flags)
-{
-       struct xfs_quotainfo    *q = mp->m_quotainfo;
-       struct xfs_dquot        *dqp, *n;
-       uint                    dqtype;
-       int                     nmisses = 0;
-       LIST_HEAD               (dispose_list);
-
-       if (!q)
-               return 0;
-
-       dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
-       dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0;
-       dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
-
-       mutex_lock(&q->qi_dqlist_lock);
-
-       /*
-        * In the first pass through all incore dquots of this filesystem,
-        * we release the group dquot pointers the user dquots may be
-        * carrying around as a hint. We need to do this irrespective of
-        * what's being turned off.
-        */
-       xfs_qm_detach_gdquots(mp);
-
-       /*
-        * Try to get rid of all of the unwanted dquots.
-        */
-       list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
-               xfs_dqlock(dqp);
-               if ((dqp->dq_flags & dqtype) != 0 &&
-                   !(dqp->dq_flags & XFS_DQ_FREEING)) {
-                       if (dqp->q_nrefs == 0) {
-                               dqp->dq_flags |= XFS_DQ_FREEING;
-                               list_move_tail(&dqp->q_mplist, &dispose_list);
-                       } else
-                               nmisses++;
-               }
-               xfs_dqunlock(dqp);
-       }
-       mutex_unlock(&q->qi_dqlist_lock);
-
-       list_for_each_entry_safe(dqp, n, &dispose_list, q_mplist)
-               xfs_qm_dqpurge(dqp);
-
-       return nmisses;
-}
-
-int
-xfs_qm_dqpurge_all(
-       xfs_mount_t     *mp,
-       uint            flags)
-{
-       int             ndquots;
-
-       /*
-        * Purge the dquot cache.
-        * None of the dquots should really be busy at this point.
-        */
-       if (mp->m_quotainfo) {
-               while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
-                       delay(ndquots * 10);
-               }
-       }
-       return 0;
-}
-
 STATIC int
 xfs_qm_dqattach_one(
        xfs_inode_t     *ip,
@@ -749,15 +761,10 @@ xfs_qm_init_quotainfo(
        INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS);
        mutex_init(&qinf->qi_tree_lock);
 
-       INIT_LIST_HEAD(&qinf->qi_dqlist);
-       mutex_init(&qinf->qi_dqlist_lock);
-
        INIT_LIST_HEAD(&qinf->qi_lru_list);
        qinf->qi_lru_count = 0;
        mutex_init(&qinf->qi_lru_lock);
 
-       qinf->qi_dqreclaims = 0;
-
        /* mutex used to serialize quotaoffs */
        mutex_init(&qinf->qi_quotaofflock);
 
@@ -854,9 +861,6 @@ xfs_qm_destroy_quotainfo(
         */
        xfs_qm_rele_quotafs_ref(mp);
 
-       ASSERT(list_empty(&qi->qi_dqlist));
-       mutex_destroy(&qi->qi_dqlist_lock);
-
        if (qi->qi_uquotaip) {
                IRELE(qi->qi_uquotaip);
                qi->qi_uquotaip = NULL; /* paranoia */
@@ -1307,6 +1311,28 @@ error0:
        return error;
 }
 
+STATIC int
+xfs_qm_flush_one(
+       struct xfs_dquot        *dqp)
+{
+       int                     error = 0;
+
+       xfs_dqlock(dqp);
+       if (dqp->dq_flags & XFS_DQ_FREEING)
+               goto out_unlock;
+       if (!XFS_DQ_IS_DIRTY(dqp))
+               goto out_unlock;
+
+       if (!xfs_dqflock_nowait(dqp))
+               xfs_dqflock_pushbuf_wait(dqp);
+
+       error = xfs_qm_dqflush(dqp, 0);
+
+out_unlock:
+       xfs_dqunlock(dqp);
+       return error;
+}
+
 /*
  * Walk thru all the filesystem inodes and construct a consistent view
  * of the disk quota world. If the quotacheck fails, disable quotas.
@@ -1315,7 +1341,7 @@ int
 xfs_qm_quotacheck(
        xfs_mount_t     *mp)
 {
-       int             done, count, error;
+       int             done, count, error, error2;
        xfs_ino_t       lastino;
        size_t          structsz;
        xfs_inode_t     *uip, *gip;
@@ -1329,12 +1355,6 @@ xfs_qm_quotacheck(
        ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip);
        ASSERT(XFS_IS_QUOTA_RUNNING(mp));
 
-       /*
-        * There should be no cached dquots. The (simplistic) quotacheck
-        * algorithm doesn't like that.
-        */
-       ASSERT(list_empty(&mp->m_quotainfo->qi_dqlist));
-
        xfs_notice(mp, "Quotacheck needed: Please wait.");
 
        /*
@@ -1373,12 +1393,21 @@ xfs_qm_quotacheck(
        } while (!done);
 
        /*
-        * We've made all the changes that we need to make incore.
-        * Flush them down to disk buffers if everything was updated
-        * successfully.
+        * We've made all the changes that we need to make incore.  Flush them
+        * down to disk buffers if everything was updated successfully.
         */
-       if (!error)
-               error = xfs_qm_dqflush_all(mp);
+       if (XFS_IS_UQUOTA_ON(mp))
+               error = xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_flush_one);
+       if (XFS_IS_GQUOTA_ON(mp)) {
+               error2 = xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_flush_one);
+               if (!error)
+                       error = error2;
+       }
+       if (XFS_IS_PQUOTA_ON(mp)) {
+               error2 = xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_flush_one);
+               if (!error)
+                       error = error2;
+       }
 
        /*
         * We can get this error if we couldn't do a dquot allocation inside
@@ -1517,13 +1546,9 @@ xfs_qm_dqfree_one(
        mutex_lock(&qi->qi_tree_lock);
        radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags),
                          be32_to_cpu(dqp->q_core.d_id));
-       mutex_unlock(&qi->qi_tree_lock);
 
-       mutex_lock(&qi->qi_dqlist_lock);
-       list_del_init(&dqp->q_mplist);
        qi->qi_dquots--;
-       qi->qi_dqreclaims++;
-       mutex_unlock(&qi->qi_dqlist_lock);
+       mutex_unlock(&qi->qi_tree_lock);
 
        xfs_qm_dqdestroy(dqp);
 }
@@ -1556,8 +1581,6 @@ xfs_qm_dqreclaim_one(
                return;
        }
 
-       ASSERT(!list_empty(&dqp->q_mplist));
-
        /*
         * Try to grab the flush lock. If this dquot is in the process of
         * getting flushed to disk, we don't want to reclaim it.
index 8f4b117823ccfe7602095fc02bd98ed402cf8e5f..76447060cd471d44e33c4d94ebe9d3f318d999d2 100644 (file)
@@ -63,11 +63,7 @@ typedef struct xfs_quotainfo {
        struct list_head qi_lru_list;
        struct mutex     qi_lru_lock;
        int              qi_lru_count;
-       struct list_head qi_dqlist;      /* all dquots in filesys */
-       struct mutex     qi_dqlist_lock;
        int              qi_dquots;
-       int              qi_dqreclaims;  /* a change here indicates
-                                           a removal in the dqlist */
        time_t           qi_btimelimit;  /* limit for blks timer */
        time_t           qi_itimelimit;  /* limit for inodes timer */
        time_t           qi_rtbtimelimit;/* limit for rt blks timer */
@@ -126,7 +122,7 @@ extern int          xfs_qm_quotacheck(xfs_mount_t *);
 extern int             xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t);
 
 /* dquot stuff */
-extern int             xfs_qm_dqpurge_all(xfs_mount_t *, uint);
+extern void            xfs_qm_dqpurge_all(xfs_mount_t *, uint);
 extern void            xfs_qm_dqrele_all_inodes(xfs_mount_t *, uint);
 
 /* quota ops */
index b9ac268a2d7c6881532834703de78bfc15c92971..c4f396e437a87656599d21a25186f426556fbcae 100644 (file)
@@ -66,7 +66,6 @@ xfs_qm_scall_quotaoff(
        int                     error;
        uint                    inactivate_flags;
        xfs_qoff_logitem_t      *qoffstart;
-       int                     nculprits;
 
        /*
         * No file system can have quotas enabled on disk but not in core.
@@ -172,18 +171,13 @@ xfs_qm_scall_quotaoff(
         * This isn't protected by a particular lock directly, because we
         * don't want to take a mrlock every time we depend on quotas being on.
         */
-       mp->m_qflags &= ~(flags);
+       mp->m_qflags &= ~flags;
 
        /*
         * Go through all the dquots of this file system and purge them,
-        * according to what was turned off. We may not be able to get rid
-        * of all dquots, because dquots can have temporary references that
-        * are not attached to inodes. eg. xfs_setattr, xfs_create.
-        * So, if we couldn't purge all the dquots from the filesystem,
-        * we can't get rid of the incore data structures.
+        * according to what was turned off.
         */
-       while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype)))
-               delay(10 * nculprits);
+       xfs_qm_dqpurge_all(mp, dqtype);
 
        /*
         * Transactions that had started before ACTIVE state bit was cleared