]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
quota: Convert dqio_mutex to rwsem
authorJan Kara <jack@suse.cz>
Thu, 8 Jun 2017 12:39:48 +0000 (14:39 +0200)
committerJan Kara <jack@suse.cz>
Thu, 17 Aug 2017 16:52:48 +0000 (18:52 +0200)
Convert dqio_mutex to rwsem and call it dqio_sem. No functional changes
yet.

Signed-off-by: Jan Kara <jack@suse.cz>
fs/ext4/super.c
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/quota/dquot.c
fs/quota/quota_tree.c
fs/super.c
include/linux/quota.h

index d61a70e2193a012d48f5c56140a416abb2280b68..4c168b90903c25a6915cd12c96227ec05d4f3e6a 100644 (file)
@@ -5263,18 +5263,13 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-/* Helper function for writing quotas on sync - we need to start transaction
- * before quota file is locked for write. Otherwise the are possible deadlocks:
- * Process 1                         Process 2
- * ext4_create()                     quota_sync()
- *   jbd2_journal_start()                  write_dquot()
- *   dquot_initialize()                         down(dqio_mutex)
- *     down(dqio_mutex)                    jbd2_journal_start()
- *
- */
 
 #ifdef CONFIG_QUOTA
 
+/*
+ * Helper functions so that transaction is started before we acquire dqio_sem
+ * to keep correct lock ordering of transaction > dqio_sem
+ */
 static inline struct inode *dquot_to_inode(struct dquot *dquot)
 {
        return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
index cec495a921e32cbbd4ff5bd5d2944bbf5c93f09b..4134d557a8e5ba6ba3ef349bddad863ec9478d3a 100644 (file)
@@ -33,7 +33,7 @@
  * Locking of quotas with OCFS2 is rather complex. Here are rules that
  * should be obeyed by all the functions:
  * - any write of quota structure (either to local or global file) is protected
- *   by dqio_mutex or dquot->dq_lock.
+ *   by dqio_sem or dquot->dq_lock.
  * - any modification of global quota file holds inode cluster lock, i_mutex,
  *   and ip_alloc_sem of the global quota file (achieved by
  *   ocfs2_lock_global_qf). It also has to hold qinfo_lock.
@@ -42,9 +42,9 @@
  *
  * A rough sketch of locking dependencies (lf = local file, gf = global file):
  * Normal filesystem operation:
- *   start_trans -> dqio_mutex -> write to lf
+ *   start_trans -> dqio_sem -> write to lf
  * Syncing of local and global file:
- *   ocfs2_lock_global_qf -> start_trans -> dqio_mutex -> qinfo_lock ->
+ *   ocfs2_lock_global_qf -> start_trans -> dqio_sem -> qinfo_lock ->
  *     write to gf
  *                                                    -> write to lf
  * Acquire dquot for the first time:
@@ -60,7 +60,7 @@
  * Recovery:
  *   inode cluster lock of recovered lf
  *     -> read bitmaps -> ip_alloc_sem of lf
- *     -> ocfs2_lock_global_qf -> start_trans -> dqio_mutex -> qinfo_lock ->
+ *     -> ocfs2_lock_global_qf -> start_trans -> dqio_sem -> qinfo_lock ->
  *        write to gf
  */
 
@@ -611,7 +611,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
                mlog_errno(status);
                goto out_ilock;
        }
-       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
+       down_write(&sb_dqopt(sb)->dqio_sem);
        status = ocfs2_sync_dquot(dquot);
        if (status < 0)
                mlog_errno(status);
@@ -619,7 +619,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
        status = ocfs2_local_write_dquot(dquot);
        if (status < 0)
                mlog_errno(status);
-       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
+       up_write(&sb_dqopt(sb)->dqio_sem);
        ocfs2_commit_trans(osb, handle);
 out_ilock:
        ocfs2_unlock_global_qf(oinfo, 1);
@@ -666,9 +666,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
                mlog_errno(status);
                goto out;
        }
-       mutex_lock(&sb_dqopt(dquot->dq_sb)->dqio_mutex);
+       down_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
        status = ocfs2_local_write_dquot(dquot);
-       mutex_unlock(&sb_dqopt(dquot->dq_sb)->dqio_mutex);
+       up_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
        ocfs2_commit_trans(osb, handle);
 out:
        return status;
@@ -939,7 +939,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
                mlog_errno(status);
                goto out_ilock;
        }
-       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
+       down_write(&sb_dqopt(sb)->dqio_sem);
        status = ocfs2_sync_dquot(dquot);
        if (status < 0) {
                mlog_errno(status);
@@ -948,7 +948,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
        /* Now write updated local dquot structure */
        status = ocfs2_local_write_dquot(dquot);
 out_dlock:
-       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
+       up_write(&sb_dqopt(sb)->dqio_sem);
        ocfs2_commit_trans(osb, handle);
 out_ilock:
        ocfs2_unlock_global_qf(oinfo, 1);
index 32c5a40c1257ecda129944a1abf4cdac83a2e8a1..1311eff1c0506b539cccde4c9438bd8e56233aef 100644 (file)
@@ -520,7 +520,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                mlog_errno(status);
                                goto out_drop_lock;
                        }
-                       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
+                       down_write(&sb_dqopt(sb)->dqio_sem);
                        spin_lock(&dq_data_lock);
                        /* Add usage from quota entry into quota changes
                         * of our node. Auxiliary variables are important
@@ -553,7 +553,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                        unlock_buffer(qbh);
                        ocfs2_journal_dirty(handle, qbh);
 out_commit:
-                       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
+                       up_write(&sb_dqopt(sb)->dqio_sem);
                        ocfs2_commit_trans(OCFS2_SB(sb), handle);
 out_drop_lock:
                        ocfs2_unlock_global_qf(oinfo, 1);
@@ -693,7 +693,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
 
        /* We don't need the lock and we have to acquire quota file locks
         * which will later depend on this lock */
-       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
+       up_write(&sb_dqopt(sb)->dqio_sem);
        info->dqi_max_spc_limit = 0x7fffffffffffffffLL;
        info->dqi_max_ino_limit = 0x7fffffffffffffffLL;
        oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
@@ -772,7 +772,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
                goto out_err;
        }
 
-       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
+       down_write(&sb_dqopt(sb)->dqio_sem);
        return 0;
 out_err:
        if (oinfo) {
@@ -786,7 +786,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
                kfree(oinfo);
        }
        brelse(bh);
-       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
+       down_write(&sb_dqopt(sb)->dqio_sem);
        return -1;
 }
 
index 53a17496c5c536a9410cba73c16d70c5efdbba88..29d4475986422da1e1de6c5ac44ffb05c91d4432 100644 (file)
  * spinlock to internal buffers before writing.
  *
  * Lock ordering (including related VFS locks) is the following:
- *   s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_mutex
+ *   s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_sem
  */
 
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock);
@@ -406,7 +406,7 @@ int dquot_acquire(struct dquot *dquot)
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
        mutex_lock(&dquot->dq_lock);
-       mutex_lock(&dqopt->dqio_mutex);
+       down_write(&dqopt->dqio_sem);
        if (!test_bit(DQ_READ_B, &dquot->dq_flags))
                ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
        if (ret < 0)
@@ -436,7 +436,7 @@ int dquot_acquire(struct dquot *dquot)
        smp_mb__before_atomic();
        set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
 out_iolock:
-       mutex_unlock(&dqopt->dqio_mutex);
+       up_write(&dqopt->dqio_sem);
        mutex_unlock(&dquot->dq_lock);
        return ret;
 }
@@ -450,7 +450,7 @@ int dquot_commit(struct dquot *dquot)
        int ret = 0;
        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
-       mutex_lock(&dqopt->dqio_mutex);
+       down_write(&dqopt->dqio_sem);
        spin_lock(&dq_list_lock);
        if (!clear_dquot_dirty(dquot)) {
                spin_unlock(&dq_list_lock);
@@ -464,7 +464,7 @@ int dquot_commit(struct dquot *dquot)
        else
                ret = -EIO;
 out_sem:
-       mutex_unlock(&dqopt->dqio_mutex);
+       up_write(&dqopt->dqio_sem);
        return ret;
 }
 EXPORT_SYMBOL(dquot_commit);
@@ -481,7 +481,7 @@ int dquot_release(struct dquot *dquot)
        /* Check whether we are not racing with some other dqget() */
        if (atomic_read(&dquot->dq_count) > 1)
                goto out_dqlock;
-       mutex_lock(&dqopt->dqio_mutex);
+       down_write(&dqopt->dqio_sem);
        if (dqopt->ops[dquot->dq_id.type]->release_dqblk) {
                ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot);
                /* Write the info */
@@ -493,7 +493,7 @@ int dquot_release(struct dquot *dquot)
                        ret = ret2;
        }
        clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
-       mutex_unlock(&dqopt->dqio_mutex);
+       up_write(&dqopt->dqio_sem);
 out_dqlock:
        mutex_unlock(&dquot->dq_lock);
        return ret;
@@ -2060,9 +2060,9 @@ int dquot_commit_info(struct super_block *sb, int type)
        int ret;
        struct quota_info *dqopt = sb_dqopt(sb);
 
-       mutex_lock(&dqopt->dqio_mutex);
+       down_write(&dqopt->dqio_sem);
        ret = dqopt->ops[type]->write_file_info(sb, type);
-       mutex_unlock(&dqopt->dqio_mutex);
+       up_write(&dqopt->dqio_sem);
        return ret;
 }
 EXPORT_SYMBOL(dquot_commit_info);
@@ -2076,9 +2076,9 @@ int dquot_get_next_id(struct super_block *sb, struct kqid *qid)
                return -ESRCH;
        if (!dqopt->ops[qid->type]->get_next_id)
                return -ENOSYS;
-       mutex_lock(&dqopt->dqio_mutex);
+       down_write(&dqopt->dqio_sem);
        err = dqopt->ops[qid->type]->get_next_id(sb, qid);
-       mutex_unlock(&dqopt->dqio_mutex);
+       up_write(&dqopt->dqio_sem);
        return err;
 }
 EXPORT_SYMBOL(dquot_get_next_id);
@@ -2328,15 +2328,15 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        dqopt->info[type].dqi_format = fmt;
        dqopt->info[type].dqi_fmt_id = format_id;
        INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
-       mutex_lock(&dqopt->dqio_mutex);
+       down_write(&dqopt->dqio_sem);
        error = dqopt->ops[type]->read_file_info(sb, type);
        if (error < 0) {
-               mutex_unlock(&dqopt->dqio_mutex);
+               up_write(&dqopt->dqio_sem);
                goto out_file_init;
        }
        if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
                dqopt->info[type].dqi_flags |= DQF_SYS_FILE;
-       mutex_unlock(&dqopt->dqio_mutex);
+       up_write(&dqopt->dqio_sem);
        spin_lock(&dq_state_lock);
        dqopt->flags |= dquot_state_flag(flags, type);
        spin_unlock(&dq_state_lock);
index 0738972e8d3f01c6469ea2f5c0917e89ba26e81a..54f85eb2609c83b3277656363e5c2532c4eba4e9 100644 (file)
@@ -379,7 +379,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
        if (!ddquot)
                return -ENOMEM;
 
-       /* dq_off is guarded by dqio_mutex */
+       /* dq_off is guarded by dqio_sem */
        if (!dquot->dq_off) {
                ret = dq_insert_tree(info, dquot);
                if (ret < 0) {
index 6bc3352adcf39fc5ed6cad77b5df5c9d7db3f9cc..221cfa1f4e92596101c6b2edf3febe6fc7c546b2 100644 (file)
@@ -242,7 +242,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
        atomic_set(&s->s_active, 1);
        mutex_init(&s->s_vfs_rename_mutex);
        lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
-       mutex_init(&s->s_dquot.dqio_mutex);
+       init_rwsem(&s->s_dquot.dqio_sem);
        s->s_maxbytes = MAX_NON_LFS;
        s->s_op = &default_op;
        s->s_time_gran = 1000000000;
index bfd077ca6ac3d642026267fa73ce2432126f8aef..3a6df7461642c7a8e7b566ded9bf9f161bab0569 100644 (file)
@@ -521,7 +521,7 @@ static inline void quota_send_warning(struct kqid qid, dev_t dev,
 
 struct quota_info {
        unsigned int flags;                     /* Flags for diskquotas on this device */
-       struct mutex dqio_mutex;                /* lock device while I/O in progress */
+       struct rw_semaphore dqio_sem;           /* Lock quota file while I/O in progress */
        struct inode *files[MAXQUOTAS];         /* inodes of quotafiles */
        struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
        const struct quota_format_ops *ops[MAXQUOTAS];  /* Operations for each type */