X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=ldiskfs%2Fkernel_patches%2Fpatches%2Flinux-5.4%2Fext4-hash-indexed-dir-dotdot-update.patch;h=2c057b84514cdb53f6ff651ac47676618b7ee7f9;hb=0536b2a26992f5d2ef9e3537a196afac81281f60;hp=ef35db0e317b2b01f81d6fb2826780187129bf90;hpb=288cfdfa8d6cee3e5e061b129035965c4054d1df;p=fs%2Flustre-release.git diff --git a/ldiskfs/kernel_patches/patches/linux-5.4/ext4-hash-indexed-dir-dotdot-update.patch b/ldiskfs/kernel_patches/patches/linux-5.4/ext4-hash-indexed-dir-dotdot-update.patch index ef35db0..2c057b8 100644 --- a/ldiskfs/kernel_patches/patches/linux-5.4/ext4-hash-indexed-dir-dotdot-update.patch +++ b/ldiskfs/kernel_patches/patches/linux-5.4/ext4-hash-indexed-dir-dotdot-update.patch @@ -11,18 +11,19 @@ diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f54e868..14ff68e 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c -@@ -2174,6 +2174,74 @@ out_frames: +@@ -2174,6 +2174,67 @@ out_frames: return retval; } -+/* update ".." for hash-indexed directory, split the item "." if necessary */ ++/* 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 *dir_block; -+ struct ext4_dir_entry_2 *de; -+ int len, journal = 0, err = 0; ++ 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); @@ -30,72 +31,65 @@ index f54e868..14ff68e 100644 + if (IS_DIRSYNC(dir)) + handle->h_sync = 1; + -+ dir_block = ext4_bread(handle, dir, 0, 0); -+ if (IS_ERR(dir_block)) { -+ err = PTR_ERR(dir_block); ++ 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; + } -+ -+ de = (struct ext4_dir_entry_2 *)dir_block->b_data; -+ /* the first item must be "." */ -+ assert(de->name_len == 1 && de->name[0] == '.'); -+ len = le16_to_cpu(de->rec_len); -+ assert(len >= EXT4_DIR_REC_LEN(1)); -+ if (len > EXT4_DIR_REC_LEN(1)) { -+ BUFFER_TRACE(dir_block, "get_write_access"); -+ err = ext4_journal_get_write_access(handle, dir_block); -+ if (err) -+ goto out_journal; -+ -+ journal = 1; -+ de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(1)); ++ 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; + } + -+ len -= EXT4_DIR_REC_LEN(1); -+ assert(len == 0 || len >= EXT4_DIR_REC_LEN(2)); -+ de = (struct ext4_dir_entry_2 *) -+ ((char *) de + le16_to_cpu(de->rec_len)); -+ if (!journal) { -+ BUFFER_TRACE(dir_block, "get_write_access"); -+ err = ext4_journal_get_write_access(handle, dir_block); -+ if (err) -+ goto out_journal; -+ } ++ BUFFER_TRACE(dir_block, "get_write_access"); ++ retval = ext4_journal_get_write_access(handle, bh); ++ if (retval) ++ goto out; + -+ de->inode = cpu_to_le32(inode->i_ino); -+ if (len > 0) -+ de->rec_len = cpu_to_le16(len); -+ else -+ assert(le16_to_cpu(de->rec_len) >= EXT4_DIR_REC_LEN(2)); -+ de->name_len = 2; -+ strcpy(de->name, ".."); -+ ext4_set_de_type(dir->i_sb, de, S_IFDIR); ++ dotdot_de->inode = cpu_to_le32(inode->i_ino); + -+out_journal: -+ if (journal) { -+ BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); -+ err = ext4_handle_dirty_dirblock(handle, dir, dir_block); -+ ext4_mark_inode_dirty(handle, dir); ++ 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); + } -+ brelse(dir_block); + +out: -+ return err; ++ brelse(bh); ++ return retval; +} + /* * ext4_add_entry() * -@@ -2229,6 +2297,9 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, +@@ -2228,6 +2296,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)) { -+ if (dentry->d_name.len == 2 && -+ memcmp(dentry->d_name.name, "..", 2) == 0) -+ return ext4_update_dotdot(handle, dentry, inode); retval = ext4_dx_add_entry(handle, &fname, dir, inode); if (!retval || (retval != ERR_BAD_DX_DIR)) - goto out; -- 2.20.1