f2fs: fix to tag gcing flag on page during block migration
[platform/kernel/linux-starfive.git] / fs / f2fs / xattr.c
index a657284..e47cc91 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,17 @@ 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) {
+                       error = f2fs_recover_xattr_data(inode, NULL);
+                       f2fs_notice(F2FS_I_SB(inode),
+                               "recover xattr in inode (%lu), error(%d)",
+                                       inode->i_ino, error);
+                       if (!error) {
+                               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;
@@ -748,6 +757,12 @@ static int __f2fs_setxattr(struct inode *inode, int index,
                memcpy(pval, value, size);
                last->e_value_size = cpu_to_le16(size);
                new_hsize += newsize;
+               /*
+                * Explicitly add the null terminator.  The unused xattr space
+                * is supposed to always be zeroed, which would make this
+                * unnecessary, but don't depend on that.
+                */
+               *(u32 *)((u8 *)last + newsize) = 0;
        }
 
        error = write_all_xattrs(inode, new_hsize, base_addr, ipage);