From ec7a166a498be607c3882ff11e98b625839e69d0 Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Sat, 9 Feb 2019 16:37:29 +1100 Subject: [PATCH] LU-11922 ldiskfs: make dirdata work with metadata_csum Handle ext4_dir_entry_tail correctly, which is a bogus dir entry contains the checksum at the end of dir leaf block. Fix how we get to the limit on the dx_root, we can't assume the rec_len as 12 as . and .. in front of the dx_root have dirdata. Also includes another fix for large_dir, where we should update checksum for dx_node calling ext4_handle_dirty_dx_node(). The change also makes large_dir patch more consistent with the upstream version. With this we can enable metadata_csum on the targets. Test-Parameters: fstype=ldiskfs envdefinitions=LDISKFS_MKFS_OPTS="-O metadata_csum" Signed-off-by: Li Dongyang Change-Id: I04df8c30d9d423111e2b4031a7e4b9058101016f Reviewed-on: https://review.whamcloud.com/34219 Reviewed-by: Yang Sheng Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Andreas Dilger --- .../patches/rhel7.2/ext4-pdirop.patch | 4 +- .../patches/rhel7.3/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- .../patches/rhel7.4/ext4-large-dir.patch | 43 +++++++++++++--------- .../patches/rhel7.4/ext4-pdirop.patch | 4 +- .../patches/rhel7/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- .../patches/rhel7/ext4-large-dir.patch | 43 +++++++++++++--------- .../kernel_patches/patches/rhel7/ext4-pdirop.patch | 4 +- .../patches/sles12/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- .../patches/sles12/ext4-pdirop.patch | 4 +- .../patches/sles12sp1/ext4-large-dir.patch | 43 +++++++++++++--------- .../patches/sles12sp2/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- .../patches/sles12sp2/ext4-large-dir.patch | 43 +++++++++++++--------- .../patches/sles12sp2/ext4-pdirop.patch | 4 +- .../patches/sles12sp3/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- .../patches/sles12sp3/ext4-large-dir.patch | 43 +++++++++++++--------- .../patches/sles12sp3/ext4-pdirop.patch | 4 +- .../ubuntu14+16/ext4-data-in-dirent-001.patch | 42 ++++++++++++++++++++- .../patches/ubuntu14+16/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- .../patches/ubuntu14+16/ext4-large-dir-001.patch | 43 +++++++++++++--------- .../patches/ubuntu14+16/ext4-large-dir.patch | 43 +++++++++++++--------- .../patches/ubuntu14+16/ext4-pdirop-001.patch | 4 +- .../patches/ubuntu14+16/ext4-pdirop.patch | 4 +- .../patches/ubuntu18/ext4-data-in-dirent.patch | 42 ++++++++++++++++++++- 23 files changed, 526 insertions(+), 143 deletions(-) diff --git a/ldiskfs/kernel_patches/patches/rhel7.2/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/rhel7.2/ext4-pdirop.patch index 21991ab..2064fd2 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.2/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.2/ext4-pdirop.patch @@ -1875,7 +1875,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c dx_get_limit((frame - 1)->entries)) { @@ -2277,16 +2622,43 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1911,7 +1911,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c goto cleanup; journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/rhel7.3/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/rhel7.3/ext4-data-in-dirent.patch index 7e89b5a..ca1ee06 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.3/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.3/ext4-data-in-dirent.patch @@ -192,7 +192,7 @@ Index: linux-stage/fs/ext4/ext4.h extern int search_dir(struct buffer_head *bh, char *search_buf, int buf_size, -@@ -2865,6 +2916,28 @@ extern struct mutex ext4__aio_mutex[EXT4 +@@ -2865,6 +2916,36 @@ extern struct mutex ext4__aio_mutex[EXT4 extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -207,6 +207,14 @@ Index: linux-stage/fs/ext4/ext4.h + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -235,6 +243,38 @@ Index: linux-stage/fs/ext4/namei.c static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(const struct qstr *d_name, struct inode *dir, +@@ -379,22 +380,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -500,11 +501,12 @@ ext4_next_entry(struct ext4_dir_entry_2 */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/rhel7.4/ext4-large-dir.patch b/ldiskfs/kernel_patches/patches/rhel7.4/ext4-large-dir.patch index 4f5fcb4..6c3d5ce 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.4/ext4-large-dir.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.4/ext4-large-dir.patch @@ -245,7 +245,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; -@@ -2203,19 +2240,25 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2203,19 +2240,27 @@ static int ext4_dx_add_entry(handle_t *h frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -260,12 +260,14 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -277,7 +279,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2224,21 +2267,14 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2224,22 +2267,17 @@ static int ext4_dx_add_entry(handle_t *h dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2*) frames[0].bh->b_data); @@ -290,24 +292,31 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2253,6 +2289,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &hinfo, &err); +@@ -2249,10 +2285,14 @@ static int ext4_dx_add_entry(handle_t *h + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/rhel7.4/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/rhel7.4/ext4-pdirop.patch index 53428bd..72788c8 100644 --- a/ldiskfs/kernel_patches/patches/rhel7.4/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/rhel7.4/ext4-pdirop.patch @@ -1875,7 +1875,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c dx_get_limit((frame - 1)->entries)) { @@ -2277,16 +2622,43 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1911,7 +1911,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c goto cleanup; journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-data-in-dirent.patch index 1910145..3bd77ff 100644 --- a/ldiskfs/kernel_patches/patches/rhel7/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-data-in-dirent.patch @@ -192,7 +192,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h extern int search_dir(struct buffer_head *bh, char *search_buf, int buf_size, -@@ -2761,6 +2810,28 @@ extern struct mutex ext4__aio_mutex[EXT4 +@@ -2761,6 +2810,36 @@ extern struct mutex ext4__aio_mutex[EXT4 extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -207,6 +207,14 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -235,6 +243,38 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/namei.c static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(const struct qstr *d_name, struct inode *dir, +@@ -379,22 +380,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -504,11 +505,12 @@ ext4_next_entry(struct ext4_dir_entry_2 */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-large-dir.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-large-dir.patch index cd250e0..15c0899 100644 --- a/ldiskfs/kernel_patches/patches/rhel7/ext4-large-dir.patch +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-large-dir.patch @@ -245,7 +245,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; -@@ -2203,19 +2240,25 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2203,19 +2240,27 @@ static int ext4_dx_add_entry(handle_t *h frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -260,12 +260,14 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -277,7 +279,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2224,21 +2267,14 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2224,22 +2267,17 @@ static int ext4_dx_add_entry(handle_t *h dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2*) frames[0].bh->b_data); @@ -290,24 +292,31 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2253,6 +2289,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &hinfo, &err); +@@ -2249,10 +2285,14 @@ static int ext4_dx_add_entry(handle_t *h + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/rhel7/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/rhel7/ext4-pdirop.patch index 31bb3e3..f512009 100644 --- a/ldiskfs/kernel_patches/patches/rhel7/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/rhel7/ext4-pdirop.patch @@ -1875,7 +1875,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c dx_get_limit((frame - 1)->entries)) { @@ -2277,16 +2622,43 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1911,7 +1911,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c goto cleanup; journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/sles12/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/sles12/ext4-data-in-dirent.patch index 8b3c01e..b9d50c2 100644 --- a/ldiskfs/kernel_patches/patches/sles12/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/sles12/ext4-data-in-dirent.patch @@ -183,7 +183,7 @@ Index: linux-stage/fs/ext4/ext4.h extern int search_dir(struct buffer_head *bh, char *search_buf, int buf_size, -@@ -2834,6 +2885,28 @@ extern struct mutex ext4__aio_mutex[EXT4 +@@ -2834,6 +2885,36 @@ extern struct mutex ext4__aio_mutex[EXT4 extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -198,6 +198,14 @@ Index: linux-stage/fs/ext4/ext4.h + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -226,6 +234,38 @@ Index: linux-stage/fs/ext4/namei.c static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(const struct qstr *d_name, struct inode *dir, +@@ -379,22 +380,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -500,11 +501,12 @@ ext4_next_entry(struct ext4_dir_entry_2 */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/sles12/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/sles12/ext4-pdirop.patch index 6ae7e71..9476d2c 100644 --- a/ldiskfs/kernel_patches/patches/sles12/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/sles12/ext4-pdirop.patch @@ -1875,7 +1875,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c dx_get_limit((frame - 1)->entries)) { @@ -2277,16 +2622,43 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1911,7 +1911,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c goto cleanup; journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/sles12sp1/ext4-large-dir.patch b/ldiskfs/kernel_patches/patches/sles12sp1/ext4-large-dir.patch index d8d60e3..bfe50f0 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp1/ext4-large-dir.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp1/ext4-large-dir.patch @@ -245,7 +245,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; -@@ -2203,19 +2240,25 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2203,19 +2240,27 @@ static int ext4_dx_add_entry(handle_t *h frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -260,12 +260,14 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -277,7 +279,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2224,21 +2267,14 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2224,22 +2267,17 @@ static int ext4_dx_add_entry(handle_t *h dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2*) frames[0].bh->b_data); @@ -290,24 +292,31 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2253,6 +2289,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &hinfo, &err); +@@ -2249,10 +2285,14 @@ static int ext4_dx_add_entry(handle_t *h + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-data-in-dirent.patch index 9327228..70a42d5 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-data-in-dirent.patch @@ -192,7 +192,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h 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, -@@ -2761,6 +2810,28 @@ extern struct mutex ext4__aio_mutex[EXT4 +@@ -2761,6 +2810,36 @@ extern struct mutex ext4__aio_mutex[EXT4 extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -207,6 +207,14 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -235,6 +243,38 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/namei.c static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(const struct qstr *d_name, struct inode *dir, +@@ -379,22 +380,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -504,11 +505,12 @@ ext4_next_entry(struct ext4_dir_entry_2 */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-large-dir.patch b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-large-dir.patch index 72bfc52..0ecf09a 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-large-dir.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-large-dir.patch @@ -240,7 +240,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; -@@ -2203,19 +2240,25 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2203,19 +2240,27 @@ static int ext4_dx_add_entry(handle_t *h frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -255,12 +255,14 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -272,7 +274,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2224,21 +2267,14 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2224,22 +2267,17 @@ static int ext4_dx_add_entry(handle_t *h dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2*) frames[0].bh->b_data); @@ -285,24 +287,31 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2253,6 +2289,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &fname->hinfo); +@@ -2249,10 +2285,14 @@ static int ext4_dx_add_entry(handle_t *h + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-pdirop.patch index b757ba4..4090c03 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp2/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp2/ext4-pdirop.patch @@ -1878,7 +1878,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c dx_get_limit((frame - 1)->entries)) { @@ -2277,8 +2622,32 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1912,7 +1912,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c goto cleanup; @@ -2277,6 +2622,8 @@ again: journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/sles12sp3/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/sles12sp3/ext4-data-in-dirent.patch index 6ef3b10..1508914 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp3/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp3/ext4-data-in-dirent.patch @@ -192,7 +192,7 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h 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, -@@ -2761,6 +2810,28 @@ extern struct mutex ext4__aio_mutex[EXT4 +@@ -2761,6 +2810,36 @@ extern struct mutex ext4__aio_mutex[EXT4 extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -207,6 +207,14 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/ext4.h + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -235,6 +243,38 @@ Index: linux-3.10.0-123.13.2.el7.x86_64/fs/ext4/namei.c static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(struct ext4_filename *fname, struct inode *dir, +@@ -383,22 +384,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -504,11 +505,12 @@ ext4_next_entry(struct ext4_dir_entry_2 */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/sles12sp3/ext4-large-dir.patch b/ldiskfs/kernel_patches/patches/sles12sp3/ext4-large-dir.patch index 9c898c5..10558a2 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp3/ext4-large-dir.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp3/ext4-large-dir.patch @@ -240,7 +240,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; -@@ -2203,19 +2240,25 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2203,19 +2240,27 @@ static int ext4_dx_add_entry(handle_t *h frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -255,12 +255,14 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -272,7 +274,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2224,21 +2267,14 @@ static int ext4_dx_add_entry(handle_t *h +@@ -2224,22 +2267,17 @@ static int ext4_dx_add_entry(handle_t *h dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2*) frames[0].bh->b_data); @@ -285,24 +287,31 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2253,6 +2289,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &fname->hinfo); +@@ -2249,10 +2285,14 @@ static int ext4_dx_add_entry(handle_t *h + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/sles12sp3/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/sles12sp3/ext4-pdirop.patch index a7480f5..9572de8 100644 --- a/ldiskfs/kernel_patches/patches/sles12sp3/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/sles12sp3/ext4-pdirop.patch @@ -1875,7 +1875,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c dx_get_limit((frame - 1)->entries)) { @@ -2496,8 +2842,32 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1909,7 +1909,7 @@ Index: linux-3.10.0-229.1.2.fc21.x86_64/fs/ext4/namei.c goto cleanup; @@ -2508,6 +2878,8 @@ again: journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent-001.patch b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent-001.patch index e014bb0..de5dd19 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent-001.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent-001.patch @@ -183,7 +183,7 @@ index 613538c..10a2a86 100644 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, -@@ -3292,6 +3343,28 @@ extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; +@@ -3292,6 +3343,36 @@ extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -198,6 +198,14 @@ index 613538c..10a2a86 100644 + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -295,6 +303,38 @@ index e90dd58..11bc299 100644 static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(struct ext4_filename *fname, struct inode *dir, +@@ -384,22 +385,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -504,11 +505,12 @@ ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent.patch index a04f784..65c9196 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent.patch @@ -183,7 +183,7 @@ index 613538c..10a2a86 100644 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, -@@ -3292,6 +3343,28 @@ extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; +@@ -3292,6 +3343,36 @@ extern struct mutex ext4__aio_mutex[EXT4_WQ_HASH_SZ]; extern int ext4_resize_begin(struct super_block *sb); extern void ext4_resize_end(struct super_block *sb); @@ -198,6 +198,14 @@ index 613538c..10a2a86 100644 + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -295,6 +303,38 @@ index 73d73fb..f6465b6 100644 static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(struct ext4_filename *fname, struct inode *dir, +@@ -384,22 +385,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -504,11 +505,12 @@ ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) diff --git a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir-001.patch b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir-001.patch index a156fe2..2dcf94c 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir-001.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir-001.patch @@ -255,7 +255,7 @@ index 11bc299..2543b8f 100644 if (err) goto journal_error; -@@ -2397,19 +2435,25 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, +@@ -2397,19 +2435,27 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -270,12 +270,14 @@ index 11bc299..2543b8f 100644 if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -287,7 +289,7 @@ index 11bc299..2543b8f 100644 icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2418,21 +2462,14 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, +@@ -2418,22 +2462,17 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2 *) frames[0].bh->b_data); @@ -300,24 +302,31 @@ index 11bc299..2543b8f 100644 - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2449,6 +2486,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &fname->hinfo); +@@ -2446,10 +2486,14 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir.patch b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir.patch index 59ef2ed..607a875 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir.patch @@ -255,7 +255,7 @@ index f6465b6..3f70bca 100644 if (err) goto journal_error; -@@ -2399,19 +2437,25 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, +@@ -2399,19 +2437,27 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, frame->entries = entries = entries2; swap(frame->bh, bh2); } @@ -270,12 +270,14 @@ index f6465b6..3f70bca 100644 if (err) goto journal_error; brelse (bh2); -+ ext4_handle_dirty_dirent_node(handle, dir, -+ (frame - 1)->bh); ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ (frame - 1)->bh); ++ if (err) ++ goto journal_error; + if (restart) { -+ ext4_handle_dirty_dirent_node(handle, dir, -+ frame->bh); -+ goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, ++ frame->bh); ++ goto journal_error; + } } else { struct dx_root_info *info; @@ -287,7 +289,7 @@ index f6465b6..3f70bca 100644 icount * sizeof(struct dx_entry)); dx_set_limit(entries2, dx_node_limit(dir)); -@@ -2420,21 +2464,14 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, +@@ -2420,22 +2464,17 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, dx_set_block(entries + 0, newblock); info = dx_get_dx_info((struct ext4_dir_entry_2 *) frames[0].bh->b_data); @@ -300,24 +302,31 @@ index f6465b6..3f70bca 100644 - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); -- if (err) -- goto journal_error; -- } -- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); -- if (err) { -- ext4_std_error(inode->i_sb, err); + info->indirect_levels += 1; + dxtrace(printk(KERN_DEBUG + "Creating %d level index...\n", + info->indirect_levels)); -+ ext4_handle_dirty_dirent_node(handle, dir, frame->bh); -+ ext4_handle_dirty_dirent_node(handle, dir, bh2); ++ err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); + if (err) + goto journal_error; +- } +- err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); +- if (err) { +- ext4_std_error(inode->i_sb, err); +- goto cleanup; ++ err = ext4_handle_dirty_dx_node(handle, dir, bh2); + brelse(bh2); + restart = 1; - goto cleanup; ++ goto journal_error; } } -@@ -2451,6 +2488,10 @@ journal_error: + de = do_split(handle, dir, &bh, frame, &fname->hinfo); +@@ -2447,10 +2488,14 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, + goto cleanup; + + journal_error: +- ext4_std_error(dir->i_sb, err); ++ ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: brelse(bh); dx_release(frames); diff --git a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop-001.patch b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop-001.patch index ad8800f..aa0bf6e 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop-001.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop-001.patch @@ -1668,7 +1668,7 @@ index 2543b8f..e70b61a 100644 dx_get_limit((frame - 1)->entries)) { @@ -2472,8 +2818,32 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1702,7 +1702,7 @@ index 2543b8f..e70b61a 100644 goto cleanup; @@ -2484,6 +2854,8 @@ again: journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop.patch b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop.patch index 508e396..71b2738 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop.patch @@ -1668,7 +1668,7 @@ index 3f70bca..99a8da2 100644 dx_get_limit((frame - 1)->entries)) { @@ -2474,8 +2820,32 @@ again: restart = 1; - goto cleanup; + goto journal_error; } + } else if (!ext4_htree_dx_locked(lck)) { + struct ext4_dir_lock_data *ld = ext4_htree_lock_data(lck); @@ -1702,7 +1702,7 @@ index 3f70bca..99a8da2 100644 goto cleanup; @@ -2486,6 +2856,8 @@ again: journal_error: - ext4_std_error(dir->i_sb, err); + ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ cleanup: + ext4_htree_dx_unlock(lck); + ext4_htree_de_unlock(lck); diff --git a/ldiskfs/kernel_patches/patches/ubuntu18/ext4-data-in-dirent.patch b/ldiskfs/kernel_patches/patches/ubuntu18/ext4-data-in-dirent.patch index 3eb83f0..463e783 100644 --- a/ldiskfs/kernel_patches/patches/ubuntu18/ext4-data-in-dirent.patch +++ b/ldiskfs/kernel_patches/patches/ubuntu18/ext4-data-in-dirent.patch @@ -190,7 +190,7 @@ Index: linux-4.15.0/fs/ext4/ext4.h 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, -@@ -3265,6 +3317,28 @@ static inline void ext4_clear_io_unwritt +@@ -3265,6 +3317,36 @@ static inline void ext4_clear_io_unwritt extern const struct iomap_ops ext4_iomap_ops; @@ -205,6 +205,14 @@ Index: linux-4.15.0/fs/ext4/ext4.h + char *len = de->name + de->name_len + 1 /* NUL terminator */; + int dlen = 0; + __u8 extra_data_flags = (de->file_type & ~EXT4_FT_MASK) >> 4; ++ struct ext4_dir_entry_tail *t = (struct ext4_dir_entry_tail *)de; ++ ++ if (!t->det_reserved_zero1 && ++ le16_to_cpu(t->det_rec_len) == ++ sizeof(struct ext4_dir_entry_tail) && ++ !t->det_reserved_zero2 && ++ t->det_reserved_ft == EXT4_FT_DIR_CSUM) ++ return 0; + + while (extra_data_flags) { + if (extra_data_flags & 1) { @@ -233,6 +241,38 @@ Index: linux-4.15.0/fs/ext4/namei.c static unsigned dx_node_limit(struct inode *dir); static struct dx_frame *dx_probe(struct ext4_filename *fname, struct inode *dir, +@@ -385,22 +386,23 @@ static struct dx_countlimit *get_dx_coun + { + struct ext4_dir_entry *dp; + struct dx_root_info *root; +- int count_offset; ++ int count_offset, dot_rec_len, dotdot_rec_len; + + if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) + count_offset = 8; +- else if (le16_to_cpu(dirent->rec_len) == 12) { +- dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); ++ else { ++ dot_rec_len = le16_to_cpu(dirent->rec_len); ++ dp = (struct ext4_dir_entry *)(((void *)dirent) + dot_rec_len); + if (le16_to_cpu(dp->rec_len) != +- EXT4_BLOCK_SIZE(inode->i_sb) - 12) ++ EXT4_BLOCK_SIZE(inode->i_sb) - dot_rec_len) + return NULL; +- root = (struct dx_root_info *)(((void *)dp + 12)); ++ dotdot_rec_len = EXT4_DIR_REC_LEN((struct ext4_dir_entry_2 *)dp); ++ root = (struct dx_root_info *)(((void *)dp + dotdot_rec_len)); + if (root->reserved_zero || + root->info_length != sizeof(struct dx_root_info)) + return NULL; +- count_offset = 32; +- } else +- return NULL; ++ count_offset = 8 + dot_rec_len + dotdot_rec_len; ++ } + + if (offset) + *offset = count_offset; @@ -505,11 +506,12 @@ ext4_next_entry(struct ext4_dir_entry_2 */ struct dx_root_info *dx_get_dx_info(struct ext4_dir_entry_2 *de) -- 1.8.3.1