Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / fs / ext4 / ext4_jbd2.c
index 451eb404533095fc323218fe5ea0f3caa0af8b16..72a3600aedbdffe48b5f2756bb0ad863f120a7b8 100644 (file)
@@ -38,31 +38,43 @@ static void ext4_put_nojournal(handle_t *handle)
 /*
  * Wrappers for jbd2_journal_start/end.
  */
-handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
-                                 int type, int nblocks)
+static int ext4_journal_check_start(struct super_block *sb)
 {
        journal_t *journal;
 
        might_sleep();
-
-       trace_ext4_journal_start(sb, nblocks, _RET_IP_);
        if (sb->s_flags & MS_RDONLY)
-               return ERR_PTR(-EROFS);
-
+               return -EROFS;
        WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
        journal = EXT4_SB(sb)->s_journal;
-       if (!journal)
-               return ext4_get_nojournal();
        /*
         * Special case here: if the journal has aborted behind our
         * backs (eg. EIO in the commit thread), then we still need to
         * take the FS itself readonly cleanly.
         */
-       if (is_journal_aborted(journal)) {
+       if (journal && is_journal_aborted(journal)) {
                ext4_abort(sb, "Detected aborted journal");
-               return ERR_PTR(-EROFS);
+               return -EROFS;
        }
-       return jbd2__journal_start(journal, nblocks, GFP_NOFS, type, line);
+       return 0;
+}
+
+handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
+                                 int type, int blocks, int rsv_blocks)
+{
+       journal_t *journal;
+       int err;
+
+       trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_);
+       err = ext4_journal_check_start(sb);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       journal = EXT4_SB(sb)->s_journal;
+       if (!journal)
+               return ext4_get_nojournal();
+       return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS,
+                                  type, line);
 }
 
 int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
@@ -86,6 +98,30 @@ int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
        return err;
 }
 
+handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
+                                       int type)
+{
+       struct super_block *sb;
+       int err;
+
+       if (!ext4_handle_valid(handle))
+               return ext4_get_nojournal();
+
+       sb = handle->h_journal->j_private;
+       trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
+                                         _RET_IP_);
+       err = ext4_journal_check_start(sb);
+       if (err < 0) {
+               jbd2_journal_free_reserved(handle);
+               return ERR_PTR(err);
+       }
+
+       err = jbd2_journal_start_reserved(handle, type, line);
+       if (err < 0)
+               return ERR_PTR(err);
+       return handle;
+}
+
 void ext4_journal_abort_handle(const char *caller, unsigned int line,
                               const char *err_fn, struct buffer_head *bh,
                               handle_t *handle, int err)