minix: fix error handling in minix_set_link
authorChristoph Hellwig <hch@lst.de>
Wed, 18 Jan 2023 17:30:23 +0000 (18:30 +0100)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 20 Jan 2023 00:26:34 +0000 (19:26 -0500)
If minix_prepare_chunk fails, updating c/mtime and marking the
dir inode dirty is wrong, as the inode hasn't been modified.  Also
propagate the error to the caller.

Note that this moves the dir_put_page call later, but that matches
other uses of this helper in the directory code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/minix/dir.c
fs/minix/minix.h
fs/minix/namei.c

index 242e179aa1fbebc0b815c69345bdc57855c65d11..34c1cdb5dc7d47fe276a84c412a658d1a02219d9 100644 (file)
@@ -410,8 +410,8 @@ not_empty:
 }
 
 /* Releases the page */
-void minix_set_link(struct minix_dir_entry *de, struct page *page,
-       struct inode *inode)
+int minix_set_link(struct minix_dir_entry *de, struct page *page,
+               struct inode *inode)
 {
        struct inode *dir = page->mapping->host;
        struct minix_sb_info *sbi = minix_sb(dir->i_sb);
@@ -420,19 +420,21 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
        int err;
 
        lock_page(page);
-
        err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
-       if (err == 0) {
-               if (sbi->s_version == MINIX_V3)
-                       ((minix3_dirent *) de)->inode = inode->i_ino;
-               else
-                       de->inode = inode->i_ino;
-               err = dir_commit_chunk(page, pos, sbi->s_dirsize);
-       } else {
+       if (err) {
                unlock_page(page);
+               return err;
        }
+       if (sbi->s_version == MINIX_V3)
+               ((minix3_dirent *)de)->inode = inode->i_ino;
+       else
+               de->inode = inode->i_ino;
+       err = dir_commit_chunk(page, pos, sbi->s_dirsize);
+       if (err)
+               return err;
        dir->i_mtime = dir->i_ctime = current_time(dir);
        mark_inode_dirty(dir);
+       return 0;
 }
 
 struct minix_dir_entry * minix_dotdot (struct inode *dir, struct page **p)
index 7158a68bdc63252a605c6cbb8773eff4e59a8c2d..65c19e078ec457c76a130b87317bd9348c292bc2 100644 (file)
@@ -69,7 +69,8 @@ extern int minix_add_link(struct dentry*, struct inode*);
 extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
 extern int minix_make_empty(struct inode*, struct inode*);
 extern int minix_empty_dir(struct inode*);
-extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
+int minix_set_link(struct minix_dir_entry *de, struct page *page,
+               struct inode *inode);
 extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
 extern ino_t minix_inode_by_name(struct dentry*);
 
index 7dc48141887119626b3385800427f8592db7aa6e..382ead96bf54166c9df204896ace2d449895d414 100644 (file)
@@ -213,10 +213,11 @@ static int minix_rename(struct user_namespace *mnt_userns,
                new_de = minix_find_entry(new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               err = 0;
-               minix_set_link(new_de, new_page, old_inode);
+               err = minix_set_link(new_de, new_page, old_inode);
                kunmap(new_page);
                put_page(new_page);
+               if (err)
+                       goto out_dir;
                new_inode->i_ctime = current_time(new_inode);
                if (dir_de)
                        drop_nlink(new_inode);
@@ -233,8 +234,9 @@ static int minix_rename(struct user_namespace *mnt_userns,
        mark_inode_dirty(old_inode);
 
        if (dir_de) {
-               minix_set_link(dir_de, dir_page, new_dir);
-               inode_dec_link_count(old_dir);
+               err = minix_set_link(dir_de, dir_page, new_dir);
+               if (!err)
+                       inode_dec_link_count(old_dir);
        }
 out_dir:
        if (dir_de) {