ext4: Speedup orphan file handling
Jan Kara
reviewerv7 cover ext4: Speedup orphan file handling
Hello,
Here is the seventh version of my series to speed up orphan inode handling in ext4. I've forgot to add a check that orphan file is not exposed in directory hierarchy. The only change in this version is addition of that fix.
Orphan inode handling in ext4 is a bottleneck for workloads which heavily excercise truncate / unlink of small files as they contend on global s_orphan_mutex (when you have fast enough storage). This patch set implements new way of handling orphan inodes - instead of using a linked list, we store inode numbers of orphaned inodes in a file which is possible to implement in a more scalable manner than linked list manipulations. See description of patch 3/5 for more details.
The patch set achieves significant gains both for a micro benchmark stressing orphan inode handling (truncating file byte-by-byte, several threads in parallel) and for reaim creat_clo workload. I'm happy for any review, thoughts, ideas about the patches. I have also implemented full support in e2fsprogs which I'll send separately.
Honza
[1] https://lore.kernel.org/lkml/20210227120804.GB22871@xsang-OptiPlex-9020/
Changes since v6:
* Rebased on top of v5.14-rc6 + patches fixing exposure of hidden inodes in directory hierarchy
* Added check orphan file cannot be linked from directory hierarchy
* Get orphan file inode with EXT4_IGET_SPECIAL flag
Changes since v5:
* Added Reviewed-by tags from Ted
* Fixed up sparse warning spotted by 0-day
* Fixed error handling path in ext4_orphan_add() to not leak orphan entry
Changes since v4:
* Rebased on top of v5.14-rc5
* Updated commit message of patch 1/5
* Added Reviewed-by tags from Ted
Changes since v3:
* Added documentation about on-disk format changes
* Add physical block number into orphan block checksum
* Improve some sanity checks, handling of corrupted orphan file
* Improved some changelogs
Changes since v2:
* Updated some comments
* Rebased onto 5.13-rc5
* Change orphan file inode from a fixed inode number to inode number stored in the superblock
Changes since v1:
* orphan blocks have now magic numbers
* split out orphan handling to a separate source file
* some smaller updates according to review
Previous versions:
Jan Kara
reviewerPATCH v7 1/5 ext4: Support for checksumming from journal triggers
JBD2 layer support triggers which are called when journaling layer moves buffer to a certain state. We can use the frozen trigger, which gets called when buffer data is frozen and about to be written out to the journal, to compute block checksums for some buffer types (similarly as does ocfs2). This avoids unnecessary repeated recomputation of the checksum (at the cost of larger window where memory corruption won't be caught by checksumming) and is even necessary when there are unsynchronized updaters of the checksummed data.
So add superblock and journal trigger type arguments to ext4_journal_get_write_access() and ext4_journal_get_create_access() so that frozen triggers can be set accordingly. Also add inode argument to ext4_walk_page_buffers() and all the callbacks used with that function for the same purpose. This patch is mostly only a change of prototype of the above mentioned functions and a few small helpers. Real checksumming will come later.
--- fs/ext4/ext4.h | 26 ++++++++++++-- fs/ext4/ext4_jbd2.c | 43 +++++++++++++++------- fs/ext4/ext4_jbd2.h | 18 ++++++---- fs/ext4/extents.c | 12 ++++--- fs/ext4/file.c | 3 +- fs/ext4/ialloc.c | 19 ++++++---- fs/ext4/indirect.c | 15 +++++--- fs/ext4/inline.c | 26 +++++++++----- fs/ext4/inode.c | 84 +++++++++++++++++++++++++------------------ fs/ext4/ioctl.c | 4 ++- fs/ext4/mballoc.c | 15 ++++---- fs/ext4/namei.c | 40 +++++++++++++-------- fs/ext4/resize.c | 38 ++++++++++++-------- fs/ext4/super.c | 16 ++++++++- fs/ext4/xattr.c | 26 +++++++++----- fs/jbd2/transaction.c | 2 +- 16 files changed, 259 insertions(+), 128 deletions(-)
fs/ext4/ext4.h +24 -2
@@ -1447,6 +1447,24 @@ struct ext4_super_block {#define EXT4_ENC_UTF8_12_1 1 +/* Types of ext4 journal triggers */ +enum ext4_journal_trigger_type { +EXT4_JTR_NONE /* This must be the last entry for indexing to work! */ +}; + +#define EXT4_JOURNAL_TRIGGER_COUNT EXT4_JTR_NONE + +struct ext4_journal_trigger { +struct jbd2_buffer_trigger_type tr_triggers; +struct super_block *sb; +}; + +static inline struct ext4_journal_trigger *EXT4_TRIGGER ( +struct jbd2_buffer_trigger_type *trigger) +{ + return container_of(trigger, struct ext4_journal_trigger, tr_triggers); +} +/* * fourth extended-fs super-block data in memory */
@@ -1625,6 +1643,9 @@ struct ext4_sb_info {struct mb_cache *s_ea_inode_cache;spinlock_t s_es_lock____cacheline_aligned_in_smp ; +/* Journal triggers for checksum computation */ +struct ext4_journal_trigger s_journal_triggers[EXT4_JOURNAL_TRIGGER_COUNT ]; +/* Ratelimit ext4 messages. */ struct ratelimit_state s_err_ratelimit_state;struct ratelimit_state s_warning_ratelimit_state;
@@ -2920,13 +2941,14 @@ int ext4_get_block(struct inode *inode, sector_t iblock,int ext4_da_get_block_prep (struct inode *inode,sector_t iblock,struct buffer_head *bh,int create);int ext4_walk_page_buffers (handle_t *handle, +struct inode *inode,struct buffer_head *head,unsigned from,unsigned to,int *partial, -int (*fn)(handle_t *handle, +int (*fn)(handle_t *handle,struct inode *inode,struct buffer_head *bh)); -int do_journal_get_write_access (handle_t *handle, +int do_journal_get_write_access (handle_t *handle,struct inode *inode,struct buffer_head *bh);#define FALL_BACK_TO_NONDELALLOC 1#define CONVERT_INLINE_DATA 2
fs/ext4/ext4_jbd2.c +31 -12
68 lines not on this page · raw message
fs/ext4/ext4_jbd2.h +12 -6
@@ -231,26 +231,32 @@ int ext4_expand_extra_isize(struct inode *inode,* Wrapper functions with which ext4 calls into JBD. */ int __ext4_journal_get_write_access (const char *where,unsigned int line, -handle_t *handle,struct buffer_head *bh); +handle_t *handle,struct super_block *sb, +struct buffer_head *bh, +enum ext4_journal_trigger_type trigger_type);int __ext4_forget (const char *where,unsigned int line,handle_t *handle,int is_metadata,struct inode *inode,struct buffer_head *bh,ext4_fsblk_t blocknr);int __ext4_journal_get_create_access (const char *where,unsigned int line, -handle_t *handle,struct buffer_head *bh); +handle_t *handle,struct super_block *sb, +struct buffer_head *bh, +enum ext4_journal_trigger_type trigger_type);int __ext4_handle_dirty_metadata (const char *where,unsigned int line,handle_t *handle,struct inode *inode,struct buffer_head *bh); -#define ext4_journal_get_write_access (handle, bh) \ - __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh)) +#define ext4_journal_get_write_access (handle, sb, bh, trigger_type) \ + __ext4_journal_get_write_access(__func__, __LINE__, (handle), (sb), \ + (bh), (trigger_type))#define ext4_forget (handle, is_metadata, inode, bh, block_nr) \ __ext4_forget(__func__, __LINE__, (handle), (is_metadata), (inode), \ (bh), (block_nr)) -#define ext4_journal_get_create_access (handle, bh) \ - __ext4_journal_get_create_access(__func__, __LINE__, (handle), (bh)) +#define ext4_journal_get_create_access (handle, sb, bh, trigger_type) \ + __ext4_journal_get_create_access(__func__, __LINE__, (handle), (sb), \ + (bh), (trigger_type))#define ext4_handle_dirty_metadata (handle, inode, bh) \ __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \ (bh))
fs/ext4/extents.c +8 -4
@@ -139,7 +139,8 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode,if (path->p_bh) {/* path points to block */ BUFFER_TRACE (path->p_bh,"get_write_access" ); -return ext4_journal_get_write_access (handle, path->p_bh); +return ext4_journal_get_write_access (handle, inode->i_sb, + path->p_bh,EXT4_JTR_NONE ); }/* path points to leaf/index in inode body */ /* we use in-core data, no need to protect them */
@@ -1082,7 +1083,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, }lock_buffer (bh); - err =ext4_journal_get_create_access (handle, bh); + err =ext4_journal_get_create_access (handle, inode->i_sb, bh, +EXT4_JTR_NONE );if (err) goto cleanup;
@@ -1160,7 +1162,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, }lock_buffer (bh); - err =ext4_journal_get_create_access (handle, bh); + err =ext4_journal_get_create_access (handle, inode->i_sb, bh, +EXT4_JTR_NONE );if (err) goto cleanup;
@@ -1286,7 +1289,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,return -ENOMEM ;lock_buffer (bh); - err =ext4_journal_get_create_access (handle, bh); + err =ext4_journal_get_create_access (handle, inode->i_sb, bh, +EXT4_JTR_NONE );if (err) {unlock_buffer (bh); goto out;
fs/ext4/file.c +2 -1
@@ -822,7 +822,8 @@ static int ext4_sample_last_mounted(struct super_block *sb,if (IS_ERR (handle)) goto out;BUFFER_TRACE (sbi->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, sbi->s_sbh); + err =ext4_journal_get_write_access (handle, sb, sbi->s_sbh, +EXT4_JTR_NONE );if (err) goto out_journal;lock_buffer (sbi->s_sbh);
fs/ext4/ialloc.c +12 -7
@@ -300,7 +300,8 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) }BUFFER_TRACE (bitmap_bh,"get_write_access" ); - fatal =ext4_journal_get_write_access (handle, bitmap_bh); + fatal =ext4_journal_get_write_access (handle, sb, bitmap_bh, +EXT4_JTR_NONE );if (fatal) goto error_return;
@@ -308,7 +309,8 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) gdp =ext4_get_group_desc (sb, block_group, &bh2);if (gdp) {BUFFER_TRACE (bh2,"get_write_access" ); - fatal =ext4_journal_get_write_access (handle, bh2); + fatal =ext4_journal_get_write_access (handle, sb, bh2, +EXT4_JTR_NONE ); }ext4_lock_group (sb, block_group); cleared =ext4_test_and_clear_bit (bit, bitmap_bh->b_data);
@@ -1085,7 +1087,8 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns, } }BUFFER_TRACE (inode_bitmap_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, inode_bitmap_bh); + err =ext4_journal_get_write_access (handle, sb, inode_bitmap_bh, +EXT4_JTR_NONE );if (err) {ext4_std_error (sb, err); goto out;
@@ -1127,7 +1130,8 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns, }BUFFER_TRACE (group_desc_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, group_desc_bh); + err =ext4_journal_get_write_access (handle, sb, group_desc_bh, +EXT4_JTR_NONE );if (err) {ext4_std_error (sb, err); goto out;
@@ -1144,7 +1148,8 @@ struct inode *__ext4_new_inode(struct user_namespace *mnt_userns, goto out; }BUFFER_TRACE (block_bitmap_bh,"get block bitmap access" ); - err =ext4_journal_get_write_access (handle, block_bitmap_bh); + err =ext4_journal_get_write_access (handle, sb, block_bitmap_bh, +EXT4_JTR_NONE );if (err) {brelse (block_bitmap_bh);ext4_std_error (sb, err);
@@ -1583,8 +1588,8 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, num = sbi->s_itb_per_group - used_blks;BUFFER_TRACE (group_desc_bh,"get_write_access" ); - ret =ext4_journal_get_write_access (handle, - group_desc_bh); + ret =ext4_journal_get_write_access (handle, sb, group_desc_bh, +EXT4_JTR_NONE );if (ret) goto err_out;
fs/ext4/indirect.c +10 -5
@@ -354,7 +354,8 @@ static int ext4_alloc_branch(handle_t *handle, }lock_buffer (bh);BUFFER_TRACE (bh,"call get_create_access" ); - err =ext4_journal_get_create_access (handle, bh); + err =ext4_journal_get_create_access (handle, ar->inode->i_sb, + bh,EXT4_JTR_NONE );if (err) {unlock_buffer (bh); goto failed;
@@ -429,7 +430,8 @@ static int ext4_splice_branch(handle_t *handle,*/ if (where->bh) {BUFFER_TRACE (where->bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, where->bh); + err =ext4_journal_get_write_access (handle, ar->inode->i_sb, + where->bh,EXT4_JTR_NONE );if (err) goto err_out; }
@@ -728,7 +730,8 @@ static int ext4_ind_truncate_ensure_credits(handle_t *handle,return ret;if (bh) {BUFFER_TRACE (bh,"retaking write access" ); - ret =ext4_journal_get_write_access (handle, bh); + ret =ext4_journal_get_write_access (handle, inode->i_sb, bh, +EXT4_JTR_NONE );if (unlikely (ret))return ret; }
@@ -916,7 +919,8 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,if (this_bh) {/* For indirect block */ BUFFER_TRACE (this_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, this_bh); + err =ext4_journal_get_write_access (handle, inode->i_sb, + this_bh,EXT4_JTR_NONE );/* Important: if we can't update the indirect pointers * to the blocks, we can't free them. */ if (err)
@@ -1079,7 +1083,8 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,*/ BUFFER_TRACE (parent_bh,"get_write_access" );if (!ext4_journal_get_write_access (handle, - parent_bh)){ + inode->i_sb, parent_bh, +EXT4_JTR_NONE )) { *p =0 ;BUFFER_TRACE (parent_bh,"call ext4_handle_dirty_metadata" );
fs/ext4/inline.c +17 -9
@@ -264,7 +264,8 @@ static int ext4_create_inline_data(handle_t *handle,return error;BUFFER_TRACE (is.iloc.bh,"get_write_access" ); - error =ext4_journal_get_write_access (handle, is.iloc.bh); + error =ext4_journal_get_write_access (handle, inode->i_sb, is.iloc.bh, +EXT4_JTR_NONE );if (error) goto out;
@@ -350,7 +351,8 @@ static int ext4_update_inline_data(handle_t *handle, struct inode *inode, goto out;BUFFER_TRACE (is.iloc.bh,"get_write_access" ); - error =ext4_journal_get_write_access (handle, is.iloc.bh); + error =ext4_journal_get_write_access (handle, inode->i_sb, is.iloc.bh, +EXT4_JTR_NONE );if (error) goto out;
@@ -427,7 +429,8 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, goto out;BUFFER_TRACE (is.iloc.bh,"get_write_access" ); - error =ext4_journal_get_write_access (handle, is.iloc.bh); + error =ext4_journal_get_write_access (handle, inode->i_sb, is.iloc.bh, +EXT4_JTR_NONE );if (error) goto out;
@@ -593,7 +596,7 @@ static int ext4_convert_inline_data_to_extent(struct address_space *mapping, ret =__block_write_begin (page, from, to, ext4_get_block);if (!ret &&ext4_should_journal_data (inode)) { - ret =ext4_walk_page_buffers (handle,page_buffers (page), + ret =ext4_walk_page_buffers (handle, inode,page_buffers (page), from, to,NULL , do_journal_get_write_access); }
@@ -682,7 +685,8 @@ int ext4_try_to_write_inline_data(struct address_space *mapping, goto convert; } - ret =ext4_journal_get_write_access (handle, iloc.bh); + ret =ext4_journal_get_write_access (handle, inode->i_sb, iloc.bh, +EXT4_JTR_NONE );if (ret) goto out;
@@ -923,7 +927,8 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,if (ret <0 ) goto out_release_page; } - ret =ext4_journal_get_write_access (handle, iloc.bh); + ret =ext4_journal_get_write_access (handle, inode->i_sb, iloc.bh, +EXT4_JTR_NONE );if (ret) goto out_release_page;
@@ -1028,7 +1033,8 @@ static int ext4_add_dirent_to_inline(handle_t *handle,return err;BUFFER_TRACE (iloc->bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, iloc->bh); + err =ext4_journal_get_write_access (handle, dir->i_sb, iloc->bh, +EXT4_JTR_NONE );if (err)return err;ext4_insert_dentry (dir, inode, de, inline_size, fname);
@@ -1223,7 +1229,8 @@ static int ext4_convert_inline_data_nolock(handle_t *handle, }lock_buffer (data_bh); - error =ext4_journal_get_create_access (handle, data_bh); + error =ext4_journal_get_create_access (handle, inode->i_sb, data_bh, +EXT4_JTR_NONE );if (error) {unlock_buffer (data_bh); error = -EIO ;
@@ -1707,7 +1714,8 @@ int ext4_delete_inline_entry(handle_t *handle, }BUFFER_TRACE (bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, dir->i_sb, bh, +EXT4_JTR_NONE );if (err) goto out;
fs/ext4/inode.c +49 -35
242 lines not on this page · raw message
fs/ext4/ioctl.c +3 -1
@@ -1154,7 +1154,9 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err =PTR_ERR (handle); goto pwsalt_err_exit; } - err =ext4_journal_get_write_access (handle, sbi->s_sbh); + err =ext4_journal_get_write_access (handle, sb, + sbi->s_sbh, +EXT4_JTR_NONE );if (err) goto pwsalt_err_journal;lock_buffer (sbi->s_sbh);
fs/ext4/mballoc.c +9 -6
@@ -3726,7 +3726,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, }BUFFER_TRACE (bitmap_bh,"getting write access" ); - err =ext4_journal_get_write_access (handle, bitmap_bh); + err =ext4_journal_get_write_access (handle, sb, bitmap_bh, +EXT4_JTR_NONE );if (err) goto out_err;
@@ -3739,7 +3740,7 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, ext4_free_group_clusters(sb, gdp));BUFFER_TRACE (gdp_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gdp_bh); + err =ext4_journal_get_write_access (handle, sb, gdp_bh,EXT4_JTR_NONE );if (err) goto out_err;
@@ -5916,7 +5917,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, }BUFFER_TRACE (bitmap_bh,"getting write access" ); - err =ext4_journal_get_write_access (handle, bitmap_bh); + err =ext4_journal_get_write_access (handle, sb, bitmap_bh, +EXT4_JTR_NONE );if (err) goto error_return;
@@ -5926,7 +5928,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,* using it */ BUFFER_TRACE (gd_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gd_bh); + err =ext4_journal_get_write_access (handle, sb, gd_bh,EXT4_JTR_NONE );if (err) goto error_return;#ifdef AGGRESSIVE_CHECK
@@ -6107,7 +6109,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, }BUFFER_TRACE (bitmap_bh,"getting write access" ); - err =ext4_journal_get_write_access (handle, bitmap_bh); + err =ext4_journal_get_write_access (handle, sb, bitmap_bh, +EXT4_JTR_NONE );if (err) goto error_return;
@@ -6117,7 +6120,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,* using it */ BUFFER_TRACE (gd_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gd_bh); + err =ext4_journal_get_write_access (handle, sb, gd_bh,EXT4_JTR_NONE );if (err) goto error_return;
fs/ext4/namei.c +26 -14
@@ -70,7 +70,8 @@ static struct buffer_head *ext4_append(handle_t *handle, inode->i_size += inode->i_sb->s_blocksize;EXT4_I (inode)->i_disksize = inode->i_size;BUFFER_TRACE (bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, inode->i_sb, bh, +EXT4_JTR_NONE );if (err) {brelse (bh);ext4_std_error (inode->i_sb, err);
@@ -1927,12 +1928,14 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, }BUFFER_TRACE (*bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, *bh); + err =ext4_journal_get_write_access (handle, dir->i_sb, *bh, +EXT4_JTR_NONE );if (err) goto journal_error;BUFFER_TRACE (frame->bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, frame->bh); + err =ext4_journal_get_write_access (handle, dir->i_sb, frame->bh, +EXT4_JTR_NONE );if (err) goto journal_error;
@@ -2109,7 +2112,8 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,return err; }BUFFER_TRACE (bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, dir->i_sb, bh, +EXT4_JTR_NONE );if (err) {ext4_std_error (dir->i_sb, err);return err;
@@ -2167,7 +2171,8 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, blocksize = dir->i_sb->s_blocksize;dxtrace (printk (KERN_DEBUG "Creating index: inode %lu\n" , dir->i_ino));BUFFER_TRACE (bh,"get_write_access" ); - retval =ext4_journal_get_write_access (handle, bh); + retval =ext4_journal_get_write_access (handle, dir->i_sb, bh, +EXT4_JTR_NONE );if (retval) {ext4_std_error (dir->i_sb, retval);brelse (bh);
@@ -2419,7 +2424,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, }BUFFER_TRACE (bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, sb, bh,EXT4_JTR_NONE );if (err) goto journal_error;
@@ -2476,7 +2481,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, node2->fake.rec_len =ext4_rec_len_to_disk (sb->s_blocksize, sb->s_blocksize);BUFFER_TRACE (frame->bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, frame->bh); + err =ext4_journal_get_write_access (handle, sb, frame->bh, +EXT4_JTR_NONE );if (err) goto journal_error;if (!add_level) {
@@ -2486,8 +2492,9 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, icount1, icount2));BUFFER_TRACE (frame->bh,"get_write_access" );/* index root */ - err =ext4_journal_get_write_access (handle, - (frame -1 )->bh); + err =ext4_journal_get_write_access (handle, sb, + (frame -1 )->bh, +EXT4_JTR_NONE );if (err) goto journal_error;
@@ -2636,7 +2643,8 @@ static int ext4_delete_entry(handle_t *handle, csum_size =sizeof (struct ext4_dir_entry_tail );BUFFER_TRACE (bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, dir->i_sb, bh, +EXT4_JTR_NONE );if (unlikely (err)) goto out;
@@ -3088,7 +3096,8 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);BUFFER_TRACE (sbi->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, sbi->s_sbh); + err =ext4_journal_get_write_access (handle, sb, sbi->s_sbh, +EXT4_JTR_NONE );if (err) goto out;
@@ -3186,7 +3195,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)if (prev == &sbi->s_orphan) {jbd_debug (4 ,"superblock will point to %u\n" , ino_next);BUFFER_TRACE (sbi->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, sbi->s_sbh); + err =ext4_journal_get_write_access (handle, inode->i_sb, + sbi->s_sbh,EXT4_JTR_NONE );if (err) {mutex_unlock (&sbi->s_orphan_lock); goto out_brelse;
@@ -3675,7 +3685,8 @@ static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent)if (le32_to_cpu (ent->parent_de->inode) != ent->dir->i_ino)return -EFSCORRUPTED ;BUFFER_TRACE (ent->dir_bh,"get_write_access" ); -return ext4_journal_get_write_access (handle, ent->dir_bh); +return ext4_journal_get_write_access (handle, ent->dir->i_sb, + ent->dir_bh,EXT4_JTR_NONE ); } static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
@@ -3710,7 +3721,8 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,int retval, retval2;BUFFER_TRACE (ent->bh,"get write access" ); - retval =ext4_journal_get_write_access (handle, ent->bh); + retval =ext4_journal_get_write_access (handle, ent->dir->i_sb, ent->bh, +EXT4_JTR_NONE );if (retval)return retval; ent->de->inode =cpu_to_le32 (ino);
fs/ext4/resize.c +23 -15
@@ -409,7 +409,8 @@ static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,if (unlikely (!bh))return ERR_PTR (-ENOMEM );BUFFER_TRACE (bh,"get_write_access" ); -if ((err =ext4_journal_get_write_access (handle, bh))) { + err =ext4_journal_get_write_access (handle, sb, bh,EXT4_JTR_NONE ); +if (err) {brelse (bh); bh =ERR_PTR (err); }else {
@@ -474,7 +475,8 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,return -ENOMEM ;BUFFER_TRACE (bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, sb, bh, +EXT4_JTR_NONE );if (err) {brelse (bh);return err;
@@ -569,7 +571,8 @@ static int setup_new_flex_group_blocks(struct super_block *sb, }BUFFER_TRACE (gdb,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gdb); + err =ext4_journal_get_write_access (handle, sb, gdb, +EXT4_JTR_NONE );if (err) {brelse (gdb); goto out;
@@ -837,17 +840,18 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, }BUFFER_TRACE (EXT4_SB (sb)->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle,EXT4_SB (sb)->s_sbh); + err =ext4_journal_get_write_access (handle, sb,EXT4_SB (sb)->s_sbh, +EXT4_JTR_NONE );if (unlikely (err)) goto errout;BUFFER_TRACE (gdb_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gdb_bh); + err =ext4_journal_get_write_access (handle, sb, gdb_bh,EXT4_JTR_NONE );if (unlikely (err)) goto errout;BUFFER_TRACE (dind,"get_write_access" ); - err =ext4_journal_get_write_access (handle, dind); + err =ext4_journal_get_write_access (handle, sb, dind,EXT4_JTR_NONE );if (unlikely (err)) {ext4_std_error (sb, err); goto errout;
@@ -956,7 +960,7 @@ static int add_new_gdb_meta_bg(struct super_block *sb, n_group_desc[gdb_num] = gdb_bh;BUFFER_TRACE (gdb_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gdb_bh); + err =ext4_journal_get_write_access (handle, sb, gdb_bh,EXT4_JTR_NONE );if (err) {kvfree (n_group_desc);brelse (gdb_bh);
@@ -1042,7 +1046,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,for (i =0 ; i < reserved_gdb; i++) {BUFFER_TRACE (primary[i],"get_write_access" ); -if ((err =ext4_journal_get_write_access (handle, primary[i]))) +if ((err =ext4_journal_get_write_access (handle, sb, primary[i], +EXT4_JTR_NONE ))) goto exit_bh; }
@@ -1149,10 +1154,9 @@ static void update_backups(struct super_block *sb, sector_t blk_off, char *data, backup_block, backup_block - ext4_group_first_block_no(sb, group));BUFFER_TRACE (bh,"get_write_access" ); -if ((err =ext4_journal_get_write_access (handle, bh))) { -brelse (bh); +if ((err =ext4_journal_get_write_access (handle, sb, bh, +EXT4_JTR_NONE )))break ; - }lock_buffer (bh);memcpy (bh->b_data, data, size);if (rest)
@@ -1232,7 +1236,8 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, gdb_bh =sbi_array_rcu_deref (sbi, s_group_desc, gdb_num);BUFFER_TRACE (gdb_bh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, gdb_bh); + err =ext4_journal_get_write_access (handle, sb, gdb_bh, +EXT4_JTR_NONE );if (!err && reserved_gdb &&ext4_bg_num_gdb (sb, group)) err =reserve_backup_gdb (handle, resize_inode, group);
@@ -1509,7 +1514,8 @@ static int ext4_flex_group_add(struct super_block *sb, }BUFFER_TRACE (sbi->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, sbi->s_sbh); + err =ext4_journal_get_write_access (handle, sb, sbi->s_sbh, +EXT4_JTR_NONE );if (err) goto exit_journal;
@@ -1722,7 +1728,8 @@ static int ext4_group_extend_no_check(struct super_block *sb, }BUFFER_TRACE (EXT4_SB (sb)->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle,EXT4_SB (sb)->s_sbh); + err =ext4_journal_get_write_access (handle, sb,EXT4_SB (sb)->s_sbh, +EXT4_JTR_NONE );if (err) {ext4_warning (sb,"error %d on journal write access" , err); goto errout;
@@ -1884,7 +1891,8 @@ static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode)return PTR_ERR (handle);BUFFER_TRACE (sbi->s_sbh,"get_write_access" ); - err =ext4_journal_get_write_access (handle, sbi->s_sbh); + err =ext4_journal_get_write_access (handle, sb, sbi->s_sbh, +EXT4_JTR_NONE );if (err) goto errout;
fs/ext4/super.c +15 -1
@@ -4014,6 +4014,20 @@ static const char *ext4_quota_mode(struct super_block *sb)#endif } +static void ext4_setup_csum_trigger (struct super_block *sb, +enum ext4_journal_trigger_type type, +void (*trigger)( +struct jbd2_buffer_trigger_type *type, +struct buffer_head *bh, +void *mapped_data, +size_t size)) +{ +struct ext4_sb_info *sbi =EXT4_SB (sb); + + sbi->s_journal_triggers[type].sb = sb; + sbi->s_journal_triggers[type].tr_triggers.t_frozen = trigger; +} +static int ext4_fill_super (struct super_block *sb,void *data,int silent) {struct dax_device *dax_dev =fs_dax_get_by_bdev (sb->s_bdev);
@@ -6609,7 +6623,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,if (!bh) goto out;BUFFER_TRACE (bh,"get write access" ); - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, sb, bh,EXT4_JTR_NONE );if (err) {brelse (bh);return err;
fs/ext4/xattr.c +17 -9
@@ -791,7 +791,8 @@ static void ext4_xattr_update_super_block(handle_t *handle,return ;BUFFER_TRACE (EXT4_SB (sb)->s_sbh,"get_write_access" ); -if (ext4_journal_get_write_access (handle,EXT4_SB (sb)->s_sbh) ==0 ) { +if (ext4_journal_get_write_access (handle, sb,EXT4_SB (sb)->s_sbh, +EXT4_JTR_NONE ) ==0 ) {lock_buffer (EXT4_SB (sb)->s_sbh);ext4_set_feature_xattr (sb);ext4_superblock_csum_set (sb);
@@ -1169,7 +1170,8 @@ ext4_xattr_inode_dec_ref_all(handle_t *handle, struct inode *parent,continue ; }if (err >0 ) { - err =ext4_journal_get_write_access (handle, bh); + err =ext4_journal_get_write_access (handle, + parent->i_sb, bh,EXT4_JTR_NONE );if (err) { ext4_warning_inode(ea_inode, "Re-get write access err=%d",
@@ -1230,7 +1232,8 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode,int error =0 ;BUFFER_TRACE (bh,"get_write_access" ); - error =ext4_journal_get_write_access (handle, bh); + error =ext4_journal_get_write_access (handle, inode->i_sb, bh, +EXT4_JTR_NONE );if (error) goto out;
@@ -1371,7 +1374,8 @@ static int ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode, "ext4_getblk() return bh = NULL");return -EFSCORRUPTED ; } - ret =ext4_journal_get_write_access (handle, bh); + ret =ext4_journal_get_write_access (handle, ea_inode->i_sb, bh, +EXT4_JTR_NONE );if (ret) goto out;
@@ -1855,7 +1859,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,if (s->base) {BUFFER_TRACE (bs->bh,"get_write_access" ); - error =ext4_journal_get_write_access (handle, bs->bh); + error =ext4_journal_get_write_access (handle, sb, bs->bh, +EXT4_JTR_NONE );if (error) goto cleanup;lock_buffer (bs->bh);
@@ -1987,8 +1992,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,if (error) goto cleanup;BUFFER_TRACE (new_bh,"get_write_access" ); - error =ext4_journal_get_write_access (handle, - new_bh); + error =ext4_journal_get_write_access ( + handle, sb, new_bh, +EXT4_JTR_NONE );if (error) goto cleanup_dquot;lock_buffer (new_bh);
@@ -2092,7 +2098,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, }lock_buffer (new_bh); - error =ext4_journal_get_create_access (handle, new_bh); + error =ext4_journal_get_create_access (handle, sb, + new_bh,EXT4_JTR_NONE );if (error) {unlock_buffer (new_bh); error = -EIO ;
@@ -2848,7 +2855,8 @@ int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, goto cleanup; } - error =ext4_journal_get_write_access (handle, iloc.bh); + error =ext4_journal_get_write_access (handle, inode->i_sb, + iloc.bh,EXT4_JTR_NONE );if (error) {EXT4_ERROR_INODE (inode,"write access (error %d)" , error);
fs/jbd2/transaction.c +1 -1
@@ -1404,7 +1404,7 @@ void jbd2_journal_set_triggers(struct buffer_head *bh, {struct journal_head *jh =jbd2_journal_grab_journal_head (bh); -if (WARN_ON (!jh)) +if (WARN_ON_ONCE (!jh))return ; jh->b_triggers = type;jbd2_journal_put_journal_head (jh);
Signature · 1 line
2.26.2
Jan Kara
reviewerPATCH v7 2/5 ext4: Move orphan inode handling into a separate file
In reply to Jan KaraMove functions for handling orphan inodes into a new file fs/ext4/orphan.c to have them in one place and somewhat reduce size of other files. No code changes.
--- fs/ext4/Makefile | 2 +- fs/ext4/ext4.h | 11 +- fs/ext4/namei.c | 182 ------------------------ fs/ext4/orphan.c | 363 +++++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/super.c | 180 +---------------------- 5 files changed, 375 insertions(+), 363 deletions(-) create mode 100644 fs/ext4/orphan.c
fs/ext4/Makefile +1 -1
@@ -10,7 +10,7 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \ indirect.o inline.o inode.o ioctl.o mballoc.o migrate.o \ mmp.o move_extent.o namei.o page-io.o readpage.o resize.o \ super.o symlink.o sysfs.o xattr.o xattr_hurd.o xattr_trusted.o \ - xattr_user.o fast_commit.o + xattr_user.o fast_commit.o orphan.o ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
fs/ext4/ext4.h +9 -2
@@ -2168,6 +2168,8 @@ static inline bool ext4_has_incompat_features(struct super_block *sb)return (EXT4_SB (sb)->s_es->s_feature_incompat !=0 ); } +extern int ext4_feature_set_ok (struct super_block *sb,int readonly); +/* * Superblock flags */
@@ -3028,8 +3030,6 @@ 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 *); -extern int ext4_orphan_del (handle_t *,struct inode *);extern int ext4_htree_fill_tree (struct file *dir_file,__u32 start_hash,__u32 start_minor_hash,__u32 *next_hash); extern int ext4_search_dir(struct buffer_head *bh,
@@ -3498,6 +3498,7 @@ static inline bool ext4_is_quota_journalled(struct super_block *sb)return (ext4_has_feature_quota (sb) || sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]); } +int ext4_enable_quotas (struct super_block *sb);#endif /*
@@ -3759,6 +3760,12 @@ extern void ext4_stop_mmpd(struct ext4_sb_info *sbi);/* verity.c */ extern const struct fsverity_operations ext4_verityops; +/* orphan.c */ +extern int ext4_orphan_add (handle_t *,struct inode *); +extern int ext4_orphan_del (handle_t *,struct inode *); +extern void ext4_orphan_cleanup (struct super_block *sb, +struct ext4_super_block *es); +/* * Add new method to test whether block and inode bitmaps are properly * initialized. With uninit_bg reading the block from disk is not enough
fs/ext4/namei.c +0 -182
188 lines not on this page · raw message
fs/ext4/orphan.c new file +363 -0
363 lines not on this page · raw message
fs/ext4/super.c +2 -178
222 lines not on this page · raw message
Signature · 1 line
2.26.2
Jan Kara
reviewerPATCH v7 3/5 ext4: Speedup ext4 orphan inode handling
In reply to Jan KaraExt4 orphan inode handling is a bottleneck for workloads which heavily truncate / unlink small files since it contends on the global s_orphan_mutex lock (and generally it's difficult to improve scalability of the ondisk linked list of orphaned inodes).
This patch implements new way of handling orphan inodes. Instead of linking orphaned inode into a linked list, we store it's inode number in a new special file which we call "orphan file". Only if there's no more space in the orphan file (too many inodes are currently orphaned) we fall back to using old style linked list. Currently we protect operations in the orphan file with a spinlock for simplicity but even in this setting we can substantially reduce the length of the critical section and thus speedup some workloads. In the next patch we improve this by making orphan handling lockless.
Note that the change is backwards compatible when the filesystem is clean - the existence of the orphan file is a compat feature, we set another ro-compat feature indicating orphan file needs scanning for orphaned inodes when mounting filesystem read-write. This ro-compat feature gets cleared on unmount / remount read-only.
Some performance data from 80 CPU Xeon Server with 512 GB of RAM, filesystem located on SSD, average of 5 runs:
stress-orphan (microbenchmark truncating files byte-by-byte from N processes in parallel)
Threads Time Time
Vanilla Patched
1 1.057200 0.945600 2 1.680400 1.331800 4 2.547000 1.995000 8 7.049400 6.424200 16 14.827800 14.937600 32 40.948200 33.038200 64 87.787400 60.823600
128 206.504000 122.941400
So we can see significant wins all over the board.
--- fs/ext4/ext4.h | 69 +++++++++- fs/ext4/inode.c | 3 +- fs/ext4/orphan.c | 340 +++++++++++++++++++++++++++++++++++++++++------ fs/ext4/super.c | 34 ++++- 4 files changed, 394 insertions(+), 52 deletions(-)
fs/ext4/ext4.h +62 -7
@@ -1034,7 +1034,14 @@ struct ext4_inode_info {*/ struct rw_semaphore xattr_sem; -struct list_head i_orphan;/* unlinked but open inodes */ +/* +* Inodes with EXT4_STATE_ORPHAN_FILE use i_orphan_idx. Otherwise +* i_orphan is used. +*/ +union { +struct list_head i_orphan;/* unlinked but open inodes */ +unsigned int i_orphan_idx;/* Index in orphan file */ + };/* Fast commit related info */
@@ -1428,7 +1435,8 @@ struct ext4_super_block {__u8 s_last_error_errcode;__le16 s_encoding;/* Filename charset encoding */ __le16 s_encoding_flags;/* Filename charset encoding flags */ -__le32 s_reserved[95 ];/* Padding to the end of the block */ +__le32 s_orphan_file_inum;/* Inode for tracking orphan inodes */ +__le32 s_reserved[94 ];/* Padding to the end of the block */ __le32 s_checksum;/* crc32c(superblock) */ };
@@ -1449,6 +1457,7 @@ struct ext4_super_block {/* Types of ext4 journal triggers */ enum ext4_journal_trigger_type { +EXT4_JTR_ORPHAN_FILE ,EXT4_JTR_NONE /* This must be the last entry for indexing to work! */ };
@@ -1465,6 +1474,36 @@ static inline struct ext4_journal_trigger *EXT4_TRIGGER( return container_of(trigger, struct ext4_journal_trigger, tr_triggers); } +#define EXT4_ORPHAN_BLOCK_MAGIC 0x0b10ca04 + +/* Structure at the tail of orphan block */ +struct ext4_orphan_block_tail { +__le32 ob_magic; +__le32 ob_checksum; +}; + +static inline int ext4_inodes_per_orphan_block (struct super_block *sb) +{ +return (sb->s_blocksize -sizeof (struct ext4_orphan_block_tail )) / +sizeof (u32); +} + +struct ext4_orphan_block { +int ob_free_entries;/* Number of free orphan entries in block */ +struct buffer_head *ob_bh;/* Buffer for orphan block */ +}; + +/* +* Info about orphan file. +*/ +struct ext4_orphan_info { +spinlock_t of_lock; +int of_blocks;/* Number of orphan blocks in a file */ +__u32 of_csum_seed;/* Checksum seed for orphan file */ +struct ext4_orphan_block *of_binfo;/* Array with info about orphan +* file blocks */ +}; +/* * fourth extended-fs super-block data in memory */
@@ -1519,9 +1558,11 @@ struct ext4_sb_info {/* Journaling */ struct journal_s *s_journal; -struct list_head s_orphan; -struct mutex s_orphan_lock;unsigned long s_ext4_flags;/* Ext4 superblock flags */ +struct mutex s_orphan_lock;/* Protects on disk list changes */ +struct list_head s_orphan;/* List of orphaned inodes in on disk +list */ +struct ext4_orphan_info s_orphan_info;unsigned long s_commit_interval;u32 s_max_batch_time;u32 s_min_batch_time;
@@ -1856,6 +1897,7 @@ enum {EXT4_STATE_LUSTRE_EA_INODE ,/* Lustre-style ea_inode */ EXT4_STATE_VERITY_IN_PROGRESS ,/* building fs-verity Merkle tree */ EXT4_STATE_FC_COMMITTING ,/* Fast commit ongoing */ + EXT4_STATE_ORPHAN_FILE, /* Inode orphaned in orphan file */ };#define EXT4_INODE_BIT_FNS (name, field, offset) \
@@ -1957,6 +1999,7 @@ static inline bool ext4_verity_in_progress(struct inode *inode)*/ #define EXT4_FEATURE_COMPAT_FAST_COMMIT 0x0400#define EXT4_FEATURE_COMPAT_STABLE_INODES 0x0800 +#define EXT4_FEATURE_COMPAT_ORPHAN_FILE 0x1000/* Orphan file exists */ #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
@@ -1977,6 +2020,8 @@ static inline bool ext4_verity_in_progress(struct inode *inode)#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000#define EXT4_FEATURE_RO_COMPAT_VERITY 0x8000 +#define EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENT 0x10000/* Orphan file may be +non-empty */ #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
@@ -2060,6 +2105,7 @@ 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_COMPAT_FUNCS(orphan_file, ORPHAN_FILE) EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, SPARSE_SUPER)EXT4_FEATURE_RO_COMPAT_FUNCS (large_file,LARGE_FILE )
@@ -2074,6 +2120,7 @@ EXT4_FEATURE_RO_COMPAT_FUNCS(metadata_csum, METADATA_CSUM) EXT4_FEATURE_RO_COMPAT_FUNCS(readonly, READONLY) EXT4_FEATURE_RO_COMPAT_FUNCS(project, PROJECT) EXT4_FEATURE_RO_COMPAT_FUNCS(verity, VERITY) +EXT4_FEATURE_RO_COMPAT_FUNCS(orphan_present, ORPHAN_PRESENT) EXT4_FEATURE_INCOMPAT_FUNCS(compression, COMPRESSION)EXT4_FEATURE_INCOMPAT_FUNCS (filetype,FILETYPE )
@@ -2107,7 +2154,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(casefold, CASEFOLD) EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT4_FEATURE_RO_COMPAT_BTREE_DIR) -#define EXT4_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR +#define EXT4_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_EXT_ATTR| \ + EXT4_FEATURE_COMPAT_ORPHAN_FILE)#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ EXT4_FEATURE_INCOMPAT_RECOVER| \ EXT4_FEATURE_INCOMPAT_META_BG| \
@@ -2132,7 +2180,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(casefold, CASEFOLD) EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ EXT4_FEATURE_RO_COMPAT_QUOTA |\ EXT4_FEATURE_RO_COMPAT_PROJECT |\ - EXT4_FEATURE_RO_COMPAT_VERITY) + EXT4_FEATURE_RO_COMPAT_VERITY |\ + EXT4_FEATURE_RO_COMPAT_ORPHAN_PRESENT)#define EXTN_FEATURE_FUNCS (ver) \ static inline bool ext4_has_unknown_ext##ver##_compat_features(struct super_block *sb) \
@@ -2182,7 +2231,6 @@ static inline int ext4_forced_shutdown(struct ext4_sb_info *sbi)return test_bit (EXT4_FLAGS_SHUTDOWN , &sbi->s_ext4_flags); } -/* * Default values for user and/or group using reserved blocks */
@@ -3765,6 +3813,13 @@ extern int ext4_orphan_add(handle_t *, struct inode *);extern int ext4_orphan_del (handle_t *,struct inode *);extern void ext4_orphan_cleanup (struct super_block *sb,struct ext4_super_block *es); +extern void ext4_release_orphan_info (struct super_block *sb); +extern int ext4_init_orphan_info (struct super_block *sb); +extern int ext4_orphan_file_empty (struct super_block *sb); +extern void ext4_orphan_file_block_trigger ( +struct jbd2_buffer_trigger_type *triggers, +struct buffer_head *bh, +void *data,size_t size);/* * Add new method to test whether block and inode bitmaps are properly
fs/ext4/inode.c +2 -1
@@ -4624,7 +4624,8 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino, ((ino <EXT4_FIRST_INO (sb) && ino !=EXT4_ROOT_INO ) || ino ==le32_to_cpu (es->s_usr_quota_inum) || ino ==le32_to_cpu (es->s_grp_quota_inum) || - ino == le32_to_cpu(es->s_prj_quota_inum))) || + ino ==le32_to_cpu (es->s_prj_quota_inum) || + ino == le32_to_cpu(es->s_orphan_file_inum))) || (ino <EXT4_ROOT_INO ) || (ino > le32_to_cpu(es->s_inodes_count))) { if (flags & EXT4_IGET_HANDLE)
fs/ext4/orphan.c +301 -39
402 lines not on this page · raw message
fs/ext4/super.c +29 -5
@@ -1174,6 +1174,7 @@ static void ext4_put_super(struct super_block *sb)flush_work (&sbi->s_error_work);destroy_workqueue (sbi->rsv_conversion_wq); +ext4_release_orphan_info (sb);/* * Unregister sysfs before destroying jbd2 journal.
@@ -1199,6 +1200,7 @@ static void ext4_put_super(struct super_block *sb)if (!sb_rdonly (sb) && !aborted) {ext4_clear_feature_journal_needs_recovery (sb); +ext4_clear_feature_orphan_present (sb); es->s_state =cpu_to_le16 (sbi->s_mount_state); }if (!sb_rdonly (sb))
@@ -2684,8 +2686,11 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, es->s_max_mnt_count =cpu_to_le16 (EXT4_DFL_MAX_MNT_COUNT );le16_add_cpu (&es->s_mnt_count,1 );ext4_update_tstamp (es, s_mtime); -if (sbi->s_journal) +if (sbi->s_journal) {ext4_set_feature_journal_needs_recovery (sb); +if (ext4_has_feature_orphan_file (sb)) +ext4_set_feature_orphan_present (sb); + } err =ext4_commit_super (sb); done:
@@ -3960,6 +3965,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) silent =1 ; goto cantfind_ext4; } +ext4_setup_csum_trigger (sb,EXT4_JTR_ORPHAN_FILE , + ext4_orphan_file_block_trigger);/* Load the checksum driver */ sbi->s_chksum_driver =crypto_alloc_shash ("crc32c" ,0 ,0 );
@@ -4624,6 +4631,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) sb->s_root =NULL ; needs_recovery = (es->s_last_orphan !=0 || +ext4_has_feature_orphan_present (sb) ||ext4_has_feature_journal_needs_recovery (sb));if (ext4_has_feature_mmp (sb) && !sb_rdonly (sb))
@@ -4914,12 +4922,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)if (err) goto failed_mount7; + err =ext4_init_orphan_info (sb); +if (err) + goto failed_mount8;#ifdef CONFIG_QUOTA /* Enable quota usage during mount. */ if (ext4_has_feature_quota (sb) && !sb_rdonly (sb)) { err =ext4_enable_quotas (sb);if (err) - goto failed_mount8; + goto failed_mount9; }#endif /* CONFIG_QUOTA */
@@ -4938,7 +4949,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)ext4_msg (sb,KERN_INFO ,"recovery complete" ); err =ext4_mark_recovery_complete (sb, es);if (err) - goto failed_mount8; + goto failed_mount9; }if (EXT4_SB (sb)->s_journal) {if (test_opt (sb,DATA_FLAGS ) ==EXT4_MOUNT_JOURNAL_DATA )
@@ -4984,6 +4995,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)ext4_msg (sb,KERN_ERR ,"VFS: Can't find ext4 filesystem" ); goto failed_mount; +failed_mount9: +ext4_release_orphan_info (sb); failed_mount8:ext4_unregister_sysfs (sb);kobject_put (&sbi->s_kobj);
@@ -5494,8 +5507,15 @@ static int ext4_mark_recovery_complete(struct super_block *sb,if (err <0 ) goto out; -if (ext4_has_feature_journal_needs_recovery (sb) &&sb_rdonly (sb)) { +if (sb_rdonly (sb) && (ext4_has_feature_journal_needs_recovery (sb) || +ext4_has_feature_orphan_present (sb))) { +if (!ext4_orphan_file_empty (sb)) { +ext4_error (sb,"Orphan file not empty on read-only fs." ); + err = -EFSCORRUPTED ; + goto out; + }ext4_clear_feature_journal_needs_recovery (sb); +ext4_clear_feature_orphan_present (sb);ext4_commit_super (sb); } out:
@@ -5638,6 +5658,8 @@ static int ext4_freeze(struct super_block *sb)/* Journal blocked and flushed, clear needs_recovery flag. */ ext4_clear_feature_journal_needs_recovery (sb); +if (ext4_orphan_file_empty (sb)) +ext4_clear_feature_orphan_present (sb); } error =ext4_commit_super (sb);
@@ -5660,6 +5682,8 @@ static int ext4_unfreeze(struct super_block *sb)if (EXT4_SB (sb)->s_journal) {/* Reset the needs_recovery flag before the fs is unlocked. */ ext4_set_feature_journal_needs_recovery (sb); +if (ext4_has_feature_orphan_file (sb)) +ext4_set_feature_orphan_present (sb); }ext4_commit_super (sb);
@@ -5863,7 +5887,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)* around from a previously readonly bdev mount, * require a full umount/remount for now. */ -if (es->s_last_orphan) { +if (es->s_last_orphan || !ext4_orphan_file_empty (sb)) {ext4_msg (sb,KERN_WARNING ,"Couldn't " "remount RDWR because of unprocessed " "orphan inode list. Please "
Signature · 1 line
2.26.2
Jan Kara
reviewerPATCH v7 4/5 ext4: Orphan file documentation
In reply to Jan KaraAdd documentation about the orphan file feature.
--- Documentation/filesystems/ext4/globals.rst | 1 + Documentation/filesystems/ext4/inodes.rst | 10 ++-- Documentation/filesystems/ext4/orphan.rst | 52 +++++++++++++++++++ .../filesystems/ext4/special_inodes.rst | 17 ++++++ Documentation/filesystems/ext4/super.rst | 15 +++++- 5 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 Documentation/filesystems/ext4/orphan.rst
Documentation/filesystems/ext4/globals.rst +1 -0
@@ -11,3 +11,4 @@ have static metadata at fixed locations. .. include:: bitmaps.rst .. include:: mmp.rst .. include:: journal.rst +.. include:: orphan.rst
Documentation/filesystems/ext4/inodes.rst +5 -5
@@ -498,11 +498,11 @@ structure -- inode change time (ctime), access time (atime), data modification time (mtime), and deletion time (dtime). The four fields are 32-bit signed integers that represent seconds since the Unix epoch (1970-01-01 00:00:00 GMT), which means that the fields will overflow in -January 2038. For inodes that are not linked from any directory but are -still open (orphan inodes), the dtime field is overloaded for use with -the orphan list. The superblock field ``s_last_orphan`` points to the -first inode in the orphan list; dtime is then the number of the next -orphaned inode, or zero if there are no more orphans. +January 2038. If the filesystem does not have orphan_file feature, inodes +that are not linked from any directory but are still open (orphan inodes) have +the dtime field overloaded for use with the orphan list. The superblock field +``s_last_orphan`` points to the first inode in the orphan list; dtime is then +the number of the next orphaned inode, or zero if there are no more orphans. If the inode structure size ``sb->s_inode_size`` is larger than 128 bytes and the ``i_inode_extra`` field is large enough to encompass the
Documentation/filesystems/ext4/orphan.rst new file +52 -0
52 lines not on this page · raw message
Documentation/filesystems/ext4/special_inodes.rst +17 -0
@@ -36,3 +36,20 @@ ext4 reserves some inode for special features, as follows: * - 11 - Traditional first non-reserved inode. Usually this is the lost+found directory. See s\_first\_ino in the superblock. +Note that there are also some inodes allocated from non-reserved inode numbers +for other filesystem features which are not referenced from standard directory +hierarchy. These are generally reference from the superblock. They are: + +.. list-table:: + :widths: 20 50 + :header-rows: 1 + + * - Superblock field + - Description + + * - s\_lpf\_ino + - Inode number of lost+found directory. + * - s\_prj\_quota\_inum + - Inode number of quota file tracking project quotas + * - s\_orphan\_file\_inum + - Inode number of file tracking orphan inodes.
Documentation/filesystems/ext4/super.rst +14 -1
@@ -479,7 +479,11 @@ The ext4 superblock is laid out as follows in - Filename charset encoding flags. * - 0x280 - \_\_le32 - - s\_reserved[95] + - s\_orphan\_file\_inum + - Orphan file inode number. + * - 0x284 + - \_\_le32 + - s\_reserved[94] - Padding to the end of the block. * - 0x3FC - \_\_le32
@@ -603,6 +607,11 @@ following: the journal, JBD2 incompat feature (JBD2\_FEATURE\_INCOMPAT\_FAST\_COMMIT) gets set (COMPAT\_FAST\_COMMIT). + * - 0x1000 + - Orphan file allocated. This is the special file for more efficient + tracking of unlinked but still open inodes. When there may be any + entries in the file, we additionally set proper rocompat feature + (RO\_COMPAT\_ORPHAN\_PRESENT). .. _super_incompat:
@@ -713,6 +722,10 @@ the following: - Filesystem tracks project quotas. (RO\_COMPAT\_PROJECT) * - 0x8000 - Verity inodes may be present on the filesystem. (RO\_COMPAT\_VERITY) + * - 0x10000 + - Indicates orphan file may have valid orphan entries and thus we need + to clean them up when mounting the filesystem + (RO\_COMPAT\_ORPHAN\_PRESENT). .. _super_def_hash:
Signature · 1 line
2.26.2
Jan Kara
reviewerPATCH v7 5/5 ext4: Improve scalability of ext4 orphan file handling
In reply to Jan KaraEven though the length of the critical section when adding / removing orphaned inodes was significantly reduced by using orphan file, the contention of lock protecting orphan file still appears high in profiles for truncate / unlink intensive workloads with high number of threads.
This patch makes handling of orphan file completely lockless. Also to reduce conflicts between CPUs different CPUs start searching for empty slot in orphan file in different blocks.
Performance comparison of locked orphan file handling, lockless orphan file handling, and completely disabled orphan inode handling from 80 CPU Xeon Server with 526 GB of RAM, filesystem located on SAS SSD disk, average of 5 runs:
stress-orphan (microbenchmark truncating files byte-by-byte from N processes in parallel)
Threads Time Time Time
Orphan locked Orphan lockless No orphan
1 0.945600 0.939400 0.891200 2 1.331800 1.246600 1.174400 4 1.995000 1.780600 1.713200 8 6.424200 4.900000 4.106000 16 14.937600 8.516400 8.138000 32 33.038200 24.565600 24.002200 64 60.823600 39.844600 38.440200 128 122.941400 70.950400 69.315000
So we can see that with lockless orphan file handling, addition / deletion of orphaned inodes got almost completely out of picture even for a microbenchmark stressing it.
For reaim creat_clo workload on ramdisk there are also noticeable gains (average of 5 runs):
Clients Vanilla (ops/s) Patched (ops/s) creat_clo-1 14705.88 ( 0.00%) 14354.07 * -2.39%* creat_clo-3 27108.43 ( 0.00%) 28301.89 ( 4.40%) creat_clo-5 37406.48 ( 0.00%) 45180.73 * 20.78%* creat_clo-7 41338.58 ( 0.00%) 54687.50 * 32.29%* creat_clo-9 45226.13 ( 0.00%) 62937.07 * 39.16%* creat_clo-11 44000.00 ( 0.00%) 65088.76 * 47.93%* creat_clo-13 36516.85 ( 0.00%) 68661.97 * 88.03%* creat_clo-15 30864.20 ( 0.00%) 69551.78 * 125.35%* creat_clo-17 27478.45 ( 0.00%) 67729.08 * 146.48%* creat_clo-19 25000.00 ( 0.00%) 61621.62 * 146.49%* creat_clo-21 18772.35 ( 0.00%) 63829.79 * 240.02%* creat_clo-23 16698.94 ( 0.00%) 61938.96 * 270.92%* creat_clo-25 14973.05 ( 0.00%) 56947.61 * 280.33%* creat_clo-27 16436.69 ( 0.00%) 65008.03 * 295.51%* creat_clo-29 13949.01 ( 0.00%) 69047.62 * 395.00%* creat_clo-31 14283.52 ( 0.00%) 67982.45 * 375.95%*
--- fs/ext4/ext4.h | 3 +- fs/ext4/orphan.c | 77 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 27 deletions(-)
fs/ext4/ext4.h +1 -2
@@ -1489,7 +1489,7 @@ static inline int ext4_inodes_per_orphan_block(struct super_block *sb) }struct ext4_orphan_block { -int ob_free_entries;/* Number of free orphan entries in block */ +atomic_t ob_free_entries;/* Number of free orphan entries in block */ struct buffer_head *ob_bh;/* Buffer for orphan block */ };
@@ -1497,7 +1497,6 @@ struct ext4_orphan_block {* Info about orphan file. */ struct ext4_orphan_info { -spinlock_t of_lock;int of_blocks;/* Number of orphan blocks in a file */ __u32 of_csum_seed;/* Checksum seed for orphan file */ struct ext4_orphan_block *of_binfo;/* Array with info about orphan
fs/ext4/orphan.c +52 -25
128 lines not on this page · raw message
Signature · 1 line
2.26.2
Theodore Ts'o
maintainerI've been running some tests exercising the orphan_file code, and there are a number of failures:
ext4/orphan_file: 512 tests, 3 failures, 25 skipped, 7325 seconds
Failures: ext4/044 generic/475 generic/643
ext4/orphan_file_1k: 524 tests, 6 failures, 37 skipped, 8361 seconds
Failures: ext4/033 ext4/044 ext4/045 generic/273 generic/476 generic/643
generic/643 is the iomap swap failure, and can be ignored. generic/475 is a pre-existing test flake that involves simulated disk failures, which we can also ignore in the context or orphan_file.
However, ext4/044 is one that looks... interesting:
root@kvm-xfstests:~# e2fsck -fn /dev/vdc e2fsck 1.46.4-orphan-file (22-Aug-2021) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information Orphan file (inode 12) block 0 is not clean. Clear? no
Failed to initialize orphan file.
Recreate? no
This is highly reproducible, and involves using a file system config that is probably a little unusual:
Filesystem features: has_journal ext_attr resize_inode dir_index orphan_file filetype sparse_super large_file
(This was created using "mke2fs -t ext3 -O orphan_file".)
The orphan_file_1k failures seem to involve running out of space in the orphan_file, and the fallback to using the old fashioned orphan list seems to return ENOSPC? For example, from ext4/045:
+mkdir: No space left on device
+Failed to create directories - 19679
ext4/045 creates a lot of directories when calls mkdir (ext4/045 tests creating more than 65000 subdirectories in a directory), and so this seems to be triggering a failure?
- Ted
Jan Kara
reviewerQuoted 27 lines · Theodore Ts'o
I've been running some tests exercising the
orphan_filecode, and there are a number of failures:ext4/orphan_file: 512 tests, 3 failures, 25 skipped, 7325 seconds
Failures: ext4/044 generic/475 generic/643
ext4/orphan_file_1k: 524 tests, 6 failures, 37 skipped, 8361 seconds
Failures: ext4/033 ext4/044 ext4/045 generic/273 generic/476 generic/643generic/643 is the iomap swap failure, and can be ignored. generic/475 is a pre-existing test flake that involves simulated disk failures, which we can also ignore in the context or
orphan_file.However, ext4/044 is one that looks... interesting:
root@kvm-xfstests:~# e2fsck -fn /dev/vdc e2fsck 1.46.4-orphan-file (22-Aug-2021) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information Orphan file (inode 12) block 0 is not clean. Clear? noFailed to initialize orphan file.
Recreate? no
Quoted 6 lines
This is highly reproducible, and involves using a file system config that is probably a little unusual:
Filesystem features:
has_journalext_attrresize_inodedir_indexorphan_filefiletypesparse_superlarge_file(This was created using "mke2fs -t ext3 -O
orphan_file".)
Interesting. I don't see how orphan handling code gets used at all for this test. Hrm. Actually it seems to be a bug in the tools themselves because just "mke2fs -t ext3 -O orphan_file" and "e2fsck -f" reproduces exactly this failure. It seems that when I was adding physical block number to orphan file block checksum, I've broken e2fsck for the situation when metadata_csum is disabled. I've fixed the bug now (relative diff attached, I can resend the full series once the other bugs are dealt with as well).
Quoted 10 lines
The
orphan_file_1kfailures seem to involve running out of space in theorphan_file, and the fallback to using the old fashioned orphan list seems to return ENOSPC? For example, from ext4/045:+mkdir: No space left on device
+Failed to create directories - 19679ext4/045 creates a lot of directories when calls mkdir (ext4/045 tests creating more than 65000 subdirectories in a directory), and so this seems to be triggering a failure?
Strange. I don't see how ext4/045 load could run out of space in the orphan file (and in fact I did test that the fallback when we run out of space in the orphan file works correctly). Anyway, I'll look into it. Thanks for the reports!
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
e2fsck/super.c +12 -8
@@ -578,11 +578,9 @@ static int reinit_orphan_block(ext2_filsys fs,e2fsck_t ctx;blk64_t blk = *block_nr;struct problem_context pctx; -struct ext4_orphan_block_tail *tail; pd = priv_data; ctx = pd->ctx; - tail =ext2fs_orphan_block_tail (fs, pd->buf);/* Orphan file must not have holes */ if (!blk) {
@@ -597,12 +595,18 @@ return_abort: pd->abort =1 ;return BLOCK_ABORT ; } -/* -* Update checksum to match expected buffer contents with appropriate -* block number. -*/ - tail->ob_checksum =ext2fs_do_orphan_file_block_csum (fs, pd->ino, - pd->generation, blk, pd->buf); + +if (ext2fs_has_feature_metadata_csum (fs->super)) { +struct ext4_orphan_block_tail *tail; + + tail =ext2fs_orphan_block_tail (fs, pd->buf); +/* +* Update checksum to match expected buffer contents with +* appropriate block number. +*/ + tail->ob_checksum =ext2fs_do_orphan_file_block_csum (fs, + pd->ino, pd->generation, blk, pd->buf); + }if (!pd->clear) { pd->errcode =io_channel_read_blk64 (fs->io, blk,1 , pd->block_buf);
Jan Kara
reviewerQuoted 8 lines · Jan Kara
Quoted 7 lines · Theodore Ts'o
I've been running some tests exercising the
orphan_filecode, and there are a number of failures:ext4/orphan_file: 512 tests, 3 failures, 25 skipped, 7325 seconds
Failures: ext4/044 generic/475 generic/643
ext4/orphan_file_1k: 524 tests, 6 failures, 37 skipped, 8361 seconds
Failures: ext4/033 ext4/044 ext4/045 generic/273 generic/476 generic/643
So I had a look into the other failures... So ext4/044 works for me after fixing e2fsck (both in 1k and 4k cases). ext4/033, ext4/045, generic/273 fail for me in the 1k case even without orphan file patches so I don't think they are a regression caused by my changes (specifically ext4/045 is a buggy test - I think the directory h-tree is not able to hold that many directories for 1k block size). Interestingly, I couldn't make generic/476 fail for me either with or without my patches so that may be some random failure. I'm now running that test in a loop to see whether the failure will reproduce to investigate.
So overall I don't see any other regressions with my patches (besides that e2fsck bug). Or did I miss something?
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Theodore Ts'o
maintainerQuoted 10 lines · Jan Kara
So I had a look into the other failures... So ext4/044 works for me after fixing e2fsck (both in 1k and 4k cases). ext4/033, ext4/045, generic/273 fail for me in the 1k case even without orphan file patches so I don't think they are a regression caused by my changes (specifically ext4/045 is a buggy test - I think the directory h-tree is not able to hold that many directories for 1k block size). Interestingly, I couldn't make generic/476 fail for me either with or without my patches so that may be some random failure. I'm now running that test in a loop to see whether the failure will reproduce to investigate.
Oh, you're right. I had forgotten I had the following in my 1k.exclude file, and I hadn't copied them over when I set up the orphan_file_1k config.
# The test fails due to too many block group descriptors when the
# block size is 1k ext4/033
# This test uses dioread_nolock which currently isn't supported when
# block_size != PAGE_SIZE. ext4/034
# This test tries to create 65536 directories, and with 1k blocks,
# and long names, we run out of htree depth ext4/045
# This test creates too many inodes on when the block size is 1k
# without using special mkfs.ext4 options to change the inode size. # This test is a bit bogus anyway, and uses a bunch of magic calculations # where it's not clear what it was originally trying to test in the # first place. So let's just skip it for now. generic/273
# This test creates too many extended attributes to fit in a 1k block generic/454
# Normal configurations don't support dax
-g dax
(We can drop ext4/034 from the exclude list since we now *do* support dioread_nolock when block_size < page_size.)
Thanks for the investigating, and apologies for not the reason why I hadn't seen the failures in the 1k case was because they had been suppressed.
- Ted
Jan Kara
reviewerQuoted 41 lines · Theodore Ts'o
Quoted 10 lines · Jan Kara
So I had a look into the other failures... So ext4/044 works for me after fixing e2fsck (both in 1k and 4k cases). ext4/033, ext4/045, generic/273 fail for me in the 1k case even without orphan file patches so I don't think they are a regression caused by my changes (specifically ext4/045 is a buggy test - I think the directory h-tree is not able to hold that many directories for 1k block size). Interestingly, I couldn't make generic/476 fail for me either with or without my patches so that may be some random failure. I'm now running that test in a loop to see whether the failure will reproduce to investigate.
Oh, you're right. I had forgotten I had the following in my 1k.exclude file, and I hadn't copied them over when I set up the
orphan_file_1kconfig.# The test fails due to too many block group descriptors when the
# block size is 1k ext4/033# This test uses
dioread_nolockwhich currently isn't supported when# block_size != PAGE_SIZE. ext4/034# This test tries to create 65536 directories, and with 1k blocks,
# and long names, we run out of htree depth ext4/045# This test creates too many inodes on when the block size is 1k
# without using special mkfs.ext4 options to change the inode size. # This test is a bit bogus anyway, and uses a bunch of magic calculations # where it's not clear what it was originally trying to test in the # first place. So let's just skip it for now. generic/273# This test creates too many extended attributes to fit in a 1k block generic/454
# Normal configurations don't support dax
-g dax
Quoted 6 lines
(We can drop ext4/034 from the exclude list since we now *do* support
dioread_nolockwhenblock_size<page_size.)Thanks for the investigating, and apologies for not the reason why I hadn't seen the failures in the 1k case was because they had been suppressed.
No problem. Glad this is cleared out. I've sent out next version of the e2fsprogs patches with fixed e2fsck bug you've found.
Honza
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
Theodore Ts'o
maintainerQuoted 5 lines · Jan Kara
Interestingly, I couldn't make generic/476
fail for me either with or without my patches so that may be some random failure. I'm now running that test in a loop to see whether the failure will reproduce to investigate.
On my test infrastructure (using gce-xfstests, which uses 5gig test and scratch partitions using PD-SSD as the device, 2CPU's, with 7.5 GB of memory), it's failing 70% of the time in the 1k and orphan_file_1k case.
Looking through my notes, that's a known failure:
generic/476 1k
Run an all-writes fsstress run with multiple threads to shake out bugs in the write path.
50% of the time. fsck complaining corrupted file system block bitmap differences all negative. Possible cause: races loading adjacent block bitmaps in a single 4k page, leading to bitmap updates getting lost?
Eric Whitney reports that it's a punch hole bug, where we are leaking a block or a cluster (in bigalloc); with fixed seed he can repro reliably at 100%.
- Ted
TESTRUNID: tytso-20210825172314 KERNEL: kernel 5.14.0-rc2-xfstests-00019-g3e5533948c16 #326 SMP Mon Aug 23 22:27:25 EDT 2021 x86_64 CMDLINE: --update-files -c 1k -C 10 generic/476 CPUS: 2 MEM: 7680
ext4/1k: 10 tests, 7 failures, 3399 seconds
generic/476 Failed 327s generic/476 Failed 348s generic/476 Failed 344s generic/476 Pass 343s generic/476 Pass 335s generic/476 Failed 348s generic/476 Failed 341s generic/476 Failed 335s generic/476 Failed 345s generic/476 Pass 333s
Totals: 10 tests, 0 skipped, 7 failures, 0 errors, 3399s
FSTESTIMG: gce-xfstests/xfstests-202108232144 FSTESTPRJ: gce-xfstests FSTESTVER: blktests 62ec9d6 (Tue, 1 Jun 2021 10:08:38 -0700) FSTESTVER: e2fsprogs v1.46.4-5-g4cda2545-orphan_file (Sun, 22 Aug 2021 10:07:15 -0400) FSTESTVER: fio fio-3.27 (Wed, 26 May 2021 10:10:32 -0600) FSTESTVER: fsverity v1.4 (Mon, 14 Jun 2021 16:14:52 -0700) FSTESTVER: ima-evm-utils v1.3.2 (Wed, 28 Oct 2020 13:18:08 -0400) FSTESTVER: nvme-cli v1.14-61-gf729e93 (Fri, 25 Jun 2021 10:21:17 -0600) FSTESTVER: quota v4.05-40-g25f16b1 (Tue, 16 Mar 2021 17:57:19 +0100) FSTESTVER: util-linux v2.37 (Tue, 1 Jun 2021 09:52:10 +0200) FSTESTVER: xfsprogs v5.12.0 (Fri, 21 May 2021 15:53:24 -0400) FSTESTVER: xfstests-bld 779b6a0 (Mon, 23 Aug 2021 21:29:52 -0400) FSTESTVER: xfstests linux-v3.8-3295-gddc09fff (Mon, 23 Aug 2021 20:54:57 -0400) FSTESTCFG: 1k FSTESTSET: generic/476 FSTESTOPT: count 10 aex GCE ID: 2585249240830380583
Quoted 4 lines · Jan Kara
Here is the seventh version of my series to speed up orphan inode handling in ext4. I've forgot to add a check that orphan file is not exposed in directory hierarchy. The only change in this version is addition of that fix.
Thanks, applied.
- Ted