Commit 741e1289 authored by Jan Kara's avatar Jan Kara

ocfs2: Fix NULL pointer deref when writing local dquot

commit_dqblk() can write quota info to global file. That is actually a bad
thing to do because if we are just modifying local quota file, we are not
prepared (do not hold proper locks, do not have transaction credits) to do
a modification of the global quota file. So do not use commit_dqblk() and
instead call our writing function directly.
Acked-by: default avatarJoel Becker <Joel.Becker@oracle.com>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 832d09cf
...@@ -109,6 +109,7 @@ int ocfs2_read_quota_phys_block(struct inode *inode, u64 p_block, ...@@ -109,6 +109,7 @@ int ocfs2_read_quota_phys_block(struct inode *inode, u64 p_block,
struct buffer_head **bh); struct buffer_head **bh);
int ocfs2_create_local_dquot(struct dquot *dquot); int ocfs2_create_local_dquot(struct dquot *dquot);
int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot); int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot);
int ocfs2_local_write_dquot(struct dquot *dquot);
extern const struct dquot_operations ocfs2_quota_operations; extern const struct dquot_operations ocfs2_quota_operations;
extern struct quota_format_type ocfs2_quota_format; extern struct quota_format_type ocfs2_quota_format;
......
...@@ -612,14 +612,13 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type) ...@@ -612,14 +612,13 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
} }
mutex_lock(&sb_dqopt(sb)->dqio_mutex); mutex_lock(&sb_dqopt(sb)->dqio_mutex);
status = ocfs2_sync_dquot(dquot); status = ocfs2_sync_dquot(dquot);
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
if (status < 0) if (status < 0)
mlog_errno(status); mlog_errno(status);
/* We have to write local structure as well... */ /* We have to write local structure as well... */
dquot_mark_dquot_dirty(dquot); status = ocfs2_local_write_dquot(dquot);
status = dquot_commit(dquot);
if (status < 0) if (status < 0)
mlog_errno(status); mlog_errno(status);
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
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);
...@@ -658,7 +657,9 @@ static int ocfs2_write_dquot(struct dquot *dquot) ...@@ -658,7 +657,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
mlog_errno(status); mlog_errno(status);
goto out; goto out;
} }
status = dquot_commit(dquot); mutex_lock(&sb_dqopt(dquot->dq_sb)->dqio_mutex);
status = ocfs2_local_write_dquot(dquot);
mutex_unlock(&sb_dqopt(dquot->dq_sb)->dqio_mutex);
ocfs2_commit_trans(osb, handle); ocfs2_commit_trans(osb, handle);
out: out:
mlog_exit(status); mlog_exit(status);
...@@ -831,7 +832,6 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot) ...@@ -831,7 +832,6 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
struct ocfs2_super *osb = OCFS2_SB(sb); struct ocfs2_super *osb = OCFS2_SB(sb);
mlog_entry("id=%u, type=%d", dquot->dq_id, type); mlog_entry("id=%u, type=%d", dquot->dq_id, type);
dquot_mark_dquot_dirty(dquot);
/* In case user set some limits, sync dquot immediately to global /* In case user set some limits, sync dquot immediately to global
* quota file so that information propagates quicker */ * quota file so that information propagates quicker */
...@@ -856,14 +856,14 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot) ...@@ -856,14 +856,14 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
} }
mutex_lock(&sb_dqopt(sb)->dqio_mutex); mutex_lock(&sb_dqopt(sb)->dqio_mutex);
status = ocfs2_sync_dquot(dquot); status = ocfs2_sync_dquot(dquot);
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto out_trans; goto out_dlock;
} }
/* Now write updated local dquot structure */ /* Now write updated local dquot structure */
status = dquot_commit(dquot); status = ocfs2_local_write_dquot(dquot);
out_trans: out_dlock:
mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
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);
...@@ -915,7 +915,7 @@ static void ocfs2_destroy_dquot(struct dquot *dquot) ...@@ -915,7 +915,7 @@ static void ocfs2_destroy_dquot(struct dquot *dquot)
} }
const struct dquot_operations ocfs2_quota_operations = { const struct dquot_operations ocfs2_quota_operations = {
.write_dquot = ocfs2_write_dquot, /* We never make dquot dirty so .write_dquot is never called */
.acquire_dquot = ocfs2_acquire_dquot, .acquire_dquot = ocfs2_acquire_dquot,
.release_dquot = ocfs2_release_dquot, .release_dquot = ocfs2_release_dquot,
.mark_dirty = ocfs2_mark_dquot_dirty, .mark_dirty = ocfs2_mark_dquot_dirty,
......
...@@ -892,7 +892,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private) ...@@ -892,7 +892,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
} }
/* Write dquot to local quota file */ /* Write dquot to local quota file */
static int ocfs2_local_write_dquot(struct dquot *dquot) int ocfs2_local_write_dquot(struct dquot *dquot)
{ {
struct super_block *sb = dquot->dq_sb; struct super_block *sb = dquot->dq_sb;
struct ocfs2_dquot *od = OCFS2_DQUOT(dquot); struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
...@@ -1309,7 +1309,6 @@ static const struct quota_format_ops ocfs2_format_ops = { ...@@ -1309,7 +1309,6 @@ static const struct quota_format_ops ocfs2_format_ops = {
.read_file_info = ocfs2_local_read_info, .read_file_info = ocfs2_local_read_info,
.write_file_info = ocfs2_global_write_info, .write_file_info = ocfs2_global_write_info,
.free_file_info = ocfs2_local_free_info, .free_file_info = ocfs2_local_free_info,
.commit_dqblk = ocfs2_local_write_dquot,
}; };
struct quota_format_type ocfs2_quota_format = { struct quota_format_type ocfs2_quota_format = {
......
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