]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/jbd2/journal.c
jbd2: optimize jbd2_journal_force_commit
[karo-tx-linux.git] / fs / jbd2 / journal.c
index 95457576e434b2624475bbdab2758974eefbd9d5..0e6c13bdcc149f98aad310e5b0c67a500e428f08 100644 (file)
@@ -310,14 +310,12 @@ static void journal_kill_thread(journal_t *journal)
  *
  * If the source buffer has already been modified by a new transaction
  * since we took the last commit snapshot, we use the frozen copy of
- * that data for IO.  If we end up using the existing buffer_head's data
- * for the write, then we *have* to lock the buffer to prevent anyone
- * else from using and possibly modifying it while the IO is in
- * progress.
+ * that data for IO. If we end up using the existing buffer_head's data
+ * for the write, then we have to make sure nobody modifies it while the
+ * IO is in progress. do_get_write_access() handles this.
  *
- * The function returns a pointer to the buffer_heads to be used for IO.
- *
- * We assume that the journal has already been locked in this function.
+ * The function returns a pointer to the buffer_head to be used for IO.
+ * 
  *
  * Return value:
  *  <0: Error
@@ -330,15 +328,14 @@ static void journal_kill_thread(journal_t *journal)
 
 int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
                                  struct journal_head  *jh_in,
-                                 struct journal_head **jh_out,
-                                 unsigned long long blocknr)
+                                 struct buffer_head **bh_out,
+                                 sector_t blocknr)
 {
        int need_copy_out = 0;
        int done_copy_out = 0;
        int do_escape = 0;
        char *mapped_data;
        struct buffer_head *new_bh;
-       struct journal_head *new_jh;
        struct page *new_page;
        unsigned int new_offset;
        struct buffer_head *bh_in = jh2bh(jh_in);
@@ -368,14 +365,13 @@ retry_alloc:
 
        /* keep subsequent assertions sane */
        atomic_set(&new_bh->b_count, 1);
-       new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
 
+       jbd_lock_bh_state(bh_in);
+repeat:
        /*
         * If a new transaction has already done a buffer copy-out, then
         * we use that version of the data for the commit.
         */
-       jbd_lock_bh_state(bh_in);
-repeat:
        if (jh_in->b_frozen_data) {
                done_copy_out = 1;
                new_page = virt_to_page(jh_in->b_frozen_data);
@@ -415,7 +411,7 @@ repeat:
                jbd_unlock_bh_state(bh_in);
                tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS);
                if (!tmp) {
-                       jbd2_journal_put_journal_head(new_jh);
+                       brelse(new_bh);
                        return -ENOMEM;
                }
                jbd_lock_bh_state(bh_in);
@@ -426,7 +422,7 @@ repeat:
 
                jh_in->b_frozen_data = tmp;
                mapped_data = kmap_atomic(new_page);
-               memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size);
+               memcpy(tmp, mapped_data + new_offset, bh_in->b_size);
                kunmap_atomic(mapped_data);
 
                new_page = virt_to_page(tmp);
@@ -452,14 +448,14 @@ repeat:
        }
 
        set_bh_page(new_bh, new_page, new_offset);
-       new_jh->b_transaction = NULL;
-       new_bh->b_size = jh2bh(jh_in)->b_size;
-       new_bh->b_bdev = transaction->t_journal->j_dev;
+       new_bh->b_size = bh_in->b_size;
+       new_bh->b_bdev = journal->j_dev;
        new_bh->b_blocknr = blocknr;
+       new_bh->b_private = bh_in;
        set_buffer_mapped(new_bh);
        set_buffer_dirty(new_bh);
 
-       *jh_out = new_jh;
+       *bh_out = new_bh;
 
        /*
         * The to-be-written buffer needs to get moved to the io queue,
@@ -470,11 +466,9 @@ repeat:
        spin_lock(&journal->j_list_lock);
        __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);
 
-       JBUFFER_TRACE(new_jh, "file as BJ_IO");
-       jbd2_journal_file_buffer(new_jh, transaction, BJ_IO);
-
        return do_escape | (done_copy_out << 1);
 }
 
@@ -483,35 +477,6 @@ repeat:
  * journal, so that we can begin checkpointing when appropriate.
  */
 
-/*
- * __jbd2_log_space_left: Return the number of free blocks left in the journal.
- *
- * Called with the journal already locked.
- *
- * Called under j_state_lock
- */
-
-int __jbd2_log_space_left(journal_t *journal)
-{
-       int left = journal->j_free;
-
-       /* assert_spin_locked(&journal->j_state_lock); */
-
-       /*
-        * Be pessimistic here about the number of those free blocks which
-        * might be required for log descriptor control blocks.
-        */
-
-#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */
-
-       left -= MIN_LOG_RESERVED_BLOCKS;
-
-       if (left <= 0)
-               return 0;
-       left -= (left >> 3);
-       return left;
-}
-
 /*
  * Called with j_state_lock locked for writing.
  * Returns true if a transaction commit was started.
@@ -564,20 +529,17 @@ int jbd2_log_start_commit(journal_t *journal, tid_t tid)
 }
 
 /*
- * Force and wait upon a commit if the calling process is not within
- * transaction.  This is used for forcing out undo-protected data which contains
- * bitmaps, when the fs is running out of space.
- *
- * We can only force the running transaction if we don't have an active handle;
- * otherwise, we will deadlock.
- *
- * Returns true if a transaction was started.
+ * Force and wait any uncommitted transactions.  We can only force the running
+ * transaction if we don't have an active handle, otherwise, we will deadlock.
+ * Returns: <0 in case of error,
+ *           0 if nothing to commit,
+ *           1 if transaction was successfully committed.
  */
-int jbd2_journal_force_commit_nested(journal_t *journal)
+static int __jbd2_journal_force_commit(journal_t *journal)
 {
        transaction_t *transaction = NULL;
        tid_t tid;
-       int need_to_start = 0;
+       int need_to_start = 0, ret = 0;
 
        read_lock(&journal->j_state_lock);
        if (journal->j_running_transaction && !current->journal_info) {
@@ -588,16 +550,53 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
                transaction = journal->j_committing_transaction;
 
        if (!transaction) {
+               /* Nothing to commit */
                read_unlock(&journal->j_state_lock);
-               return 0;       /* Nothing to retry */
+               return 0;
        }
-
        tid = transaction->t_tid;
        read_unlock(&journal->j_state_lock);
        if (need_to_start)
                jbd2_log_start_commit(journal, tid);
-       jbd2_log_wait_commit(journal, tid);
-       return 1;
+       ret = jbd2_log_wait_commit(journal, tid);
+       if (!ret)
+               ret = 1;
+
+       return ret;
+}
+
+/**
+ * Force and wait upon a commit if the calling process is not within
+ * transaction.  This is used for forcing out undo-protected data which contains
+ * bitmaps, when the fs is running out of space.
+ *
+ * @journal: journal to force
+ * Returns true if progress was made.
+ */
+int jbd2_journal_force_commit_nested(journal_t *journal)
+{
+       int ret;
+
+       ret = __jbd2_journal_force_commit(journal);
+       return ret > 0;
+}
+
+/**
+ * int journal_force_commit() - force any uncommitted transactions
+ * @journal: journal to force
+ *
+ * Caller want unconditional commit. We can only force the running transaction
+ * if we don't have an active handle, otherwise, we will deadlock.
+ */
+int jbd2_journal_force_commit(journal_t *journal)
+{
+       int ret;
+
+       J_ASSERT(!current->journal_info);
+       ret = __jbd2_journal_force_commit(journal);
+       if (ret > 0)
+               ret = 0;
+       return ret;
 }
 
 /*
@@ -798,7 +797,7 @@ int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
  * But we don't bother doing that, so there will be coherency problems with
  * mmaps of blockdevs which hold live JBD-controlled filesystems.
  */
-struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
+struct buffer_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
 {
        struct buffer_head *bh;
        unsigned long long blocknr;
@@ -817,7 +816,7 @@ struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
        BUFFER_TRACE(bh, "return this buffer");
-       return jbd2_journal_add_journal_head(bh);
+       return bh;
 }
 
 /*
@@ -1062,11 +1061,10 @@ static journal_t * journal_init_common (void)
                return NULL;
 
        init_waitqueue_head(&journal->j_wait_transaction_locked);
-       init_waitqueue_head(&journal->j_wait_logspace);
        init_waitqueue_head(&journal->j_wait_done_commit);
-       init_waitqueue_head(&journal->j_wait_checkpoint);
        init_waitqueue_head(&journal->j_wait_commit);
        init_waitqueue_head(&journal->j_wait_updates);
+       init_waitqueue_head(&journal->j_wait_reserved);
        mutex_init(&journal->j_barrier);
        mutex_init(&journal->j_checkpoint_mutex);
        spin_lock_init(&journal->j_revoke_lock);
@@ -1076,6 +1074,7 @@ static journal_t * journal_init_common (void)
        journal->j_commit_interval = (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE);
        journal->j_min_batch_time = 0;
        journal->j_max_batch_time = 15000; /* 15ms */
+       atomic_set(&journal->j_reserved_credits, 0);
 
        /* The journal is marked for error until we succeed with recovery! */
        journal->j_flags = JBD2_ABORT;
@@ -2325,13 +2324,13 @@ static struct journal_head *journal_alloc_journal_head(void)
 #ifdef CONFIG_JBD2_DEBUG
        atomic_inc(&nr_journal_heads);
 #endif
-       ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
+       ret = kmem_cache_zalloc(jbd2_journal_head_cache, GFP_NOFS);
        if (!ret) {
                jbd_debug(1, "out of memory for journal_head\n");
                pr_notice_ratelimited("ENOMEM in %s, retrying.\n", __func__);
                while (!ret) {
                        yield();
-                       ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
+                       ret = kmem_cache_zalloc(jbd2_journal_head_cache, GFP_NOFS);
                }
        }
        return ret;
@@ -2393,10 +2392,8 @@ struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh)
        struct journal_head *new_jh = NULL;
 
 repeat:
-       if (!buffer_jbd(bh)) {
+       if (!buffer_jbd(bh))
                new_jh = journal_alloc_journal_head();
-               memset(new_jh, 0, sizeof(*new_jh));
-       }
 
        jbd_lock_bh_journal_head(bh);
        if (buffer_jbd(bh)) {