From 90e08b15c06d9ca886bef3d1fc8599a800874d7a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 4 Feb 2025 12:36:30 +0100 Subject: [PATCH] 6.6-stable patches added patches: f2fs-introduce-linear-search-for-dentries.patch nfsd-reset-cb_seq_status-after-nfs4err_delay.patch --- ...introduce-linear-search-for-dentries.patch | 218 ++++++++++++++++++ ...et-cb_seq_status-after-nfs4err_delay.patch | 41 ++++ queue-6.6/series | 2 + 3 files changed, 261 insertions(+) create mode 100644 queue-6.6/f2fs-introduce-linear-search-for-dentries.patch create mode 100644 queue-6.6/nfsd-reset-cb_seq_status-after-nfs4err_delay.patch diff --git a/queue-6.6/f2fs-introduce-linear-search-for-dentries.patch b/queue-6.6/f2fs-introduce-linear-search-for-dentries.patch new file mode 100644 index 0000000000..daeb7695b0 --- /dev/null +++ b/queue-6.6/f2fs-introduce-linear-search-for-dentries.patch @@ -0,0 +1,218 @@ +From 91b587ba79e1b68bb718d12b0758dbcdab4e9cb7 Mon Sep 17 00:00:00 2001 +From: Daniel Lee +Date: Fri, 20 Dec 2024 15:41:31 -0800 +Subject: f2fs: Introduce linear search for dentries + +From: Daniel Lee + +commit 91b587ba79e1b68bb718d12b0758dbcdab4e9cb7 upstream. + +This patch addresses an issue where some files in case-insensitive +directories become inaccessible due to changes in how the kernel function, +utf8_casefold(), generates case-folded strings from the commit 5c26d2f1d3f5 +("unicode: Don't special case ignorable code points"). + +F2FS uses these case-folded names to calculate hash values for locating +dentries and stores them on disk. Since utf8_casefold() can produce +different output across kernel versions, stored hash values and newly +calculated hash values may differ. This results in affected files no +longer being found via the hash-based lookup. + +To resolve this, the patch introduces a linear search fallback. +If the initial hash-based search fails, F2FS will sequentially scan the +directory entries. + +Fixes: 5c26d2f1d3f5 ("unicode: Don't special case ignorable code points") +Link: https://bugzilla.kernel.org/show_bug.cgi?id=219586 +Signed-off-by: Daniel Lee +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Cc: Daniel Rosenberg +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/dir.c | 53 ++++++++++++++++++++++++++++++++++++++--------------- + fs/f2fs/f2fs.h | 6 ++++-- + fs/f2fs/inline.c | 5 +++-- + 3 files changed, 45 insertions(+), 19 deletions(-) + +--- a/fs/f2fs/dir.c ++++ b/fs/f2fs/dir.c +@@ -166,7 +166,8 @@ static unsigned long dir_block_index(uns + static struct f2fs_dir_entry *find_in_block(struct inode *dir, + struct page *dentry_page, + const struct f2fs_filename *fname, +- int *max_slots) ++ int *max_slots, ++ bool use_hash) + { + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dentry_ptr d; +@@ -174,7 +175,7 @@ static struct f2fs_dir_entry *find_in_bl + dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page); + + make_dentry_ptr_block(dir, &d, dentry_blk); +- return f2fs_find_target_dentry(&d, fname, max_slots); ++ return f2fs_find_target_dentry(&d, fname, max_slots, use_hash); + } + + #if IS_ENABLED(CONFIG_UNICODE) +@@ -251,7 +252,8 @@ static inline int f2fs_match_name(const + } + + struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d, +- const struct f2fs_filename *fname, int *max_slots) ++ const struct f2fs_filename *fname, int *max_slots, ++ bool use_hash) + { + struct f2fs_dir_entry *de; + unsigned long bit_pos = 0; +@@ -274,7 +276,7 @@ struct f2fs_dir_entry *f2fs_find_target_ + continue; + } + +- if (de->hash_code == fname->hash) { ++ if (!use_hash || de->hash_code == fname->hash) { + res = f2fs_match_name(d->inode, fname, + d->filename[bit_pos], + le16_to_cpu(de->name_len)); +@@ -301,11 +303,12 @@ found: + static struct f2fs_dir_entry *find_in_level(struct inode *dir, + unsigned int level, + const struct f2fs_filename *fname, +- struct page **res_page) ++ struct page **res_page, ++ bool use_hash) + { + int s = GET_DENTRY_SLOTS(fname->disk_name.len); + unsigned int nbucket, nblock; +- unsigned int bidx, end_block; ++ unsigned int bidx, end_block, bucket_no; + struct page *dentry_page; + struct f2fs_dir_entry *de = NULL; + pgoff_t next_pgofs; +@@ -315,8 +318,11 @@ static struct f2fs_dir_entry *find_in_le + nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); + nblock = bucket_blocks(level); + ++ bucket_no = use_hash ? le32_to_cpu(fname->hash) % nbucket : 0; ++ ++start_find_bucket: + bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level, +- le32_to_cpu(fname->hash) % nbucket); ++ bucket_no); + end_block = bidx + nblock; + + while (bidx < end_block) { +@@ -333,7 +339,7 @@ static struct f2fs_dir_entry *find_in_le + } + } + +- de = find_in_block(dir, dentry_page, fname, &max_slots); ++ de = find_in_block(dir, dentry_page, fname, &max_slots, use_hash); + if (IS_ERR(de)) { + *res_page = ERR_CAST(de); + de = NULL; +@@ -350,12 +356,18 @@ static struct f2fs_dir_entry *find_in_le + bidx++; + } + +- if (!de && room && F2FS_I(dir)->chash != fname->hash) { +- F2FS_I(dir)->chash = fname->hash; +- F2FS_I(dir)->clevel = level; +- } ++ if (de) ++ return de; + +- return de; ++ if (likely(use_hash)) { ++ if (room && F2FS_I(dir)->chash != fname->hash) { ++ F2FS_I(dir)->chash = fname->hash; ++ F2FS_I(dir)->clevel = level; ++ } ++ } else if (++bucket_no < nbucket) { ++ goto start_find_bucket; ++ } ++ return NULL; + } + + struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir, +@@ -366,11 +378,15 @@ struct f2fs_dir_entry *__f2fs_find_entry + struct f2fs_dir_entry *de = NULL; + unsigned int max_depth; + unsigned int level; ++ bool use_hash = true; + + *res_page = NULL; + ++#if IS_ENABLED(CONFIG_UNICODE) ++start_find_entry: ++#endif + if (f2fs_has_inline_dentry(dir)) { +- de = f2fs_find_in_inline_dir(dir, fname, res_page); ++ de = f2fs_find_in_inline_dir(dir, fname, res_page, use_hash); + goto out; + } + +@@ -386,11 +402,18 @@ struct f2fs_dir_entry *__f2fs_find_entry + } + + for (level = 0; level < max_depth; level++) { +- de = find_in_level(dir, level, fname, res_page); ++ de = find_in_level(dir, level, fname, res_page, use_hash); + if (de || IS_ERR(*res_page)) + break; + } ++ + out: ++#if IS_ENABLED(CONFIG_UNICODE) ++ if (IS_CASEFOLDED(dir) && !de && use_hash) { ++ use_hash = false; ++ goto start_find_entry; ++ } ++#endif + /* This is to increase the speed of f2fs_create */ + if (!de) + F2FS_I(dir)->task = current; +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -3531,7 +3531,8 @@ int f2fs_prepare_lookup(struct inode *di + struct f2fs_filename *fname); + void f2fs_free_filename(struct f2fs_filename *fname); + struct f2fs_dir_entry *f2fs_find_target_dentry(const struct f2fs_dentry_ptr *d, +- const struct f2fs_filename *fname, int *max_slots); ++ const struct f2fs_filename *fname, int *max_slots, ++ bool use_hash); + int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d, + unsigned int start_pos, struct fscrypt_str *fstr); + void f2fs_do_make_empty_dir(struct inode *inode, struct inode *parent, +@@ -4148,7 +4149,8 @@ int f2fs_write_inline_data(struct inode + int f2fs_recover_inline_data(struct inode *inode, struct page *npage); + struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, + const struct f2fs_filename *fname, +- struct page **res_page); ++ struct page **res_page, ++ bool use_hash); + int f2fs_make_empty_inline_dir(struct inode *inode, struct inode *parent, + struct page *ipage); + int f2fs_add_inline_entry(struct inode *dir, const struct f2fs_filename *fname, +--- a/fs/f2fs/inline.c ++++ b/fs/f2fs/inline.c +@@ -353,7 +353,8 @@ process_inline: + + struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, + const struct f2fs_filename *fname, +- struct page **res_page) ++ struct page **res_page, ++ bool use_hash) + { + struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb); + struct f2fs_dir_entry *de; +@@ -370,7 +371,7 @@ struct f2fs_dir_entry *f2fs_find_in_inli + inline_dentry = inline_data_addr(dir, ipage); + + make_dentry_ptr_inline(dir, &d, inline_dentry); +- de = f2fs_find_target_dentry(&d, fname, NULL); ++ de = f2fs_find_target_dentry(&d, fname, NULL, use_hash); + unlock_page(ipage); + if (IS_ERR(de)) { + *res_page = ERR_CAST(de); diff --git a/queue-6.6/nfsd-reset-cb_seq_status-after-nfs4err_delay.patch b/queue-6.6/nfsd-reset-cb_seq_status-after-nfs4err_delay.patch new file mode 100644 index 0000000000..2b251a67ed --- /dev/null +++ b/queue-6.6/nfsd-reset-cb_seq_status-after-nfs4err_delay.patch @@ -0,0 +1,41 @@ +From 961b4b5e86bf56a2e4b567f81682defa5cba957e Mon Sep 17 00:00:00 2001 +From: Chuck Lever +Date: Fri, 26 Jan 2024 12:45:17 -0500 +Subject: NFSD: Reset cb_seq_status after NFS4ERR_DELAY + +From: Chuck Lever + +commit 961b4b5e86bf56a2e4b567f81682defa5cba957e upstream. + +I noticed that once an NFSv4.1 callback operation gets a +NFS4ERR_DELAY status on CB_SEQUENCE and then the connection is lost, +the callback client loops, resending it indefinitely. + +The switch arm in nfsd4_cb_sequence_done() that handles +NFS4ERR_DELAY uses rpc_restart_call() to rearm the RPC state machine +for the retransmit, but that path does not call the rpc_prepare_call +callback again. Thus cb_seq_status is set to -10008 by the first +NFS4ERR_DELAY result, but is never set back to 1 for the retransmits. + +nfsd4_cb_sequence_done() thinks it's getting nothing but a +long series of CB_SEQUENCE NFS4ERR_DELAY replies. + +Fixes: 7ba6cad6c88f ("nfsd: New helper nfsd4_cb_sequence_done() for processing more cb errors") +Reviewed-by: Jeff Layton +Reviewed-by: Benjamin Coddington +Signed-off-by: Chuck Lever +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfsd/nfs4callback.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -1202,6 +1202,7 @@ static bool nfsd4_cb_sequence_done(struc + ret = false; + break; + case -NFS4ERR_DELAY: ++ cb->cb_seq_status = 1; + if (!rpc_restart_call(task)) + goto out; + diff --git a/queue-6.6/series b/queue-6.6/series index bcc076d9b7..9dd46aa0e8 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -370,3 +370,5 @@ kconfig-werror-unmet-symbol-dependency.patch kconfig-fix-memory-leak-in-sym_warn_unmet_dep.patch hexagon-fix-using-plain-integer-as-null-pointer-warn.patch hexagon-fix-unbalanced-spinlock-in-die.patch +f2fs-introduce-linear-search-for-dentries.patch +nfsd-reset-cb_seq_status-after-nfs4err_delay.patch -- 2.47.2