Whamcloud - gitweb
LU-11922 ldiskfs: make dirdata work with metadata_csum 19/34219/4
authorLi Dongyang <dongyangli@ddn.com>
Sat, 9 Feb 2019 05:37:29 +0000 (16:37 +1100)
committerOleg Drokin <green@whamcloud.com>
Fri, 15 Mar 2019 23:45:50 +0000 (23:45 +0000)
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 <dongyangli@ddn.com>
Change-Id: I04df8c30d9d423111e2b4031a7e4b9058101016f
Reviewed-on: https://review.whamcloud.com/34219
Reviewed-by: Yang Sheng <ys@whamcloud.com>
Tested-by: Jenkins
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
23 files changed:
ldiskfs/kernel_patches/patches/rhel7.2/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/rhel7.3/ext4-data-in-dirent.patch
ldiskfs/kernel_patches/patches/rhel7.4/ext4-large-dir.patch
ldiskfs/kernel_patches/patches/rhel7.4/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/rhel7/ext4-data-in-dirent.patch
ldiskfs/kernel_patches/patches/rhel7/ext4-large-dir.patch
ldiskfs/kernel_patches/patches/rhel7/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/sles12/ext4-data-in-dirent.patch
ldiskfs/kernel_patches/patches/sles12/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/sles12sp1/ext4-large-dir.patch
ldiskfs/kernel_patches/patches/sles12sp2/ext4-data-in-dirent.patch
ldiskfs/kernel_patches/patches/sles12sp2/ext4-large-dir.patch
ldiskfs/kernel_patches/patches/sles12sp2/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/sles12sp3/ext4-data-in-dirent.patch
ldiskfs/kernel_patches/patches/sles12sp3/ext4-large-dir.patch
ldiskfs/kernel_patches/patches/sles12sp3/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent-001.patch
ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-data-in-dirent.patch
ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir-001.patch
ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-large-dir.patch
ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop-001.patch
ldiskfs/kernel_patches/patches/ubuntu14+16/ext4-pdirop.patch
ldiskfs/kernel_patches/patches/ubuntu18/ext4-data-in-dirent.patch

index 21991ab..2064fd2 100644 (file)
@@ -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);
index 7e89b5a..ca1ee06 100644 (file)
@@ -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)
index 4f5fcb4..6c3d5ce 100644 (file)
@@ -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);
index 53428bd..72788c8 100644 (file)
@@ -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);
index 1910145..3bd77ff 100644 (file)
@@ -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)
index cd250e0..15c0899 100644 (file)
@@ -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);
index 31bb3e3..f512009 100644 (file)
@@ -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);
index 8b3c01e..b9d50c2 100644 (file)
@@ -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)
index 6ae7e71..9476d2c 100644 (file)
@@ -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);
index d8d60e3..bfe50f0 100644 (file)
@@ -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);
index 9327228..70a42d5 100644 (file)
@@ -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)
index 72bfc52..0ecf09a 100644 (file)
@@ -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);
index b757ba4..4090c03 100644 (file)
@@ -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);
index 6ef3b10..1508914 100644 (file)
@@ -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)
index 9c898c5..10558a2 100644 (file)
@@ -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);
index a7480f5..9572de8 100644 (file)
@@ -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);
index e014bb0..de5dd19 100644 (file)
@@ -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)
index a04f784..65c9196 100644 (file)
@@ -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)
index a156fe2..2dcf94c 100644 (file)
@@ -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);
index 59ef2ed..607a875 100644 (file)
@@ -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);
index ad8800f..aa0bf6e 100644 (file)
@@ -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);
index 508e396..71b2738 100644 (file)
@@ -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);
index 3eb83f0..463e783 100644 (file)
@@ -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)