Whamcloud - gitweb
LU-17711 osd-ldiskfs: do not delete dotdot during rename
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / rhel8.7 / ext4-hash-indexed-dir-dotdot-update.patch
diff --git a/ldiskfs/kernel_patches/patches/rhel8.7/ext4-hash-indexed-dir-dotdot-update.patch b/ldiskfs/kernel_patches/patches/rhel8.7/ext4-hash-indexed-dir-dotdot-update.patch
new file mode 100644 (file)
index 0000000..68d4aa2
--- /dev/null
@@ -0,0 +1,83 @@
+Index: linux-4.15.0/fs/ext4/namei.c
+===================================================================
+--- linux-4.15.0.orig/fs/ext4/namei.c
++++ linux-4.15.0/fs/ext4/namei.c
+@@ -2043,6 +2043,67 @@ out_frames:
+       return retval;
+ }
++/* update ".." entry */
++static int ext4_update_dotdot(handle_t *handle, struct dentry *dentry,
++                            struct inode *inode)
++{
++      struct inode *dir = dentry->d_parent->d_inode;
++      struct buffer_head *bh;
++      struct ext4_dir_entry_2 *dot_de, *dotdot_de;
++      unsigned int offset;
++      int retval = 0;
++
++      if (IS_ERR(handle))
++              return PTR_ERR(handle);
++
++      if (IS_DIRSYNC(dir))
++              handle->h_sync = 1;
++
++      bh = ext4_read_dirblock(dir, 0, DIRENT_HTREE);
++      if (IS_ERR(bh))
++              return PTR_ERR(bh);
++
++      dot_de = (struct ext4_dir_entry_2 *) bh->b_data;
++      if (ext4_check_dir_entry(dir, NULL, dot_de, bh, bh->b_data,
++                               bh->b_size, 0) ||
++          le32_to_cpu(dot_de->inode) != dir->i_ino ||
++          strcmp(".", dot_de->name)) {
++              EXT4_ERROR_INODE(dir, "directory missing '.'");
++              retval = -EFSCORRUPTED;
++              goto out;
++      }
++      offset = ext4_rec_len_from_disk(dot_de->rec_len,
++                                      dir->i_sb->s_blocksize);
++      dotdot_de = ext4_next_entry(dot_de, dir->i_sb->s_blocksize);
++      if (ext4_check_dir_entry(dir, NULL, dotdot_de, bh, bh->b_data,
++                               bh->b_size, offset) ||
++          le32_to_cpu(dotdot_de->inode) == 0 ||
++          strcmp("..", dotdot_de->name)) {
++              EXT4_ERROR_INODE(dir, "directory missing '..'");
++              retval = -EFSCORRUPTED;
++              goto out;
++      }
++
++      BUFFER_TRACE(dir_block, "get_write_access");
++      retval = ext4_journal_get_write_access(handle, bh);
++      if (retval)
++              goto out;
++
++      dotdot_de->inode = cpu_to_le32(inode->i_ino);
++
++      ext4_mark_inode_dirty(handle, dir);
++      BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
++      if (is_dx(dir)) {
++              retval = ext4_handle_dirty_dx_node(handle, dir, bh);
++      } else {
++              retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
++      }
++
++out:
++      brelse(bh);
++      return retval;
++}
++
+ /*
+  *    ext4_add_entry()
+  *
+@@ -2090,6 +2158,10 @@ static int ext4_add_entry(handle_t *hand
+               }
+       }
++      if (dentry->d_name.len == 2 &&
++                      memcmp(dentry->d_name.name, "..", 2) == 0)
++              return ext4_update_dotdot(handle, dentry, inode);
++
+       if (is_dx(dir)) {
+               retval = ext4_dx_add_entry(handle, &fname, dir, inode);
+               if (!retval || (retval != ERR_BAD_DX_DIR))