ocfs2: Fix NULL pointer deref when writing local dquot
authorJan Kara <jack@suse.cz>
Thu, 13 May 2010 16:05:15 +0000 (18:05 +0200)
committerJan Kara <jack@suse.cz>
Fri, 21 May 2010 17:30:48 +0000 (19:30 +0200)
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: Joel Becker <Joel.Becker@oracle.com>
Signed-off-by: Jan Kara <jack@suse.cz>
fs/ocfs2/quota.h
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c

index 903ffa933d53a29ad4103098ccf6aae7c186475a..196fcb52d95d42f9f2c6dafc1a9efd276a88adca 100644 (file)
@@ -109,6 +109,7 @@ int ocfs2_read_quota_phys_block(struct inode *inode, u64 p_block,
                                struct buffer_head **bh);
 int ocfs2_create_local_dquot(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 struct quota_format_type ocfs2_quota_format;
index 7349958237407d67aff8e4c414344e7559d7c348..2bb35fe00511e98f41f23fa9a93d752d3a82b4fe 100644 (file)
@@ -612,14 +612,13 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
        }
        mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        status = ocfs2_sync_dquot(dquot);
-       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
        if (status < 0)
                mlog_errno(status);
        /* We have to write local structure as well... */
-       dquot_mark_dquot_dirty(dquot);
-       status = dquot_commit(dquot);
+       status = ocfs2_local_write_dquot(dquot);
        if (status < 0)
                mlog_errno(status);
+       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
        ocfs2_commit_trans(osb, handle);
 out_ilock:
        ocfs2_unlock_global_qf(oinfo, 1);
@@ -658,7 +657,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
                mlog_errno(status);
                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);
 out:
        mlog_exit(status);
@@ -831,7 +832,6 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
        struct ocfs2_super *osb = OCFS2_SB(sb);
 
        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
         * quota file so that information propagates quicker */
@@ -856,14 +856,14 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
        }
        mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        status = ocfs2_sync_dquot(dquot);
-       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
        if (status < 0) {
                mlog_errno(status);
-               goto out_trans;
+               goto out_dlock;
        }
        /* Now write updated local dquot structure */
-       status = dquot_commit(dquot);
-out_trans:
+       status = ocfs2_local_write_dquot(dquot);
+out_dlock:
+       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
        ocfs2_commit_trans(osb, handle);
 out_ilock:
        ocfs2_unlock_global_qf(oinfo, 1);
@@ -915,7 +915,7 @@ static void ocfs2_destroy_dquot(struct dquot *dquot)
 }
 
 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,
        .release_dquot  = ocfs2_release_dquot,
        .mark_dirty     = ocfs2_mark_dquot_dirty,
index 778947f0e951af0000a0d4edad9da7c9d3cc7ca6..551a6bff9f2c38beac91683429dca153a197332b 100644 (file)
@@ -892,7 +892,7 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
 }
 
 /* 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 ocfs2_dquot *od = OCFS2_DQUOT(dquot);
@@ -1309,7 +1309,6 @@ static const struct quota_format_ops ocfs2_format_ops = {
        .read_file_info         = ocfs2_local_read_info,
        .write_file_info        = ocfs2_global_write_info,
        .free_file_info         = ocfs2_local_free_info,
-       .commit_dqblk           = ocfs2_local_write_dquot,
 };
 
 struct quota_format_type ocfs2_quota_format = {