f2fs: do not return EFSCORRUPTED, but try to run online repair
authorJaegeuk Kim <jaegeuk@kernel.org>
Thu, 19 Oct 2023 22:51:08 +0000 (15:51 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 28 Nov 2023 17:20:11 +0000 (17:20 +0000)
commit 50a472bbc79ff9d5a88be8019a60e936cadf9f13 upstream.

If we return the error, there's no way to recover the status as of now, since
fsck does not fix the xattr boundary issue.

Cc: stable@vger.kernel.org
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/f2fs/node.c
fs/f2fs/xattr.c

index ed963c5..8b30f11 100644 (file)
@@ -2751,7 +2751,9 @@ recover_xnid:
        f2fs_update_inode_page(inode);
 
        /* 3: update and set xattr node page dirty */
-       memcpy(F2FS_NODE(xpage), F2FS_NODE(page), VALID_XATTR_BLOCK_SIZE);
+       if (page)
+               memcpy(F2FS_NODE(xpage), F2FS_NODE(page),
+                               VALID_XATTR_BLOCK_SIZE);
 
        set_page_dirty(xpage);
        f2fs_put_page(xpage, 1);
index a657284..465d145 100644 (file)
@@ -364,10 +364,10 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
 
        *xe = __find_xattr(cur_addr, last_txattr_addr, NULL, index, len, name);
        if (!*xe) {
-               f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+               f2fs_err(F2FS_I_SB(inode), "lookup inode (%lu) has corrupted xattr",
                                                                inode->i_ino);
                set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
-               err = -EFSCORRUPTED;
+               err = -ENODATA;
                f2fs_handle_error(F2FS_I_SB(inode),
                                        ERROR_CORRUPTED_XATTR);
                goto out;
@@ -584,13 +584,12 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 
                if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
                        (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
-                       f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+                       f2fs_err(F2FS_I_SB(inode), "list inode (%lu) has corrupted xattr",
                                                inode->i_ino);
                        set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
-                       error = -EFSCORRUPTED;
                        f2fs_handle_error(F2FS_I_SB(inode),
                                                ERROR_CORRUPTED_XATTR);
-                       goto cleanup;
+                       break;
                }
 
                if (!prefix)
@@ -650,7 +649,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
 
        if (size > MAX_VALUE_LEN(inode))
                return -E2BIG;
-
+retry:
        error = read_all_xattrs(inode, ipage, &base_addr);
        if (error)
                return error;
@@ -660,7 +659,14 @@ static int __f2fs_setxattr(struct inode *inode, int index,
        /* find entry with wanted name. */
        here = __find_xattr(base_addr, last_base_addr, NULL, index, len, name);
        if (!here) {
-               f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
+               if (!F2FS_I(inode)->i_xattr_nid) {
+                       f2fs_notice(F2FS_I_SB(inode),
+                               "recover xattr in inode (%lu)", inode->i_ino);
+                       f2fs_recover_xattr_data(inode, NULL);
+                       kfree(base_addr);
+                       goto retry;
+               }
+               f2fs_err(F2FS_I_SB(inode), "set inode (%lu) has corrupted xattr",
                                                                inode->i_ino);
                set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
                error = -EFSCORRUPTED;