[ Sasha's backport helper bot ] Hi, Summary of potential issues and notes: ℹ️ This is part 3/3 of a series The upstream commit SHA1 provided is correct: ee70999a988b8abc3490609142f50ebaa8344432 Note: The patch differs from the upstream commit: --- 1: ee70999a988b8 ! 1: 1d6894c5f5775 nilfs2: handle errors that nilfs_prepare_chunk() may return @@ Metadata ## Commit message ## nilfs2: handle errors that nilfs_prepare_chunk() may return + commit ee70999a988b8abc3490609142f50ebaa8344432 upstream. + Patch series "nilfs2: fix issues with rename operations". This series fixes BUG_ON check failures reported by syzbot around rename operations, and a minor behavioral issue where the mtime of a child directory changes when it is renamed instead of moved. - This patch (of 2): The directory manipulation routines nilfs_set_link() and @@ Commit message Fix this issue by adding missing error paths in nilfs_set_link(), nilfs_delete_entry(), and their caller nilfs_rename(). + [konishi.ryusuke@xxxxxxxxx: adjusted for page/folio conversion] Link: https://lkml.kernel.org/r/20250111143518.7901-1-konishi.ryusuke@xxxxxxxxx Link: https://lkml.kernel.org/r/20250111143518.7901-2-konishi.ryusuke@xxxxxxxxx Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxx> @@ fs/nilfs2/dir.c: int nilfs_inode_by_name(struct inode *dir, const struct qstr *q -void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, +int nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, - struct folio *folio, struct inode *inode) + struct page *page, struct inode *inode) { - size_t from = offset_in_folio(folio, de); + unsigned int from = (char *)de - (char *)page_address(page); @@ fs/nilfs2/dir.c: void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, - folio_lock(folio); - err = nilfs_prepare_chunk(folio, from, to); + lock_page(page); + err = nilfs_prepare_chunk(page, from, to); - BUG_ON(err); + if (unlikely(err)) { -+ folio_unlock(folio); ++ unlock_page(page); + return err; + } de->inode = cpu_to_le64(inode->i_ino); - de->file_type = fs_umode_to_ftype(inode->i_mode); - nilfs_commit_chunk(folio, mapping, from, to); - inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir)); + nilfs_set_de_type(de, inode); + nilfs_commit_chunk(page, mapping, from, to); + dir->i_mtime = inode_set_ctime_current(dir); + return 0; } /* -@@ fs/nilfs2/dir.c: int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct folio *folio) - from = (char *)pde - kaddr; - folio_lock(folio); - err = nilfs_prepare_chunk(folio, from, to); +@@ fs/nilfs2/dir.c: int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) + from = (char *)pde - (char *)page_address(page); + lock_page(page); + err = nilfs_prepare_chunk(page, from, to); - BUG_ON(err); + if (unlikely(err)) { -+ folio_unlock(folio); ++ unlock_page(page); + goto out; + } if (pde) @@ fs/nilfs2/namei.c: static int nilfs_rename(struct mnt_idmap *idmap, err = PTR_ERR(new_de); goto out_dir; } -- nilfs_set_link(new_dir, new_de, new_folio, old_inode); -+ err = nilfs_set_link(new_dir, new_de, new_folio, old_inode); - folio_release_kmap(new_folio, new_de); +- nilfs_set_link(new_dir, new_de, new_page, old_inode); ++ err = nilfs_set_link(new_dir, new_de, new_page, old_inode); + nilfs_put_page(new_page); + if (unlikely(err)) + goto out_dir; nilfs_mark_inode_dirty(new_dir); @@ fs/nilfs2/namei.c: static int nilfs_rename(struct mnt_idmap *idmap, */ inode_set_ctime_current(old_inode); -- nilfs_delete_entry(old_de, old_folio); +- nilfs_delete_entry(old_de, old_page); - - if (dir_de) { -- nilfs_set_link(old_inode, dir_de, dir_folio, new_dir); -- folio_release_kmap(dir_folio, dir_de); +- nilfs_set_link(old_inode, dir_de, dir_page, new_dir); +- nilfs_put_page(dir_page); - drop_nlink(old_dir); -+ err = nilfs_delete_entry(old_de, old_folio); ++ err = nilfs_delete_entry(old_de, old_page); + if (likely(!err)) { + if (dir_de) { -+ err = nilfs_set_link(old_inode, dir_de, dir_folio, ++ err = nilfs_set_link(old_inode, dir_de, dir_page, + new_dir); + drop_nlink(old_dir); + } + nilfs_mark_inode_dirty(old_dir); } -- folio_release_kmap(old_folio, old_de); +- nilfs_put_page(old_page); - - nilfs_mark_inode_dirty(old_dir); nilfs_mark_inode_dirty(old_inode); @@ fs/nilfs2/namei.c: static int nilfs_rename(struct mnt_idmap *idmap, - out_dir: if (dir_de) - folio_release_kmap(dir_folio, dir_de); + nilfs_put_page(dir_page); out_old: - folio_release_kmap(old_folio, old_de); + nilfs_put_page(old_page); out: - nilfs_transaction_abort(old_dir->i_sb); + if (likely(!err)) @@ fs/nilfs2/namei.c: static int nilfs_rename(struct mnt_idmap *idmap, ## fs/nilfs2/nilfs.h ## -@@ fs/nilfs2/nilfs.h: struct nilfs_dir_entry *nilfs_find_entry(struct inode *, const struct qstr *, - int nilfs_delete_entry(struct nilfs_dir_entry *, struct folio *); - int nilfs_empty_dir(struct inode *); - struct nilfs_dir_entry *nilfs_dotdot(struct inode *, struct folio **); --void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, -- struct folio *, struct inode *); +@@ fs/nilfs2/nilfs.h: nilfs_find_entry(struct inode *, const struct qstr *, struct page **); + extern int nilfs_delete_entry(struct nilfs_dir_entry *, struct page *); + extern int nilfs_empty_dir(struct inode *); + extern struct nilfs_dir_entry *nilfs_dotdot(struct inode *, struct page **); +-extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *, +- struct page *, struct inode *); +int nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, -+ struct folio *folio, struct inode *inode); ++ struct page *page, struct inode *inode); - /* file.c */ - extern int nilfs_sync_file(struct file *, loff_t, loff_t, int); + static inline void nilfs_put_page(struct page *page) + { --- NOTE: These results are for this patch alone. Full series testing will be performed when all parts are received. Results of testing on various branches: | Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-6.6.y | Success | Success |