Subject: [PATCH] linux-5.14/ext4-hash-indexed-dir-dotdot-update.patch --- fs/ext4/namei.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 95b21f5..e4514c9 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2364,6 +2364,68 @@ 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, dir->i_sb, bh, + EXT4_JTR_NONE); + 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_dirblock(handle, dir, bh); + } + +out: + brelse(bh); + return retval; +} + /* * ext4_add_entry() * @@ -2356,6 +2424,10 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, } } + 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)) -- 2.31.1