quota: Remove dq_wait_unused from dquot
authorJan Kara <jack@suse.cz>
Wed, 2 Aug 2017 15:18:50 +0000 (17:18 +0200)
committerJan Kara <jack@suse.cz>
Thu, 17 Aug 2017 20:00:40 +0000 (22:00 +0200)
Currently every dquot carries a wait_queue_head_t used only when we are
turning quotas off to wait for last users to drop dquot references.
Since such rare case is not performance sensitive in any means, just use
a global waitqueue for this and save space in struct dquot. Also convert
the logic to use wait_event() instead of open-coding it.

Signed-off-by: Jan Kara <jack@suse.cz>
fs/quota/dquot.c
include/linux/quota.h

index 93adcdd6a260a3fe23d8e222280685145dd3740b..361a2a6f13e102b67b7aca3cc099ad0c7aa28a4c 100644 (file)
@@ -126,6 +126,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock);
 EXPORT_SYMBOL(dq_data_lock);
 DEFINE_STATIC_SRCU(dquot_srcu);
 
 EXPORT_SYMBOL(dq_data_lock);
 DEFINE_STATIC_SRCU(dquot_srcu);
 
+static DECLARE_WAIT_QUEUE_HEAD(dquot_ref_wq);
+
 void __quota_error(struct super_block *sb, const char *func,
                   const char *fmt, ...)
 {
 void __quota_error(struct super_block *sb, const char *func,
                   const char *fmt, ...)
 {
@@ -527,22 +529,18 @@ restart:
                        continue;
                /* Wait for dquot users */
                if (atomic_read(&dquot->dq_count)) {
                        continue;
                /* Wait for dquot users */
                if (atomic_read(&dquot->dq_count)) {
-                       DEFINE_WAIT(wait);
-
                        dqgrab(dquot);
                        dqgrab(dquot);
-                       prepare_to_wait(&dquot->dq_wait_unused, &wait,
-                                       TASK_UNINTERRUPTIBLE);
                        spin_unlock(&dq_list_lock);
                        spin_unlock(&dq_list_lock);
-                       /* Once dqput() wakes us up, we know it's time to free
+                       /*
+                        * Once dqput() wakes us up, we know it's time to free
                         * the dquot.
                         * IMPORTANT: we rely on the fact that there is always
                         * at most one process waiting for dquot to free.
                         * Otherwise dq_count would be > 1 and we would never
                         * wake up.
                         */
                         * the dquot.
                         * IMPORTANT: we rely on the fact that there is always
                         * at most one process waiting for dquot to free.
                         * Otherwise dq_count would be > 1 and we would never
                         * wake up.
                         */
-                       if (atomic_read(&dquot->dq_count) > 1)
-                               schedule();
-                       finish_wait(&dquot->dq_wait_unused, &wait);
+                       wait_event(dquot_ref_wq,
+                                  atomic_read(&dquot->dq_count) == 1);
                        dqput(dquot);
                        /* At this moment dquot() need not exist (it could be
                         * reclaimed by prune_dqcache(). Hence we must
                        dqput(dquot);
                        /* At this moment dquot() need not exist (it could be
                         * reclaimed by prune_dqcache(). Hence we must
@@ -754,7 +752,7 @@ we_slept:
                /* Releasing dquot during quotaoff phase? */
                if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) &&
                    atomic_read(&dquot->dq_count) == 1)
                /* Releasing dquot during quotaoff phase? */
                if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_id.type) &&
                    atomic_read(&dquot->dq_count) == 1)
-                       wake_up(&dquot->dq_wait_unused);
+                       wake_up(&dquot_ref_wq);
                spin_unlock(&dq_list_lock);
                return;
        }
                spin_unlock(&dq_list_lock);
                return;
        }
@@ -809,7 +807,6 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
        INIT_LIST_HEAD(&dquot->dq_inuse);
        INIT_HLIST_NODE(&dquot->dq_hash);
        INIT_LIST_HEAD(&dquot->dq_dirty);
        INIT_LIST_HEAD(&dquot->dq_inuse);
        INIT_HLIST_NODE(&dquot->dq_hash);
        INIT_LIST_HEAD(&dquot->dq_dirty);
-       init_waitqueue_head(&dquot->dq_wait_unused);
        dquot->dq_sb = sb;
        dquot->dq_id = make_kqid_invalid(type);
        atomic_set(&dquot->dq_count, 1);
        dquot->dq_sb = sb;
        dquot->dq_id = make_kqid_invalid(type);
        atomic_set(&dquot->dq_count, 1);
index 3a6df7461642c7a8e7b566ded9bf9f161bab0569..ad6809f099ac6eff72fa80cd4ed74d353cf96d76 100644 (file)
@@ -299,7 +299,6 @@ struct dquot {
        struct list_head dq_dirty;      /* List of dirty dquots */
        struct mutex dq_lock;           /* dquot IO lock */
        atomic_t dq_count;              /* Use count */
        struct list_head dq_dirty;      /* List of dirty dquots */
        struct mutex dq_lock;           /* dquot IO lock */
        atomic_t dq_count;              /* Use count */
-       wait_queue_head_t dq_wait_unused;       /* Wait queue for dquot to become unused */
        struct super_block *dq_sb;      /* superblock this applies to */
        struct kqid dq_id;              /* ID this applies to (uid, gid, projid) */
        loff_t dq_off;                  /* Offset of dquot on disk */
        struct super_block *dq_sb;      /* superblock this applies to */
        struct kqid dq_id;              /* ID this applies to (uid, gid, projid) */
        loff_t dq_off;                  /* Offset of dquot on disk */