ext4: update docs for fast commit feature
PATCH v5 1/20 ext4: update docs for fast commit feature
In reply to a message not in the archiveThis patch series adds support for fast commits which is a simplified version of the scheme proposed by Park and Shin, in their paper, "iJournaling: Fine-Grained Journaling for Improving the Latency of Fsync System Call"[1]. The basic idea of fast commits is to make JBD2 give the client file system an opportunity to perform a faster commit. Only if the file system cannot perform such a commit operation, then JBD2 should fall back to traditional commits.
Because JBD2 operates at block granularity, for every file system metadata update it commits all the changed blocks are written to the journal at commit time. This is inefficient because updates to some blocks that JBD2 commits are derivable from some other blocks. For example, if a new extent is added to an inode, then corresponding updates to the inode table, the block bitmap, the group descriptor and the superblock can be derived based on just the extent information and the corresponding inode information. So, if we take this relationship between blocks into account and replay the journalled blocks smartly, we could increase performance of file system commits significantly.
Fast commits introduced in this patch have two main contributions:
(1) Making JBD2 fast commit aware, so that clients of JBD2 can implement fast commits
(2) Add support in ext4 to use JBD2's new interfaces and implement fast commits.
Ext4 supports two modes of fast commits: 1) fast commits with hard consistency guarantees 2) fast commits with soft consistency guarantees
When hard consistency is enabled, fast commit guarantees that all the updates will be committed. After a successful replay of fast commits blocks in hard consistency mode, the entire file system would be in the same state as that when fsync() returned before crash. This guarantee is similar to what jbd2 gives with full commits.
With soft consistency, file system only guarantees consistency for the inode in question. In this mode, file system will try to write as less data to the backend as possible during the commit time. To be precise, file system records all the data updates for the inode in question and directory updates that are required for guaranteeing consistency of the inode in question.
In our evaluations, fast commits with hard consistency performed better than fast commits with soft consistency. That's because with hard consistency, a fast commit often ends up committing other inodes together, while with soft consistency commits get serialized. Future work can look at creating hybrid approach between the two extremes that are there in this patchset.
Testing
-------
e2fsprogs was updated to set fast commit feature flag and to ignore fast commit blocks during e2fsck.
https://github.com/harshadjs/e2fsprogs.git
After applying all the patches in this series, following runs of xfstests were performed:
- kvm-xfstest.sh -g log -c 4k
- kvm-xfstests.sh smoke
All the log tests were successful and smoke tests didn't introduce any additional failures.
Performance Evaluation
----------------------
Ext4 file system performance was tested with full commits, with fast commits with soft consistency and with fast commits with hard consistency. fs_mark benchmark showed that depending on the file size, performance improvement was seen up to 50%. Soft fast commits performed slightly worse than hard fast commits. But soft fast commits ended up writing slightly lesser number of blocks on disk.
Changes since V4:
- Rebased on top of v5.6-rc3
- Fixed inode handling due to changed ext4_add_nondir()
Harshad Shirwadkar(20):
ext4: add debug mount option to test fast commit replay
ext4: add fast commit replay path
ext4: disable certain features in replay path
ext4: add idempotent helpers to manipulate bitmaps
ext4: fast commit recovery path preparation
jbd2: add fast commit recovery path support
ext4: main commit routine for fast commits
jbd2: add new APIs for commit path of fast commits
ext4: add fast commit on-disk format structs
ext4: add fast commit track points
ext4: break ext4_unlink() and ext4_link()
ext4: add inode tracking and ineligible marking routines
ext4: add directory entry tracking routines
ext4: add generic diff tracking routines and range tracking
jbd2: fast commit main commit path changes
jbd2: disable fast commits if journal is empty
jbd2: add fast commit block tracker variables ext4, jbd2: add fast commit initialization routines
ext4: add handling for extended mount options
ext4: update docs for fast commit feature
Documentation/filesystems/ext4/journal.rst | 127 ++- Documentation/filesystems/journalling.rst | 18 + fs/ext4/acl.c | 1 + fs/ext4/balloc.c | 10 +- fs/ext4/ext4.h | 126 +++ fs/ext4/ext4_jbd2.c | 1484 +++++++++++++++++++++++++++- fs/ext4/ext4_jbd2.h | 71 ++ fs/ext4/extents.c | 5 + fs/ext4/extents_status.c | 24 + fs/ext4/fsync.c | 2 +- fs/ext4/ialloc.c | 165 +++- fs/ext4/inline.c | 3 + fs/ext4/inode.c | 76 +- fs/ext4/ioctl.c | 11 +- fs/ext4/mballoc.c | 158 ++- fs/ext4/mballoc.h | 2 + fs/ext4/migrate.c | 1 + fs/ext4/namei.c | 182 ++-- fs/ext4/super.c | 72 +- fs/ext4/xattr.c | 6 + fs/jbd2/commit.c | 61 ++ fs/jbd2/journal.c | 217 +++- fs/jbd2/recovery.c | 67 +- include/linux/jbd2.h | 83 +- include/trace/events/ext4.h | 208 +++- 25 files changed, 3046 insertions(+), 134 deletions(-)ˆ
--- Documentation/filesystems/ext4/journal.rst | 127 ++++++++++++++++++++- Documentation/filesystems/journalling.rst | 18 +++ 2 files changed, 139 insertions(+), 6 deletions(-)
Documentation/filesystems/ext4/journal.rst +121 -6
@@ -29,10 +29,10 @@ safest. If ``data=writeback``, dirty data blocks are not flushed to the disk before the metadata are written to disk through the journal. The journal inode is typically inode 8. The first 68 bytes of the -journal inode are replicated in the ext4 superblock. The journal itself -is normal (but hidden) file within the filesystem. The file usually -consumes an entire block group, though mke2fs tries to put it in the -middle of the disk. +journal inode are replicated in the ext4 superblock. The journal +itself is normal (but hidden) file within the filesystem. The file +usually consumes an entire block group, though mke2fs tries to put it +in the middle of the disk. All fields in jbd2 are written to disk in big-endian order. This is the opposite of ext4.
@@ -42,22 +42,74 @@ NOTE: Both ext4 and ocfs2 use jbd2. The maximum size of a journal embedded in an ext4 filesystem is 2^32 blocks. jbd2 itself does not seem to care. +Fast Commits +~~~~~~~~~~~~ + +Ext4 also implements fast commits and integrates it with JBD2 journalling. +Fast commits store metadata changes made to the file system as inode level +diff. In other words, each fast commit block identifies updates made to +a particular inode and collectively they represent total changes made to +the file system. + +A fast commit is valid only if there is no full commit after that particular +fast commit. Because of this feature, fast commit blocks can be reused by +the following transactions. + +Each fast commit block stores updates to 1 particular inode. Updates in each +fast commit block are one of the 2 types: +- Data updates (add range / delete range) +- Directory entry updates (Add / remove links) + +Fast commit blocks must be replayed in the order in which they appear on disk. +That's because directory entry updates are written in fast commit blocks +in the order in which they are applied on the file system before crash. +Changing the order of replaying for directory entry updates may result +in inconsistent file system. Note that only directory entry updates need +ordering, data updates, since they apply to only one inode, do not require +ordered replay. Also, fast commits guarantee that file system is in consistent +state after replay of each fast commit block as long as order of replay has +been followed. + +Note that directory inode updates are never directly recorded in fast commits. +Just like other file system level metaata, updates to directories are always +implied based on directory entry updates stored in fast commit blocks. + +Based on which directory entry updates are committed with an inode, fast +commits have two modes of operation: + +- Hard Consistency (default) +- Soft Consistency (can be enabled by setting mount flag "fc_soft_consistency") + +When hard consistency is enabled, fast commit guarantees that all the updates +will be committed. After a successful replay of fast commits blocks +in hard consistency mode, the entire file system would be in the same state as +that when fsync() returned before crash. This guarantee is similar to what +jbd2 gives. + +With soft consistency, file system only guarantees consistency for the +inode in question. In this mode, file system will try to write as less data +to the backed as possible during the commit time. To be precise, file system +records all the data updates for the inode in question and directory updates +that are required for guaranteeing consistency of the inode in question. + Layout ~~~~~~ Generally speaking, the journal has this format: .. list-table:: - :widths: 16 48 16 + :widths: 16 48 16 18 :header-rows: 1 * - Superblock - descriptor\_block (data\_blocks or revocation\_block) [more data or revocations] commmit\_block - [more transactions...] + - [Fast commits...] * - - One transaction - + - Notice that a transaction begins with either a descriptor and some data, or a block revocation list. A finished transaction always ends with a
@@ -76,7 +128,7 @@ The journal superblock will be in the next full block after the superblock. .. list-table:: - :widths: 12 12 12 32 12 + :widths: 12 12 12 32 12 12 :header-rows: 1 * - 1024 bytes of padding
@@ -85,11 +137,13 @@ superblock. - descriptor\_block (data\_blocks or revocation\_block) [more data or revocations] commmit\_block - [more transactions...] + - [Fast commits...] * - - - - One transaction - + - Block Header ~~~~~~~~~~~~
@@ -609,3 +663,64 @@ bytes long (but uses a full block): - h\_commit\_nsec - Nanoseconds component of the above timestamp. +Fast Commit Block +~~~~~~~~~~~~~~~~~ + +The fast commit block indicates an append to the last commit block +that was written to the journal. One fast commit block records updates +to one inode. So, typically you would find as many fast commit blocks +as the number of inodes that got changed since the last commit. A fast +commit block is valid only if there is no commit block present with +transaction ID greater than that of the fast commit block. If such a +block a present, then there is no need to replay the fast commit +block. + +.. list-table:: + :widths: 8 8 24 40 + :header-rows: 1 + + * - Offset + - Type + - Name + - Descriptor + * - 0x0 + - journal\_header\_s + - (open coded) + - Common block header. + * - 0xC + - \_\_le32 + - fc\_magic + - Magic value which should be set to 0xE2540090. This identifies + that this block is a fast commit block. + * - 0x10 + - \_\_u8 + - fc\_features + - Features used by this fast commit block. + * - 0x11 + - \_\_le16 + - fc_num_tlvs + - Number of TLVs contained in this fast commit block + * - 0x13 + - \_\_le32 + - \_\_fc\_len + - Length of the fast commit block in terms of number of blocks + * - 0x17 + - \_\_le32 + - fc\_ino + - Inode number of the inode that will be recovered using this fast commit + * - 0x2B + - struct ext4\_inode + - inode + - On-disk copy of the inode at the commit time + * - <Variable based on inode size> + - struct ext4\_fc\_tl + - Array of struct ext4\_fc\_tl + - The actual delta with the last commit. Starting at this offset, + there is an array of TLVs that indicates which all extents + should be present in the corresponding inode. Currently, + following tags are supported: EXT4\_FC\_TAG\_EXT (extent that + should be present in the inode), EXT4\_FC\_TAG\_HOLE (extent + that should be removed from the inode), EXT4\_FC\_TAG\_ADD\_DENTRY + (dentry that should be linked), EXT4\_FC\_TAG\_DEL\_DENTRY + (dentry that should be unlinked), EXT4\_FC\_TAG\_CREATE\_DENTRY + (dentry that for the file that should be created for the first time).
Documentation/filesystems/journalling.rst +18 -0
@@ -115,6 +115,24 @@ called after each transaction commit. You can also use ``transaction->t_private_list`` for attaching entries to a transaction that need processing when the transaction commits. +JBD2 also allows client file systems to implement file system specific +commits which are called as ``fast commits``. Fast commits are +asynchronous in nature i.e. file systems can call their own commit +functions at any time. In order to avoid the race with kjournald +thread and other possible fast commits that may be happening in +parallel, file systems should first call +:c:func:`jbd2_start_async_fc()`. File system can call +:c:func:`jbd2_map_fc_buf()` to get buffers reserved for fast +commits. Once a fast commit is completed, file system should call +:c:func:`jbd2_stop_async_fc()` to indicate and unblock other +committers and the kjournald thread. After performing either a fast +or a full commit, JBD2 calls ``journal->j_fc_cleanup_cb`` to allow +file systems to perform cleanups for their internal fast commit +related data structures. At the replay time, JBD2 passes each and +every fast commit block to the file system via +``journal->j_fc_replay_cb``. Ext4 effectively uses this fast commit +mechanism to improve journal commit performance. + JBD2 also provides a way to block all transaction updates via :c:func:`jbd2_journal_lock_updates()` / :c:func:`jbd2_journal_unlock_updates()`. Ext4 uses this when it wants a
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 2/20 ext4: add handling for extended mount options
We are running out of mount option bits. Add handling for using s_mount_opt2. Add ability to turn on / off the fast commit feature and to turn on / off fast commit soft consistency option.
--- fs/ext4/ext4.h | 7 +++++++ fs/ext4/super.c | 23 +++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-)
fs/ext4/ext4.h +7 -0
@@ -1173,6 +1173,13 @@ struct ext4_inode_info {#define EXT4_MOUNT2_EXPLICIT_JOURNAL_CHECKSUM 0x00000008/* User explicitly specified journal checksum */ +#define EXT4_MOUNT2_JOURNAL_FAST_COMMIT 0x00000010/* Journal fast commit */ + +#define EXT4_MOUNT2_JOURNAL_FC_SOFT_CONSISTENCY 0x00000020/* Soft consistency +* mode for fast +* commits +*/ +#define clear_opt (sb, opt) EXT4_SB(sb)->s_mount_opt &= \ ~EXT4_MOUNT_##opt#define set_opt (sb, opt) EXT4_SB(sb)->s_mount_opt |= \
fs/ext4/super.c +19 -4
@@ -1526,6 +1526,7 @@ enum { Opt_dioread_nolock, Opt_dioread_lock, Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache, + Opt_no_fc, Opt_fc_soft_consistency }; static const match_table_t tokens = {
@@ -1609,6 +1610,8 @@ static const match_table_t tokens = { {Opt_init_itable, "init_itable=%u"}, {Opt_init_itable, "init_itable"}, {Opt_noinit_itable, "noinit_itable"}, + {Opt_no_fc, "no_fc"}, + {Opt_fc_soft_consistency, "fc_soft_consistency"}, {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_test_dummy_encryption, "test_dummy_encryption"}, {Opt_nombcache, "nombcache"},
@@ -1731,6 +1734,7 @@ static int clear_qf_name(struct super_block *sb, int qtype)#define MOPT_NO_EXT3 0x0200#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3)#define MOPT_STRING 0x0400 +#define MOPT_2 0x0800 static const struct mount_opts { int token;
@@ -1823,6 +1827,10 @@ static const struct mount_opts { {Opt_max_dir_size_kb, 0, MOPT_GTE0}, {Opt_test_dummy_encryption, 0, MOPT_GTE0}, {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET}, + {Opt_no_fc, EXT4_MOUNT2_JOURNAL_FAST_COMMIT, + MOPT_CLEAR | MOPT_2 | MOPT_EXT4_ONLY}, + {Opt_fc_soft_consistency, EXT4_MOUNT2_JOURNAL_FC_SOFT_CONSISTENCY, + MOPT_SET | MOPT_2 | MOPT_EXT4_ONLY}, {Opt_err, 0, 0} };
@@ -2113,10 +2121,17 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,WARN_ON (1 );return -1 ; } -if (arg !=0 ) - sbi->s_mount_opt |= m->mount_opt; -else - sbi->s_mount_opt &= ~m->mount_opt; +if (m->flags &MOPT_2 ) { +if (arg !=0 ) + sbi->s_mount_opt2 |= m->mount_opt; +else + sbi->s_mount_opt2 &= ~m->mount_opt; + }else { +if (arg !=0 ) + sbi->s_mount_opt |= m->mount_opt; +else + sbi->s_mount_opt &= ~m->mount_opt; + } }return 1 ; }
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 3/20 ext4, jbd2: add fast commit initialization routines
In reply to Harshad ShirwadkarDefine feature flags for fast commits and add routines to allow ext4 to initialize fast commits. Note that we allow 128 blocks to be used for fast commits. As of now, that's the default constant value.
--- fs/ext4/ext4.h | 2 ++ fs/ext4/ext4_jbd2.c | 6 ++++++ fs/ext4/ext4_jbd2.h | 13 +++++++++++++ fs/ext4/super.c | 5 +++++ fs/jbd2/journal.c | 11 +++++++++++ include/linux/jbd2.h | 19 ++++++++++++++++++- 6 files changed, 55 insertions(+), 1 deletion(-)
fs/ext4/ext4.h +2 -0
@@ -1771,6 +1771,7 @@ static inline bool ext4_verity_in_progress(struct inode *inode)#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 +#define EXT4_FEATURE_COMPAT_FAST_COMMIT 0x0400#define EXT4_FEATURE_COMPAT_STABLE_INODES 0x0800#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
@@ -1873,6 +1874,7 @@ EXT4_FEATURE_COMPAT_FUNCS(xattr, EXT_ATTR) EXT4_FEATURE_COMPAT_FUNCS(resize_inode, RESIZE_INODE) EXT4_FEATURE_COMPAT_FUNCS(dir_index, DIR_INDEX) EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, SPARSE_SUPER2) +EXT4_FEATURE_COMPAT_FUNCS(fast_commit, FAST_COMMIT) EXT4_FEATURE_COMPAT_FUNCS(stable_inodes, STABLE_INODES)EXT4_FEATURE_RO_COMPAT_FUNCS (sparse_super,SPARSE_SUPER )
fs/ext4/ext4_jbd2.c +6 -0
@@ -371,3 +371,9 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,mark_buffer_dirty (bh);return err; } +void ext4_init_fast_commit (struct super_block *sb,journal_t *journal) +{ +if (!ext4_should_fast_commit (sb)) +return ; +jbd2_init_fast_commit (journal,EXT4_NUM_FC_BLKS ); +}
fs/ext4/ext4_jbd2.h +13 -0
@@ -440,6 +440,17 @@ static inline int ext4_jbd2_inode_add_wait(handle_t *handle,return 0 ; } +static inline int ext4_should_fast_commit (struct super_block *sb) +{ +if (!ext4_has_feature_fast_commit (sb)) +return 0 ; +if (!test_opt2 (sb,JOURNAL_FAST_COMMIT )) +return 0 ; +if (test_opt (sb,QUOTA )) +return 0 ; +return 1 ; +} +static inline void ext4_update_inode_fsync_trans (handle_t *handle,struct inode *inode,int datasync)
@@ -515,4 +526,6 @@ static inline int ext4_should_dioread_nolock(struct inode *inode) return 1; } +#define EXT4_NUM_FC_BLKS 128 +void ext4_init_fast_commit (struct super_block *sb,journal_t *journal);#endif /* _EXT4_JBD2_H */
fs/ext4/super.c +5 -0
@@ -3804,6 +3804,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)#ifdef CONFIG_EXT4_FS_POSIX_ACL set_opt (sb,POSIX_ACL );#endif +if (ext4_has_feature_fast_commit (sb)) +set_opt2 (sb,JOURNAL_FAST_COMMIT ); +/* don't forget to enable journal_csum when metadata_csum is enabled. */ if (ext4_has_metadata_csum (sb))set_opt (sb,JOURNAL_CHECKSUM );
@@ -4454,6 +4457,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM ;clear_opt (sb,JOURNAL_CHECKSUM );clear_opt (sb,DATA_FLAGS ); +clear_opt2 (sb,JOURNAL_FAST_COMMIT ); sbi->s_journal =NULL ; needs_recovery =0 ; goto no_journal;
@@ -4812,6 +4816,7 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal) journal->j_commit_interval = sbi->s_commit_interval; journal->j_min_batch_time = sbi->s_min_batch_time; journal->j_max_batch_time = sbi->s_max_batch_time; +ext4_init_fast_commit (sb, journal);write_lock (&journal->j_state_lock);if (test_opt (sb,BARRIER ))
fs/jbd2/journal.c +11 -0
@@ -1196,6 +1196,14 @@ static journal_t *journal_init_common(struct block_device *bdev,return NULL ; } +void jbd2_init_fast_commit (journal_t *journal,int num_fc_blks) +{ + journal->j_fc_wbufsize = num_fc_blks; + journal->j_wbufsize = journal->j_blocksize /sizeof (journal_block_tag_t) + - journal->j_fc_wbufsize; + journal->j_fc_wbuf = &journal->j_wbuf[journal->j_wbufsize]; +} +/* jbd2_journal_init_dev and jbd2_journal_init_inode: * * Create a journal structure assigned some fixed set of disk blocks to
@@ -1722,6 +1730,9 @@ int jbd2_journal_load(journal_t *journal)*/ journal->j_flags &= ~JBD2_ABORT ; +if (journal->j_fc_wbufsize >0 ) +jbd2_journal_set_features (journal,0 ,0 , +JBD2_FEATURE_INCOMPAT_FAST_COMMIT );/* OK, we've finished with the dynamic journal bits: * reinitialise the dynamic contents of the superblock in memory * and reset them on disk. */
include/linux/jbd2.h +18 -1
@@ -288,6 +288,7 @@ typedef struct journal_superblock_s#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004#define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008#define JBD2_FEATURE_INCOMPAT_CSUM_V3 0x00000010 +#define JBD2_FEATURE_INCOMPAT_FAST_COMMIT 0x00000020/* See "journal feature predicate functions" below */
@@ -298,7 +299,8 @@ typedef struct journal_superblock_sJBD2_FEATURE_INCOMPAT_64BIT | \JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | \JBD2_FEATURE_INCOMPAT_CSUM_V2 | \ - JBD2_FEATURE_INCOMPAT_CSUM_V3) +JBD2_FEATURE_INCOMPAT_CSUM_V3 | \ + JBD2_FEATURE_INCOMPAT_FAST_COMMIT) #ifdef __KERNEL__
@@ -1058,6 +1060,12 @@ struct journal_s*/ struct buffer_head **j_wbuf; +/** +* @j_fc_wbuf: Array of fast commit bhs for +* jbd2_journal_commit_transaction. +*/ +struct buffer_head **j_fc_wbuf; +/** * @j_wbufsize: *
@@ -1065,6 +1073,13 @@ struct journal_s*/ int j_wbufsize; +/** +* @j_fc_wbufsize: +* +* Size of @j_fc_wbuf array. +*/ +int j_fc_wbufsize; +/** * @j_last_sync_writer: *
@@ -1234,6 +1249,7 @@ JBD2_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT) JBD2_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT) JBD2_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2) JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3) +JBD2_FEATURE_INCOMPAT_FUNCS (fast_commit,FAST_COMMIT )/* * Journal flag definitions
@@ -1500,6 +1516,7 @@ void __jbd2_log_wait_for_space(journal_t *journal);extern void __jbd2_journal_drop_transaction (journal_t *,transaction_t *);extern int jbd2_cleanup_journal_tail (journal_t *); +void jbd2_init_fast_commit (journal_t *journal,int num_fc_blks);/* * is_journal_abort *
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 4/20 jbd2: add fast commit block tracker variables
In reply to Harshad ShirwadkarAdd j_first_fc, j_last_fc and j_fc_offset variables to track fast commit area. j_first_fc and j_last_fc mark the start and the end of the area, while j_fc_offset points to the last used block in the region.
--- fs/jbd2/journal.c | 33 ++++++++++++++++++++++++++++----- include/linux/jbd2.h | 24 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-)
fs/jbd2/journal.c +28 -5
@@ -1178,6 +1178,11 @@ static journal_t *journal_init_common(struct block_device *bdev,if (!journal->j_wbuf) goto err_cleanup; +if (journal->j_fc_wbufsize >0 ) { + journal->j_wbufsize = n - journal->j_fc_wbufsize; + journal->j_fc_wbuf = &journal->j_wbuf[journal->j_wbufsize]; + } + bh =getblk_unmovable (journal->j_dev, start, journal->j_blocksize);if (!bh) { pr_err("%s: Cannot get buffer for journal superblock\n",
@@ -1321,11 +1326,20 @@ static int journal_reset(journal_t *journal) } journal->j_first = first; - journal->j_last = last; - journal->j_head = first; - journal->j_tail = first; - journal->j_free = last - first; +if (jbd2_has_feature_fast_commit (journal) && + journal->j_fc_wbufsize >0 ) { + journal->j_last_fc = last; + journal->j_last = last - journal->j_fc_wbufsize; + journal->j_first_fc = journal->j_last +1 ; + journal->j_fc_off =0 ; + }else { + journal->j_last = last; + } + + journal->j_head = journal->j_first; + journal->j_tail = journal->j_first; + journal->j_free = journal->j_last - journal->j_first; journal->j_tail_sequence = journal->j_transaction_sequence; journal->j_commit_sequence = journal->j_transaction_sequence -1 ;
@@ -1667,9 +1681,18 @@ static int load_superblock(journal_t *journal) journal->j_tail_sequence =be32_to_cpu (sb->s_sequence); journal->j_tail =be32_to_cpu (sb->s_start); journal->j_first =be32_to_cpu (sb->s_first); - journal->j_last =be32_to_cpu (sb->s_maxlen); journal->j_errno =be32_to_cpu (sb->s_errno); +if (jbd2_has_feature_fast_commit (journal) && + journal->j_fc_wbufsize >0 ) { + journal->j_last_fc =be32_to_cpu (sb->s_maxlen); + journal->j_last = journal->j_last_fc - journal->j_fc_wbufsize; + journal->j_first_fc = journal->j_last +1 ; + journal->j_fc_off =0 ; + }else { + journal->j_last =be32_to_cpu (sb->s_maxlen); + } +return 0 ; }
include/linux/jbd2.h +24 -0
@@ -910,6 +910,30 @@ struct journal_s*/ unsigned long j_last; +/** +* @j_first_fc: +* +* The block number of the first fast commit block in the journal +* [j_state_lock]. +*/ +unsigned long j_first_fc; + +/** +* @j_fc_off: +* +* Number of fast commit blocks currently allocated. +* [j_state_lock]. +*/ +unsigned long j_fc_off; + +/** +* @j_last_fc: +* +* The block number one beyond the last fast commit block in the journal +* [j_state_lock]. +*/ +unsigned long j_last_fc; +/** * @j_dev: Device where we store the journal. */
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 5/20 jbd2: disable fast commits if journal is empty
In reply to Harshad ShirwadkarIf journal is empty, clear the fast commit flag from the on disk superblock. With this optimization, chances of running into backward compatibility issues are reduced.
--- fs/jbd2/journal.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/jbd2/journal.c +12 -0
@@ -1482,6 +1482,7 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid,static void jbd2_mark_journal_empty (journal_t *journal,int write_op) {journal_superblock_t *sb = journal->j_superblock; +bool had_fast_commit = false;BUG_ON (!mutex_is_locked (&journal->j_checkpoint_mutex));lock_buffer (journal->j_sb_buffer);
@@ -1495,9 +1496,20 @@ static void jbd2_mark_journal_empty(journal_t *journal, int write_op) sb->s_sequence =cpu_to_be32 (journal->j_tail_sequence); sb->s_start =cpu_to_be32 (0 ); +if (jbd2_has_feature_fast_commit (journal)) { +/* +* When journal is clean, no need to commit fast commit flag and +* make file system incompatible with older kernels. +*/ +jbd2_clear_feature_fast_commit (journal); + had_fast_commit = true; + }jbd2_write_superblock (journal, write_op); +if (had_fast_commit) +jbd2_set_feature_fast_commit (journal); +/* Log is no longer empty */ write_lock (&journal->j_state_lock); journal->j_flags |=JBD2_FLUSHED ;
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 7/20 ext4: add generic diff tracking routines and range tracking
In reply to Harshad ShirwadkarIn fast commits, we need to track changes that have been made to the file system since last full commit. Add generic diff tracking infrastructure. We use those helpers to track logical block ranges that have been affected for inodes. The diff tracking helpers are used in following patches to track directory entry updates as well.
--- fs/ext4/ext4.h | 32 ++++++++++ fs/ext4/ext4_jbd2.c | 121 ++++++++++++++++++++++++++++++++++++ fs/ext4/ext4_jbd2.h | 3 + fs/ext4/inode.c | 18 ++++++ fs/ext4/super.c | 5 ++ include/trace/events/ext4.h | 27 ++++++++ 6 files changed, 206 insertions(+)
fs/ext4/ext4.h +32 -0
@@ -984,6 +984,32 @@ struct ext4_inode_info {struct list_head i_orphan;/* unlinked but open inodes */ +struct list_head i_fc_list;/* +* inodes that need fast commit +* protected by sbi->s_fc_lock. +*/ +/* +* TID of when this struct was last updated. If fc_tid != +* running transaction tid, then none of the other fields in this +* struct are valid. Don't directly modify fields in this struct. +* Use wrappers provided in ext4_jbd2.c. +*/ +tid_t i_fc_tid; + +/* +* Start of logical block range that needs to be committed in +* this fast commit. +*/ +ext4_lblk_t i_fc_lblk_start; + +/* +* End of logical block range that needs to be committed in this fast +* commit +*/ +ext4_lblk_t i_fc_lblk_end; + +rwlock_t i_fc_lock; +/* * i_disksize keeps track of what the inode size is ON DISK, not * in memory. During truncate, i_size is set to the new size by
@@ -1103,6 +1129,7 @@ struct ext4_inode_info {#define EXT4_VALID_FS 0x0001/* Unmounted cleanly */ #define EXT4_ERROR_FS 0x0002/* Errors detected */ #define EXT4_ORPHAN_FS 0x0004/* Orphans being recovered */ +#define EXT4_FC_REPLAY 0x0008/* Fast commit replay ongoing */ /* * Misc. filesystem flags
@@ -1568,6 +1595,11 @@ struct ext4_sb_info {#ifdef CONFIG_EXT4_DEBUG unsigned long s_simulate_fail;#endif +/* Ext4 fast commit stuff */ +struct list_head s_fc_q;/* Inodes staged for fast commit +* that have data changes in them. +*/ +spinlock_t s_fc_lock; };static inline struct ext4_sb_info *EXT4_SB (struct super_block *sb)
fs/ext4/ext4_jbd2.c +121 -0
127 lines not on this page · raw message
fs/ext4/ext4_jbd2.h +3 -0
@@ -528,4 +528,7 @@ static inline int ext4_should_dioread_nolock(struct inode *inode)#define EXT4_NUM_FC_BLKS 128void ext4_init_fast_commit (struct super_block *sb,journal_t *journal); +void ext4_init_inode_fc_info (struct inode *inode); +void ext4_fc_track_range (struct inode *inode,ext4_lblk_t start, +ext4_lblk_t end);#endif /* _EXT4_JBD2_H */
fs/ext4/inode.c +18 -0
@@ -726,6 +726,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,if (ret)return ret; } +ext4_fc_track_range (inode, map->m_lblk, + map->m_lblk + map->m_len -1 ); }return retval; }
@@ -4055,6 +4057,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)up_write (&EXT4_I (inode)->i_data_sem); } +ext4_fc_track_range (inode, first_block, stop_block);if (IS_SYNC (inode))ext4_handle_sync (handle);
@@ -4670,6 +4673,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,for (block =0 ; block <EXT4_N_BLOCKS ; block++) ei->i_data[block] = raw_inode->i_block[block];INIT_LIST_HEAD (&ei->i_orphan); +ext4_init_inode_fc_info (&ei->vfs_inode);/* * Set transaction id's of transactions that have to be committed
@@ -5338,6 +5342,20 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) inode->i_mtime =current_time (inode); inode->i_ctime = inode->i_mtime; } + +if (shrink) +ext4_fc_track_range ( + inode, attr->ia_size >> + inode->i_sb->s_blocksize_bits, + oldsize >> + inode->i_sb->s_blocksize_bits); +else +ext4_fc_track_range ( + inode, oldsize >> + inode->i_sb->s_blocksize_bits, + attr->ia_size >> + inode->i_sb->s_blocksize_bits); +down_write (&EXT4_I (inode)->i_data_sem);EXT4_I (inode)->i_disksize = attr->ia_size; rc =ext4_mark_inode_dirty (handle, inode);
fs/ext4/super.c +5 -0
@@ -1154,6 +1154,8 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) ei->i_datasync_tid =0 ;atomic_set (&ei->i_unwritten,0 );INIT_WORK (&ei->i_rsv_conversion_work, ext4_end_io_rsv_work); +ext4_init_inode_fc_info (&ei->vfs_inode); +rwlock_init (&ei->i_fc_lock);return &ei->vfs_inode; }
@@ -1196,6 +1198,7 @@ static void init_once(void *foo)init_rwsem (&ei->i_data_sem);init_rwsem (&ei->i_mmap_sem);inode_init_once (&ei->vfs_inode); +ext4_init_inode_fc_info (&ei->vfs_inode); }static int __init init_inodecache (void )
@@ -4408,6 +4411,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)INIT_LIST_HEAD (&sbi->s_orphan);/* unlinked but open files */ mutex_init (&sbi->s_orphan_lock); +INIT_LIST_HEAD (&sbi->s_fc_q); +spin_lock_init (&sbi->s_fc_lock); sb->s_root =NULL ; needs_recovery = (es->s_last_orphan != 0 ||
include/trace/events/ext4.h +27 -0
@@ -2723,6 +2723,33 @@ TRACE_EVENT(ext4_error, __entry->function, __entry->line) ); +TRACE_EVENT (ext4_fc_track_range, + TP_PROTO(struct inode *inode, long start, long end, int ret), + +TP_ARGS (inode, start, end, ret), + +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(int, ino) + __field(long, start) + __field(long, end) +__field (int, error) + ), + +TP_fast_assign ( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->start = start; + __entry->end = end; + __entry->error = ret; + ), + +TP_printk ("dev %d:%d, inode %d, error %d, start %ld, end %ld" , +MAJOR (__entry->dev),MINOR (__entry->dev), + __entry->ino, __entry->error, __entry->start, + __entry->end) + ); +#endif /* _TRACE_EXT4_H */ /* This part must be outside protection */
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 8/20 ext4: add directory entry tracking routines
In reply to Harshad ShirwadkarAdds directory entry change tracking routines for fast commits. Use an in-memory list of directory updates to track directory entry updates.
--- fs/ext4/ext4.h | 26 +++++++++ fs/ext4/ext4_jbd2.c | 102 ++++++++++++++++++++++++++++++++++++ fs/ext4/ext4_jbd2.h | 4 ++ fs/ext4/super.c | 7 +++ include/trace/events/ext4.h | 28 ++++++++++ 5 files changed, 167 insertions(+)
fs/ext4/ext4.h +26 -0
@@ -951,6 +951,26 @@ enum { }; +/* Fast commit tags */ +#define EXT4_FC_TAG_ADD_RANGE 0x1 +#define EXT4_FC_TAG_DEL_RANGE 0x2 +#define EXT4_FC_TAG_CREAT_DENTRY 0x3 +#define EXT4_FC_TAG_ADD_DENTRY 0x4 +#define EXT4_FC_TAG_DEL_DENTRY 0x5 + +/* +* In memory list of dentry updates that are performed on the file +* system used by fast commit code. +*/ +struct ext4_fc_dentry_update { +int fcd_op;/* Type of update create / add / del */ +int fcd_parent;/* Parent inode number */ +int fcd_ino;/* Inode number */ +struct qstr fcd_name;/* Dirent name qstr */ +unsigned char fcd_iname[DNAME_INLINE_LEN ];/* Dirent name string */ +struct list_head fcd_list; +}; +/* * fourth extended file system inode data in memory */
@@ -1010,6 +1030,11 @@ struct ext4_inode_info {rwlock_t i_fc_lock; +/* +* Last mdata / dirent update that happened on this inode. +*/ +struct ext4_fc_dentry_update *i_fc_mdata_update; +/* * i_disksize keeps track of what the inode size is ON DISK, not * in memory. During truncate, i_size is set to the new size by
@@ -1599,6 +1624,7 @@ struct ext4_sb_info {struct list_head s_fc_q;/* Inodes staged for fast commit * that have data changes in them. */ +struct list_head s_fc_dentry_q;spinlock_t s_fc_lock; };
fs/ext4/ext4_jbd2.c +102 -0
123 lines not on this page · raw message
fs/ext4/ext4_jbd2.h +4 -0
@@ -531,4 +531,8 @@ void ext4_init_fast_commit(struct super_block *sb, journal_t *journal);void ext4_init_inode_fc_info (struct inode *inode);void ext4_fc_track_range (struct inode *inode,ext4_lblk_t start,ext4_lblk_t end); +void ext4_fc_track_unlink (struct inode *inode,struct dentry *dentry); +void ext4_fc_track_link (struct inode *inode,struct dentry *dentry); +void ext4_fc_track_create (struct inode *inode,struct dentry *dentry); +int __init ext4_init_fc_dentry_cache (void );#endif /* _EXT4_JBD2_H */
fs/ext4/super.c +7 -0
@@ -4412,6 +4412,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)mutex_init (&sbi->s_orphan_lock);INIT_LIST_HEAD (&sbi->s_fc_q); +INIT_LIST_HEAD (&sbi->s_fc_dentry_q);spin_lock_init (&sbi->s_fc_lock); sb->s_root =NULL ;
@@ -6245,6 +6246,11 @@ static int __init ext4_init_fs(void) err =init_inodecache ();if (err) goto out1; + + err =ext4_init_fc_dentry_cache (); +if (err) + goto out05; +register_as_ext3 ();register_as_ext2 (); err =register_filesystem (&ext4_fs_type);
@@ -6255,6 +6261,7 @@ static int __init ext4_init_fs(void) out:unregister_as_ext2 ();unregister_as_ext3 (); +out05:destroy_inodecache (); out1:ext4_exit_mballoc ();
include/trace/events/ext4.h +28 -0
@@ -2723,6 +2723,34 @@ TRACE_EVENT(ext4_error, __entry->function, __entry->line) ); +#define DEFINE_TRACE_DENTRY_EVENT (__type) \ + TRACE_EVENT(ext4_fc_track_##__type, \ + TP_PROTO(struct inode *inode, struct dentry *dentry, int ret), \ + \ + TP_ARGS(inode, dentry, ret), \ + \ + TP_STRUCT__entry( \ + __field(dev_t, dev) \ + __field(int, ino) \ + __field(int, error) \ + ), \ + \ + TP_fast_assign( \ + __entry->dev = inode->i_sb->s_dev; \ + __entry->ino = inode->i_ino; \ + __entry->error = ret; \ + ), \ + \ + TP_printk("dev %d:%d, inode %d, error %d, fc_%s", \ + MAJOR(__entry->dev), MINOR(__entry->dev), \ + __entry->ino, __entry->error, \ + #__type) \ + ) + +DEFINE_TRACE_DENTRY_EVENT (create); +DEFINE_TRACE_DENTRY_EVENT (link); +DEFINE_TRACE_DENTRY_EVENT (unlink); + TRACE_EVENT(ext4_fc_track_range, TP_PROTO(struct inode *inode, long start, long end, int ret),
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 6/20 jbd2: fast commit main commit path changes
In reply to Harshad ShirwadkarAdd 3 new APIs jbd2_start_async_fc_nowait(), jbd2_start_async_fc_wait() and jbd2_stop_async_fc(). These APIs can be used by file systems to indicate to jbd2 that they are starting or stopping a fast commit.
--- fs/jbd2/commit.c | 21 +++++++++++ fs/jbd2/journal.c | 85 +++++++++++++++++++++++++++++++++++++++++++- include/linux/jbd2.h | 21 +++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-)
fs/jbd2/commit.c +21 -0
@@ -413,6 +413,23 @@ void jbd2_journal_commit_transaction(journal_t *journal)J_ASSERT (journal->j_running_transaction !=NULL );J_ASSERT (journal->j_committing_transaction ==NULL ); +write_lock (&journal->j_state_lock); + journal->j_flags |=JBD2_FULL_COMMIT_ONGOING ; +while (journal->j_flags &JBD2_FAST_COMMIT_ONGOING ) { +DEFINE_WAIT (wait); + +prepare_to_wait (&journal->j_wait_async_fc, &wait, +TASK_UNINTERRUPTIBLE ); +write_unlock (&journal->j_state_lock); +schedule (); +write_lock (&journal->j_state_lock); +finish_wait (&journal->j_wait_async_fc, &wait); + } +write_unlock (&journal->j_state_lock); + +if (journal->j_fc_cleanup_callback) + journal->j_fc_cleanup_callback (journal); + commit_transaction = journal->j_running_transaction;trace_jbd2_start_commit (journal, commit_transaction);
@@ -420,6 +437,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) commit_transaction->t_tid);write_lock (&journal->j_state_lock); + journal->j_fc_off =0 ;J_ASSERT (commit_transaction->t_state ==T_RUNNING ); commit_transaction->t_state =T_LOCKED ;
@@ -1124,6 +1142,8 @@ void jbd2_journal_commit_transaction(journal_t *journal) journal->j_commit_sequence, journal->j_tail_sequence);write_lock (&journal->j_state_lock); + journal->j_flags &= ~JBD2_FULL_COMMIT_ONGOING ; + journal->j_flags &= ~JBD2_FAST_COMMIT_ONGOING ;spin_lock (&journal->j_list_lock); commit_transaction->t_state =T_FINISHED ;/* Check if the transaction can be dropped now that we are finished */
@@ -1135,6 +1155,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)spin_unlock (&journal->j_list_lock);write_unlock (&journal->j_state_lock);wake_up (&journal->j_wait_done_commit); +wake_up (&journal->j_wait_async_fc);/* * Calculate overall stats
fs/jbd2/journal.c +84 -1
103 lines not on this page · raw message
include/linux/jbd2.h +21 -0
@@ -853,6 +853,13 @@ struct journal_s*/ wait_queue_head_t j_wait_reserved; +/** +* @j_wait_async_fc: +* +* Wait queue to wait for completion of async fast commits. +*/ +wait_queue_head_t j_wait_async_fc; +/** * @j_checkpoint_mutex: *
@@ -1203,6 +1210,14 @@ struct journal_s*/ struct lockdep_map j_trans_commit_map;#endif + +/** +* @j_fc_cleanup_callback: +* +* Clean-up after fast commit or full commit. JBD2 calls this function +* after every commit operation. +*/ +void (*j_fc_cleanup_callback)(struct journal_s *journal); };#define jbd2_might_wait_for_commit (j) \
@@ -1288,6 +1303,8 @@ JBD2_FEATURE_INCOMPAT_FUNCS(fast_commit, FAST_COMMIT)* data write error in ordered * mode */ #define JBD2_REC_ERR 0x080/* The errno in the sb has been recorded */ +#define JBD2_FAST_COMMIT_ONGOING 0x100/* Fast commit is ongoing */ +#define JBD2_FULL_COMMIT_ONGOING 0x200/* Full commit is ongoing */ /* * Function declarations for the journaling transaction and buffer
@@ -1540,6 +1557,10 @@ void __jbd2_log_wait_for_space(journal_t *journal);extern void __jbd2_journal_drop_transaction (journal_t *,transaction_t *);extern int jbd2_cleanup_journal_tail (journal_t *); +/* Fast commit related APIs */ +int jbd2_start_async_fc_nowait (journal_t *journal,tid_t tid); +int jbd2_start_async_fc_wait (journal_t *journal,tid_t tid); +void jbd2_stop_async_fc (journal_t *journal,tid_t tid);void jbd2_init_fast_commit (journal_t *journal,int num_fc_blks);/* * is_journal_abort
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 9/20 ext4: add inode tracking and ineligible marking routines
In reply to Harshad ShirwadkarUnder certain situations, such as zeroing a range, there are only data updates and no metadata updates. We need to track such inodes for fast commits. Also, under some situations, we need to fall back to full commits because remembering the delta is either not yet supported or fast commits won't be "fast" enough. In such cases, we need to mark inodes as ineligible for fast commits. Add routines that allow tracking just the inodes and marking inodes as well as entire file system as fast commit ineligible.
--- fs/ext4/ext4.h | 2 ++ fs/ext4/ext4_jbd2.c | 57 +++++++++++++++++++++++++++++++++++++ fs/ext4/ext4_jbd2.h | 4 +++ fs/ext4/super.c | 1 + include/trace/events/ext4.h | 22 ++++++++++++++ 5 files changed, 86 insertions(+)
fs/ext4/ext4.h +2 -0
@@ -1155,6 +1155,7 @@ struct ext4_inode_info {#define EXT4_ERROR_FS 0x0002/* Errors detected */ #define EXT4_ORPHAN_FS 0x0004/* Orphans being recovered */ #define EXT4_FC_REPLAY 0x0008/* Fast commit replay ongoing */ +#define EXT4_FC_INELIGIBLE 0x0010/* Fast commit ineligible */ /* * Misc. filesystem flags
@@ -1736,6 +1737,7 @@ enum {EXT4_STATE_EXT_PRECACHED ,/* extents have been precached */ EXT4_STATE_LUSTRE_EA_INODE ,/* Lustre-style ea_inode */ EXT4_STATE_VERITY_IN_PROGRESS ,/* building fs-verity Merkle tree */ + EXT4_STATE_FC_ELIGIBLE, /* File is Fast commit eligible */ };#define EXT4_INODE_BIT_FNS (name, field, offset) \
fs/ext4/ext4_jbd2.c +57 -0
85 lines not on this page · raw message
fs/ext4/ext4_jbd2.h +4 -0
@@ -535,4 +535,8 @@ void ext4_fc_track_unlink(struct inode *inode, struct dentry *dentry);void ext4_fc_track_link (struct inode *inode,struct dentry *dentry);void ext4_fc_track_create (struct inode *inode,struct dentry *dentry);int __init ext4_init_fc_dentry_cache (void ); +void ext4_fc_track_inode (struct inode *inode); +void ext4_fc_mark_ineligible (struct inode *inode,int reason); +void ext4_fc_disable (struct super_block *sb,int reason); +#endif /* _EXT4_JBD2_H */
fs/ext4/super.c +1 -0
@@ -4413,6 +4413,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)INIT_LIST_HEAD (&sbi->s_fc_q);INIT_LIST_HEAD (&sbi->s_fc_dentry_q); + sbi->s_mount_state &= ~EXT4_FC_INELIGIBLE ;spin_lock_init (&sbi->s_fc_lock); sb->s_root =NULL ;
include/trace/events/ext4.h +22 -0
@@ -2751,6 +2751,28 @@ DEFINE_TRACE_DENTRY_EVENT(create);DEFINE_TRACE_DENTRY_EVENT (link);DEFINE_TRACE_DENTRY_EVENT (unlink); +TRACE_EVENT (ext4_fc_track_inode, + TP_PROTO(struct inode *inode, int ret), + +TP_ARGS (inode, ret), + +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(int, ino) +__field (int, error) + ), + +TP_fast_assign ( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->error = ret; + ), + +TP_printk ("dev %d:%d, inode %d, error %d" , +MAJOR (__entry->dev),MINOR (__entry->dev), + __entry->ino, __entry->error) + ); + TRACE_EVENT(ext4_fc_track_range, TP_PROTO(struct inode *inode, long start, long end, int ret),
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 10/20 ext4: break ext4_unlink() and ext4_link()
In reply to Harshad ShirwadkarBreak ext4_link() and ext4_unlink() each into 2 parts in order to make them usable in recovery path as well.
--- fs/ext4/ext4.h | 4 ++ fs/ext4/namei.c | 139 +++++++++++++++++++++++++++++------------------- 2 files changed, 88 insertions(+), 55 deletions(-)
fs/ext4/ext4.h +4 -0
@@ -3348,6 +3348,10 @@ extern int ext4_handle_dirty_dirblock(handle_t *handle, struct inode *inode,extern int ext4_ci_compare (const struct inode *parent,const struct qstr *fname,const struct qstr *entry,bool quick); +extern int __ext4_unlink (struct inode *dir,const struct qstr *d_name, +struct inode *inode); +extern int __ext4_link (struct inode *dir,struct inode *inode, +struct dentry *dentry);#define S_SHIFT 12static const unsigned char ext4_type_by_mode[(S_IFMT >>S_SHIFT ) +1 ] = {
fs/ext4/namei.c +84 -55
190 lines not on this page · raw message
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 11/20 ext4: add fast commit track points
In reply to Harshad ShirwadkarPrevious patches in the series have added following tracking routines:
- ext4_fc_track_inode() -> tracks just the inode
- ext4_fc_track_create() -> tracks creation of an inode and remembers its dirent
- ext4_fc_track_unlink() -> tracks inode unlink
- ext4_fc_track_link() -> tracks inode link
- ext4_fc_mark_ineligible() -> marks inode as ineligible for fast commits
- ext4_fc_disable() -> marks entire file system as fast commit ineligible
Add these different track points at various points in the file system. This patch also adds high level stats to remember reasons why inodes were marked ineligible.
--- fs/ext4/acl.c | 1 + fs/ext4/balloc.c | 3 +++ fs/ext4/ext4.h | 26 ++++++++++++++++++++++++++ fs/ext4/ext4_jbd2.c | 5 +++++ fs/ext4/extents.c | 5 +++++ fs/ext4/inline.c | 3 +++ fs/ext4/inode.c | 6 ++++++ fs/ext4/ioctl.c | 5 +++++ fs/ext4/namei.c | 41 +++++++++++++++++++++++++++++++++++++++-- fs/ext4/super.c | 9 +++++++++ fs/ext4/xattr.c | 6 ++++++ 11 files changed, 108 insertions(+), 2 deletions(-)
fs/ext4/acl.c +1 -0
@@ -257,6 +257,7 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) inode->i_mode = mode; inode->i_ctime =current_time (inode);ext4_mark_inode_dirty (handle, inode); +ext4_fc_track_inode (inode); } out_stop:ext4_journal_stop (handle);
fs/ext4/balloc.c +3 -0
@@ -665,6 +665,9 @@ ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, ar.len = count ? *count :1 ; ar.flags = flags; +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_META_ALLOC ); + ret =ext4_mb_new_blocks (handle, &ar, errp);if (count) *count = ar.len;
fs/ext4/ext4.h +26 -0
@@ -1440,6 +1440,31 @@ struct ext4_super_block {#define ext4_has_strict_mode (sbi) \ (sbi->s_encoding_flags & EXT4_ENC_STRICT_MODE_FL) +/* +* Fast commit ineligible reasons. +*/ +enum { +EXT4_FC_REASON_META_ALLOC , +EXT4_FC_REASON_QUOTA , +EXT4_FC_REASON_XATTR , +EXT4_FC_REASON_CROSS_RENAME , +EXT4_FC_REASON_FALLOC_RANGE_OP , +EXT4_FC_REASON_JOURNAL_FLAG_CHANGE , +EXT4_FC_REASON_DELETE , +EXT4_FC_REASON_MEM , +EXT4_FC_REASON_SWAP_BOOT , +EXT4_FC_REASON_RESIZE , +EXT4_FC_REASON_RENAME_DIR , +EXT4_FC_REASON_MAX +}; + +struct ext4_fc_stats { +int fc_ineligible_reason_count[EXT4_FC_REASON_MAX ]; +int fc_num_commits; +int fc_ineligible_commits; +int fc_numblks; +}; +/* * fourth extended-fs super-block data in memory */
@@ -1627,6 +1652,7 @@ struct ext4_sb_info {*/ struct list_head s_fc_dentry_q;spinlock_t s_fc_lock; +struct ext4_fc_stats s_fc_stats; };static inline struct ext4_sb_info *EXT4_SB (struct super_block *sb)
fs/ext4/ext4_jbd2.c +5 -0
@@ -431,6 +431,8 @@ void ext4_fc_mark_ineligible(struct inode *inode, int reason) (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY)) return; +WARN_ON (reason >=EXT4_FC_REASON_MAX ); + sbi->s_fc_stats.fc_ineligible_reason_count[reason]++;if (sbi->s_journal) ei->i_fc_tid =get_running_txn_tid (inode->i_sb);ext4_clear_inode_state (inode,EXT4_STATE_FC_ELIGIBLE );
@@ -443,6 +445,8 @@ void ext4_fc_disable(struct super_block *sb, int reason)struct ext4_sb_info *sbi =EXT4_SB (sb); sbi->s_mount_state |=EXT4_FC_INELIGIBLE ; +WARN_ON (reason >=EXT4_FC_REASON_MAX ); + sbi->s_fc_stats.fc_ineligible_reason_count[reason]++; }/*
@@ -504,6 +508,7 @@ static int __ext4_dentry_update(struct inode *inode, void *arg, bool update)write_unlock (&ei->i_fc_lock); node =kmem_cache_alloc (ext4_fc_dentry_cachep,GFP_NOFS );if (!node) { +ext4_fc_disable (inode->i_sb,EXT4_FC_REASON_MEM );write_lock (&ei->i_fc_lock);return -ENOMEM ; }
fs/ext4/extents.c +5 -0
@@ -4813,6 +4813,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,ext4_set_inode_flag (inode,EXT4_INODE_EOFBLOCKS ); }ext4_mark_inode_dirty (handle, inode); +ext4_fc_track_inode (inode);/* Zero out partial block at the edges of the range */ ret =ext4_zero_partial_blocks (handle, inode, offset, len);
@@ -5551,6 +5552,8 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)if (IS_SYNC (inode))ext4_handle_sync (handle); inode->i_mtime = inode->i_ctime =current_time (inode); +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_FALLOC_RANGE_OP );ext4_mark_inode_dirty (handle, inode);ext4_update_inode_fsync_trans (handle, inode,1 );
@@ -5661,6 +5664,8 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) inode->i_size += len;EXT4_I (inode)->i_disksize += len; inode->i_mtime = inode->i_ctime =current_time (inode); +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_FALLOC_RANGE_OP ); ret =ext4_mark_inode_dirty (handle, inode);if (ret) goto out_stop;
fs/ext4/inline.c +3 -0
@@ -760,6 +760,7 @@ int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len,ext4_write_unlock_xattr (inode, &no_expand);brelse (iloc.bh); +ext4_fc_track_inode (inode);mark_inode_dirty (inode); out:return copied;
@@ -975,6 +976,7 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,* ordering of page lock and transaction start for journaling * filesystems. */ +ext4_fc_track_inode (inode);mark_inode_dirty (inode);return copied;
@@ -1988,6 +1990,7 @@ int ext4_inline_data_truncate(struct inode *inode, int *has_inline)if (err ==0 ) { inode->i_mtime = inode->i_ctime =current_time (inode); +ext4_fc_track_inode (inode); err =ext4_mark_inode_dirty (handle, inode);if (IS_SYNC (inode))ext4_handle_sync (handle);
fs/ext4/inode.c +6 -0
@@ -2851,6 +2851,7 @@ static int ext4_writepages(struct address_space *mapping, out_writepages:trace_ext4_writepages_result (inode, wbc, ret, nr_to_write - wbc->nr_to_write); +ext4_fc_track_inode (inode);percpu_up_read (&sbi->s_writepages_rwsem);return ret; }
@@ -5282,6 +5283,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)if (attr->ia_valid &ATTR_GID ) inode->i_gid = attr->ia_gid; error =ext4_mark_inode_dirty (handle, inode); +ext4_fc_track_inode (inode);ext4_journal_stop (handle); }
@@ -5400,6 +5402,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)if (!error) {setattr_copy (inode, attr); +ext4_fc_track_inode (inode);mark_inode_dirty (inode); }
@@ -5830,6 +5833,7 @@ void ext4_dirty_inode(struct inode *inode, int flags) goto out;ext4_mark_inode_dirty (handle, inode); +ext4_fc_track_inode (inode);ext4_journal_stop (handle); out:
@@ -5915,6 +5919,8 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)if (IS_ERR (handle))return PTR_ERR (handle); +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_JOURNAL_FLAG_CHANGE ); err =ext4_mark_inode_dirty (handle, inode);ext4_handle_sync (handle);ext4_journal_stop (handle);
fs/ext4/ioctl.c +5 -0
@@ -204,6 +204,8 @@ static long swap_inode_boot_loader(struct super_block *sb,ext4_discard_preallocations (inode); +if (EXT4_SB (sb)->s_journal) +ext4_fc_disable (sb,EXT4_FC_REASON_SWAP_BOOT ); err =ext4_mark_inode_dirty (handle, inode);if (err <0 ) {/* No need to update quota information. */
@@ -397,6 +399,8 @@ static int ext4_ioctl_setflags(struct inode *inode, inode->i_ctime =current_time (inode); err =ext4_mark_iloc_dirty (handle, inode, &iloc); +ext4_fc_track_inode (inode); + flags_err:ext4_journal_stop (handle);if (err)
@@ -1080,6 +1084,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err =ext4_resize_fs (sb, n_blocks_count);if (EXT4_SB (sb)->s_journal) { +ext4_fc_disable (sb,EXT4_FC_REASON_RESIZE );jbd2_journal_lock_updates (EXT4_SB (sb)->s_journal); err2 =jbd2_journal_flush (EXT4_SB (sb)->s_journal);jbd2_journal_unlock_updates (EXT4_SB (sb)->s_journal);
fs/ext4/namei.c +39 -2
109 lines not on this page · raw message
fs/ext4/super.c +9 -0
@@ -1384,6 +1384,7 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,* S_DAX may be disabled */ ext4_set_inode_flags (inode); +ext4_fc_track_inode (inode); res =ext4_mark_inode_dirty (handle, inode);if (res)EXT4_ERROR_INODE (inode,"Failed to mark inode dirty" );
@@ -4415,6 +4416,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)INIT_LIST_HEAD (&sbi->s_fc_dentry_q); sbi->s_mount_state &= ~EXT4_FC_INELIGIBLE ;spin_lock_init (&sbi->s_fc_lock); +memset (&sbi->s_fc_stats,0 ,sizeof (sbi->s_fc_stats)); + sb->s_root =NULL ; needs_recovery = (es->s_last_orphan != 0 ||
@@ -5910,6 +5913,8 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,EXT4_I (inode)->i_flags |=EXT4_NOATIME_FL |EXT4_IMMUTABLE_FL ;inode_set_flags (inode,S_NOATIME |S_IMMUTABLE ,S_NOATIME |S_IMMUTABLE ); +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_QUOTA );ext4_mark_inode_dirty (handle, inode);ext4_journal_stop (handle); unlock_inode:
@@ -6017,6 +6022,8 @@ static int ext4_quota_off(struct super_block *sb, int type)EXT4_I (inode)->i_flags &= ~(EXT4_NOATIME_FL |EXT4_IMMUTABLE_FL );inode_set_flags (inode,0 ,S_NOATIME |S_IMMUTABLE ); inode->i_mtime = inode->i_ctime =current_time (inode); +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_QUOTA );ext4_mark_inode_dirty (handle, inode);ext4_journal_stop (handle); out_unlock:
@@ -6123,6 +6130,8 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,if (inode->i_size < off + len) {i_size_write (inode, off + len);EXT4_I (inode)->i_disksize = inode->i_size; +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_QUOTA );ext4_mark_inode_dirty (handle, inode); }return len;
fs/ext4/xattr.c +6 -0
@@ -2413,6 +2413,8 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,if (IS_SYNC (inode))ext4_handle_sync (handle); } +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_XATTR ); cleanup:brelse (is.iloc.bh);
@@ -2490,6 +2492,8 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name,if (error ==0 ) error = error2; } +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_XATTR );return error; }
@@ -2922,6 +2926,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, error); goto cleanup; } +ext4_fc_mark_ineligible (inode, +EXT4_FC_REASON_XATTR ); } error =0 ; cleanup:
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 13/20 jbd2: add new APIs for commit path of fast commits
In reply to Harshad ShirwadkarAdd following helpers for commit path:
- jbd2_map_fc_buf() - allocates fast commit buffers for caller
- jbd2_wait_on_fc_bufs() - waits on fast commit buffers allocated
using jbd2_map_fc_buf()
- jbd2_submit_inode_data() - submit data buffers for one inode
- jbd2_wait_inode_data() - wait for inode data
--- fs/jbd2/commit.c | 40 +++++++++++++++++++++++ fs/jbd2/journal.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/jbd2.h | 6 ++++ 3 files changed, 122 insertions(+)
fs/jbd2/commit.c +40 -0
@@ -202,6 +202,46 @@ static int journal_submit_inode_data_buffers(struct address_space *mapping,return ret; } +/* Send all the data buffers related to an inode */ +int jbd2_submit_inode_data (journal_t *journal,struct jbd2_inode *jinode) +{ +struct address_space *mapping; +loff_t dirty_start; +loff_t dirty_end; +int ret; + +if (!jinode) +return 0 ; + + dirty_start = jinode->i_dirty_start; + dirty_end = jinode->i_dirty_end; + +if (!(jinode->i_flags &JI_WRITE_DATA )) +return 0 ; + + dirty_start = jinode->i_dirty_start; + dirty_end = jinode->i_dirty_end; + + mapping = jinode->i_vfs_inode->i_mapping; + +trace_jbd2_submit_inode_data (jinode->i_vfs_inode); + ret =journal_submit_inode_data_buffers (mapping, dirty_start, + dirty_end); + +return ret; +} +EXPORT_SYMBOL (jbd2_submit_inode_data); + +int jbd2_wait_inode_data (journal_t *journal,struct jbd2_inode *jinode) +{ +if (!jinode || !(jinode->i_flags &JI_WAIT_DATA )) +return 0 ; +return filemap_fdatawait_range_keep_errors ( + jinode->i_vfs_inode->i_mapping, jinode->i_dirty_start, + jinode->i_dirty_end); +} +EXPORT_SYMBOL (jbd2_wait_inode_data); +/* * Submit all the data buffers of inode associated with the transaction to * disk.
fs/jbd2/journal.c +76 -0
82 lines not on this page · raw message
include/linux/jbd2.h +6 -0
@@ -123,6 +123,7 @@ typedef struct journal_s journal_t; /* Journal control structure */#define JBD2_SUPERBLOCK_V1 3#define JBD2_SUPERBLOCK_V2 4#define JBD2_REVOKE_BLOCK 5 +#define JBD2_FC_BLOCK 6/* * Standard header for all descriptor blocks:
@@ -1562,6 +1563,11 @@ int jbd2_start_async_fc_nowait(journal_t *journal, tid_t tid);int jbd2_start_async_fc_wait (journal_t *journal,tid_t tid);void jbd2_stop_async_fc (journal_t *journal,tid_t tid);void jbd2_init_fast_commit (journal_t *journal,int num_fc_blks); +int jbd2_map_fc_buf (journal_t *journal,struct buffer_head **bh_out); +int jbd2_wait_on_fc_bufs (journal_t *journal,int num_blks); +int jbd2_submit_inode_data (journal_t *journal,struct jbd2_inode *jinode); +int jbd2_wait_inode_data (journal_t *journal,struct jbd2_inode *jinode); +/* * is_journal_abort *
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 12/20 ext4: add fast commit on-disk format structs
In reply to Harshad ShirwadkarAdd structs representing on-disk format of the commit header and tlvs in the commit header.
--- fs/ext4/ext4_jbd2.c | 1 + fs/ext4/ext4_jbd2.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+)
fs/ext4/ext4_jbd2.c +1 -0
@@ -4,6 +4,7 @@*/ #include "ext4_jbd2.h" +#include "ext4_extents.h" #include <trace/events/ext4.h>
fs/ext4/ext4_jbd2.h +45 -0
52 lines not on this page · raw message
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 14/20 ext4: main commit routine for fast commits
In reply to Harshad ShirwadkarAdd main commit routine for fast commits to perform a fast commit. Also, handle race between inode deletion which results in inode being deleted from fast commit list and the commit routine. Add commit routines for fast commit with hard consistency as well as for soft consistency.
--- fs/ext4/ext4.h | 7 + fs/ext4/ext4_jbd2.c | 714 ++++++++++++++++++++++++++++++++++++ fs/ext4/ext4_jbd2.h | 2 + fs/ext4/fsync.c | 2 +- fs/ext4/inode.c | 6 +- fs/ext4/migrate.c | 1 + fs/ext4/super.c | 12 + include/trace/events/ext4.h | 101 +++++ 8 files changed, 842 insertions(+), 3 deletions(-)
fs/ext4/ext4.h +7 -0
@@ -1764,6 +1764,10 @@ enum {EXT4_STATE_LUSTRE_EA_INODE ,/* Lustre-style ea_inode */ EXT4_STATE_VERITY_IN_PROGRESS ,/* building fs-verity Merkle tree */ EXT4_STATE_FC_ELIGIBLE ,/* File is Fast commit eligible */ +EXT4_STATE_FC_DATA_SUBMIT ,/* File is going through fast commit */ + EXT4_STATE_FC_MDATA_SUBMIT, /* Fast commit block is + * being submitted + */ };#define EXT4_INODE_BIT_FNS (name, field, offset) \
@@ -2854,6 +2858,9 @@ extern int ext4_group_extend(struct super_block *sb,extern int ext4_resize_fs (struct super_block *sb,ext4_fsblk_t n_blocks_count);/* super.c */ + +int ext4_fc_async_commit_inode (journal_t *journal,tid_t commit_tid, +struct inode *inode);extern struct buffer_head *ext4_sb_bread (struct super_block *sb,sector_t block,int op_flags);extern int ext4_seq_options_show (struct seq_file *seq,void *offset);
fs/ext4/ext4_jbd2.c +714 -0
742 lines not on this page · raw message
fs/ext4/ext4_jbd2.h +2 -0
@@ -583,5 +583,7 @@ int __init ext4_init_fc_dentry_cache(void);void ext4_fc_track_inode (struct inode *inode);void ext4_fc_mark_ineligible (struct inode *inode,int reason);void ext4_fc_disable (struct super_block *sb,int reason); +void ext4_fc_del (struct inode *inode); +#endif /* _EXT4_JBD2_H */
fs/ext4/fsync.c +1 -1
@@ -114,7 +114,7 @@ static int ext4_fsync_journal(struct inode *inode, bool datasync, !jbd2_trans_will_send_data_barrier(journal, commit_tid)) *needs_barrier = true; -return jbd2_complete_transaction (journal, commit_tid); +return ext4_fc_async_commit_inode (journal, commit_tid, inode); }/*
fs/ext4/inode.c +4 -2
@@ -5121,8 +5121,10 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)if (wbc->sync_mode !=WB_SYNC_ALL || wbc->for_sync)return 0 ; - err =jbd2_complete_transaction (EXT4_SB (inode->i_sb)->s_journal, -EXT4_I (inode)->i_sync_tid); + err =ext4_fc_async_commit_inode (EXT4_SB (inode->i_sb) + ->s_journal, +EXT4_I (inode)->i_sync_tid, + inode); }else {struct ext4_iloc iloc;
fs/ext4/migrate.c +1 -0
@@ -496,6 +496,7 @@ int ext4_ext_migrate(struct inode *inode)* work to orphan_list_cleanup() */ ext4_orphan_del (NULL , tmp_inode); +ext4_fc_del (inode); retval =PTR_ERR (handle); goto out_tmp_inode; }
fs/ext4/super.c +12 -0
@@ -1165,6 +1165,11 @@ static int ext4_drop_inode(struct inode *inode)if (!drop) drop =fscrypt_drop_inode (inode); +if (drop) { +spin_unlock (&inode->i_lock); +ext4_fc_del (inode); +spin_lock (&inode->i_lock); + }trace_ext4_drop_inode (inode, drop);return drop;
@@ -1173,6 +1178,11 @@ static int ext4_drop_inode(struct inode *inode)static void ext4_free_in_core_inode (struct inode *inode) {fscrypt_free_inode (inode); +if (!list_empty (&(EXT4_I (inode)->i_fc_list))) { +pr_warn ("%s: inode %ld still in fc list" , + __func__, inode->i_ino); +ext4_fc_del (inode); + }kmem_cache_free (ext4_inode_cachep,EXT4_I (inode)); }
@@ -1187,6 +1197,8 @@ static void ext4_destroy_inode(struct inode *inode) true);dump_stack (); } +if (!list_empty (&(EXT4_I (inode)->i_fc_list))) +ext4_fc_del (inode); }static void init_once (void *foo)
include/trace/events/ext4.h +101 -0
113 lines not on this page · raw message
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 15/20 jbd2: add fast commit recovery path support
In reply to Harshad ShirwadkarAdd fc_do_one_pass to invoke file system specific replay callback and pass discovered fast commit blocks to let file system handle those.
--- fs/jbd2/recovery.c | 67 +++++++++++++++++++++++++++++++++++++++++--- include/linux/jbd2.h | 13 +++++++++ 2 files changed, 76 insertions(+), 4 deletions(-)
fs/jbd2/recovery.c +63 -4
@@ -35,7 +35,6 @@ struct recovery_infoint nr_revoke_hits; }; -enum passtype {PASS_SCAN ,PASS_REVOKE ,PASS_REPLAY };static int do_one_pass (journal_t *journal,struct recovery_info *info,enum passtype pass); static int scan_revoke_records(journal_t *, struct buffer_head *,
@@ -225,10 +224,63 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)/* Make sure we wrap around the log correctly! */ #define wrap (journal, var) \ do { \ - if (var >= (journal)->j_last) \ - var -= ((journal)->j_last - (journal)->j_first); \ + unsigned long _wrap_last = \ + jbd2_has_feature_fast_commit(journal) ? \ + (journal)->j_last_fc : (journal)->j_last; \ + \ + if (var >= _wrap_last) \ + var -= (_wrap_last - (journal)->j_first); \ } while (0) +static int fc_do_one_pass (journal_t *journal, +struct recovery_info *info,enum passtype pass) +{ +unsigned int expected_commit_id = info->end_transaction; +unsigned long next_fc_block; +struct buffer_head *bh; +unsigned int seq; +journal_header_t *jhdr; +int err =0 ; + + next_fc_block = journal->j_first_fc; + +while (next_fc_block <= journal->j_last_fc) { +jbd_debug (3 ,"Fast commit replay: next block %ld" , + next_fc_block); + err =jread (&bh, journal, next_fc_block); +if (err) { +jbd_debug (3 ,"Fast commit replay: read error" ); +break ; + } + + jhdr = (journal_header_t *)bh->b_data; + seq =be32_to_cpu (jhdr->h_sequence); +if (be32_to_cpu (jhdr->h_magic) !=JBD2_MAGIC_NUMBER || + seq != expected_commit_id) { +jbd_debug (3 ,"Fast commit replay: magic / commitid error [%d / %d / %d]\n" , +be32_to_cpu (jhdr->h_magic), seq, + expected_commit_id); +break ; + } +jbd_debug (3 ,"Processing fast commit blk with seq %d" , + seq); +if (journal->j_fc_replay_callback) { + err = journal->j_fc_replay_callback ( + journal, bh, pass, + next_fc_block - + journal->j_first_fc); +if (err) +break ; + } + next_fc_block++; + } + +if (err) +jbd_debug (3 ,"Fast commit replay failed, err = %d\n" , err); + +return err; +} +/** * jbd2_journal_recover - recovers a on-disk journal * @journal: the journal to recover
@@ -470,7 +522,7 @@ static int do_one_pass(journal_t *journal,break ;jbd_debug (2 ,"Scanning for sequence ID %u at %lu/%lu\n" , - next_commit_ID, next_log_block, journal->j_last); + next_commit_ID, next_log_block, journal->j_last_fc);/* Skip over each chunk of the transaction looking * either the next descriptor block or the final commit
@@ -768,6 +820,9 @@ static int do_one_pass(journal_t *journal,if (err) goto failed;continue ; +case JBD2_FC_BLOCK : +pr_warn ("Unexpectedly found fast commit block.\n" ); +continue ;default : jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
@@ -799,6 +854,10 @@ static int do_one_pass(journal_t *journal, success = -EIO ; } } + +if (jbd2_has_feature_fast_commit (journal) && pass !=PASS_REVOKE ) + success =fc_do_one_pass (journal, info, pass); +if (block_error && success ==0 ) success = -EIO ;return success;
include/linux/jbd2.h +13 -0
@@ -749,6 +749,8 @@ jbd2_time_diff(unsigned long start, unsigned long end)#define JBD2_NR_BATCH 64 +enum passtype {PASS_SCAN ,PASS_REVOKE ,PASS_REPLAY }; +/** * struct journal_s - The journal_s type is the concrete type associated with * journal_t.
@@ -1219,6 +1221,17 @@ struct journal_s* after every commit operation. */ void (*j_fc_cleanup_callback)(struct journal_s *journal); + +/* +* @j_fc_replay_callback: +* +* File-system specific function that performs replay of a fast +* commit. JBD2 calls this function for each fast commit block found in +* the journal. +*/ +int (*j_fc_replay_callback)(struct journal_s *journal, +struct buffer_head *bh, +enum passtype pass,int off); };#define jbd2_might_wait_for_commit (j) \
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 16/20 ext4: fast commit recovery path preparation
In reply to Harshad ShirwadkarPrepare for making ext4 fast commit recovery path changes. Make a few existing functions visible. Break and add a wrapper around ext4_get_inode_loc to allow reading inode from disk without having a corresponding VFS inode.
--- fs/ext4/ext4.h | 7 +++++++ fs/ext4/inode.c | 34 +++++++++++++++++++--------------- fs/ext4/ioctl.c | 6 +++--- fs/ext4/namei.c | 2 +- include/trace/events/ext4.h | 8 ++++---- 5 files changed, 34 insertions(+), 23 deletions(-)
fs/ext4/ext4.h +7 -0
@@ -2741,6 +2741,8 @@ extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);extern void ext4_process_freed_data (struct super_block *sb,tid_t commit_tid);/* inode.c */ +void ext4_inode_csum_set (struct inode *inode,struct ext4_inode *raw, +struct ext4_inode_info *ei);int ext4_inode_is_fast_symlink (struct inode *inode);struct buffer_head *ext4_getblk (handle_t *,struct inode *,ext4_lblk_t ,int );struct buffer_head *ext4_bread (handle_t *,struct inode *,ext4_lblk_t ,int );
@@ -2787,6 +2789,8 @@ extern int ext4_sync_inode(handle_t *, struct inode *);extern void ext4_dirty_inode (struct inode *,int );extern int ext4_change_inode_journal_flag (struct inode *,int );extern int ext4_get_inode_loc (struct inode *,struct ext4_iloc *); +extern int ext4_get_fc_inode_loc (struct super_block *sb,unsigned long ino, +struct ext4_iloc *iloc);extern int ext4_inode_attach_jinode (struct inode *inode);extern int ext4_can_truncate (struct inode *inode);extern int ext4_truncate (struct inode *);
@@ -2820,12 +2824,15 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,/* ioctl.c */ extern long ext4_ioctl (struct file *,unsigned int ,unsigned long );extern long ext4_compat_ioctl (struct file *,unsigned int ,unsigned long ); +extern void ext4_reset_inode_seed (struct inode *inode);/* migrate.c */ extern int ext4_ext_migrate (struct inode *);extern int ext4_ind_migrate (struct inode *inode);/* namei.c */ +extern int ext4_init_new_dir (handle_t *handle,struct inode *dir, +struct inode *inode);extern int ext4_dirblock_csum_verify (struct inode *inode,struct buffer_head *bh);extern int ext4_orphan_add (handle_t *,struct inode *);
fs/ext4/inode.c +19 -15
@@ -101,8 +101,8 @@ static int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw,return provided == calculated; } -static void ext4_inode_csum_set (struct inode *inode,struct ext4_inode *raw, -struct ext4_inode_info *ei) +void ext4_inode_csum_set (struct inode *inode,struct ext4_inode *raw, +struct ext4_inode_info *ei) {__u32 csum;
@@ -4235,22 +4235,21 @@ int ext4_truncate(struct inode *inode)* data in memory that is needed to recreate the on-disk version of this * inode. */ -static int __ext4_get_inode_loc (struct inode *inode, +static int __ext4_get_inode_loc (struct super_block *sb,unsigned long ino,struct ext4_iloc *iloc,int in_mem) {struct ext4_group_desc *gdp;struct buffer_head *bh; -struct super_block *sb = inode->i_sb;ext4_fsblk_t block;struct blk_plug plug;int inodes_per_block, inode_offset; iloc->bh =NULL ; -if (inode->i_ino <EXT4_ROOT_INO || - inode->i_ino >le32_to_cpu (EXT4_SB (sb)->s_es->s_inodes_count)) +if (ino <EXT4_ROOT_INO || + ino >le32_to_cpu (EXT4_SB (sb)->s_es->s_inodes_count))return -EFSCORRUPTED ; - iloc->block_group = (inode->i_ino -1 ) /EXT4_INODES_PER_GROUP (sb); + iloc->block_group = (ino -1 ) /EXT4_INODES_PER_GROUP (sb); gdp =ext4_get_group_desc (sb, iloc->block_group,NULL );if (!gdp)return -EIO ;
@@ -4259,7 +4258,7 @@ static int __ext4_get_inode_loc(struct inode *inode,* Figure out the offset within the block group inode table */ inodes_per_block =EXT4_SB (sb)->s_inodes_per_block; - inode_offset = ((inode->i_ino -1 ) % + inode_offset = ((ino -1 ) %EXT4_INODES_PER_GROUP (sb)); block =ext4_inode_table (sb, gdp) + (inode_offset / inodes_per_block); iloc->offset = (inode_offset % inodes_per_block) *EXT4_INODE_SIZE (sb);
@@ -4360,7 +4359,7 @@ static int __ext4_get_inode_loc(struct inode *inode,* has in-inode xattrs, or we don't have this inode in memory. * Read the block from disk. */ -trace_ext4_load_inode (inode); +trace_ext4_load_inode (sb, ino);get_bh (bh); bh->b_end_io = end_buffer_read_sync;submit_bh (REQ_OP_READ ,REQ_META |REQ_PRIO , bh);
@@ -4368,9 +4367,8 @@ static int __ext4_get_inode_loc(struct inode *inode,wait_on_buffer (bh);if (!buffer_uptodate (bh)) { simulate_eio: -ext4_set_errno (inode->i_sb,EIO ); -EXT4_ERROR_INODE_BLOCK (inode, block, -"unable to read itable block" ); +ext4_set_errno (sb,EIO ); +ext4_error (sb,"unable to read itable block" );brelse (bh);return -EIO ; }
@@ -4383,10 +4381,16 @@ static int __ext4_get_inode_loc(struct inode *inode,int ext4_get_inode_loc (struct inode *inode,struct ext4_iloc *iloc) {/* We have all inode data except xattrs in memory here. */ -return __ext4_get_inode_loc (inode, iloc, +return __ext4_get_inode_loc (inode->i_sb, inode->i_ino, iloc, !ext4_test_inode_state (inode,EXT4_STATE_XATTR )); } +int ext4_get_fc_inode_loc (struct super_block *sb,unsigned long ino, +struct ext4_iloc *iloc) +{ +return __ext4_get_inode_loc (sb, ino, iloc,0 ); +} +static bool ext4_should_use_dax (struct inode *inode) {if (!test_opt (inode->i_sb,DAX ))
@@ -4536,7 +4540,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, ei =EXT4_I (inode); iloc.bh =NULL ; - ret =__ext4_get_inode_loc (inode, &iloc,0 ); + ret =__ext4_get_inode_loc (sb, inode->i_ino, &iloc,0 );if (ret <0 ) goto bad_inode; raw_inode =ext4_raw_inode (&iloc);
@@ -5128,7 +5132,7 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc) }else {struct ext4_iloc iloc; - err =__ext4_get_inode_loc (inode, &iloc,0 ); + err =__ext4_get_inode_loc (inode->i_sb, inode->i_ino, &iloc,0 );if (err)return err;/*
fs/ext4/ioctl.c +3 -3
@@ -86,7 +86,7 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)i_size_write (inode2, isize); } -static void reset_inode_seed (struct inode *inode) +void ext4_reset_inode_seed (struct inode *inode) {struct ext4_inode_info *ei =EXT4_I (inode);struct ext4_sb_info *sbi =EXT4_SB (inode->i_sb);
@@ -199,8 +199,8 @@ static long swap_inode_boot_loader(struct super_block *sb, inode->i_generation =prandom_u32 (); inode_bl->i_generation =prandom_u32 (); -reset_inode_seed (inode); -reset_inode_seed (inode_bl); +ext4_reset_inode_seed (inode); +ext4_reset_inode_seed (inode_bl);ext4_discard_preallocations (inode);
fs/ext4/namei.c +1 -1
@@ -2742,7 +2742,7 @@ struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,return ext4_next_entry (de, blocksize); } -static int ext4_init_new_dir (handle_t *handle,struct inode *dir, +int ext4_init_new_dir (handle_t *handle,struct inode *dir,struct inode *inode) {struct buffer_head *dir_block =NULL ;
include/trace/events/ext4.h +4 -4
@@ -1755,9 +1755,9 @@ TRACE_EVENT(ext4_ext_load_extent, ); TRACE_EVENT(ext4_load_inode, - TP_PROTO(struct inode *inode), + TP_PROTO(struct super_block *sb, unsigned long ino), - TP_ARGS(inode), + TP_ARGS(sb, ino), TP_STRUCT__entry( __field( dev_t, dev )
@@ -1765,8 +1765,8 @@ TRACE_EVENT(ext4_load_inode, ), TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; + __entry->dev = sb->s_dev; + __entry->ino = ino; ), TP_printk("dev %d,%d ino %ld",
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 17/20 ext4: add idempotent helpers to manipulate bitmaps
In reply to Harshad ShirwadkarFor fast commit replay path, we need idempotent helpers that mark inodes used, data blocks as used or free. It's important these are idempotent and that's because we can crash while we are replaying.
--- fs/ext4/ext4.h | 1 + fs/ext4/ialloc.c | 113 ++++++++++++++++++++++++++++++++++++++ fs/ext4/mballoc.c | 136 +++++++++++++++++++++++++++++++++++++++++++++- fs/ext4/mballoc.h | 2 + 4 files changed, 251 insertions(+), 1 deletion(-)
fs/ext4/ext4.h +1 -0
@@ -2691,6 +2691,7 @@ extern int ext4fs_dirhash(const struct inode *dir, const char *name, int len, struct dx_hash_info *hinfo);/* ialloc.c */ +extern int ext4_mark_inode_used (struct super_block *sb,int ino); extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t, const struct qstr *qstr, __u32 goal, uid_t *owner, __u32 i_flags,
fs/ext4/ialloc.c +113 -0
119 lines not on this page · raw message
fs/ext4/mballoc.c +135 -1
160 lines not on this page · raw message
fs/ext4/mballoc.h +2 -0
@@ -215,4 +215,6 @@ ext4_mballoc_query_range(ext4_mballoc_query_range_fn formatter, void *priv); +void ext4_mb_mark_used (struct super_block *sb,ext4_fsblk_t block, +int len);#endif
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 19/20 ext4: add fast commit replay path
In reply to Harshad ShirwadkarAdd main routine for replaying fast commit blocks. Fast commit replay routine should be idempotent; so that if we crash while replaying, we can restart from the beginning and won't result in a corrupted file system.
--- fs/ext4/ext4.h | 9 + fs/ext4/ext4_jbd2.c | 470 ++++++++++++++++++++++++++++++++++++ include/trace/events/ext4.h | 22 ++ 3 files changed, 501 insertions(+)
fs/ext4/ext4.h +9 -0
@@ -1440,6 +1440,14 @@ struct ext4_super_block {#define ext4_has_strict_mode (sbi) \ (sbi->s_encoding_flags & EXT4_ENC_STRICT_MODE_FL) +/* +* Fast commit replay state. +*/ +struct ext4_fc_replay_state { +int fc_replay_error; +int fc_replay_expected_off; +}; +/* * Fast commit ineligible reasons. */
@@ -1651,6 +1659,7 @@ struct ext4_sb_info {* that have data changes in them. */ struct list_head s_fc_dentry_q; +struct ext4_fc_replay_state s_fc_replay_state;spinlock_t s_fc_lock;struct ext4_fc_stats s_fc_stats; };
fs/ext4/ext4_jbd2.c +470 -0
494 lines not on this page · raw message
include/trace/events/ext4.h +22 -0
@@ -2736,6 +2736,28 @@ TRACE_EVENT(ext4_error, __entry->function, __entry->line) ); +TRACE_EVENT (ext4_journal_fc_replay_scan, + TP_PROTO(struct super_block *sb, int error, int off), + +TP_ARGS (sb, error, off), + +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(int, error) +__field (int, off) + ), + +TP_fast_assign ( + __entry->dev = sb->s_dev; + __entry->error = error; + __entry->off = off; + ), + +TP_printk ("FC scan pass on dev %d,%d: error %d, off %d" , +MAJOR (__entry->dev),MINOR (__entry->dev), + __entry->error, __entry->off) +); + TRACE_EVENT(ext4_journal_fc_commit_cb_start, TP_PROTO(struct super_block *sb),
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 18/20 ext4: disable certain features in replay path
In reply to Harshad ShirwadkarReplay path uses similar code paths for replaying committed changes. But since it runs before full initialization of the file system and also since we don't have to be super careful about performance, we can and need to disable certain file system features during the replay path. More specifically, we disable most of the extent status tree stuff, mballoc and some places where we mark file system with errors.
--- fs/ext4/balloc.c | 7 +++++- fs/ext4/ext4_jbd2.c | 2 +- fs/ext4/extents_status.c | 24 +++++++++++++++++++ fs/ext4/ialloc.c | 52 +++++++++++++++++++++++++++------------- fs/ext4/inode.c | 12 ++++++---- fs/ext4/mballoc.c | 22 +++++++++++------ 6 files changed, 90 insertions(+), 29 deletions(-)
fs/ext4/balloc.c +6 -1
@@ -368,7 +368,12 @@ static int ext4_validate_block_bitmap(struct super_block *sb, struct buffer_head *bh) {ext4_fsblk_t blk; -struct ext4_group_info *grp =ext4_get_group_info (sb, block_group); +struct ext4_group_info *grp; + +if (EXT4_SB (sb)->s_mount_state &EXT4_FC_REPLAY ) +return 0 ; + + grp =ext4_get_group_info (sb, block_group);if (buffer_verified (bh))return 0 ;
fs/ext4/ext4_jbd2.c +1 -1
@@ -102,7 +102,7 @@ handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,return ERR_PTR (err); journal =EXT4_SB (sb)->s_journal; -if (!journal) +if (!journal || (EXT4_SB (sb)->s_mount_state &EXT4_FC_REPLAY ))return ext4_get_nojournal ();return jbd2__journal_start (journal, blocks, rsv_blocks, revoke_creds,GFP_NOFS , type, line);
fs/ext4/extents_status.c +24 -0
@@ -311,6 +311,9 @@ void ext4_es_find_extent_range(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t end, struct extent_status *es) { + if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) + return; +trace_ext4_es_find_extent_range_enter (inode ,lblk );read_lock (&EXT4_I (inode)->i_es_lock);
@@ -361,6 +364,9 @@ bool ext4_es_scan_range(struct inode *inode, {bool ret; +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return false; +read_lock (&EXT4_I (inode)->i_es_lock); ret =__es_scan_range (inode, matching_fn, lblk, end);read_unlock (&EXT4_I (inode)->i_es_lock);
@@ -404,6 +410,9 @@ bool ext4_es_scan_clu(struct inode *inode, {bool ret; +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return false; +read_lock (&EXT4_I (inode)->i_es_lock); ret =__es_scan_clu (inode, matching_fn, lblk);read_unlock (&EXT4_I (inode)->i_es_lock);
@@ -812,6 +821,9 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,int err =0 ;struct ext4_sb_info *sbi =EXT4_SB (inode->i_sb); +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return 0 ; +es_debug ("add [%u/%u) %llu %x to extent status tree of inode %lu\n" , lblk, len, pblk, status, inode->i_ino);
@@ -873,6 +885,9 @@ void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,struct extent_status newes;ext4_lblk_t end = lblk + len -1 ; +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return ; + newes.es_lblk = lblk; newes.es_len = len;ext4_es_store_pblock_status (&newes, pblk, status);
@@ -908,6 +923,9 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,struct rb_node *node;int found =0 ; +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return 0 ; +trace_ext4_es_lookup_extent_enter (inode, lblk);es_debug ("lookup extent in block %u\n" , lblk);
@@ -1419,6 +1437,9 @@ int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,int err =0 ;int reserved =0 ; +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return 0 ; +trace_ext4_es_remove_extent (inode, lblk, len);es_debug ("remove [%u/%u) from extent status tree of inode %lu\n" , lblk, len, inode->i_ino);
@@ -1969,6 +1990,9 @@ int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk,struct extent_status newes;int err =0 ; +if (EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) +return 0 ; +es_debug ("add [%u/1) delayed to extent status tree of inode %lu\n" , lblk, inode->i_ino);
fs/ext4/ialloc.c +36 -16
103 lines not on this page · raw message
fs/ext4/inode.c +8 -4
@@ -509,7 +509,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,return -EFSCORRUPTED ;/* Lookup extent status tree firstly */ -if (ext4_es_lookup_extent (inode, map->m_lblk,NULL , &es)) { +if (!(EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) && +ext4_es_lookup_extent (inode, map->m_lblk,NULL , &es)) {if (ext4_es_is_written (&es) ||ext4_es_is_unwritten (&es)) { map->m_pblk =ext4_es_pblock (&es) + map->m_lblk - es.es_lblk;
@@ -821,7 +822,8 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,int create = map_flags &EXT4_GET_BLOCKS_CREATE ;int err; -J_ASSERT (handle !=NULL || create ==0 ); +J_ASSERT ((EXT4_SB (inode->i_sb)->s_mount_state |EXT4_FC_REPLAY ) + || handle !=NULL || create ==0 ); map.m_lblk = block; map.m_len =1 ;
@@ -837,7 +839,8 @@ struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,return ERR_PTR (-ENOMEM );if (map.m_flags &EXT4_MAP_NEW ) {J_ASSERT (create !=0 ); -J_ASSERT (handle !=NULL ); +J_ASSERT ((EXT4_SB (inode->i_sb)->s_mount_state &EXT4_FC_REPLAY ) + || (handle !=NULL ));/* * Now that we do not always journal data, we should
@@ -4589,7 +4592,8 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,if (!ext4_inode_csum_verify (inode, raw_inode, ei) ||ext4_simulate_fail (sb,EXT4_SIM_INODE_CRC )) {ext4_set_errno (inode->i_sb,EFSBADCRC ); -ext4_error_inode (inode, function, line,0 , +if (!(EXT4_SB (sb)->s_mount_state &EXT4_FC_REPLAY )) +ext4_error_inode (inode, function, line,0 ,"iget: checksum invalid" ); ret = -EFSBADCRC ; goto bad_inode;
fs/ext4/mballoc.c +15 -7
@@ -1449,14 +1449,17 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, blocknr =ext4_group_first_block_no (sb, e4b->bd_group); blocknr +=EXT4_C2B (sbi, block); -ext4_grp_locked_error (sb, e4b->bd_group, - inode ? inode->i_ino :0 , - blocknr, -"freeing already freed block " -"(bit %u); block bitmap corrupt." , - block); -ext4_mark_group_bitmap_corrupted (sb, e4b->bd_group, +if (!(sbi->s_mount_state &EXT4_FC_REPLAY )) { +ext4_grp_locked_error (sb, e4b->bd_group, + inode ? inode->i_ino :0 , + blocknr, +"freeing already freed block " +"(bit %u); block bitmap corrupt." , + block); +ext4_mark_group_bitmap_corrupted ( + sb, e4b->bd_group,EXT4_GROUP_INFO_BBITMAP_CORRUPT ); + }mb_regenerate_buddy (e4b); goto done; }
@@ -4109,6 +4112,9 @@ void ext4_discard_preallocations(struct inode *inode)return ; } +if (EXT4_SB (sb)->s_mount_state &EXT4_FC_REPLAY ) +return ; +mb_debug (1 ,"discard preallocation for inode %lu\n" , inode->i_ino);trace_ext4_discard_preallocations (inode);
@@ -4585,6 +4591,8 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, sb = ar->inode->i_sb; sbi =EXT4_SB (sb); +WARN_ON (sbi->s_mount_state &EXT4_FC_REPLAY ); +trace_ext4_request_blocks (ar);/* Allow to use superuser reservation for quota file */
Signature · 1 line
2.25.1.481.gfbce0eb801-goog
PATCH v5 20/20 ext4: add debug mount option to test fast commit replay
In reply to Harshad ShirwadkarAdd a debug mount option to simulate errors while replaying. If fc_debug_max_replay is set, ext4 will replay only as many fast commit blocks as passed as an argument.
--- fs/ext4/ext4.h | 3 +++ fs/ext4/ext4_jbd2.c | 6 ++++++ fs/ext4/super.c | 12 +++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-)
fs/ext4/ext4.h +3 -0
@@ -1661,6 +1661,9 @@ struct ext4_sb_info {struct list_head s_fc_dentry_q;struct ext4_fc_replay_state s_fc_replay_state;spinlock_t s_fc_lock; +#ifdef EXT4_FC_DEBUG +int s_fc_debug_max_replay; +#endif struct ext4_fc_stats s_fc_stats; };
fs/ext4/ext4_jbd2.c +6 -0
@@ -1561,6 +1561,12 @@ static int ext4_journal_fc_replay_cb(journal_t *journal, struct buffer_head *bh,return sbi->s_fc_replay_state.fc_replay_error; } +#ifdef EXT4_FC_DEBUG +if (sbi->s_fc_debug_max_replay && off >= sbi->s_fc_debug_max_replay) { +pr_warn ("Dropping fc block %d because max_replay set\n" , off); +return -EINVAL ; + } +#endif sbi->s_mount_state |=EXT4_FC_REPLAY ; fc_hdr = (struct ext4_fc_commit_hdr *) ((__u8 *)bh->b_data +sizeof (journal_header_t));
fs/ext4/super.c +11 -1
@@ -1542,7 +1542,7 @@ enum { Opt_dioread_nolock, Opt_dioread_lock, Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache, - Opt_no_fc, Opt_fc_soft_consistency + Opt_no_fc, Opt_fc_soft_consistency, Opt_fc_debug_max_replay }; static const match_table_t tokens = {
@@ -1628,6 +1628,9 @@ static const match_table_t tokens = { {Opt_noinit_itable, "noinit_itable"}, {Opt_no_fc, "no_fc"}, {Opt_fc_soft_consistency, "fc_soft_consistency"}, +#ifdef EXT4_FC_DEBUG + {Opt_fc_debug_max_replay, "fc_debug_max_replay=%u"}, +#endif {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_test_dummy_encryption, "test_dummy_encryption"}, {Opt_nombcache, "nombcache"},
@@ -1847,6 +1850,9 @@ static const struct mount_opts { MOPT_CLEAR | MOPT_2 | MOPT_EXT4_ONLY}, {Opt_fc_soft_consistency,EXT4_MOUNT2_JOURNAL_FC_SOFT_CONSISTENCY , MOPT_SET | MOPT_2 | MOPT_EXT4_ONLY}, +#ifdef EXT4_FC_DEBUG + {Opt_fc_debug_max_replay, 0, MOPT_GTE0}, +#endif {Opt_err, 0, 0} };
@@ -2006,6 +2012,10 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, sbi->s_li_wait_mult = arg; }else if (token == Opt_max_dir_size_kb) { sbi->s_max_dir_size_kb = arg; +#ifdef EXT4_FC_DEBUG + }else if (token == Opt_fc_debug_max_replay) { + sbi->s_fc_debug_max_replay = arg; +#endif }else if (token == Opt_stripe) { sbi->s_stripe = arg; }else if (token == Opt_resuid) {
Signature · 1 line
2.25.1.481.gfbce0eb801-goog