]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Jan 2026 11:32:13 +0000 (12:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 19 Jan 2026 11:32:13 +0000 (12:32 +0100)
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

queue-5.10/efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch [new file with mode: 0644]
queue-5.10/nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch [new file with mode: 0644]
queue-5.10/nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch b/queue-5.10/efi-cper-fix-cper_bits_to_str-buffer-handling-and-return-value.patch
new file mode 100644 (file)
index 0000000..be179e5
--- /dev/null
@@ -0,0 +1,35 @@
+From d7f1b4bdc7108be1b178e1617b5f45c8918e88d7 Mon Sep 17 00:00:00 2001
+From: Morduan Zang <zhangdandan@uniontech.com>
+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 <zhangdandan@uniontech.com>
+
+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 <zhangdandan@uniontech.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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.10/nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch b/queue-5.10/nfs-add-barriers-when-testing-for-nfs_fsdata_blocked.patch
new file mode 100644 (file)
index 0000000..b127c0c
--- /dev/null
@@ -0,0 +1,147 @@
+From 99bc9f2eb3f79a2b4296d9bf43153e1d10ca50d3 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Tue, 28 May 2024 13:27:17 +1000
+Subject: NFS: add barriers when testing for NFS_FSDATA_BLOCKED
+
+From: NeilBrown <neilb@suse.de>
+
+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 <richard+debian+bugreport@kojedz.in>
+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 <neilb@suse.de>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/dir.c |   48 ++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 32 insertions(+), 16 deletions(-)
+
+--- a/fs/nfs/dir.c
++++ b/fs/nfs/dir.c
+@@ -1421,9 +1421,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);
+@@ -1436,6 +1437,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
+@@ -2114,16 +2138,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;
+@@ -2231,8 +2251,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);
+ }
+ /*
+@@ -2295,11 +2314,6 @@ int nfs_rename(struct inode *old_dir, st
+               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) {
+@@ -2321,7 +2335,7 @@ int nfs_rename(struct inode *old_dir, st
+                       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);
+@@ -2334,6 +2348,8 @@ int nfs_rename(struct inode *old_dir, st
+       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.10/nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch b/queue-5.10/nfs-unlink-rmdir-shouldn-t-call-d_delete-twice-on-enoent.patch
new file mode 100644 (file)
index 0000000..bac74d9
--- /dev/null
@@ -0,0 +1,58 @@
+From f16857e62bac60786104c020ad7c86e2163b2c5b Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Fri, 19 Aug 2022 09:55:59 +1000
+Subject: NFS: unlink/rmdir shouldn't call d_delete() twice on ENOENT
+
+From: NeilBrown <neilb@suse.de>
+
+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 <neilb@suse.de>
+Tested-by: Olga Kornievskaia <aglo@umich.edu>
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/nfs/dir.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/nfs/dir.c
++++ b/fs/nfs/dir.c
+@@ -2008,7 +2008,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));
index 1669bcd8aaf8967b827b383942c8eee0cb2ad2a9..41d98a870b647fe0ba28625737e8b25c6e9db262 100644 (file)
@@ -434,3 +434,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