summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2023-10-25 03:03:02 +0000
committerRobin Peng <robinpeng@google.com>2023-10-25 03:03:04 +0000
commit7db1424e76745193a3e19710a2db5bff0a357da2 (patch)
tree47896704644b65d3b6f77480eef9192d19059aa3
parent1b69820506fdea4339b15b177d1392b04099752c (diff)
parentdfb1120f912b54476997aefadd7a862382d53e0a (diff)
downloadgs-android-gs-lynx-android14-release.tar.gz
Merge SHA: dfb1120f912b5 FROMGIT: f2fs: do not return EFSCORRUPTED, but try to run online repair Bug: 305658663 Bug: 280545073 (ACK) Bug: 305658663 (ACK) Bug: 307367469 (ACK) Change-Id: I8b76c3dafb9ece6f052f8a3db69c49f0673d98fb Signed-off-by: Robin Peng <robinpeng@google.com>
-rw-r--r--fs/f2fs/dir.c9
-rw-r--r--fs/f2fs/f2fs.h1
-rw-r--r--fs/f2fs/node.c4
-rw-r--r--fs/f2fs/super.c1
-rw-r--r--fs/f2fs/xattr.c53
5 files changed, 51 insertions, 17 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index 1bc7e0387842..281241c6effc 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -808,8 +808,15 @@ int f2fs_add_dentry(struct inode *dir, const struct f2fs_filename *fname,
{
int err = -EAGAIN;
- if (f2fs_has_inline_dentry(dir))
+ if (f2fs_has_inline_dentry(dir)) {
+ /*
+ * Should get i_xattr_sem to keep the lock order:
+ * i_xattr_sem -> inode_page lock used by f2fs_setxattr.
+ */
+ f2fs_down_read(&F2FS_I(dir)->i_xattr_sem);
err = f2fs_add_inline_entry(dir, fname, inode, ino, mode);
+ f2fs_up_read(&F2FS_I(dir)->i_xattr_sem);
+ }
if (err == -EAGAIN)
err = f2fs_add_regular_entry(dir, fname, inode, ino, mode);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 91458b9dcb2b..d9e038d42548 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -808,6 +808,7 @@ struct f2fs_inode_info {
/* avoid racing between foreground op and gc */
struct f2fs_rwsem i_gc_rwsem[2];
struct f2fs_rwsem i_mmap_sem;
+ struct f2fs_rwsem i_xattr_sem; /* avoid racing between reading and changing EAs */
int i_extra_isize; /* size of extra space located in i_addr */
kprojid_t i_projid; /* id for project quota */
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 7f637b7c34cd..8df5cfcc3ab1 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -2741,7 +2741,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);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index eb34fed89b8f..0d20b52ae247 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1390,6 +1390,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
init_f2fs_rwsem(&fi->i_gc_rwsem[READ]);
init_f2fs_rwsem(&fi->i_gc_rwsem[WRITE]);
init_f2fs_rwsem(&fi->i_mmap_sem);
+ init_f2fs_rwsem(&fi->i_xattr_sem);
/* Will be used by directory only */
fi->i_dir_level = F2FS_SB(sb)->dir_level;
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 5b48357a7e91..6eb47b7445b4 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -361,10 +361,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;
goto out;
}
check:
@@ -428,7 +428,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
size_t inline_size = inline_xattr_size(inode);
- struct page *in_page = ipage;
+ struct page *in_page = NULL;
void *xattr_addr;
void *inline_addr = NULL;
struct page *xpage;
@@ -441,19 +441,29 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
/* write to inline xattr */
if (inline_size) {
- if (!in_page) {
+ if (ipage) {
+ inline_addr = inline_xattr_addr(inode, ipage);
+ } else {
in_page = f2fs_get_node_page(sbi, inode->i_ino);
if (IS_ERR(in_page)) {
f2fs_alloc_nid_failed(sbi, new_nid);
return PTR_ERR(in_page);
}
+ inline_addr = inline_xattr_addr(inode, in_page);
}
- inline_addr = inline_xattr_addr(inode, in_page);
- f2fs_wait_on_page_writeback(in_page, NODE, true, true);
+ f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
+ NODE, true, true);
+ /* no need to use xattr node block */
if (hsize <= inline_size) {
+ err = f2fs_truncate_xattr_node(inode);
+ f2fs_alloc_nid_failed(sbi, new_nid);
+ if (err) {
+ f2fs_put_page(in_page, 1);
+ return err;
+ }
memcpy(inline_addr, txattr_addr, inline_size);
- set_page_dirty(in_page);
+ set_page_dirty(ipage ? ipage : in_page);
goto in_page_out;
}
}
@@ -487,13 +497,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
if (inline_size)
- set_page_dirty(in_page);
+ set_page_dirty(ipage ? ipage : in_page);
set_page_dirty(xpage);
f2fs_put_page(xpage, 1);
in_page_out:
- if (in_page != ipage)
- f2fs_put_page(in_page, 1);
+ f2fs_put_page(in_page, 1);
return err;
}
@@ -514,8 +523,12 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
if (len > F2FS_NAME_LEN)
return -ERANGE;
+ if (!ipage)
+ f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
error = lookup_all_xattrs(inode, ipage, index, len, name,
&entry, &base_addr, &base_size, &is_inline);
+ if (!ipage)
+ f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
if (error)
return error;
@@ -549,7 +562,9 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
int error;
size_t rest = buffer_size;
+ f2fs_down_read(&F2FS_I(inode)->i_xattr_sem);
error = read_all_xattrs(inode, NULL, &base_addr);
+ f2fs_up_read(&F2FS_I(inode)->i_xattr_sem);
if (error)
return error;
@@ -564,11 +579,10 @@ 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;
- goto cleanup;
+ break;
}
if (!handler || (handler->list && !handler->list(dentry)))
@@ -629,7 +643,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;
@@ -639,7 +653,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;
@@ -771,7 +792,9 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
f2fs_balance_fs(sbi, true);
f2fs_lock_op(sbi);
+ f2fs_down_write(&F2FS_I(inode)->i_xattr_sem);
err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
+ f2fs_up_write(&F2FS_I(inode)->i_xattr_sem);
f2fs_unlock_op(sbi);
f2fs_update_time(sbi, REQ_TIME);