summaryrefslogtreecommitdiff
path: root/fs/sysv
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2023-01-19 20:05:43 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2023-01-19 23:24:42 -0500
commitabb7c742397324f8676c5b622effdce911cd52e3 (patch)
tree7ed6e6848e00b5e2d5f1e826b3752374f2a44933 /fs/sysv
parent83005276d383387fec7e18c7a36daade579a23a7 (diff)
sysv: fix handling of delete_entry and set_link failures
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>
Diffstat (limited to 'fs/sysv')
-rw-r--r--fs/sysv/dir.c16
-rw-r--r--fs/sysv/namei.c33
-rw-r--r--fs/sysv/sysv.h2
3 files changed, 30 insertions, 21 deletions
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 3ed98d66b152..999bceb99974 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -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);
}
/*
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 371cf9012052..1bfe788851a9 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -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)
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index 50f19bfd8d10..7d900dce713d 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -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 *);