On Wed, Jan 11, 2023 at 05:26:41AM +0100, Christoph Hellwig wrote: > On Wed, Jan 11, 2023 at 02:20:41AM +0000, Al Viro wrote: > > More seriously, all those ..._set_link() need to return an error and their > > callers (..._rename()) need to deal with failures. > > That's actually what I did yesterday: > > http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/remove-write_one_page ext2 also has that bug. As well as "need to check for delete_entry errors" one (also in ext2_rename()). Completely untested patch follows: diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index e5cbc27ba459..b38fab33cd0d 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -461,7 +461,7 @@ static int ext2_handle_dirsync(struct inode *dir) return err; } -void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, +int ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, struct page *page, void *page_addr, struct inode *inode, int update_times) { @@ -480,7 +480,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, dir->i_mtime = dir->i_ctime = current_time(dir); EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; mark_inode_dirty(dir); - ext2_handle_dirsync(dir); + return ext2_handle_dirsync(dir); } /* diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 28de11a22e5f..95c083bb1b7c 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -734,7 +734,7 @@ extern int ext2_delete_entry(struct ext2_dir_entry_2 *dir, struct page *page, char *kaddr); extern int ext2_empty_dir (struct inode *); extern struct ext2_dir_entry_2 *ext2_dotdot(struct inode *dir, struct page **p, void **pa); -extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, void *, +extern int ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, void *, struct inode *, int); static inline void ext2_put_page(struct page *page, void *page_addr) { diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index c056957221a2..5e3397680faa 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -370,8 +370,10 @@ static int ext2_rename (struct user_namespace * mnt_userns, err = PTR_ERR(new_de); goto out_dir; } - ext2_set_link(new_dir, new_de, new_page, page_addr, old_inode, 1); + err = ext2_set_link(new_dir, new_de, new_page, page_addr, old_inode, 1); ext2_put_page(new_page, page_addr); + if (err) + goto out_dir; new_inode->i_ctime = current_time(new_inode); if (dir_de) drop_nlink(new_inode); @@ -391,7 +393,9 @@ static int ext2_rename (struct user_namespace * mnt_userns, old_inode->i_ctime = current_time(old_inode); mark_inode_dirty(old_inode); - ext2_delete_entry(old_de, old_page, old_page_addr); + err = ext2_delete_entry(old_de, old_page, old_page_addr); + if (err) + goto out_dir; if (dir_de) { if (old_dir != new_dir)