ocfs2: Don't relink cluster groups when allocating discontig block groups
[safe/jmp/linux-2.6] / fs / ocfs2 / quota_local.c
index 7053664..a8f4cea 100644 (file)
@@ -20,6 +20,7 @@
 #include "sysfile.h"
 #include "dlmglue.h"
 #include "quota.h"
+#include "uptodate.h"
 
 /* Number of local quota structures per block */
 static inline unsigned int ol_quota_entries_per_block(struct super_block *sb)
@@ -100,14 +101,15 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
        handle_t *handle;
        int status;
 
-       handle = ocfs2_start_trans(OCFS2_SB(sb), 1);
+       handle = ocfs2_start_trans(OCFS2_SB(sb),
+                                  OCFS2_QUOTA_BLOCK_UPDATE_CREDITS);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
                mlog_errno(status);
                return status;
        }
-       status = ocfs2_journal_access(handle, inode, bh,
-                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       status = ocfs2_journal_access_dq(handle, INODE_CACHE(inode), bh,
+                                        OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
                ocfs2_commit_trans(OCFS2_SB(sb), handle);
@@ -116,12 +118,8 @@ static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
        lock_buffer(bh);
        modify(bh, private);
        unlock_buffer(bh);
-       status = ocfs2_journal_dirty(handle, bh);
-       if (status < 0) {
-               mlog_errno(status);
-               ocfs2_commit_trans(OCFS2_SB(sb), handle);
-               return status;
-       }
+       ocfs2_journal_dirty(handle, bh);
+
        status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
        if (status < 0) {
                mlog_errno(status);
@@ -444,10 +442,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 
        mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type);
 
-       status = ocfs2_lock_global_qf(oinfo, 1);
-       if (status < 0)
-               goto out;
-
        list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) {
                chunk = rchunk->rc_chunk;
                hbh = NULL;
@@ -459,7 +453,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                        break;
                }
                dchunk = (struct ocfs2_local_disk_chunk *)hbh->b_data;
-               for_each_bit(bit, rchunk->rc_bitmap, ol_chunk_entries(sb)) {
+               for_each_set_bit(bit, rchunk->rc_bitmap, ol_chunk_entries(sb)) {
                        qbh = NULL;
                        status = ocfs2_read_quota_block(lqinode,
                                                ol_dqblk_block(sb, chunk, bit),
@@ -480,12 +474,18 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                     type);
                                goto out_put_bh;
                        }
+                       status = ocfs2_lock_global_qf(oinfo, 1);
+                       if (status < 0) {
+                               mlog_errno(status);
+                               goto out_put_dquot;
+                       }
+
                        handle = ocfs2_start_trans(OCFS2_SB(sb),
                                                   OCFS2_QSYNC_CREDITS);
                        if (IS_ERR(handle)) {
                                status = PTR_ERR(handle);
                                mlog_errno(status);
-                               goto out_put_dquot;
+                               goto out_drop_lock;
                        }
                        mutex_lock(&sb_dqopt(sb)->dqio_mutex);
                        spin_lock(&dq_data_lock);
@@ -506,7 +506,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                goto out_commit;
                        }
                        /* Release local quota file entry */
-                       status = ocfs2_journal_access(handle, lqinode,
+                       status = ocfs2_journal_access_dq(handle,
+                                       INODE_CACHE(lqinode),
                                        qbh, OCFS2_JOURNAL_ACCESS_WRITE);
                        if (status < 0) {
                                mlog_errno(status);
@@ -517,12 +518,12 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                        ocfs2_clear_bit(bit, dchunk->dqc_bitmap);
                        le32_add_cpu(&dchunk->dqc_free, 1);
                        unlock_buffer(qbh);
-                       status = ocfs2_journal_dirty(handle, qbh);
-                       if (status < 0)
-                               mlog_errno(status);
+                       ocfs2_journal_dirty(handle, qbh);
 out_commit:
                        mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
                        ocfs2_commit_trans(OCFS2_SB(sb), handle);
+out_drop_lock:
+                       ocfs2_unlock_global_qf(oinfo, 1);
 out_put_dquot:
                        dqput(dquot);
 out_put_bh:
@@ -537,8 +538,6 @@ out_put_bh:
                if (status < 0)
                        break;
        }
-       ocfs2_unlock_global_qf(oinfo, 1);
-out:
        if (status < 0)
                free_recovery_list(&(rec->r_list[type]));
        mlog_exit(status);
@@ -608,14 +607,16 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
                        goto out_bh;
                /* Mark quota file as clean if we are recovering quota file of
                 * some other node. */
-               handle = ocfs2_start_trans(osb, 1);
+               handle = ocfs2_start_trans(osb,
+                                          OCFS2_LOCAL_QINFO_WRITE_CREDITS);
                if (IS_ERR(handle)) {
                        status = PTR_ERR(handle);
                        mlog_errno(status);
                        goto out_bh;
                }
-               status = ocfs2_journal_access(handle, lqinode, bh,
-                                             OCFS2_JOURNAL_ACCESS_WRITE);
+               status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode),
+                                                bh,
+                                                OCFS2_JOURNAL_ACCESS_WRITE);
                if (status < 0) {
                        mlog_errno(status);
                        goto out_trans;
@@ -623,9 +624,7 @@ int ocfs2_finish_quota_recovery(struct ocfs2_super *osb,
                lock_buffer(bh);
                ldinfo->dqi_flags = cpu_to_le32(flags | OLQF_CLEAN);
                unlock_buffer(bh);
-               status = ocfs2_journal_dirty(handle, bh);
-               if (status < 0)
-                       mlog_errno(status);
+               ocfs2_journal_dirty(handle, bh);
 out_trans:
                ocfs2_commit_trans(osb, handle);
 out_bh:
@@ -655,6 +654,9 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
        struct ocfs2_quota_recovery *rec;
        int locked = 0;
 
+       /* 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);
        info->dqi_maxblimit = 0x7fffffffffffffffLL;
        info->dqi_maxilimit = 0x7fffffffffffffffLL;
        oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
@@ -733,6 +735,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
                goto out_err;
        }
 
+       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        return 0;
 out_err:
        if (oinfo) {
@@ -746,6 +749,7 @@ out_err:
                kfree(oinfo);
        }
        brelse(bh);
+       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        return -1;
 }
 
@@ -848,7 +852,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
                                          od->dq_originodes);
        spin_unlock(&dq_data_lock);
        mlog(0, "Writing local dquot %u space %lld inodes %lld\n",
-            od->dq_dquot.dq_id, dqblk->dqb_spacemod, dqblk->dqb_inodemod);
+            od->dq_dquot.dq_id, (long long)le64_to_cpu(dqblk->dqb_spacemod),
+            (long long)le64_to_cpu(dqblk->dqb_inodemod));
 }
 
 /* Write dquot to local quota file */
@@ -932,7 +937,7 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
        struct ocfs2_local_disk_chunk *dchunk;
        int status;
        handle_t *handle;
-       struct buffer_head *bh = NULL;
+       struct buffer_head *bh = NULL, *dbh = NULL;
        u64 p_blkno;
 
        /* We are protected by dqio_sem so no locking needed */
@@ -956,49 +961,75 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
                mlog_errno(status);
                goto out;
        }
+       /* Local quota info and two new blocks we initialize */
+       handle = ocfs2_start_trans(OCFS2_SB(sb),
+                       OCFS2_LOCAL_QINFO_WRITE_CREDITS +
+                       2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               mlog_errno(status);
+               goto out;
+       }
 
+       /* Initialize chunk header */
        down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
        status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks,
                                             &p_blkno, NULL, NULL);
        up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
        if (status < 0) {
                mlog_errno(status);
-               goto out;
+               goto out_trans;
        }
        bh = sb_getblk(sb, p_blkno);
        if (!bh) {
                status = -ENOMEM;
                mlog_errno(status);
-               goto out;
+               goto out_trans;
        }
        dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
-
-       handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
-       if (IS_ERR(handle)) {
-               status = PTR_ERR(handle);
-               mlog_errno(status);
-               goto out;
-       }
-
-       status = ocfs2_journal_access(handle, lqinode, bh,
-                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), bh);
+       status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), bh,
+                                        OCFS2_JOURNAL_ACCESS_CREATE);
        if (status < 0) {
                mlog_errno(status);
                goto out_trans;
        }
        lock_buffer(bh);
-       dchunk->dqc_free = ol_quota_entries_per_block(sb);
+       dchunk->dqc_free = cpu_to_le32(ol_quota_entries_per_block(sb));
        memset(dchunk->dqc_bitmap, 0,
               sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) -
               OCFS2_QBLK_RESERVED_SPACE);
-       set_buffer_uptodate(bh);
        unlock_buffer(bh);
-       status = ocfs2_journal_dirty(handle, bh);
+       ocfs2_journal_dirty(handle, bh);
+
+       /* Initialize new block with structures */
+       down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+       status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks + 1,
+                                            &p_blkno, NULL, NULL);
+       up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out_trans;
+       }
+       dbh = sb_getblk(sb, p_blkno);
+       if (!dbh) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto out_trans;
+       }
+       ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), dbh);
+       status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), dbh,
+                                        OCFS2_JOURNAL_ACCESS_CREATE);
        if (status < 0) {
                mlog_errno(status);
                goto out_trans;
        }
+       lock_buffer(dbh);
+       memset(dbh->b_data, 0, sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE);
+       unlock_buffer(dbh);
+       ocfs2_journal_dirty(handle, dbh);
 
+       /* Update local quotafile info */
        oinfo->dqi_blocks += 2;
        oinfo->dqi_chunks++;
        status = ocfs2_local_write_info(sb, type);
@@ -1023,6 +1054,7 @@ out_trans:
        ocfs2_commit_trans(OCFS2_SB(sb), handle);
 out:
        brelse(bh);
+       brelse(dbh);
        kmem_cache_free(ocfs2_qf_chunk_cachep, chunk);
        return ERR_PTR(status);
 }
@@ -1040,6 +1072,8 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
        struct ocfs2_local_disk_chunk *dchunk;
        int epb = ol_quota_entries_per_block(sb);
        unsigned int chunk_blocks;
+       struct buffer_head *bh;
+       u64 p_blkno;
        int status;
        handle_t *handle;
 
@@ -1067,13 +1101,48 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
                mlog_errno(status);
                goto out;
        }
-       handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
+
+       /* Get buffer from the just added block */
+       down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+       status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks,
+                                            &p_blkno, NULL, NULL);
+       up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+       bh = sb_getblk(sb, p_blkno);
+       if (!bh) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto out;
+       }
+       ocfs2_set_new_buffer_uptodate(INODE_CACHE(lqinode), bh);
+
+       /* Local quota info, chunk header and the new block we initialize */
+       handle = ocfs2_start_trans(OCFS2_SB(sb),
+                       OCFS2_LOCAL_QINFO_WRITE_CREDITS +
+                       2 * OCFS2_QUOTA_BLOCK_UPDATE_CREDITS);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
                mlog_errno(status);
                goto out;
        }
-       status = ocfs2_journal_access(handle, lqinode, chunk->qc_headerbh,
+       /* Zero created block */
+       status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode), bh,
+                                OCFS2_JOURNAL_ACCESS_CREATE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out_trans;
+       }
+       lock_buffer(bh);
+       memset(bh->b_data, 0, sb->s_blocksize);
+       unlock_buffer(bh);
+       ocfs2_journal_dirty(handle, bh);
+
+       /* Update chunk header */
+       status = ocfs2_journal_access_dq(handle, INODE_CACHE(lqinode),
+                                        chunk->qc_headerbh,
                                 OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -1084,11 +1153,9 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
        lock_buffer(chunk->qc_headerbh);
        le32_add_cpu(&dchunk->dqc_free, ol_quota_entries_per_block(sb));
        unlock_buffer(chunk->qc_headerbh);
-       status = ocfs2_journal_dirty(handle, chunk->qc_headerbh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto out_trans;
-       }
+       ocfs2_journal_dirty(handle, chunk->qc_headerbh);
+
+       /* Update file header */
        oinfo->dqi_blocks++;
        status = ocfs2_local_write_info(sb, type);
        if (status < 0) {
@@ -1109,7 +1176,7 @@ out:
        return ERR_PTR(status);
 }
 
-void olq_alloc_dquot(struct buffer_head *bh, void *private)
+static void olq_alloc_dquot(struct buffer_head *bh, void *private)
 {
        int *offset = private;
        struct ocfs2_local_disk_chunk *dchunk;
@@ -1206,7 +1273,8 @@ static int ocfs2_local_release_dquot(struct dquot *dquot)
                goto out;
        }
 
-       status = ocfs2_journal_access(handle, sb_dqopt(sb)->files[type],
+       status = ocfs2_journal_access_dq(handle,
+                       INODE_CACHE(sb_dqopt(sb)->files[type]),
                        od->dq_chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -1221,12 +1289,8 @@ static int ocfs2_local_release_dquot(struct dquot *dquot)
        ocfs2_clear_bit(offset, dchunk->dqc_bitmap);
        le32_add_cpu(&dchunk->dqc_free, 1);
        unlock_buffer(od->dq_chunk->qc_headerbh);
-       status = ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto out;
-       }
-       status = 0;
+       ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
+
 out:
        /* Clear the read bit so that next time someone uses this
         * dquot he reads fresh info from disk and allocates local
@@ -1235,7 +1299,7 @@ out:
        return status;
 }
 
-static struct quota_format_ops ocfs2_format_ops = {
+static const struct quota_format_ops ocfs2_format_ops = {
        .check_quota_file       = ocfs2_local_check_quota_file,
        .read_file_info         = ocfs2_local_read_info,
        .write_file_info        = ocfs2_global_write_info,