Re: [PATCH 01/27] quota: Convert dqio_mutex to rwsem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Aug 16, 2017, at 9:41 AM, Jan Kara <jack@xxxxxxx> wrote:
> 
> Convert dqio_mutex to rwsem and call it dqio_sem. No functional changes
> yet.
> 
> Signed-off-by: Jan Kara <jack@xxxxxxx>
> ---
> fs/ext4/super.c         |  4 ++--
> fs/ocfs2/quota_global.c | 20 ++++++++++----------
> fs/ocfs2/quota_local.c  | 10 +++++-----
> fs/quota/dquot.c        | 28 ++++++++++++++--------------
> fs/quota/quota_tree.c   |  2 +-
> fs/super.c              |  2 +-
> include/linux/quota.h   |  2 +-
> 7 files changed, 34 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index d61a70e2193a..8e0c27387ab7 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -5268,8 +5268,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
>   * Process 1                         Process 2
>   * ext4_create()                     quota_sync()
>   *   jbd2_journal_start()                  write_dquot()
> - *   dquot_initialize()                         down(dqio_mutex)
> - *     down(dqio_mutex)                    jbd2_journal_start()
> + *   dquot_initialize()                         down(dqio_sem)
> + *     down(dqio_sem)                           jbd2_journal_start()

Not a big deal, since this is a comment, but it should probably be changed
to down_write(dqio_sem) on both lines, as this deadlock wouldn't happen if
it was down_read(dqio_sem), and it is more consistent with the new usage.

That said, this comment doesn't appear to be relevant anymore.  At least I
couldn't find where in those callpaths dqio_mutex/dqio_sem is used anymore.

Cheers, Andreas

>   *
>   */
> 
> diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
> index cec495a921e3..4134d557a8e5 100644
> --- a/fs/ocfs2/quota_global.c
> +++ b/fs/ocfs2/quota_global.c
> @@ -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);
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index 32c5a40c1257..1311eff1c050 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -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;
> }
> 
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 53a17496c5c5..29d447598642 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -120,7 +120,7 @@
>  * 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);
> diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
> index 0738972e8d3f..54f85eb2609c 100644
> --- a/fs/quota/quota_tree.c
> +++ b/fs/quota/quota_tree.c
> @@ -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) {
> diff --git a/fs/super.c b/fs/super.c
> index 6bc3352adcf3..221cfa1f4e92 100644
> --- a/fs/super.c
> +++ b/fs/super.c
> @@ -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;
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index bfd077ca6ac3..3a6df7461642 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -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 */
> --
> 2.12.3
> 


Cheers, Andreas





Attachment: signature.asc
Description: Message signed with OpenPGP


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux