]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/ext4/ext4_jbd2.h
Merge tag 'upstream-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs
[linux.git] / fs / ext4 / ext4_jbd2.h
index ef8fcf7d0d3b3ac1aff52ff3ad7d53f626c60a50..a6b9b66dbfade76a5f5d8bb31ad9337af5fd22d1 100644 (file)
@@ -261,7 +261,8 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,
        __ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb))
 
 handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
-                                 int type, int blocks, int rsv_blocks);
+                                 int type, int blocks, int rsv_blocks,
+                                 int revoke_creds);
 int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle);
 
 #define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096)
@@ -288,28 +289,41 @@ static inline int ext4_handle_is_aborted(handle_t *handle)
        return 0;
 }
 
-static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed)
+static inline int ext4_free_metadata_revoke_credits(struct super_block *sb,
+                                                   int blocks)
 {
-       if (ext4_handle_valid(handle) && handle->h_buffer_credits < needed)
-               return 0;
-       return 1;
+       /* Freeing each metadata block can result in freeing one cluster */
+       return blocks * EXT4_SB(sb)->s_cluster_ratio;
+}
+
+static inline int ext4_trans_default_revoke_credits(struct super_block *sb)
+{
+       return ext4_free_metadata_revoke_credits(sb, 8);
 }
 
 #define ext4_journal_start_sb(sb, type, nblocks)                       \
-       __ext4_journal_start_sb((sb), __LINE__, (type), (nblocks), 0)
+       __ext4_journal_start_sb((sb), __LINE__, (type), (nblocks), 0,   \
+                               ext4_trans_default_revoke_credits(sb))
 
 #define ext4_journal_start(inode, type, nblocks)                       \
-       __ext4_journal_start((inode), __LINE__, (type), (nblocks), 0)
+       __ext4_journal_start((inode), __LINE__, (type), (nblocks), 0,   \
+                            ext4_trans_default_revoke_credits((inode)->i_sb))
+
+#define ext4_journal_start_with_reserve(inode, type, blocks, rsv_blocks)\
+       __ext4_journal_start((inode), __LINE__, (type), (blocks), (rsv_blocks),\
+                            ext4_trans_default_revoke_credits((inode)->i_sb))
 
-#define ext4_journal_start_with_reserve(inode, type, blocks, rsv_blocks) \
-       __ext4_journal_start((inode), __LINE__, (type), (blocks), (rsv_blocks))
+#define ext4_journal_start_with_revoke(inode, type, blocks, revoke_creds) \
+       __ext4_journal_start((inode), __LINE__, (type), (blocks), 0,    \
+                            (revoke_creds))
 
 static inline handle_t *__ext4_journal_start(struct inode *inode,
                                             unsigned int line, int type,
-                                            int blocks, int rsv_blocks)
+                                            int blocks, int rsv_blocks,
+                                            int revoke_creds)
 {
        return __ext4_journal_start_sb(inode->i_sb, line, type, blocks,
-                                      rsv_blocks);
+                                      rsv_blocks, revoke_creds);
 }
 
 #define ext4_journal_stop(handle) \
@@ -332,20 +346,68 @@ static inline handle_t *ext4_journal_current_handle(void)
        return journal_current_handle();
 }
 
-static inline int ext4_journal_extend(handle_t *handle, int nblocks)
+static inline int ext4_journal_extend(handle_t *handle, int nblocks, int revoke)
 {
        if (ext4_handle_valid(handle))
-               return jbd2_journal_extend(handle, nblocks);
+               return jbd2_journal_extend(handle, nblocks, revoke);
        return 0;
 }
 
-static inline int ext4_journal_restart(handle_t *handle, int nblocks)
+static inline int ext4_journal_restart(handle_t *handle, int nblocks,
+                                      int revoke)
 {
        if (ext4_handle_valid(handle))
-               return jbd2_journal_restart(handle, nblocks);
+               return jbd2__journal_restart(handle, nblocks, revoke, GFP_NOFS);
        return 0;
 }
 
+int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
+                                 int extend_cred, int revoke_cred);
+
+
+/*
+ * Ensure @handle has at least @check_creds credits available. If not,
+ * transaction will be extended or restarted to contain at least @extend_cred
+ * credits. Before restarting transaction @fn is executed to allow for cleanup
+ * before the transaction is restarted.
+ *
+ * The return value is < 0 in case of error, 0 in case the handle has enough
+ * credits or transaction extension succeeded, 1 in case transaction had to be
+ * restarted.
+ */
+#define ext4_journal_ensure_credits_fn(handle, check_cred, extend_cred,        \
+                                      revoke_cred, fn) \
+({                                                                     \
+       __label__ __ensure_end;                                         \
+       int err = __ext4_journal_ensure_credits((handle), (check_cred), \
+                                       (extend_cred), (revoke_cred));  \
+                                                                       \
+       if (err <= 0)                                                   \
+               goto __ensure_end;                                      \
+       err = (fn);                                                     \
+       if (err < 0)                                                    \
+               goto __ensure_end;                                      \
+       err = ext4_journal_restart((handle), (extend_cred), (revoke_cred)); \
+       if (err == 0)                                                   \
+               err = 1;                                                \
+__ensure_end:                                                          \
+       err;                                                            \
+})
+
+/*
+ * Ensure given handle has at least requested amount of credits available,
+ * possibly restarting transaction if needed. We also make sure the transaction
+ * has space for at least ext4_trans_default_revoke_credits(sb) revoke records
+ * as freeing one or two blocks is very common pattern and requesting this is
+ * very cheap.
+ */
+static inline int ext4_journal_ensure_credits(handle_t *handle, int credits,
+                                             int revoke_creds)
+{
+       return ext4_journal_ensure_credits_fn(handle, credits, credits,
+                               revoke_creds, 0);
+}
+
 static inline int ext4_journal_blocks_per_page(struct inode *inode)
 {
        if (EXT4_JOURNAL(inode) != NULL)
@@ -407,6 +469,7 @@ static inline int ext4_inode_journal_mode(struct inode *inode)
                return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
        /* We do not support data journalling with delayed allocation */
        if (!S_ISREG(inode->i_mode) ||
+           ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
            test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
            (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
            !test_opt(inode->i_sb, DELALLOC))) {
@@ -437,6 +500,19 @@ static inline int ext4_should_writeback_data(struct inode *inode)
        return ext4_inode_journal_mode(inode) & EXT4_INODE_WRITEBACK_DATA_MODE;
 }
 
+static inline int ext4_free_data_revoke_credits(struct inode *inode, int blocks)
+{
+       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+               return 0;
+       if (!ext4_should_journal_data(inode))
+               return 0;
+       /*
+        * Data blocks in one extent are contiguous, just account for partial
+        * clusters at extent boundaries
+        */
+       return blocks + 2*(EXT4_SB(inode->i_sb)->s_cluster_ratio - 1);
+}
+
 /*
  * This function controls whether or not we should try to go down the
  * dioread_nolock code paths, which makes it safe to avoid taking