]> git.itanic.dy.fi Git - linux-stable/commitdiff
reiserfs: Avoid touching renamed directory if parent does not change
authorJan Kara <jack@suse.cz>
Thu, 12 Oct 2023 21:14:20 +0000 (23:14 +0200)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 25 Nov 2023 07:53:20 +0000 (02:53 -0500)
The VFS will not be locking moved directory if its parent does not
change. Change reiserfs rename code to avoid touching renamed directory
if its parent does not change as without locking that can corrupt the
filesystem.

Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/reiserfs/namei.c

index 994d6e6995ab1967ba5470c92225e366a71b10e4..5996197ba40ca7f99fb40c9a4e70d3c855a8d91e 100644 (file)
@@ -1324,8 +1324,8 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
        struct inode *old_inode, *new_dentry_inode;
        struct reiserfs_transaction_handle th;
        int jbegin_count;
-       umode_t old_inode_mode;
        unsigned long savelink = 1;
+       bool update_dir_parent = false;
 
        if (flags & ~RENAME_NOREPLACE)
                return -EINVAL;
@@ -1375,8 +1375,7 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
                return -ENOENT;
        }
 
-       old_inode_mode = old_inode->i_mode;
-       if (S_ISDIR(old_inode_mode)) {
+       if (S_ISDIR(old_inode->i_mode)) {
                /*
                 * make sure that directory being renamed has correct ".."
                 * and that its new parent directory has not too many links
@@ -1389,24 +1388,28 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
                        }
                }
 
-               /*
-                * directory is renamed, its parent directory will be changed,
-                * so find ".." entry
-                */
-               dot_dot_de.de_gen_number_bit_string = NULL;
-               retval =
-                   reiserfs_find_entry(old_inode, "..", 2, &dot_dot_entry_path,
+               if (old_dir != new_dir) {
+                       /*
+                        * directory is renamed, its parent directory will be
+                        * changed, so find ".." entry
+                        */
+                       dot_dot_de.de_gen_number_bit_string = NULL;
+                       retval =
+                           reiserfs_find_entry(old_inode, "..", 2,
+                                       &dot_dot_entry_path,
                                        &dot_dot_de);
-               pathrelse(&dot_dot_entry_path);
-               if (retval != NAME_FOUND) {
-                       reiserfs_write_unlock(old_dir->i_sb);
-                       return -EIO;
-               }
+                       pathrelse(&dot_dot_entry_path);
+                       if (retval != NAME_FOUND) {
+                               reiserfs_write_unlock(old_dir->i_sb);
+                               return -EIO;
+                       }
 
-               /* inode number of .. must equal old_dir->i_ino */
-               if (dot_dot_de.de_objectid != old_dir->i_ino) {
-                       reiserfs_write_unlock(old_dir->i_sb);
-                       return -EIO;
+                       /* inode number of .. must equal old_dir->i_ino */
+                       if (dot_dot_de.de_objectid != old_dir->i_ino) {
+                               reiserfs_write_unlock(old_dir->i_sb);
+                               return -EIO;
+                       }
+                       update_dir_parent = true;
                }
        }
 
@@ -1486,7 +1489,7 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
 
                reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1);
 
-               if (S_ISDIR(old_inode->i_mode)) {
+               if (update_dir_parent) {
                        if ((retval =
                             search_by_entry_key(new_dir->i_sb,
                                                 &dot_dot_de.de_entry_key,
@@ -1534,14 +1537,14 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
                                                         new_de.de_bh);
                        reiserfs_restore_prepared_buffer(old_inode->i_sb,
                                                         old_de.de_bh);
-                       if (S_ISDIR(old_inode_mode))
+                       if (update_dir_parent)
                                reiserfs_restore_prepared_buffer(old_inode->
                                                                 i_sb,
                                                                 dot_dot_de.
                                                                 de_bh);
                        continue;
                }
-               if (S_ISDIR(old_inode_mode)) {
+               if (update_dir_parent) {
                        if (item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
                            !entry_points_to_object("..", 2, &dot_dot_de,
                                                    old_dir)) {
@@ -1559,7 +1562,7 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
                        }
                }
 
-               RFALSE(S_ISDIR(old_inode_mode) &&
+               RFALSE(update_dir_parent &&
                       !buffer_journal_prepared(dot_dot_de.de_bh), "");
 
                break;
@@ -1592,11 +1595,12 @@ static int reiserfs_rename(struct mnt_idmap *idmap,
                savelink = new_dentry_inode->i_nlink;
        }
 
-       if (S_ISDIR(old_inode_mode)) {
+       if (update_dir_parent) {
                /* adjust ".." of renamed directory */
                set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir));
                journal_mark_dirty(&th, dot_dot_de.de_bh);
-
+       }
+       if (S_ISDIR(old_inode->i_mode)) {
                /*
                 * there (in new_dir) was no directory, so it got new link
                 * (".."  of renamed directory)