diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2023-01-19 20:05:43 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2023-01-19 23:24:42 -0500 |
commit | abb7c742397324f8676c5b622effdce911cd52e3 (patch) | |
tree | 7ed6e6848e00b5e2d5f1e826b3752374f2a44933 /fs/sysv | |
parent | 83005276d383387fec7e18c7a36daade579a23a7 (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.c | 16 | ||||
-rw-r--r-- | fs/sysv/namei.c | 33 | ||||
-rw-r--r-- | fs/sysv/sysv.h | 2 |
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 *); |