]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Fri, 28 Feb 2025 04:41:23 +0000 (23:41 -0500)
committerSasha Levin <sashal@kernel.org>
Fri, 28 Feb 2025 04:41:23 +0000 (23:41 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.15/ib-mlx5-set-and-get-correct-qp_num-for-a-dct-qp.patch [new file with mode: 0644]
queue-5.15/ovl-fix-uaf-in-ovl_dentry_update_reval-by-moving-dpu.patch [new file with mode: 0644]
queue-5.15/ovl-pass-ofs-to-creation-operations.patch [new file with mode: 0644]
queue-5.15/ovl-use-wrappers-to-all-vfs_-xattr-calls.patch [new file with mode: 0644]
queue-5.15/rdma-mlx5-fix-bind-qp-error-cleanup-flow.patch [new file with mode: 0644]
queue-5.15/scsi-core-clear-driver-private-data-when-retrying-re.patch [new file with mode: 0644]
queue-5.15/scsi-core-don-t-memset-the-entire-scsi_cmnd-in-scsi_.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/sunrpc-suppress-warnings-for-unused-procfs-functions.patch [new file with mode: 0644]

diff --git a/queue-5.15/ib-mlx5-set-and-get-correct-qp_num-for-a-dct-qp.patch b/queue-5.15/ib-mlx5-set-and-get-correct-qp_num-for-a-dct-qp.patch
new file mode 100644 (file)
index 0000000..7769c2a
--- /dev/null
@@ -0,0 +1,50 @@
+From 32c05d58b1efaf02576efd954028712c1c6d9266 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jan 2025 14:39:46 +0200
+Subject: IB/mlx5: Set and get correct qp_num for a DCT QP
+
+From: Mark Zhang <markzhang@nvidia.com>
+
+[ Upstream commit 12d044770e12c4205fa69535b4fa8a9981fea98f ]
+
+When a DCT QP is created on an active lag, it's dctc.port is assigned
+in a round-robin way, which is from 1 to dev->lag_port. In this case
+when querying this QP, we may get qp_attr.port_num > 2.
+Fix this by setting qp->port when modifying a DCT QP, and read port_num
+from qp->port instead of dctc.port when querying it.
+
+Fixes: 7c4b1ab9f167 ("IB/mlx5: Add DCT RoCE LAG support")
+Signed-off-by: Mark Zhang <markzhang@nvidia.com>
+Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
+Link: https://patch.msgid.link/94c76bf0adbea997f87ffa27674e0a7118ad92a9.1737290358.git.leon@kernel.org
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/hw/mlx5/qp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
+index d2b4db783b254..d58ed4a09cd93 100644
+--- a/drivers/infiniband/hw/mlx5/qp.c
++++ b/drivers/infiniband/hw/mlx5/qp.c
+@@ -4461,6 +4461,8 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+               set_id = mlx5_ib_get_counters_id(dev, attr->port_num - 1);
+               MLX5_SET(dctc, dctc, counter_set_id, set_id);
++
++              qp->port = attr->port_num;
+       } else if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
+               struct mlx5_ib_modify_qp_resp resp = {};
+               u32 out[MLX5_ST_SZ_DW(create_dct_out)] = {};
+@@ -4949,7 +4951,7 @@ static int mlx5_ib_dct_query_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *mqp,
+       }
+       if (qp_attr_mask & IB_QP_PORT)
+-              qp_attr->port_num = MLX5_GET(dctc, dctc, port);
++              qp_attr->port_num = mqp->port;
+       if (qp_attr_mask & IB_QP_MIN_RNR_TIMER)
+               qp_attr->min_rnr_timer = MLX5_GET(dctc, dctc, min_rnr_nak);
+       if (qp_attr_mask & IB_QP_AV) {
+-- 
+2.39.5
+
diff --git a/queue-5.15/ovl-fix-uaf-in-ovl_dentry_update_reval-by-moving-dpu.patch b/queue-5.15/ovl-fix-uaf-in-ovl_dentry_update_reval-by-moving-dpu.patch
new file mode 100644 (file)
index 0000000..3b37944
--- /dev/null
@@ -0,0 +1,71 @@
+From 8dec2b20fa70493d01edc457f87aab3b9f18aaca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 15 Feb 2025 00:51:48 +0300
+Subject: ovl: fix UAF in ovl_dentry_update_reval by moving dput() in
+ ovl_link_up
+
+From: Vasiliy Kovalev <kovalev@altlinux.org>
+
+[ Upstream commit c84e125fff2615b4d9c259e762596134eddd2f27 ]
+
+The issue was caused by dput(upper) being called before
+ovl_dentry_update_reval(), while upper->d_flags was still
+accessed in ovl_dentry_remote().
+
+Move dput(upper) after its last use to prevent use-after-free.
+
+BUG: KASAN: slab-use-after-free in ovl_dentry_remote fs/overlayfs/util.c:162 [inline]
+BUG: KASAN: slab-use-after-free in ovl_dentry_update_reval+0xd2/0xf0 fs/overlayfs/util.c:167
+
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:88 [inline]
+ dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:114
+ print_address_description mm/kasan/report.c:377 [inline]
+ print_report+0xc3/0x620 mm/kasan/report.c:488
+ kasan_report+0xd9/0x110 mm/kasan/report.c:601
+ ovl_dentry_remote fs/overlayfs/util.c:162 [inline]
+ ovl_dentry_update_reval+0xd2/0xf0 fs/overlayfs/util.c:167
+ ovl_link_up fs/overlayfs/copy_up.c:610 [inline]
+ ovl_copy_up_one+0x2105/0x3490 fs/overlayfs/copy_up.c:1170
+ ovl_copy_up_flags+0x18d/0x200 fs/overlayfs/copy_up.c:1223
+ ovl_rename+0x39e/0x18c0 fs/overlayfs/dir.c:1136
+ vfs_rename+0xf84/0x20a0 fs/namei.c:4893
+...
+ </TASK>
+
+Fixes: b07d5cc93e1b ("ovl: update of dentry revalidate flags after copy up")
+Reported-by: syzbot+316db8a1191938280eb6@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=316db8a1191938280eb6
+Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org>
+Link: https://lore.kernel.org/r/20250214215148.761147-1-kovalev@altlinux.org
+Reviewed-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/overlayfs/copy_up.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index 205238c73dbc5..5fc32483afed8 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -537,7 +537,6 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
+       err = PTR_ERR(upper);
+       if (!IS_ERR(upper)) {
+               err = ovl_do_link(ofs, ovl_dentry_upper(c->dentry), udir, upper);
+-              dput(upper);
+               if (!err) {
+                       /* Restore timestamps on parent (best effort) */
+@@ -545,6 +544,7 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
+                       ovl_dentry_set_upper_alias(c->dentry);
+                       ovl_dentry_update_reval(c->dentry, upper);
+               }
++              dput(upper);
+       }
+       inode_unlock(udir);
+       if (err)
+-- 
+2.39.5
+
diff --git a/queue-5.15/ovl-pass-ofs-to-creation-operations.patch b/queue-5.15/ovl-pass-ofs-to-creation-operations.patch
new file mode 100644 (file)
index 0000000..dc38b2a
--- /dev/null
@@ -0,0 +1,815 @@
+From 37979f156d697a7a89ee79d406457e512e5f4ba9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Apr 2022 12:51:43 +0200
+Subject: ovl: pass ofs to creation operations
+
+From: Christian Brauner <brauner@kernel.org>
+
+[ Upstream commit 576bb263450bbba6601a9f528d0cf601d97a13e6 ]
+
+Pass down struct ovl_fs to all creation helpers so we can ultimately
+retrieve the relevant upper mount and take the mount's idmapping into
+account when creating new filesystem objects. This is needed to support
+idmapped base layers with overlay.
+
+Cc: <linux-unionfs@vger.kernel.org>
+Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
+Reviewed-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Stable-dep-of: c84e125fff26 ("ovl: fix UAF in ovl_dentry_update_reval by moving dput() in ovl_link_up")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/overlayfs/copy_up.c   | 21 +++++-----
+ fs/overlayfs/dir.c       | 85 +++++++++++++++++++++-------------------
+ fs/overlayfs/overlayfs.h | 54 +++++++++++++++----------
+ fs/overlayfs/readdir.c   | 28 +++++++------
+ fs/overlayfs/super.c     | 28 +++++++------
+ fs/overlayfs/util.c      |  2 +-
+ 6 files changed, 121 insertions(+), 97 deletions(-)
+
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index 80e7ae8152fdd..205238c73dbc5 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -474,7 +474,7 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
+       if (err)
+               return err;
+-      temp = ovl_create_temp(indexdir, OVL_CATTR(S_IFDIR | 0));
++      temp = ovl_create_temp(ofs, indexdir, OVL_CATTR(S_IFDIR | 0));
+       err = PTR_ERR(temp);
+       if (IS_ERR(temp))
+               goto free_name;
+@@ -487,12 +487,12 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
+       if (IS_ERR(index)) {
+               err = PTR_ERR(index);
+       } else {
+-              err = ovl_do_rename(dir, temp, dir, index, 0);
++              err = ovl_do_rename(ofs, dir, temp, dir, index, 0);
+               dput(index);
+       }
+ out:
+       if (err)
+-              ovl_cleanup(dir, temp);
++              ovl_cleanup(ofs, dir, temp);
+       dput(temp);
+ free_name:
+       kfree(name.name);
+@@ -519,6 +519,7 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
+       int err;
+       struct dentry *upper;
+       struct dentry *upperdir = ovl_dentry_upper(c->parent);
++      struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+       struct inode *udir = d_inode(upperdir);
+       /* Mark parent "impure" because it may now contain non-pure upper */
+@@ -535,7 +536,7 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
+                              c->dentry->d_name.len);
+       err = PTR_ERR(upper);
+       if (!IS_ERR(upper)) {
+-              err = ovl_do_link(ovl_dentry_upper(c->dentry), udir, upper);
++              err = ovl_do_link(ofs, ovl_dentry_upper(c->dentry), udir, upper);
+               dput(upper);
+               if (!err) {
+@@ -658,6 +659,7 @@ static void ovl_revert_cu_creds(struct ovl_cu_creds *cc)
+  */
+ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
+ {
++      struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+       struct inode *inode;
+       struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir);
+       struct dentry *temp, *upper;
+@@ -679,7 +681,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
+       if (err)
+               goto unlock;
+-      temp = ovl_create_temp(c->workdir, &cattr);
++      temp = ovl_create_temp(ofs, c->workdir, &cattr);
+       ovl_revert_cu_creds(&cc);
+       err = PTR_ERR(temp);
+@@ -701,7 +703,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
+       if (IS_ERR(upper))
+               goto cleanup;
+-      err = ovl_do_rename(wdir, temp, udir, upper, 0);
++      err = ovl_do_rename(ofs, wdir, temp, udir, upper, 0);
+       dput(upper);
+       if (err)
+               goto cleanup;
+@@ -718,7 +720,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
+       return err;
+ cleanup:
+-      ovl_cleanup(wdir, temp);
++      ovl_cleanup(ofs, wdir, temp);
+       dput(temp);
+       goto unlock;
+ }
+@@ -726,6 +728,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
+ /* Copyup using O_TMPFILE which does not require cross dir locking */
+ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+ {
++      struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+       struct inode *udir = d_inode(c->destdir);
+       struct dentry *temp, *upper;
+       struct ovl_cu_creds cc;
+@@ -735,7 +738,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+       if (err)
+               return err;
+-      temp = ovl_do_tmpfile(c->workdir, c->stat.mode);
++      temp = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
+       ovl_revert_cu_creds(&cc);
+       if (IS_ERR(temp))
+@@ -750,7 +753,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+       upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len);
+       err = PTR_ERR(upper);
+       if (!IS_ERR(upper)) {
+-              err = ovl_do_link(temp, udir, upper);
++              err = ovl_do_link(ofs, temp, udir, upper);
+               dput(upper);
+       }
+       inode_unlock(udir);
+diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
+index 5e9005a0afaad..584b78f0bfa1a 100644
+--- a/fs/overlayfs/dir.c
++++ b/fs/overlayfs/dir.c
+@@ -23,15 +23,15 @@ MODULE_PARM_DESC(redirect_max,
+ static int ovl_set_redirect(struct dentry *dentry, bool samedir);
+-int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
++int ovl_cleanup(struct ovl_fs *ofs, struct inode *wdir, struct dentry *wdentry)
+ {
+       int err;
+       dget(wdentry);
+       if (d_is_dir(wdentry))
+-              err = ovl_do_rmdir(wdir, wdentry);
++              err = ovl_do_rmdir(ofs, wdir, wdentry);
+       else
+-              err = ovl_do_unlink(wdir, wdentry);
++              err = ovl_do_unlink(ofs, wdir, wdentry);
+       dput(wdentry);
+       if (err) {
+@@ -42,7 +42,7 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
+       return err;
+ }
+-struct dentry *ovl_lookup_temp(struct dentry *workdir)
++struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir)
+ {
+       struct dentry *temp;
+       char name[20];
+@@ -70,11 +70,11 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
+       struct inode *wdir = workdir->d_inode;
+       if (!ofs->whiteout) {
+-              whiteout = ovl_lookup_temp(workdir);
++              whiteout = ovl_lookup_temp(ofs, workdir);
+               if (IS_ERR(whiteout))
+                       goto out;
+-              err = ovl_do_whiteout(wdir, whiteout);
++              err = ovl_do_whiteout(ofs, wdir, whiteout);
+               if (err) {
+                       dput(whiteout);
+                       whiteout = ERR_PTR(err);
+@@ -84,11 +84,11 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
+       }
+       if (ofs->share_whiteout) {
+-              whiteout = ovl_lookup_temp(workdir);
++              whiteout = ovl_lookup_temp(ofs, workdir);
+               if (IS_ERR(whiteout))
+                       goto out;
+-              err = ovl_do_link(ofs->whiteout, wdir, whiteout);
++              err = ovl_do_link(ofs, ofs->whiteout, wdir, whiteout);
+               if (!err)
+                       goto out;
+@@ -122,27 +122,28 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
+       if (d_is_dir(dentry))
+               flags = RENAME_EXCHANGE;
+-      err = ovl_do_rename(wdir, whiteout, dir, dentry, flags);
++      err = ovl_do_rename(ofs, wdir, whiteout, dir, dentry, flags);
+       if (err)
+               goto kill_whiteout;
+       if (flags)
+-              ovl_cleanup(wdir, dentry);
++              ovl_cleanup(ofs, wdir, dentry);
+ out:
+       dput(whiteout);
+       return err;
+ kill_whiteout:
+-      ovl_cleanup(wdir, whiteout);
++      ovl_cleanup(ofs, wdir, whiteout);
+       goto out;
+ }
+-int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode)
++int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir,
++                 struct dentry **newdentry, umode_t mode)
+ {
+       int err;
+       struct dentry *d, *dentry = *newdentry;
+-      err = ovl_do_mkdir(dir, dentry, mode);
++      err = ovl_do_mkdir(ofs, dir, dentry, mode);
+       if (err)
+               return err;
+@@ -167,8 +168,8 @@ int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode)
+       return 0;
+ }
+-struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
+-                             struct ovl_cattr *attr)
++struct dentry *ovl_create_real(struct ovl_fs *ofs, struct inode *dir,
++                             struct dentry *newdentry, struct ovl_cattr *attr)
+ {
+       int err;
+@@ -180,28 +181,28 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
+               goto out;
+       if (attr->hardlink) {
+-              err = ovl_do_link(attr->hardlink, dir, newdentry);
++              err = ovl_do_link(ofs, attr->hardlink, dir, newdentry);
+       } else {
+               switch (attr->mode & S_IFMT) {
+               case S_IFREG:
+-                      err = ovl_do_create(dir, newdentry, attr->mode);
++                      err = ovl_do_create(ofs, dir, newdentry, attr->mode);
+                       break;
+               case S_IFDIR:
+                       /* mkdir is special... */
+-                      err =  ovl_mkdir_real(dir, &newdentry, attr->mode);
++                      err =  ovl_mkdir_real(ofs, dir, &newdentry, attr->mode);
+                       break;
+               case S_IFCHR:
+               case S_IFBLK:
+               case S_IFIFO:
+               case S_IFSOCK:
+-                      err = ovl_do_mknod(dir, newdentry, attr->mode,
++                      err = ovl_do_mknod(ofs, dir, newdentry, attr->mode,
+                                          attr->rdev);
+                       break;
+               case S_IFLNK:
+-                      err = ovl_do_symlink(dir, newdentry, attr->link);
++                      err = ovl_do_symlink(ofs, dir, newdentry, attr->link);
+                       break;
+               default:
+@@ -223,10 +224,11 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
+       return newdentry;
+ }
+-struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr)
++struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
++                             struct ovl_cattr *attr)
+ {
+-      return ovl_create_real(d_inode(workdir), ovl_lookup_temp(workdir),
+-                             attr);
++      return ovl_create_real(ofs, d_inode(workdir),
++                             ovl_lookup_temp(ofs, workdir), attr);
+ }
+ static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper,
+@@ -329,7 +331,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
+               attr->mode &= ~current_umask();
+       inode_lock_nested(udir, I_MUTEX_PARENT);
+-      newdentry = ovl_create_real(udir,
++      newdentry = ovl_create_real(ofs, udir,
+                                   lookup_one_len(dentry->d_name.name,
+                                                  upperdir,
+                                                  dentry->d_name.len),
+@@ -352,7 +354,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
+       return err;
+ out_cleanup:
+-      ovl_cleanup(udir, newdentry);
++      ovl_cleanup(ofs, udir, newdentry);
+       dput(newdentry);
+       goto out_unlock;
+ }
+@@ -360,6 +362,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
+ static struct dentry *ovl_clear_empty(struct dentry *dentry,
+                                     struct list_head *list)
+ {
++      struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+       struct dentry *workdir = ovl_workdir(dentry);
+       struct inode *wdir = workdir->d_inode;
+       struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
+@@ -390,7 +393,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
+       if (upper->d_parent->d_inode != udir)
+               goto out_unlock;
+-      opaquedir = ovl_create_temp(workdir, OVL_CATTR(stat.mode));
++      opaquedir = ovl_create_temp(ofs, workdir, OVL_CATTR(stat.mode));
+       err = PTR_ERR(opaquedir);
+       if (IS_ERR(opaquedir))
+               goto out_unlock;
+@@ -409,12 +412,12 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
+       if (err)
+               goto out_cleanup;
+-      err = ovl_do_rename(wdir, opaquedir, udir, upper, RENAME_EXCHANGE);
++      err = ovl_do_rename(ofs, wdir, opaquedir, udir, upper, RENAME_EXCHANGE);
+       if (err)
+               goto out_cleanup;
+-      ovl_cleanup_whiteouts(upper, list);
+-      ovl_cleanup(wdir, upper);
++      ovl_cleanup_whiteouts(ofs, upper, list);
++      ovl_cleanup(ofs, wdir, upper);
+       unlock_rename(workdir, upperdir);
+       /* dentry's upper doesn't match now, get rid of it */
+@@ -423,7 +426,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
+       return opaquedir;
+ out_cleanup:
+-      ovl_cleanup(wdir, opaquedir);
++      ovl_cleanup(ofs, wdir, opaquedir);
+       dput(opaquedir);
+ out_unlock:
+       unlock_rename(workdir, upperdir);
+@@ -494,7 +497,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
+       if (d_is_negative(upper) || !IS_WHITEOUT(d_inode(upper)))
+               goto out_dput;
+-      newdentry = ovl_create_temp(workdir, cattr);
++      newdentry = ovl_create_temp(ofs, workdir, cattr);
+       err = PTR_ERR(newdentry);
+       if (IS_ERR(newdentry))
+               goto out_dput;
+@@ -532,20 +535,20 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
+               if (err)
+                       goto out_cleanup;
+-              err = ovl_do_rename(wdir, newdentry, udir, upper,
++              err = ovl_do_rename(ofs, wdir, newdentry, udir, upper,
+                                   RENAME_EXCHANGE);
+               if (err)
+                       goto out_cleanup;
+-              ovl_cleanup(wdir, upper);
++              ovl_cleanup(ofs, wdir, upper);
+       } else {
+-              err = ovl_do_rename(wdir, newdentry, udir, upper, 0);
++              err = ovl_do_rename(ofs, wdir, newdentry, udir, upper, 0);
+               if (err)
+                       goto out_cleanup;
+       }
+       err = ovl_instantiate(dentry, inode, newdentry, hardlink);
+       if (err) {
+-              ovl_cleanup(udir, newdentry);
++              ovl_cleanup(ofs, udir, newdentry);
+               dput(newdentry);
+       }
+ out_dput:
+@@ -560,7 +563,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
+       return err;
+ out_cleanup:
+-      ovl_cleanup(wdir, newdentry);
++      ovl_cleanup(ofs, wdir, newdentry);
+       dput(newdentry);
+       goto out_dput;
+ }
+@@ -814,6 +817,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
+ static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
+                           struct list_head *list)
+ {
++      struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+       struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
+       struct inode *dir = upperdir->d_inode;
+       struct dentry *upper;
+@@ -840,9 +844,9 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
+               goto out_dput_upper;
+       if (is_dir)
+-              err = vfs_rmdir(&init_user_ns, dir, upper);
++              err = ovl_do_rmdir(ofs, dir, upper);
+       else
+-              err = vfs_unlink(&init_user_ns, dir, upper, NULL);
++              err = ovl_do_unlink(ofs, dir, upper);
+       ovl_dir_modified(dentry->d_parent, ovl_type_origin(dentry));
+       /*
+@@ -1107,6 +1111,7 @@ static int ovl_rename(struct user_namespace *mnt_userns, struct inode *olddir,
+       bool samedir = olddir == newdir;
+       struct dentry *opaquedir = NULL;
+       const struct cred *old_cred = NULL;
++      struct ovl_fs *ofs = OVL_FS(old->d_sb);
+       LIST_HEAD(list);
+       err = -EINVAL;
+@@ -1263,13 +1268,13 @@ static int ovl_rename(struct user_namespace *mnt_userns, struct inode *olddir,
+       if (err)
+               goto out_dput;
+-      err = ovl_do_rename(old_upperdir->d_inode, olddentry,
++      err = ovl_do_rename(ofs, old_upperdir->d_inode, olddentry,
+                           new_upperdir->d_inode, newdentry, flags);
+       if (err)
+               goto out_dput;
+       if (cleanup_whiteout)
+-              ovl_cleanup(old_upperdir->d_inode, newdentry);
++              ovl_cleanup(ofs, old_upperdir->d_inode, newdentry);
+       if (overwrite && d_inode(new)) {
+               if (new_is_dir)
+diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
+index 3f4655b9c71ca..43b211cf437cc 100644
+--- a/fs/overlayfs/overlayfs.h
++++ b/fs/overlayfs/overlayfs.h
+@@ -122,7 +122,8 @@ static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox)
+       return ovl_xattr_table[ox][ofs->config.userxattr];
+ }
+-static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
++static inline int ovl_do_rmdir(struct ovl_fs *ofs,
++                             struct inode *dir, struct dentry *dentry)
+ {
+       int err = vfs_rmdir(&init_user_ns, dir, dentry);
+@@ -130,7 +131,8 @@ static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
+       return err;
+ }
+-static inline int ovl_do_unlink(struct inode *dir, struct dentry *dentry)
++static inline int ovl_do_unlink(struct ovl_fs *ofs, struct inode *dir,
++                              struct dentry *dentry)
+ {
+       int err = vfs_unlink(&init_user_ns, dir, dentry, NULL);
+@@ -138,8 +140,8 @@ static inline int ovl_do_unlink(struct inode *dir, struct dentry *dentry)
+       return err;
+ }
+-static inline int ovl_do_link(struct dentry *old_dentry, struct inode *dir,
+-                            struct dentry *new_dentry)
++static inline int ovl_do_link(struct ovl_fs *ofs, struct dentry *old_dentry,
++                            struct inode *dir, struct dentry *new_dentry)
+ {
+       int err = vfs_link(old_dentry, &init_user_ns, dir, new_dentry, NULL);
+@@ -147,7 +149,8 @@ static inline int ovl_do_link(struct dentry *old_dentry, struct inode *dir,
+       return err;
+ }
+-static inline int ovl_do_create(struct inode *dir, struct dentry *dentry,
++static inline int ovl_do_create(struct ovl_fs *ofs,
++                              struct inode *dir, struct dentry *dentry,
+                               umode_t mode)
+ {
+       int err = vfs_create(&init_user_ns, dir, dentry, mode, true);
+@@ -156,7 +159,8 @@ static inline int ovl_do_create(struct inode *dir, struct dentry *dentry,
+       return err;
+ }
+-static inline int ovl_do_mkdir(struct inode *dir, struct dentry *dentry,
++static inline int ovl_do_mkdir(struct ovl_fs *ofs,
++                             struct inode *dir, struct dentry *dentry,
+                              umode_t mode)
+ {
+       int err = vfs_mkdir(&init_user_ns, dir, dentry, mode);
+@@ -164,7 +168,8 @@ static inline int ovl_do_mkdir(struct inode *dir, struct dentry *dentry,
+       return err;
+ }
+-static inline int ovl_do_mknod(struct inode *dir, struct dentry *dentry,
++static inline int ovl_do_mknod(struct ovl_fs *ofs,
++                             struct inode *dir, struct dentry *dentry,
+                              umode_t mode, dev_t dev)
+ {
+       int err = vfs_mknod(&init_user_ns, dir, dentry, mode, dev);
+@@ -173,7 +178,8 @@ static inline int ovl_do_mknod(struct inode *dir, struct dentry *dentry,
+       return err;
+ }
+-static inline int ovl_do_symlink(struct inode *dir, struct dentry *dentry,
++static inline int ovl_do_symlink(struct ovl_fs *ofs,
++                               struct inode *dir, struct dentry *dentry,
+                                const char *oldname)
+ {
+       int err = vfs_symlink(&init_user_ns, dir, dentry, oldname);
+@@ -233,9 +239,9 @@ static inline int ovl_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
+       return ovl_do_removexattr(ofs, dentry, ovl_xattr(ofs, ox));
+ }
+-static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
+-                              struct inode *newdir, struct dentry *newdentry,
+-                              unsigned int flags)
++static inline int ovl_do_rename(struct ovl_fs *ofs, struct inode *olddir,
++                              struct dentry *olddentry, struct inode *newdir,
++                              struct dentry *newdentry, unsigned int flags)
+ {
+       int err;
+       struct renamedata rd = {
+@@ -257,14 +263,16 @@ static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
+       return err;
+ }
+-static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
++static inline int ovl_do_whiteout(struct ovl_fs *ofs,
++                                struct inode *dir, struct dentry *dentry)
+ {
+       int err = vfs_whiteout(&init_user_ns, dir, dentry);
+       pr_debug("whiteout(%pd2) = %i\n", dentry, err);
+       return err;
+ }
+-static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
++static inline struct dentry *ovl_do_tmpfile(struct ovl_fs *ofs,
++                                          struct dentry *dentry, umode_t mode)
+ {
+       struct dentry *ret = vfs_tmpfile(&init_user_ns, dentry, mode, 0);
+       int err = PTR_ERR_OR_ZERO(ret);
+@@ -483,12 +491,13 @@ static inline int ovl_verify_upper(struct ovl_fs *ofs, struct dentry *index,
+ extern const struct file_operations ovl_dir_operations;
+ struct file *ovl_dir_real_file(const struct file *file, bool want_upper);
+ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
+-void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
++void ovl_cleanup_whiteouts(struct ovl_fs *ofs, struct dentry *upper,
++                         struct list_head *list);
+ void ovl_cache_free(struct list_head *list);
+ void ovl_dir_cache_free(struct inode *inode);
+ int ovl_check_d_type_supported(struct path *realpath);
+-int ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
+-                      struct dentry *dentry, int level);
++int ovl_workdir_cleanup(struct ovl_fs *ofs, struct inode *dir,
++                      struct vfsmount *mnt, struct dentry *dentry, int level);
+ int ovl_indexdir_cleanup(struct ovl_fs *ofs);
+ /*
+@@ -583,12 +592,15 @@ struct ovl_cattr {
+ #define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) })
+-int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry, umode_t mode);
+-struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
++int ovl_mkdir_real(struct ovl_fs *ofs, struct inode *dir,
++                 struct dentry **newdentry, umode_t mode);
++struct dentry *ovl_create_real(struct ovl_fs *ofs,
++                             struct inode *dir, struct dentry *newdentry,
++                             struct ovl_cattr *attr);
++int ovl_cleanup(struct ovl_fs *ofs, struct inode *dir, struct dentry *dentry);
++struct dentry *ovl_lookup_temp(struct ovl_fs *ofs, struct dentry *workdir);
++struct dentry *ovl_create_temp(struct ovl_fs *ofs, struct dentry *workdir,
+                              struct ovl_cattr *attr);
+-int ovl_cleanup(struct inode *dir, struct dentry *dentry);
+-struct dentry *ovl_lookup_temp(struct dentry *workdir);
+-struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr);
+ /* file.c */
+ extern const struct file_operations ovl_file_operations;
+diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
+index c7b542331065c..9c580ef8cd6fc 100644
+--- a/fs/overlayfs/readdir.c
++++ b/fs/overlayfs/readdir.c
+@@ -1001,7 +1001,8 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
+       return err;
+ }
+-void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
++void ovl_cleanup_whiteouts(struct ovl_fs *ofs, struct dentry *upper,
++                         struct list_head *list)
+ {
+       struct ovl_cache_entry *p;
+@@ -1020,7 +1021,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
+                       continue;
+               }
+               if (dentry->d_inode)
+-                      ovl_cleanup(upper->d_inode, dentry);
++                      ovl_cleanup(ofs, upper->d_inode, dentry);
+               dput(dentry);
+       }
+       inode_unlock(upper->d_inode);
+@@ -1064,7 +1065,8 @@ int ovl_check_d_type_supported(struct path *realpath)
+ #define OVL_INCOMPATDIR_NAME "incompat"
+-static int ovl_workdir_cleanup_recurse(struct path *path, int level)
++static int ovl_workdir_cleanup_recurse(struct ovl_fs *ofs, struct path *path,
++                                     int level)
+ {
+       int err;
+       struct inode *dir = path->dentry->d_inode;
+@@ -1115,7 +1117,7 @@ static int ovl_workdir_cleanup_recurse(struct path *path, int level)
+               if (IS_ERR(dentry))
+                       continue;
+               if (dentry->d_inode)
+-                      err = ovl_workdir_cleanup(dir, path->mnt, dentry, level);
++                      err = ovl_workdir_cleanup(ofs, dir, path->mnt, dentry, level);
+               dput(dentry);
+               if (err)
+                       break;
+@@ -1126,24 +1128,24 @@ static int ovl_workdir_cleanup_recurse(struct path *path, int level)
+       return err;
+ }
+-int ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
+-                       struct dentry *dentry, int level)
++int ovl_workdir_cleanup(struct ovl_fs *ofs, struct inode *dir,
++                      struct vfsmount *mnt, struct dentry *dentry, int level)
+ {
+       int err;
+       if (!d_is_dir(dentry) || level > 1) {
+-              return ovl_cleanup(dir, dentry);
++              return ovl_cleanup(ofs, dir, dentry);
+       }
+-      err = ovl_do_rmdir(dir, dentry);
++      err = ovl_do_rmdir(ofs, dir, dentry);
+       if (err) {
+               struct path path = { .mnt = mnt, .dentry = dentry };
+               inode_unlock(dir);
+-              err = ovl_workdir_cleanup_recurse(&path, level + 1);
++              err = ovl_workdir_cleanup_recurse(ofs, &path, level + 1);
+               inode_lock_nested(dir, I_MUTEX_PARENT);
+               if (!err)
+-                      err = ovl_cleanup(dir, dentry);
++                      err = ovl_cleanup(ofs, dir, dentry);
+       }
+       return err;
+@@ -1187,7 +1189,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
+               }
+               /* Cleanup leftover from index create/cleanup attempt */
+               if (index->d_name.name[0] == '#') {
+-                      err = ovl_workdir_cleanup(dir, path.mnt, index, 1);
++                      err = ovl_workdir_cleanup(ofs, dir, path.mnt, index, 1);
+                       if (err)
+                               break;
+                       goto next;
+@@ -1197,7 +1199,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
+                       goto next;
+               } else if (err == -ESTALE) {
+                       /* Cleanup stale index entries */
+-                      err = ovl_cleanup(dir, index);
++                      err = ovl_cleanup(ofs, dir, index);
+               } else if (err != -ENOENT) {
+                       /*
+                        * Abort mount to avoid corrupting the index if
+@@ -1213,7 +1215,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
+                       err = ovl_cleanup_and_whiteout(ofs, dir, index);
+               } else {
+                       /* Cleanup orphan index entries */
+-                      err = ovl_cleanup(dir, index);
++                      err = ovl_cleanup(ofs, dir, index);
+               }
+               if (err)
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index 1dad3dabe0099..2ad1f8652ce61 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -784,7 +784,7 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
+                               goto out_unlock;
+                       retried = true;
+-                      err = ovl_workdir_cleanup(dir, mnt, work, 0);
++                      err = ovl_workdir_cleanup(ofs, dir, mnt, work, 0);
+                       dput(work);
+                       if (err == -EINVAL) {
+                               work = ERR_PTR(err);
+@@ -793,7 +793,7 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
+                       goto retry;
+               }
+-              err = ovl_mkdir_real(dir, &work, attr.ia_mode);
++              err = ovl_mkdir_real(ofs, dir, &work, attr.ia_mode);
+               if (err)
+                       goto out_dput;
+@@ -1262,8 +1262,9 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
+  * Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
+  * negative values if error is encountered.
+  */
+-static int ovl_check_rename_whiteout(struct dentry *workdir)
++static int ovl_check_rename_whiteout(struct ovl_fs *ofs)
+ {
++      struct dentry *workdir = ofs->workdir;
+       struct inode *dir = d_inode(workdir);
+       struct dentry *temp;
+       struct dentry *dest;
+@@ -1273,12 +1274,12 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
+       inode_lock_nested(dir, I_MUTEX_PARENT);
+-      temp = ovl_create_temp(workdir, OVL_CATTR(S_IFREG | 0));
++      temp = ovl_create_temp(ofs, workdir, OVL_CATTR(S_IFREG | 0));
+       err = PTR_ERR(temp);
+       if (IS_ERR(temp))
+               goto out_unlock;
+-      dest = ovl_lookup_temp(workdir);
++      dest = ovl_lookup_temp(ofs, workdir);
+       err = PTR_ERR(dest);
+       if (IS_ERR(dest)) {
+               dput(temp);
+@@ -1287,7 +1288,7 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
+       /* Name is inline and stable - using snapshot as a copy helper */
+       take_dentry_name_snapshot(&name, temp);
+-      err = ovl_do_rename(dir, temp, dir, dest, RENAME_WHITEOUT);
++      err = ovl_do_rename(ofs, dir, temp, dir, dest, RENAME_WHITEOUT);
+       if (err) {
+               if (err == -EINVAL)
+                       err = 0;
+@@ -1303,11 +1304,11 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
+       /* Best effort cleanup of whiteout and temp file */
+       if (err)
+-              ovl_cleanup(dir, whiteout);
++              ovl_cleanup(ofs, dir, whiteout);
+       dput(whiteout);
+ cleanup_temp:
+-      ovl_cleanup(dir, temp);
++      ovl_cleanup(ofs, dir, temp);
+       release_dentry_name_snapshot(&name);
+       dput(temp);
+       dput(dest);
+@@ -1318,7 +1319,8 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
+       return err;
+ }
+-static struct dentry *ovl_lookup_or_create(struct dentry *parent,
++static struct dentry *ovl_lookup_or_create(struct ovl_fs *ofs,
++                                         struct dentry *parent,
+                                          const char *name, umode_t mode)
+ {
+       size_t len = strlen(name);
+@@ -1327,7 +1329,7 @@ static struct dentry *ovl_lookup_or_create(struct dentry *parent,
+       inode_lock_nested(parent->d_inode, I_MUTEX_PARENT);
+       child = lookup_one_len(name, parent, len);
+       if (!IS_ERR(child) && !child->d_inode)
+-              child = ovl_create_real(parent->d_inode, child,
++              child = ovl_create_real(ofs, parent->d_inode, child,
+                                       OVL_CATTR(mode));
+       inode_unlock(parent->d_inode);
+       dput(parent);
+@@ -1349,7 +1351,7 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs)
+       const char *const *name = volatile_path;
+       for (ctr = ARRAY_SIZE(volatile_path); ctr; ctr--, name++) {
+-              d = ovl_lookup_or_create(d, *name, ctr > 1 ? S_IFDIR : S_IFREG);
++              d = ovl_lookup_or_create(ofs, d, *name, ctr > 1 ? S_IFDIR : S_IFREG);
+               if (IS_ERR(d))
+                       return PTR_ERR(d);
+       }
+@@ -1397,7 +1399,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
+               pr_warn("upper fs needs to support d_type.\n");
+       /* Check if upper/work fs supports O_TMPFILE */
+-      temp = ovl_do_tmpfile(ofs->workdir, S_IFREG | 0);
++      temp = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0);
+       ofs->tmpfile = !IS_ERR(temp);
+       if (ofs->tmpfile)
+               dput(temp);
+@@ -1406,7 +1408,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
+       /* Check if upper/work fs supports RENAME_WHITEOUT */
+-      err = ovl_check_rename_whiteout(ofs->workdir);
++      err = ovl_check_rename_whiteout(ofs);
+       if (err < 0)
+               goto out;
+diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
+index eea9ec8f8c57a..8a9980ab2ad8f 100644
+--- a/fs/overlayfs/util.c
++++ b/fs/overlayfs/util.c
+@@ -866,7 +866,7 @@ static void ovl_cleanup_index(struct dentry *dentry)
+                                              dir, index);
+       } else {
+               /* Cleanup orphan index entries */
+-              err = ovl_cleanup(dir, index);
++              err = ovl_cleanup(ofs, dir, index);
+       }
+       inode_unlock(dir);
+-- 
+2.39.5
+
diff --git a/queue-5.15/ovl-use-wrappers-to-all-vfs_-xattr-calls.patch b/queue-5.15/ovl-use-wrappers-to-all-vfs_-xattr-calls.patch
new file mode 100644 (file)
index 0000000..4503667
--- /dev/null
@@ -0,0 +1,449 @@
+From 2e851b734612edad5c0cdbc46191b7cdb13e9efb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Apr 2022 12:51:42 +0200
+Subject: ovl: use wrappers to all vfs_*xattr() calls
+
+From: Amir Goldstein <amir73il@gmail.com>
+
+[ Upstream commit c914c0e27eb0843b7cf3bec71d6f34d53a3a671e ]
+
+Use helpers ovl_*xattr() to access user/trusted.overlay.* xattrs
+and use helpers ovl_do_*xattr() to access generic xattrs. This is a
+preparatory patch for using idmapped base layers with overlay.
+
+Note that a few of those places called vfs_*xattr() calls directly to
+reduce the amount of debug output. But as Miklos pointed out since
+overlayfs has been stable for quite some time the debug output isn't all
+that relevant anymore and the additional debug in all locations was
+actually quite helpful when developing this patch series.
+
+Cc: <linux-unionfs@vger.kernel.org>
+Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
+Reviewed-by: Christian Brauner (Microsoft) <brauner@kernel.org>
+Signed-off-by: Amir Goldstein <amir73il@gmail.com>
+Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Stable-dep-of: c84e125fff26 ("ovl: fix UAF in ovl_dentry_update_reval by moving dput() in ovl_link_up")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/overlayfs/copy_up.c   | 21 +++++++++++----------
+ fs/overlayfs/dir.c       | 15 ++++++++-------
+ fs/overlayfs/inode.c     | 17 +++++++++--------
+ fs/overlayfs/namei.c     |  6 +++---
+ fs/overlayfs/overlayfs.h | 38 ++++++++++++++++++++++++++++----------
+ fs/overlayfs/readdir.c   |  4 ++--
+ fs/overlayfs/super.c     | 12 ++++++------
+ fs/overlayfs/util.c      | 16 ++++++++--------
+ 8 files changed, 75 insertions(+), 54 deletions(-)
+
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index 0ed70eff9cb9e..80e7ae8152fdd 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -117,7 +117,7 @@ int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
+                       goto retry;
+               }
+-              error = vfs_setxattr(&init_user_ns, new, name, value, size, 0);
++              error = ovl_do_setxattr(OVL_FS(sb), new, name, value, size, 0);
+               if (error) {
+                       if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name))
+                               break;
+@@ -433,7 +433,7 @@ static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
+       if (IS_ERR(fh))
+               return PTR_ERR(fh);
+-      err = ovl_do_setxattr(ofs, index, OVL_XATTR_UPPER, fh->buf, fh->fb.len);
++      err = ovl_setxattr(ofs, index, OVL_XATTR_UPPER, fh->buf, fh->fb.len);
+       kfree(fh);
+       return err;
+@@ -868,12 +868,13 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode,
+       return true;
+ }
+-static ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value)
++static ssize_t ovl_getxattr_value(struct ovl_fs *ofs, struct dentry *dentry,
++                                char *name, char **value)
+ {
+       ssize_t res;
+       char *buf;
+-      res = vfs_getxattr(&init_user_ns, dentry, name, NULL, 0);
++      res = ovl_do_getxattr(ofs, dentry, name, NULL, 0);
+       if (res == -ENODATA || res == -EOPNOTSUPP)
+               res = 0;
+@@ -882,7 +883,7 @@ static ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value)
+               if (!buf)
+                       return -ENOMEM;
+-              res = vfs_getxattr(&init_user_ns, dentry, name, buf, res);
++              res = ovl_do_getxattr(ofs, dentry, name, buf, res);
+               if (res < 0)
+                       kfree(buf);
+               else
+@@ -909,8 +910,8 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
+               return -EIO;
+       if (c->stat.size) {
+-              err = cap_size = ovl_getxattr(upperpath.dentry, XATTR_NAME_CAPS,
+-                                            &capability);
++              err = cap_size = ovl_getxattr_value(ofs, upperpath.dentry,
++                                                  XATTR_NAME_CAPS, &capability);
+               if (cap_size < 0)
+                       goto out;
+       }
+@@ -924,14 +925,14 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
+        * don't want that to happen for normal copy-up operation.
+        */
+       if (capability) {
+-              err = vfs_setxattr(&init_user_ns, upperpath.dentry,
+-                                 XATTR_NAME_CAPS, capability, cap_size, 0);
++              err = ovl_do_setxattr(ofs, upperpath.dentry, XATTR_NAME_CAPS,
++                                    capability, cap_size, 0);
+               if (err)
+                       goto out_free;
+       }
+-      err = ovl_do_removexattr(ofs, upperpath.dentry, OVL_XATTR_METACOPY);
++      err = ovl_removexattr(ofs, upperpath.dentry, OVL_XATTR_METACOPY);
+       if (err)
+               goto out_free;
+diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
+index 519193ce7d575..5e9005a0afaad 100644
+--- a/fs/overlayfs/dir.c
++++ b/fs/overlayfs/dir.c
+@@ -431,8 +431,8 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
+       return ERR_PTR(err);
+ }
+-static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
+-                           const struct posix_acl *acl)
++static int ovl_set_upper_acl(struct ovl_fs *ofs, struct dentry *upperdentry,
++                           const char *name, const struct posix_acl *acl)
+ {
+       void *buffer;
+       size_t size;
+@@ -450,7 +450,7 @@ static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
+       if (err < 0)
+               goto out_free;
+-      err = vfs_setxattr(&init_user_ns, upperdentry, name, buffer, size, XATTR_CREATE);
++      err = ovl_do_setxattr(ofs, upperdentry, name, buffer, size, XATTR_CREATE);
+ out_free:
+       kfree(buffer);
+       return err;
+@@ -459,6 +459,7 @@ static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
+ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
+                                   struct ovl_cattr *cattr)
+ {
++      struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+       struct dentry *workdir = ovl_workdir(dentry);
+       struct inode *wdir = workdir->d_inode;
+       struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
+@@ -515,13 +516,13 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
+                       goto out_cleanup;
+       }
+       if (!hardlink) {
+-              err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS,
+-                                      acl);
++              err = ovl_set_upper_acl(ofs, newdentry,
++                                      XATTR_NAME_POSIX_ACL_ACCESS, acl);
+               if (err)
+                       goto out_cleanup;
+-              err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT,
+-                                      default_acl);
++              err = ovl_set_upper_acl(ofs, newdentry,
++                                      XATTR_NAME_POSIX_ACL_DEFAULT, default_acl);
+               if (err)
+                       goto out_cleanup;
+       }
+diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
+index 7961d6888c520..aa8513aac4728 100644
+--- a/fs/overlayfs/inode.c
++++ b/fs/overlayfs/inode.c
+@@ -342,6 +342,7 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
+                 const void *value, size_t size, int flags)
+ {
+       int err;
++      struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+       struct dentry *upperdentry = ovl_i_dentry_upper(inode);
+       struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
+       const struct cred *old_cred;
+@@ -367,12 +368,12 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
+       }
+       old_cred = ovl_override_creds(dentry->d_sb);
+-      if (value)
+-              err = vfs_setxattr(&init_user_ns, realdentry, name, value, size,
+-                                 flags);
+-      else {
++      if (value) {
++              err = ovl_do_setxattr(ofs, realdentry, name, value, size,
++                                    flags);
++      } else {
+               WARN_ON(flags != XATTR_REPLACE);
+-              err = vfs_removexattr(&init_user_ns, realdentry, name);
++              err = ovl_do_removexattr(ofs, realdentry, name);
+       }
+       revert_creds(old_cred);
+@@ -887,8 +888,8 @@ static int ovl_set_nlink_common(struct dentry *dentry,
+       if (WARN_ON(len >= sizeof(buf)))
+               return -EIO;
+-      return ovl_do_setxattr(OVL_FS(inode->i_sb), ovl_dentry_upper(dentry),
+-                             OVL_XATTR_NLINK, buf, len);
++      return ovl_setxattr(OVL_FS(inode->i_sb), ovl_dentry_upper(dentry),
++                          OVL_XATTR_NLINK, buf, len);
+ }
+ int ovl_set_nlink_upper(struct dentry *dentry)
+@@ -913,7 +914,7 @@ unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry,
+       if (!lowerdentry || !upperdentry || d_inode(lowerdentry)->i_nlink == 1)
+               return fallback;
+-      err = ovl_do_getxattr(ofs, upperdentry, OVL_XATTR_NLINK,
++      err = ovl_getxattr(ofs, upperdentry, OVL_XATTR_NLINK,
+                             &buf, sizeof(buf) - 1);
+       if (err < 0)
+               goto fail;
+diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
+index 9c055d11a95de..00d74311aa0d3 100644
+--- a/fs/overlayfs/namei.c
++++ b/fs/overlayfs/namei.c
+@@ -111,7 +111,7 @@ static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry,
+       int res, err;
+       struct ovl_fh *fh = NULL;
+-      res = ovl_do_getxattr(ofs, dentry, ox, NULL, 0);
++      res = ovl_getxattr(ofs, dentry, ox, NULL, 0);
+       if (res < 0) {
+               if (res == -ENODATA || res == -EOPNOTSUPP)
+                       return NULL;
+@@ -125,7 +125,7 @@ static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry,
+       if (!fh)
+               return ERR_PTR(-ENOMEM);
+-      res = ovl_do_getxattr(ofs, dentry, ox, fh->buf, res);
++      res = ovl_getxattr(ofs, dentry, ox, fh->buf, res);
+       if (res < 0)
+               goto fail;
+@@ -464,7 +464,7 @@ int ovl_verify_set_fh(struct ovl_fs *ofs, struct dentry *dentry,
+       err = ovl_verify_fh(ofs, dentry, ox, fh);
+       if (set && err == -ENODATA)
+-              err = ovl_do_setxattr(ofs, dentry, ox, fh->buf, fh->fb.len);
++              err = ovl_setxattr(ofs, dentry, ox, fh->buf, fh->fb.len);
+       if (err)
+               goto fail;
+diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
+index a96b67586f817..3f4655b9c71ca 100644
+--- a/fs/overlayfs/overlayfs.h
++++ b/fs/overlayfs/overlayfs.h
+@@ -183,10 +183,9 @@ static inline int ovl_do_symlink(struct inode *dir, struct dentry *dentry,
+ }
+ static inline ssize_t ovl_do_getxattr(struct ovl_fs *ofs, struct dentry *dentry,
+-                                    enum ovl_xattr ox, void *value,
++                                    const char *name, void *value,
+                                     size_t size)
+ {
+-      const char *name = ovl_xattr(ofs, ox);
+       int err = vfs_getxattr(&init_user_ns, dentry, name, value, size);
+       int len = (value && err > 0) ? err : 0;
+@@ -195,26 +194,45 @@ static inline ssize_t ovl_do_getxattr(struct ovl_fs *ofs, struct dentry *dentry,
+       return err;
+ }
++static inline ssize_t ovl_getxattr(struct ovl_fs *ofs, struct dentry *dentry,
++                                 enum ovl_xattr ox, void *value,
++                                 size_t size)
++{
++      return ovl_do_getxattr(ofs, dentry, ovl_xattr(ofs, ox), value, size);
++}
++
+ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
+-                                enum ovl_xattr ox, const void *value,
+-                                size_t size)
++                                const char *name, const void *value,
++                                size_t size, int flags)
+ {
+-      const char *name = ovl_xattr(ofs, ox);
+-      int err = vfs_setxattr(&init_user_ns, dentry, name, value, size, 0);
+-      pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, 0) = %i\n",
+-               dentry, name, min((int)size, 48), value, size, err);
++      int err = vfs_setxattr(&init_user_ns, dentry, name, value, size, flags);
++
++      pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n",
++               dentry, name, min((int)size, 48), value, size, flags, err);
+       return err;
+ }
++static inline int ovl_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
++                             enum ovl_xattr ox, const void *value,
++                             size_t size)
++{
++      return ovl_do_setxattr(ofs, dentry, ovl_xattr(ofs, ox), value, size, 0);
++}
++
+ static inline int ovl_do_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
+-                                   enum ovl_xattr ox)
++                                   const char *name)
+ {
+-      const char *name = ovl_xattr(ofs, ox);
+       int err = vfs_removexattr(&init_user_ns, dentry, name);
+       pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err);
+       return err;
+ }
++static inline int ovl_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
++                                enum ovl_xattr ox)
++{
++      return ovl_do_removexattr(ofs, dentry, ovl_xattr(ofs, ox));
++}
++
+ static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
+                               struct inode *newdir, struct dentry *newdentry,
+                               unsigned int flags)
+diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
+index 150fdf3bc68d4..c7b542331065c 100644
+--- a/fs/overlayfs/readdir.c
++++ b/fs/overlayfs/readdir.c
+@@ -623,8 +623,8 @@ static struct ovl_dir_cache *ovl_cache_get_impure(struct path *path)
+                * Removing the "impure" xattr is best effort.
+                */
+               if (!ovl_want_write(dentry)) {
+-                      ovl_do_removexattr(ofs, ovl_dentry_upper(dentry),
+-                                         OVL_XATTR_IMPURE);
++                      ovl_removexattr(ofs, ovl_dentry_upper(dentry),
++                                      OVL_XATTR_IMPURE);
+                       ovl_drop_write(dentry);
+               }
+               ovl_clear_flag(OVL_IMPURE, d_inode(dentry));
+diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
+index 5310271cf2e38..1dad3dabe0099 100644
+--- a/fs/overlayfs/super.c
++++ b/fs/overlayfs/super.c
+@@ -815,13 +815,13 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
+                * allowed as upper are limited to "normal" ones, where checking
+                * for the above two errors is sufficient.
+                */
+-              err = vfs_removexattr(&init_user_ns, work,
+-                                    XATTR_NAME_POSIX_ACL_DEFAULT);
++              err = ovl_do_removexattr(ofs, work,
++                                       XATTR_NAME_POSIX_ACL_DEFAULT);
+               if (err && err != -ENODATA && err != -EOPNOTSUPP)
+                       goto out_dput;
+-              err = vfs_removexattr(&init_user_ns, work,
+-                                    XATTR_NAME_POSIX_ACL_ACCESS);
++              err = ovl_do_removexattr(ofs, work,
++                                       XATTR_NAME_POSIX_ACL_ACCESS);
+               if (err && err != -ENODATA && err != -EOPNOTSUPP)
+                       goto out_dput;
+@@ -1417,7 +1417,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
+       /*
+        * Check if upper/work fs supports (trusted|user).overlay.* xattr
+        */
+-      err = ovl_do_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1);
++      err = ovl_setxattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE, "0", 1);
+       if (err) {
+               pr_warn("failed to set xattr on upper\n");
+               ofs->noxattr = true;
+@@ -1438,7 +1438,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
+                       pr_info("try mounting with 'userxattr' option\n");
+               err = 0;
+       } else {
+-              ovl_do_removexattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE);
++              ovl_removexattr(ofs, ofs->workdir, OVL_XATTR_OPAQUE);
+       }
+       /*
+diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
+index 747b47048b3aa..eea9ec8f8c57a 100644
+--- a/fs/overlayfs/util.c
++++ b/fs/overlayfs/util.c
+@@ -586,7 +586,7 @@ bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry)
+ {
+       int res;
+-      res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_ORIGIN, NULL, 0);
++      res = ovl_getxattr(ofs, dentry, OVL_XATTR_ORIGIN, NULL, 0);
+       /* Zero size value means "copied up but origin unknown" */
+       if (res >= 0)
+@@ -604,7 +604,7 @@ bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
+       if (!d_is_dir(dentry))
+               return false;
+-      res = ovl_do_getxattr(OVL_FS(sb), dentry, ox, &val, 1);
++      res = ovl_getxattr(OVL_FS(sb), dentry, ox, &val, 1);
+       if (res == 1 && val == 'y')
+               return true;
+@@ -644,7 +644,7 @@ int ovl_check_setxattr(struct ovl_fs *ofs, struct dentry *upperdentry,
+       if (ofs->noxattr)
+               return xerr;
+-      err = ovl_do_setxattr(ofs, upperdentry, ox, value, size);
++      err = ovl_setxattr(ofs, upperdentry, ox, value, size);
+       if (err == -EOPNOTSUPP) {
+               pr_warn("cannot set %s xattr on upper\n", ovl_xattr(ofs, ox));
+@@ -684,7 +684,7 @@ void ovl_check_protattr(struct inode *inode, struct dentry *upper)
+       char buf[OVL_PROTATTR_MAX+1];
+       int res, n;
+-      res = ovl_do_getxattr(ofs, upper, OVL_XATTR_PROTATTR, buf,
++      res = ovl_getxattr(ofs, upper, OVL_XATTR_PROTATTR, buf,
+                             OVL_PROTATTR_MAX);
+       if (res < 0)
+               return;
+@@ -740,7 +740,7 @@ int ovl_set_protattr(struct inode *inode, struct dentry *upper,
+               err = ovl_check_setxattr(ofs, upper, OVL_XATTR_PROTATTR,
+                                        buf, len, -EPERM);
+       } else if (inode->i_flags & OVL_PROT_I_FLAGS_MASK) {
+-              err = ovl_do_removexattr(ofs, upper, OVL_XATTR_PROTATTR);
++              err = ovl_removexattr(ofs, upper, OVL_XATTR_PROTATTR);
+               if (err == -EOPNOTSUPP || err == -ENODATA)
+                       err = 0;
+       }
+@@ -983,7 +983,7 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry)
+       if (!S_ISREG(d_inode(dentry)->i_mode))
+               return 0;
+-      res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_METACOPY, NULL, 0);
++      res = ovl_getxattr(ofs, dentry, OVL_XATTR_METACOPY, NULL, 0);
+       if (res < 0) {
+               if (res == -ENODATA || res == -EOPNOTSUPP)
+                       return 0;
+@@ -1025,7 +1025,7 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
+       int res;
+       char *s, *next, *buf = NULL;
+-      res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, NULL, 0);
++      res = ovl_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, NULL, 0);
+       if (res == -ENODATA || res == -EOPNOTSUPP)
+               return NULL;
+       if (res < 0)
+@@ -1037,7 +1037,7 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+-      res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, buf, res);
++      res = ovl_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, buf, res);
+       if (res < 0)
+               goto fail;
+       if (res == 0)
+-- 
+2.39.5
+
diff --git a/queue-5.15/rdma-mlx5-fix-bind-qp-error-cleanup-flow.patch b/queue-5.15/rdma-mlx5-fix-bind-qp-error-cleanup-flow.patch
new file mode 100644 (file)
index 0000000..9e78108
--- /dev/null
@@ -0,0 +1,63 @@
+From dd16e257721f61a0e279d885ef8a99e1092f2f92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 08:47:10 +0200
+Subject: RDMA/mlx5: Fix bind QP error cleanup flow
+
+From: Patrisious Haddad <phaddad@nvidia.com>
+
+[ Upstream commit e1a0bdbdfdf08428f0ede5ae49c7f4139ac73ef5 ]
+
+When there is a failure during bind QP, the cleanup flow destroys the
+counter regardless if it is the one that created it or not, which is
+problematic since if it isn't the one that created it, that counter could
+still be in use.
+
+Fix that by destroying the counter only if it was created during this call.
+
+Fixes: 45842fc627c7 ("IB/mlx5: Support statistic q counter configuration")
+Signed-off-by: Patrisious Haddad <phaddad@nvidia.com>
+Reviewed-by: Mark Zhang <markzhang@nvidia.com>
+Link: https://patch.msgid.link/25dfefddb0ebefa668c32e06a94d84e3216257cf.1740033937.git.leon@kernel.org
+Reviewed-by: Zhu Yanjun <yanjun.zhu@linux.dev>
+Signed-off-by: Leon Romanovsky <leon@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/infiniband/hw/mlx5/counters.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/infiniband/hw/mlx5/counters.c b/drivers/infiniband/hw/mlx5/counters.c
+index 1a0ecf439c099..870a089198116 100644
+--- a/drivers/infiniband/hw/mlx5/counters.c
++++ b/drivers/infiniband/hw/mlx5/counters.c
+@@ -337,6 +337,7 @@ static int mlx5_ib_counter_bind_qp(struct rdma_counter *counter,
+                                  struct ib_qp *qp)
+ {
+       struct mlx5_ib_dev *dev = to_mdev(qp->device);
++      bool new = false;
+       int err;
+       if (!counter->id) {
+@@ -351,6 +352,7 @@ static int mlx5_ib_counter_bind_qp(struct rdma_counter *counter,
+                       return err;
+               counter->id =
+                       MLX5_GET(alloc_q_counter_out, out, counter_set_id);
++              new = true;
+       }
+       err = mlx5_ib_qp_set_counter(qp, counter);
+@@ -360,8 +362,10 @@ static int mlx5_ib_counter_bind_qp(struct rdma_counter *counter,
+       return 0;
+ fail_set_counter:
+-      mlx5_ib_counter_dealloc(counter);
+-      counter->id = 0;
++      if (new) {
++              mlx5_ib_counter_dealloc(counter);
++              counter->id = 0;
++      }
+       return err;
+ }
+-- 
+2.39.5
+
diff --git a/queue-5.15/scsi-core-clear-driver-private-data-when-retrying-re.patch b/queue-5.15/scsi-core-clear-driver-private-data-when-retrying-re.patch
new file mode 100644 (file)
index 0000000..c44003d
--- /dev/null
@@ -0,0 +1,68 @@
+From a55b12cb7d3b0d403df8996092c40cbe2aa81b51 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 10:16:28 +0800
+Subject: scsi: core: Clear driver private data when retrying request
+
+From: Ye Bin <yebin10@huawei.com>
+
+[ Upstream commit dce5c4afd035e8090a26e5d776b1682c0e649683 ]
+
+After commit 1bad6c4a57ef ("scsi: zero per-cmd private driver data for each
+MQ I/O"), the xen-scsifront/virtio_scsi/snic drivers all removed code that
+explicitly zeroed driver-private command data.
+
+In combination with commit 464a00c9e0ad ("scsi: core: Kill DRIVER_SENSE"),
+after virtio_scsi performs a capacity expansion, the first request will
+return a unit attention to indicate that the capacity has changed. And then
+the original command is retried. As driver-private command data was not
+cleared, the request would return UA again and eventually time out and fail.
+
+Zero driver-private command data when a request is retried.
+
+Fixes: f7de50da1479 ("scsi: xen-scsifront: Remove code that zeroes driver-private command data")
+Fixes: c2bb87318baa ("scsi: virtio_scsi: Remove code that zeroes driver-private command data")
+Fixes: c3006a926468 ("scsi: snic: Remove code that zeroes driver-private command data")
+Signed-off-by: Ye Bin <yebin10@huawei.com>
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Link: https://lore.kernel.org/r/20250217021628.2929248-1-yebin@huaweicloud.com
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/scsi_lib.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index ddaffaea2c32c..c8be41d8eb247 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -1532,13 +1532,6 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
+       if (in_flight)
+               __set_bit(SCMD_STATE_INFLIGHT, &cmd->state);
+-      /*
+-       * Only clear the driver-private command data if the LLD does not supply
+-       * a function to initialize that data.
+-       */
+-      if (!shost->hostt->init_cmd_priv)
+-              memset(cmd + 1, 0, shost->hostt->cmd_size);
+-
+       cmd->prot_op = SCSI_PROT_NORMAL;
+       if (blk_rq_bytes(req))
+               cmd->sc_data_direction = rq_dma_dir(req);
+@@ -1675,6 +1668,13 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
+       if (!scsi_host_queue_ready(q, shost, sdev, cmd))
+               goto out_dec_target_busy;
++      /*
++       * Only clear the driver-private command data if the LLD does not supply
++       * a function to initialize that data.
++       */
++      if (shost->hostt->cmd_size && !shost->hostt->init_cmd_priv)
++              memset(cmd + 1, 0, shost->hostt->cmd_size);
++
+       if (!(req->rq_flags & RQF_DONTPREP)) {
+               ret = scsi_prepare_cmd(req);
+               if (ret != BLK_STS_OK)
+-- 
+2.39.5
+
diff --git a/queue-5.15/scsi-core-don-t-memset-the-entire-scsi_cmnd-in-scsi_.patch b/queue-5.15/scsi-core-don-t-memset-the-entire-scsi_cmnd-in-scsi_.patch
new file mode 100644 (file)
index 0000000..4ac4c23
--- /dev/null
@@ -0,0 +1,121 @@
+From 3039005b7ab8db780c75d240d5c329f48129722b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 24 Feb 2022 18:55:46 +0100
+Subject: scsi: core: Don't memset() the entire scsi_cmnd in
+ scsi_init_command()
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 71bada345b33b9297e7cc9415db6328c99b554f9 ]
+
+Replace the big fat memset that requires saving and restoring various
+fields with just initializing those fields that need initialization.
+
+All the clearing to 0 is moved to scsi_prepare_cmd() as scsi_ioctl_reset()
+alreadly uses kzalloc() to allocate a pre-zeroed command.
+
+This is still conservative and can probably be optimized further.
+
+Link: https://lore.kernel.org/r/20220224175552.988286-3-hch@lst.de
+Reviewed-by: Bart Van Assche <bvanassche@acm.org>
+Reviewed-by: John Garry <john.garry@huawei.com>
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: dce5c4afd035 ("scsi: core: Clear driver private data when retrying request")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/scsi_lib.c | 60 +++++++++++++++++++----------------------
+ 1 file changed, 28 insertions(+), 32 deletions(-)
+
+diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
+index 9721984fd9bc6..ddaffaea2c32c 100644
+--- a/drivers/scsi/scsi_lib.c
++++ b/drivers/scsi/scsi_lib.c
+@@ -1114,45 +1114,16 @@ static void scsi_cleanup_rq(struct request *rq)
+ /* Called before a request is prepared. See also scsi_mq_prep_fn(). */
+ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
+ {
+-      void *buf = cmd->sense_buffer;
+-      void *prot = cmd->prot_sdb;
+       struct request *rq = scsi_cmd_to_rq(cmd);
+-      unsigned int flags = cmd->flags & SCMD_PRESERVED_FLAGS;
+-      unsigned long jiffies_at_alloc;
+-      int retries, to_clear;
+-      bool in_flight;
+-      int budget_token = cmd->budget_token;
+-
+-      if (!blk_rq_is_passthrough(rq) && !(flags & SCMD_INITIALIZED)) {
+-              flags |= SCMD_INITIALIZED;
++
++      if (!blk_rq_is_passthrough(rq) && !(cmd->flags & SCMD_INITIALIZED)) {
++              cmd->flags |= SCMD_INITIALIZED;
+               scsi_initialize_rq(rq);
+       }
+-      jiffies_at_alloc = cmd->jiffies_at_alloc;
+-      retries = cmd->retries;
+-      in_flight = test_bit(SCMD_STATE_INFLIGHT, &cmd->state);
+-      /*
+-       * Zero out the cmd, except for the embedded scsi_request. Only clear
+-       * the driver-private command data if the LLD does not supply a
+-       * function to initialize that data.
+-       */
+-      to_clear = sizeof(*cmd) - sizeof(cmd->req);
+-      if (!dev->host->hostt->init_cmd_priv)
+-              to_clear += dev->host->hostt->cmd_size;
+-      memset((char *)cmd + sizeof(cmd->req), 0, to_clear);
+-
+       cmd->device = dev;
+-      cmd->sense_buffer = buf;
+-      cmd->prot_sdb = prot;
+-      cmd->flags = flags;
+       INIT_LIST_HEAD(&cmd->eh_entry);
+       INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
+-      cmd->jiffies_at_alloc = jiffies_at_alloc;
+-      cmd->retries = retries;
+-      if (in_flight)
+-              __set_bit(SCMD_STATE_INFLIGHT, &cmd->state);
+-      cmd->budget_token = budget_token;
+-
+ }
+ static blk_status_t scsi_setup_scsi_cmnd(struct scsi_device *sdev,
+@@ -1539,10 +1510,35 @@ static blk_status_t scsi_prepare_cmd(struct request *req)
+       struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req);
+       struct scsi_device *sdev = req->q->queuedata;
+       struct Scsi_Host *shost = sdev->host;
++      bool in_flight = test_bit(SCMD_STATE_INFLIGHT, &cmd->state);
+       struct scatterlist *sg;
+       scsi_init_command(sdev, cmd);
++      cmd->eh_eflags = 0;
++      cmd->allowed = 0;
++      cmd->prot_type = 0;
++      cmd->prot_flags = 0;
++      cmd->submitter = 0;
++      cmd->cmd_len = 0;
++      cmd->cmnd = NULL;
++      memset(&cmd->sdb, 0, sizeof(cmd->sdb));
++      cmd->underflow = 0;
++      cmd->transfersize = 0;
++      cmd->host_scribble = NULL;
++      cmd->result = 0;
++      cmd->extra_len = 0;
++      cmd->state = 0;
++      if (in_flight)
++              __set_bit(SCMD_STATE_INFLIGHT, &cmd->state);
++
++      /*
++       * Only clear the driver-private command data if the LLD does not supply
++       * a function to initialize that data.
++       */
++      if (!shost->hostt->init_cmd_priv)
++              memset(cmd + 1, 0, shost->hostt->cmd_size);
++
+       cmd->prot_op = SCSI_PROT_NORMAL;
+       if (blk_rq_bytes(req))
+               cmd->sc_data_direction = rq_dma_dir(req);
+-- 
+2.39.5
+
index 539253133a98e309ac3f69794f8682081169a382..a2e0b1b2b4f853a5627755eb95a57c9c1910f147 100644 (file)
@@ -487,3 +487,11 @@ mtd-rawnand-cadence-fix-error-code-in-cadence_nand_init.patch
 mtd-rawnand-cadence-use-dma_map_resource-for-sdma-address.patch
 mtd-rawnand-cadence-fix-incorrect-device-in-dma_unmap_single.patch
 x86-cpu-kvm-srso-fix-possible-missing-ibpb-on-vm-exit.patch
+ib-mlx5-set-and-get-correct-qp_num-for-a-dct-qp.patch
+ovl-use-wrappers-to-all-vfs_-xattr-calls.patch
+ovl-pass-ofs-to-creation-operations.patch
+ovl-fix-uaf-in-ovl_dentry_update_reval-by-moving-dpu.patch
+scsi-core-don-t-memset-the-entire-scsi_cmnd-in-scsi_.patch
+scsi-core-clear-driver-private-data-when-retrying-re.patch
+rdma-mlx5-fix-bind-qp-error-cleanup-flow.patch
+sunrpc-suppress-warnings-for-unused-procfs-functions.patch
diff --git a/queue-5.15/sunrpc-suppress-warnings-for-unused-procfs-functions.patch b/queue-5.15/sunrpc-suppress-warnings-for-unused-procfs-functions.patch
new file mode 100644 (file)
index 0000000..f38a3a8
--- /dev/null
@@ -0,0 +1,71 @@
+From d85cb2eee17af738e1ba719ef712541c12a16ebd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 15:52:21 +0100
+Subject: sunrpc: suppress warnings for unused procfs functions
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 1f7a4f98c11fbeb18ed21f3b3a497e90a50ad2e0 ]
+
+There is a warning about unused variables when building with W=1 and no procfs:
+
+net/sunrpc/cache.c:1660:30: error: 'cache_flush_proc_ops' defined but not used [-Werror=unused-const-variable=]
+ 1660 | static const struct proc_ops cache_flush_proc_ops = {
+      |                              ^~~~~~~~~~~~~~~~~~~~
+net/sunrpc/cache.c:1622:30: error: 'content_proc_ops' defined but not used [-Werror=unused-const-variable=]
+ 1622 | static const struct proc_ops content_proc_ops = {
+      |                              ^~~~~~~~~~~~~~~~
+net/sunrpc/cache.c:1598:30: error: 'cache_channel_proc_ops' defined but not used [-Werror=unused-const-variable=]
+ 1598 | static const struct proc_ops cache_channel_proc_ops = {
+      |                              ^~~~~~~~~~~~~~~~~~~~~~
+
+These are used inside of an #ifdef, so replacing that with an
+IS_ENABLED() check lets the compiler see how they are used while
+still dropping them during dead code elimination.
+
+Fixes: dbf847ecb631 ("knfsd: allow cache_register to return error on failure")
+Reviewed-by: Jeff Layton <jlayton@kernel.org>
+Acked-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/sunrpc/cache.c | 10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
+index 8c9597b9a3f2e..95aab48d32e67 100644
+--- a/net/sunrpc/cache.c
++++ b/net/sunrpc/cache.c
+@@ -1659,12 +1659,14 @@ static void remove_cache_proc_entries(struct cache_detail *cd)
+       }
+ }
+-#ifdef CONFIG_PROC_FS
+ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
+ {
+       struct proc_dir_entry *p;
+       struct sunrpc_net *sn;
++      if (!IS_ENABLED(CONFIG_PROC_FS))
++              return 0;
++
+       sn = net_generic(net, sunrpc_net_id);
+       cd->procfs = proc_mkdir(cd->name, sn->proc_net_rpc);
+       if (cd->procfs == NULL)
+@@ -1692,12 +1694,6 @@ static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
+       remove_cache_proc_entries(cd);
+       return -ENOMEM;
+ }
+-#else /* CONFIG_PROC_FS */
+-static int create_cache_proc_entries(struct cache_detail *cd, struct net *net)
+-{
+-      return 0;
+-}
+-#endif
+ void __init cache_initialize(void)
+ {
+-- 
+2.39.5
+