OSDN Git Service

sysv: fix handling of delete_entry and set_link failures
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 20 Jan 2023 01:05:43 +0000 (20:05 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 20 Jan 2023 04:24:42 +0000 (23:24 -0500)
similar to minixfs series - make sysv_set_link() report failures,
lift dir_put_page() into the callers of sysv_set_link() and
sysv_delete_entry(), make sysv_rename() handle failures in both.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/sysv/dir.c
fs/sysv/namei.c
fs/sysv/sysv.h

index 3ed98d6..999bceb 100644 (file)
@@ -249,10 +249,12 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
 
        lock_page(page);
        err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
-       BUG_ON(err);
+       if (err) {
+               unlock_page(page);
+               return err;
+       }
        de->inode = 0;
        dir_commit_chunk(page, pos, SYSV_DIRSIZE);
-       dir_put_page(page, de);
        inode->i_ctime = inode->i_mtime = current_time(inode);
        mark_inode_dirty(inode);
        return sysv_handle_dirsync(inode);
@@ -335,7 +337,7 @@ not_empty:
 }
 
 /* Releases the page */
-void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
+int sysv_set_link(struct sysv_dir_entry *de, struct page *page,
        struct inode *inode)
 {
        struct inode *dir = page->mapping->host;
@@ -344,13 +346,15 @@ void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
 
        lock_page(page);
        err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
-       BUG_ON(err);
+       if (err) {
+               unlock_page(page);
+               return err;
+       }
        de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
        dir_commit_chunk(page, pos, SYSV_DIRSIZE);
-       dir_put_page(page, de);
        dir->i_mtime = dir->i_ctime = current_time(dir);
        mark_inode_dirty(dir);
-       sysv_handle_dirsync(inode);
+       return sysv_handle_dirsync(inode);
 }
 
 /*
index 371cf90..1bfe788 100644 (file)
@@ -153,19 +153,18 @@ static int sysv_unlink(struct inode * dir, struct dentry * dentry)
        struct inode * inode = d_inode(dentry);
        struct page * page;
        struct sysv_dir_entry * de;
-       int err = -ENOENT;
+       int err;
 
        de = sysv_find_entry(dentry, &page);
        if (!de)
-               goto out;
-
-       err = sysv_delete_entry (de, page);
-       if (err)
-               goto out;
+               return -ENOENT;
 
-       inode->i_ctime = dir->i_ctime;
-       inode_dec_link_count(inode);
-out:
+       err = sysv_delete_entry(de, page);
+       if (!err) {
+               inode->i_ctime = dir->i_ctime;
+               inode_dec_link_count(inode);
+       }
+       dir_put_page(page, de);
        return err;
 }
 
@@ -227,7 +226,10 @@ static int sysv_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                new_de = sysv_find_entry(new_dentry, &new_page);
                if (!new_de)
                        goto out_dir;
-               sysv_set_link(new_de, new_page, old_inode);
+               err = sysv_set_link(new_de, new_page, old_inode);
+               dir_put_page(new_page, new_de);
+               if (err)
+                       goto out_dir;
                new_inode->i_ctime = current_time(new_inode);
                if (dir_de)
                        drop_nlink(new_inode);
@@ -240,14 +242,17 @@ static int sysv_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
                        inode_inc_link_count(new_dir);
        }
 
-       sysv_delete_entry(old_de, old_page);
+       err = sysv_delete_entry(old_de, old_page);
+       if (err)
+               goto out_dir;
+
        mark_inode_dirty(old_inode);
 
        if (dir_de) {
-               sysv_set_link(dir_de, dir_page, new_dir);
-               inode_dec_link_count(old_dir);
+               err = sysv_set_link(dir_de, dir_page, new_dir);
+               if (!err)
+                       inode_dec_link_count(old_dir);
        }
-       return 0;
 
 out_dir:
        if (dir_de)
index 50f19bf..7d900dc 100644 (file)
@@ -154,7 +154,7 @@ extern int sysv_add_link(struct dentry *, struct inode *);
 extern int sysv_delete_entry(struct sysv_dir_entry *, struct page *);
 extern int sysv_make_empty(struct inode *, struct inode *);
 extern int sysv_empty_dir(struct inode *);
-extern void sysv_set_link(struct sysv_dir_entry *, struct page *,
+extern int sysv_set_link(struct sysv_dir_entry *, struct page *,
                        struct inode *);
 extern struct sysv_dir_entry *sysv_dotdot(struct inode *, struct page **);
 extern ino_t sysv_inode_by_name(struct dentry *);