Commit bc8230ee authored by Jan Kara's avatar Jan Kara

quota: Convert dqio_mutex to rwsem

Convert dqio_mutex to rwsem and call it dqio_sem. No functional changes
yet.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent aae4e7a8
...@@ -5263,18 +5263,13 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -5263,18 +5263,13 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0; 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 #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) static inline struct inode *dquot_to_inode(struct dquot *dquot)
{ {
return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type]; return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type];
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
* Locking of quotas with OCFS2 is rather complex. Here are rules that * Locking of quotas with OCFS2 is rather complex. Here are rules that
* should be obeyed by all the functions: * should be obeyed by all the functions:
* - any write of quota structure (either to local or global file) is protected * - 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, * - any modification of global quota file holds inode cluster lock, i_mutex,
* and ip_alloc_sem of the global quota file (achieved by * and ip_alloc_sem of the global quota file (achieved by
* ocfs2_lock_global_qf). It also has to hold qinfo_lock. * ocfs2_lock_global_qf). It also has to hold qinfo_lock.
...@@ -42,9 +42,9 @@ ...@@ -42,9 +42,9 @@
* *
* A rough sketch of locking dependencies (lf = local file, gf = global file): * A rough sketch of locking dependencies (lf = local file, gf = global file):
* Normal filesystem operation: * Normal filesystem operation:
* start_trans -> dqio_mutex -> write to lf * start_trans -> dqio_sem -> write to lf
* Syncing of local and global file: * 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 gf
* -> write to lf * -> write to lf
* Acquire dquot for the first time: * Acquire dquot for the first time:
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
* Recovery: * Recovery:
* inode cluster lock of recovered lf * inode cluster lock of recovered lf
* -> read bitmaps -> ip_alloc_sem of 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 * write to gf
*/ */
...@@ -611,7 +611,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type) ...@@ -611,7 +611,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
mlog_errno(status); mlog_errno(status);
goto out_ilock; goto out_ilock;
} }
mutex_lock(&sb_dqopt(sb)->dqio_mutex); down_write(&sb_dqopt(sb)->dqio_sem);
status = ocfs2_sync_dquot(dquot); status = ocfs2_sync_dquot(dquot);
if (status < 0) if (status < 0)
mlog_errno(status); mlog_errno(status);
...@@ -619,7 +619,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type) ...@@ -619,7 +619,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
status = ocfs2_local_write_dquot(dquot); status = ocfs2_local_write_dquot(dquot);
if (status < 0) if (status < 0)
mlog_errno(status); mlog_errno(status);
mutex_unlock(&sb_dqopt(sb)->dqio_mutex); up_write(&sb_dqopt(sb)->dqio_sem);
ocfs2_commit_trans(osb, handle); ocfs2_commit_trans(osb, handle);
out_ilock: out_ilock:
ocfs2_unlock_global_qf(oinfo, 1); ocfs2_unlock_global_qf(oinfo, 1);
...@@ -666,9 +666,9 @@ static int ocfs2_write_dquot(struct dquot *dquot) ...@@ -666,9 +666,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
mlog_errno(status); mlog_errno(status);
goto out; 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); 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); ocfs2_commit_trans(osb, handle);
out: out:
return status; return status;
...@@ -939,7 +939,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot) ...@@ -939,7 +939,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
mlog_errno(status); mlog_errno(status);
goto out_ilock; goto out_ilock;
} }
mutex_lock(&sb_dqopt(sb)->dqio_mutex); down_write(&sb_dqopt(sb)->dqio_sem);
status = ocfs2_sync_dquot(dquot); status = ocfs2_sync_dquot(dquot);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
...@@ -948,7 +948,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot) ...@@ -948,7 +948,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
/* Now write updated local dquot structure */ /* Now write updated local dquot structure */
status = ocfs2_local_write_dquot(dquot); status = ocfs2_local_write_dquot(dquot);
out_dlock: out_dlock:
mutex_unlock(&sb_dqopt(sb)->dqio_mutex); up_write(&sb_dqopt(sb)->dqio_sem);
ocfs2_commit_trans(osb, handle); ocfs2_commit_trans(osb, handle);
out_ilock: out_ilock:
ocfs2_unlock_global_qf(oinfo, 1); ocfs2_unlock_global_qf(oinfo, 1);
......
...@@ -520,7 +520,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, ...@@ -520,7 +520,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
mlog_errno(status); mlog_errno(status);
goto out_drop_lock; goto out_drop_lock;
} }
mutex_lock(&sb_dqopt(sb)->dqio_mutex); down_write(&sb_dqopt(sb)->dqio_sem);
spin_lock(&dq_data_lock); spin_lock(&dq_data_lock);
/* Add usage from quota entry into quota changes /* Add usage from quota entry into quota changes
* of our node. Auxiliary variables are important * of our node. Auxiliary variables are important
...@@ -553,7 +553,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, ...@@ -553,7 +553,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
unlock_buffer(qbh); unlock_buffer(qbh);
ocfs2_journal_dirty(handle, qbh); ocfs2_journal_dirty(handle, qbh);
out_commit: out_commit:
mutex_unlock(&sb_dqopt(sb)->dqio_mutex); up_write(&sb_dqopt(sb)->dqio_sem);
ocfs2_commit_trans(OCFS2_SB(sb), handle); ocfs2_commit_trans(OCFS2_SB(sb), handle);
out_drop_lock: out_drop_lock:
ocfs2_unlock_global_qf(oinfo, 1); ocfs2_unlock_global_qf(oinfo, 1);
...@@ -693,7 +693,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) ...@@ -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 /* We don't need the lock and we have to acquire quota file locks
* which will later depend on this lock */ * 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_spc_limit = 0x7fffffffffffffffLL;
info->dqi_max_ino_limit = 0x7fffffffffffffffLL; info->dqi_max_ino_limit = 0x7fffffffffffffffLL;
oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); 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) ...@@ -772,7 +772,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
goto out_err; goto out_err;
} }
mutex_lock(&sb_dqopt(sb)->dqio_mutex); down_write(&sb_dqopt(sb)->dqio_sem);
return 0; return 0;
out_err: out_err:
if (oinfo) { if (oinfo) {
...@@ -786,7 +786,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) ...@@ -786,7 +786,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
kfree(oinfo); kfree(oinfo);
} }
brelse(bh); brelse(bh);
mutex_lock(&sb_dqopt(sb)->dqio_mutex); down_write(&sb_dqopt(sb)->dqio_sem);
return -1; return -1;
} }
......
...@@ -120,7 +120,7 @@ ...@@ -120,7 +120,7 @@
* spinlock to internal buffers before writing. * spinlock to internal buffers before writing.
* *
* Lock ordering (including related VFS locks) is the following: * 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); static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock);
...@@ -406,7 +406,7 @@ int dquot_acquire(struct dquot *dquot) ...@@ -406,7 +406,7 @@ int dquot_acquire(struct dquot *dquot)
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
mutex_lock(&dquot->dq_lock); mutex_lock(&dquot->dq_lock);
mutex_lock(&dqopt->dqio_mutex); down_write(&dqopt->dqio_sem);
if (!test_bit(DQ_READ_B, &dquot->dq_flags)) if (!test_bit(DQ_READ_B, &dquot->dq_flags))
ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot); ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
if (ret < 0) if (ret < 0)
...@@ -436,7 +436,7 @@ int dquot_acquire(struct dquot *dquot) ...@@ -436,7 +436,7 @@ int dquot_acquire(struct dquot *dquot)
smp_mb__before_atomic(); smp_mb__before_atomic();
set_bit(DQ_ACTIVE_B, &dquot->dq_flags); set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
out_iolock: out_iolock:
mutex_unlock(&dqopt->dqio_mutex); up_write(&dqopt->dqio_sem);
mutex_unlock(&dquot->dq_lock); mutex_unlock(&dquot->dq_lock);
return ret; return ret;
} }
...@@ -450,7 +450,7 @@ int dquot_commit(struct dquot *dquot) ...@@ -450,7 +450,7 @@ int dquot_commit(struct dquot *dquot)
int ret = 0; int ret = 0;
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
mutex_lock(&dqopt->dqio_mutex); down_write(&dqopt->dqio_sem);
spin_lock(&dq_list_lock); spin_lock(&dq_list_lock);
if (!clear_dquot_dirty(dquot)) { if (!clear_dquot_dirty(dquot)) {
spin_unlock(&dq_list_lock); spin_unlock(&dq_list_lock);
...@@ -464,7 +464,7 @@ int dquot_commit(struct dquot *dquot) ...@@ -464,7 +464,7 @@ int dquot_commit(struct dquot *dquot)
else else
ret = -EIO; ret = -EIO;
out_sem: out_sem:
mutex_unlock(&dqopt->dqio_mutex); up_write(&dqopt->dqio_sem);
return ret; return ret;
} }
EXPORT_SYMBOL(dquot_commit); EXPORT_SYMBOL(dquot_commit);
...@@ -481,7 +481,7 @@ int dquot_release(struct dquot *dquot) ...@@ -481,7 +481,7 @@ int dquot_release(struct dquot *dquot)
/* Check whether we are not racing with some other dqget() */ /* Check whether we are not racing with some other dqget() */
if (atomic_read(&dquot->dq_count) > 1) if (atomic_read(&dquot->dq_count) > 1)
goto out_dqlock; goto out_dqlock;
mutex_lock(&dqopt->dqio_mutex); down_write(&dqopt->dqio_sem);
if (dqopt->ops[dquot->dq_id.type]->release_dqblk) { if (dqopt->ops[dquot->dq_id.type]->release_dqblk) {
ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot); ret = dqopt->ops[dquot->dq_id.type]->release_dqblk(dquot);
/* Write the info */ /* Write the info */
...@@ -493,7 +493,7 @@ int dquot_release(struct dquot *dquot) ...@@ -493,7 +493,7 @@ int dquot_release(struct dquot *dquot)
ret = ret2; ret = ret2;
} }
clear_bit(DQ_ACTIVE_B, &dquot->dq_flags); clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
mutex_unlock(&dqopt->dqio_mutex); up_write(&dqopt->dqio_sem);
out_dqlock: out_dqlock:
mutex_unlock(&dquot->dq_lock); mutex_unlock(&dquot->dq_lock);
return ret; return ret;
...@@ -2060,9 +2060,9 @@ int dquot_commit_info(struct super_block *sb, int type) ...@@ -2060,9 +2060,9 @@ int dquot_commit_info(struct super_block *sb, int type)
int ret; int ret;
struct quota_info *dqopt = sb_dqopt(sb); 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); ret = dqopt->ops[type]->write_file_info(sb, type);
mutex_unlock(&dqopt->dqio_mutex); up_write(&dqopt->dqio_sem);
return ret; return ret;
} }
EXPORT_SYMBOL(dquot_commit_info); EXPORT_SYMBOL(dquot_commit_info);
...@@ -2076,9 +2076,9 @@ int dquot_get_next_id(struct super_block *sb, struct kqid *qid) ...@@ -2076,9 +2076,9 @@ int dquot_get_next_id(struct super_block *sb, struct kqid *qid)
return -ESRCH; return -ESRCH;
if (!dqopt->ops[qid->type]->get_next_id) if (!dqopt->ops[qid->type]->get_next_id)
return -ENOSYS; return -ENOSYS;
mutex_lock(&dqopt->dqio_mutex); down_write(&dqopt->dqio_sem);
err = dqopt->ops[qid->type]->get_next_id(sb, qid); err = dqopt->ops[qid->type]->get_next_id(sb, qid);
mutex_unlock(&dqopt->dqio_mutex); up_write(&dqopt->dqio_sem);
return err; return err;
} }
EXPORT_SYMBOL(dquot_get_next_id); EXPORT_SYMBOL(dquot_get_next_id);
...@@ -2328,15 +2328,15 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_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_format = fmt;
dqopt->info[type].dqi_fmt_id = format_id; dqopt->info[type].dqi_fmt_id = format_id;
INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); 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); error = dqopt->ops[type]->read_file_info(sb, type);
if (error < 0) { if (error < 0) {
mutex_unlock(&dqopt->dqio_mutex); up_write(&dqopt->dqio_sem);
goto out_file_init; goto out_file_init;
} }
if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) if (dqopt->flags & DQUOT_QUOTA_SYS_FILE)
dqopt->info[type].dqi_flags |= DQF_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); spin_lock(&dq_state_lock);
dqopt->flags |= dquot_state_flag(flags, type); dqopt->flags |= dquot_state_flag(flags, type);
spin_unlock(&dq_state_lock); spin_unlock(&dq_state_lock);
......
...@@ -379,7 +379,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) ...@@ -379,7 +379,7 @@ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
if (!ddquot) if (!ddquot)
return -ENOMEM; return -ENOMEM;
/* dq_off is guarded by dqio_mutex */ /* dq_off is guarded by dqio_sem */
if (!dquot->dq_off) { if (!dquot->dq_off) {
ret = dq_insert_tree(info, dquot); ret = dq_insert_tree(info, dquot);
if (ret < 0) { if (ret < 0) {
......
...@@ -242,7 +242,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, ...@@ -242,7 +242,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
atomic_set(&s->s_active, 1); atomic_set(&s->s_active, 1);
mutex_init(&s->s_vfs_rename_mutex); mutex_init(&s->s_vfs_rename_mutex);
lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key); 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_maxbytes = MAX_NON_LFS;
s->s_op = &default_op; s->s_op = &default_op;
s->s_time_gran = 1000000000; s->s_time_gran = 1000000000;
......
...@@ -521,7 +521,7 @@ static inline void quota_send_warning(struct kqid qid, dev_t dev, ...@@ -521,7 +521,7 @@ static inline void quota_send_warning(struct kqid qid, dev_t dev,
struct quota_info { struct quota_info {
unsigned int flags; /* Flags for diskquotas on this device */ 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 inode *files[MAXQUOTAS]; /* inodes of quotafiles */
struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */
const struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ const struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment