Commit c6453d0a authored by Andreas Dilger's avatar Andreas Dilger Committed by Linus Torvalds

[PATCH] ext3: htree rename fix

A problem with htree was recently discovered during Lustre testing when
files were being renamed within the same directory.  In some cases the
addition of the new name caused a directory block split and the old
dir_entry was pointing at the wrong entry, and the wrong entry was removed.
This would seem entirely possible in a Maildir directory, since the MTA
will be doing a lot of renames within the same directory.

If old_de is pointing to the newly-added entry (i_ino is the same) we end up
deleting the new entry instead of the old one.  It looks as if the rename
never happened.  We need to verify that the name we are unlinking is what we
expect.

If is also possible that old_de is pointing to the now-unused space at the end
of a newly-split leaf block, so we still need to try ext3_delete_entry()
(which will skip the stale entry and return ENOENT) instead of just relying on
the inum + name check.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1d90ac58
...@@ -2262,11 +2262,15 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, ...@@ -2262,11 +2262,15 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
/* /*
* ok, that's it * ok, that's it
*/ */
retval = ext3_delete_entry(handle, old_dir, old_de, old_bh); if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
if (retval == -ENOENT) { old_de->name_len != old_dentry->d_name.len ||
/* strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
* old_de could have moved out from under us. (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 buffer_head *old_bh2;
struct ext3_dir_entry_2 *old_de2; struct ext3_dir_entry_2 *old_de2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment