]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 24 Sep 2022 10:12:41 +0000 (12:12 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 24 Sep 2022 10:12:41 +0000 (12:12 +0200)
added patches:
xfs-fix-xfs_ifree-error-handling-to-not-leak-perag-ref.patch
xfs-reorder-iunlink-remove-operation-in-xfs_ifree.patch
xfs-validate-inode-fork-size-against-fork-format.patch

queue-5.15/series
queue-5.15/xfs-fix-xfs_ifree-error-handling-to-not-leak-perag-ref.patch [new file with mode: 0644]
queue-5.15/xfs-reorder-iunlink-remove-operation-in-xfs_ifree.patch [new file with mode: 0644]
queue-5.15/xfs-validate-inode-fork-size-against-fork-format.patch [new file with mode: 0644]

index 869694c0a14d7e14aba6082d9d72764727cd6afa..d54633831303f9c04946c1401719d28555c94403 100644 (file)
@@ -52,3 +52,6 @@ mm-slub-fix-flush_cpu_slab-__free_slab-invocations-in-task-context.patch
 kvm-x86-inject-ud-on-emulated-xsetbv-if-xsaves-isn-t-enabled.patch
 arm64-topology-fix-possible-overflow-in-amu_fie_setup.patch
 vmlinux.lds.h-cfi-reduce-alignment-of-jump-table-to-function-alignment.patch
+xfs-reorder-iunlink-remove-operation-in-xfs_ifree.patch
+xfs-fix-xfs_ifree-error-handling-to-not-leak-perag-ref.patch
+xfs-validate-inode-fork-size-against-fork-format.patch
diff --git a/queue-5.15/xfs-fix-xfs_ifree-error-handling-to-not-leak-perag-ref.patch b/queue-5.15/xfs-fix-xfs_ifree-error-handling-to-not-leak-perag-ref.patch
new file mode 100644 (file)
index 0000000..7b1febf
--- /dev/null
@@ -0,0 +1,41 @@
+From foo@baz Sat Sep 24 11:39:38 AM CEST 2022
+From: Leah Rumancik <leah.rumancik@gmail.com>
+Date: Thu, 22 Sep 2022 08:15:00 -0700
+Subject: xfs: fix xfs_ifree() error handling to not leak perag ref
+To: stable@vger.kernel.org
+Cc: linux-xfs@vger.kernel.org, amir73il@gmail.com, chandan.babu@oracle.com, Brian Foster <bfoster@redhat.com>, "Darrick J . Wong" <djwong@kernel.org>, Dave Chinner <dchinner@redhat.com>, Dave Chinner <david@fromorbit.com>, Leah Rumancik <leah.rumancik@gmail.com>
+Message-ID: <20220922151501.2297190-3-leah.rumancik@gmail.com>
+
+From: Brian Foster <bfoster@redhat.com>
+
+[ Upstream commit 6f5097e3367a7c0751e165e4c15bc30511a4ba38 ]
+
+For some reason commit 9a5280b312e2e ("xfs: reorder iunlink remove
+operation in xfs_ifree") replaced a jump to the exit path in the
+event of an xfs_difree() error with a direct return, which skips
+releasing the perag reference acquired at the top of the function.
+Restore the original code to drop the reference on error.
+
+Fixes: 9a5280b312e2e ("xfs: reorder iunlink remove operation in xfs_ifree")
+Signed-off-by: Brian Foster <bfoster@redhat.com>
+Reviewed-by: Darrick J. Wong <djwong@kernel.org>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Leah Rumancik <leah.rumancik@gmail.com>
+Acked-by: Darrick J. Wong <djwong@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/xfs/xfs_inode.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -2634,7 +2634,7 @@ xfs_ifree(
+        */
+       error = xfs_difree(tp, pag, ip->i_ino, &xic);
+       if (error)
+-              return error;
++              goto out;
+       error = xfs_iunlink_remove(tp, pag, ip);
+       if (error)
diff --git a/queue-5.15/xfs-reorder-iunlink-remove-operation-in-xfs_ifree.patch b/queue-5.15/xfs-reorder-iunlink-remove-operation-in-xfs_ifree.patch
new file mode 100644 (file)
index 0000000..cf37b3c
--- /dev/null
@@ -0,0 +1,91 @@
+From foo@baz Sat Sep 24 11:39:38 AM CEST 2022
+From: Leah Rumancik <leah.rumancik@gmail.com>
+Date: Thu, 22 Sep 2022 08:14:59 -0700
+Subject: xfs: reorder iunlink remove operation in xfs_ifree
+To: stable@vger.kernel.org
+Cc: linux-xfs@vger.kernel.org, amir73il@gmail.com, chandan.babu@oracle.com, Dave Chinner <dchinner@redhat.com>, Frank Hofmann <fhofmann@cloudflare.com>, "Darrick J . Wong" <darrick.wong@oracle.com>, Dave Chinner <david@fromorbit.com>, Leah Rumancik <leah.rumancik@gmail.com>, "Darrick J . Wong" <djwong@kernel.org>
+Message-ID: <20220922151501.2297190-2-leah.rumancik@gmail.com>
+
+From: Dave Chinner <dchinner@redhat.com>
+
+[ Upstream commit 9a5280b312e2e7898b6397b2ca3cfd03f67d7be1 ]
+
+The O_TMPFILE creation implementation creates a specific order of
+operations for inode allocation/freeing and unlinked list
+modification. Currently both are serialised by the AGI, so the order
+doesn't strictly matter as long as the are both in the same
+transaction.
+
+However, if we want to move the unlinked list insertions largely out
+from under the AGI lock, then we have to be concerned about the
+order in which we do unlinked list modification operations.
+O_TMPFILE creation tells us this order is inode allocation/free,
+then unlinked list modification.
+
+Change xfs_ifree() to use this same ordering on unlinked list
+removal. This way we always guarantee that when we enter the
+iunlinked list removal code from this path, we already have the AGI
+locked and we don't have to worry about lock nesting AGI reads
+inside unlink list locks because it's already locked and attached to
+the transaction.
+
+We can do this safely as the inode freeing and unlinked list removal
+are done in the same transaction and hence are atomic operations
+with respect to log recovery.
+
+Reported-by: Frank Hofmann <fhofmann@cloudflare.com>
+Fixes: 298f7bec503f ("xfs: pin inode backing buffer to the inode log item")
+Signed-off-by: Dave Chinner <dchinner@redhat.com>
+Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Leah Rumancik <leah.rumancik@gmail.com>
+Acked-by: Darrick J. Wong <djwong@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/xfs/xfs_inode.c |   24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+--- a/fs/xfs/xfs_inode.c
++++ b/fs/xfs/xfs_inode.c
+@@ -2599,14 +2599,13 @@ xfs_ifree_cluster(
+ }
+ /*
+- * This is called to return an inode to the inode free list.
+- * The inode should already be truncated to 0 length and have
+- * no pages associated with it.  This routine also assumes that
+- * the inode is already a part of the transaction.
++ * This is called to return an inode to the inode free list.  The inode should
++ * already be truncated to 0 length and have no pages associated with it.  This
++ * routine also assumes that the inode is already a part of the transaction.
+  *
+- * The on-disk copy of the inode will have been added to the list
+- * of unlinked inodes in the AGI. We need to remove the inode from
+- * that list atomically with respect to freeing it here.
++ * The on-disk copy of the inode will have been added to the list of unlinked
++ * inodes in the AGI. We need to remove the inode from that list atomically with
++ * respect to freeing it here.
+  */
+ int
+ xfs_ifree(
+@@ -2628,13 +2627,16 @@ xfs_ifree(
+       pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
+       /*
+-       * Pull the on-disk inode from the AGI unlinked list.
++       * Free the inode first so that we guarantee that the AGI lock is going
++       * to be taken before we remove the inode from the unlinked list. This
++       * makes the AGI lock -> unlinked list modification order the same as
++       * used in O_TMPFILE creation.
+        */
+-      error = xfs_iunlink_remove(tp, pag, ip);
++      error = xfs_difree(tp, pag, ip->i_ino, &xic);
+       if (error)
+-              goto out;
++              return error;
+-      error = xfs_difree(tp, pag, ip->i_ino, &xic);
++      error = xfs_iunlink_remove(tp, pag, ip);
+       if (error)
+               goto out;
diff --git a/queue-5.15/xfs-validate-inode-fork-size-against-fork-format.patch b/queue-5.15/xfs-validate-inode-fork-size-against-fork-format.patch
new file mode 100644 (file)
index 0000000..3dc1714
--- /dev/null
@@ -0,0 +1,86 @@
+From foo@baz Sat Sep 24 11:39:38 AM CEST 2022
+From: Leah Rumancik <leah.rumancik@gmail.com>
+Date: Thu, 22 Sep 2022 08:15:01 -0700
+Subject: xfs: validate inode fork size against fork format
+To: stable@vger.kernel.org
+Cc: linux-xfs@vger.kernel.org, amir73il@gmail.com, chandan.babu@oracle.com, Dave Chinner <dchinner@redhat.com>, Christoph Hellwig <hch@lst.de>, "Darrick J . Wong" <djwong@kernel.org>, Dave Chinner <david@fromorbit.com>, Leah Rumancik <leah.rumancik@gmail.com>
+Message-ID: <20220922151501.2297190-4-leah.rumancik@gmail.com>
+
+From: Dave Chinner <dchinner@redhat.com>
+
+[ Upstream commit 1eb70f54c445fcbb25817841e774adb3d912f3e8 ]
+
+xfs_repair catches fork size/format mismatches, but the in-kernel
+verifier doesn't, leading to null pointer failures when attempting
+to perform operations on the fork. This can occur in the
+xfs_dir_is_empty() where the in-memory fork format does not match
+the size and so the fork data pointer is accessed incorrectly.
+
+Note: this causes new failures in xfs/348 which is testing mode vs
+ftype mismatches. We now detect a regular file that has been changed
+to a directory or symlink mode as being corrupt because the data
+fork is for a symlink or directory should be in local form when
+there are only 3 bytes of data in the data fork. Hence the inode
+verify for the regular file now fires w/ -EFSCORRUPTED because
+the inode fork format does not match the format the corrupted mode
+says it should be in.
+
+Signed-off-by: Dave Chinner <dchinner@redhat.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Darrick J. Wong <djwong@kernel.org>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Leah Rumancik <leah.rumancik@gmail.com>
+Acked-by: Darrick J. Wong <djwong@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/xfs/libxfs/xfs_inode_buf.c |   35 ++++++++++++++++++++++++++---------
+ 1 file changed, 26 insertions(+), 9 deletions(-)
+
+--- a/fs/xfs/libxfs/xfs_inode_buf.c
++++ b/fs/xfs/libxfs/xfs_inode_buf.c
+@@ -337,19 +337,36 @@ xfs_dinode_verify_fork(
+       int                     whichfork)
+ {
+       uint32_t                di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
++      mode_t                  mode = be16_to_cpu(dip->di_mode);
++      uint32_t                fork_size = XFS_DFORK_SIZE(dip, mp, whichfork);
++      uint32_t                fork_format = XFS_DFORK_FORMAT(dip, whichfork);
+-      switch (XFS_DFORK_FORMAT(dip, whichfork)) {
++      /*
++       * For fork types that can contain local data, check that the fork
++       * format matches the size of local data contained within the fork.
++       *
++       * For all types, check that when the size says the should be in extent
++       * or btree format, the inode isn't claiming it is in local format.
++       */
++      if (whichfork == XFS_DATA_FORK) {
++              if (S_ISDIR(mode) || S_ISLNK(mode)) {
++                      if (be64_to_cpu(dip->di_size) <= fork_size &&
++                          fork_format != XFS_DINODE_FMT_LOCAL)
++                              return __this_address;
++              }
++
++              if (be64_to_cpu(dip->di_size) > fork_size &&
++                  fork_format == XFS_DINODE_FMT_LOCAL)
++                      return __this_address;
++      }
++
++      switch (fork_format) {
+       case XFS_DINODE_FMT_LOCAL:
+               /*
+-               * no local regular files yet
++               * No local regular files yet.
+                */
+-              if (whichfork == XFS_DATA_FORK) {
+-                      if (S_ISREG(be16_to_cpu(dip->di_mode)))
+-                              return __this_address;
+-                      if (be64_to_cpu(dip->di_size) >
+-                                      XFS_DFORK_SIZE(dip, mp, whichfork))
+-                              return __this_address;
+-              }
++              if (S_ISREG(mode) && whichfork == XFS_DATA_FORK)
++                      return __this_address;
+               if (di_nextents)
+                       return __this_address;
+               break;