# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # # namei.c | 21 ++++++++++++++++++++- # 1 files changed, 20 insertions(+), 1 deletion(-) # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/11/07 tytso@snap.thunk.org 1.779 # Fix ext3 htree rename bug. # # This fixes an ext3 htree bug pointed out by Christopher Li; if # adding the new name to the directory causes a split, this can cause # the directory entry containing the old name to move to another # block, and then the removal of the old name will fail. # -------------------------------------------- # diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c --- a/fs/ext3/namei.c Thu Nov 7 10:57:49 2002 +++ b/fs/ext3/namei.c Thu Nov 7 10:57:49 2002 @@ -2173,7 +2173,30 @@ /* * ok, that's it */ - ext3_delete_entry(handle, old_dir, old_de, old_bh); + if (le32_to_cpu(old_de->inode) != old_inode->i_ino || + old_de->name_len != old_dentry->d_name.len || + strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || + (retval = ext3_delete_entry(handle, old_dir, + old_de, old_bh)) == -ENOENT) { + /* old_de could have moved from under us during htree split, so + * make sure that we are deleting the right entry. We might + * also be pointing to a stale entry in the unused part of + * old_bh so just checking inum and the name isn't enough. */ + struct buffer_head *old_bh2; + struct ext3_dir_entry_2 *old_de2; + + old_bh2 = ext3_find_entry(old_dentry, &old_de2); + if (old_bh2) { + retval = ext3_delete_entry(handle, old_dir, + old_de2, old_bh2); + brelse(old_bh2); + } + } + if (retval) { + ext3_warning(old_dir->i_sb, "ext3_rename", + "Deleting old file (%lu), %d, error=%d", + old_dir->i_ino, old_dir->i_nlink, retval); + } if (new_inode) { new_inode->i_nlink--;