diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2023-03-10 19:48:47 +0100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2024-10-18 23:35:30 +0200 |
commit | 6a1c4c4688355063c8ead7de328c358bd959297a (patch) | |
tree | 8db7ceebf560c056c919eb6c8fbb76bcdabbddd1 | |
parent | Linux 6.12-rc2 (diff) | |
download | linux-6a1c4c4688355063c8ead7de328c358bd959297a.tar.xz linux-6a1c4c4688355063c8ead7de328c358bd959297a.zip |
ufs: fix handling of delete_entry and set_link failures
similar to minixfs series - make ufs_set_link() report failures,
lift folio_release_kmap() into the callers of ufs_set_link()
and ufs_delete_entry(), make ufs_rename() handle failures in both.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/ufs/dir.c | 29 | ||||
-rw-r--r-- | fs/ufs/namei.c | 39 | ||||
-rw-r--r-- | fs/ufs/ufs.h | 4 |
3 files changed, 33 insertions, 39 deletions
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index d6e6a2198971..88d0062cfdb9 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -81,10 +81,9 @@ ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr) } -/* Releases the page */ -void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, - struct folio *folio, struct inode *inode, - bool update_times) +int ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, + struct folio *folio, struct inode *inode, + bool update_times) { loff_t pos = folio_pos(folio) + offset_in_folio(folio, de); unsigned len = fs16_to_cpu(dir->i_sb, de->d_reclen); @@ -92,17 +91,19 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, folio_lock(folio); err = ufs_prepare_chunk(folio, pos, len); - BUG_ON(err); + if (unlikely(err)) { + folio_unlock(folio); + return err; + } de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); ufs_set_de_type(dir->i_sb, de, inode->i_mode); ufs_commit_chunk(folio, pos, len); - folio_release_kmap(folio, de); if (update_times) inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); mark_inode_dirty(dir); - ufs_handle_dirsync(dir); + return ufs_handle_dirsync(dir); } static bool ufs_check_folio(struct folio *folio, char *kaddr) @@ -505,8 +506,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, if (de->d_reclen == 0) { ufs_error(inode->i_sb, __func__, "zero-length directory entry"); - err = -EIO; - goto out; + return -EIO; } pde = de; de = ufs_next_entry(sb, de); @@ -516,18 +516,17 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, pos = folio_pos(folio) + from; folio_lock(folio); err = ufs_prepare_chunk(folio, pos, to - from); - BUG_ON(err); + if (unlikely(err)) { + folio_unlock(folio); + return err; + } if (pde) pde->d_reclen = cpu_to_fs16(sb, to - from); dir->d_ino = 0; ufs_commit_chunk(folio, pos, to - from); inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); mark_inode_dirty(inode); - err = ufs_handle_dirsync(inode); -out: - folio_release_kmap(folio, kaddr); - UFSD("EXIT\n"); - return err; + return ufs_handle_dirsync(inode); } int ufs_make_empty(struct inode * inode, struct inode *dir) diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index c8390976ab6a..38a024c8cccd 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -210,20 +210,18 @@ static int ufs_unlink(struct inode *dir, struct dentry *dentry) struct inode * inode = d_inode(dentry); struct ufs_dir_entry *de; struct folio *folio; - int err = -ENOENT; + int err; de = ufs_find_entry(dir, &dentry->d_name, &folio); if (!de) - goto out; + return -ENOENT; err = ufs_delete_entry(dir, de, folio); - if (err) - goto out; - - inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); - inode_dec_link_count(inode); - err = 0; -out: + if (!err) { + inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); + inode_dec_link_count(inode); + } + folio_release_kmap(folio, de); return err; } @@ -253,14 +251,14 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct ufs_dir_entry * dir_de = NULL; struct folio *old_folio; struct ufs_dir_entry *old_de; - int err = -ENOENT; + int err; if (flags & ~RENAME_NOREPLACE) return -EINVAL; old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_folio); if (!old_de) - goto out; + return -ENOENT; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; @@ -281,7 +279,10 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir, new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_folio); if (!new_de) goto out_dir; - ufs_set_link(new_dir, new_de, new_folio, old_inode, 1); + err = ufs_set_link(new_dir, new_de, new_folio, old_inode, 1); + folio_release_kmap(new_folio, new_de); + if (err) + goto out_dir; inode_set_ctime_current(new_inode); if (dir_de) drop_nlink(new_inode); @@ -299,26 +300,20 @@ static int ufs_rename(struct mnt_idmap *idmap, struct inode *old_dir, * rename. */ inode_set_ctime_current(old_inode); - - ufs_delete_entry(old_dir, old_de, old_folio); mark_inode_dirty(old_inode); - if (dir_de) { + err = ufs_delete_entry(old_dir, old_de, old_folio); + if (!err && dir_de) { if (old_dir != new_dir) - ufs_set_link(old_inode, dir_de, dir_folio, new_dir, 0); - else - folio_release_kmap(dir_folio, dir_de); + err = ufs_set_link(old_inode, dir_de, dir_folio, + new_dir, 0); inode_dec_link_count(old_dir); } - return 0; - - out_dir: if (dir_de) folio_release_kmap(dir_folio, dir_de); out_old: folio_release_kmap(old_folio, old_de); -out: return err; } diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index a2c762cb65a0..c7638e62ffe8 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -108,8 +108,8 @@ struct ufs_dir_entry *ufs_find_entry(struct inode *, const struct qstr *, int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct folio *); int ufs_empty_dir(struct inode *); struct ufs_dir_entry *ufs_dotdot(struct inode *, struct folio **); -void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, - struct folio *folio, struct inode *inode, bool update_times); +int ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, + struct folio *folio, struct inode *inode, bool update_times); /* file.c */ extern const struct inode_operations ufs_file_inode_operations; |