FAILED: patch "[PATCH] nilfs2: propagate directory read errors from" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 08cfa12adf888db98879dbd735bc741360a34168
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2024101853-recall-payee-2d9d@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 08cfa12adf888db98879dbd735bc741360a34168 Mon Sep 17 00:00:00 2001
From: Ryusuke Konishi <[email protected]>
Date: Fri, 4 Oct 2024 12:35:31 +0900
Subject: [PATCH] nilfs2: propagate directory read errors from
nilfs_find_entry()
Syzbot reported that a task hang occurs in vcs_open() during a fuzzing test for nilfs2.
The root cause of this problem is that in nilfs_find_entry(), which searches for directory entries, ignores errors when loading a directory page/folio via nilfs_get_folio() fails.
If the filesystem images is corrupted, and the i_size of the directory inode is large, and the directory page/folio is successfully read but fails the sanity check, for example when it is zero-filled, nilfs_check_folio() may continue to spit out error messages in bursts.
Fix this issue by propagating the error to the callers when loading a page/folio fails in nilfs_find_entry().
The current interface of nilfs_find_entry() and its callers is outdated and cannot propagate error codes such as -EIO and -ENOMEM returned via nilfs_find_entry(), so fix it together.
fs/nilfs2/dir.c +25 -23
@@ -289,7 +289,7 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx)* The folio is mapped and unlocked. When the caller is finished with * the entry, it should call folio_release_kmap(). * -* On failure, returns NULL and the caller should ignore foliop. +* On failure, returns an error pointer and the caller should ignore foliop. */ struct nilfs_dir_entry *nilfs_find_entry (struct inode *dir,const struct qstr *qstr,struct folio **foliop)
@@ -312,22 +312,24 @@ struct nilfs_dir_entry *nilfs_find_entry(struct inode *dir, do { char *kaddr = nilfs_get_folio(dir, n, foliop); - if (!IS_ERR(kaddr)) { - de = (struct nilfs_dir_entry *)kaddr; - kaddr += nilfs_last_byte(dir, n) - reclen; - while ((char *) de <= kaddr) { - if (de->rec_len == 0) { - nilfs_error(dir->i_sb, - "zero-length directory entry"); - folio_release_kmap(*foliop, kaddr); - goto out; - } - if (nilfs_match(namelen, name, de)) - goto found; - de = nilfs_next_entry(de); + if (IS_ERR(kaddr)) + return ERR_CAST(kaddr); + + de = (struct nilfs_dir_entry *)kaddr; + kaddr += nilfs_last_byte(dir, n) - reclen; + while ((char *)de <= kaddr) { + if (de->rec_len == 0) { + nilfs_error(dir->i_sb, + "zero-length directory entry"); + folio_release_kmap(*foliop, kaddr); + goto out; } - folio_release_kmap(*foliop, kaddr); + if (nilfs_match(namelen, name, de)) + goto found; + de = nilfs_next_entry(de); } + folio_release_kmap(*foliop, kaddr); + if (++n >= npages) n = 0; /* next folio is past the blocks we've got */
@@ -340,7 +342,7 @@ struct nilfs_dir_entry *nilfs_find_entry(struct inode *dir, } }while (n != start); out: -return NULL ; +return ERR_PTR (-ENOENT ); found: ei->i_dir_start_lookup = n;
@@ -384,18 +386,18 @@ fail:return NULL ; } -ino_t nilfs_inode_by_name (struct inode *dir,const struct qstr *qstr) +int nilfs_inode_by_name (struct inode *dir,const struct qstr *qstr,ino_t *ino) { -ino_t res =0 ;struct nilfs_dir_entry *de;struct folio *folio; de =nilfs_find_entry (dir, qstr, &folio); -if (de) { - res =le64_to_cpu (de->inode); -folio_release_kmap (folio, de); - } -return res; +if (IS_ERR (de)) +return PTR_ERR (de); + + *ino =le64_to_cpu (de->inode); +folio_release_kmap (folio, de); +return 0 ; } void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
fs/nilfs2/namei.c +26 -13
@@ -55,12 +55,20 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) {struct inode *inode;ino_t ino; +int res;if (dentry->d_name.len >NILFS_NAME_LEN )return ERR_PTR (-ENAMETOOLONG ); - ino =nilfs_inode_by_name (dir, &dentry->d_name); - inode = ino ?nilfs_iget (dir->i_sb,NILFS_I (dir)->i_root, ino) :NULL ; + res =nilfs_inode_by_name (dir, &dentry->d_name, &ino); +if (res) { +if (res != -ENOENT ) +return ERR_PTR (res); + inode =NULL ; + }else { + inode =nilfs_iget (dir->i_sb,NILFS_I (dir)->i_root, ino); + } +return d_splice_alias (inode, dentry); }
@@ -263,10 +271,11 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)struct folio *folio;int err; - err = -ENOENT ; de =nilfs_find_entry (dir, &dentry->d_name, &folio); -if (!de) +if (IS_ERR (de)) { + err =PTR_ERR (de); goto out; + } inode =d_inode (dentry); err = -EIO ;
@@ -362,10 +371,11 @@ static int nilfs_rename(struct mnt_idmap *idmap,if (unlikely (err))return err; - err = -ENOENT ; old_de =nilfs_find_entry (old_dir, &old_dentry->d_name, &old_folio); -if (!old_de) +if (IS_ERR (old_de)) { + err =PTR_ERR (old_de); goto out; + }if (S_ISDIR (old_inode->i_mode)) { err = -EIO ;
@@ -382,10 +392,12 @@ static int nilfs_rename(struct mnt_idmap *idmap,if (dir_de && !nilfs_empty_dir (new_inode)) goto out_dir; - err = -ENOENT ; - new_de =nilfs_find_entry (new_dir, &new_dentry->d_name, &new_folio); -if (!new_de) + new_de =nilfs_find_entry (new_dir, &new_dentry->d_name, + &new_folio); +if (IS_ERR (new_de)) { + err =PTR_ERR (new_de); goto out_dir; + }nilfs_set_link (new_dir, new_de, new_folio, old_inode);folio_release_kmap (new_folio, new_de);nilfs_mark_inode_dirty (new_dir);
@@ -440,12 +452,13 @@ out:*/ static struct dentry *nilfs_get_parent (struct dentry *child) { -unsigned long ino; +ino_t ino; +int res;struct nilfs_root *root; - ino =nilfs_inode_by_name (d_inode (child), &dotdot_name); -if (!ino) -return ERR_PTR (-ENOENT ); + res =nilfs_inode_by_name (d_inode (child), &dotdot_name, &ino); +if (res) +return ERR_PTR (res); root =NILFS_I (d_inode (child))->i_root;
fs/nilfs2/nilfs.h +1 -1
@@ -254,7 +254,7 @@ static inline __u32 nilfs_mask_flags(umode_t mode, __u32 flags)/* dir.c */ int nilfs_add_link (struct dentry *,struct inode *); -ino_t nilfs_inode_by_name (struct inode *,const struct qstr *); +int nilfs_inode_by_name (struct inode *dir,const struct qstr *qstr,ino_t *ino);int nilfs_make_empty (struct inode *,struct inode *);struct nilfs_dir_entry *nilfs_find_entry (struct inode *,const struct qstr *,struct folio **);
Ryusuke Konishi
maintainerPATCH 1/1 nilfs2: propagate directory read errors from nilfs_find_entry()
commit 08cfa12adf888db98879dbd735bc741360a34168 upstream.
Syzbot reported that a task hang occurs in vcs_open() during a fuzzing test for nilfs2.
The root cause of this problem is that in nilfs_find_entry(), which searches for directory entries, ignores errors when loading a directory page/folio via nilfs_get_folio() fails.
If the filesystem images is corrupted, and the i_size of the directory inode is large, and the directory page/folio is successfully read but fails the sanity check, for example when it is zero-filled, nilfs_check_folio() may continue to spit out error messages in bursts.
Fix this issue by propagating the error to the callers when loading a page/folio fails in nilfs_find_entry().
The current interface of nilfs_find_entry() and its callers is outdated and cannot propagate error codes such as -EIO and -ENOMEM returned via nilfs_find_entry(), so fix it together.
---
Please apply this patch to the stable trees indicated by the subject prefix instead of the failed patches.
This patch is tailored to take page/folio conversion into account and avoid a few conflicts. Compiled and tested successfully.
Thanks,
Ryusuke Konishi
fs/nilfs2/dir.c | 50 +++++++++++++++++++++++++---------------------- fs/nilfs2/namei.c | 39 ++++++++++++++++++++++++------------ fs/nilfs2/nilfs.h | 2 +- 3 files changed, 54 insertions(+), 37 deletions(-)
fs/nilfs2/dir.c +27 -23
@@ -331,6 +331,8 @@ static int nilfs_readdir(struct file *file, struct dir_context *ctx)* returns the page in which the entry was found, and the entry itself * (as a parameter - res_dir). Page is returned mapped and unlocked. * Entry is guaranteed to be valid. +* +* On failure, returns an error pointer and the caller should ignore res_page. */ struct nilfs_dir_entry * nilfs_find_entry(struct inode *dir, const struct qstr *qstr,
@@ -358,22 +360,24 @@ nilfs_find_entry(struct inode *dir, const struct qstr *qstr, do { char *kaddr = nilfs_get_page(dir, n, &page); - if (!IS_ERR(kaddr)) { - de = (struct nilfs_dir_entry *)kaddr; - kaddr += nilfs_last_byte(dir, n) - reclen; - while ((char *) de <= kaddr) { - if (de->rec_len == 0) { - nilfs_error(dir->i_sb, - "zero-length directory entry"); - nilfs_put_page(page); - goto out; - } - if (nilfs_match(namelen, name, de)) - goto found; - de = nilfs_next_entry(de); + if (IS_ERR(kaddr)) + return ERR_CAST(kaddr); + + de = (struct nilfs_dir_entry *)kaddr; + kaddr += nilfs_last_byte(dir, n) - reclen; + while ((char *)de <= kaddr) { + if (de->rec_len == 0) { + nilfs_error(dir->i_sb, + "zero-length directory entry"); + nilfs_put_page(page); + goto out; } - nilfs_put_page(page); + if (nilfs_match(namelen, name, de)) + goto found; + de = nilfs_next_entry(de); } + nilfs_put_page(page); + if (++n >= npages) n = 0; /* next page is past the blocks we've got */
@@ -386,7 +390,7 @@ nilfs_find_entry(struct inode *dir, const struct qstr *qstr, } }while (n != start); out: -return NULL ; +return ERR_PTR (-ENOENT ); found: *res_page = page;
@@ -431,19 +435,19 @@ struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct page **p)return NULL ; } -ino_t nilfs_inode_by_name (struct inode *dir,const struct qstr *qstr) +int nilfs_inode_by_name (struct inode *dir,const struct qstr *qstr,ino_t *ino) { -ino_t res =0 ;struct nilfs_dir_entry *de;struct page *page; de =nilfs_find_entry (dir, qstr, &page); -if (de) { - res =le64_to_cpu (de->inode); -kunmap (page); -put_page (page); - } -return res; +if (IS_ERR (de)) +return PTR_ERR (de); + + *ino =le64_to_cpu (de->inode); +kunmap (page); +put_page (page); +return 0 ; }/* Releases the page */
fs/nilfs2/namei.c +26 -13
@@ -55,12 +55,20 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) {struct inode *inode;ino_t ino; +int res;if (dentry->d_name.len >NILFS_NAME_LEN )return ERR_PTR (-ENAMETOOLONG ); - ino =nilfs_inode_by_name (dir, &dentry->d_name); - inode = ino ?nilfs_iget (dir->i_sb,NILFS_I (dir)->i_root, ino) :NULL ; + res =nilfs_inode_by_name (dir, &dentry->d_name, &ino); +if (res) { +if (res != -ENOENT ) +return ERR_PTR (res); + inode =NULL ; + }else { + inode =nilfs_iget (dir->i_sb,NILFS_I (dir)->i_root, ino); + } +return d_splice_alias (inode, dentry); }
@@ -261,10 +269,11 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)struct page *page;int err; - err = -ENOENT ; de =nilfs_find_entry (dir, &dentry->d_name, &page); -if (!de) +if (IS_ERR (de)) { + err =PTR_ERR (de); goto out; + } inode =d_inode (dentry); err = -EIO ;
@@ -358,10 +367,11 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,if (unlikely (err))return err; - err = -ENOENT ; old_de =nilfs_find_entry (old_dir, &old_dentry->d_name, &old_page); -if (!old_de) +if (IS_ERR (old_de)) { + err =PTR_ERR (old_de); goto out; + }if (S_ISDIR (old_inode->i_mode)) { err = -EIO ;
@@ -378,10 +388,12 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,if (dir_de && !nilfs_empty_dir (new_inode)) goto out_dir; - err = -ENOENT ; - new_de =nilfs_find_entry (new_dir, &new_dentry->d_name, &new_page); -if (!new_de) + new_de =nilfs_find_entry (new_dir, &new_dentry->d_name, + &new_page); +if (IS_ERR (new_de)) { + err =PTR_ERR (new_de); goto out_dir; + }nilfs_set_link (new_dir, new_de, new_page, old_inode);nilfs_mark_inode_dirty (new_dir); new_inode->i_ctime =current_time (new_inode);
@@ -435,14 +447,15 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,*/ static struct dentry *nilfs_get_parent (struct dentry *child) { -unsigned long ino; +ino_t ino; +int res;struct inode *inode;struct qstr dotdot =QSTR_INIT (".." ,2 );struct nilfs_root *root; - ino =nilfs_inode_by_name (d_inode (child), &dotdot); -if (!ino) -return ERR_PTR (-ENOENT ); + res =nilfs_inode_by_name (d_inode (child), &dotdot, &ino); +if (res) +return ERR_PTR (res); root =NILFS_I (d_inode (child))->i_root;
fs/nilfs2/nilfs.h +1 -1
@@ -233,7 +233,7 @@ static inline __u32 nilfs_mask_flags(umode_t mode, __u32 flags)/* dir.c */ extern int nilfs_add_link (struct dentry *,struct inode *); -extern ino_t nilfs_inode_by_name (struct inode *,const struct qstr *); +int nilfs_inode_by_name (struct inode *dir,const struct qstr *qstr,ino_t *ino);extern int nilfs_make_empty (struct inode *,struct inode *);extern struct nilfs_dir_entry *nilfs_find_entry (struct inode *,const struct qstr *,struct page **);
Signature · 1 line
2.43.5
Greg Kroah-Hartman
maintainerRe: [PATCH 4.19 5.4 5.10] nilfs2: propagate directory read errors from nilfs_find_entry()
Quoted 30 lines · Ryusuke Konishi
commit
08cfa12adf888db98879dbd735bc741360a34168upstream.Syzbot reported that a task hang occurs in
vcs_open()during a fuzzing test for nilfs2.The root cause of this problem is that in
nilfs_find_entry(), which searches for directory entries, ignores errors when loading a directory page/folio vianilfs_get_folio()fails.If the filesystem images is corrupted, and the
i_sizeof the directory inode is large, and the directory page/folio is successfully read but fails the sanity check, for example when it is zero-filled,nilfs_check_folio()may continue to spit out error messages in bursts.Fix this issue by propagating the error to the callers when loading a page/folio fails in
nilfs_find_entry().The current interface of
nilfs_find_entry()and its callers is outdated and cannot propagate error codes such as-EIOand-ENOMEMreturned vianilfs_find_entry(), so fix it together.Fixes 2ba466d74ed7 ("nilfs2: directory entry operations")Signed-off-by Ryusuke Konishi <[email protected]>Reported-by Lizhi Xu <[email protected]>Reported-by [email protected]Cc <[email protected]>Signed-off-by Andrew Morton <[email protected]>
Quoted 6 lines
---
Please apply this patch to the stable trees indicated by the subject prefix instead of the failed patches.This patch is tailored to take page/folio conversion into account and avoid a few conflicts. Compiled and tested successfully.
All now queued up, thanks for the backports.
greg k-h