From: Greg Kroah-Hartman Date: Mon, 19 Jan 2026 11:32:25 +0000 (+0100) Subject: 5.15-stable patches X-Git-Tag: v5.15.198~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f5985d9d86f69b9847397f8450c492192e67f34;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch --- diff --git a/queue-5.15/efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch b/queue-5.15/efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch new file mode 100644 index 0000000000..be179e5a4b --- /dev/null +++ b/queue-5.15/efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch @@ -0,0 +1,35 @@ +From d7f1b4bdc7108be1b178e1617b5f45c8918e88d7 Mon Sep 17 00:00:00 2001 +From: Morduan Zang +Date: Wed, 14 Jan 2026 13:30:33 +0800 +Subject: efi/cper: Fix cper_bits_to_str buffer handling and return value + +From: Morduan Zang + +commit d7f1b4bdc7108be1b178e1617b5f45c8918e88d7 upstream. + +The return value calculation was incorrect: `return len - buf_size;` +Initially `len = buf_size`, then `len` decreases with each operation. +This results in a negative return value on success. + +Fix by returning `buf_size - len` which correctly calculates the actual +number of bytes written. + +Fixes: a976d790f494 ("efi/cper: Add a new helper function to print bitmasks") +Signed-off-by: Morduan Zang +Signed-off-by: Ard Biesheuvel +Signed-off-by: Greg Kroah-Hartman +--- + drivers/firmware/efi/cper.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/firmware/efi/cper.c ++++ b/drivers/firmware/efi/cper.c +@@ -161,7 +161,7 @@ int cper_bits_to_str(char *buf, int buf_ + len -= size; + str += size; + } +- return len - buf_size; ++ return buf_size - len; + } + EXPORT_SYMBOL_GPL(cper_bits_to_str); + diff --git a/queue-5.15/nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch b/queue-5.15/nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch new file mode 100644 index 0000000000..d873a9ea5e --- /dev/null +++ b/queue-5.15/nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch @@ -0,0 +1,147 @@ +From 99bc9f2eb3f79a2b4296d9bf43153e1d10ca50d3 Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Tue, 28 May 2024 13:27:17 +1000 +Subject: NFS: add barriers when testing for NFS_FSDATA_BLOCKED + +From: NeilBrown + +commit 99bc9f2eb3f79a2b4296d9bf43153e1d10ca50d3 upstream. + +dentry->d_fsdata is set to NFS_FSDATA_BLOCKED while unlinking or +renaming-over a file to ensure that no open succeeds while the NFS +operation progressed on the server. + +Setting dentry->d_fsdata to NFS_FSDATA_BLOCKED is done under ->d_lock +after checking the refcount is not elevated. Any attempt to open the +file (through that name) will go through lookp_open() which will take +->d_lock while incrementing the refcount, we can be sure that once the +new value is set, __nfs_lookup_revalidate() *will* see the new value and +will block. + +We don't have any locking guarantee that when we set ->d_fsdata to NULL, +the wait_var_event() in __nfs_lookup_revalidate() will notice. +wait/wake primitives do NOT provide barriers to guarantee order. We +must use smp_load_acquire() in wait_var_event() to ensure we look at an +up-to-date value, and must use smp_store_release() before wake_up_var(). + +This patch adds those barrier functions and factors out +block_revalidate() and unblock_revalidate() far clarity. + +There is also a hypothetical bug in that if memory allocation fails +(which never happens in practice) we might leave ->d_fsdata locked. +This patch adds the missing call to unblock_revalidate(). + +Reported-and-tested-by: Richard Kojedzinszky +Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1071501 +Fixes: 3c59366c207e ("NFS: don't unhash dentry during unlink/rename") +Signed-off-by: NeilBrown +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/dir.c | 48 ++++++++++++++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 16 deletions(-) + +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -1636,9 +1636,10 @@ __nfs_lookup_revalidate(struct dentry *d + if (parent != READ_ONCE(dentry->d_parent)) + return -ECHILD; + } else { +- /* Wait for unlink to complete */ ++ /* Wait for unlink to complete - see unblock_revalidate() */ + wait_var_event(&dentry->d_fsdata, +- dentry->d_fsdata != NFS_FSDATA_BLOCKED); ++ smp_load_acquire(&dentry->d_fsdata) ++ != NFS_FSDATA_BLOCKED); + parent = dget_parent(dentry); + ret = reval(d_inode(parent), dentry, flags); + dput(parent); +@@ -1651,6 +1652,29 @@ static int nfs_lookup_revalidate(struct + return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate); + } + ++static void block_revalidate(struct dentry *dentry) ++{ ++ /* old devname - just in case */ ++ kfree(dentry->d_fsdata); ++ ++ /* Any new reference that could lead to an open ++ * will take ->d_lock in lookup_open() -> d_lookup(). ++ * Holding this lock ensures we cannot race with ++ * __nfs_lookup_revalidate() and removes and need ++ * for further barriers. ++ */ ++ lockdep_assert_held(&dentry->d_lock); ++ ++ dentry->d_fsdata = NFS_FSDATA_BLOCKED; ++} ++ ++static void unblock_revalidate(struct dentry *dentry) ++{ ++ /* store_release ensures wait_var_event() sees the update */ ++ smp_store_release(&dentry->d_fsdata, NULL); ++ wake_up_var(&dentry->d_fsdata); ++} ++ + /* + * A weaker form of d_revalidate for revalidating just the d_inode(dentry) + * when we don't really care about the dentry name. This is called when a +@@ -2336,16 +2360,12 @@ int nfs_unlink(struct inode *dir, struct + spin_unlock(&dentry->d_lock); + goto out; + } +- if (dentry->d_fsdata) +- /* old devname */ +- kfree(dentry->d_fsdata); +- dentry->d_fsdata = NFS_FSDATA_BLOCKED; ++ block_revalidate(dentry); + + spin_unlock(&dentry->d_lock); + error = nfs_safe_remove(dentry); + nfs_dentry_remove_handle_error(dir, dentry, error); +- dentry->d_fsdata = NULL; +- wake_up_var(&dentry->d_fsdata); ++ unblock_revalidate(dentry); + out: + trace_nfs_unlink_exit(dir, dentry, error); + return error; +@@ -2454,8 +2474,7 @@ nfs_unblock_rename(struct rpc_task *task + { + struct dentry *new_dentry = data->new_dentry; + +- new_dentry->d_fsdata = NULL; +- wake_up_var(&new_dentry->d_fsdata); ++ unblock_revalidate(new_dentry); + } + + /* +@@ -2518,11 +2537,6 @@ int nfs_rename(struct user_namespace *mn + if (WARN_ON(new_dentry->d_flags & DCACHE_NFSFS_RENAMED) || + WARN_ON(new_dentry->d_fsdata == NFS_FSDATA_BLOCKED)) + goto out; +- if (new_dentry->d_fsdata) { +- /* old devname */ +- kfree(new_dentry->d_fsdata); +- new_dentry->d_fsdata = NULL; +- } + + spin_lock(&new_dentry->d_lock); + if (d_count(new_dentry) > 2) { +@@ -2544,7 +2558,7 @@ int nfs_rename(struct user_namespace *mn + new_dentry = dentry; + new_inode = NULL; + } else { +- new_dentry->d_fsdata = NFS_FSDATA_BLOCKED; ++ block_revalidate(new_dentry); + must_unblock = true; + new_gencount = NFS_I(new_inode)->attr_gencount; + spin_unlock(&new_dentry->d_lock); +@@ -2557,6 +2571,8 @@ int nfs_rename(struct user_namespace *mn + task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, + must_unblock ? nfs_unblock_rename : NULL); + if (IS_ERR(task)) { ++ if (must_unblock) ++ unblock_revalidate(new_dentry); + error = PTR_ERR(task); + goto out; + } diff --git a/queue-5.15/nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch b/queue-5.15/nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch new file mode 100644 index 0000000000..1b320b52a0 --- /dev/null +++ b/queue-5.15/nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch @@ -0,0 +1,58 @@ +From f16857e62bac60786104c020ad7c86e2163b2c5b Mon Sep 17 00:00:00 2001 +From: NeilBrown +Date: Fri, 19 Aug 2022 09:55:59 +1000 +Subject: NFS: unlink/rmdir shouldn't call d_delete() twice on ENOENT + +From: NeilBrown + +commit f16857e62bac60786104c020ad7c86e2163b2c5b upstream. + +nfs_unlink() calls d_delete() twice if it receives ENOENT from the +server - once in nfs_dentry_handle_enoent() from nfs_safe_remove and +once in nfs_dentry_remove_handle_error(). + +nfs_rmddir() also calls it twice - the nfs_dentry_handle_enoent() call +is direct and inside a region locked with ->rmdir_sem + +It is safe to call d_delete() twice if the refcount > 1 as the dentry is +simply unhashed. +If the refcount is 1, the first call sets d_inode to NULL and the second +call crashes. + +This patch guards the d_delete() call from nfs_dentry_handle_enoent() +leaving the one under ->remdir_sem in case that is important. + +In mainline it would be safe to remove the d_delete() call. However in +older kernels to which this might be backported, that would change the +behaviour of nfs_unlink(). nfs_unlink() used to unhash the dentry which +resulted in nfs_dentry_handle_enoent() not calling d_delete(). So in +older kernels we need the d_delete() in nfs_dentry_remove_handle_error() +when called from nfs_unlink() but not when called from nfs_rmdir(). + +To make the code work correctly for old and new kernels, and from both +nfs_unlink() and nfs_rmdir(), we protect the d_delete() call with +simple_positive(). This ensures it is never called in a circumstance +where it could crash. + +Fixes: 3c59366c207e ("NFS: don't unhash dentry during unlink/rename") +Fixes: 9019fb391de0 ("NFS: Label the dentry with a verifier in nfs_rmdir() and nfs_unlink()") +Signed-off-by: NeilBrown +Tested-by: Olga Kornievskaia +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman +--- + fs/nfs/dir.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -2230,7 +2230,8 @@ static void nfs_dentry_remove_handle_err + { + switch (error) { + case -ENOENT: +- d_delete(dentry); ++ if (d_really_is_positive(dentry)) ++ d_delete(dentry); + fallthrough; + case 0: + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); diff --git a/queue-5.15/series b/queue-5.15/series index 6996a014cc..40674a5849 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -535,3 +535,6 @@ can-j1939-make-j1939_session_activate-fail-if-device.patch asoc-fsl_sai-add-missing-registers-to-cache-default.patch scsi-sg-fix-occasional-bogus-elapsed-time-that-excee.patch firmware-imx-scu-irq-set-mu_resource_id-before-get-handle.patch +efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch +nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch +nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch