]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Tue, 8 Jul 2025 00:37:06 +0000 (20:37 -0400)
committerSasha Levin <sashal@kernel.org>
Tue, 8 Jul 2025 00:37:06 +0000 (20:37 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
18 files changed:
queue-5.15/btrfs-fix-inode-lookup-error-handling-during-log-rep.patch [new file with mode: 0644]
queue-5.15/btrfs-propagate-last_unlink_trans-earlier-when-doing.patch [new file with mode: 0644]
queue-5.15/btrfs-remove-noinline-from-btrfs_update_inode.patch [new file with mode: 0644]
queue-5.15/btrfs-remove-redundant-root-argument-from-fixup_inod.patch [new file with mode: 0644]
queue-5.15/btrfs-use-btrfs_record_snapshot_destroy-during-rmdir.patch [new file with mode: 0644]
queue-5.15/dpaa2-eth-fix-xdp_rxq_info-leak.patch [new file with mode: 0644]
queue-5.15/dpaa2-eth-update-dpni_get_single_step_cfg-command.patch [new file with mode: 0644]
queue-5.15/dpaa2-eth-update-single_step-register-access.patch [new file with mode: 0644]
queue-5.15/drm-v3d-disable-interrupts-before-resetting-the-gpu.patch [new file with mode: 0644]
queue-5.15/ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch [new file with mode: 0644]
queue-5.15/mmc-core-sd-apply-broken_sd_discard-quirk-earlier.patch [new file with mode: 0644]
queue-5.15/net-dpaa2-eth-rearrange-variable-in-dpaa2_eth_get_et.patch [new file with mode: 0644]
queue-5.15/nfsv4-flexfiles-fix-handling-of-nfs-level-errors-in-.patch [new file with mode: 0644]
queue-5.15/platform-x86-dell-wmi-sysman-fix-class-device-unregi.patch [new file with mode: 0644]
queue-5.15/platform-x86-think-lmi-fix-class-device-unregistrati.patch [new file with mode: 0644]
queue-5.15/regulator-gpio-add-input_supply-support-in-gpio_regu.patch [new file with mode: 0644]
queue-5.15/regulator-gpio-fix-the-out-of-bounds-access-to-drvda.patch [new file with mode: 0644]
queue-5.15/series

diff --git a/queue-5.15/btrfs-fix-inode-lookup-error-handling-during-log-rep.patch b/queue-5.15/btrfs-fix-inode-lookup-error-handling-during-log-rep.patch
new file mode 100644 (file)
index 0000000..8868aae
--- /dev/null
@@ -0,0 +1,451 @@
+From 66b39b200cc42b3e4d9962311739f75d8ce20c45 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Jun 2025 15:58:31 +0100
+Subject: btrfs: fix inode lookup error handling during log replay
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 5f61b961599acbd2bed028d3089105a1f7d224b8 ]
+
+When replaying log trees we use read_one_inode() to get an inode, which is
+just a wrapper around btrfs_iget_logging(), which in turn is a wrapper for
+btrfs_iget(). But read_one_inode() always returns NULL for any error
+that btrfs_iget_logging() / btrfs_iget() may return and this is a problem
+because:
+
+1) In many callers of read_one_inode() we convert the NULL into -EIO,
+   which is not accurate since btrfs_iget() may return -ENOMEM and -ENOENT
+   for example, besides -EIO and other errors. So during log replay we
+   may end up reporting a false -EIO, which is confusing since we may
+   not have had any IO error at all;
+
+2) When replaying directory deletes, at replay_dir_deletes(), we assume
+   the NULL returned from read_one_inode() means that the inode doesn't
+   exist and then proceed as if no error had happened. This is wrong
+   because unless btrfs_iget() returned ERR_PTR(-ENOENT), we had an
+   actual error and the target inode may exist in the target subvolume
+   root - this may later result in the log replay code failing at a
+   later stage (if we are "lucky") or succeed but leaving some
+   inconsistency in the filesystem.
+
+So fix this by not ignoring errors from btrfs_iget_logging() and as
+a consequence remove the read_one_inode() wrapper and just use
+btrfs_iget_logging() directly. Also since btrfs_iget_logging() is
+supposed to be called only against subvolume roots, just like
+read_one_inode() which had a comment about it, add an assertion to
+btrfs_iget_logging() to check that the target root corresponds to a
+subvolume root.
+
+Fixes: 5d4f98a28c7d ("Btrfs: Mixed back reference  (FORWARD ROLLING FORMAT CHANGE)")
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-log.c | 206 +++++++++++++++++++++++++++++---------------
+ 1 file changed, 138 insertions(+), 68 deletions(-)
+
+diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
+index 10db10544c96c..459b85268bc6b 100644
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -130,6 +130,31 @@ static void wait_log_commit(struct btrfs_root *root, int transid);
+  * and once to do all the other items.
+  */
++static struct btrfs_inode *btrfs_iget_logging(u64 objectid, struct btrfs_root *root)
++{
++      unsigned int nofs_flag;
++      struct inode *inode;
++
++      /* Only meant to be called for subvolume roots and not for log roots. */
++      ASSERT(root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
++             root->root_key.objectid != BTRFS_TREE_LOG_FIXUP_OBJECTID);
++
++      /*
++       * We're holding a transaction handle whether we are logging or
++       * replaying a log tree, so we must make sure NOFS semantics apply
++       * because btrfs_alloc_inode() may be triggered and it uses GFP_KERNEL
++       * to allocate an inode, which can recurse back into the filesystem and
++       * attempt a transaction commit, resulting in a deadlock.
++       */
++      nofs_flag = memalloc_nofs_save();
++      inode = btrfs_iget(root->fs_info->sb, objectid, root);
++      memalloc_nofs_restore(nofs_flag);
++
++      if (IS_ERR(inode))
++              return ERR_CAST(inode);
++
++      return BTRFS_I(inode);
++}
+ /*
+  * start a sub transaction and setup the log tree
+  * this increments the log tree writer count to make the people
+@@ -584,19 +609,18 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
+       return 0;
+ }
+-/*
+- * simple helper to read an inode off the disk from a given root
+- * This can only be called for subvolume roots and not for the log
+- */
+-static noinline struct inode *read_one_inode(struct btrfs_root *root,
+-                                           u64 objectid)
++static int read_alloc_one_name(struct extent_buffer *eb, void *start, int len,
++                             char **name)
+ {
+-      struct inode *inode;
++      char *buf;
+-      inode = btrfs_iget(root->fs_info->sb, objectid, root);
+-      if (IS_ERR(inode))
+-              inode = NULL;
+-      return inode;
++      buf = kmalloc(len, GFP_NOFS);
++      if (!buf)
++              return -ENOMEM;
++
++      read_extent_buffer(eb, buf, (unsigned long)start, len);
++      *name = buf;
++      return 0;
+ }
+ /* replays a single extent in 'eb' at 'slot' with 'key' into the
+@@ -652,10 +676,14 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
+               goto out;
+       }
+-      inode = read_one_inode(root, key->objectid);
+-      if (!inode) {
+-              ret = -EIO;
+-              goto out;
++      {
++              struct btrfs_inode *btrfs_inode;
++              btrfs_inode = btrfs_iget_logging(key->objectid, root);
++              if (IS_ERR(btrfs_inode)) {
++                      ret = PTR_ERR(btrfs_inode);
++                      goto out;
++              }
++              inode = &btrfs_inode->vfs_inode;
+       }
+       /*
+@@ -918,6 +946,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
+                                     struct btrfs_inode *dir,
+                                     struct btrfs_dir_item *di)
+ {
++      struct btrfs_inode *btrfs_inode;
+       struct inode *inode;
+       char *name;
+       int name_len;
+@@ -936,11 +965,13 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
+       read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len);
+       btrfs_release_path(path);
+-      inode = read_one_inode(root, location.objectid);
+-      if (!inode) {
+-              ret = -EIO;
++      btrfs_inode = btrfs_iget_logging(location.objectid, root);
++      if (IS_ERR(btrfs_inode)) {
++              ret = PTR_ERR(btrfs_inode);
++              inode = NULL;
+               goto out;
+       }
++      inode = &btrfs_inode->vfs_inode;
+       ret = link_to_fixup_dir(trans, root, path, location.objectid);
+       if (ret)
+@@ -1140,6 +1171,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
+               u32 item_size;
+               u32 cur_offset = 0;
+               unsigned long base;
++              struct btrfs_inode *victim_parent_btrfs;
+               struct inode *victim_parent;
+               leaf = path->nodes[0];
+@@ -1173,10 +1205,11 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
+                               kfree(victim_name);
+                               return ret;
+                       } else if (!ret) {
+-                              ret = -ENOENT;
+-                              victim_parent = read_one_inode(root,
+-                                              parent_objectid);
+-                              if (victim_parent) {
++                              victim_parent_btrfs = btrfs_iget_logging(parent_objectid, root);
++                              if (IS_ERR(victim_parent_btrfs)) {
++                                      ret = PTR_ERR(victim_parent_btrfs);
++                              } else {
++                                      victim_parent = &victim_parent_btrfs->vfs_inode;
+                                       inc_nlink(&inode->vfs_inode);
+                                       btrfs_release_path(path);
+@@ -1333,11 +1366,15 @@ static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
+                       struct inode *dir;
+                       btrfs_release_path(path);
+-                      dir = read_one_inode(root, parent_id);
+-                      if (!dir) {
+-                              ret = -ENOENT;
+-                              kfree(name);
+-                              goto out;
++                      {
++                              struct btrfs_inode *btrfs_dir;
++                              btrfs_dir = btrfs_iget_logging(parent_id, root);
++                              if (IS_ERR(btrfs_dir)) {
++                                      ret = PTR_ERR(btrfs_dir);
++                                      kfree(name);
++                                      goto out;
++                              }
++                              dir = &btrfs_dir->vfs_inode;
+                       }
+                       ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir),
+                                                inode, name, namelen);
+@@ -1432,10 +1469,14 @@ static int add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root,
+        */
+       btrfs_dir_item_key_to_cpu(path->nodes[0], dir_item, &key);
+       btrfs_release_path(path);
+-      other_inode = read_one_inode(root, key.objectid);
+-      if (!other_inode) {
+-              ret = -ENOENT;
+-              goto out;
++      {
++              struct btrfs_inode *btrfs_other_inode;
++              btrfs_other_inode = btrfs_iget_logging(key.objectid, root);
++              if (IS_ERR(btrfs_other_inode)) {
++                      ret = PTR_ERR(btrfs_other_inode);
++                      goto out;
++              }
++              other_inode = &btrfs_other_inode->vfs_inode;
+       }
+       ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(other_inode),
+                                         name, namelen);
+@@ -1470,6 +1511,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
+                                 struct extent_buffer *eb, int slot,
+                                 struct btrfs_key *key)
+ {
++      struct btrfs_inode *dir_btrfs = NULL;
++      struct btrfs_inode *inode_btrfs = NULL;
+       struct inode *dir = NULL;
+       struct inode *inode = NULL;
+       unsigned long ref_ptr;
+@@ -1506,17 +1549,21 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
+        * copy the back ref in.  The link count fixup code will take
+        * care of the rest
+        */
+-      dir = read_one_inode(root, parent_objectid);
+-      if (!dir) {
+-              ret = -ENOENT;
++      dir_btrfs = btrfs_iget_logging(parent_objectid, root);
++      if (IS_ERR(dir_btrfs)) {
++              ret = PTR_ERR(dir_btrfs);
++              dir = NULL;
+               goto out;
+       }
++      dir = &dir_btrfs->vfs_inode;
+-      inode = read_one_inode(root, inode_objectid);
+-      if (!inode) {
+-              ret = -EIO;
++      inode_btrfs = btrfs_iget_logging(inode_objectid, root);
++      if (IS_ERR(inode_btrfs)) {
++              ret = PTR_ERR(inode_btrfs);
++              inode = NULL;
+               goto out;
+       }
++      inode = &inode_btrfs->vfs_inode;
+       while (ref_ptr < ref_end) {
+               if (log_ref_ver) {
+@@ -1526,11 +1573,14 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
+                        * parent object can change from one array
+                        * item to another.
+                        */
+-                      if (!dir)
+-                              dir = read_one_inode(root, parent_objectid);
+                       if (!dir) {
+-                              ret = -ENOENT;
+-                              goto out;
++                              dir_btrfs = btrfs_iget_logging(parent_objectid, root);
++                              if (IS_ERR(dir_btrfs)) {
++                                      ret = PTR_ERR(dir_btrfs);
++                                      dir = NULL;
++                                      goto out;
++                              }
++                              dir = &dir_btrfs->vfs_inode;
+                       }
+               } else {
+                       ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
+@@ -1805,6 +1855,7 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
+ {
+       int ret;
+       struct btrfs_key key;
++      struct btrfs_inode *btrfs_inode;
+       struct inode *inode;
+       key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
+@@ -1832,11 +1883,12 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
+                       break;
+               btrfs_release_path(path);
+-              inode = read_one_inode(root, key.offset);
+-              if (!inode) {
+-                      ret = -EIO;
++              btrfs_inode = btrfs_iget_logging(key.offset, root);
++              if (IS_ERR(btrfs_inode)) {
++                      ret = PTR_ERR(btrfs_inode);
+                       break;
+               }
++              inode = &btrfs_inode->vfs_inode;
+               ret = fixup_inode_link_count(trans, inode);
+               iput(inode);
+@@ -1867,11 +1919,13 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
+ {
+       struct btrfs_key key;
+       int ret = 0;
++      struct btrfs_inode *btrfs_inode;
+       struct inode *inode;
+-      inode = read_one_inode(root, objectid);
+-      if (!inode)
+-              return -EIO;
++      btrfs_inode = btrfs_iget_logging(objectid, root);
++      if (IS_ERR(btrfs_inode))
++              return PTR_ERR(btrfs_inode);
++      inode = &btrfs_inode->vfs_inode;
+       key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
+       key.type = BTRFS_ORPHAN_ITEM_KEY;
+@@ -1907,17 +1961,21 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
+ {
+       struct inode *inode;
+       struct inode *dir;
++      struct btrfs_inode *btrfs_inode;
++      struct btrfs_inode *btrfs_dir;
+       int ret;
+-      inode = read_one_inode(root, location->objectid);
+-      if (!inode)
+-              return -ENOENT;
++      btrfs_inode = btrfs_iget_logging(location->objectid, root);
++      if (IS_ERR(btrfs_inode))
++              return PTR_ERR(btrfs_inode);
++      inode = &btrfs_inode->vfs_inode;
+-      dir = read_one_inode(root, dirid);
+-      if (!dir) {
++      btrfs_dir = btrfs_iget_logging(dirid, root);
++      if (IS_ERR(btrfs_dir)) {
+               iput(inode);
+-              return -EIO;
++              return PTR_ERR(btrfs_dir);
+       }
++      dir = &btrfs_dir->vfs_inode;
+       ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name,
+                       name_len, 1, index);
+@@ -1957,6 +2015,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
+       struct btrfs_dir_item *dst_di;
+       struct btrfs_key found_key;
+       struct btrfs_key log_key;
++      struct btrfs_inode *dir_btrfs;
+       struct inode *dir;
+       u8 log_type;
+       bool exists;
+@@ -1964,9 +2023,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
+       bool update_size = (key->type == BTRFS_DIR_INDEX_KEY);
+       bool name_added = false;
+-      dir = read_one_inode(root, key->objectid);
+-      if (!dir)
+-              return -EIO;
++      dir_btrfs = btrfs_iget_logging(key->objectid, root);
++      if (IS_ERR(dir_btrfs))
++              return PTR_ERR(dir_btrfs);
++      dir = &dir_btrfs->vfs_inode;
+       name_len = btrfs_dir_name_len(eb, di);
+       name = kmalloc(name_len, GFP_NOFS);
+@@ -2273,6 +2333,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
+       struct btrfs_dir_item *di;
+       int name_len;
+       char *name;
++      struct btrfs_inode *btrfs_inode = NULL;
+       struct inode *inode = NULL;
+       struct btrfs_key location;
+@@ -2316,11 +2377,13 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
+       btrfs_dir_item_key_to_cpu(eb, di, &location);
+       btrfs_release_path(path);
+       btrfs_release_path(log_path);
+-      inode = read_one_inode(root, location.objectid);
+-      if (!inode) {
+-              ret = -EIO;
++      btrfs_inode = btrfs_iget_logging(location.objectid, root);
++      if (IS_ERR(btrfs_inode)) {
++              ret = PTR_ERR(btrfs_inode);
++              inode = NULL;
+               goto out;
+       }
++      inode = &btrfs_inode->vfs_inode;
+       ret = link_to_fixup_dir(trans, root, path, location.objectid);
+       if (ret)
+@@ -2462,6 +2525,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
+       struct btrfs_key dir_key;
+       struct btrfs_key found_key;
+       struct btrfs_path *log_path;
++      struct btrfs_inode *dir_btrfs;
+       struct inode *dir;
+       dir_key.objectid = dirid;
+@@ -2470,15 +2534,19 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
+       if (!log_path)
+               return -ENOMEM;
+-      dir = read_one_inode(root, dirid);
+-      /* it isn't an error if the inode isn't there, that can happen
+-       * because we replay the deletes before we copy in the inode item
+-       * from the log
++      dir_btrfs = btrfs_iget_logging(dirid, root);
++      /*
++       * It isn't an error if the inode isn't there, that can happen because
++       * we replay the deletes before we copy in the inode item from the log.
+        */
+-      if (!dir) {
++      if (IS_ERR(dir_btrfs)) {
+               btrfs_free_path(log_path);
+-              return 0;
++              ret = PTR_ERR(dir_btrfs);
++              if (ret == -ENOENT)
++                      ret = 0;
++              return ret;
+       }
++      dir = &dir_btrfs->vfs_inode;
+       range_start = 0;
+       range_end = 0;
+@@ -2629,14 +2697,16 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
+                        */
+                       if (S_ISREG(mode)) {
+                               struct btrfs_drop_extents_args drop_args = { 0 };
++                              struct btrfs_inode *btrfs_inode;
+                               struct inode *inode;
+                               u64 from;
+-                              inode = read_one_inode(root, key.objectid);
+-                              if (!inode) {
+-                                      ret = -EIO;
++                              btrfs_inode = btrfs_iget_logging(key.objectid, root);
++                              if (IS_ERR(btrfs_inode)) {
++                                      ret = PTR_ERR(btrfs_inode);
+                                       break;
+                               }
++                              inode = &btrfs_inode->vfs_inode;
+                               from = ALIGN(i_size_read(inode),
+                                            root->fs_info->sectorsize);
+                               drop_args.start = from;
+-- 
+2.39.5
+
diff --git a/queue-5.15/btrfs-propagate-last_unlink_trans-earlier-when-doing.patch b/queue-5.15/btrfs-propagate-last_unlink_trans-earlier-when-doing.patch
new file mode 100644 (file)
index 0000000..ee6d955
--- /dev/null
@@ -0,0 +1,101 @@
+From cd133f62cfbbbee8a2bbca746aaefc6e52f9e2a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Jun 2025 15:54:05 +0100
+Subject: btrfs: propagate last_unlink_trans earlier when doing a rmdir
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit c466e33e729a0ee017d10d919cba18f503853c60 ]
+
+In case the removed directory had a snapshot that was deleted, we are
+propagating its inode's last_unlink_trans to the parent directory after
+we removed the entry from the parent directory. This leaves a small race
+window where someone can log the parent directory after we removed the
+entry and before we updated last_unlink_trans, and as a result if we ever
+try to replay such a log tree, we will fail since we will attempt to
+remove a snapshot during log replay, which is currently not possible and
+results in the log replay (and mount) to fail. This is the type of failure
+described in commit 1ec9a1ae1e30 ("Btrfs: fix unreplayable log after
+snapshot delete + parent dir fsync").
+
+So fix this by propagating the last_unlink_trans to the parent directory
+before we remove the entry from it.
+
+Fixes: 44f714dae50a ("Btrfs: improve performance on fsync against new inode after rename/unlink")
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 36 ++++++++++++++++++------------------
+ 1 file changed, 18 insertions(+), 18 deletions(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 32ae349b6abfb..76a59f95e7613 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4655,7 +4655,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
+       struct inode *inode = d_inode(dentry);
+       int err = 0;
+       struct btrfs_trans_handle *trans;
+-      u64 last_unlink_trans;
+       if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
+               return -ENOTEMPTY;
+@@ -4666,6 +4665,23 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
++      /*
++       * Propagate the last_unlink_trans value of the deleted dir to its
++       * parent directory. This is to prevent an unrecoverable log tree in the
++       * case we do something like this:
++       * 1) create dir foo
++       * 2) create snapshot under dir foo
++       * 3) delete the snapshot
++       * 4) rmdir foo
++       * 5) mkdir foo
++       * 6) fsync foo or some file inside foo
++       *
++       * This is because we can't unlink other roots when replaying the dir
++       * deletes for directory foo.
++       */
++      if (BTRFS_I(inode)->last_unlink_trans >= trans->transid)
++              BTRFS_I(dir)->last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
++
+       if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
+               err = btrfs_unlink_subvol(trans, dir, dentry);
+               goto out;
+@@ -4675,28 +4691,12 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
+       if (err)
+               goto out;
+-      last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
+-
+       /* now the directory is empty */
+       err = btrfs_unlink_inode(trans, BTRFS_I(dir),
+                       BTRFS_I(d_inode(dentry)), dentry->d_name.name,
+                       dentry->d_name.len);
+-      if (!err) {
++      if (!err)
+               btrfs_i_size_write(BTRFS_I(inode), 0);
+-              /*
+-               * Propagate the last_unlink_trans value of the deleted dir to
+-               * its parent directory. This is to prevent an unrecoverable
+-               * log tree in the case we do something like this:
+-               * 1) create dir foo
+-               * 2) create snapshot under dir foo
+-               * 3) delete the snapshot
+-               * 4) rmdir foo
+-               * 5) mkdir foo
+-               * 6) fsync foo or some file inside foo
+-               */
+-              if (last_unlink_trans >= trans->transid)
+-                      BTRFS_I(dir)->last_unlink_trans = last_unlink_trans;
+-      }
+ out:
+       btrfs_end_transaction(trans);
+       btrfs_btree_balance_dirty(BTRFS_I(dir)->root->fs_info);
+-- 
+2.39.5
+
diff --git a/queue-5.15/btrfs-remove-noinline-from-btrfs_update_inode.patch b/queue-5.15/btrfs-remove-noinline-from-btrfs_update_inode.patch
new file mode 100644 (file)
index 0000000..c441510
--- /dev/null
@@ -0,0 +1,42 @@
+From 749a04213654801d0644d81baf712cb3f7daba35 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 11:37:20 +0100
+Subject: btrfs: remove noinline from btrfs_update_inode()
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit cddaaacca9339d2f13599a822dc2f68be71d2e0d ]
+
+The noinline attribute of btrfs_update_inode() is pointless as the
+function is exported and widely used, so remove it.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 5f61b961599a ("btrfs: fix inode lookup error handling during log replay")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index e3e5bd4fb477a..32ae349b6abfb 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4074,9 +4074,9 @@ static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,
+ /*
+  * copy everything in the in-memory inode into the btree.
+  */
+-noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
+-                              struct btrfs_root *root,
+-                              struct btrfs_inode *inode)
++int btrfs_update_inode(struct btrfs_trans_handle *trans,
++                     struct btrfs_root *root,
++                     struct btrfs_inode *inode)
+ {
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       int ret;
+-- 
+2.39.5
+
diff --git a/queue-5.15/btrfs-remove-redundant-root-argument-from-fixup_inod.patch b/queue-5.15/btrfs-remove-redundant-root-argument-from-fixup_inod.patch
new file mode 100644 (file)
index 0000000..84a67ee
--- /dev/null
@@ -0,0 +1,108 @@
+From 0a86a37de55a083ad6ddb17ee782640f238fdb6e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 11:37:26 +0100
+Subject: btrfs: remove redundant root argument from fixup_inode_link_count()
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 8befc61cbba2d4567122d400542da8900a352971 ]
+
+The root argument for fixup_inode_link_count() always matches the root of
+the given inode, so remove the root argument and get it from the inode
+argument. This also applies to the helpers count_inode_extrefs() and
+count_inode_refs() used by fixup_inode_link_count() - they don't need the
+root argument, as it always matches the root of the inode passed to them.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Stable-dep-of: 5f61b961599a ("btrfs: fix inode lookup error handling during log replay")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/tree-log.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
+index 7049a19e07baf..10db10544c96c 100644
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -1638,8 +1638,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
+       return ret;
+ }
+-static int count_inode_extrefs(struct btrfs_root *root,
+-              struct btrfs_inode *inode, struct btrfs_path *path)
++static int count_inode_extrefs(struct btrfs_inode *inode, struct btrfs_path *path)
+ {
+       int ret = 0;
+       int name_len;
+@@ -1653,8 +1652,8 @@ static int count_inode_extrefs(struct btrfs_root *root,
+       struct extent_buffer *leaf;
+       while (1) {
+-              ret = btrfs_find_one_extref(root, inode_objectid, offset, path,
+-                                          &extref, &offset);
++              ret = btrfs_find_one_extref(inode->root, inode_objectid, offset,
++                                          path, &extref, &offset);
+               if (ret)
+                       break;
+@@ -1682,8 +1681,7 @@ static int count_inode_extrefs(struct btrfs_root *root,
+       return nlink;
+ }
+-static int count_inode_refs(struct btrfs_root *root,
+-                      struct btrfs_inode *inode, struct btrfs_path *path)
++static int count_inode_refs(struct btrfs_inode *inode, struct btrfs_path *path)
+ {
+       int ret;
+       struct btrfs_key key;
+@@ -1698,7 +1696,7 @@ static int count_inode_refs(struct btrfs_root *root,
+       key.offset = (u64)-1;
+       while (1) {
+-              ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
++              ret = btrfs_search_slot(NULL, inode->root, &key, path, 0, 0);
+               if (ret < 0)
+                       break;
+               if (ret > 0) {
+@@ -1750,9 +1748,9 @@ static int count_inode_refs(struct btrfs_root *root,
+  * will free the inode.
+  */
+ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
+-                                         struct btrfs_root *root,
+                                          struct inode *inode)
+ {
++      struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_path *path;
+       int ret;
+       u64 nlink = 0;
+@@ -1762,13 +1760,13 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
+       if (!path)
+               return -ENOMEM;
+-      ret = count_inode_refs(root, BTRFS_I(inode), path);
++      ret = count_inode_refs(BTRFS_I(inode), path);
+       if (ret < 0)
+               goto out;
+       nlink = ret;
+-      ret = count_inode_extrefs(root, BTRFS_I(inode), path);
++      ret = count_inode_extrefs(BTRFS_I(inode), path);
+       if (ret < 0)
+               goto out;
+@@ -1840,7 +1838,7 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
+                       break;
+               }
+-              ret = fixup_inode_link_count(trans, root, inode);
++              ret = fixup_inode_link_count(trans, inode);
+               iput(inode);
+               if (ret)
+                       break;
+-- 
+2.39.5
+
diff --git a/queue-5.15/btrfs-use-btrfs_record_snapshot_destroy-during-rmdir.patch b/queue-5.15/btrfs-use-btrfs_record_snapshot_destroy-during-rmdir.patch
new file mode 100644 (file)
index 0000000..bb90446
--- /dev/null
@@ -0,0 +1,46 @@
+From c9d4e50e114d31aab2c9842c0498b032dfa441d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Jun 2025 16:37:01 +0100
+Subject: btrfs: use btrfs_record_snapshot_destroy() during rmdir
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 157501b0469969fc1ba53add5049575aadd79d80 ]
+
+We are setting the parent directory's last_unlink_trans directly which
+may result in a concurrent task starting to log the directory not see the
+update and therefore can log the directory after we removed a child
+directory which had a snapshot within instead of falling back to a
+transaction commit. Replaying such a log tree would result in a mount
+failure since we can't currently delete snapshots (and subvolumes) during
+log replay. This is the type of failure described in commit 1ec9a1ae1e30
+("Btrfs: fix unreplayable log after snapshot delete + parent dir fsync").
+
+Fix this by using btrfs_record_snapshot_destroy() which updates the
+last_unlink_trans field while holding the inode's log_mutex lock.
+
+Fixes: 44f714dae50a ("Btrfs: improve performance on fsync against new inode after rename/unlink")
+Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/inode.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 76a59f95e7613..92a4c1a9d639b 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4680,7 +4680,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
+        * deletes for directory foo.
+        */
+       if (BTRFS_I(inode)->last_unlink_trans >= trans->transid)
+-              BTRFS_I(dir)->last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
++              btrfs_record_snapshot_destroy(trans, BTRFS_I(dir));
+       if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
+               err = btrfs_unlink_subvol(trans, dir, dentry);
+-- 
+2.39.5
+
diff --git a/queue-5.15/dpaa2-eth-fix-xdp_rxq_info-leak.patch b/queue-5.15/dpaa2-eth-fix-xdp_rxq_info-leak.patch
new file mode 100644 (file)
index 0000000..7c548cf
--- /dev/null
@@ -0,0 +1,101 @@
+From b5b52ec4e00e310c0a9a08bcab0c68082c4cd703 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Jul 2025 16:06:22 -0400
+Subject: dpaa2-eth: fix xdp_rxq_info leak
+
+From: Fushuai Wang <wangfushuai@baidu.com>
+
+[ Upstream commit 2def09ead4ad5907988b655d1e1454003aaf8297 ]
+
+The driver registered xdp_rxq_info structures via xdp_rxq_info_reg()
+but failed to properly unregister them in error paths and during
+removal.
+
+Fixes: d678be1dc1ec ("dpaa2-eth: add XDP_REDIRECT support")
+Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Link: https://patch.msgid.link/20250626133003.80136-1-wangfushuai@baidu.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 26 +++++++++++++++++--
+ 1 file changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+index acbb26cb2177e..07d8c9e41328e 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -3512,6 +3512,7 @@ static int dpaa2_eth_setup_rx_flow(struct dpaa2_eth_priv *priv,
+                                        MEM_TYPE_PAGE_ORDER0, NULL);
+       if (err) {
+               dev_err(dev, "xdp_rxq_info_reg_mem_model failed\n");
++              xdp_rxq_info_unreg(&fq->channel->xdp_rxq);
+               return err;
+       }
+@@ -4004,17 +4005,25 @@ static int dpaa2_eth_bind_dpni(struct dpaa2_eth_priv *priv)
+                       return -EINVAL;
+               }
+               if (err)
+-                      return err;
++                      goto out;
+       }
+       err = dpni_get_qdid(priv->mc_io, 0, priv->mc_token,
+                           DPNI_QUEUE_TX, &priv->tx_qdid);
+       if (err) {
+               dev_err(dev, "dpni_get_qdid() failed\n");
+-              return err;
++              goto out;
+       }
+       return 0;
++
++out:
++      while (i--) {
++              if (priv->fq[i].type == DPAA2_RX_FQ &&
++                  xdp_rxq_info_is_reg(&priv->fq[i].channel->xdp_rxq))
++                      xdp_rxq_info_unreg(&priv->fq[i].channel->xdp_rxq);
++      }
++      return err;
+ }
+ /* Allocate rings for storing incoming frame descriptors */
+@@ -4371,6 +4380,17 @@ static void dpaa2_eth_del_ch_napi(struct dpaa2_eth_priv *priv)
+       }
+ }
++static void dpaa2_eth_free_rx_xdp_rxq(struct dpaa2_eth_priv *priv)
++{
++      int i;
++
++      for (i = 0; i < priv->num_fqs; i++) {
++              if (priv->fq[i].type == DPAA2_RX_FQ &&
++                  xdp_rxq_info_is_reg(&priv->fq[i].channel->xdp_rxq))
++                      xdp_rxq_info_unreg(&priv->fq[i].channel->xdp_rxq);
++      }
++}
++
+ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
+ {
+       struct device *dev;
+@@ -4559,6 +4579,7 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev)
+       free_percpu(priv->percpu_stats);
+ err_alloc_percpu_stats:
+       dpaa2_eth_del_ch_napi(priv);
++      dpaa2_eth_free_rx_xdp_rxq(priv);
+ err_bind:
+       dpaa2_eth_free_dpbp(priv);
+ err_dpbp_setup:
+@@ -4610,6 +4631,7 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
+       free_percpu(priv->percpu_extras);
+       dpaa2_eth_del_ch_napi(priv);
++      dpaa2_eth_free_rx_xdp_rxq(priv);
+       dpaa2_eth_free_dpbp(priv);
+       dpaa2_eth_free_dpio(priv);
+       dpaa2_eth_free_dpni(priv);
+-- 
+2.39.5
+
diff --git a/queue-5.15/dpaa2-eth-update-dpni_get_single_step_cfg-command.patch b/queue-5.15/dpaa2-eth-update-dpni_get_single_step_cfg-command.patch
new file mode 100644 (file)
index 0000000..b2f68ed
--- /dev/null
@@ -0,0 +1,100 @@
+From 80073cdedb72f40e403091ce23a8e95d53193c39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 18 Feb 2022 22:22:00 +0200
+Subject: dpaa2-eth: Update dpni_get_single_step_cfg command
+
+From: Radu Bulie <radu-andrei.bulie@nxp.com>
+
+[ Upstream commit 9572594ecf027a2b1828e42c26fb55cbd3219708 ]
+
+dpni_get_single_step_cfg is an MC firmware command used for
+retrieving the contents of SINGLE_STEP 1588 register available
+in a DPMAC.
+
+This patch adds a new version of this command that returns as an extra
+argument the physical base address of the aforementioned register.
+The address will be used to directly modify the contents of the
+SINGLE_STEP register instead of invoking the MC command
+dpni_set_single_step_cgf. The former approach introduced huge delays on
+the TX datapath when one step PTP events were transmitted. This led to low
+throughput and high latencies observed in the PTP correction field.
+
+Signed-off-by: Radu Bulie <radu-andrei.bulie@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 2def09ead4ad ("dpaa2-eth: fix xdp_rxq_info leak")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h | 6 +++++-
+ drivers/net/ethernet/freescale/dpaa2/dpni.c     | 2 ++
+ drivers/net/ethernet/freescale/dpaa2/dpni.h     | 6 ++++++
+ 3 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+index 9f80bdfeedece..828f538097af8 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni-cmd.h
+@@ -98,7 +98,7 @@
+ #define DPNI_CMDID_GET_LINK_CFG                               DPNI_CMD(0x278)
+ #define DPNI_CMDID_SET_SINGLE_STEP_CFG                        DPNI_CMD(0x279)
+-#define DPNI_CMDID_GET_SINGLE_STEP_CFG                        DPNI_CMD(0x27a)
++#define DPNI_CMDID_GET_SINGLE_STEP_CFG                        DPNI_CMD_V2(0x27a)
+ /* Macros for accessing command fields smaller than 1byte */
+ #define DPNI_MASK(field)      \
+@@ -658,12 +658,16 @@ struct dpni_cmd_single_step_cfg {
+       __le16 flags;
+       __le16 offset;
+       __le32 peer_delay;
++      __le32 ptp_onestep_reg_base;
++      __le32 pad0;
+ };
+ struct dpni_rsp_single_step_cfg {
+       __le16 flags;
+       __le16 offset;
+       __le32 peer_delay;
++      __le32 ptp_onestep_reg_base;
++      __le32 pad0;
+ };
+ struct dpni_cmd_enable_vlan_filter {
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.c b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+index d6afada99fb66..6c3b36f20fb80 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.c
+@@ -2136,6 +2136,8 @@ int dpni_get_single_step_cfg(struct fsl_mc_io *mc_io,
+       ptp_cfg->ch_update = dpni_get_field(le16_to_cpu(rsp_params->flags),
+                                           PTP_CH_UPDATE) ? 1 : 0;
+       ptp_cfg->peer_delay = le32_to_cpu(rsp_params->peer_delay);
++      ptp_cfg->ptp_onestep_reg_base =
++                                le32_to_cpu(rsp_params->ptp_onestep_reg_base);
+       return err;
+ }
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpni.h b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+index 7de0562bbf59c..6fffd519aa00e 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpni.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpni.h
+@@ -1074,12 +1074,18 @@ int dpni_set_tx_shaping(struct fsl_mc_io *mc_io,
+  * @peer_delay:       For peer-to-peer transparent clocks add this value to the
+  *            correction field in addition to the transient time update.
+  *            The value expresses nanoseconds.
++ * @ptp_onestep_reg_base: 1588 SINGLE_STEP register base address. This address
++ *                      is used to update directly the register contents.
++ *                      User has to create an address mapping for it.
++ *
++ *
+  */
+ struct dpni_single_step_cfg {
+       u8      en;
+       u8      ch_update;
+       u16     offset;
+       u32     peer_delay;
++      u32     ptp_onestep_reg_base;
+ };
+ int dpni_set_single_step_cfg(struct fsl_mc_io *mc_io,
+-- 
+2.39.5
+
diff --git a/queue-5.15/dpaa2-eth-update-single_step-register-access.patch b/queue-5.15/dpaa2-eth-update-single_step-register-access.patch
new file mode 100644 (file)
index 0000000..25cbc10
--- /dev/null
@@ -0,0 +1,234 @@
+From c3a34eba2e422582e2af976fa660b2bc2c184736 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 18 Feb 2022 22:22:01 +0200
+Subject: dpaa2-eth: Update SINGLE_STEP register access
+
+From: Radu Bulie <radu-andrei.bulie@nxp.com>
+
+[ Upstream commit c4680c978567328a696fd2400bbf58a36cff95d1 ]
+
+DPAA2 MAC supports 1588 one step timestamping.
+If this option is enabled then for each transmitted PTP event packet,
+the 1588 SINGLE_STEP register is accessed to modify the following fields:
+
+-offset of the correction field inside the PTP packet
+-UDP checksum update bit,  in case the PTP event packet has
+ UDP encapsulation
+
+These values can change any time, because there may be multiple
+PTP clients connected, that receive various 1588 frame types:
+- L2 only frame
+- UDP / Ipv4
+- UDP / Ipv6
+- other
+
+The current implementation uses dpni_set_single_step_cfg to update the
+SINLGE_STEP register.
+Using an MC command  on the Tx datapath for each transmitted 1588 message
+introduces high delays, leading to low throughput and consequently to a
+small number of supported PTP clients. Besides these, the nanosecond
+correction field from the PTP packet will contain the high delay from the
+driver which together with the originTimestamp will render timestamp
+values that are unacceptable in a GM clock implementation.
+
+This patch updates the Tx datapath for 1588 messages when single step
+timestamp is enabled and provides direct access to SINGLE_STEP register,
+eliminating the  overhead caused by the dpni_set_single_step_cfg
+MC command. MC version >= 10.32 implements this functionality.
+If the MC version does not have support for returning the
+single step register base address, the driver will use
+dpni_set_single_step_cfg command for updates operations.
+
+All the delay introduced by dpni_set_single_step_cfg
+function will be eliminated (if MC version has support for returning the
+base address of the single step register), improving the egress driver
+performance for PTP packets when single step timestamping is enabled.
+
+Before these changes the maximum throughput for 1588 messages with
+single step hardware timestamp enabled was around 2000pps.
+After the updates the throughput increased up to 32.82 Mbps / 46631.02 pps.
+
+Signed-off-by: Radu Bulie <radu-andrei.bulie@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 2def09ead4ad ("dpaa2-eth: fix xdp_rxq_info leak")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../net/ethernet/freescale/dpaa2/dpaa2-eth.c  | 89 +++++++++++++++++--
+ .../net/ethernet/freescale/dpaa2/dpaa2-eth.h  | 14 ++-
+ 2 files changed, 93 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+index fa1b1b7dd8a06..acbb26cb2177e 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -34,6 +34,75 @@ MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver");
+ struct ptp_qoriq *dpaa2_ptp;
+ EXPORT_SYMBOL(dpaa2_ptp);
++static void dpaa2_eth_detect_features(struct dpaa2_eth_priv *priv)
++{
++      priv->features = 0;
++
++      if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_PTP_ONESTEP_VER_MAJOR,
++                                 DPNI_PTP_ONESTEP_VER_MINOR) >= 0)
++              priv->features |= DPAA2_ETH_FEATURE_ONESTEP_CFG_DIRECT;
++}
++
++static void dpaa2_update_ptp_onestep_indirect(struct dpaa2_eth_priv *priv,
++                                            u32 offset, u8 udp)
++{
++      struct dpni_single_step_cfg cfg;
++
++      cfg.en = 1;
++      cfg.ch_update = udp;
++      cfg.offset = offset;
++      cfg.peer_delay = 0;
++
++      if (dpni_set_single_step_cfg(priv->mc_io, 0, priv->mc_token, &cfg))
++              WARN_ONCE(1, "Failed to set single step register");
++}
++
++static void dpaa2_update_ptp_onestep_direct(struct dpaa2_eth_priv *priv,
++                                          u32 offset, u8 udp)
++{
++      u32 val = 0;
++
++      val = DPAA2_PTP_SINGLE_STEP_ENABLE |
++             DPAA2_PTP_SINGLE_CORRECTION_OFF(offset);
++
++      if (udp)
++              val |= DPAA2_PTP_SINGLE_STEP_CH;
++
++      if (priv->onestep_reg_base)
++              writel(val, priv->onestep_reg_base);
++}
++
++static void dpaa2_ptp_onestep_reg_update_method(struct dpaa2_eth_priv *priv)
++{
++      struct device *dev = priv->net_dev->dev.parent;
++      struct dpni_single_step_cfg ptp_cfg;
++
++      priv->dpaa2_set_onestep_params_cb = dpaa2_update_ptp_onestep_indirect;
++
++      if (!(priv->features & DPAA2_ETH_FEATURE_ONESTEP_CFG_DIRECT))
++              return;
++
++      if (dpni_get_single_step_cfg(priv->mc_io, 0,
++                                   priv->mc_token, &ptp_cfg)) {
++              dev_err(dev, "dpni_get_single_step_cfg cannot retrieve onestep reg, falling back to indirect update\n");
++              return;
++      }
++
++      if (!ptp_cfg.ptp_onestep_reg_base) {
++              dev_err(dev, "1588 onestep reg not available, falling back to indirect update\n");
++              return;
++      }
++
++      priv->onestep_reg_base = ioremap(ptp_cfg.ptp_onestep_reg_base,
++                                       sizeof(u32));
++      if (!priv->onestep_reg_base) {
++              dev_err(dev, "1588 onestep reg cannot be mapped, falling back to indirect update\n");
++              return;
++      }
++
++      priv->dpaa2_set_onestep_params_cb = dpaa2_update_ptp_onestep_direct;
++}
++
+ static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
+                               dma_addr_t iova_addr)
+ {
+@@ -693,7 +762,6 @@ static void dpaa2_eth_enable_tx_tstamp(struct dpaa2_eth_priv *priv,
+                                      struct sk_buff *skb)
+ {
+       struct ptp_tstamp origin_timestamp;
+-      struct dpni_single_step_cfg cfg;
+       u8 msgtype, twostep, udp;
+       struct dpaa2_faead *faead;
+       struct dpaa2_fas *fas;
+@@ -747,14 +815,12 @@ static void dpaa2_eth_enable_tx_tstamp(struct dpaa2_eth_priv *priv,
+                       htonl(origin_timestamp.sec_lsb);
+               *(__be32 *)(data + offset2 + 6) = htonl(origin_timestamp.nsec);
+-              cfg.en = 1;
+-              cfg.ch_update = udp;
+-              cfg.offset = offset1;
+-              cfg.peer_delay = 0;
++              if (priv->ptp_correction_off == offset1)
++                      return;
++
++              priv->dpaa2_set_onestep_params_cb(priv, offset1, udp);
++              priv->ptp_correction_off = offset1;
+-              if (dpni_set_single_step_cfg(priv->mc_io, 0, priv->mc_token,
+-                                           &cfg))
+-                      WARN_ONCE(1, "Failed to set single step register");
+       }
+ }
+@@ -2199,6 +2265,9 @@ static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+               config.rx_filter = HWTSTAMP_FILTER_ALL;
+       }
++      if (priv->tx_tstamp_type == HWTSTAMP_TX_ONESTEP_SYNC)
++              dpaa2_ptp_onestep_reg_update_method(priv);
++
+       return copy_to_user(rq->ifr_data, &config, sizeof(config)) ?
+                       -EFAULT : 0;
+ }
+@@ -4096,6 +4165,8 @@ static int dpaa2_eth_netdev_init(struct net_device *net_dev)
+               return err;
+       }
++      dpaa2_eth_detect_features(priv);
++
+       /* Capabilities listing */
+       supported |= IFF_LIVE_ADDR_CHANGE;
+@@ -4542,6 +4613,8 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev)
+       dpaa2_eth_free_dpbp(priv);
+       dpaa2_eth_free_dpio(priv);
+       dpaa2_eth_free_dpni(priv);
++      if (priv->onestep_reg_base)
++              iounmap(priv->onestep_reg_base);
+       fsl_mc_portal_free(priv->mc_io);
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+index 67fd926331fed..805e5619e1e63 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h
+@@ -506,12 +506,15 @@ struct dpaa2_eth_priv {
+       u8 num_channels;
+       struct dpaa2_eth_channel *channel[DPAA2_ETH_MAX_DPCONS];
+       struct dpaa2_eth_sgt_cache __percpu *sgt_cache;
+-
++      unsigned long features;
+       struct dpni_attr dpni_attrs;
+       u16 dpni_ver_major;
+       u16 dpni_ver_minor;
+       u16 tx_data_offset;
+-
++      void __iomem *onestep_reg_base;
++      u8 ptp_correction_off;
++      void (*dpaa2_set_onestep_params_cb)(struct dpaa2_eth_priv *priv,
++                                          u32 offset, u8 udp);
+       struct fsl_mc_device *dpbp_dev;
+       u16 rx_buf_size;
+       u16 bpid;
+@@ -651,6 +654,13 @@ enum dpaa2_eth_rx_dist {
+ #define DPAA2_ETH_DIST_L4DST          BIT(8)
+ #define DPAA2_ETH_DIST_ALL            (~0ULL)
++#define DPNI_PTP_ONESTEP_VER_MAJOR 8
++#define DPNI_PTP_ONESTEP_VER_MINOR 2
++#define DPAA2_ETH_FEATURE_ONESTEP_CFG_DIRECT BIT(0)
++#define DPAA2_PTP_SINGLE_STEP_ENABLE  BIT(31)
++#define DPAA2_PTP_SINGLE_STEP_CH      BIT(7)
++#define DPAA2_PTP_SINGLE_CORRECTION_OFF(v) ((v) << 8)
++
+ #define DPNI_PAUSE_VER_MAJOR          7
+ #define DPNI_PAUSE_VER_MINOR          13
+ #define dpaa2_eth_has_pause_support(priv)                     \
+-- 
+2.39.5
+
diff --git a/queue-5.15/drm-v3d-disable-interrupts-before-resetting-the-gpu.patch b/queue-5.15/drm-v3d-disable-interrupts-before-resetting-the-gpu.patch
new file mode 100644 (file)
index 0000000..622e1d6
--- /dev/null
@@ -0,0 +1,217 @@
+From 3c2b6a858023e8bc31477619ad8269976f9dad61 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 28 Jun 2025 19:42:42 -0300
+Subject: drm/v3d: Disable interrupts before resetting the GPU
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Maíra Canal <mcanal@igalia.com>
+
+[ Upstream commit 226862f50a7a88e4e4de9abbf36c64d19acd6fd0 ]
+
+Currently, an interrupt can be triggered during a GPU reset, which can
+lead to GPU hangs and NULL pointer dereference in an interrupt context
+as shown in the following trace:
+
+ [  314.035040] Unable to handle kernel NULL pointer dereference at virtual address 00000000000000c0
+ [  314.043822] Mem abort info:
+ [  314.046606]   ESR = 0x0000000096000005
+ [  314.050347]   EC = 0x25: DABT (current EL), IL = 32 bits
+ [  314.055651]   SET = 0, FnV = 0
+ [  314.058695]   EA = 0, S1PTW = 0
+ [  314.061826]   FSC = 0x05: level 1 translation fault
+ [  314.066694] Data abort info:
+ [  314.069564]   ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
+ [  314.075039]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
+ [  314.080080]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
+ [  314.085382] user pgtable: 4k pages, 39-bit VAs, pgdp=0000000102728000
+ [  314.091814] [00000000000000c0] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000
+ [  314.100511] Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP
+ [  314.106770] Modules linked in: v3d i2c_brcmstb vc4 snd_soc_hdmi_codec gpu_sched drm_shmem_helper drm_display_helper cec drm_dma_helper drm_kms_helper drm drm_panel_orientation_quirks snd_soc_core snd_compress snd_pcm_dmaengine snd_pcm snd_timer snd backlight
+ [  314.129654] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.12.25+rpt-rpi-v8 #1  Debian 1:6.12.25-1+rpt1
+ [  314.139388] Hardware name: Raspberry Pi 4 Model B Rev 1.4 (DT)
+ [  314.145211] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
+ [  314.152165] pc : v3d_irq+0xec/0x2e0 [v3d]
+ [  314.156187] lr : v3d_irq+0xe0/0x2e0 [v3d]
+ [  314.160198] sp : ffffffc080003ea0
+ [  314.163502] x29: ffffffc080003ea0 x28: ffffffec1f184980 x27: 021202b000000000
+ [  314.170633] x26: ffffffec1f17f630 x25: ffffff8101372000 x24: ffffffec1f17d9f0
+ [  314.177764] x23: 000000000000002a x22: 000000000000002a x21: ffffff8103252000
+ [  314.184895] x20: 0000000000000001 x19: 00000000deadbeef x18: 0000000000000000
+ [  314.192026] x17: ffffff94e51d2000 x16: ffffffec1dac3cb0 x15: c306000000000000
+ [  314.199156] x14: 0000000000000000 x13: b2fc982e03cc5168 x12: 0000000000000001
+ [  314.206286] x11: ffffff8103f8bcc0 x10: ffffffec1f196868 x9 : ffffffec1dac3874
+ [  314.213416] x8 : 0000000000000000 x7 : 0000000000042a3a x6 : ffffff810017a180
+ [  314.220547] x5 : ffffffec1ebad400 x4 : ffffffec1ebad320 x3 : 00000000000bebeb
+ [  314.227677] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000
+ [  314.234807] Call trace:
+ [  314.237243]  v3d_irq+0xec/0x2e0 [v3d]
+ [  314.240906]  __handle_irq_event_percpu+0x58/0x218
+ [  314.245609]  handle_irq_event+0x54/0xb8
+ [  314.249439]  handle_fasteoi_irq+0xac/0x240
+ [  314.253527]  handle_irq_desc+0x48/0x68
+ [  314.257269]  generic_handle_domain_irq+0x24/0x38
+ [  314.261879]  gic_handle_irq+0x48/0xd8
+ [  314.265533]  call_on_irq_stack+0x24/0x58
+ [  314.269448]  do_interrupt_handler+0x88/0x98
+ [  314.273624]  el1_interrupt+0x34/0x68
+ [  314.277193]  el1h_64_irq_handler+0x18/0x28
+ [  314.281281]  el1h_64_irq+0x64/0x68
+ [  314.284673]  default_idle_call+0x3c/0x168
+ [  314.288675]  do_idle+0x1fc/0x230
+ [  314.291895]  cpu_startup_entry+0x3c/0x50
+ [  314.295810]  rest_init+0xe4/0xf0
+ [  314.299030]  start_kernel+0x5e8/0x790
+ [  314.302684]  __primary_switched+0x80/0x90
+ [  314.306691] Code: 940029eb 360ffc13 f9442ea0 52800001 (f9406017)
+ [  314.312775] ---[ end trace 0000000000000000 ]---
+ [  314.317384] Kernel panic - not syncing: Oops: Fatal exception in interrupt
+ [  314.324249] SMP: stopping secondary CPUs
+ [  314.328167] Kernel Offset: 0x2b9da00000 from 0xffffffc080000000
+ [  314.334076] PHYS_OFFSET: 0x0
+ [  314.336946] CPU features: 0x08,00002013,c0200000,0200421b
+ [  314.342337] Memory Limit: none
+ [  314.345382] ---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]---
+
+Before resetting the GPU, it's necessary to disable all interrupts and
+deal with any interrupt handler still in-flight. Otherwise, the GPU might
+reset with jobs still running, or yet, an interrupt could be handled
+during the reset.
+
+Cc: stable@vger.kernel.org
+Fixes: 57692c94dcbe ("drm/v3d: Introduce a new DRM driver for Broadcom V3D V3.x+")
+Reviewed-by: Juan A. Suarez <jasuarez@igalia.com>
+Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
+Link: https://lore.kernel.org/r/20250628224243.47599-1-mcanal@igalia.com
+Signed-off-by: Maíra Canal <mcanal@igalia.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/v3d/v3d_drv.h |  8 +++++++
+ drivers/gpu/drm/v3d/v3d_gem.c |  2 ++
+ drivers/gpu/drm/v3d/v3d_irq.c | 39 +++++++++++++++++++++++++----------
+ 3 files changed, 38 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h
+index 2701347790730..0d551b1d9b05d 100644
+--- a/drivers/gpu/drm/v3d/v3d_drv.h
++++ b/drivers/gpu/drm/v3d/v3d_drv.h
+@@ -71,6 +71,12 @@ struct v3d_perfmon {
+       u64 values[];
+ };
++enum v3d_irq {
++      V3D_CORE_IRQ,
++      V3D_HUB_IRQ,
++      V3D_MAX_IRQS,
++};
++
+ struct v3d_dev {
+       struct drm_device drm;
+@@ -80,6 +86,8 @@ struct v3d_dev {
+       int ver;
+       bool single_irq_line;
++      int irq[V3D_MAX_IRQS];
++
+       void __iomem *hub_regs;
+       void __iomem *core_regs[3];
+       void __iomem *bridge_regs;
+diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
+index 805d6f6cba0e2..ecd03ad9699a0 100644
+--- a/drivers/gpu/drm/v3d/v3d_gem.c
++++ b/drivers/gpu/drm/v3d/v3d_gem.c
+@@ -120,6 +120,8 @@ v3d_reset(struct v3d_dev *v3d)
+       if (false)
+               v3d_idle_axi(v3d, 0);
++      v3d_irq_disable(v3d);
++
+       v3d_idle_gca(v3d);
+       v3d_reset_v3d(v3d);
+diff --git a/drivers/gpu/drm/v3d/v3d_irq.c b/drivers/gpu/drm/v3d/v3d_irq.c
+index b2d59a1686972..9aba78e6d7a5a 100644
+--- a/drivers/gpu/drm/v3d/v3d_irq.c
++++ b/drivers/gpu/drm/v3d/v3d_irq.c
+@@ -215,7 +215,7 @@ v3d_hub_irq(int irq, void *arg)
+ int
+ v3d_irq_init(struct v3d_dev *v3d)
+ {
+-      int irq1, ret, core;
++      int irq, ret, core;
+       INIT_WORK(&v3d->overflow_mem_work, v3d_overflow_mem_work);
+@@ -226,17 +226,24 @@ v3d_irq_init(struct v3d_dev *v3d)
+               V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
+       V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
+-      irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1);
+-      if (irq1 == -EPROBE_DEFER)
+-              return irq1;
+-      if (irq1 > 0) {
+-              ret = devm_request_irq(v3d->drm.dev, irq1,
++      irq = platform_get_irq_optional(v3d_to_pdev(v3d), 1);
++      if (irq == -EPROBE_DEFER)
++              return irq;
++      if (irq > 0) {
++              v3d->irq[V3D_CORE_IRQ] = irq;
++
++              ret = devm_request_irq(v3d->drm.dev, v3d->irq[V3D_CORE_IRQ],
+                                      v3d_irq, IRQF_SHARED,
+                                      "v3d_core0", v3d);
+               if (ret)
+                       goto fail;
+-              ret = devm_request_irq(v3d->drm.dev,
+-                                     platform_get_irq(v3d_to_pdev(v3d), 0),
++
++              irq = platform_get_irq(v3d_to_pdev(v3d), 0);
++              if (irq < 0)
++                      return irq;
++              v3d->irq[V3D_HUB_IRQ] = irq;
++
++              ret = devm_request_irq(v3d->drm.dev, v3d->irq[V3D_HUB_IRQ],
+                                      v3d_hub_irq, IRQF_SHARED,
+                                      "v3d_hub", v3d);
+               if (ret)
+@@ -244,8 +251,12 @@ v3d_irq_init(struct v3d_dev *v3d)
+       } else {
+               v3d->single_irq_line = true;
+-              ret = devm_request_irq(v3d->drm.dev,
+-                                     platform_get_irq(v3d_to_pdev(v3d), 0),
++              irq = platform_get_irq(v3d_to_pdev(v3d), 0);
++              if (irq < 0)
++                      return irq;
++              v3d->irq[V3D_CORE_IRQ] = irq;
++
++              ret = devm_request_irq(v3d->drm.dev, v3d->irq[V3D_CORE_IRQ],
+                                      v3d_irq, IRQF_SHARED,
+                                      "v3d", v3d);
+               if (ret)
+@@ -279,13 +290,19 @@ v3d_irq_enable(struct v3d_dev *v3d)
+ void
+ v3d_irq_disable(struct v3d_dev *v3d)
+ {
+-      int core;
++      int core, i;
+       /* Disable all interrupts. */
+       for (core = 0; core < v3d->cores; core++)
+               V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~0);
+       V3D_WRITE(V3D_HUB_INT_MSK_SET, ~0);
++      /* Finish any interrupt handler still in flight. */
++      for (i = 0; i < V3D_MAX_IRQS; i++) {
++              if (v3d->irq[i])
++                      synchronize_irq(v3d->irq[i]);
++      }
++
+       /* Clear any pending interrupts we might have left. */
+       for (core = 0; core < v3d->cores; core++)
+               V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
+-- 
+2.39.5
+
diff --git a/queue-5.15/ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch b/queue-5.15/ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch
new file mode 100644 (file)
index 0000000..d3823e9
--- /dev/null
@@ -0,0 +1,212 @@
+From 120ac71b5a511a9d1a5c2fec0560a43d7fd8e17f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Jun 2025 16:16:24 +0200
+Subject: ethernet: atl1: Add missing DMA mapping error checks and count errors
+
+From: Thomas Fourier <fourier.thomas@gmail.com>
+
+[ Upstream commit d72411d20905180cdc452c553be17481b24463d2 ]
+
+The `dma_map_XXX()` functions can fail and must be checked using
+`dma_mapping_error()`.  This patch adds proper error handling for all
+DMA mapping calls.
+
+In `atl1_alloc_rx_buffers()`, if DMA mapping fails, the buffer is
+deallocated and marked accordingly.
+
+In `atl1_tx_map()`, previously mapped buffers are unmapped and the
+packet is dropped on failure.
+
+If `atl1_xmit_frame()` drops the packet, increment the tx_error counter.
+
+Fixes: f3cc28c79760 ("Add Attansic L1 ethernet driver.")
+Signed-off-by: Thomas Fourier <fourier.thomas@gmail.com>
+Link: https://patch.msgid.link/20250625141629.114984-2-fourier.thomas@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/atheros/atlx/atl1.c | 78 +++++++++++++++++-------
+ 1 file changed, 56 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
+index 68f6c0bbd945c..ca8d7a82407b6 100644
+--- a/drivers/net/ethernet/atheros/atlx/atl1.c
++++ b/drivers/net/ethernet/atheros/atlx/atl1.c
+@@ -1861,14 +1861,21 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+                       break;
+               }
+-              buffer_info->alloced = 1;
+-              buffer_info->skb = skb;
+-              buffer_info->length = (u16) adapter->rx_buffer_len;
+               page = virt_to_page(skb->data);
+               offset = offset_in_page(skb->data);
+               buffer_info->dma = dma_map_page(&pdev->dev, page, offset,
+                                               adapter->rx_buffer_len,
+                                               DMA_FROM_DEVICE);
++              if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
++                      kfree_skb(skb);
++                      adapter->soft_stats.rx_dropped++;
++                      break;
++              }
++
++              buffer_info->alloced = 1;
++              buffer_info->skb = skb;
++              buffer_info->length = (u16)adapter->rx_buffer_len;
++
+               rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+               rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+               rfd_desc->coalese = 0;
+@@ -2180,8 +2187,8 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
+       return 0;
+ }
+-static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+-      struct tx_packet_desc *ptpd)
++static bool atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
++                      struct tx_packet_desc *ptpd)
+ {
+       struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+       struct atl1_buffer *buffer_info;
+@@ -2191,6 +2198,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+       unsigned int nr_frags;
+       unsigned int f;
+       int retval;
++      u16 first_mapped;
+       u16 next_to_use;
+       u16 data_len;
+       u8 hdr_len;
+@@ -2198,6 +2206,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+       buf_len -= skb->data_len;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       next_to_use = atomic_read(&tpd_ring->next_to_use);
++      first_mapped = next_to_use;
+       buffer_info = &tpd_ring->buffer_info[next_to_use];
+       BUG_ON(buffer_info->skb);
+       /* put skb in last TPD */
+@@ -2213,6 +2222,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+               buffer_info->dma = dma_map_page(&adapter->pdev->dev, page,
+                                               offset, hdr_len,
+                                               DMA_TO_DEVICE);
++              if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
++                      goto dma_err;
+               if (++next_to_use == tpd_ring->count)
+                       next_to_use = 0;
+@@ -2239,6 +2250,9 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+                                                               page, offset,
+                                                               buffer_info->length,
+                                                               DMA_TO_DEVICE);
++                              if (dma_mapping_error(&adapter->pdev->dev,
++                                                    buffer_info->dma))
++                                      goto dma_err;
+                               if (++next_to_use == tpd_ring->count)
+                                       next_to_use = 0;
+                       }
+@@ -2251,6 +2265,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+               buffer_info->dma = dma_map_page(&adapter->pdev->dev, page,
+                                               offset, buf_len,
+                                               DMA_TO_DEVICE);
++              if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
++                      goto dma_err;
+               if (++next_to_use == tpd_ring->count)
+                       next_to_use = 0;
+       }
+@@ -2274,6 +2290,9 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+                       buffer_info->dma = skb_frag_dma_map(&adapter->pdev->dev,
+                               frag, i * ATL1_MAX_TX_BUF_LEN,
+                               buffer_info->length, DMA_TO_DEVICE);
++                      if (dma_mapping_error(&adapter->pdev->dev,
++                                            buffer_info->dma))
++                              goto dma_err;
+                       if (++next_to_use == tpd_ring->count)
+                               next_to_use = 0;
+@@ -2282,6 +2301,22 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+       /* last tpd's buffer-info */
+       buffer_info->skb = skb;
++
++      return true;
++
++ dma_err:
++      while (first_mapped != next_to_use) {
++              buffer_info = &tpd_ring->buffer_info[first_mapped];
++              dma_unmap_page(&adapter->pdev->dev,
++                             buffer_info->dma,
++                             buffer_info->length,
++                             DMA_TO_DEVICE);
++              buffer_info->dma = 0;
++
++              if (++first_mapped == tpd_ring->count)
++                      first_mapped = 0;
++      }
++      return false;
+ }
+ static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count,
+@@ -2352,10 +2387,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
+       len = skb_headlen(skb);
+-      if (unlikely(skb->len <= 0)) {
+-              dev_kfree_skb_any(skb);
+-              return NETDEV_TX_OK;
+-      }
++      if (unlikely(skb->len <= 0))
++              goto drop_packet;
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       for (f = 0; f < nr_frags; f++) {
+@@ -2369,10 +2402,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
+               if (skb->protocol == htons(ETH_P_IP)) {
+                       proto_hdr_len = (skb_transport_offset(skb) +
+                                        tcp_hdrlen(skb));
+-                      if (unlikely(proto_hdr_len > len)) {
+-                              dev_kfree_skb_any(skb);
+-                              return NETDEV_TX_OK;
+-                      }
++                      if (unlikely(proto_hdr_len > len))
++                              goto drop_packet;
+                       /* need additional TPD ? */
+                       if (proto_hdr_len != len)
+                               count += (len - proto_hdr_len +
+@@ -2404,23 +2435,26 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
+       }
+       tso = atl1_tso(adapter, skb, ptpd);
+-      if (tso < 0) {
+-              dev_kfree_skb_any(skb);
+-              return NETDEV_TX_OK;
+-      }
++      if (tso < 0)
++              goto drop_packet;
+       if (!tso) {
+               ret_val = atl1_tx_csum(adapter, skb, ptpd);
+-              if (ret_val < 0) {
+-                      dev_kfree_skb_any(skb);
+-                      return NETDEV_TX_OK;
+-              }
++              if (ret_val < 0)
++                      goto drop_packet;
+       }
+-      atl1_tx_map(adapter, skb, ptpd);
++      if (!atl1_tx_map(adapter, skb, ptpd))
++              goto drop_packet;
++
+       atl1_tx_queue(adapter, count, ptpd);
+       atl1_update_mailbox(adapter);
+       return NETDEV_TX_OK;
++
++drop_packet:
++      adapter->soft_stats.tx_errors++;
++      dev_kfree_skb_any(skb);
++      return NETDEV_TX_OK;
+ }
+ static int atl1_rings_clean(struct napi_struct *napi, int budget)
+-- 
+2.39.5
+
diff --git a/queue-5.15/mmc-core-sd-apply-broken_sd_discard-quirk-earlier.patch b/queue-5.15/mmc-core-sd-apply-broken_sd_discard-quirk-earlier.patch
new file mode 100644 (file)
index 0000000..71dc6a7
--- /dev/null
@@ -0,0 +1,65 @@
+From 25a4800edcd012c6b239cbc557907a9a46a5be30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 May 2025 14:44:45 +0300
+Subject: mmc: core: sd: Apply BROKEN_SD_DISCARD quirk earlier
+
+From: Avri Altman <avri.altman@sandisk.com>
+
+[ Upstream commit 009c3a4bc41e855fd76f92727f9fbae4e5917d7f ]
+
+Move the BROKEN_SD_DISCARD quirk for certain SanDisk SD cards from the
+`mmc_blk_fixups[]` to `mmc_sd_fixups[]`. This ensures the quirk is
+applied earlier in the device initialization process, aligning with the
+reasoning in [1]. Applying the quirk sooner prevents the kernel from
+incorrectly enabling discard support on affected cards during initial
+setup.
+
+[1] https://lore.kernel.org/all/20240820230631.GA436523@sony.com
+
+Fixes: 07d2872bf4c8 ("mmc: core: Add SD card quirk for broken discard")
+Signed-off-by: Avri Altman <avri.altman@sandisk.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20250526114445.675548-1-avri.altman@sandisk.com
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/mmc/core/quirks.h | 16 +++++++++-------
+ 1 file changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
+index afe8d8c5fa8a2..2920633e2ae1e 100644
+--- a/drivers/mmc/core/quirks.h
++++ b/drivers/mmc/core/quirks.h
+@@ -14,6 +14,15 @@
+ #include "card.h"
++static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
++      /*
++       * Some SD cards reports discard support while they don't
++       */
++      MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
++                MMC_QUIRK_BROKEN_SD_DISCARD),
++
++      END_FIXUP
++};
+ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
+ #define INAND_CMD38_ARG_EXT_CSD  113
+ #define INAND_CMD38_ARG_ERASE    0x00
+@@ -112,13 +121,6 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
+        */
+       MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
+                 MMC_QUIRK_TRIM_BROKEN),
+-
+-      /*
+-       * Some SD cards reports discard support while they don't
+-       */
+-      MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
+-                MMC_QUIRK_BROKEN_SD_DISCARD),
+-
+       END_FIXUP
+ };
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-dpaa2-eth-rearrange-variable-in-dpaa2_eth_get_et.patch b/queue-5.15/net-dpaa2-eth-rearrange-variable-in-dpaa2_eth_get_et.patch
new file mode 100644 (file)
index 0000000..fab3570
--- /dev/null
@@ -0,0 +1,62 @@
+From fd2f7d2736b04cbda92a15cbda7d6e6c738f4c3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Oct 2022 17:18:51 +0300
+Subject: net: dpaa2-eth: rearrange variable in dpaa2_eth_get_ethtool_stats
+
+From: Ioana Ciornei <ioana.ciornei@nxp.com>
+
+[ Upstream commit 3313206827678f6f036eca601a51f6c4524b559a ]
+
+Rearrange the variables in the dpaa2_eth_get_ethtool_stats() function so
+that we adhere to the reverse Christmas tree rule.
+Also, in the next patch we are adding more variables and I didn't know
+where to place them with the current ordering.
+
+Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: 2def09ead4ad ("dpaa2-eth: fix xdp_rxq_info leak")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../ethernet/freescale/dpaa2/dpaa2-ethtool.c   | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+index 2da5f881f6302..3a310d92ef2f7 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c
+@@ -225,17 +225,8 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
+                                       struct ethtool_stats *stats,
+                                       u64 *data)
+ {
+-      int i = 0;
+-      int j, k, err;
+-      int num_cnt;
+-      union dpni_statistics dpni_stats;
+-      u32 fcnt, bcnt;
+-      u32 fcnt_rx_total = 0, fcnt_tx_total = 0;
+-      u32 bcnt_rx_total = 0, bcnt_tx_total = 0;
+-      u32 buf_cnt;
+       struct dpaa2_eth_priv *priv = netdev_priv(net_dev);
+-      struct dpaa2_eth_drv_stats *extras;
+-      struct dpaa2_eth_ch_stats *ch_stats;
++      union dpni_statistics dpni_stats;
+       int dpni_stats_page_size[DPNI_STATISTICS_CNT] = {
+               sizeof(dpni_stats.page_0),
+               sizeof(dpni_stats.page_1),
+@@ -245,6 +236,13 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev,
+               sizeof(dpni_stats.page_5),
+               sizeof(dpni_stats.page_6),
+       };
++      u32 fcnt_rx_total = 0, fcnt_tx_total = 0;
++      u32 bcnt_rx_total = 0, bcnt_tx_total = 0;
++      struct dpaa2_eth_ch_stats *ch_stats;
++      struct dpaa2_eth_drv_stats *extras;
++      int j, k, err, num_cnt, i = 0;
++      u32 fcnt, bcnt;
++      u32 buf_cnt;
+       memset(data, 0,
+              sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS));
+-- 
+2.39.5
+
diff --git a/queue-5.15/nfsv4-flexfiles-fix-handling-of-nfs-level-errors-in-.patch b/queue-5.15/nfsv4-flexfiles-fix-handling-of-nfs-level-errors-in-.patch
new file mode 100644 (file)
index 0000000..d19e2cc
--- /dev/null
@@ -0,0 +1,250 @@
+From d4f86625444c5b1a84cf044a8da842b25bd6e2de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Jun 2025 15:16:11 -0400
+Subject: NFSv4/flexfiles: Fix handling of NFS level errors in I/O
+
+From: Trond Myklebust <trond.myklebust@hammerspace.com>
+
+[ Upstream commit 38074de35b015df5623f524d6f2b49a0cd395c40 ]
+
+Allow the flexfiles error handling to recognise NFS level errors (as
+opposed to RPC level errors) and handle them separately. The main
+motivator is the NFSERR_PERM errors that get returned if the NFS client
+connects to the data server through a port number that is lower than
+1024. In that case, the client should disconnect and retry a READ on a
+different data server, or it should retry a WRITE after reconnecting.
+
+Reviewed-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
+Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver")
+Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/nfs/flexfilelayout/flexfilelayout.c | 121 ++++++++++++++++++-------
+ 1 file changed, 87 insertions(+), 34 deletions(-)
+
+diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
+index a55eec241657d..7a568d2de472e 100644
+--- a/fs/nfs/flexfilelayout/flexfilelayout.c
++++ b/fs/nfs/flexfilelayout/flexfilelayout.c
+@@ -1099,6 +1099,7 @@ static void ff_layout_reset_read(struct nfs_pgio_header *hdr)
+ }
+ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
++                                         u32 op_status,
+                                          struct nfs4_state *state,
+                                          struct nfs_client *clp,
+                                          struct pnfs_layout_segment *lseg,
+@@ -1109,32 +1110,42 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
+       struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
+       struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
+-      switch (task->tk_status) {
+-      case -NFS4ERR_BADSESSION:
+-      case -NFS4ERR_BADSLOT:
+-      case -NFS4ERR_BAD_HIGH_SLOT:
+-      case -NFS4ERR_DEADSESSION:
+-      case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+-      case -NFS4ERR_SEQ_FALSE_RETRY:
+-      case -NFS4ERR_SEQ_MISORDERED:
++      switch (op_status) {
++      case NFS4_OK:
++      case NFS4ERR_NXIO:
++              break;
++      case NFSERR_PERM:
++              if (!task->tk_xprt)
++                      break;
++              xprt_force_disconnect(task->tk_xprt);
++              goto out_retry;
++      case NFS4ERR_BADSESSION:
++      case NFS4ERR_BADSLOT:
++      case NFS4ERR_BAD_HIGH_SLOT:
++      case NFS4ERR_DEADSESSION:
++      case NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
++      case NFS4ERR_SEQ_FALSE_RETRY:
++      case NFS4ERR_SEQ_MISORDERED:
+               dprintk("%s ERROR %d, Reset session. Exchangeid "
+                       "flags 0x%x\n", __func__, task->tk_status,
+                       clp->cl_exchange_flags);
+               nfs4_schedule_session_recovery(clp->cl_session, task->tk_status);
+-              break;
+-      case -NFS4ERR_DELAY:
+-      case -NFS4ERR_GRACE:
++              goto out_retry;
++      case NFS4ERR_DELAY:
++              nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY);
++              fallthrough;
++      case NFS4ERR_GRACE:
+               rpc_delay(task, FF_LAYOUT_POLL_RETRY_MAX);
+-              break;
+-      case -NFS4ERR_RETRY_UNCACHED_REP:
+-              break;
++              goto out_retry;
++      case NFS4ERR_RETRY_UNCACHED_REP:
++              goto out_retry;
+       /* Invalidate Layout errors */
+-      case -NFS4ERR_PNFS_NO_LAYOUT:
+-      case -ESTALE:           /* mapped NFS4ERR_STALE */
+-      case -EBADHANDLE:       /* mapped NFS4ERR_BADHANDLE */
+-      case -EISDIR:           /* mapped NFS4ERR_ISDIR */
+-      case -NFS4ERR_FHEXPIRED:
+-      case -NFS4ERR_WRONG_TYPE:
++      case NFS4ERR_PNFS_NO_LAYOUT:
++      case NFS4ERR_STALE:
++      case NFS4ERR_BADHANDLE:
++      case NFS4ERR_ISDIR:
++      case NFS4ERR_FHEXPIRED:
++      case NFS4ERR_WRONG_TYPE:
+               dprintk("%s Invalid layout error %d\n", __func__,
+                       task->tk_status);
+               /*
+@@ -1147,6 +1158,11 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
+               pnfs_destroy_layout(NFS_I(inode));
+               rpc_wake_up(&tbl->slot_tbl_waitq);
+               goto reset;
++      default:
++              break;
++      }
++
++      switch (task->tk_status) {
+       /* RPC connection errors */
+       case -ECONNREFUSED:
+       case -EHOSTDOWN:
+@@ -1162,26 +1178,56 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
+               nfs4_delete_deviceid(devid->ld, devid->nfs_client,
+                               &devid->deviceid);
+               rpc_wake_up(&tbl->slot_tbl_waitq);
+-              fallthrough;
++              break;
+       default:
+-              if (ff_layout_avoid_mds_available_ds(lseg))
+-                      return -NFS4ERR_RESET_TO_PNFS;
+-reset:
+-              dprintk("%s Retry through MDS. Error %d\n", __func__,
+-                      task->tk_status);
+-              return -NFS4ERR_RESET_TO_MDS;
++              break;
+       }
++
++      if (ff_layout_avoid_mds_available_ds(lseg))
++              return -NFS4ERR_RESET_TO_PNFS;
++reset:
++      dprintk("%s Retry through MDS. Error %d\n", __func__,
++              task->tk_status);
++      return -NFS4ERR_RESET_TO_MDS;
++
++out_retry:
+       task->tk_status = 0;
+       return -EAGAIN;
+ }
+ /* Retry all errors through either pNFS or MDS except for -EJUKEBOX */
+ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
++                                         u32 op_status,
++                                         struct nfs_client *clp,
+                                          struct pnfs_layout_segment *lseg,
+                                          u32 idx)
+ {
+       struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx);
++      switch (op_status) {
++      case NFS_OK:
++      case NFSERR_NXIO:
++              break;
++      case NFSERR_PERM:
++              if (!task->tk_xprt)
++                      break;
++              xprt_force_disconnect(task->tk_xprt);
++              goto out_retry;
++      case NFSERR_ACCES:
++      case NFSERR_BADHANDLE:
++      case NFSERR_FBIG:
++      case NFSERR_IO:
++      case NFSERR_NOSPC:
++      case NFSERR_ROFS:
++      case NFSERR_STALE:
++              goto out_reset_to_pnfs;
++      case NFSERR_JUKEBOX:
++              nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY);
++              goto out_retry;
++      default:
++              break;
++      }
++
+       switch (task->tk_status) {
+       /* File access problems. Don't mark the device as unavailable */
+       case -EACCES:
+@@ -1200,6 +1246,7 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
+               nfs4_delete_deviceid(devid->ld, devid->nfs_client,
+                               &devid->deviceid);
+       }
++out_reset_to_pnfs:
+       /* FIXME: Need to prevent infinite looping here. */
+       return -NFS4ERR_RESET_TO_PNFS;
+ out_retry:
+@@ -1210,6 +1257,7 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task,
+ }
+ static int ff_layout_async_handle_error(struct rpc_task *task,
++                                      u32 op_status,
+                                       struct nfs4_state *state,
+                                       struct nfs_client *clp,
+                                       struct pnfs_layout_segment *lseg,
+@@ -1228,10 +1276,11 @@ static int ff_layout_async_handle_error(struct rpc_task *task,
+       switch (vers) {
+       case 3:
+-              return ff_layout_async_handle_error_v3(task, lseg, idx);
+-      case 4:
+-              return ff_layout_async_handle_error_v4(task, state, clp,
++              return ff_layout_async_handle_error_v3(task, op_status, clp,
+                                                      lseg, idx);
++      case 4:
++              return ff_layout_async_handle_error_v4(task, op_status, state,
++                                                     clp, lseg, idx);
+       default:
+               /* should never happen */
+               WARN_ON_ONCE(1);
+@@ -1284,6 +1333,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
+       switch (status) {
+       case NFS4ERR_DELAY:
+       case NFS4ERR_GRACE:
++      case NFS4ERR_PERM:
+               break;
+       case NFS4ERR_NXIO:
+               ff_layout_mark_ds_unreachable(lseg, idx);
+@@ -1316,7 +1366,8 @@ static int ff_layout_read_done_cb(struct rpc_task *task,
+               trace_ff_layout_read_error(hdr);
+       }
+-      err = ff_layout_async_handle_error(task, hdr->args.context->state,
++      err = ff_layout_async_handle_error(task, hdr->res.op_status,
++                                         hdr->args.context->state,
+                                          hdr->ds_clp, hdr->lseg,
+                                          hdr->pgio_mirror_idx);
+@@ -1483,7 +1534,8 @@ static int ff_layout_write_done_cb(struct rpc_task *task,
+               trace_ff_layout_write_error(hdr);
+       }
+-      err = ff_layout_async_handle_error(task, hdr->args.context->state,
++      err = ff_layout_async_handle_error(task, hdr->res.op_status,
++                                         hdr->args.context->state,
+                                          hdr->ds_clp, hdr->lseg,
+                                          hdr->pgio_mirror_idx);
+@@ -1529,8 +1581,9 @@ static int ff_layout_commit_done_cb(struct rpc_task *task,
+               trace_ff_layout_commit_error(data);
+       }
+-      err = ff_layout_async_handle_error(task, NULL, data->ds_clp,
+-                                         data->lseg, data->ds_commit_index);
++      err = ff_layout_async_handle_error(task, data->res.op_status,
++                                         NULL, data->ds_clp, data->lseg,
++                                         data->ds_commit_index);
+       trace_nfs4_pnfs_commit_ds(data, err);
+       switch (err) {
+-- 
+2.39.5
+
diff --git a/queue-5.15/platform-x86-dell-wmi-sysman-fix-class-device-unregi.patch b/queue-5.15/platform-x86-dell-wmi-sysman-fix-class-device-unregi.patch
new file mode 100644 (file)
index 0000000..3d7d0a9
--- /dev/null
@@ -0,0 +1,52 @@
+From c0db36591cf2117f334863bb6166b503207c9b8f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Jul 2025 15:14:51 -0400
+Subject: platform/x86: dell-wmi-sysman: Fix class device unregistration
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kurt Borja <kuurtb@gmail.com>
+
+[ Upstream commit 314e5ad4782d08858b3abc325c0487bd2abc23a1 ]
+
+Devices under the firmware_attributes_class do not have unique a dev_t.
+Therefore, device_unregister() should be used instead of
+device_destroy(), since the latter may match any device with a given
+dev_t.
+
+Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems")
+Signed-off-by: Kurt Borja <kuurtb@gmail.com>
+Link: https://lore.kernel.org/r/20250625-dest-fix-v1-3-3a0f342312bb@gmail.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/dell/dell-wmi-sysman/sysman.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
+index ab639dc8a8072..ddde6e41d8f36 100644
+--- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
++++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
+@@ -605,7 +605,7 @@ static int __init sysman_init(void)
+       release_attributes_data();
+ err_destroy_classdev:
+-      device_destroy(fw_attr_class, MKDEV(0, 0));
++      device_unregister(wmi_priv.class_dev);
+ err_unregister_class:
+       fw_attributes_class_put();
+@@ -622,7 +622,7 @@ static int __init sysman_init(void)
+ static void __exit sysman_exit(void)
+ {
+       release_attributes_data();
+-      device_destroy(fw_attr_class, MKDEV(0, 0));
++      device_unregister(wmi_priv.class_dev);
+       fw_attributes_class_put();
+       exit_bios_attr_set_interface();
+       exit_bios_attr_pass_interface();
+-- 
+2.39.5
+
diff --git a/queue-5.15/platform-x86-think-lmi-fix-class-device-unregistrati.patch b/queue-5.15/platform-x86-think-lmi-fix-class-device-unregistrati.patch
new file mode 100644 (file)
index 0000000..adadb4b
--- /dev/null
@@ -0,0 +1,52 @@
+From 5136321525127637927ca27a27b9cea1c19e0b1a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 25 Jun 2025 22:17:36 -0300
+Subject: platform/x86: think-lmi: Fix class device unregistration
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kurt Borja <kuurtb@gmail.com>
+
+[ Upstream commit 5ff1fbb3059730700b4823f43999fc1315984632 ]
+
+Devices under the firmware_attributes_class do not have unique a dev_t.
+Therefore, device_unregister() should be used instead of
+device_destroy(), since the latter may match any device with a given
+dev_t.
+
+Fixes: a40cd7ef22fb ("platform/x86: think-lmi: Add WMI interface support on Lenovo platforms")
+Signed-off-by: Kurt Borja <kuurtb@gmail.com>
+Link: https://lore.kernel.org/r/20250625-dest-fix-v1-2-3a0f342312bb@gmail.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/think-lmi.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
+index 154b1b26d03f8..462f7779daaa6 100644
+--- a/drivers/platform/x86/think-lmi.c
++++ b/drivers/platform/x86/think-lmi.c
+@@ -892,7 +892,7 @@ static int tlmi_sysfs_init(void)
+ fail_create_attr:
+       tlmi_release_attr();
+ fail_device_created:
+-      device_destroy(fw_attr_class, MKDEV(0, 0));
++      device_unregister(tlmi_priv.class_dev);
+ fail_class_created:
+       fw_attributes_class_put();
+       return ret;
+@@ -1055,7 +1055,7 @@ static int tlmi_analyze(void)
+ static void tlmi_remove(struct wmi_device *wdev)
+ {
+       tlmi_release_attr();
+-      device_destroy(fw_attr_class, MKDEV(0, 0));
++      device_unregister(tlmi_priv.class_dev);
+       fw_attributes_class_put();
+ }
+-- 
+2.39.5
+
diff --git a/queue-5.15/regulator-gpio-add-input_supply-support-in-gpio_regu.patch b/queue-5.15/regulator-gpio-add-input_supply-support-in-gpio_regu.patch
new file mode 100644 (file)
index 0000000..ea5f7b9
--- /dev/null
@@ -0,0 +1,82 @@
+From 29a5fa7b2f96ea122d1802dd2a1fae7460d95bf0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 Sep 2022 15:25:25 +0200
+Subject: regulator: gpio: Add input_supply support in gpio_regulator_config
+
+From: Jerome Neanne <jneanne@baylibre.com>
+
+[ Upstream commit adfdfcbdbd32b356323a3db6d3a683270051a7e6 ]
+
+This is simillar as fixed-regulator.
+Used to extract regulator parent from the device tree.
+
+Without that property used, the parent regulator can be shut down (if not an always on).
+Thus leading to inappropriate behavior:
+On am62-SP-SK this fix is required to avoid tps65219 ldo1 (SDMMC rail) to be shut down after boot completion.
+
+Signed-off-by: Jerome Neanne <jneanne@baylibre.com>
+Link: https://lore.kernel.org/r/20220929132526.29427-2-jneanne@baylibre.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: c9764fd88bc7 ("regulator: gpio: Fix the out-of-bounds access to drvdata::gpiods")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/regulator/gpio-regulator.c       | 15 +++++++++++++++
+ include/linux/regulator/gpio-regulator.h |  2 ++
+ 2 files changed, 17 insertions(+)
+
+diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
+index 5927d4f3eabd7..95e61a2f43f5d 100644
+--- a/drivers/regulator/gpio-regulator.c
++++ b/drivers/regulator/gpio-regulator.c
+@@ -220,6 +220,9 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np,
+                                regtype);
+       }
++      if (of_find_property(np, "vin-supply", NULL))
++              config->input_supply = "vin";
++
+       return config;
+ }
+@@ -259,6 +262,18 @@ static int gpio_regulator_probe(struct platform_device *pdev)
+       drvdata->gpiods = devm_kzalloc(dev, sizeof(struct gpio_desc *),
+                                      GFP_KERNEL);
++
++      if (config->input_supply) {
++              drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
++                                                       config->input_supply,
++                                                       GFP_KERNEL);
++              if (!drvdata->desc.supply_name) {
++                      dev_err(&pdev->dev,
++                              "Failed to allocate input supply\n");
++                      return -ENOMEM;
++              }
++      }
++
+       if (!drvdata->gpiods)
+               return -ENOMEM;
+       for (i = 0; i < config->ngpios; i++) {
+diff --git a/include/linux/regulator/gpio-regulator.h b/include/linux/regulator/gpio-regulator.h
+index fdeb312cdabdf..c223e50ff9f78 100644
+--- a/include/linux/regulator/gpio-regulator.h
++++ b/include/linux/regulator/gpio-regulator.h
+@@ -42,6 +42,7 @@ struct gpio_regulator_state {
+ /**
+  * struct gpio_regulator_config - config structure
+  * @supply_name:      Name of the regulator supply
++ * @input_supply:     Name of the input regulator supply
+  * @enabled_at_boot:  Whether regulator has been enabled at
+  *                    boot or not. 1 = Yes, 0 = No
+  *                    This is used to keep the regulator at
+@@ -62,6 +63,7 @@ struct gpio_regulator_state {
+  */
+ struct gpio_regulator_config {
+       const char *supply_name;
++      const char *input_supply;
+       unsigned enabled_at_boot:1;
+       unsigned startup_delay;
+-- 
+2.39.5
+
diff --git a/queue-5.15/regulator-gpio-fix-the-out-of-bounds-access-to-drvda.patch b/queue-5.15/regulator-gpio-fix-the-out-of-bounds-access-to-drvda.patch
new file mode 100644 (file)
index 0000000..518c8f3
--- /dev/null
@@ -0,0 +1,57 @@
+From bcabbcdc1991b3d14e2827cb2647ae62275bf2d1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 3 Jul 2025 16:05:49 +0530
+Subject: regulator: gpio: Fix the out-of-bounds access to drvdata::gpiods
+
+From: Manivannan Sadhasivam <mani@kernel.org>
+
+[ Upstream commit c9764fd88bc744592b0604ccb6b6fc1a5f76b4e3 ]
+
+drvdata::gpiods is supposed to hold an array of 'gpio_desc' pointers. But
+the memory is allocated for only one pointer. This will lead to
+out-of-bounds access later in the code if 'config::ngpios' is > 1. So
+fix the code to allocate enough memory to hold 'config::ngpios' of GPIO
+descriptors.
+
+While at it, also move the check for memory allocation failure to be below
+the allocation to make it more readable.
+
+Cc: stable@vger.kernel.org # 5.0
+Fixes: d6cd33ad7102 ("regulator: gpio: Convert to use descriptors")
+Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
+Link: https://patch.msgid.link/20250703103549.16558-1-mani@kernel.org
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/regulator/gpio-regulator.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
+index 95e61a2f43f5d..b34671eb49b52 100644
+--- a/drivers/regulator/gpio-regulator.c
++++ b/drivers/regulator/gpio-regulator.c
+@@ -260,8 +260,10 @@ static int gpio_regulator_probe(struct platform_device *pdev)
+               return -ENOMEM;
+       }
+-      drvdata->gpiods = devm_kzalloc(dev, sizeof(struct gpio_desc *),
+-                                     GFP_KERNEL);
++      drvdata->gpiods = devm_kcalloc(dev, config->ngpios,
++                                     sizeof(struct gpio_desc *), GFP_KERNEL);
++      if (!drvdata->gpiods)
++              return -ENOMEM;
+       if (config->input_supply) {
+               drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
+@@ -274,8 +276,6 @@ static int gpio_regulator_probe(struct platform_device *pdev)
+               }
+       }
+-      if (!drvdata->gpiods)
+-              return -ENOMEM;
+       for (i = 0; i < config->ngpios; i++) {
+               drvdata->gpiods[i] = devm_gpiod_get_index(dev,
+                                                         NULL,
+-- 
+2.39.5
+
index 8008a6d48fce2e807af33d0f36cdf10c65438a30..cf49673e0a65a0f03f7d886dff3d7cdce7baa20f 100644 (file)
@@ -134,3 +134,20 @@ wifi-ath6kl-remove-warn-on-bad-firmware-input.patch
 acpica-refuse-to-evaluate-a-method-if-arguments-are-.patch
 mtd-spinand-fix-memory-leak-of-ecc-engine-conf.patch
 rcu-return-early-if-callback-is-not-specified.patch
+mmc-core-sd-apply-broken_sd_discard-quirk-earlier.patch
+regulator-gpio-add-input_supply-support-in-gpio_regu.patch
+regulator-gpio-fix-the-out-of-bounds-access-to-drvda.patch
+drm-v3d-disable-interrupts-before-resetting-the-gpu.patch
+nfsv4-flexfiles-fix-handling-of-nfs-level-errors-in-.patch
+btrfs-remove-noinline-from-btrfs_update_inode.patch
+btrfs-remove-redundant-root-argument-from-fixup_inod.patch
+btrfs-fix-inode-lookup-error-handling-during-log-rep.patch
+btrfs-propagate-last_unlink_trans-earlier-when-doing.patch
+btrfs-use-btrfs_record_snapshot_destroy-during-rmdir.patch
+ethernet-atl1-add-missing-dma-mapping-error-checks-a.patch
+dpaa2-eth-update-dpni_get_single_step_cfg-command.patch
+dpaa2-eth-update-single_step-register-access.patch
+net-dpaa2-eth-rearrange-variable-in-dpaa2_eth_get_et.patch
+dpaa2-eth-fix-xdp_rxq_info-leak.patch
+platform-x86-think-lmi-fix-class-device-unregistrati.patch
+platform-x86-dell-wmi-sysman-fix-class-device-unregi.patch