Merge tag 'gpio-v5.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
[linux-2.6-microblaze.git] / fs / jbd2 / journal.c
index 1c58859..5e408ee 100644 (file)
@@ -363,7 +363,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
        /* keep subsequent assertions sane */
        atomic_set(&new_bh->b_count, 1);
 
-       jbd_lock_bh_state(bh_in);
+       spin_lock(&jh_in->b_state_lock);
 repeat:
        /*
         * If a new transaction has already done a buffer copy-out, then
@@ -405,13 +405,13 @@ repeat:
        if (need_copy_out && !done_copy_out) {
                char *tmp;
 
-               jbd_unlock_bh_state(bh_in);
+               spin_unlock(&jh_in->b_state_lock);
                tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS);
                if (!tmp) {
                        brelse(new_bh);
                        return -ENOMEM;
                }
-               jbd_lock_bh_state(bh_in);
+               spin_lock(&jh_in->b_state_lock);
                if (jh_in->b_frozen_data) {
                        jbd2_free(tmp, bh_in->b_size);
                        goto repeat;
@@ -464,7 +464,7 @@ repeat:
        __jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
        spin_unlock(&journal->j_list_lock);
        set_buffer_shadow(bh_in);
-       jbd_unlock_bh_state(bh_in);
+       spin_unlock(&jh_in->b_state_lock);
 
        return do_escape | (done_copy_out << 1);
 }
@@ -840,6 +840,7 @@ jbd2_journal_get_descriptor_buffer(transaction_t *transaction, int type)
        bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
        if (!bh)
                return NULL;
+       atomic_dec(&transaction->t_outstanding_credits);
        lock_buffer(bh);
        memset(bh->b_data, 0, journal->j_blocksize);
        header = (journal_header_t *)bh->b_data;
@@ -1098,6 +1099,16 @@ static void jbd2_stats_proc_exit(journal_t *journal)
        remove_proc_entry(journal->j_devname, proc_jbd2_stats);
 }
 
+/* Minimum size of descriptor tag */
+static int jbd2_min_tag_size(void)
+{
+       /*
+        * Tag with 32-bit block numbers does not use last four bytes of the
+        * structure
+        */
+       return sizeof(journal_block_tag_t) - 4;
+}
+
 /*
  * Management for journal control blocks: functions to create and
  * destroy journal_t structures, and to initialise and read existing
@@ -1156,7 +1167,8 @@ static journal_t *journal_init_common(struct block_device *bdev,
        journal->j_fs_dev = fs_dev;
        journal->j_blk_offset = start;
        journal->j_maxlen = len;
-       n = journal->j_blocksize / sizeof(journal_block_tag_t);
+       /* We need enough buffers to write out full descriptor block. */
+       n = journal->j_blocksize / jbd2_min_tag_size();
        journal->j_wbufsize = n;
        journal->j_wbuf = kmalloc_array(n, sizeof(struct buffer_head *),
                                        GFP_KERNEL);
@@ -1488,6 +1500,21 @@ void jbd2_journal_update_sb_errno(journal_t *journal)
 }
 EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
 
+static int journal_revoke_records_per_block(journal_t *journal)
+{
+       int record_size;
+       int space = journal->j_blocksize - sizeof(jbd2_journal_revoke_header_t);
+
+       if (jbd2_has_feature_64bit(journal))
+               record_size = 8;
+       else
+               record_size = 4;
+
+       if (jbd2_journal_has_csum_v2or3(journal))
+               space -= sizeof(struct jbd2_journal_block_tail);
+       return space / record_size;
+}
+
 /*
  * Read the superblock for a given journal, performing initial
  * validation of the format.
@@ -1596,6 +1623,8 @@ static int journal_get_superblock(journal_t *journal)
                                                   sizeof(sb->s_uuid));
        }
 
+       journal->j_revoke_records_per_block =
+                               journal_revoke_records_per_block(journal);
        set_buffer_verified(bh);
 
        return 0;
@@ -1916,6 +1945,8 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
        sb->s_feature_ro_compat |= cpu_to_be32(ro);
        sb->s_feature_incompat  |= cpu_to_be32(incompat);
        unlock_buffer(journal->j_sb_buffer);
+       journal->j_revoke_records_per_block =
+                               journal_revoke_records_per_block(journal);
 
        return 1;
 #undef COMPAT_FEATURE_ON
@@ -1946,6 +1977,8 @@ void jbd2_journal_clear_features(journal_t *journal, unsigned long compat,
        sb->s_feature_compat    &= ~cpu_to_be32(compat);
        sb->s_feature_ro_compat &= ~cpu_to_be32(ro);
        sb->s_feature_incompat  &= ~cpu_to_be32(incompat);
+       journal->j_revoke_records_per_block =
+                               journal_revoke_records_per_block(journal);
 }
 EXPORT_SYMBOL(jbd2_journal_clear_features);
 
@@ -2410,6 +2443,8 @@ static struct journal_head *journal_alloc_journal_head(void)
                ret = kmem_cache_zalloc(jbd2_journal_head_cache,
                                GFP_NOFS | __GFP_NOFAIL);
        }
+       if (ret)
+               spin_lock_init(&ret->b_state_lock);
        return ret;
 }
 
@@ -2529,17 +2564,23 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
        J_ASSERT_BH(bh, buffer_jbd(bh));
        J_ASSERT_BH(bh, jh2bh(jh) == bh);
        BUFFER_TRACE(bh, "remove journal_head");
+
+       /* Unlink before dropping the lock */
+       bh->b_private = NULL;
+       jh->b_bh = NULL;        /* debug, really */
+       clear_buffer_jbd(bh);
+}
+
+static void journal_release_journal_head(struct journal_head *jh, size_t b_size)
+{
        if (jh->b_frozen_data) {
                printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__);
-               jbd2_free(jh->b_frozen_data, bh->b_size);
+               jbd2_free(jh->b_frozen_data, b_size);
        }
        if (jh->b_committed_data) {
                printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__);
-               jbd2_free(jh->b_committed_data, bh->b_size);
+               jbd2_free(jh->b_committed_data, b_size);
        }
-       bh->b_private = NULL;
-       jh->b_bh = NULL;        /* debug, really */
-       clear_buffer_jbd(bh);
        journal_free_journal_head(jh);
 }
 
@@ -2557,9 +2598,11 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
        if (!jh->b_jcount) {
                __journal_remove_journal_head(bh);
                jbd_unlock_bh_journal_head(bh);
+               journal_release_journal_head(jh, bh->b_size);
                __brelse(bh);
-       } else
+       } else {
                jbd_unlock_bh_journal_head(bh);
+       }
 }
 
 /*