]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Fri, 28 Jul 2023 14:38:02 +0000 (10:38 -0400)
committerSasha Levin <sashal@kernel.org>
Fri, 28 Jul 2023 14:38:02 +0000 (10:38 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
49 files changed:
queue-5.15/btrfs-fix-race-between-quota-disable-and-relocation.patch [new file with mode: 0644]
queue-5.15/cifs-if-deferred-close-is-disabled-then-close-files-.patch [new file with mode: 0644]
queue-5.15/cifs-missing-directory-in-maintainers-file.patch [new file with mode: 0644]
queue-5.15/cifs-use-fs_context-for-automounts.patch [new file with mode: 0644]
queue-5.15/dlm-cleanup-plock_op-vs-plock_xop.patch [new file with mode: 0644]
queue-5.15/dlm-rearrange-async-condition-return.patch [new file with mode: 0644]
queue-5.15/drm-amdgpu-fix-vkms-crtc-settings.patch [new file with mode: 0644]
queue-5.15/drm-amdgpu-vkms-relax-timer-deactivation-by-hrtimer_.patch [new file with mode: 0644]
queue-5.15/drm-ttm-don-t-leak-a-resource-on-eviction-error.patch [new file with mode: 0644]
queue-5.15/drm-ttm-don-t-print-error-message-if-eviction-was-in.patch [new file with mode: 0644]
queue-5.15/drm-ttm-never-consider-pinned-bos-for-eviction-swap.patch [new file with mode: 0644]
queue-5.15/fs-dlm-interrupt-posix-locks-only-when-process-is-ki.patch [new file with mode: 0644]
queue-5.15/gpio-mvebu-fix-irq-domain-leak.patch [new file with mode: 0644]
queue-5.15/gpio-mvebu-make-use-of-devm_pwmchip_add.patch [new file with mode: 0644]
queue-5.15/gpio-tps68470-make-tps68470_gpio_output-always-set-t.patch [new file with mode: 0644]
queue-5.15/i2c-delete-error-messages-for-failed-memory-allocati.patch [new file with mode: 0644]
queue-5.15/i2c-improve-size-determinations.patch [new file with mode: 0644]
queue-5.15/i2c-nomadik-remove-a-useless-call-in-the-remove-func.patch [new file with mode: 0644]
queue-5.15/i2c-nomadik-remove-unnecessary-goto-label.patch [new file with mode: 0644]
queue-5.15/i2c-nomadik-use-devm_clk_get_enabled.patch [new file with mode: 0644]
queue-5.15/io_uring-don-t-audit-the-capability-check-in-io_urin.patch [new file with mode: 0644]
queue-5.15/jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch [new file with mode: 0644]
queue-5.15/jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch [new file with mode: 0644]
queue-5.15/jbd2-remove-journal_clean_one_cp_list.patch [new file with mode: 0644]
queue-5.15/jbd2-remove-t_checkpoint_io_list.patch [new file with mode: 0644]
queue-5.15/ksmbd-remove-internal.h-include.patch [new file with mode: 0644]
queue-5.15/kvm-s390-pv-fix-index-value-of-replaced-asce.patch [new file with mode: 0644]
queue-5.15/n_tty-rename-tail-to-old_tail-in-n_tty_read.patch [new file with mode: 0644]
queue-5.15/pci-aspm-avoid-link-retraining-race.patch [new file with mode: 0644]
queue-5.15/pci-aspm-factor-out-pcie_wait_for_retrain.patch [new file with mode: 0644]
queue-5.15/pci-aspm-return-0-or-etimedout-from-pcie_retrain_lin.patch [new file with mode: 0644]
queue-5.15/pci-rockchip-don-t-advertise-msi-x-in-pcie-capabilit.patch [new file with mode: 0644]
queue-5.15/pci-rockchip-fix-window-mapping-and-address-translat.patch [new file with mode: 0644]
queue-5.15/pci-rockchip-remove-writes-to-unused-registers.patch [new file with mode: 0644]
queue-5.15/pwm-meson-fix-handling-of-period-duty-if-greater-tha.patch [new file with mode: 0644]
queue-5.15/pwm-meson-simplify-duplicated-per-channel-tracking.patch [new file with mode: 0644]
queue-5.15/revert-tracing-add-fault-name-injection-to-kernel-pr.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-add-debug-prints-in-the-device-remove-p.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-fix-hang-in-task-management.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-fix-task-management-cmd-fail-due-to-una.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-fix-task-management-cmd-failure.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-multi-que-support-for-tmf.patch [new file with mode: 0644]
queue-5.15/scsi-qla2xxx-remove-unused-declarations-for-qla2xxx.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/tracing-allow-synthetic-events-to-pass-around-stackt.patch [new file with mode: 0644]
queue-5.15/tracing-probes-add-symstr-type-for-dynamic-events.patch [new file with mode: 0644]
queue-5.15/tracing-probes-fix-to-avoid-double-count-of-the-stri.patch [new file with mode: 0644]
queue-5.15/tracing-probes-fix-to-record-0-length-data_loc-in-fe.patch [new file with mode: 0644]
queue-5.15/tty-fix-hang-on-tty-device-with-no_room-set.patch [new file with mode: 0644]

diff --git a/queue-5.15/btrfs-fix-race-between-quota-disable-and-relocation.patch b/queue-5.15/btrfs-fix-race-between-quota-disable-and-relocation.patch
new file mode 100644 (file)
index 0000000..2ab859e
--- /dev/null
@@ -0,0 +1,97 @@
+From ee59420526d47ee7ea747caa98d04afdebeb2fc7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 19 Jun 2023 17:21:50 +0100
+Subject: btrfs: fix race between quota disable and relocation
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 8a4a0b2a3eaf75ca8854f856ef29690c12b2f531 ]
+
+If we disable quotas while we have a relocation of a metadata block group
+that has extents belonging to the quota root, we can cause the relocation
+to fail with -ENOENT. This is because relocation builds backref nodes for
+extents of the quota root and later needs to walk the backrefs and access
+the quota root - however if in between a task disables quotas, it results
+in deleting the quota root from the root tree (with btrfs_del_root(),
+called from btrfs_quota_disable().
+
+This can be sporadically triggered by test case btrfs/255 from fstests:
+
+  $ ./check btrfs/255
+  FSTYP         -- btrfs
+  PLATFORM      -- Linux/x86_64 debian0 6.4.0-rc6-btrfs-next-134+ #1 SMP PREEMPT_DYNAMIC Thu Jun 15 11:59:28 WEST 2023
+  MKFS_OPTIONS  -- /dev/sdc
+  MOUNT_OPTIONS -- /dev/sdc /home/fdmanana/btrfs-tests/scratch_1
+
+  btrfs/255 6s ... _check_dmesg: something found in dmesg (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.dmesg)
+  - output mismatch (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad)
+      --- tests/btrfs/255.out  2023-03-02 21:47:53.876609426 +0000
+      +++ /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad   2023-06-16 10:20:39.267563212 +0100
+      @@ -1,2 +1,4 @@
+       QA output created by 255
+      +ERROR: error during balancing '/home/fdmanana/btrfs-tests/scratch_1': No such file or directory
+      +There may be more info in syslog - try dmesg | tail
+       Silence is golden
+      ...
+      (Run 'diff -u /home/fdmanana/git/hub/xfstests/tests/btrfs/255.out /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad'  to see the entire diff)
+  Ran: btrfs/255
+  Failures: btrfs/255
+  Failed 1 of 1 tests
+
+To fix this make the quota disable operation take the cleaner mutex, as
+relocation of a block group also takes this mutex. This is also what we
+do when deleting a subvolume/snapshot, we take the cleaner mutex in the
+cleaner kthread (at cleaner_kthread()) and then we call btrfs_del_root()
+at btrfs_drop_snapshot() while under the protection of the cleaner mutex.
+
+Fixes: bed92eae26cc ("Btrfs: qgroup implementation and prototypes")
+CC: stable@vger.kernel.org # 5.4+
+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/qgroup.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index d408d1dfde7c8..d46a070275ff5 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1201,12 +1201,23 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+       int ret = 0;
+       /*
+-       * We need to have subvol_sem write locked, to prevent races between
+-       * concurrent tasks trying to disable quotas, because we will unlock
+-       * and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
++       * We need to have subvol_sem write locked to prevent races with
++       * snapshot creation.
+        */
+       lockdep_assert_held_write(&fs_info->subvol_sem);
++      /*
++       * Lock the cleaner mutex to prevent races with concurrent relocation,
++       * because relocation may be building backrefs for blocks of the quota
++       * root while we are deleting the root. This is like dropping fs roots
++       * of deleted snapshots/subvolumes, we need the same protection.
++       *
++       * This also prevents races between concurrent tasks trying to disable
++       * quotas, because we will unlock and relock qgroup_ioctl_lock across
++       * BTRFS_FS_QUOTA_ENABLED changes.
++       */
++      mutex_lock(&fs_info->cleaner_mutex);
++
+       mutex_lock(&fs_info->qgroup_ioctl_lock);
+       if (!fs_info->quota_root)
+               goto out;
+@@ -1287,6 +1298,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+               btrfs_end_transaction(trans);
+       else if (trans)
+               ret = btrfs_end_transaction(trans);
++      mutex_unlock(&fs_info->cleaner_mutex);
+       return ret;
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.15/cifs-if-deferred-close-is-disabled-then-close-files-.patch b/queue-5.15/cifs-if-deferred-close-is-disabled-then-close-files-.patch
new file mode 100644 (file)
index 0000000..7c8ba36
--- /dev/null
@@ -0,0 +1,41 @@
+From 4f410636bcafe6febb64257cd99651160e10504a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Jul 2023 15:29:01 +0000
+Subject: cifs: if deferred close is disabled then close files immediately
+
+From: Bharath SM <bharathsm@microsoft.com>
+
+[ Upstream commit df9d70c18616760c6504b97fec66b6379c172dbb ]
+
+If defer close timeout value is set to 0, then there is no
+need to include files in the deferred close list and utilize
+the delayed worker for closing. Instead, we can close them
+immediately.
+
+Signed-off-by: Bharath SM <bharathsm@microsoft.com>
+Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/file.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index 4e4f73a90574b..e65fbae9e804b 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -880,8 +880,8 @@ int cifs_close(struct inode *inode, struct file *file)
+               cfile = file->private_data;
+               file->private_data = NULL;
+               dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
+-              if ((cinode->oplock == CIFS_CACHE_RHW_FLG) &&
+-                  cinode->lease_granted &&
++              if ((cifs_sb->ctx->closetimeo && cinode->oplock == CIFS_CACHE_RHW_FLG)
++                  && cinode->lease_granted &&
+                   !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags) &&
+                   dclose) {
+                       if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
+-- 
+2.39.2
+
diff --git a/queue-5.15/cifs-missing-directory-in-maintainers-file.patch b/queue-5.15/cifs-missing-directory-in-maintainers-file.patch
new file mode 100644 (file)
index 0000000..19b5993
--- /dev/null
@@ -0,0 +1,36 @@
+From 3113e3cbb7f24f98ee9c32672187cddbc3f24d1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 13 Aug 2022 17:22:11 -0500
+Subject: cifs: missing directory in MAINTAINERS file
+
+From: Steve French <stfrench@microsoft.com>
+
+[ Upstream commit 5dd8ce24667a70bb9f7808f5eec0354bd37290c6 ]
+
+The include/uapi/linux/cifs directory (not just fs/cifs and
+fs/smbfs_common) should be included in cifs entry in the
+MAINTAINERS file.
+
+Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: df9d70c18616 ("cifs: if deferred close is disabled then close files immediately")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ MAINTAINERS | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 2bf1ad0fb2a6f..e6b53e76651be 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4666,6 +4666,7 @@ T:       git git://git.samba.org/sfrench/cifs-2.6.git
+ F:    Documentation/admin-guide/cifs/
+ F:    fs/cifs/
+ F:    fs/smbfs_common/
++F:    include/uapi/linux/cifs
+ COMPACTPCI HOTPLUG CORE
+ M:    Scott Murray <scott@spiteful.org>
+-- 
+2.39.2
+
diff --git a/queue-5.15/cifs-use-fs_context-for-automounts.patch b/queue-5.15/cifs-use-fs_context-for-automounts.patch
new file mode 100644 (file)
index 0000000..34e060c
--- /dev/null
@@ -0,0 +1,168 @@
+From 6e997dc19578b44af9b5e3aea9152e7f5812e359 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Oct 2022 18:41:20 -0300
+Subject: cifs: use fs_context for automounts
+
+From: Paulo Alcantara <pc@cjr.nz>
+
+[ Upstream commit 9fd29a5bae6e8f94b410374099a6fddb253d2d5f ]
+
+Use filesystem context support to handle dfs links.
+
+Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: df9d70c18616 ("cifs: if deferred close is disabled then close files immediately")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/cifs_dfs_ref.c | 100 +++++++++++++++++------------------------
+ 1 file changed, 40 insertions(+), 60 deletions(-)
+
+diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
+index b0864da9ef434..020e71fe1454e 100644
+--- a/fs/cifs/cifs_dfs_ref.c
++++ b/fs/cifs/cifs_dfs_ref.c
+@@ -258,61 +258,23 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
+       goto compose_mount_options_out;
+ }
+-/**
+- * cifs_dfs_do_mount - mounts specified path using DFS full path
+- *
+- * Always pass down @fullpath to smb3_do_mount() so we can use the root server
+- * to perform failover in case we failed to connect to the first target in the
+- * referral.
+- *
+- * @mntpt:            directory entry for the path we are trying to automount
+- * @cifs_sb:          parent/root superblock
+- * @fullpath:         full path in UNC format
+- */
+-static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
+-                                        struct cifs_sb_info *cifs_sb,
+-                                        const char *fullpath)
+-{
+-      struct vfsmount *mnt;
+-      char *mountdata;
+-      char *devname;
+-
+-      devname = kstrdup(fullpath, GFP_KERNEL);
+-      if (!devname)
+-              return ERR_PTR(-ENOMEM);
+-
+-      convert_delimiter(devname, '/');
+-
+-      /* TODO: change to call fs_context_for_mount(), fill in context directly, call fc_mount */
+-
+-      /* See afs_mntpt_do_automount in fs/afs/mntpt.c for an example */
+-
+-      /* strip first '\' from fullpath */
+-      mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
+-                                             fullpath + 1, NULL, NULL);
+-      if (IS_ERR(mountdata)) {
+-              kfree(devname);
+-              return (struct vfsmount *)mountdata;
+-      }
+-
+-      mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
+-      kfree(mountdata);
+-      kfree(devname);
+-      return mnt;
+-}
+-
+ /*
+  * Create a vfsmount that we can automount
+  */
+-static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
++static struct vfsmount *cifs_dfs_do_automount(struct path *path)
+ {
++      int rc;
++      struct dentry *mntpt = path->dentry;
++      struct fs_context *fc;
+       struct cifs_sb_info *cifs_sb;
+-      void *page;
++      void *page = NULL;
++      struct smb3_fs_context *ctx, *cur_ctx;
++      struct smb3_fs_context tmp;
+       char *full_path;
+       struct vfsmount *mnt;
+-      cifs_dbg(FYI, "in %s\n", __func__);
+-      BUG_ON(IS_ROOT(mntpt));
++      if (IS_ROOT(mntpt))
++              return ERR_PTR(-ESTALE);
+       /*
+        * The MSDFS spec states that paths in DFS referral requests and
+@@ -321,29 +283,47 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
+        * gives us the latter, so we must adjust the result.
+        */
+       cifs_sb = CIFS_SB(mntpt->d_sb);
+-      if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
+-              mnt = ERR_PTR(-EREMOTE);
+-              goto cdda_exit;
+-      }
++      if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
++              return ERR_PTR(-EREMOTE);
++
++      cur_ctx = cifs_sb->ctx;
++
++      fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
++      if (IS_ERR(fc))
++              return ERR_CAST(fc);
++
++      ctx = smb3_fc2context(fc);
+       page = alloc_dentry_path();
+       /* always use tree name prefix */
+       full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
+       if (IS_ERR(full_path)) {
+               mnt = ERR_CAST(full_path);
+-              goto free_full_path;
++              goto out;
+       }
+-      convert_delimiter(full_path, '\\');
++      convert_delimiter(full_path, '/');
+       cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
+-      mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
+-      cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
++      tmp = *cur_ctx;
++      tmp.source = full_path;
++      tmp.UNC = tmp.prepath = NULL;
++
++      rc = smb3_fs_context_dup(ctx, &tmp);
++      if (rc) {
++              mnt = ERR_PTR(rc);
++              goto out;
++      }
++
++      rc = smb3_parse_devname(full_path, ctx);
++      if (!rc)
++              mnt = fc_mount(fc);
++      else
++              mnt = ERR_PTR(rc);
+-free_full_path:
++out:
++      put_fs_context(fc);
+       free_dentry_path(page);
+-cdda_exit:
+-      cifs_dbg(FYI, "leaving %s\n" , __func__);
+       return mnt;
+ }
+@@ -354,9 +334,9 @@ struct vfsmount *cifs_dfs_d_automount(struct path *path)
+ {
+       struct vfsmount *newmnt;
+-      cifs_dbg(FYI, "in %s\n", __func__);
++      cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
+-      newmnt = cifs_dfs_do_automount(path->dentry);
++      newmnt = cifs_dfs_do_automount(path);
+       if (IS_ERR(newmnt)) {
+               cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
+               return newmnt;
+-- 
+2.39.2
+
diff --git a/queue-5.15/dlm-cleanup-plock_op-vs-plock_xop.patch b/queue-5.15/dlm-cleanup-plock_op-vs-plock_xop.patch
new file mode 100644 (file)
index 0000000..e8bc5a8
--- /dev/null
@@ -0,0 +1,233 @@
+From cd247b5ace431ae27ed84f2a1571d879c2ba1164 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Apr 2022 16:06:32 -0400
+Subject: dlm: cleanup plock_op vs plock_xop
+
+From: Alexander Aring <aahringo@redhat.com>
+
+[ Upstream commit bcbb4ba6c9ba81e6975b642a2cade68044cd8a66 ]
+
+Lately the different casting between plock_op and plock_xop and list
+holders which was involved showed some issues which were hard to see.
+This patch removes the "plock_xop" structure and introduces a
+"struct plock_async_data". This structure will be set in "struct plock_op"
+in case of asynchronous lock handling as the original "plock_xop" was
+made for. There is no need anymore to cast pointers around for
+additional fields in case of asynchronous lock handling.  As disadvantage
+another allocation was introduces but only needed in the asynchronous
+case which is currently only used in combination with nfs lockd.
+
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Stable-dep-of: 59e45c758ca1 ("fs: dlm: interrupt posix locks only when process is killed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/plock.c | 77 ++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 46 insertions(+), 31 deletions(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index edce0b25cd90e..e70e23eca03ec 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -19,20 +19,20 @@ static struct list_head recv_list;
+ static wait_queue_head_t send_wq;
+ static wait_queue_head_t recv_wq;
+-struct plock_op {
+-      struct list_head list;
+-      int done;
+-      struct dlm_plock_info info;
+-      int (*callback)(struct file_lock *fl, int result);
+-};
+-
+-struct plock_xop {
+-      struct plock_op xop;
++struct plock_async_data {
+       void *fl;
+       void *file;
+       struct file_lock flc;
++      int (*callback)(struct file_lock *fl, int result);
+ };
++struct plock_op {
++      struct list_head list;
++      int done;
++      struct dlm_plock_info info;
++      /* if set indicates async handling */
++      struct plock_async_data *data;
++};
+ static inline void set_version(struct dlm_plock_info *info)
+ {
+@@ -58,6 +58,12 @@ static int check_version(struct dlm_plock_info *info)
+       return 0;
+ }
++static void dlm_release_plock_op(struct plock_op *op)
++{
++      kfree(op->data);
++      kfree(op);
++}
++
+ static void send_op(struct plock_op *op)
+ {
+       set_version(&op->info);
+@@ -101,22 +107,21 @@ static void do_unlock_close(struct dlm_ls *ls, u64 number,
+ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+                  int cmd, struct file_lock *fl)
+ {
++      struct plock_async_data *op_data;
+       struct dlm_ls *ls;
+       struct plock_op *op;
+-      struct plock_xop *xop;
+       int rv;
+       ls = dlm_find_lockspace_local(lockspace);
+       if (!ls)
+               return -EINVAL;
+-      xop = kzalloc(sizeof(*xop), GFP_NOFS);
+-      if (!xop) {
++      op = kzalloc(sizeof(*op), GFP_NOFS);
++      if (!op) {
+               rv = -ENOMEM;
+               goto out;
+       }
+-      op = &xop->xop;
+       op->info.optype         = DLM_PLOCK_OP_LOCK;
+       op->info.pid            = fl->fl_pid;
+       op->info.ex             = (fl->fl_type == F_WRLCK);
+@@ -125,22 +130,32 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+       op->info.number         = number;
+       op->info.start          = fl->fl_start;
+       op->info.end            = fl->fl_end;
++      /* async handling */
+       if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
++              op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
++              if (!op_data) {
++                      dlm_release_plock_op(op);
++                      rv = -ENOMEM;
++                      goto out;
++              }
++
+               /* fl_owner is lockd which doesn't distinguish
+                  processes on the nfs client */
+               op->info.owner  = (__u64) fl->fl_pid;
+-              op->callback    = fl->fl_lmops->lm_grant;
+-              locks_init_lock(&xop->flc);
+-              locks_copy_lock(&xop->flc, fl);
+-              xop->fl         = fl;
+-              xop->file       = file;
++              op_data->callback = fl->fl_lmops->lm_grant;
++              locks_init_lock(&op_data->flc);
++              locks_copy_lock(&op_data->flc, fl);
++              op_data->fl             = fl;
++              op_data->file   = file;
++
++              op->data = op_data;
+       } else {
+               op->info.owner  = (__u64)(long) fl->fl_owner;
+       }
+       send_op(op);
+-      if (!op->callback) {
++      if (!op->data) {
+               rv = wait_event_interruptible(recv_wq, (op->done != 0));
+               if (rv == -ERESTARTSYS) {
+                       log_debug(ls, "dlm_posix_lock: wait killed %llx",
+@@ -148,7 +163,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+                       spin_lock(&ops_lock);
+                       list_del(&op->list);
+                       spin_unlock(&ops_lock);
+-                      kfree(xop);
++                      dlm_release_plock_op(op);
+                       do_unlock_close(ls, number, file, fl);
+                       goto out;
+               }
+@@ -173,7 +188,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+                                 (unsigned long long)number);
+       }
+-      kfree(xop);
++      dlm_release_plock_op(op);
+ out:
+       dlm_put_lockspace(ls);
+       return rv;
+@@ -183,11 +198,11 @@ EXPORT_SYMBOL_GPL(dlm_posix_lock);
+ /* Returns failure iff a successful lock operation should be canceled */
+ static int dlm_plock_callback(struct plock_op *op)
+ {
++      struct plock_async_data *op_data = op->data;
+       struct file *file;
+       struct file_lock *fl;
+       struct file_lock *flc;
+       int (*notify)(struct file_lock *fl, int result) = NULL;
+-      struct plock_xop *xop = (struct plock_xop *)op;
+       int rv = 0;
+       spin_lock(&ops_lock);
+@@ -199,10 +214,10 @@ static int dlm_plock_callback(struct plock_op *op)
+       spin_unlock(&ops_lock);
+       /* check if the following 2 are still valid or make a copy */
+-      file = xop->file;
+-      flc = &xop->flc;
+-      fl = xop->fl;
+-      notify = op->callback;
++      file = op_data->file;
++      flc = &op_data->flc;
++      fl = op_data->fl;
++      notify = op_data->callback;
+       if (op->info.rv) {
+               notify(fl, op->info.rv);
+@@ -233,7 +248,7 @@ static int dlm_plock_callback(struct plock_op *op)
+       }
+ out:
+-      kfree(xop);
++      dlm_release_plock_op(op);
+       return rv;
+ }
+@@ -303,7 +318,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+               rv = 0;
+ out_free:
+-      kfree(op);
++      dlm_release_plock_op(op);
+ out:
+       dlm_put_lockspace(ls);
+       fl->fl_flags = fl_flags;
+@@ -371,7 +386,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+               rv = 0;
+       }
+-      kfree(op);
++      dlm_release_plock_op(op);
+ out:
+       dlm_put_lockspace(ls);
+       return rv;
+@@ -407,7 +422,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
+          (the process did not make an unlock call). */
+       if (op->info.flags & DLM_PLOCK_FL_CLOSE)
+-              kfree(op);
++              dlm_release_plock_op(op);
+       if (copy_to_user(u, &info, sizeof(info)))
+               return -EFAULT;
+@@ -439,7 +454,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
+                   op->info.owner == info.owner) {
+                       list_del_init(&op->list);
+                       memcpy(&op->info, &info, sizeof(info));
+-                      if (op->callback)
++                      if (op->data)
+                               do_callback = 1;
+                       else
+                               op->done = 1;
+-- 
+2.39.2
+
diff --git a/queue-5.15/dlm-rearrange-async-condition-return.patch b/queue-5.15/dlm-rearrange-async-condition-return.patch
new file mode 100644 (file)
index 0000000..e2a6029
--- /dev/null
@@ -0,0 +1,67 @@
+From 9171eb97c29452e232caa4b44526dffa6e515757 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Apr 2022 16:06:33 -0400
+Subject: dlm: rearrange async condition return
+
+From: Alexander Aring <aahringo@redhat.com>
+
+[ Upstream commit a800ba77fd285c6391a82819867ac64e9ab3af46 ]
+
+This patch moves the return of FILE_LOCK_DEFERRED a little bit earlier
+than checking afterwards again if the request was an asynchronous request.
+
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Stable-dep-of: 59e45c758ca1 ("fs: dlm: interrupt posix locks only when process is killed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/plock.c | 27 +++++++++++++--------------
+ 1 file changed, 13 insertions(+), 14 deletions(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index e70e23eca03ec..01fb7d8c0bca5 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -149,26 +149,25 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+               op_data->file   = file;
+               op->data = op_data;
++
++              send_op(op);
++              rv = FILE_LOCK_DEFERRED;
++              goto out;
+       } else {
+               op->info.owner  = (__u64)(long) fl->fl_owner;
+       }
+       send_op(op);
+-      if (!op->data) {
+-              rv = wait_event_interruptible(recv_wq, (op->done != 0));
+-              if (rv == -ERESTARTSYS) {
+-                      log_debug(ls, "dlm_posix_lock: wait killed %llx",
+-                                (unsigned long long)number);
+-                      spin_lock(&ops_lock);
+-                      list_del(&op->list);
+-                      spin_unlock(&ops_lock);
+-                      dlm_release_plock_op(op);
+-                      do_unlock_close(ls, number, file, fl);
+-                      goto out;
+-              }
+-      } else {
+-              rv = FILE_LOCK_DEFERRED;
++      rv = wait_event_interruptible(recv_wq, (op->done != 0));
++      if (rv == -ERESTARTSYS) {
++              log_debug(ls, "%s: wait killed %llx", __func__,
++                        (unsigned long long)number);
++              spin_lock(&ops_lock);
++              list_del(&op->list);
++              spin_unlock(&ops_lock);
++              dlm_release_plock_op(op);
++              do_unlock_close(ls, number, file, fl);
+               goto out;
+       }
+-- 
+2.39.2
+
diff --git a/queue-5.15/drm-amdgpu-fix-vkms-crtc-settings.patch b/queue-5.15/drm-amdgpu-fix-vkms-crtc-settings.patch
new file mode 100644 (file)
index 0000000..84a1fdf
--- /dev/null
@@ -0,0 +1,168 @@
+From cb0e3d168f003d982d765720240b875c61a43964 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Nov 2021 10:34:57 +0800
+Subject: drm/amdgpu: fix vkms crtc settings
+
+From: Flora Cui <flora.cui@amd.com>
+
+[ Upstream commit deefd07eedb7baa25956c8365373e6a58c81565a ]
+
+otherwise adev->mode_info.crtcs[] is NULL
+
+Signed-off-by: Flora Cui <flora.cui@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: b42ae87a7b38 ("drm/amdgpu/vkms: relax timer deactivation by hrtimer_try_to_cancel")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 42 ++++++++++++++++--------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h |  5 ++-
+ 2 files changed, 30 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+index 7d58bf410be05..24251cdf95073 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+@@ -16,6 +16,8 @@
+ #include "ivsrcid/ivsrcid_vislands30.h"
+ #include "amdgpu_vkms.h"
+ #include "amdgpu_display.h"
++#include "atom.h"
++#include "amdgpu_irq.h"
+ /**
+  * DOC: amdgpu_vkms
+@@ -41,14 +43,13 @@ static const u32 amdgpu_vkms_formats[] = {
+ static enum hrtimer_restart amdgpu_vkms_vblank_simulate(struct hrtimer *timer)
+ {
+-      struct amdgpu_vkms_output *output = container_of(timer,
+-                                                       struct amdgpu_vkms_output,
+-                                                       vblank_hrtimer);
+-      struct drm_crtc *crtc = &output->crtc;
++      struct amdgpu_crtc *amdgpu_crtc = container_of(timer, struct amdgpu_crtc, vblank_timer);
++      struct drm_crtc *crtc = &amdgpu_crtc->base;
++      struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);
+       u64 ret_overrun;
+       bool ret;
+-      ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
++      ret_overrun = hrtimer_forward_now(&amdgpu_crtc->vblank_timer,
+                                         output->period_ns);
+       WARN_ON(ret_overrun != 1);
+@@ -65,22 +66,21 @@ static int amdgpu_vkms_enable_vblank(struct drm_crtc *crtc)
+       unsigned int pipe = drm_crtc_index(crtc);
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+       struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);
++      struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       drm_calc_timestamping_constants(crtc, &crtc->mode);
+-      hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+-      out->vblank_hrtimer.function = &amdgpu_vkms_vblank_simulate;
+       out->period_ns = ktime_set(0, vblank->framedur_ns);
+-      hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL);
++      hrtimer_start(&amdgpu_crtc->vblank_timer, out->period_ns, HRTIMER_MODE_REL);
+       return 0;
+ }
+ static void amdgpu_vkms_disable_vblank(struct drm_crtc *crtc)
+ {
+-      struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);
++      struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+-      hrtimer_cancel(&out->vblank_hrtimer);
++      hrtimer_cancel(&amdgpu_crtc->vblank_timer);
+ }
+ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
+@@ -92,13 +92,14 @@ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
+       unsigned int pipe = crtc->index;
+       struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);
+       struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
++      struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       if (!READ_ONCE(vblank->enabled)) {
+               *vblank_time = ktime_get();
+               return true;
+       }
+-      *vblank_time = READ_ONCE(output->vblank_hrtimer.node.expires);
++      *vblank_time = READ_ONCE(amdgpu_crtc->vblank_timer.node.expires);
+       if (WARN_ON(*vblank_time == vblank->time))
+               return true;
+@@ -166,6 +167,8 @@ static const struct drm_crtc_helper_funcs amdgpu_vkms_crtc_helper_funcs = {
+ static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                         struct drm_plane *primary, struct drm_plane *cursor)
+ {
++      struct amdgpu_device *adev = drm_to_adev(dev);
++      struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       int ret;
+       ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,
+@@ -177,6 +180,17 @@ static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+       drm_crtc_helper_add(crtc, &amdgpu_vkms_crtc_helper_funcs);
++      amdgpu_crtc->crtc_id = drm_crtc_index(crtc);
++      adev->mode_info.crtcs[drm_crtc_index(crtc)] = amdgpu_crtc;
++
++      amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
++      amdgpu_crtc->encoder = NULL;
++      amdgpu_crtc->connector = NULL;
++      amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
++
++      hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++      amdgpu_crtc->vblank_timer.function = &amdgpu_vkms_vblank_simulate;
++
+       return ret;
+ }
+@@ -402,7 +416,7 @@ int amdgpu_vkms_output_init(struct drm_device *dev,
+ {
+       struct drm_connector *connector = &output->connector;
+       struct drm_encoder *encoder = &output->encoder;
+-      struct drm_crtc *crtc = &output->crtc;
++      struct drm_crtc *crtc = &output->crtc.base;
+       struct drm_plane *primary, *cursor = NULL;
+       int ret;
+@@ -505,8 +519,8 @@ static int amdgpu_vkms_sw_fini(void *handle)
+       int i = 0;
+       for (i = 0; i < adev->mode_info.num_crtc; i++)
+-              if (adev->amdgpu_vkms_output[i].vblank_hrtimer.function)
+-                      hrtimer_cancel(&adev->amdgpu_vkms_output[i].vblank_hrtimer);
++              if (adev->mode_info.crtcs[i])
++                      hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer);
+       kfree(adev->mode_info.bios_hardcoded_edid);
+       kfree(adev->amdgpu_vkms_output);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h
+index 97f1b79c0724e..4f8722ff37c25 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h
+@@ -10,15 +10,14 @@
+ #define YRES_MAX  16384
+ #define drm_crtc_to_amdgpu_vkms_output(target) \
+-      container_of(target, struct amdgpu_vkms_output, crtc)
++      container_of(target, struct amdgpu_vkms_output, crtc.base)
+ extern const struct amdgpu_ip_block_version amdgpu_vkms_ip_block;
+ struct amdgpu_vkms_output {
+-      struct drm_crtc crtc;
++      struct amdgpu_crtc crtc;
+       struct drm_encoder encoder;
+       struct drm_connector connector;
+-      struct hrtimer vblank_hrtimer;
+       ktime_t period_ns;
+       struct drm_pending_vblank_event *event;
+ };
+-- 
+2.39.2
+
diff --git a/queue-5.15/drm-amdgpu-vkms-relax-timer-deactivation-by-hrtimer_.patch b/queue-5.15/drm-amdgpu-vkms-relax-timer-deactivation-by-hrtimer_.patch
new file mode 100644 (file)
index 0000000..8cc1ae9
--- /dev/null
@@ -0,0 +1,106 @@
+From 2291d9f1bcb49b557c2877157eaa2d6bc91da1d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Jul 2023 15:57:21 +0800
+Subject: drm/amdgpu/vkms: relax timer deactivation by hrtimer_try_to_cancel
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guchun Chen <guchun.chen@amd.com>
+
+[ Upstream commit b42ae87a7b3878afaf4c3852ca66c025a5b996e0 ]
+
+In below thousands of screen rotation loop tests with virtual display
+enabled, a CPU hard lockup issue may happen, leading system to unresponsive
+and crash.
+
+do {
+       xrandr --output Virtual --rotate inverted
+       xrandr --output Virtual --rotate right
+       xrandr --output Virtual --rotate left
+       xrandr --output Virtual --rotate normal
+} while (1);
+
+NMI watchdog: Watchdog detected hard LOCKUP on cpu 1
+
+? hrtimer_run_softirq+0x140/0x140
+? store_vblank+0xe0/0xe0 [drm]
+hrtimer_cancel+0x15/0x30
+amdgpu_vkms_disable_vblank+0x15/0x30 [amdgpu]
+drm_vblank_disable_and_save+0x185/0x1f0 [drm]
+drm_crtc_vblank_off+0x159/0x4c0 [drm]
+? record_print_text.cold+0x11/0x11
+? wait_for_completion_timeout+0x232/0x280
+? drm_crtc_wait_one_vblank+0x40/0x40 [drm]
+? bit_wait_io_timeout+0xe0/0xe0
+? wait_for_completion_interruptible+0x1d7/0x320
+? mutex_unlock+0x81/0xd0
+amdgpu_vkms_crtc_atomic_disable
+
+It's caused by a stuck in lock dependency in such scenario on different
+CPUs.
+
+CPU1                                             CPU2
+drm_crtc_vblank_off                              hrtimer_interrupt
+    grab event_lock (irq disabled)                   __hrtimer_run_queues
+        grab vbl_lock/vblank_time_block                  amdgpu_vkms_vblank_simulate
+            amdgpu_vkms_disable_vblank                       drm_handle_vblank
+                hrtimer_cancel                                         grab dev->event_lock
+
+So CPU1 stucks in hrtimer_cancel as timer callback is running endless on
+current clock base, as that timer queue on CPU2 has no chance to finish it
+because of failing to hold the lock. So NMI watchdog will throw the errors
+after its threshold, and all later CPUs are impacted/blocked.
+
+So use hrtimer_try_to_cancel to fix this, as disable_vblank callback
+does not need to wait the handler to finish. And also it's not necessary
+to check the return value of hrtimer_try_to_cancel, because even if it's
+-1 which means current timer callback is running, it will be reprogrammed
+in hrtimer_start with calling enable_vblank to make it works.
+
+v2: only re-arm timer when vblank is enabled (Christian) and add a Fixes
+tag as well
+
+v3: drop warn printing (Christian)
+
+v4: drop superfluous check of blank->enabled in timer function, as it's
+guaranteed in drm_handle_vblank (Christian)
+
+Fixes: 84ec374bd580 ("drm/amdgpu: create amdgpu_vkms (v4)")
+Cc: stable@vger.kernel.org
+Suggested-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Guchun Chen <guchun.chen@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+index 24251cdf95073..4e8274de8fc0c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+@@ -54,8 +54,9 @@ static enum hrtimer_restart amdgpu_vkms_vblank_simulate(struct hrtimer *timer)
+       WARN_ON(ret_overrun != 1);
+       ret = drm_crtc_handle_vblank(crtc);
++      /* Don't queue timer again when vblank is disabled. */
+       if (!ret)
+-              DRM_ERROR("amdgpu_vkms failure on handling vblank");
++              return HRTIMER_NORESTART;
+       return HRTIMER_RESTART;
+ }
+@@ -80,7 +81,7 @@ static void amdgpu_vkms_disable_vblank(struct drm_crtc *crtc)
+ {
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+-      hrtimer_cancel(&amdgpu_crtc->vblank_timer);
++      hrtimer_try_to_cancel(&amdgpu_crtc->vblank_timer);
+ }
+ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
+-- 
+2.39.2
+
diff --git a/queue-5.15/drm-ttm-don-t-leak-a-resource-on-eviction-error.patch b/queue-5.15/drm-ttm-don-t-leak-a-resource-on-eviction-error.patch
new file mode 100644 (file)
index 0000000..6fef51c
--- /dev/null
@@ -0,0 +1,72 @@
+From cb49f8d791c2603eb5da6e5bbdbf36dcc53d37d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Jun 2023 11:14:49 +0200
+Subject: drm/ttm: Don't leak a resource on eviction error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit e8188c461ee015ba0b9ab2fc82dbd5ebca5a5532 ]
+
+On eviction errors other than -EMULTIHOP we were leaking a resource.
+Fix.
+
+v2:
+- Avoid yet another goto (Andi Shyti)
+
+Fixes: 403797925768 ("drm/ttm: Fix multihop assert on eviction.")
+Cc: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: Christian Koenig <christian.koenig@amd.com>
+Cc: Huang Rui <ray.huang@amd.com>
+Cc: dri-devel@lists.freedesktop.org
+Cc: <stable@vger.kernel.org> # v5.15+
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Nirmoy Das <nirmoy.das@intel.com> #v1
+Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20230626091450.14757-4-thomas.hellstrom@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index cf390ab636978..6080f4b5c450c 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -552,18 +552,18 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
+               goto out;
+       }
+-bounce:
+-      ret = ttm_bo_handle_move_mem(bo, evict_mem, true, ctx, &hop);
+-      if (ret == -EMULTIHOP) {
++      do {
++              ret = ttm_bo_handle_move_mem(bo, evict_mem, true, ctx, &hop);
++              if (ret != -EMULTIHOP)
++                      break;
++
+               ret = ttm_bo_bounce_temp_buffer(bo, &evict_mem, ctx, &hop);
+-              if (ret) {
+-                      if (ret != -ERESTARTSYS && ret != -EINTR)
+-                              pr_err("Buffer eviction failed\n");
+-                      ttm_resource_free(bo, &evict_mem);
+-                      goto out;
+-              }
+-              /* try and move to final place now. */
+-              goto bounce;
++      } while (!ret);
++
++      if (ret) {
++              ttm_resource_free(bo, &evict_mem);
++              if (ret != -ERESTARTSYS && ret != -EINTR)
++                      pr_err("Buffer eviction failed\n");
+       }
+ out:
+       return ret;
+-- 
+2.39.2
+
diff --git a/queue-5.15/drm-ttm-don-t-print-error-message-if-eviction-was-in.patch b/queue-5.15/drm-ttm-don-t-print-error-message-if-eviction-was-in.patch
new file mode 100644 (file)
index 0000000..d7e2867
--- /dev/null
@@ -0,0 +1,42 @@
+From cfdc82035adbf6df02439a902bf16a5f19898007 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Mar 2023 15:46:19 +0100
+Subject: drm/ttm: Don't print error message if eviction was interrupted
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit 8ab3b0663e279ab550bc2c0b5d602960e8b94e02 ]
+
+Avoid printing an error message if eviction was interrupted by,
+for example, the user pressing CTRL-C. That may happen if eviction
+is waiting for something, like for example a free batch-buffer.
+
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20230307144621.10748-6-thomas.hellstrom@linux.intel.com
+Stable-dep-of: e8188c461ee0 ("drm/ttm: Don't leak a resource on eviction error")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index d5a2b69489e7f..cf390ab636978 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -557,7 +557,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
+       if (ret == -EMULTIHOP) {
+               ret = ttm_bo_bounce_temp_buffer(bo, &evict_mem, ctx, &hop);
+               if (ret) {
+-                      pr_err("Buffer eviction failed\n");
++                      if (ret != -ERESTARTSYS && ret != -EINTR)
++                              pr_err("Buffer eviction failed\n");
+                       ttm_resource_free(bo, &evict_mem);
+                       goto out;
+               }
+-- 
+2.39.2
+
diff --git a/queue-5.15/drm-ttm-never-consider-pinned-bos-for-eviction-swap.patch b/queue-5.15/drm-ttm-never-consider-pinned-bos-for-eviction-swap.patch
new file mode 100644 (file)
index 0000000..7d73b94
--- /dev/null
@@ -0,0 +1,46 @@
+From f050822f2bc5bdcf55c3259f2428a89feeba62d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Jul 2023 11:25:00 +0200
+Subject: drm/ttm: never consider pinned BOs for eviction&swap
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit a2848d08742c8e8494675892c02c0d22acbe3cf8 ]
+
+There is a small window where we have already incremented the pin count
+but not yet moved the bo from the lru to the pinned list.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Reported-by: Pelloux-Prayer, Pierre-Eric <Pierre-eric.Pelloux-prayer@amd.com>
+Tested-by: Pelloux-Prayer, Pierre-Eric <Pierre-eric.Pelloux-prayer@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Link: https://patchwork.freedesktop.org/patch/msgid/20230707120826.3701-1-christian.koenig@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index 6080f4b5c450c..4d0ef5ab25319 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -604,6 +604,12 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
+ {
+       bool ret = false;
++      if (bo->pin_count) {
++              *locked = false;
++              *busy = false;
++              return false;
++      }
++
+       if (bo->base.resv == ctx->resv) {
+               dma_resv_assert_held(bo->base.resv);
+               if (ctx->allow_res_evict)
+-- 
+2.39.2
+
diff --git a/queue-5.15/fs-dlm-interrupt-posix-locks-only-when-process-is-ki.patch b/queue-5.15/fs-dlm-interrupt-posix-locks-only-when-process-is-ki.patch
new file mode 100644 (file)
index 0000000..6becf6a
--- /dev/null
@@ -0,0 +1,44 @@
+From 72ce2ba1a355dc0d473cf395f58a8b1d94e376b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 May 2023 11:21:26 -0400
+Subject: fs: dlm: interrupt posix locks only when process is killed
+
+From: Alexander Aring <aahringo@redhat.com>
+
+[ Upstream commit 59e45c758ca1b9893ac923dd63536da946ac333b ]
+
+If a posix lock request is waiting for a result from user space
+(dlm_controld), do not let it be interrupted unless the process
+is killed. This reverts commit a6b1533e9a57 ("dlm: make posix locks
+interruptible"). The problem with the interruptible change is
+that all locks were cleared on any signal interrupt. If a signal
+was received that did not terminate the process, the process
+could continue running after all its dlm posix locks had been
+cleared. A future patch will add cancelation to allow proper
+interruption.
+
+Cc: stable@vger.kernel.org
+Fixes: a6b1533e9a57 ("dlm: make posix locks interruptible")
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/plock.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index 01fb7d8c0bca5..f3482e936cc25 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -159,7 +159,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+       send_op(op);
+-      rv = wait_event_interruptible(recv_wq, (op->done != 0));
++      rv = wait_event_killable(recv_wq, (op->done != 0));
+       if (rv == -ERESTARTSYS) {
+               log_debug(ls, "%s: wait killed %llx", __func__,
+                         (unsigned long long)number);
+-- 
+2.39.2
+
diff --git a/queue-5.15/gpio-mvebu-fix-irq-domain-leak.patch b/queue-5.15/gpio-mvebu-fix-irq-domain-leak.patch
new file mode 100644 (file)
index 0000000..9abb393
--- /dev/null
@@ -0,0 +1,77 @@
+From 4b97e0208a504563b54b58de395f48e95caf4f3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Jul 2023 13:41:01 +0200
+Subject: gpio: mvebu: fix irq domain leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 644ee70267a934be27370f9aa618b29af7290544 ]
+
+Uwe Kleine-König pointed out we still have one resource leak in the mvebu
+driver triggered on driver detach. Let's address it with a custom devm
+action.
+
+Fixes: 812d47889a8e ("gpio/mvebu: Use irq_domain_add_linear")
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mvebu.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index 4d64b3358c50c..b965513f44fea 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -1112,6 +1112,13 @@ static int mvebu_gpio_probe_syscon(struct platform_device *pdev,
+       return 0;
+ }
++static void mvebu_gpio_remove_irq_domain(void *data)
++{
++      struct irq_domain *domain = data;
++
++      irq_domain_remove(domain);
++}
++
+ static int mvebu_gpio_probe(struct platform_device *pdev)
+ {
+       struct mvebu_gpio_chip *mvchip;
+@@ -1247,13 +1254,18 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+               return -ENODEV;
+       }
++      err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain,
++                                     mvchip->domain);
++      if (err)
++              return err;
++
+       err = irq_alloc_domain_generic_chips(
+           mvchip->domain, ngpios, 2, np->name, handle_level_irq,
+           IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+       if (err) {
+               dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
+                       mvchip->chip.label);
+-              goto err_domain;
++              return err;
+       }
+       /*
+@@ -1293,10 +1305,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+       }
+       return 0;
+-
+-err_domain:
+-      irq_domain_remove(mvchip->domain);
+-      return err;
+ }
+ static struct platform_driver mvebu_gpio_driver = {
+-- 
+2.39.2
+
diff --git a/queue-5.15/gpio-mvebu-make-use-of-devm_pwmchip_add.patch b/queue-5.15/gpio-mvebu-make-use-of-devm_pwmchip_add.patch
new file mode 100644 (file)
index 0000000..a0df535
--- /dev/null
@@ -0,0 +1,61 @@
+From 4f63c883d0b08e81d08ca9e9f9473ad6abaac935 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Jul 2023 16:27:43 +0200
+Subject: gpio: mvebu: Make use of devm_pwmchip_add
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 1945063eb59e64d2919cb14d54d081476d9e53bb ]
+
+This allows to get rid of a call to pwmchip_remove() in the error path. There
+is no .remove function for this driver, so this change fixes a resource leak
+when a gpio-mvebu device is unbound.
+
+Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Andy Shevchenko <andy@kernel.org>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mvebu.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index a245bfd5a6173..4d64b3358c50c 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -874,7 +874,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
+       spin_lock_init(&mvpwm->lock);
+-      return pwmchip_add(&mvpwm->chip);
++      return devm_pwmchip_add(dev, &mvpwm->chip);
+ }
+ #ifdef CONFIG_DEBUG_FS
+@@ -1244,8 +1244,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+       if (!mvchip->domain) {
+               dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
+                       mvchip->chip.label);
+-              err = -ENODEV;
+-              goto err_pwm;
++              return -ENODEV;
+       }
+       err = irq_alloc_domain_generic_chips(
+@@ -1297,9 +1296,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ err_domain:
+       irq_domain_remove(mvchip->domain);
+-err_pwm:
+-      pwmchip_remove(&mvchip->mvpwm->chip);
+-
+       return err;
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.15/gpio-tps68470-make-tps68470_gpio_output-always-set-t.patch b/queue-5.15/gpio-tps68470-make-tps68470_gpio_output-always-set-t.patch
new file mode 100644 (file)
index 0000000..2478181
--- /dev/null
@@ -0,0 +1,50 @@
+From 5a7247b05210fcc9f1ecad601dcfcc57db3e0cf4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jul 2023 14:34:25 +0200
+Subject: gpio: tps68470: Make tps68470_gpio_output() always set the initial
+ value
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit 5a7adc6c1069ce31ef4f606ae9c05592c80a6ab5 ]
+
+Make tps68470_gpio_output() call tps68470_gpio_set() for output-only pins
+too, so that the initial value passed to gpiod_direction_output() is
+honored for these pins too.
+
+Fixes: 275b13a65547 ("gpio: Add support for TPS68470 GPIOs")
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
+Tested-by: Daniel Scally <dan.scally@ideasonboard.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-tps68470.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c
+index 423b7bc30ae88..03a523a6d6fa4 100644
+--- a/drivers/gpio/gpio-tps68470.c
++++ b/drivers/gpio/gpio-tps68470.c
+@@ -91,13 +91,13 @@ static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset,
+       struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
+       struct regmap *regmap = tps68470_gpio->tps68470_regmap;
++      /* Set the initial value */
++      tps68470_gpio_set(gc, offset, value);
++
+       /* rest are always outputs */
+       if (offset >= TPS68470_N_REGULAR_GPIO)
+               return 0;
+-      /* Set the initial value */
+-      tps68470_gpio_set(gc, offset, value);
+-
+       return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset),
+                                TPS68470_GPIO_MODE_MASK,
+                                TPS68470_GPIO_MODE_OUT_CMOS);
+-- 
+2.39.2
+
diff --git a/queue-5.15/i2c-delete-error-messages-for-failed-memory-allocati.patch b/queue-5.15/i2c-delete-error-messages-for-failed-memory-allocati.patch
new file mode 100644 (file)
index 0000000..5d200db
--- /dev/null
@@ -0,0 +1,81 @@
+From 09e26e1759387dfdab7326d4ba381b1f2dddf771 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2018 17:24:57 +0100
+Subject: i2c: Delete error messages for failed memory allocations
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit 6b3b21a8542fd2fb6ffc61bc13b9419f0c58ebad ]
+
+These issues were detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-ibm_iic.c  | 4 +---
+ drivers/i2c/busses/i2c-nomadik.c  | 1 -
+ drivers/i2c/busses/i2c-sh7760.c   | 1 -
+ drivers/i2c/busses/i2c-tiny-usb.c | 4 +---
+ 4 files changed, 2 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
+index 9f71daf6db64b..c073f5b8833a2 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.c
++++ b/drivers/i2c/busses/i2c-ibm_iic.c
+@@ -694,10 +694,8 @@ static int iic_probe(struct platform_device *ofdev)
+       int ret;
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+-      if (!dev) {
+-              dev_err(&ofdev->dev, "failed to allocate device data\n");
++      if (!dev)
+               return -ENOMEM;
+-      }
+       platform_set_drvdata(ofdev, dev);
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index a2d12a5b1c34c..05eaae5aeb180 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -972,7 +972,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+       dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+       if (!dev) {
+-              dev_err(&adev->dev, "cannot allocate memory\n");
+               ret = -ENOMEM;
+               goto err_no_mem;
+       }
+diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
+index 319d1fa617c88..a0ccc5d009874 100644
+--- a/drivers/i2c/busses/i2c-sh7760.c
++++ b/drivers/i2c/busses/i2c-sh7760.c
+@@ -445,7 +445,6 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
+       id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+       if (!id) {
+-              dev_err(&pdev->dev, "no mem for private data\n");
+               ret = -ENOMEM;
+               goto out0;
+       }
+diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
+index 7279ca0eaa2d0..d1fa9ff5aeab4 100644
+--- a/drivers/i2c/busses/i2c-tiny-usb.c
++++ b/drivers/i2c/busses/i2c-tiny-usb.c
+@@ -226,10 +226,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+-      if (dev == NULL) {
+-              dev_err(&interface->dev, "Out of memory\n");
++      if (!dev)
+               goto error;
+-      }
+       dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+       dev->interface = interface;
+-- 
+2.39.2
+
diff --git a/queue-5.15/i2c-improve-size-determinations.patch b/queue-5.15/i2c-improve-size-determinations.patch
new file mode 100644 (file)
index 0000000..391f411
--- /dev/null
@@ -0,0 +1,54 @@
+From 50ea2a0b7ebd12da80211ce37177e490e2e056c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2018 14:50:09 +0100
+Subject: i2c: Improve size determinations
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit 06e989578232da33a7fe96b04191b862af8b2cec ]
+
+Replace the specification of a data structure by a pointer dereference
+as the parameter for the operator "sizeof" to make the corresponding
+size determination a bit safer according to the Linux coding style
+convention.
+
+This issue was detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 2 +-
+ drivers/i2c/busses/i2c-sh7760.c  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 05eaae5aeb180..5004b9dd98563 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -970,7 +970,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+       struct i2c_vendor_data *vendor = id->data;
+       u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+-      dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
++      dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               ret = -ENOMEM;
+               goto err_no_mem;
+diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
+index a0ccc5d009874..051b904cb35f6 100644
+--- a/drivers/i2c/busses/i2c-sh7760.c
++++ b/drivers/i2c/busses/i2c-sh7760.c
+@@ -443,7 +443,7 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
+               goto out0;
+       }
+-      id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
++      id = kzalloc(sizeof(*id), GFP_KERNEL);
+       if (!id) {
+               ret = -ENOMEM;
+               goto out0;
+-- 
+2.39.2
+
diff --git a/queue-5.15/i2c-nomadik-remove-a-useless-call-in-the-remove-func.patch b/queue-5.15/i2c-nomadik-remove-a-useless-call-in-the-remove-func.patch
new file mode 100644 (file)
index 0000000..53ed310
--- /dev/null
@@ -0,0 +1,49 @@
+From 34a60f664ab617a1caf611af6355eeb3b51a9f0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jul 2023 21:50:28 +0200
+Subject: i2c: nomadik: Remove a useless call in the remove function
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 05f933d5f7318b03ff2028c1704dc867ac16f2c7 ]
+
+Since commit 235602146ec9 ("i2c-nomadik: turn the platform driver to an amba
+driver"), there is no more request_mem_region() call in this driver.
+
+So remove the release_mem_region() call from the remove function which is
+likely a left over.
+
+Fixes: 235602146ec9 ("i2c-nomadik: turn the platform driver to an amba driver")
+Cc: <stable@vger.kernel.org> # v3.6+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 2141ba05dfece..9c5d66bd6dc1c 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -1040,7 +1040,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ static void nmk_i2c_remove(struct amba_device *adev)
+ {
+-      struct resource *res = &adev->res;
+       struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
+       i2c_del_adapter(&dev->adap);
+@@ -1049,7 +1048,6 @@ static void nmk_i2c_remove(struct amba_device *adev)
+       clear_all_interrupts(dev);
+       /* disable the controller */
+       i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+-      release_mem_region(res->start, resource_size(res));
+ }
+ static struct i2c_vendor_data vendor_stn8815 = {
+-- 
+2.39.2
+
diff --git a/queue-5.15/i2c-nomadik-remove-unnecessary-goto-label.patch b/queue-5.15/i2c-nomadik-remove-unnecessary-goto-label.patch
new file mode 100644 (file)
index 0000000..1f8328d
--- /dev/null
@@ -0,0 +1,85 @@
+From 655c28066fa458bcb6ff3a4a156e7494256f2041 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Jun 2023 03:36:59 +0200
+Subject: i2c: nomadik: Remove unnecessary goto label
+
+From: Andi Shyti <andi.shyti@kernel.org>
+
+[ Upstream commit 1c5d33fff0d375e4ab7c4261dc62a286babbb4c6 ]
+
+The err_no_mem goto label doesn't do anything. Remove it.
+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 21 ++++++++-------------
+ 1 file changed, 8 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 5004b9dd98563..8b9577318388e 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -971,10 +971,9 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+       u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+       dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
+-      if (!dev) {
+-              ret = -ENOMEM;
+-              goto err_no_mem;
+-      }
++      if (!dev)
++              return -ENOMEM;
++
+       dev->vendor = vendor;
+       dev->adev = adev;
+       nmk_i2c_of_probe(np, dev);
+@@ -995,30 +994,27 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+       dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
+                               resource_size(&adev->res));
+-      if (!dev->virtbase) {
+-              ret = -ENOMEM;
+-              goto err_no_mem;
+-      }
++      if (!dev->virtbase)
++              return -ENOMEM;
+       dev->irq = adev->irq[0];
+       ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
+                               DRIVER_NAME, dev);
+       if (ret) {
+               dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
+-              goto err_no_mem;
++              return ret;
+       }
+       dev->clk = devm_clk_get(&adev->dev, NULL);
+       if (IS_ERR(dev->clk)) {
+               dev_err(&adev->dev, "could not get i2c clock\n");
+-              ret = PTR_ERR(dev->clk);
+-              goto err_no_mem;
++              return PTR_ERR(dev->clk);
+       }
+       ret = clk_prepare_enable(dev->clk);
+       if (ret) {
+               dev_err(&adev->dev, "can't prepare_enable clock\n");
+-              goto err_no_mem;
++              return ret;
+       }
+       init_hw(dev);
+@@ -1049,7 +1045,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+  err_no_adap:
+       clk_disable_unprepare(dev->clk);
+- err_no_mem:
+       return ret;
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.15/i2c-nomadik-use-devm_clk_get_enabled.patch b/queue-5.15/i2c-nomadik-use-devm_clk_get_enabled.patch
new file mode 100644 (file)
index 0000000..f62a85b
--- /dev/null
@@ -0,0 +1,76 @@
+From 497a487c66fefe6d04f96f9d4acc070d8689565f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Jun 2023 03:37:00 +0200
+Subject: i2c: nomadik: Use devm_clk_get_enabled()
+
+From: Andi Shyti <andi.shyti@kernel.org>
+
+[ Upstream commit 9c7174db4cdd111e10d19eed5c36fd978a14c8a2 ]
+
+Replace the pair of functions, devm_clk_get() and
+clk_prepare_enable(), with a single function
+devm_clk_get_enabled().
+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 8b9577318388e..2141ba05dfece 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -1005,18 +1005,12 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+               return ret;
+       }
+-      dev->clk = devm_clk_get(&adev->dev, NULL);
++      dev->clk = devm_clk_get_enabled(&adev->dev, NULL);
+       if (IS_ERR(dev->clk)) {
+-              dev_err(&adev->dev, "could not get i2c clock\n");
++              dev_err(&adev->dev, "could enable i2c clock\n");
+               return PTR_ERR(dev->clk);
+       }
+-      ret = clk_prepare_enable(dev->clk);
+-      if (ret) {
+-              dev_err(&adev->dev, "can't prepare_enable clock\n");
+-              return ret;
+-      }
+-
+       init_hw(dev);
+       adap = &dev->adap;
+@@ -1037,16 +1031,11 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+       ret = i2c_add_adapter(adap);
+       if (ret)
+-              goto err_no_adap;
++              return ret;
+       pm_runtime_put(&adev->dev);
+       return 0;
+-
+- err_no_adap:
+-      clk_disable_unprepare(dev->clk);
+-
+-      return ret;
+ }
+ static void nmk_i2c_remove(struct amba_device *adev)
+@@ -1060,7 +1049,6 @@ static void nmk_i2c_remove(struct amba_device *adev)
+       clear_all_interrupts(dev);
+       /* disable the controller */
+       i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+-      clk_disable_unprepare(dev->clk);
+       release_mem_region(res->start, resource_size(res));
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.15/io_uring-don-t-audit-the-capability-check-in-io_urin.patch b/queue-5.15/io_uring-don-t-audit-the-capability-check-in-io_urin.patch
new file mode 100644 (file)
index 0000000..fce195a
--- /dev/null
@@ -0,0 +1,47 @@
+From 4b74f1cbdf97d18a5afa9ae0bcae7b211dbc1e02 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Jul 2023 13:56:07 +0200
+Subject: io_uring: don't audit the capability check in io_uring_create()
+
+From: Ondrej Mosnacek <omosnace@redhat.com>
+
+[ Upstream commit 6adc2272aaaf84f34b652cf77f770c6fcc4b8336 ]
+
+The check being unconditional may lead to unwanted denials reported by
+LSMs when a process has the capability granted by DAC, but denied by an
+LSM. In the case of SELinux such denials are a problem, since they can't
+be effectively filtered out via the policy and when not silenced, they
+produce noise that may hide a true problem or an attack.
+
+Since not having the capability merely means that the created io_uring
+context will be accounted against the current user's RLIMIT_MEMLOCK
+limit, we can disable auditing of denials for this check by using
+ns_capable_noaudit() instead of capable().
+
+Fixes: 2b188cc1bb85 ("Add io_uring IO interface")
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2193317
+Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
+Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
+Link: https://lore.kernel.org/r/20230718115607.65652-1-omosnace@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index d7f87157be9aa..f65c6811ede81 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -10602,7 +10602,7 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
+       if (!ctx)
+               return -ENOMEM;
+       ctx->compat = in_compat_syscall();
+-      if (!capable(CAP_IPC_LOCK))
++      if (!ns_capable_noaudit(&init_user_ns, CAP_IPC_LOCK))
+               ctx->user = get_uid(current_user());
+       /*
+-- 
+2.39.2
+
diff --git a/queue-5.15/jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch b/queue-5.15/jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
new file mode 100644 (file)
index 0000000..f169b4a
--- /dev/null
@@ -0,0 +1,150 @@
+From b756a018ae344b7a50133eec86185342030b7e89 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:27 +0800
+Subject: jbd2: fix a race when checking checkpoint buffer busy
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit 46f881b5b1758dc4a35fba4a643c10717d0cf427 ]
+
+Before removing checkpoint buffer from the t_checkpoint_list, we have to
+check both BH_Dirty and BH_Lock bits together to distinguish buffers
+have not been or were being written back. But __cp_buffer_busy() checks
+them separately, it first check lock state and then check dirty, the
+window between these two checks could be raced by writing back
+procedure, which locks buffer and clears buffer dirty before I/O
+completes. So it cannot guarantee checkpointing buffers been written
+back to disk if some error happens later. Finally, it may clean
+checkpoint transactions and lead to inconsistent filesystem.
+
+jbd2_journal_forget() and __journal_try_to_free_buffer() also have the
+same problem (journal_unmap_buffer() escape from this issue since it's
+running under the buffer lock), so fix them through introducing a new
+helper to try holding the buffer lock and remove really clean buffer.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
+Cc: stable@vger.kernel.org
+Suggested-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-6-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c  | 38 +++++++++++++++++++++++++++++++++++---
+ fs/jbd2/transaction.c | 17 +++++------------
+ include/linux/jbd2.h  |  1 +
+ 3 files changed, 41 insertions(+), 15 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index ab72aeb766a74..fc6989e7a8c51 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -376,11 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+               jh = next_jh;
+               next_jh = jh->b_cpnext;
+-              if (!destroy && __cp_buffer_busy(jh))
+-                      continue;
++              if (destroy) {
++                      ret = __jbd2_journal_remove_checkpoint(jh);
++              } else {
++                      ret = jbd2_journal_try_remove_checkpoint(jh);
++                      if (ret < 0)
++                              continue;
++              }
+               nr_freed++;
+-              ret = __jbd2_journal_remove_checkpoint(jh);
+               if (ret) {
+                       *released = true;
+                       break;
+@@ -616,6 +620,34 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+       return 1;
+ }
++/*
++ * Check the checkpoint buffer and try to remove it from the checkpoint
++ * list if it's clean. Returns -EBUSY if it is not clean, returns 1 if
++ * it frees the transaction, 0 otherwise.
++ *
++ * This function is called with j_list_lock held.
++ */
++int jbd2_journal_try_remove_checkpoint(struct journal_head *jh)
++{
++      struct buffer_head *bh = jh2bh(jh);
++
++      if (!trylock_buffer(bh))
++              return -EBUSY;
++      if (buffer_dirty(bh)) {
++              unlock_buffer(bh);
++              return -EBUSY;
++      }
++      unlock_buffer(bh);
++
++      /*
++       * Buffer is clean and the IO has finished (we held the buffer
++       * lock) so the checkpoint is done. We can safely remove the
++       * buffer from this transaction.
++       */
++      JBUFFER_TRACE(jh, "remove from checkpoint list");
++      return __jbd2_journal_remove_checkpoint(jh);
++}
++
+ /*
+  * journal_insert_checkpoint: put a committed buffer onto a checkpoint
+  * list so that we know when it is safe to clean the transaction out of
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index ce4a5ccadeff4..62e68c5b8ec3d 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1775,8 +1775,7 @@ int jbd2_journal_forget(handle_t *handle, struct buffer_head *bh)
+                * Otherwise, if the buffer has been written to disk,
+                * it is safe to remove the checkpoint and drop it.
+                */
+-              if (!buffer_dirty(bh)) {
+-                      __jbd2_journal_remove_checkpoint(jh);
++              if (jbd2_journal_try_remove_checkpoint(jh) >= 0) {
+                       spin_unlock(&journal->j_list_lock);
+                       goto drop;
+               }
+@@ -2103,20 +2102,14 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
+       jh = bh2jh(bh);
+-      if (buffer_locked(bh) || buffer_dirty(bh))
+-              goto out;
+-
+       if (jh->b_next_transaction != NULL || jh->b_transaction != NULL)
+-              goto out;
++              return;
+       spin_lock(&journal->j_list_lock);
+-      if (jh->b_cp_transaction != NULL) {
+-              /* written-back checkpointed metadata buffer */
+-              JBUFFER_TRACE(jh, "remove from checkpoint list");
+-              __jbd2_journal_remove_checkpoint(jh);
+-      }
++      /* Remove written-back checkpointed metadata buffer */
++      if (jh->b_cp_transaction != NULL)
++              jbd2_journal_try_remove_checkpoint(jh);
+       spin_unlock(&journal->j_list_lock);
+-out:
+       return;
+ }
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index e6cfbcde96f29..ade8a6d7acff9 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -1441,6 +1441,7 @@ extern void jbd2_journal_commit_transaction(journal_t *);
+ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy);
+ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal, unsigned long *nr_to_scan);
+ int __jbd2_journal_remove_checkpoint(struct journal_head *);
++int jbd2_journal_try_remove_checkpoint(struct journal_head *jh);
+ void jbd2_journal_destroy_checkpoint(journal_t *journal);
+ void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
+-- 
+2.39.2
+
diff --git a/queue-5.15/jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch b/queue-5.15/jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch
new file mode 100644 (file)
index 0000000..0ce4dd3
--- /dev/null
@@ -0,0 +1,106 @@
+From 8ef166c955d5e1682826ea7a9cd405ad77cc5240 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:26 +0800
+Subject: jbd2: Fix wrongly judgement for buffer head removing while doing
+ checkpoint
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+[ Upstream commit e34c8dd238d0c9368b746480f313055f5bab5040 ]
+
+Following process,
+
+jbd2_journal_commit_transaction
+// there are several dirty buffer heads in transaction->t_checkpoint_list
+          P1                   wb_workfn
+jbd2_log_do_checkpoint
+ if (buffer_locked(bh)) // false
+                            __block_write_full_page
+                             trylock_buffer(bh)
+                             test_clear_buffer_dirty(bh)
+ if (!buffer_dirty(bh))
+  __jbd2_journal_remove_checkpoint(jh)
+   if (buffer_write_io_error(bh)) // false
+                             >> bh IO error occurs <<
+ jbd2_cleanup_journal_tail
+  __jbd2_update_log_tail
+   jbd2_write_superblock
+   // The bh won't be replayed in next mount.
+, which could corrupt the ext4 image, fetch a reproducer in [Link].
+
+Since writeback process clears buffer dirty after locking buffer head,
+we can fix it by try locking buffer and check dirtiness while buffer is
+locked, the buffer head can be removed if it is neither dirty nor locked.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
+Fixes: 470decc613ab ("[PATCH] jbd2: initial copy of files from jbd")
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-5-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index fe8bb031b7d7f..d2aba55833f92 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -221,20 +221,6 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+               jh = transaction->t_checkpoint_list;
+               bh = jh2bh(jh);
+-              /*
+-               * The buffer may be writing back, or flushing out in the
+-               * last couple of cycles, or re-adding into a new transaction,
+-               * need to check it again until it's unlocked.
+-               */
+-              if (buffer_locked(bh)) {
+-                      get_bh(bh);
+-                      spin_unlock(&journal->j_list_lock);
+-                      wait_on_buffer(bh);
+-                      /* the journal_head may have gone by now */
+-                      BUFFER_TRACE(bh, "brelse");
+-                      __brelse(bh);
+-                      goto retry;
+-              }
+               if (jh->b_transaction != NULL) {
+                       transaction_t *t = jh->b_transaction;
+                       tid_t tid = t->t_tid;
+@@ -269,7 +255,22 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+                       spin_lock(&journal->j_list_lock);
+                       goto restart;
+               }
+-              if (!buffer_dirty(bh)) {
++              if (!trylock_buffer(bh)) {
++                      /*
++                       * The buffer is locked, it may be writing back, or
++                       * flushing out in the last couple of cycles, or
++                       * re-adding into a new transaction, need to check
++                       * it again until it's unlocked.
++                       */
++                      get_bh(bh);
++                      spin_unlock(&journal->j_list_lock);
++                      wait_on_buffer(bh);
++                      /* the journal_head may have gone by now */
++                      BUFFER_TRACE(bh, "brelse");
++                      __brelse(bh);
++                      goto retry;
++              } else if (!buffer_dirty(bh)) {
++                      unlock_buffer(bh);
+                       BUFFER_TRACE(bh, "remove from checkpoint");
+                       /*
+                        * If the transaction was released or the checkpoint
+@@ -279,6 +280,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+                           !transaction->t_checkpoint_list)
+                               goto out;
+               } else {
++                      unlock_buffer(bh);
+                       /*
+                        * We are about to write the buffer, it could be
+                        * raced by some other transaction shrink or buffer
+-- 
+2.39.2
+
diff --git a/queue-5.15/jbd2-remove-journal_clean_one_cp_list.patch b/queue-5.15/jbd2-remove-journal_clean_one_cp_list.patch
new file mode 100644 (file)
index 0000000..7bdc682
--- /dev/null
@@ -0,0 +1,235 @@
+From aecb975234f28cd552c2716b840cb4df901d3027 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:25 +0800
+Subject: jbd2: remove journal_clean_one_cp_list()
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit b98dba273a0e47dbfade89c9af73c5b012a4eabb ]
+
+journal_clean_one_cp_list() and journal_shrink_one_cp_list() are almost
+the same, so merge them into journal_shrink_one_cp_list(), remove the
+nr_to_scan parameter, always scan and try to free the whole checkpoint
+list.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-4-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c        | 75 +++++++++----------------------------
+ include/trace/events/jbd2.h | 12 ++----
+ 2 files changed, 21 insertions(+), 66 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index c1f543e86170a..ab72aeb766a74 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -349,50 +349,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
+ /* Checkpoint list management */
+-/*
+- * journal_clean_one_cp_list
+- *
+- * Find all the written-back checkpoint buffers in the given list and
+- * release them. If 'destroy' is set, clean all buffers unconditionally.
+- *
+- * Called with j_list_lock held.
+- * Returns 1 if we freed the transaction, 0 otherwise.
+- */
+-static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
+-{
+-      struct journal_head *last_jh;
+-      struct journal_head *next_jh = jh;
+-
+-      if (!jh)
+-              return 0;
+-
+-      last_jh = jh->b_cpprev;
+-      do {
+-              jh = next_jh;
+-              next_jh = jh->b_cpnext;
+-
+-              if (!destroy && __cp_buffer_busy(jh))
+-                      return 0;
+-
+-              if (__jbd2_journal_remove_checkpoint(jh))
+-                      return 1;
+-              /*
+-               * This function only frees up some memory
+-               * if possible so we dont have an obligation
+-               * to finish processing. Bail out if preemption
+-               * requested:
+-               */
+-              if (need_resched())
+-                      return 0;
+-      } while (jh != last_jh);
+-
+-      return 0;
+-}
+-
+ /*
+  * journal_shrink_one_cp_list
+  *
+- * Find 'nr_to_scan' written-back checkpoint buffers in the given list
++ * Find all the written-back checkpoint buffers in the given list
+  * and try to release them. If the whole transaction is released, set
+  * the 'released' parameter. Return the number of released checkpointed
+  * buffers.
+@@ -400,15 +360,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
+  * Called with j_list_lock held.
+  */
+ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+-                                              unsigned long *nr_to_scan,
+-                                              bool *released)
++                                              bool destroy, bool *released)
+ {
+       struct journal_head *last_jh;
+       struct journal_head *next_jh = jh;
+       unsigned long nr_freed = 0;
+       int ret;
+-      if (!jh || *nr_to_scan == 0)
++      *released = false;
++      if (!jh)
+               return 0;
+       last_jh = jh->b_cpprev;
+@@ -416,8 +376,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+               jh = next_jh;
+               next_jh = jh->b_cpnext;
+-              (*nr_to_scan)--;
+-              if (__cp_buffer_busy(jh))
++              if (!destroy && __cp_buffer_busy(jh))
+                       continue;
+               nr_freed++;
+@@ -429,7 +388,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+               if (need_resched())
+                       break;
+-      } while (jh != last_jh && *nr_to_scan);
++      } while (jh != last_jh);
+       return nr_freed;
+ }
+@@ -447,11 +406,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+                                                 unsigned long *nr_to_scan)
+ {
+       transaction_t *transaction, *last_transaction, *next_transaction;
+-      bool released;
++      bool __maybe_unused released;
+       tid_t first_tid = 0, last_tid = 0, next_tid = 0;
+       tid_t tid = 0;
+       unsigned long nr_freed = 0;
+-      unsigned long nr_scanned = *nr_to_scan;
++      unsigned long freed;
+ again:
+       spin_lock(&journal->j_list_lock);
+@@ -480,10 +439,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+               transaction = next_transaction;
+               next_transaction = transaction->t_cpnext;
+               tid = transaction->t_tid;
+-              released = false;
+-              nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
+-                                                     nr_to_scan, &released);
++              freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
++                                                 false, &released);
++              nr_freed += freed;
++              (*nr_to_scan) -= min(*nr_to_scan, freed);
+               if (*nr_to_scan == 0)
+                       break;
+               if (need_resched() || spin_needbreak(&journal->j_list_lock))
+@@ -504,9 +464,8 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+       if (*nr_to_scan && next_tid)
+               goto again;
+ out:
+-      nr_scanned -= *nr_to_scan;
+       trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid,
+-                                        nr_freed, nr_scanned, next_tid);
++                                        nr_freed, next_tid);
+       return nr_freed;
+ }
+@@ -522,7 +481,7 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ {
+       transaction_t *transaction, *last_transaction, *next_transaction;
+-      int ret;
++      bool released;
+       transaction = journal->j_checkpoint_transactions;
+       if (!transaction)
+@@ -533,8 +492,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+       do {
+               transaction = next_transaction;
+               next_transaction = transaction->t_cpnext;
+-              ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
+-                                              destroy);
++              journal_shrink_one_cp_list(transaction->t_checkpoint_list,
++                                         destroy, &released);
+               /*
+                * This function only frees up some memory if possible so we
+                * dont have an obligation to finish processing. Bail out if
+@@ -547,7 +506,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+                * avoids pointless scanning of transactions which still
+                * weren't checkpointed.
+                */
+-              if (!ret)
++              if (!released)
+                       return;
+       } while (transaction != last_transaction);
+ }
+diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
+index 29414288ea3e0..34ce197bd76e0 100644
+--- a/include/trace/events/jbd2.h
++++ b/include/trace/events/jbd2.h
+@@ -462,11 +462,9 @@ TRACE_EVENT(jbd2_shrink_scan_exit,
+ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+       TP_PROTO(journal_t *journal, tid_t first_tid, tid_t tid, tid_t last_tid,
+-               unsigned long nr_freed, unsigned long nr_scanned,
+-               tid_t next_tid),
++               unsigned long nr_freed, tid_t next_tid),
+-      TP_ARGS(journal, first_tid, tid, last_tid, nr_freed,
+-              nr_scanned, next_tid),
++      TP_ARGS(journal, first_tid, tid, last_tid, nr_freed, next_tid),
+       TP_STRUCT__entry(
+               __field(dev_t, dev)
+@@ -474,7 +472,6 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+               __field(tid_t, tid)
+               __field(tid_t, last_tid)
+               __field(unsigned long, nr_freed)
+-              __field(unsigned long, nr_scanned)
+               __field(tid_t, next_tid)
+       ),
+@@ -484,15 +481,14 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+               __entry->tid            = tid;
+               __entry->last_tid       = last_tid;
+               __entry->nr_freed       = nr_freed;
+-              __entry->nr_scanned     = nr_scanned;
+               __entry->next_tid       = next_tid;
+       ),
+       TP_printk("dev %d,%d shrink transaction %u-%u(%u) freed %lu "
+-                "scanned %lu next transaction %u",
++                "next transaction %u",
+                 MAJOR(__entry->dev), MINOR(__entry->dev),
+                 __entry->first_tid, __entry->tid, __entry->last_tid,
+-                __entry->nr_freed, __entry->nr_scanned, __entry->next_tid)
++                __entry->nr_freed, __entry->next_tid)
+ );
+ #endif /* _TRACE_JBD2_H */
+-- 
+2.39.2
+
diff --git a/queue-5.15/jbd2-remove-t_checkpoint_io_list.patch b/queue-5.15/jbd2-remove-t_checkpoint_io_list.patch
new file mode 100644 (file)
index 0000000..a399eba
--- /dev/null
@@ -0,0 +1,146 @@
+From 92d4d5454f0734d09f34beaae5f86cf3dcc3087f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:24 +0800
+Subject: jbd2: remove t_checkpoint_io_list
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit be22255360f80d3af789daad00025171a65424a5 ]
+
+Since t_checkpoint_io_list was stop using in jbd2_log_do_checkpoint()
+now, it's time to remove the whole t_checkpoint_io_list logic.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-3-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 42 ++----------------------------------------
+ fs/jbd2/commit.c     |  3 +--
+ include/linux/jbd2.h |  6 ------
+ 3 files changed, 3 insertions(+), 48 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index d2aba55833f92..c1f543e86170a 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -27,7 +27,7 @@
+  *
+  * Called with j_list_lock held.
+  */
+-static inline void __buffer_unlink_first(struct journal_head *jh)
++static inline void __buffer_unlink(struct journal_head *jh)
+ {
+       transaction_t *transaction = jh->b_cp_transaction;
+@@ -40,23 +40,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
+       }
+ }
+-/*
+- * Unlink a buffer from a transaction checkpoint(io) list.
+- *
+- * Called with j_list_lock held.
+- */
+-static inline void __buffer_unlink(struct journal_head *jh)
+-{
+-      transaction_t *transaction = jh->b_cp_transaction;
+-
+-      __buffer_unlink_first(jh);
+-      if (transaction->t_checkpoint_io_list == jh) {
+-              transaction->t_checkpoint_io_list = jh->b_cpnext;
+-              if (transaction->t_checkpoint_io_list == jh)
+-                      transaction->t_checkpoint_io_list = NULL;
+-      }
+-}
+-
+ /*
+  * Check a checkpoint buffer could be release or not.
+  *
+@@ -505,15 +488,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+                       break;
+               if (need_resched() || spin_needbreak(&journal->j_list_lock))
+                       break;
+-              if (released)
+-                      continue;
+-
+-              nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
+-                                                     nr_to_scan, &released);
+-              if (*nr_to_scan == 0)
+-                      break;
+-              if (need_resched() || spin_needbreak(&journal->j_list_lock))
+-                      break;
+       } while (transaction != last_transaction);
+       if (transaction != last_transaction) {
+@@ -568,17 +542,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+                */
+               if (need_resched())
+                       return;
+-              if (ret)
+-                      continue;
+-              /*
+-               * It is essential that we are as careful as in the case of
+-               * t_checkpoint_list with removing the buffer from the list as
+-               * we can possibly see not yet submitted buffers on io_list
+-               */
+-              ret = journal_clean_one_cp_list(transaction->
+-                              t_checkpoint_io_list, destroy);
+-              if (need_resched())
+-                      return;
+               /*
+                * Stop scanning if we couldn't free the transaction. This
+                * avoids pointless scanning of transactions which still
+@@ -663,7 +626,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+       jbd2_journal_put_journal_head(jh);
+       /* Is this transaction empty? */
+-      if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
++      if (transaction->t_checkpoint_list)
+               return 0;
+       /*
+@@ -755,7 +718,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
+       J_ASSERT(transaction->t_forget == NULL);
+       J_ASSERT(transaction->t_shadow_list == NULL);
+       J_ASSERT(transaction->t_checkpoint_list == NULL);
+-      J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+       J_ASSERT(atomic_read(&transaction->t_updates) == 0);
+       J_ASSERT(journal->j_committing_transaction != transaction);
+       J_ASSERT(journal->j_running_transaction != transaction);
+diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
+index ac328e3321242..20294c1bbeab7 100644
+--- a/fs/jbd2/commit.c
++++ b/fs/jbd2/commit.c
+@@ -1184,8 +1184,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
+       spin_lock(&journal->j_list_lock);
+       commit_transaction->t_state = T_FINISHED;
+       /* Check if the transaction can be dropped now that we are finished */
+-      if (commit_transaction->t_checkpoint_list == NULL &&
+-          commit_transaction->t_checkpoint_io_list == NULL) {
++      if (commit_transaction->t_checkpoint_list == NULL) {
+               __jbd2_journal_drop_transaction(journal, commit_transaction);
+               jbd2_journal_free_transaction(commit_transaction);
+       }
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index d63b8106796e2..e6cfbcde96f29 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -626,12 +626,6 @@ struct transaction_s
+        */
+       struct journal_head     *t_checkpoint_list;
+-      /*
+-       * Doubly-linked circular list of all buffers submitted for IO while
+-       * checkpointing. [j_list_lock]
+-       */
+-      struct journal_head     *t_checkpoint_io_list;
+-
+       /*
+        * Doubly-linked circular list of metadata buffers being
+        * shadowed by log IO.  The IO buffers on the iobuf list and
+-- 
+2.39.2
+
diff --git a/queue-5.15/ksmbd-remove-internal.h-include.patch b/queue-5.15/ksmbd-remove-internal.h-include.patch
new file mode 100644 (file)
index 0000000..54575c1
--- /dev/null
@@ -0,0 +1,66 @@
+From d9c75a1623fdb440b59aae1d3bc66d6a49841d68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Mar 2023 07:34:33 +0900
+Subject: ksmbd: remove internal.h include
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 211db0ac9e3dc6c46f2dd53395b34d76af929faf ]
+
+Since vfs_path_lookup is exported, It should not be internal.
+Move vfs_path_lookup prototype in internal.h to linux/namei.h.
+
+Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Stable-dep-of: df9d70c18616 ("cifs: if deferred close is disabled then close files immediately")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/internal.h         | 2 --
+ fs/ksmbd/vfs.c        | 2 --
+ include/linux/namei.h | 2 ++
+ 3 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/fs/internal.h b/fs/internal.h
+index ceb154583a3c4..1ff8cfc94467b 100644
+--- a/fs/internal.h
++++ b/fs/internal.h
+@@ -58,8 +58,6 @@ extern int finish_clean_context(struct fs_context *fc);
+  */
+ extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
+                          struct path *path, struct path *root);
+-extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+-                         const char *, unsigned int, struct path *);
+ int do_rmdir(int dfd, struct filename *name);
+ int do_unlinkat(int dfd, struct filename *name);
+ int may_linkat(struct user_namespace *mnt_userns, struct path *link);
+diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
+index 52cc6a9627ed7..f76acd83c2944 100644
+--- a/fs/ksmbd/vfs.c
++++ b/fs/ksmbd/vfs.c
+@@ -19,8 +19,6 @@
+ #include <linux/sched/xacct.h>
+ #include <linux/crc32c.h>
+-#include "../internal.h"      /* for vfs_path_lookup */
+-
+ #include "glob.h"
+ #include "oplock.h"
+ #include "connection.h"
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index caeb08a98536c..40c693525f796 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -63,6 +63,8 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
+ extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
+ extern void done_path_create(struct path *, struct dentry *);
+ extern struct dentry *kern_path_locked(const char *, struct path *);
++int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
++                  unsigned int, struct path *);
+ extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+-- 
+2.39.2
+
diff --git a/queue-5.15/kvm-s390-pv-fix-index-value-of-replaced-asce.patch b/queue-5.15/kvm-s390-pv-fix-index-value-of-replaced-asce.patch
new file mode 100644 (file)
index 0000000..dad2669
--- /dev/null
@@ -0,0 +1,46 @@
+From b295b7e4014dd96e83bfd9f8778f82dd01044ef5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jul 2023 13:19:37 +0200
+Subject: KVM: s390: pv: fix index value of replaced ASCE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Claudio Imbrenda <imbrenda@linux.ibm.com>
+
+[ Upstream commit c2fceb59bbda16468bda82b002383bff59de89ab ]
+
+The index field of the struct page corresponding to a guest ASCE should
+be 0. When replacing the ASCE in s390_replace_asce(), the index of the
+new ASCE should also be set to 0.
+
+Having the wrong index might lead to the wrong addresses being passed
+around when notifying pte invalidations, and eventually to validity
+intercepts (VM crash) if the prefix gets unmapped and the notifier gets
+called with the wrong address.
+
+Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
+Fixes: faa2f72cb356 ("KVM: s390: pv: leak the topmost page table when destroy fails")
+Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
+Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
+Message-ID: <20230705111937.33472-3-imbrenda@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/mm/gmap.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
+index ff40bf92db43a..a2c872de29a66 100644
+--- a/arch/s390/mm/gmap.c
++++ b/arch/s390/mm/gmap.c
+@@ -2791,6 +2791,7 @@ int s390_replace_asce(struct gmap *gmap)
+       page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER);
+       if (!page)
+               return -ENOMEM;
++      page->index = 0;
+       table = page_to_virt(page);
+       memcpy(table, gmap->table, 1UL << (CRST_ALLOC_ORDER + PAGE_SHIFT));
+-- 
+2.39.2
+
diff --git a/queue-5.15/n_tty-rename-tail-to-old_tail-in-n_tty_read.patch b/queue-5.15/n_tty-rename-tail-to-old_tail-in-n_tty_read.patch
new file mode 100644 (file)
index 0000000..ebea0c0
--- /dev/null
@@ -0,0 +1,60 @@
+From 46947742388959c672d059772208ccb938fef065 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Nov 2022 16:25:02 +0200
+Subject: n_tty: Rename tail to old_tail in n_tty_read()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit 947d66b68f3c4e7cf8f3f3500807b9d2a0de28ce ]
+
+The local tail variable in n_tty_read() is used for one purpose, it
+keeps the old tail. Thus, rename it appropriately to improve code
+readability.
+
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
+Link: https://lore.kernel.org/r/22b37499-ff9a-7fc1-f6e0-58411328d122@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 4903fde8047a ("tty: fix hang on tty device with no_room set")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_tty.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
+index 891036bd9f897..8f57448e1ce46 100644
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -2100,7 +2100,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+       ssize_t retval = 0;
+       long timeout;
+       bool packet;
+-      size_t tail;
++      size_t old_tail;
+       /*
+        * Is this a continuation of a read started earler?
+@@ -2163,7 +2163,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+       }
+       packet = tty->ctrl.packet;
+-      tail = ldata->read_tail;
++      old_tail = ldata->read_tail;
+       add_wait_queue(&tty->read_wait, &wait);
+       while (nr) {
+@@ -2252,7 +2252,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+               if (time)
+                       timeout = time;
+       }
+-      if (tail != ldata->read_tail)
++      if (old_tail != ldata->read_tail)
+               n_tty_kick_worker(tty);
+       up_read(&tty->termios_rwsem);
+-- 
+2.39.2
+
diff --git a/queue-5.15/pci-aspm-avoid-link-retraining-race.patch b/queue-5.15/pci-aspm-avoid-link-retraining-race.patch
new file mode 100644 (file)
index 0000000..00e88de
--- /dev/null
@@ -0,0 +1,64 @@
+From e8d78a001d6cd99367d133ad691f99306ade7ae0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 May 2023 11:39:23 +0300
+Subject: PCI/ASPM: Avoid link retraining race
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit e7e39756363ad5bd83ddeae1063193d0f13870fd ]
+
+PCIe r6.0.1, sec 7.5.3.7, recommends setting the link control parameters,
+then waiting for the Link Training bit to be clear before setting the
+Retrain Link bit.
+
+This avoids a race where the LTSSM may not use the updated parameters if it
+is already in the midst of link training because of other normal link
+activity.
+
+Wait for the Link Training bit to be clear before toggling the Retrain Link
+bit to ensure that the LTSSM uses the updated link control parameters.
+
+[bhelgaas: commit log, return 0 (success)/-ETIMEDOUT instead of bool for
+both pcie_wait_for_retrain() and the existing pcie_retrain_link()]
+Suggested-by: Lukas Wunner <lukas@wunner.de>
+Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support")
+Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Lukas Wunner <lukas@wunner.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index 5e09cbb563366..3078de668f911 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -212,8 +212,19 @@ static int pcie_wait_for_retrain(struct pci_dev *pdev)
+ static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+       struct pci_dev *parent = link->pdev;
++      int rc;
+       u16 reg16;
++      /*
++       * Ensure the updated LNKCTL parameters are used during link
++       * training by checking that there is no ongoing link training to
++       * avoid LTSSM race as recommended in Implementation Note at the
++       * end of PCIe r6.0.1 sec 7.5.3.7.
++       */
++      rc = pcie_wait_for_retrain(parent);
++      if (rc)
++              return rc;
++
+       pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &reg16);
+       reg16 |= PCI_EXP_LNKCTL_RL;
+       pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+-- 
+2.39.2
+
diff --git a/queue-5.15/pci-aspm-factor-out-pcie_wait_for_retrain.patch b/queue-5.15/pci-aspm-factor-out-pcie_wait_for_retrain.patch
new file mode 100644 (file)
index 0000000..96a9790
--- /dev/null
@@ -0,0 +1,79 @@
+From 36264db8f61aace836eefc44d4b4ce6f14df5392 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Jun 2023 14:49:33 -0500
+Subject: PCI/ASPM: Factor out pcie_wait_for_retrain()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit 9c7f136433d26592cb4d9cd00b4e15c33d9797c6 ]
+
+Factor pcie_wait_for_retrain() out from pcie_retrain_link().  No functional
+change intended.
+
+[bhelgaas: split out from
+https: //lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com]
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: e7e39756363a ("PCI/ASPM: Avoid link retraining race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index e7f742ff31c3c..5e09cbb563366 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -192,10 +192,26 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
+       link->clkpm_disable = blacklist ? 1 : 0;
+ }
++static int pcie_wait_for_retrain(struct pci_dev *pdev)
++{
++      unsigned long end_jiffies;
++      u16 reg16;
++
++      /* Wait for Link Training to be cleared by hardware */
++      end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
++      do {
++              pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &reg16);
++              if (!(reg16 & PCI_EXP_LNKSTA_LT))
++                      return 0;
++              msleep(1);
++      } while (time_before(jiffies, end_jiffies));
++
++      return -ETIMEDOUT;
++}
++
+ static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+       struct pci_dev *parent = link->pdev;
+-      unsigned long end_jiffies;
+       u16 reg16;
+       pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &reg16);
+@@ -211,17 +227,7 @@ static int pcie_retrain_link(struct pcie_link_state *link)
+               pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+       }
+-      /* Wait for link training end. Break out after waiting for timeout */
+-      end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
+-      do {
+-              pcie_capability_read_word(parent, PCI_EXP_LNKSTA, &reg16);
+-              if (!(reg16 & PCI_EXP_LNKSTA_LT))
+-                      break;
+-              msleep(1);
+-      } while (time_before(jiffies, end_jiffies));
+-      if (reg16 & PCI_EXP_LNKSTA_LT)
+-              return -ETIMEDOUT;
+-      return 0;
++      return pcie_wait_for_retrain(parent);
+ }
+ /*
+-- 
+2.39.2
+
diff --git a/queue-5.15/pci-aspm-return-0-or-etimedout-from-pcie_retrain_lin.patch b/queue-5.15/pci-aspm-return-0-or-etimedout-from-pcie_retrain_lin.patch
new file mode 100644 (file)
index 0000000..5fa4b88
--- /dev/null
@@ -0,0 +1,72 @@
+From 786317a4aaccf786bfb06a38f742fc49680c4ae3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Jun 2023 14:44:55 -0500
+Subject: PCI/ASPM: Return 0 or -ETIMEDOUT from pcie_retrain_link()
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit f5297a01ee805d7fa569d288ed65fc0f9ac9b03d ]
+
+"pcie_retrain_link" is not a question with a true/false answer, so "bool"
+isn't quite the right return type.  Return 0 for success or -ETIMEDOUT if
+the retrain failed.  No functional change intended.
+
+[bhelgaas: based on Ilpo's patch below]
+Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: e7e39756363a ("PCI/ASPM: Avoid link retraining race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index c58294f53fcd1..e7f742ff31c3c 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -192,7 +192,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
+       link->clkpm_disable = blacklist ? 1 : 0;
+ }
+-static bool pcie_retrain_link(struct pcie_link_state *link)
++static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+       struct pci_dev *parent = link->pdev;
+       unsigned long end_jiffies;
+@@ -219,7 +219,9 @@ static bool pcie_retrain_link(struct pcie_link_state *link)
+                       break;
+               msleep(1);
+       } while (time_before(jiffies, end_jiffies));
+-      return !(reg16 & PCI_EXP_LNKSTA_LT);
++      if (reg16 & PCI_EXP_LNKSTA_LT)
++              return -ETIMEDOUT;
++      return 0;
+ }
+ /*
+@@ -288,15 +290,15 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
+               reg16 &= ~PCI_EXP_LNKCTL_CCC;
+       pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+-      if (pcie_retrain_link(link))
+-              return;
++      if (pcie_retrain_link(link)) {
+-      /* Training failed. Restore common clock configurations */
+-      pci_err(parent, "ASPM: Could not configure common clock\n");
+-      list_for_each_entry(child, &linkbus->devices, bus_list)
+-              pcie_capability_write_word(child, PCI_EXP_LNKCTL,
++              /* Training failed. Restore common clock configurations */
++              pci_err(parent, "ASPM: Could not configure common clock\n");
++              list_for_each_entry(child, &linkbus->devices, bus_list)
++                      pcie_capability_write_word(child, PCI_EXP_LNKCTL,
+                                          child_reg[PCI_FUNC(child->devfn)]);
+-      pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
++              pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
++      }
+ }
+ /* Convert L0s latency encoding to ns */
+-- 
+2.39.2
+
diff --git a/queue-5.15/pci-rockchip-don-t-advertise-msi-x-in-pcie-capabilit.patch b/queue-5.15/pci-rockchip-don-t-advertise-msi-x-in-pcie-capabilit.patch
new file mode 100644 (file)
index 0000000..1e5f3fd
--- /dev/null
@@ -0,0 +1,103 @@
+From 30c4c68808b06e28cf438684c3c0d54ab8a181b4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:57 +0200
+Subject: PCI: rockchip: Don't advertise MSI-X in PCIe capabilities
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit a52587e0bee14cbeeadf48a24013828cb04b8df8 ]
+
+The RK3399 PCIe endpoint controller cannot generate MSI-X IRQs.
+This is documented in the RK3399 technical reference manual (TRM)
+section 17.5.9 "Interrupt Support".
+
+MSI-X capability should therefore not be advertised. Remove the
+MSI-X capability by editing the capability linked-list. The
+previous entry is the MSI capability, therefore get the next
+entry from the MSI-X capability entry and set it as next entry
+for the MSI capability. This in effect removes MSI-X from the list.
+
+Linked list before : MSI cap -> MSI-X cap -> PCIe Device cap -> ...
+Linked list now : MSI cap -> PCIe Device cap -> ...
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-11-rick.wertenbroek@gmail.com
+Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller")
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 24 +++++++++++++++++++++++
+ drivers/pci/controller/pcie-rockchip.h    |  5 +++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 3d6f828d29fc2..0af0e965fb57e 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -508,6 +508,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+       size_t max_regions;
+       struct pci_epc_mem_window *windows = NULL;
+       int err, i;
++      u32 cfg_msi, cfg_msix_cp;
+       ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+       if (!ep)
+@@ -583,6 +584,29 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+       ep->irq_pci_addr = ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR;
++      /*
++       * MSI-X is not supported but the controller still advertises the MSI-X
++       * capability by default, which can lead to the Root Complex side
++       * allocating MSI-X vectors which cannot be used. Avoid this by skipping
++       * the MSI-X capability entry in the PCIe capabilities linked-list: get
++       * the next pointer from the MSI-X entry and set that in the MSI
++       * capability entry (which is the previous entry). This way the MSI-X
++       * entry is skipped (left out of the linked-list) and not advertised.
++       */
++      cfg_msi = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_BASE +
++                                   ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
++
++      cfg_msi &= ~ROCKCHIP_PCIE_EP_MSI_CP1_MASK;
++
++      cfg_msix_cp = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_BASE +
++                                       ROCKCHIP_PCIE_EP_MSIX_CAP_REG) &
++                                       ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK;
++
++      cfg_msi |= cfg_msix_cp;
++
++      rockchip_pcie_write(rockchip, cfg_msi,
++                          PCIE_EP_CONFIG_BASE + ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
++
+       rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE,
+                           PCIE_CLIENT_CONFIG);
+diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
+index 498a40251d0be..88e2bf65e433a 100644
+--- a/drivers/pci/controller/pcie-rockchip.h
++++ b/drivers/pci/controller/pcie-rockchip.h
+@@ -228,6 +228,8 @@
+ #define ROCKCHIP_PCIE_EP_CMD_STATUS                   0x4
+ #define   ROCKCHIP_PCIE_EP_CMD_STATUS_IS              BIT(19)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_REG                 0x90
++#define   ROCKCHIP_PCIE_EP_MSI_CP1_OFFSET             8
++#define   ROCKCHIP_PCIE_EP_MSI_CP1_MASK                       GENMASK(15, 8)
+ #define   ROCKCHIP_PCIE_EP_MSI_FLAGS_OFFSET           16
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET                17
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_MASK          GENMASK(19, 17)
+@@ -235,6 +237,9 @@
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK          GENMASK(22, 20)
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_ME                                BIT(16)
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP      BIT(24)
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_REG                 0xb0
++#define   ROCKCHIP_PCIE_EP_MSIX_CAP_CP_OFFSET         8
++#define   ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK           GENMASK(15, 8)
+ #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR                               0x1
+ #define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR          0x3
+ #define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \
+-- 
+2.39.2
+
diff --git a/queue-5.15/pci-rockchip-fix-window-mapping-and-address-translat.patch b/queue-5.15/pci-rockchip-fix-window-mapping-and-address-translat.patch
new file mode 100644 (file)
index 0000000..1d18276
--- /dev/null
@@ -0,0 +1,340 @@
+From 654fa12adc6b26111c6aea4f41edab940ae82f85 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:55 +0200
+Subject: PCI: rockchip: Fix window mapping and address translation for
+ endpoint
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit dc73ed0f1b8bddd7f2bf70d123e68ffc99ad71ce ]
+
+The RK3399 PCI endpoint core has 33 windows for PCIe space, now in the
+driver up to 32 fixed size (1M) windows are used and pages are allocated
+and mapped accordingly. The driver first used a single window and allocated
+space inside which caused translation issues (between CPU space and PCI
+space) because a window can only have a single translation at a given
+time, which if multiple pages are allocated inside will cause conflicts.
+Now each window is a single region of 1M which will always guarantee that
+the translation is not in conflict.
+
+Set the translation register addresses for physical function. As documented
+in the technical reference manual (TRM) section 17.5.5 "PCIe Address
+Translation" and section 17.6.8 "Address Translation Registers Description"
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-9-rick.wertenbroek@gmail.com
+Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller")
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 128 ++++++++++------------
+ drivers/pci/controller/pcie-rockchip.h    |  35 +++---
+ 2 files changed, 75 insertions(+), 88 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 9e17f3dba743a..3d6f828d29fc2 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -64,52 +64,29 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
+ }
+ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+-                                       u32 r, u32 type, u64 cpu_addr,
+-                                       u64 pci_addr, size_t size)
++                                       u32 r, u64 cpu_addr, u64 pci_addr,
++                                       size_t size)
+ {
+-      u64 sz = 1ULL << fls64(size - 1);
+-      int num_pass_bits = ilog2(sz);
+-      u32 addr0, addr1, desc0, desc1;
+-      bool is_nor_msg = (type == AXI_WRAPPER_NOR_MSG);
++      int num_pass_bits = fls64(size - 1);
++      u32 addr0, addr1, desc0;
+-      /* The minimal region size is 1MB */
+       if (num_pass_bits < 8)
+               num_pass_bits = 8;
+-      cpu_addr -= rockchip->mem_res->start;
+-      addr0 = ((is_nor_msg ? 0x10 : (num_pass_bits - 1)) &
+-              PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
+-              (lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+-      addr1 = upper_32_bits(is_nor_msg ? cpu_addr : pci_addr);
+-      desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | type;
+-      desc1 = 0;
+-
+-      if (is_nor_msg) {
+-              rockchip_pcie_write(rockchip, 0,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
+-              rockchip_pcie_write(rockchip, 0,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
+-              rockchip_pcie_write(rockchip, desc0,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
+-              rockchip_pcie_write(rockchip, desc1,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+-      } else {
+-              /* PCI bus address region */
+-              rockchip_pcie_write(rockchip, addr0,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
+-              rockchip_pcie_write(rockchip, addr1,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
+-              rockchip_pcie_write(rockchip, desc0,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
+-              rockchip_pcie_write(rockchip, desc1,
+-                                  ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+-
+-              addr0 =
+-                  ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
+-                  (lower_32_bits(cpu_addr) &
+-                   PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+-              addr1 = upper_32_bits(cpu_addr);
+-      }
++      addr0 = ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
++              (lower_32_bits(pci_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
++      addr1 = upper_32_bits(pci_addr);
++      desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | AXI_WRAPPER_MEM_WRITE;
++
++      /* PCI bus address region */
++      rockchip_pcie_write(rockchip, addr0,
++                          ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
++      rockchip_pcie_write(rockchip, addr1,
++                          ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
++      rockchip_pcie_write(rockchip, desc0,
++                          ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
++      rockchip_pcie_write(rockchip, 0,
++                          ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+ }
+ static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+@@ -248,26 +225,20 @@ static void rockchip_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn,
+                           ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar));
+ }
++static inline u32 rockchip_ob_region(phys_addr_t addr)
++{
++      return (addr >> ilog2(SZ_1M)) & 0x1f;
++}
++
+ static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+                                    phys_addr_t addr, u64 pci_addr,
+                                    size_t size)
+ {
+       struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
+       struct rockchip_pcie *pcie = &ep->rockchip;
+-      u32 r;
++      u32 r = rockchip_ob_region(addr);
+-      r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG);
+-      /*
+-       * Region 0 is reserved for configuration space and shouldn't
+-       * be used elsewhere per TRM, so leave it out.
+-       */
+-      if (r >= ep->max_regions - 1) {
+-              dev_err(&epc->dev, "no free outbound region\n");
+-              return -EINVAL;
+-      }
+-
+-      rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, AXI_WRAPPER_MEM_WRITE, addr,
+-                                   pci_addr, size);
++      rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, addr, pci_addr, size);
+       set_bit(r, &ep->ob_region_map);
+       ep->ob_addr[r] = addr;
+@@ -282,15 +253,11 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+       struct rockchip_pcie *rockchip = &ep->rockchip;
+       u32 r;
+-      for (r = 0; r < ep->max_regions - 1; r++)
++      for (r = 0; r < ep->max_regions; r++)
+               if (ep->ob_addr[r] == addr)
+                       break;
+-      /*
+-       * Region 0 is reserved for configuration space and shouldn't
+-       * be used elsewhere per TRM, so leave it out.
+-       */
+-      if (r == ep->max_regions - 1)
++      if (r == ep->max_regions)
+               return;
+       rockchip_pcie_clear_ep_ob_atu(rockchip, r);
+@@ -387,7 +354,8 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
+       struct rockchip_pcie *rockchip = &ep->rockchip;
+       u32 flags, mme, data, data_mask;
+       u8 msi_count;
+-      u64 pci_addr, pci_addr_mask = 0xff;
++      u64 pci_addr;
++      u32 r;
+       /* Check MSI enable bit */
+       flags = rockchip_pcie_read(&ep->rockchip,
+@@ -421,21 +389,20 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
+                                      ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
+                                      ROCKCHIP_PCIE_EP_MSI_CTRL_REG +
+                                      PCI_MSI_ADDRESS_LO);
+-      pci_addr &= GENMASK_ULL(63, 2);
+       /* Set the outbound region if needed. */
+-      if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
++      if (unlikely(ep->irq_pci_addr != (pci_addr & PCIE_ADDR_MASK) ||
+                    ep->irq_pci_fn != fn)) {
+-              rockchip_pcie_prog_ep_ob_atu(rockchip, fn, ep->max_regions - 1,
+-                                           AXI_WRAPPER_MEM_WRITE,
++              r = rockchip_ob_region(ep->irq_phys_addr);
++              rockchip_pcie_prog_ep_ob_atu(rockchip, fn, r,
+                                            ep->irq_phys_addr,
+-                                           pci_addr & ~pci_addr_mask,
+-                                           pci_addr_mask + 1);
+-              ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
++                                           pci_addr & PCIE_ADDR_MASK,
++                                           ~PCIE_ADDR_MASK + 1);
++              ep->irq_pci_addr = (pci_addr & PCIE_ADDR_MASK);
+               ep->irq_pci_fn = fn;
+       }
+-      writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
++      writew(data, ep->irq_cpu_addr + (pci_addr & ~PCIE_ADDR_MASK));
+       return 0;
+ }
+@@ -517,6 +484,8 @@ static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip,
+       if (err < 0 || ep->max_regions > MAX_REGION_LIMIT)
+               ep->max_regions = MAX_REGION_LIMIT;
++      ep->ob_region_map = 0;
++
+       err = of_property_read_u8(dev->of_node, "max-functions",
+                                 &ep->epc->max_functions);
+       if (err < 0)
+@@ -537,7 +506,8 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+       struct rockchip_pcie *rockchip;
+       struct pci_epc *epc;
+       size_t max_regions;
+-      int err;
++      struct pci_epc_mem_window *windows = NULL;
++      int err, i;
+       ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+       if (!ep)
+@@ -584,15 +554,27 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+       /* Only enable function 0 by default */
+       rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG);
+-      err = pci_epc_mem_init(epc, rockchip->mem_res->start,
+-                             resource_size(rockchip->mem_res), PAGE_SIZE);
++      windows = devm_kcalloc(dev, ep->max_regions,
++                             sizeof(struct pci_epc_mem_window), GFP_KERNEL);
++      if (!windows) {
++              err = -ENOMEM;
++              goto err_uninit_port;
++      }
++      for (i = 0; i < ep->max_regions; i++) {
++              windows[i].phys_base = rockchip->mem_res->start + (SZ_1M * i);
++              windows[i].size = SZ_1M;
++              windows[i].page_size = SZ_1M;
++      }
++      err = pci_epc_multi_mem_init(epc, windows, ep->max_regions);
++      devm_kfree(dev, windows);
++
+       if (err < 0) {
+               dev_err(dev, "failed to initialize the memory space\n");
+               goto err_uninit_port;
+       }
+       ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
+-                                                SZ_128K);
++                                                SZ_1M);
+       if (!ep->irq_cpu_addr) {
+               dev_err(dev, "failed to reserve memory space for MSI\n");
+               err = -ENOMEM;
+diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
+index cbd2fd25ba761..498a40251d0be 100644
+--- a/drivers/pci/controller/pcie-rockchip.h
++++ b/drivers/pci/controller/pcie-rockchip.h
+@@ -139,6 +139,7 @@
+ #define PCIE_RC_RP_ATS_BASE           0x400000
+ #define PCIE_RC_CONFIG_NORMAL_BASE    0x800000
++#define PCIE_EP_PF_CONFIG_REGS_BASE   0x800000
+ #define PCIE_RC_CONFIG_BASE           0xa00000
+ #define PCIE_EP_CONFIG_BASE           0xa00000
+ #define PCIE_EP_CONFIG_DID_VID                (PCIE_EP_CONFIG_BASE + 0x00)
+@@ -158,10 +159,11 @@
+ #define PCIE_RC_CONFIG_THP_CAP                (PCIE_RC_CONFIG_BASE + 0x274)
+ #define   PCIE_RC_CONFIG_THP_CAP_NEXT_MASK    GENMASK(31, 20)
++#define PCIE_ADDR_MASK                        0xffffff00
+ #define PCIE_CORE_AXI_CONF_BASE               0xc00000
+ #define PCIE_CORE_OB_REGION_ADDR0     (PCIE_CORE_AXI_CONF_BASE + 0x0)
+ #define   PCIE_CORE_OB_REGION_ADDR0_NUM_BITS  0x3f
+-#define   PCIE_CORE_OB_REGION_ADDR0_LO_ADDR   0xffffff00
++#define   PCIE_CORE_OB_REGION_ADDR0_LO_ADDR   PCIE_ADDR_MASK
+ #define PCIE_CORE_OB_REGION_ADDR1     (PCIE_CORE_AXI_CONF_BASE + 0x4)
+ #define PCIE_CORE_OB_REGION_DESC0     (PCIE_CORE_AXI_CONF_BASE + 0x8)
+ #define PCIE_CORE_OB_REGION_DESC1     (PCIE_CORE_AXI_CONF_BASE + 0xc)
+@@ -169,7 +171,7 @@
+ #define PCIE_CORE_AXI_INBOUND_BASE    0xc00800
+ #define PCIE_RP_IB_ADDR0              (PCIE_CORE_AXI_INBOUND_BASE + 0x0)
+ #define   PCIE_CORE_IB_REGION_ADDR0_NUM_BITS  0x3f
+-#define   PCIE_CORE_IB_REGION_ADDR0_LO_ADDR   0xffffff00
++#define   PCIE_CORE_IB_REGION_ADDR0_LO_ADDR   PCIE_ADDR_MASK
+ #define PCIE_RP_IB_ADDR1              (PCIE_CORE_AXI_INBOUND_BASE + 0x4)
+ /* Size of one AXI Region (not Region 0) */
+@@ -234,13 +236,15 @@
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_ME                                BIT(16)
+ #define   ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP      BIT(24)
+ #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR                               0x1
+-#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn)        (((fn) << 12) & GENMASK(19, 12))
++#define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR          0x3
++#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \
++      (PCIE_EP_PF_CONFIG_REGS_BASE + (((fn) << 12) & GENMASK(19, 12)))
++#define ROCKCHIP_PCIE_EP_VIRT_FUNC_BASE(fn) \
++      (PCIE_EP_PF_CONFIG_REGS_BASE + 0x10000 + (((fn) << 12) & GENMASK(19, 12)))
+ #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
+-      (PCIE_RC_RP_ATS_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
++      (PCIE_CORE_AXI_CONF_BASE + 0x0828 + (fn) * 0x0040 + (bar) * 0x0008)
+ #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
+-      (PCIE_RC_RP_ATS_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+-      (PCIE_RC_RP_ATS_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
++      (PCIE_CORE_AXI_CONF_BASE + 0x082c + (fn) * 0x0040 + (bar) * 0x0008)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK       GENMASK(19, 12)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+       (((devfn) << 12) & \
+@@ -248,20 +252,21 @@
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+               (((bus) << 20) & ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
++#define PCIE_RC_EP_ATR_OB_REGIONS_1_32 (PCIE_CORE_AXI_CONF_BASE + 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
++              (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0000 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+-              (PCIE_RC_RP_ATS_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
++              (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0004 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID        BIT(23)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK   GENMASK(31, 24)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+               (((devfn) << 24) & ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r) \
+-              (PCIE_RC_RP_ATS_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r)   \
+-              (PCIE_RC_RP_ATS_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+-              (PCIE_RC_RP_ATS_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+-              (PCIE_RC_RP_ATS_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
++              (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0008 + ((r) & 0x1f) * 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \
++              (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x000c + ((r) & 0x1f) * 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_DESC2(r) \
++              (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0010 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG0(fn) \
+               (PCIE_CORE_CTRL_MGMT_BASE + 0x0240 + (fn) * 0x0008)
+-- 
+2.39.2
+
diff --git a/queue-5.15/pci-rockchip-remove-writes-to-unused-registers.patch b/queue-5.15/pci-rockchip-remove-writes-to-unused-registers.patch
new file mode 100644 (file)
index 0000000..e394e40
--- /dev/null
@@ -0,0 +1,55 @@
+From 3c396e7e23569e81b99a721c937a676dc265af4a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:48 +0200
+Subject: PCI: rockchip: Remove writes to unused registers
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit 92a9c57c325dd51682d428ba960d961fec3c8a08 ]
+
+Remove write accesses to registers that are marked "unused" (and
+therefore read-only) in the technical reference manual (TRM)
+(see RK3399 TRM 17.6.8.1)
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-2-rick.wertenbroek@gmail.com
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Stable-dep-of: dc73ed0f1b8b ("PCI: rockchip: Fix window mapping and address translation for endpoint")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 827d91e73efab..9e17f3dba743a 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -61,10 +61,6 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
+                           ROCKCHIP_PCIE_AT_OB_REGION_DESC0(region));
+       rockchip_pcie_write(rockchip, 0,
+                           ROCKCHIP_PCIE_AT_OB_REGION_DESC1(region));
+-      rockchip_pcie_write(rockchip, 0,
+-                          ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(region));
+-      rockchip_pcie_write(rockchip, 0,
+-                          ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(region));
+ }
+ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+@@ -114,12 +110,6 @@ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+                    PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+               addr1 = upper_32_bits(cpu_addr);
+       }
+-
+-      /* CPU bus address region */
+-      rockchip_pcie_write(rockchip, addr0,
+-                          ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r));
+-      rockchip_pcie_write(rockchip, addr1,
+-                          ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r));
+ }
+ static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+-- 
+2.39.2
+
diff --git a/queue-5.15/pwm-meson-fix-handling-of-period-duty-if-greater-tha.patch b/queue-5.15/pwm-meson-fix-handling-of-period-duty-if-greater-tha.patch
new file mode 100644 (file)
index 0000000..37921f3
--- /dev/null
@@ -0,0 +1,85 @@
+From d3bef08736704119bf87858580b0a9539083d322 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 May 2023 21:48:36 +0200
+Subject: pwm: meson: fix handling of period/duty if greater than UINT_MAX
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Heiner Kallweit <hkallweit1@gmail.com>
+
+[ Upstream commit 87a2cbf02d7701255f9fcca7e5bd864a7bb397cf ]
+
+state->period/duty are of type u64, and if their value is greater than
+UINT_MAX, then the cast to uint will cause problems. Fix this by
+changing the type of the respective local variables to u64.
+
+Fixes: b79c3670e120 ("pwm: meson: Don't duplicate the polarity internally")
+Cc: stable@vger.kernel.org
+Suggested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-meson.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
+index 37bbad88a3ee5..ec6a544d6f526 100644
+--- a/drivers/pwm/pwm-meson.c
++++ b/drivers/pwm/pwm-meson.c
+@@ -163,8 +163,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+                         const struct pwm_state *state)
+ {
+       struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+-      unsigned int duty, period, pre_div, cnt, duty_cnt;
++      unsigned int pre_div, cnt, duty_cnt;
+       unsigned long fin_freq;
++      u64 duty, period;
+       duty = state->duty_cycle;
+       period = state->period;
+@@ -186,19 +187,19 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+       dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
+-      pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL);
++      pre_div = div64_u64(fin_freq * period, NSEC_PER_SEC * 0xffffLL);
+       if (pre_div > MISC_CLK_DIV_MASK) {
+               dev_err(meson->chip.dev, "unable to get period pre_div\n");
+               return -EINVAL;
+       }
+-      cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1));
++      cnt = div64_u64(fin_freq * period, NSEC_PER_SEC * (pre_div + 1));
+       if (cnt > 0xffff) {
+               dev_err(meson->chip.dev, "unable to get period cnt\n");
+               return -EINVAL;
+       }
+-      dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period,
++      dev_dbg(meson->chip.dev, "period=%llu pre_div=%u cnt=%u\n", period,
+               pre_div, cnt);
+       if (duty == period) {
+@@ -211,14 +212,13 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+               channel->lo = cnt;
+       } else {
+               /* Then check is we can have the duty with the same pre_div */
+-              duty_cnt = div64_u64(fin_freq * (u64)duty,
+-                                   NSEC_PER_SEC * (pre_div + 1));
++              duty_cnt = div64_u64(fin_freq * duty, NSEC_PER_SEC * (pre_div + 1));
+               if (duty_cnt > 0xffff) {
+                       dev_err(meson->chip.dev, "unable to get duty cycle\n");
+                       return -EINVAL;
+               }
+-              dev_dbg(meson->chip.dev, "duty=%u pre_div=%u duty_cnt=%u\n",
++              dev_dbg(meson->chip.dev, "duty=%llu pre_div=%u duty_cnt=%u\n",
+                       duty, pre_div, duty_cnt);
+               channel->pre_div = pre_div;
+-- 
+2.39.2
+
diff --git a/queue-5.15/pwm-meson-simplify-duplicated-per-channel-tracking.patch b/queue-5.15/pwm-meson-simplify-duplicated-per-channel-tracking.patch
new file mode 100644 (file)
index 0000000..1b58784
--- /dev/null
@@ -0,0 +1,77 @@
+From ca49b41a11f321f87f3aa9271261b5a23699911d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Nov 2021 14:46:26 +0100
+Subject: pwm: meson: Simplify duplicated per-channel tracking
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 5f97f18feac9bd5a8163b108aee52d783114b36f ]
+
+The driver tracks per-channel data via struct pwm_device::chip_data and
+struct meson_pwm::channels[]. The latter holds the actual data, the former
+is only a pointer to the latter. So simplify by using struct
+meson_pwm::channels[] consistently.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
+Stable-dep-of: 87a2cbf02d77 ("pwm: meson: fix handling of period/duty if greater than UINT_MAX")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-meson.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
+index 76f702c43cbc3..37bbad88a3ee5 100644
+--- a/drivers/pwm/pwm-meson.c
++++ b/drivers/pwm/pwm-meson.c
+@@ -147,12 +147,13 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+               return err;
+       }
+-      return pwm_set_chip_data(pwm, channel);
++      return 0;
+ }
+ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+ {
+-      struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
++      struct meson_pwm *meson = to_meson_pwm(chip);
++      struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+       if (channel)
+               clk_disable_unprepare(channel->clk);
+@@ -161,7 +162,7 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+                         const struct pwm_state *state)
+ {
+-      struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
++      struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+       unsigned int duty, period, pre_div, cnt, duty_cnt;
+       unsigned long fin_freq;
+@@ -230,7 +231,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
+ {
+-      struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
++      struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+       struct meson_pwm_channel_data *channel_data;
+       unsigned long flags;
+       u32 value;
+@@ -273,8 +274,8 @@ static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm)
+ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                          const struct pwm_state *state)
+ {
+-      struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
+       struct meson_pwm *meson = to_meson_pwm(chip);
++      struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+       int err = 0;
+       if (!state)
+-- 
+2.39.2
+
diff --git a/queue-5.15/revert-tracing-add-fault-name-injection-to-kernel-pr.patch b/queue-5.15/revert-tracing-add-fault-name-injection-to-kernel-pr.patch
new file mode 100644 (file)
index 0000000..7710934
--- /dev/null
@@ -0,0 +1,135 @@
+From 5a71e3f9d94ce54053dfb0cee214a0ac6766835f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 23:15:57 +0900
+Subject: Revert "tracing: Add "(fault)" name injection to kernel probes"
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 4ed8f337dee32df71435689c19d22e4ee846e15a ]
+
+This reverts commit 2e9906f84fc7c99388bb7123ade167250d50f1c0.
+
+It was turned out that commit 2e9906f84fc7 ("tracing: Add "(fault)"
+name injection to kernel probes") did not work correctly and probe
+events still show just '(fault)' (instead of '"(fault)"'). Also,
+current '(fault)' is more explicit that it faulted.
+
+This also moves FAULT_STRING macro to trace.h so that synthetic
+event can keep using it, and uses it in trace_probe.c too.
+
+Link: https://lore.kernel.org/all/168908495772.123124.1250788051922100079.stgit@devnote2/
+Link: https://lore.kernel.org/all/20230706230642.3793a593@rorschach.local.home/
+
+Cc: stable@vger.kernel.org
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Tom Zanussi <zanussi@kernel.org>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: 797311bce5c2 ("tracing/probes: Fix to record 0-length data_loc in fetch_store_string*() if fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace.h              |  2 ++
+ kernel/trace/trace_probe.c        |  2 +-
+ kernel/trace/trace_probe_kernel.h | 31 ++++++-------------------------
+ 3 files changed, 9 insertions(+), 26 deletions(-)
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 33c55c8826a7e..43058077a4def 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -113,6 +113,8 @@ enum trace_type {
+ #define MEM_FAIL(condition, fmt, ...)                                 \
+       DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__)
++#define FAULT_STRING "(fault)"
++
+ #define HIST_STACKTRACE_DEPTH 16
+ #define HIST_STACKTRACE_SIZE  (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
+ #define HIST_STACKTRACE_SKIP  5
+diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
+index 90bae188d0928..0888f0644d257 100644
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -64,7 +64,7 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
+       int len = *(u32 *)data >> 16;
+       if (!len)
+-              trace_seq_puts(s, "(fault)");
++              trace_seq_puts(s, FAULT_STRING);
+       else
+               trace_seq_printf(s, "\"%s\"",
+                                (const char *)get_loc_data(data, ent));
+diff --git a/kernel/trace/trace_probe_kernel.h b/kernel/trace/trace_probe_kernel.h
+index 77dbd9ff97826..1d43df29a1f8e 100644
+--- a/kernel/trace/trace_probe_kernel.h
++++ b/kernel/trace/trace_probe_kernel.h
+@@ -2,8 +2,6 @@
+ #ifndef __TRACE_PROBE_KERNEL_H_
+ #define __TRACE_PROBE_KERNEL_H_
+-#define FAULT_STRING "(fault)"
+-
+ /*
+  * This depends on trace_probe.h, but can not include it due to
+  * the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c.
+@@ -15,16 +13,8 @@ static nokprobe_inline int
+ kern_fetch_store_strlen_user(unsigned long addr)
+ {
+       const void __user *uaddr =  (__force const void __user *)addr;
+-      int ret;
+-      ret = strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
+-      /*
+-       * strnlen_user_nofault returns zero on fault, insert the
+-       * FAULT_STRING when that occurs.
+-       */
+-      if (ret <= 0)
+-              return strlen(FAULT_STRING) + 1;
+-      return ret;
++      return strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
+ }
+ /* Return the length of string -- including null terminal byte */
+@@ -44,18 +34,7 @@ kern_fetch_store_strlen(unsigned long addr)
+               len++;
+       } while (c && ret == 0 && len < MAX_STRING_SIZE);
+-      /* For faults, return enough to hold the FAULT_STRING */
+-      return (ret < 0) ? strlen(FAULT_STRING) + 1 : len;
+-}
+-
+-static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base, int len)
+-{
+-      if (ret >= 0) {
+-              *(u32 *)dest = make_data_loc(ret, __dest - base);
+-      } else {
+-              strscpy(__dest, FAULT_STRING, len);
+-              ret = strlen(__dest) + 1;
+-      }
++      return (ret < 0) ? ret : len;
+ }
+ /*
+@@ -76,7 +55,8 @@ kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
+       __dest = get_loc_data(dest, base);
+       ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
+-      set_data_loc(ret, dest, __dest, base, maxlen);
++      if (ret >= 0)
++              *(u32 *)dest = make_data_loc(ret, __dest - base);
+       return ret;
+ }
+@@ -107,7 +87,8 @@ kern_fetch_store_string(unsigned long addr, void *dest, void *base)
+        * probing.
+        */
+       ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
+-      set_data_loc(ret, dest, __dest, base, maxlen);
++      if (ret >= 0)
++              *(u32 *)dest = make_data_loc(ret, __dest - base);
+       return ret;
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.15/scsi-qla2xxx-add-debug-prints-in-the-device-remove-p.patch b/queue-5.15/scsi-qla2xxx-add-debug-prints-in-the-device-remove-p.patch
new file mode 100644 (file)
index 0000000..edbce59
--- /dev/null
@@ -0,0 +1,54 @@
+From ca965bfd92d47bf2d16a179681e1779d841b71c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jun 2022 22:35:05 -0700
+Subject: scsi: qla2xxx: Add debug prints in the device remove path
+
+From: Arun Easi <aeasi@marvell.com>
+
+[ Upstream commit f12d2d130efc49464ef0666789bfeb9073162743 ]
+
+Add a debug print in the devloss callback.
+
+Link: https://lore.kernel.org/r/20220616053508.27186-9-njavali@marvell.com
+Signed-off-by: Arun Easi <aeasi@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 9ae615c5bfd3 ("scsi: qla2xxx: Fix hang in task management")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_attr.c | 3 +++
+ drivers/scsi/qla2xxx/qla_def.h  | 6 ++++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
+index de57d45ffc5cb..4a5df867057bc 100644
+--- a/drivers/scsi/qla2xxx/qla_attr.c
++++ b/drivers/scsi/qla2xxx/qla_attr.c
+@@ -2705,6 +2705,9 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
+       if (!fcport)
+               return;
++      ql_dbg(ql_dbg_async, fcport->vha, 0x5101,
++             DBG_FCPORT_PRFMT(fcport, "dev_loss_tmo expiry, rport_state=%d",
++                              rport->port_state));
+       /*
+        * Now that the rport has been deleted, set the fcport state to
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index bbeb116c16cc3..2a2bca2fb57ee 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -5475,4 +5475,10 @@ struct ql_vnd_tgt_stats_resp {
+ #define IS_SESSION_DELETED(_fcport) (_fcport->disc_state == DSC_DELETE_PEND || \
+                                     _fcport->disc_state == DSC_DELETED)
++#define DBG_FCPORT_PRFMT(_fp, _fmt, _args...) \
++      "%s: %8phC: " _fmt " (state=%d disc_state=%d scan_state=%d loopid=0x%x deleted=%d flags=0x%x)\n", \
++      __func__, _fp->port_name, ##_args, atomic_read(&_fp->state), \
++      _fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \
++      _fp->flags
++
+ #endif
+-- 
+2.39.2
+
diff --git a/queue-5.15/scsi-qla2xxx-fix-hang-in-task-management.patch b/queue-5.15/scsi-qla2xxx-fix-hang-in-task-management.patch
new file mode 100644 (file)
index 0000000..1805d7f
--- /dev/null
@@ -0,0 +1,195 @@
+From 92c8ae8a606aee9eeeb8e31aa58d646a6665bbfb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:36 -0700
+Subject: scsi: qla2xxx: Fix hang in task management
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 9ae615c5bfd37bd091772969b1153de5335ea986 ]
+
+Task management command hangs where a side
+band chip reset failed to nudge the TMF
+from it's current send path.
+
+Add additional error check to block TMF
+from entering during chip reset and along
+the TMF path to cause it to bail out, skip
+over abort of marker.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-5-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h  |  4 +++
+ drivers/scsi/qla2xxx/qla_init.c | 60 +++++++++++++++++++++++++++++++--
+ 2 files changed, 61 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 2a2bca2fb57ee..83228ce822af3 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -5481,4 +5481,8 @@ struct ql_vnd_tgt_stats_resp {
+       _fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \
+       _fp->flags
++#define TMF_NOT_READY(_fcport) \
++      (!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
++      !_fcport->vha->hw->flags.fw_started)
++
+ #endif
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 2c42ecb2a64a5..a97872b6350ca 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -1998,6 +1998,11 @@ qla2x00_tmf_iocb_timeout(void *data)
+       int rc, h;
+       unsigned long flags;
++      if (sp->type == SRB_MARKER) {
++              complete(&tmf->u.tmf.comp);
++              return;
++      }
++
+       rc = qla24xx_async_abort_cmd(sp, false);
+       if (rc) {
+               spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
+@@ -2025,6 +2030,7 @@ static void qla_marker_sp_done(srb_t *sp, int res)
+                   sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
+                   sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
++      sp->u.iocb_cmd.u.tmf.data = res;
+       complete(&tmf->u.tmf.comp);
+ }
+@@ -2041,6 +2047,11 @@ static void qla_marker_sp_done(srb_t *sp, int res)
+       } while (cnt); \
+ }
++/**
++ * qla26xx_marker: send marker IOCB and wait for the completion of it.
++ * @arg: pointer to argument list.
++ *    It is assume caller will provide an fcport pointer and modifier
++ */
+ static int
+ qla26xx_marker(struct tmf_arg *arg)
+ {
+@@ -2050,6 +2061,14 @@ qla26xx_marker(struct tmf_arg *arg)
+       int rval = QLA_FUNCTION_FAILED;
+       fc_port_t *fcport = arg->fcport;
++      if (TMF_NOT_READY(arg->fcport)) {
++              ql_dbg(ql_dbg_taskm, vha, 0x8039,
++                  "FC port not ready for marker loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
++                  fcport->loop_id, fcport->d_id.b24,
++                  arg->modifier, arg->lun, arg->qpair->id);
++              return QLA_SUSPENDED;
++      }
++
+       /* ref: INIT */
+       sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+       if (!sp)
+@@ -2076,11 +2095,19 @@ qla26xx_marker(struct tmf_arg *arg)
+       if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x8031,
+-                  "Marker IOCB failed (%x).\n", rval);
++                  "Marker IOCB send failure (%x).\n", rval);
+               goto done_free_sp;
+       }
+       wait_for_completion(&tm_iocb->u.tmf.comp);
++      rval = tm_iocb->u.tmf.data;
++
++      if (rval != QLA_SUCCESS) {
++              ql_log(ql_log_warn, vha, 0x8019,
++                  "Marker failed hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
++                  sp->handle, fcport->loop_id, fcport->d_id.b24,
++                  arg->modifier, arg->lun, sp->qpair->id, rval);
++      }
+ done_free_sp:
+       /* ref: INIT */
+@@ -2093,6 +2120,8 @@ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
+ {
+       struct srb_iocb *tmf = &sp->u.iocb_cmd;
++      if (res)
++              tmf->u.tmf.data = res;
+       complete(&tmf->u.tmf.comp);
+ }
+@@ -2106,6 +2135,14 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+       fc_port_t *fcport = arg->fcport;
++      if (TMF_NOT_READY(arg->fcport)) {
++              ql_dbg(ql_dbg_taskm, vha, 0x8032,
++                  "FC port not ready for TM command loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
++                  fcport->loop_id, fcport->d_id.b24,
++                  arg->modifier, arg->lun, arg->qpair->id);
++              return QLA_SUSPENDED;
++      }
++
+       /* ref: INIT */
+       sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+       if (!sp)
+@@ -2180,7 +2217,9 @@ int qla_get_tmf(fc_port_t *fcport)
+               msleep(1);
+               spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+-              if (fcport->deleted) {
++              if (TMF_NOT_READY(fcport)) {
++                      ql_log(ql_log_warn, vha, 0x802c,
++                          "Unable to acquire TM resource due to disruption.\n");
+                       rc = EIO;
+                       break;
+               }
+@@ -2206,7 +2245,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_qpair *qpair;
+       struct tmf_arg a;
+-      int i, rval;
++      int i, rval = QLA_SUCCESS;
++
++      if (TMF_NOT_READY(fcport))
++              return QLA_SUSPENDED;
+       a.vha = fcport->vha;
+       a.fcport = fcport;
+@@ -2225,6 +2267,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+                       qpair = vha->hw->queue_pair_map[i];
+                       if (!qpair)
+                               continue;
++
++                      if (TMF_NOT_READY(fcport)) {
++                              ql_log(ql_log_warn, vha, 0x8026,
++                                  "Unable to send TM due to disruption.\n");
++                              rval = QLA_SUSPENDED;
++                              break;
++                      }
++
+                       a.qpair = qpair;
+                       a.flags = flags|TCF_NOTMCMD_TO_TARGET;
+                       rval = __qla2x00_async_tm_cmd(&a);
+@@ -2233,10 +2283,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+               }
+       }
++      if (rval)
++              goto bailout;
++
+       a.qpair = vha->hw->base_qpair;
+       a.flags = flags;
+       rval = __qla2x00_async_tm_cmd(&a);
++bailout:
+       if (a.modifier == MK_SYNC_ID_LUN)
+               qla_put_tmf(fcport);
+-- 
+2.39.2
+
diff --git a/queue-5.15/scsi-qla2xxx-fix-task-management-cmd-fail-due-to-una.patch b/queue-5.15/scsi-qla2xxx-fix-task-management-cmd-fail-due-to-una.patch
new file mode 100644 (file)
index 0000000..995c1ae
--- /dev/null
@@ -0,0 +1,155 @@
+From cc2d6f72c6b995159aecc843410b558cf9f36ee8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:35 -0700
+Subject: scsi: qla2xxx: Fix task management cmd fail due to unavailable
+ resource
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 6a87679626b51b53fbb6be417ad8eb083030b617 ]
+
+Task management command failed with status 2Ch which is
+a result of too many task management commands sent
+to the same target. Hence limit task management commands
+to 8 per target.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Link: https://lore.kernel.org/oe-kbuild-all/202304271952.NKNmoFzv-lkp@intel.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-4-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h  |  3 ++
+ drivers/scsi/qla2xxx/qla_init.c | 63 ++++++++++++++++++++++++++++++---
+ 2 files changed, 61 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index ca63aa8f33b5d..bbeb116c16cc3 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -2523,6 +2523,7 @@ enum rscn_addr_format {
+ typedef struct fc_port {
+       struct list_head list;
+       struct scsi_qla_host *vha;
++      struct list_head tmf_pending;
+       unsigned int conf_compl_supported:1;
+       unsigned int deleted:2;
+@@ -2543,6 +2544,8 @@ typedef struct fc_port {
+       unsigned int do_prli_nvme:1;
+       uint8_t nvme_flag;
++      uint8_t active_tmf;
++#define MAX_ACTIVE_TMF 8
+       uint8_t node_name[WWN_SIZE];
+       uint8_t port_name[WWN_SIZE];
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 9d9b16f7f34a6..2c42ecb2a64a5 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2151,6 +2151,54 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+       return rval;
+ }
++static void qla_put_tmf(fc_port_t *fcport)
++{
++      struct scsi_qla_host *vha = fcport->vha;
++      struct qla_hw_data *ha = vha->hw;
++      unsigned long flags;
++
++      spin_lock_irqsave(&ha->tgt.sess_lock, flags);
++      fcport->active_tmf--;
++      spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
++}
++
++static
++int qla_get_tmf(fc_port_t *fcport)
++{
++      struct scsi_qla_host *vha = fcport->vha;
++      struct qla_hw_data *ha = vha->hw;
++      unsigned long flags;
++      int rc = 0;
++      LIST_HEAD(tmf_elem);
++
++      spin_lock_irqsave(&ha->tgt.sess_lock, flags);
++      list_add_tail(&tmf_elem, &fcport->tmf_pending);
++
++      while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
++              spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
++
++              msleep(1);
++
++              spin_lock_irqsave(&ha->tgt.sess_lock, flags);
++              if (fcport->deleted) {
++                      rc = EIO;
++                      break;
++              }
++              if (fcport->active_tmf < MAX_ACTIVE_TMF &&
++                  list_is_first(&tmf_elem, &fcport->tmf_pending))
++                      break;
++      }
++
++      list_del(&tmf_elem);
++
++      if (!rc)
++              fcport->active_tmf++;
++
++      spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
++
++      return rc;
++}
++
+ int
+ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+                    uint32_t tag)
+@@ -2158,18 +2206,19 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_qpair *qpair;
+       struct tmf_arg a;
+-      struct completion comp;
+       int i, rval;
+-      init_completion(&comp);
+       a.vha = fcport->vha;
+       a.fcport = fcport;
+       a.lun = lun;
+-
+-      if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
++      if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
+               a.modifier = MK_SYNC_ID_LUN;
+-      else
++
++              if (qla_get_tmf(fcport))
++                      return QLA_FUNCTION_FAILED;
++      } else {
+               a.modifier = MK_SYNC_ID;
++      }
+       if (vha->hw->mqenable) {
+               for (i = 0; i < vha->hw->num_qpairs; i++) {
+@@ -2188,6 +2237,9 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+       a.flags = flags;
+       rval = __qla2x00_async_tm_cmd(&a);
++      if (a.modifier == MK_SYNC_ID_LUN)
++              qla_put_tmf(fcport);
++
+       return rval;
+ }
+@@ -5423,6 +5475,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
+       INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
+       INIT_LIST_HEAD(&fcport->gnl_entry);
+       INIT_LIST_HEAD(&fcport->list);
++      INIT_LIST_HEAD(&fcport->tmf_pending);
+       INIT_LIST_HEAD(&fcport->sess_cmd_list);
+       spin_lock_init(&fcport->sess_cmd_lock);
+-- 
+2.39.2
+
diff --git a/queue-5.15/scsi-qla2xxx-fix-task-management-cmd-failure.patch b/queue-5.15/scsi-qla2xxx-fix-task-management-cmd-failure.patch
new file mode 100644 (file)
index 0000000..5e644c3
--- /dev/null
@@ -0,0 +1,325 @@
+From 2f94cf7340cc56172560a73a72eb3964522f88e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:34 -0700
+Subject: scsi: qla2xxx: Fix task management cmd failure
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 9803fb5d27597ea98f2e05b0b6cfc48ae808458e ]
+
+Task management cmd failed with status 30h which means
+FW is not able to finish processing one task management
+before another task management for the same lun.
+Hence add wait for completion of marker to space it out.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Link: https://lore.kernel.org/oe-kbuild-all/202304271802.uCZfwQC1-lkp@intel.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-3-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com <mailto:himanshu.madhani@oracle.com>>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h  |   6 ++
+ drivers/scsi/qla2xxx/qla_init.c | 102 +++++++++++++++++++++++++++-----
+ drivers/scsi/qla2xxx/qla_iocb.c |  28 +++++++--
+ drivers/scsi/qla2xxx/qla_isr.c  |  26 +++++++-
+ 4 files changed, 139 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index d4b8d9dd8106d..ca63aa8f33b5d 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -458,6 +458,7 @@ struct tmf_arg {
+       struct scsi_qla_host *vha;
+       u64 lun;
+       u32 flags;
++      uint8_t modifier;
+ };
+ struct els_logo_payload {
+@@ -539,6 +540,10 @@ struct srb_iocb {
+                       uint32_t data;
+                       struct completion comp;
+                       __le16 comp_status;
++
++                      uint8_t modifier;
++                      uint8_t vp_index;
++                      uint16_t loop_id;
+               } tmf;
+               struct {
+ #define SRB_FXDISC_REQ_DMA_VALID      BIT_0
+@@ -642,6 +647,7 @@ struct srb_iocb {
+ #define SRB_SA_UPDATE 25
+ #define SRB_ELS_CMD_HST_NOLOGIN 26
+ #define SRB_SA_REPLACE        27
++#define SRB_MARKER    28
+ struct qla_els_pt_arg {
+       u8 els_opcode;
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index f64c238e3a45b..9d9b16f7f34a6 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2015,6 +2015,80 @@ qla2x00_tmf_iocb_timeout(void *data)
+       }
+ }
++static void qla_marker_sp_done(srb_t *sp, int res)
++{
++      struct srb_iocb *tmf = &sp->u.iocb_cmd;
++
++      if (res != QLA_SUCCESS)
++              ql_dbg(ql_dbg_taskm, sp->vha, 0x8004,
++                  "Async-marker fail hdl=%x portid=%06x ctrl=%x lun=%lld qp=%d.\n",
++                  sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
++                  sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
++
++      complete(&tmf->u.tmf.comp);
++}
++
++#define  START_SP_W_RETRIES(_sp, _rval) \
++{\
++      int cnt = 5; \
++      do { \
++              _rval = qla2x00_start_sp(_sp); \
++              if (_rval == EAGAIN) \
++                      msleep(1); \
++              else \
++                      break; \
++              cnt--; \
++      } while (cnt); \
++}
++
++static int
++qla26xx_marker(struct tmf_arg *arg)
++{
++      struct scsi_qla_host *vha = arg->vha;
++      struct srb_iocb *tm_iocb;
++      srb_t *sp;
++      int rval = QLA_FUNCTION_FAILED;
++      fc_port_t *fcport = arg->fcport;
++
++      /* ref: INIT */
++      sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
++      if (!sp)
++              goto done;
++
++      sp->type = SRB_MARKER;
++      sp->name = "marker";
++      qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), qla_marker_sp_done);
++      sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout;
++
++      tm_iocb = &sp->u.iocb_cmd;
++      init_completion(&tm_iocb->u.tmf.comp);
++      tm_iocb->u.tmf.modifier = arg->modifier;
++      tm_iocb->u.tmf.lun = arg->lun;
++      tm_iocb->u.tmf.loop_id = fcport->loop_id;
++      tm_iocb->u.tmf.vp_index = vha->vp_idx;
++
++      START_SP_W_RETRIES(sp, rval);
++
++      ql_dbg(ql_dbg_taskm, vha, 0x8006,
++          "Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
++          sp->handle, fcport->loop_id, fcport->d_id.b24,
++          arg->modifier, arg->lun, sp->qpair->id, rval);
++
++      if (rval != QLA_SUCCESS) {
++              ql_log(ql_log_warn, vha, 0x8031,
++                  "Marker IOCB failed (%x).\n", rval);
++              goto done_free_sp;
++      }
++
++      wait_for_completion(&tm_iocb->u.tmf.comp);
++
++done_free_sp:
++      /* ref: INIT */
++      kref_put(&sp->cmd_kref, qla2x00_sp_release);
++done:
++      return rval;
++}
++
+ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
+ {
+       struct srb_iocb *tmf = &sp->u.iocb_cmd;
+@@ -2028,7 +2102,6 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+       struct scsi_qla_host *vha = arg->vha;
+       struct srb_iocb *tm_iocb;
+       srb_t *sp;
+-      unsigned long flags;
+       int rval = QLA_FUNCTION_FAILED;
+       fc_port_t *fcport = arg->fcport;
+@@ -2050,11 +2123,12 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+       tm_iocb->u.tmf.flags = arg->flags;
+       tm_iocb->u.tmf.lun = arg->lun;
+-      rval = qla2x00_start_sp(sp);
++      START_SP_W_RETRIES(sp, rval);
++
+       ql_dbg(ql_dbg_taskm, vha, 0x802f,
+-          "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x ctrl=%x.\n",
+-          sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+-          fcport->d_id.b.area, fcport->d_id.b.al_pa, arg->flags);
++          "Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n",
++          sp->handle, fcport->loop_id, fcport->d_id.b24,
++          arg->flags, arg->lun, sp->qpair->id, rval);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+@@ -2067,17 +2141,8 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+                   "TM IOCB failed (%x).\n", rval);
+       }
+-      if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
+-              flags = tm_iocb->u.tmf.flags;
+-              if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|
+-                      TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
+-                      flags = MK_SYNC_ID_LUN;
+-              else
+-                      flags = MK_SYNC_ID;
+-
+-              qla2x00_marker(vha, sp->qpair,
+-                  sp->fcport->loop_id, arg->lun, flags);
+-      }
++      if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
++              rval = qla26xx_marker(arg);
+ done_free_sp:
+       /* ref: INIT */
+@@ -2101,6 +2166,11 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+       a.fcport = fcport;
+       a.lun = lun;
++      if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
++              a.modifier = MK_SYNC_ID_LUN;
++      else
++              a.modifier = MK_SYNC_ID;
++
+       if (vha->hw->mqenable) {
+               for (i = 0; i < vha->hw->num_qpairs; i++) {
+                       qpair = vha->hw->queue_pair_map[i];
+diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
+index ac82392c22eed..c9a686f06d29d 100644
+--- a/drivers/scsi/qla2xxx/qla_iocb.c
++++ b/drivers/scsi/qla2xxx/qla_iocb.c
+@@ -522,21 +522,25 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
+               return (QLA_FUNCTION_FAILED);
+       }
++      mrk24 = (struct mrk_entry_24xx *)mrk;
++
+       mrk->entry_type = MARKER_TYPE;
+       mrk->modifier = type;
+       if (type != MK_SYNC_ALL) {
+               if (IS_FWI2_CAPABLE(ha)) {
+-                      mrk24 = (struct mrk_entry_24xx *) mrk;
+                       mrk24->nport_handle = cpu_to_le16(loop_id);
+                       int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
+                       host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
+                       mrk24->vp_index = vha->vp_idx;
+-                      mrk24->handle = make_handle(req->id, mrk24->handle);
+               } else {
+                       SET_TARGET_ID(ha, mrk->target, loop_id);
+                       mrk->lun = cpu_to_le16((uint16_t)lun);
+               }
+       }
++
++      if (IS_FWI2_CAPABLE(ha))
++              mrk24->handle = QLA_SKIP_HANDLE;
++
+       wmb();
+       qla2x00_start_iocbs(vha, req);
+@@ -3860,9 +3864,9 @@ int qla_get_iocbs_resource(struct srb *sp)
+       case SRB_NACK_LOGO:
+       case SRB_LOGOUT_CMD:
+       case SRB_CTRL_VP:
+-              push_it_through = true;
+-              fallthrough;
++      case SRB_MARKER:
+       default:
++              push_it_through = true;
+               get_exch = false;
+       }
+@@ -3878,6 +3882,19 @@ int qla_get_iocbs_resource(struct srb *sp)
+       return qla_get_fw_resources(sp->qpair, &sp->iores);
+ }
++static void
++qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
++{
++      mrk->entry_type = MARKER_TYPE;
++      mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier;
++      if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) {
++              mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
++              int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun);
++              host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
++              mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index;
++      }
++}
++
+ int
+ qla2x00_start_sp(srb_t *sp)
+ {
+@@ -3981,6 +3998,9 @@ qla2x00_start_sp(srb_t *sp)
+       case SRB_SA_REPLACE:
+               qla24xx_sa_replace_iocb(sp, pkt);
+               break;
++      case SRB_MARKER:
++              qla_marker_iocb(sp, pkt);
++              break;
+       default:
+               break;
+       }
+diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
+index 665959938e5e3..08d43f43995ef 100644
+--- a/drivers/scsi/qla2xxx/qla_isr.c
++++ b/drivers/scsi/qla2xxx/qla_isr.c
+@@ -3737,6 +3737,28 @@ static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
+       return rc;
+ }
++static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
++      struct mrk_entry_24xx *pkt)
++{
++      const char func[] = "MRK-IOCB";
++      srb_t *sp;
++      int res = QLA_SUCCESS;
++
++      if (!IS_FWI2_CAPABLE(vha->hw))
++              return;
++
++      sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
++      if (!sp)
++              return;
++
++      if (pkt->entry_status) {
++              ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n");
++              res = QLA_COMMAND_ERROR;
++      }
++      sp->u.iocb_cmd.u.tmf.data = res;
++      sp->done(sp, res);
++}
++
+ /**
+  * qla24xx_process_response_queue() - Process response queue entries.
+  * @vha: SCSI driver HA context
+@@ -3858,9 +3880,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
+                                       (struct nack_to_isp *)pkt);
+                       break;
+               case MARKER_TYPE:
+-                      /* Do nothing in this case, this check is to prevent it
+-                       * from falling into default case
+-                       */
++                      qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
+                       break;
+               case ABORT_IOCB_TYPE:
+                       qla24xx_abort_iocb_entry(vha, rsp->req,
+-- 
+2.39.2
+
diff --git a/queue-5.15/scsi-qla2xxx-multi-que-support-for-tmf.patch b/queue-5.15/scsi-qla2xxx-multi-que-support-for-tmf.patch
new file mode 100644 (file)
index 0000000..edb0b3c
--- /dev/null
@@ -0,0 +1,200 @@
+From 7a5ff7d37980768885f42d099c91a9a258a920fd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:33 -0700
+Subject: scsi: qla2xxx: Multi-que support for TMF
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit d90171dd0da50212f5950cc708240831e82f2f91 ]
+
+Add queue flush for task management command, before
+placing it on the wire.
+Do IO flush for all Request Q's.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Link: https://lore.kernel.org/oe-kbuild-all/202304271702.GpIL391S-lkp@intel.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-2-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com <mailto:himanshu.madhani@oracle.com>>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h  |  8 ++++
+ drivers/scsi/qla2xxx/qla_gbl.h  |  2 +-
+ drivers/scsi/qla2xxx/qla_init.c | 69 ++++++++++++++++++++++++++-------
+ drivers/scsi/qla2xxx/qla_iocb.c |  5 ++-
+ 4 files changed, 66 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index e674d3fb59269..d4b8d9dd8106d 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -452,6 +452,14 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id)
+       return res;
+ }
++struct tmf_arg {
++      struct qla_qpair *qpair;
++      struct fc_port *fcport;
++      struct scsi_qla_host *vha;
++      u64 lun;
++      u32 flags;
++};
++
+ struct els_logo_payload {
+       uint8_t opcode;
+       uint8_t rsvd[3];
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index 4ed0777cd2a6f..9e467262c0f17 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -69,7 +69,7 @@ extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
+ extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *);
+ extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
+     uint16_t *);
+-extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
++extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint64_t, uint32_t);
+ struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
+     enum qla_work_type);
+ extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 37cb469dc9257..f64c238e3a45b 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2022,17 +2022,19 @@ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
+       complete(&tmf->u.tmf.comp);
+ }
+-int
+-qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+-      uint32_t tag)
++static int
++__qla2x00_async_tm_cmd(struct tmf_arg *arg)
+ {
+-      struct scsi_qla_host *vha = fcport->vha;
++      struct scsi_qla_host *vha = arg->vha;
+       struct srb_iocb *tm_iocb;
+       srb_t *sp;
++      unsigned long flags;
+       int rval = QLA_FUNCTION_FAILED;
++      fc_port_t *fcport = arg->fcport;
++
+       /* ref: INIT */
+-      sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
++      sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+       if (!sp)
+               goto done;
+@@ -2045,15 +2047,15 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+       tm_iocb = &sp->u.iocb_cmd;
+       init_completion(&tm_iocb->u.tmf.comp);
+-      tm_iocb->u.tmf.flags = flags;
+-      tm_iocb->u.tmf.lun = lun;
++      tm_iocb->u.tmf.flags = arg->flags;
++      tm_iocb->u.tmf.lun = arg->lun;
++      rval = qla2x00_start_sp(sp);
+       ql_dbg(ql_dbg_taskm, vha, 0x802f,
+-          "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
++          "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x ctrl=%x.\n",
+           sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+-          fcport->d_id.b.area, fcport->d_id.b.al_pa);
++          fcport->d_id.b.area, fcport->d_id.b.al_pa, arg->flags);
+-      rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+       wait_for_completion(&tm_iocb->u.tmf.comp);
+@@ -2067,12 +2069,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+       if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
+               flags = tm_iocb->u.tmf.flags;
+-              lun = (uint16_t)tm_iocb->u.tmf.lun;
++              if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|
++                      TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
++                      flags = MK_SYNC_ID_LUN;
++              else
++                      flags = MK_SYNC_ID;
+-              /* Issue Marker IOCB */
+-              qla2x00_marker(vha, vha->hw->base_qpair,
+-                  fcport->loop_id, lun,
+-                  flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
++              qla2x00_marker(vha, sp->qpair,
++                  sp->fcport->loop_id, arg->lun, flags);
+       }
+ done_free_sp:
+@@ -2082,6 +2086,41 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+       return rval;
+ }
++int
++qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
++                   uint32_t tag)
++{
++      struct scsi_qla_host *vha = fcport->vha;
++      struct qla_qpair *qpair;
++      struct tmf_arg a;
++      struct completion comp;
++      int i, rval;
++
++      init_completion(&comp);
++      a.vha = fcport->vha;
++      a.fcport = fcport;
++      a.lun = lun;
++
++      if (vha->hw->mqenable) {
++              for (i = 0; i < vha->hw->num_qpairs; i++) {
++                      qpair = vha->hw->queue_pair_map[i];
++                      if (!qpair)
++                              continue;
++                      a.qpair = qpair;
++                      a.flags = flags|TCF_NOTMCMD_TO_TARGET;
++                      rval = __qla2x00_async_tm_cmd(&a);
++                      if (rval)
++                              break;
++              }
++      }
++
++      a.qpair = vha->hw->base_qpair;
++      a.flags = flags;
++      rval = __qla2x00_async_tm_cmd(&a);
++
++      return rval;
++}
++
+ int
+ qla24xx_async_abort_command(srb_t *sp)
+ {
+diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
+index 7a4298388ef1d..ac82392c22eed 100644
+--- a/drivers/scsi/qla2xxx/qla_iocb.c
++++ b/drivers/scsi/qla2xxx/qla_iocb.c
+@@ -2542,7 +2542,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+       scsi_qla_host_t *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       struct srb_iocb *iocb = &sp->u.iocb_cmd;
+-      struct req_que *req = vha->req;
++      struct req_que *req = sp->qpair->req;
+       flags = iocb->u.tmf.flags;
+       lun = iocb->u.tmf.lun;
+@@ -2558,7 +2558,8 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+       tsk->port_id[2] = fcport->d_id.b.domain;
+       tsk->vp_index = fcport->vha->vp_idx;
+-      if (flags == TCF_LUN_RESET) {
++      if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET|
++          TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
+               int_to_scsilun(lun, &tsk->lun);
+               host_to_fcp_swap((uint8_t *)&tsk->lun,
+                       sizeof(tsk->lun));
+-- 
+2.39.2
+
diff --git a/queue-5.15/scsi-qla2xxx-remove-unused-declarations-for-qla2xxx.patch b/queue-5.15/scsi-qla2xxx-remove-unused-declarations-for-qla2xxx.patch
new file mode 100644 (file)
index 0000000..154db33
--- /dev/null
@@ -0,0 +1,109 @@
+From 13832700de34ab55520788122d5f1451b2dc51a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Sep 2022 10:37:21 +0800
+Subject: scsi: qla2xxx: Remove unused declarations for qla2xxx
+
+From: Gaosheng Cui <cuigaosheng1@huawei.com>
+
+[ Upstream commit 1b80addaae099dc33e683d971aba90eeeaf887a3 ]
+
+qla2x00_get_fw_version_str() has been removed since commit abbd8870b9cb
+("[SCSI] qla2xxx: Factor-out ISP specific functions to method-based call
+tables.").
+
+qla2x00_release_nvram_protection() has been removed since commit
+459c537807bd ("[SCSI] qla2xxx: Add ISP24xx flash-manipulation routines.").
+
+qla82xx_rdmem() and qla82xx_wrmem() have been removed since commit
+3711333dfbee ("[SCSI] qla2xxx: Updates for ISP82xx.").
+
+qla25xx_rd_req_reg(), qla24xx_rd_req_reg(), qla25xx_wrt_rsp_reg(),
+qla24xx_wrt_rsp_reg(), qla25xx_wrt_req_reg() and qla24xx_wrt_req_reg() have
+been removed since commit 08029990b25b ("[SCSI] qla2xxx: Refactor
+request/response-queue register handling.").
+
+qla2x00_async_login_done() has been removed since commit 726b85487067
+("qla2xxx: Add framework for async fabric discovery").
+
+qlt_24xx_process_response_error() has been removed since commit
+c5419e2618b9 ("scsi: qla2xxx: Combine Active command arrays.").
+
+Remove the declarations for them from header file.
+
+Link: https://lore.kernel.org/r/20220913023722.547249-2-cuigaosheng1@huawei.com
+Signed-off-by: Gaosheng Cui <cuigaosheng1@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_gbl.h    | 12 ------------
+ drivers/scsi/qla2xxx/qla_target.h |  2 --
+ 2 files changed, 14 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index f82e4a348330a..4ed0777cd2a6f 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -70,8 +70,6 @@ extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *);
+ extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
+     uint16_t *);
+ extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
+-extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
+-    uint16_t *);
+ struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
+     enum qla_work_type);
+ extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
+@@ -278,7 +276,6 @@ extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
+ extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
+ extern void qla2x00_sp_free_dma(srb_t *sp);
+-extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
+ extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
+ extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
+@@ -611,7 +608,6 @@ void __qla_consume_iocb(struct scsi_qla_host *vha, void **pkt, struct rsp_que **
+ /*
+  * Global Function Prototypes in qla_sup.c source file.
+  */
+-extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
+ extern int qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
+     uint32_t, uint32_t);
+ extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+@@ -781,12 +777,6 @@ extern void qla2x00_init_response_q_entries(struct rsp_que *);
+ extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *);
+ extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *);
+ extern int qla25xx_delete_queues(struct scsi_qla_host *);
+-extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t);
+-extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t);
+-extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
+-extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
+-extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+-extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+ /* qlafx00 related functions */
+ extern int qlafx00_pci_config(struct scsi_qla_host *);
+@@ -871,8 +861,6 @@ extern void qla82xx_init_flags(struct qla_hw_data *);
+ extern void qla82xx_set_drv_active(scsi_qla_host_t *);
+ extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32);
+ extern int qla82xx_rd_32(struct qla_hw_data *, ulong);
+-extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int);
+-extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int);
+ /* ISP 8021 IDC */
+ extern void qla82xx_clear_drv_active(struct qla_hw_data *);
+diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
+index 156b950ca7e72..aa83434448377 100644
+--- a/drivers/scsi/qla2xxx/qla_target.h
++++ b/drivers/scsi/qla2xxx/qla_target.h
+@@ -1080,8 +1080,6 @@ extern void qlt_81xx_config_nvram_stage2(struct scsi_qla_host *,
+       struct init_cb_81xx *);
+ extern void qlt_81xx_config_nvram_stage1(struct scsi_qla_host *,
+       struct nvram_81xx *);
+-extern int qlt_24xx_process_response_error(struct scsi_qla_host *,
+-      struct sts_entry_24xx *);
+ extern void qlt_modify_vp_config(struct scsi_qla_host *,
+       struct vp_config_entry_24xx *);
+ extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
+-- 
+2.39.2
+
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e9527f72dbbe04bceec525cc4843890981d22bc0 100644 (file)
@@ -0,0 +1,48 @@
+jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch
+kvm-s390-pv-fix-index-value-of-replaced-asce.patch
+io_uring-don-t-audit-the-capability-check-in-io_urin.patch
+gpio-tps68470-make-tps68470_gpio_output-always-set-t.patch
+gpio-mvebu-make-use-of-devm_pwmchip_add.patch
+gpio-mvebu-fix-irq-domain-leak.patch
+btrfs-fix-race-between-quota-disable-and-relocation.patch
+i2c-delete-error-messages-for-failed-memory-allocati.patch
+i2c-improve-size-determinations.patch
+i2c-nomadik-remove-unnecessary-goto-label.patch
+i2c-nomadik-use-devm_clk_get_enabled.patch
+i2c-nomadik-remove-a-useless-call-in-the-remove-func.patch
+pci-aspm-return-0-or-etimedout-from-pcie_retrain_lin.patch
+pci-aspm-factor-out-pcie_wait_for_retrain.patch
+pci-aspm-avoid-link-retraining-race.patch
+pci-rockchip-remove-writes-to-unused-registers.patch
+pci-rockchip-fix-window-mapping-and-address-translat.patch
+pci-rockchip-don-t-advertise-msi-x-in-pcie-capabilit.patch
+dlm-cleanup-plock_op-vs-plock_xop.patch
+dlm-rearrange-async-condition-return.patch
+fs-dlm-interrupt-posix-locks-only-when-process-is-ki.patch
+drm-ttm-don-t-print-error-message-if-eviction-was-in.patch
+drm-ttm-don-t-leak-a-resource-on-eviction-error.patch
+n_tty-rename-tail-to-old_tail-in-n_tty_read.patch
+tty-fix-hang-on-tty-device-with-no_room-set.patch
+drm-ttm-never-consider-pinned-bos-for-eviction-swap.patch
+cifs-missing-directory-in-maintainers-file.patch
+cifs-use-fs_context-for-automounts.patch
+ksmbd-remove-internal.h-include.patch
+cifs-if-deferred-close-is-disabled-then-close-files-.patch
+pwm-meson-simplify-duplicated-per-channel-tracking.patch
+pwm-meson-fix-handling-of-period-duty-if-greater-tha.patch
+tracing-probes-add-symstr-type-for-dynamic-events.patch
+tracing-probes-fix-to-avoid-double-count-of-the-stri.patch
+tracing-allow-synthetic-events-to-pass-around-stackt.patch
+revert-tracing-add-fault-name-injection-to-kernel-pr.patch
+tracing-probes-fix-to-record-0-length-data_loc-in-fe.patch
+scsi-qla2xxx-remove-unused-declarations-for-qla2xxx.patch
+scsi-qla2xxx-multi-que-support-for-tmf.patch
+scsi-qla2xxx-fix-task-management-cmd-failure.patch
+scsi-qla2xxx-fix-task-management-cmd-fail-due-to-una.patch
+scsi-qla2xxx-add-debug-prints-in-the-device-remove-p.patch
+scsi-qla2xxx-fix-hang-in-task-management.patch
+drm-amdgpu-fix-vkms-crtc-settings.patch
+drm-amdgpu-vkms-relax-timer-deactivation-by-hrtimer_.patch
+jbd2-remove-t_checkpoint_io_list.patch
+jbd2-remove-journal_clean_one_cp_list.patch
+jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
diff --git a/queue-5.15/tracing-allow-synthetic-events-to-pass-around-stackt.patch b/queue-5.15/tracing-allow-synthetic-events-to-pass-around-stackt.patch
new file mode 100644 (file)
index 0000000..e4a3307
--- /dev/null
@@ -0,0 +1,282 @@
+From e79460fddac99eb405ecd2ce0c248072680cbd60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jan 2023 10:21:28 -0500
+Subject: tracing: Allow synthetic events to pass around stacktraces
+
+From: Steven Rostedt (Google) <rostedt@goodmis.org>
+
+[ Upstream commit 00cf3d672a9dd409418647e9f98784c339c3ff63 ]
+
+Allow a stacktrace from one event to be displayed by the end event of a
+synthetic event. This is very useful when looking for the longest latency
+of a sleep or something blocked on I/O.
+
+ # cd /sys/kernel/tracing/
+ # echo 's:block_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events
+ # echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace  if prev_state == 1||prev_state == 2' > events/sched/sched_switch/trigger
+ # echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(block_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger
+
+The above creates a "block_lat" synthetic event that take the stacktrace of
+when a task schedules out in either the interruptible or uninterruptible
+states, and on a new per process max $delta (the time it was scheduled
+out), will print the process id and the stacktrace.
+
+  # echo 1 > events/synthetic/block_lat/enable
+  # cat trace
+ #           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
+ #              | |         |   |||||     |         |
+    kworker/u16:0-767     [006] d..4.   560.645045: block_lat: pid=767 delta=66 stack=STACK:
+ => __schedule
+ => schedule
+ => pipe_read
+ => vfs_read
+ => ksys_read
+ => do_syscall_64
+ => 0x966000aa
+
+           <idle>-0       [003] d..4.   561.132117: block_lat: pid=0 delta=413787 stack=STACK:
+ => __schedule
+ => schedule
+ => schedule_hrtimeout_range_clock
+ => do_sys_poll
+ => __x64_sys_poll
+ => do_syscall_64
+ => 0x966000aa
+
+            <...>-153     [006] d..4.   562.068407: block_lat: pid=153 delta=54 stack=STACK:
+ => __schedule
+ => schedule
+ => io_schedule
+ => rq_qos_wait
+ => wbt_wait
+ => __rq_qos_throttle
+ => blk_mq_submit_bio
+ => submit_bio_noacct_nocheck
+ => ext4_bio_write_page
+ => mpage_submit_page
+ => mpage_process_page_bufs
+ => mpage_prepare_extent_to_map
+ => ext4_do_writepages
+ => ext4_writepages
+ => do_writepages
+ => __writeback_single_inode
+
+Link: https://lkml.kernel.org/r/20230117152236.010941267@goodmis.org
+
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Tom Zanussi <zanussi@kernel.org>
+Cc: Ross Zwisler <zwisler@google.com>
+Cc: Ching-lin Yu <chinglinyu@google.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: 797311bce5c2 ("tracing/probes: Fix to record 0-length data_loc in fetch_store_string*() if fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace.h              |  4 ++
+ kernel/trace/trace_events_hist.c  |  7 ++-
+ kernel/trace/trace_events_synth.c | 80 ++++++++++++++++++++++++++++++-
+ kernel/trace/trace_synth.h        |  1 +
+ 4 files changed, 87 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 2c3d9b6ce1485..33c55c8826a7e 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -113,6 +113,10 @@ enum trace_type {
+ #define MEM_FAIL(condition, fmt, ...)                                 \
+       DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__)
++#define HIST_STACKTRACE_DEPTH 16
++#define HIST_STACKTRACE_SIZE  (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
++#define HIST_STACKTRACE_SKIP  5
++
+ /*
+  * syscalls are special, and need special handling, this is why
+  * they are not included in trace_entries.h
+diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
+index 1b70fc4c703f7..c32a53f089229 100644
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -315,10 +315,6 @@ DEFINE_HIST_FIELD_FN(u8);
+ #define for_each_hist_key_field(i, hist_data) \
+       for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
+-#define HIST_STACKTRACE_DEPTH 16
+-#define HIST_STACKTRACE_SIZE  (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
+-#define HIST_STACKTRACE_SKIP  5
+-
+ #define HITCOUNT_IDX          0
+ #define HIST_KEY_SIZE_MAX     (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE)
+@@ -3431,6 +3427,9 @@ static int check_synth_field(struct synth_event *event,
+           && field->is_dynamic)
+               return 0;
++      if (strstr(hist_field->type, "long[") && field->is_stack)
++              return 0;
++
+       if (strcmp(field->type, hist_field->type) != 0) {
+               if (field->size != hist_field->size ||
+                   (!field->is_string && field->is_signed != hist_field->is_signed))
+diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
+index 08c7df42ade7e..ce8fad956b38d 100644
+--- a/kernel/trace/trace_events_synth.c
++++ b/kernel/trace/trace_events_synth.c
+@@ -165,6 +165,14 @@ static int synth_field_is_string(char *type)
+       return false;
+ }
++static int synth_field_is_stack(char *type)
++{
++      if (strstr(type, "long[") != NULL)
++              return true;
++
++      return false;
++}
++
+ static int synth_field_string_size(char *type)
+ {
+       char buf[4], *end, *start;
+@@ -240,6 +248,8 @@ static int synth_field_size(char *type)
+               size = sizeof(gfp_t);
+       else if (synth_field_is_string(type))
+               size = synth_field_string_size(type);
++      else if (synth_field_is_stack(type))
++              size = 0;
+       return size;
+ }
+@@ -284,6 +294,8 @@ static const char *synth_field_fmt(char *type)
+               fmt = "%x";
+       else if (synth_field_is_string(type))
+               fmt = "%.*s";
++      else if (synth_field_is_stack(type))
++              fmt = "%s";
+       return fmt;
+ }
+@@ -363,6 +375,23 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter,
+                                                i == se->n_fields - 1 ? "" : " ");
+                               n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
+                       }
++              } else if (se->fields[i]->is_stack) {
++                      u32 offset, data_offset, len;
++                      unsigned long *p, *end;
++
++                      offset = (u32)entry->fields[n_u64];
++                      data_offset = offset & 0xffff;
++                      len = offset >> 16;
++
++                      p = (void *)entry + data_offset;
++                      end = (void *)p + len - (sizeof(long) - 1);
++
++                      trace_seq_printf(s, "%s=STACK:\n", se->fields[i]->name);
++
++                      for (; *p && p < end; p++)
++                              trace_seq_printf(s, "=> %pS\n", (void *)*p);
++                      n_u64++;
++
+               } else {
+                       struct trace_print_flags __flags[] = {
+                           __def_gfpflag_names, {-1, NULL} };
+@@ -439,6 +468,43 @@ static unsigned int trace_string(struct synth_trace_event *entry,
+       return len;
+ }
++static unsigned int trace_stack(struct synth_trace_event *entry,
++                               struct synth_event *event,
++                               long *stack,
++                               unsigned int data_size,
++                               unsigned int *n_u64)
++{
++      unsigned int len;
++      u32 data_offset;
++      void *data_loc;
++
++      data_offset = struct_size(entry, fields, event->n_u64);
++      data_offset += data_size;
++
++      for (len = 0; len < HIST_STACKTRACE_DEPTH; len++) {
++              if (!stack[len])
++                      break;
++      }
++
++      /* Include the zero'd element if it fits */
++      if (len < HIST_STACKTRACE_DEPTH)
++              len++;
++
++      len *= sizeof(long);
++
++      /* Find the dynamic section to copy the stack into. */
++      data_loc = (void *)entry + data_offset;
++      memcpy(data_loc, stack, len);
++
++      /* Fill in the field that holds the offset/len combo */
++      data_offset |= len << 16;
++      *(u32 *)&entry->fields[*n_u64] = data_offset;
++
++      (*n_u64)++;
++
++      return len;
++}
++
+ static notrace void trace_event_raw_event_synth(void *__data,
+                                               u64 *var_ref_vals,
+                                               unsigned int *var_ref_idx)
+@@ -491,6 +557,12 @@ static notrace void trace_event_raw_event_synth(void *__data,
+                                          event->fields[i]->is_dynamic,
+                                          data_size, &n_u64);
+                       data_size += len; /* only dynamic string increments */
++              } if (event->fields[i]->is_stack) {
++                      long *stack = (long *)(long)var_ref_vals[val_idx];
++
++                      len = trace_stack(entry, event, stack,
++                                         data_size, &n_u64);
++                      data_size += len;
+               } else {
+                       struct synth_field *field = event->fields[i];
+                       u64 val = var_ref_vals[val_idx];
+@@ -553,6 +625,9 @@ static int __set_synth_event_print_fmt(struct synth_event *event,
+                   event->fields[i]->is_dynamic)
+                       pos += snprintf(buf + pos, LEN_OR_ZERO,
+                               ", __get_str(%s)", event->fields[i]->name);
++              else if (event->fields[i]->is_stack)
++                      pos += snprintf(buf + pos, LEN_OR_ZERO,
++                              ", __get_stacktrace(%s)", event->fields[i]->name);
+               else
+                       pos += snprintf(buf + pos, LEN_OR_ZERO,
+                                       ", REC->%s", event->fields[i]->name);
+@@ -689,7 +764,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
+               ret = -EINVAL;
+               goto free;
+       } else if (size == 0) {
+-              if (synth_field_is_string(field->type)) {
++              if (synth_field_is_string(field->type) ||
++                  synth_field_is_stack(field->type)) {
+                       char *type;
+                       len = sizeof("__data_loc ") + strlen(field->type) + 1;
+@@ -720,6 +796,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
+       if (synth_field_is_string(field->type))
+               field->is_string = true;
++      else if (synth_field_is_stack(field->type))
++              field->is_stack = true;
+       field->is_signed = synth_field_signed(field->type);
+  out:
+diff --git a/kernel/trace/trace_synth.h b/kernel/trace/trace_synth.h
+index b29595fe3ac5a..43f6fb6078dbf 100644
+--- a/kernel/trace/trace_synth.h
++++ b/kernel/trace/trace_synth.h
+@@ -18,6 +18,7 @@ struct synth_field {
+       bool is_signed;
+       bool is_string;
+       bool is_dynamic;
++      bool is_stack;
+ };
+ struct synth_event {
+-- 
+2.39.2
+
diff --git a/queue-5.15/tracing-probes-add-symstr-type-for-dynamic-events.patch b/queue-5.15/tracing-probes-add-symstr-type-for-dynamic-events.patch
new file mode 100644 (file)
index 0000000..f90ec62
--- /dev/null
@@ -0,0 +1,313 @@
+From 2042d57a437472c231b19ad0094733936e7981ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Nov 2022 13:47:56 +0900
+Subject: tracing/probes: Add symstr type for dynamic events
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit b26a124cbfa80f42bfc4e63e1d5643ca98159d66 ]
+
+Add 'symstr' type for storing the kernel symbol as a string data
+instead of the symbol address. This allows us to filter the
+events by wildcard symbol name.
+
+e.g.
+  # echo 'e:wqfunc workqueue.workqueue_execute_start symname=$function:symstr' >> dynamic_events
+  # cat events/eprobes/wqfunc/format
+  name: wqfunc
+  ID: 2110
+  format:
+       field:unsigned short common_type;       offset:0;       size:2; signed:0;
+       field:unsigned char common_flags;       offset:2;       size:1; signed:0;
+       field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
+       field:int common_pid;   offset:4;       size:4; signed:1;
+
+       field:__data_loc char[] symname;        offset:8;       size:4; signed:1;
+
+  print fmt: " symname=\"%s\"", __get_str(symname)
+
+Note that there is already 'symbol' type which just change the
+print format (so it still stores the symbol address in the tracing
+ring buffer.) On the other hand, 'symstr' type stores the actual
+"symbol+offset/size" data as a string.
+
+Link: https://lore.kernel.org/all/166679930847.1528100.4124308529180235965.stgit@devnote3/
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Stable-dep-of: 66bcf65d6cf0 ("tracing/probes: Fix to avoid double count of the string length on the array")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/trace/kprobetrace.rst |  8 +++--
+ kernel/trace/trace.c                |  2 +-
+ kernel/trace/trace_probe.c          | 44 ++++++++++++++++++---------
+ kernel/trace/trace_probe.h          | 16 +++++++---
+ kernel/trace/trace_probe_tmpl.h     | 47 +++++++++++++++++++++++++++--
+ 5 files changed, 91 insertions(+), 26 deletions(-)
+
+diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
+index b175d88f31ebb..15e4bfa2bd83c 100644
+--- a/Documentation/trace/kprobetrace.rst
++++ b/Documentation/trace/kprobetrace.rst
+@@ -58,8 +58,8 @@ Synopsis of kprobe_events
+   NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
+   FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
+                 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
+-                (x8/x16/x32/x64), "string", "ustring" and bitfield
+-                are supported.
++                (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr"
++                  and bitfield are supported.
+   (\*1) only for the probe on function entry (offs == 0).
+   (\*2) only for return probe.
+@@ -96,6 +96,10 @@ offset, and container-size (usually 32). The syntax is::
+ Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
+ which shows given pointer in "symbol+offset" style.
++On the other hand, symbol-string type ('symstr') converts the given address to
++"symbol+offset/symbolsize" style and stores it as a null-terminated string.
++With 'symstr' type, you can filter the event with wildcard pattern of the
++symbols, and you don't need to solve symbol name by yourself.
+ For $comm, the default type is "string"; any other type is invalid.
+ .. _user_mem_access:
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index 1dda36c7e5eb5..ae7005af78c34 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -5609,7 +5609,7 @@ static const char readme_msg[] =
+       "\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
+       "\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
+       "\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
+-      "\t           <type>\\[<array-size>\\]\n"
++      "\t           symstr, <type>\\[<array-size>\\]\n"
+ #ifdef CONFIG_HIST_TRIGGERS
+       "\t    field: <stype> <name>;\n"
+       "\t    stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
+diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
+index cb8f9fe5669ad..90bae188d0928 100644
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -76,9 +76,11 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
+ /* Fetch type information table */
+ static const struct fetch_type probe_fetch_types[] = {
+       /* Special types */
+-      __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
++      __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, 1,
+                           "__data_loc char[]"),
+-      __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,
++      __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, 1,
++                          "__data_loc char[]"),
++      __ASSIGN_FETCH_TYPE("symstr", string, string, sizeof(u32), 1, 1,
+                           "__data_loc char[]"),
+       /* Basic types */
+       ASSIGN_FETCH_TYPE(u8,  u8,  0),
+@@ -658,16 +660,26 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
+       ret = -EINVAL;
+       /* Store operation */
+-      if (!strcmp(parg->type->name, "string") ||
+-          !strcmp(parg->type->name, "ustring")) {
+-              if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
+-                  code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
+-                  code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
+-                      trace_probe_log_err(offset + (t ? (t - arg) : 0),
+-                                          BAD_STRING);
+-                      goto fail;
++      if (parg->type->is_string) {
++              if (!strcmp(parg->type->name, "symstr")) {
++                      if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
++                          code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
++                          code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
++                              trace_probe_log_err(offset + (t ? (t - arg) : 0),
++                                                  BAD_SYMSTRING);
++                              goto fail;
++                      }
++              } else {
++                      if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
++                          code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
++                          code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
++                              trace_probe_log_err(offset + (t ? (t - arg) : 0),
++                                                  BAD_STRING);
++                              goto fail;
++                      }
+               }
+-              if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
++              if (!strcmp(parg->type->name, "symstr") ||
++                  (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
+                    code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
+                    parg->count) {
+                       /*
+@@ -675,6 +687,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
+                        * must be kept, and if parg->count != 0, this is an
+                        * array of string pointers instead of string address
+                        * itself.
++                       * For the symstr, it doesn't need to dereference, thus
++                       * it just get the value.
+                        */
+                       code++;
+                       if (code->op != FETCH_OP_NOP) {
+@@ -686,6 +700,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
+               if (!strcmp(parg->type->name, "ustring") ||
+                   code->op == FETCH_OP_UDEREF)
+                       code->op = FETCH_OP_ST_USTRING;
++              else if (!strcmp(parg->type->name, "symstr"))
++                      code->op = FETCH_OP_ST_SYMSTR;
+               else
+                       code->op = FETCH_OP_ST_STRING;
+               code->size = parg->type->size;
+@@ -915,8 +931,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
+       for (i = 0; i < tp->nr_args; i++) {
+               parg = tp->args + i;
+               if (parg->count) {
+-                      if ((strcmp(parg->type->name, "string") == 0) ||
+-                          (strcmp(parg->type->name, "ustring") == 0))
++                      if (parg->type->is_string)
+                               fmt = ", __get_str(%s[%d])";
+                       else
+                               fmt = ", REC->%s[%d]";
+@@ -924,8 +939,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
+                               pos += snprintf(buf + pos, LEN_OR_ZERO,
+                                               fmt, parg->name, j);
+               } else {
+-                      if ((strcmp(parg->type->name, "string") == 0) ||
+-                          (strcmp(parg->type->name, "ustring") == 0))
++                      if (parg->type->is_string)
+                               fmt = ", __get_str(%s)";
+                       else
+                               fmt = ", REC->%s";
+diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
+index 84d495cbd876a..0f0e5005b97a0 100644
+--- a/kernel/trace/trace_probe.h
++++ b/kernel/trace/trace_probe.h
+@@ -99,6 +99,7 @@ enum fetch_op {
+       FETCH_OP_ST_UMEM,       /* Mem: .offset, .size */
+       FETCH_OP_ST_STRING,     /* String: .offset, .size */
+       FETCH_OP_ST_USTRING,    /* User String: .offset, .size */
++      FETCH_OP_ST_SYMSTR,     /* Kernel Symbol String: .offset, .size */
+       // Stage 4 (modify) op
+       FETCH_OP_MOD_BF,        /* Bitfield: .basesize, .lshift, .rshift */
+       // Stage 5 (loop) op
+@@ -134,7 +135,8 @@ struct fetch_insn {
+ struct fetch_type {
+       const char              *name;          /* Name of type */
+       size_t                  size;           /* Byte size of type */
+-      int                     is_signed;      /* Signed flag */
++      bool                    is_signed;      /* Signed flag */
++      bool                    is_string;      /* String flag */
+       print_type_func_t       print;          /* Print functions */
+       const char              *fmt;           /* Format string */
+       const char              *fmttype;       /* Name in format file */
+@@ -178,16 +180,19 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
+ #define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
+ #define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
+-#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)       \
+-      {.name = _name,                         \
++#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, str, _fmttype)  \
++      {.name = _name,                                 \
+        .size = _size,                                 \
+-       .is_signed = sign,                             \
++       .is_signed = (bool)sign,                       \
++       .is_string = (bool)str,                        \
+        .print = PRINT_TYPE_FUNC_NAME(ptype),          \
+        .fmt = PRINT_TYPE_FMT_NAME(ptype),             \
+        .fmttype = _fmttype,                           \
+       }
++
++/* Non string types can use these macros */
+ #define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)        \
+-      __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)
++      __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, 0, #_fmttype)
+ #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)                 \
+       _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
+@@ -432,6 +437,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+       C(ARRAY_TOO_BIG,        "Array number is too big"),             \
+       C(BAD_TYPE,             "Unknown type is specified"),           \
+       C(BAD_STRING,           "String accepts only memory argument"), \
++      C(BAD_SYMSTRING,        "Symbol String doesn't accept data/userdata"),  \
+       C(BAD_BITFIELD,         "Invalid bitfield"),                    \
+       C(ARG_NAME_TOO_LONG,    "Argument name is too long"),           \
+       C(NO_ARG_NAME,          "Argument name is not specified"),      \
+diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
+index c293a607d5366..21799fa813ca8 100644
+--- a/kernel/trace/trace_probe_tmpl.h
++++ b/kernel/trace/trace_probe_tmpl.h
+@@ -67,6 +67,37 @@ probe_mem_read(void *dest, void *src, size_t size);
+ static nokprobe_inline int
+ probe_mem_read_user(void *dest, void *src, size_t size);
++static nokprobe_inline int
++fetch_store_symstrlen(unsigned long addr)
++{
++      char namebuf[KSYM_SYMBOL_LEN];
++      int ret;
++
++      ret = sprint_symbol(namebuf, addr);
++      if (ret < 0)
++              return 0;
++
++      return ret + 1;
++}
++
++/*
++ * Fetch a null-terminated symbol string + offset. Caller MUST set *(u32 *)buf
++ * with max length and relative data location.
++ */
++static nokprobe_inline int
++fetch_store_symstring(unsigned long addr, void *dest, void *base)
++{
++      int maxlen = get_loc_len(*(u32 *)dest);
++      void *__dest;
++
++      if (unlikely(!maxlen))
++              return -ENOMEM;
++
++      __dest = get_loc_data(dest, base);
++
++      return sprint_symbol(__dest, addr);
++}
++
+ /* From the 2nd stage, routine is same */
+ static nokprobe_inline int
+ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+@@ -99,16 +130,22 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+ stage3:
+       /* 3rd stage: store value to buffer */
+       if (unlikely(!dest)) {
+-              if (code->op == FETCH_OP_ST_STRING) {
++              switch (code->op) {
++              case FETCH_OP_ST_STRING:
+                       ret = fetch_store_strlen(val + code->offset);
+                       code++;
+                       goto array;
+-              } else if (code->op == FETCH_OP_ST_USTRING) {
++              case FETCH_OP_ST_USTRING:
+                       ret += fetch_store_strlen_user(val + code->offset);
+                       code++;
+                       goto array;
+-              } else
++              case FETCH_OP_ST_SYMSTR:
++                      ret += fetch_store_symstrlen(val + code->offset);
++                      code++;
++                      goto array;
++              default:
+                       return -EILSEQ;
++              }
+       }
+       switch (code->op) {
+@@ -129,6 +166,10 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+               loc = *(u32 *)dest;
+               ret = fetch_store_string_user(val + code->offset, dest, base);
+               break;
++      case FETCH_OP_ST_SYMSTR:
++              loc = *(u32 *)dest;
++              ret = fetch_store_symstring(val + code->offset, dest, base);
++              break;
+       default:
+               return -EILSEQ;
+       }
+-- 
+2.39.2
+
diff --git a/queue-5.15/tracing-probes-fix-to-avoid-double-count-of-the-stri.patch b/queue-5.15/tracing-probes-fix-to-avoid-double-count-of-the-stri.patch
new file mode 100644 (file)
index 0000000..75b02f2
--- /dev/null
@@ -0,0 +1,49 @@
+From 59d2bace78087a3c5992fcad7bc5ae9dcecb68de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 23:15:29 +0900
+Subject: tracing/probes: Fix to avoid double count of the string length on the
+ array
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 66bcf65d6cf0ca6540e2341e88ee7ef02dbdda08 ]
+
+If an array is specified with the ustring or symstr, the length of the
+strings are accumlated on both of 'ret' and 'total', which means the
+length is double counted.
+Just set the length to the 'ret' value for avoiding double counting.
+
+Link: https://lore.kernel.org/all/168908492917.123124.15076463491122036025.stgit@devnote2/
+
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/all/8819b154-2ba1-43c3-98a2-cbde20892023@moroto.mountain/
+Fixes: 88903c464321 ("tracing/probe: Add ustring type for user-space string")
+Cc: stable@vger.kernel.org
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_probe_tmpl.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
+index 21799fa813ca8..98ac09052fea4 100644
+--- a/kernel/trace/trace_probe_tmpl.h
++++ b/kernel/trace/trace_probe_tmpl.h
+@@ -136,11 +136,11 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+                       code++;
+                       goto array;
+               case FETCH_OP_ST_USTRING:
+-                      ret += fetch_store_strlen_user(val + code->offset);
++                      ret = fetch_store_strlen_user(val + code->offset);
+                       code++;
+                       goto array;
+               case FETCH_OP_ST_SYMSTR:
+-                      ret += fetch_store_symstrlen(val + code->offset);
++                      ret = fetch_store_symstrlen(val + code->offset);
+                       code++;
+                       goto array;
+               default:
+-- 
+2.39.2
+
diff --git a/queue-5.15/tracing-probes-fix-to-record-0-length-data_loc-in-fe.patch b/queue-5.15/tracing-probes-fix-to-record-0-length-data_loc-in-fe.patch
new file mode 100644 (file)
index 0000000..f0862cf
--- /dev/null
@@ -0,0 +1,109 @@
+From 8de4149670d00bd10367a4990957857868abf239 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 23:16:07 +0900
+Subject: tracing/probes: Fix to record 0-length data_loc in
+ fetch_store_string*() if fails
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 797311bce5c2ac90b8d65e357603cfd410d36ebb ]
+
+Fix to record 0-length data to data_loc in fetch_store_string*() if it fails
+to get the string data.
+Currently those expect that the data_loc is updated by store_trace_args() if
+it returns the error code. However, that does not work correctly if the
+argument is an array of strings. In that case, store_trace_args() only clears
+the first entry of the array (which may have no error) and leaves other
+entries. So it should be cleared by fetch_store_string*() itself.
+Also, 'dyndata' and 'maxlen' in store_trace_args() should be updated
+only if it is used (ret > 0 and argument is a dynamic data.)
+
+Link: https://lore.kernel.org/all/168908496683.123124.4761206188794205601.stgit@devnote2/
+
+Fixes: 40b53b771806 ("tracing: probeevent: Add array type support")
+Cc: stable@vger.kernel.org
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_probe_kernel.h | 13 +++++++++----
+ kernel/trace/trace_probe_tmpl.h   | 10 +++-------
+ kernel/trace/trace_uprobe.c       |  3 ++-
+ 3 files changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/kernel/trace/trace_probe_kernel.h b/kernel/trace/trace_probe_kernel.h
+index 1d43df29a1f8e..2da70be83831c 100644
+--- a/kernel/trace/trace_probe_kernel.h
++++ b/kernel/trace/trace_probe_kernel.h
+@@ -37,6 +37,13 @@ kern_fetch_store_strlen(unsigned long addr)
+       return (ret < 0) ? ret : len;
+ }
++static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base)
++{
++      if (ret < 0)
++              ret = 0;
++      *(u32 *)dest = make_data_loc(ret, __dest - base);
++}
++
+ /*
+  * Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf
+  * with max length and relative data location.
+@@ -55,8 +62,7 @@ kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
+       __dest = get_loc_data(dest, base);
+       ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
+-      if (ret >= 0)
+-              *(u32 *)dest = make_data_loc(ret, __dest - base);
++      set_data_loc(ret, dest, __dest, base);
+       return ret;
+ }
+@@ -87,8 +93,7 @@ kern_fetch_store_string(unsigned long addr, void *dest, void *base)
+        * probing.
+        */
+       ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
+-      if (ret >= 0)
+-              *(u32 *)dest = make_data_loc(ret, __dest - base);
++      set_data_loc(ret, dest, __dest, base);
+       return ret;
+ }
+diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
+index 98ac09052fea4..3e2f5a43b974c 100644
+--- a/kernel/trace/trace_probe_tmpl.h
++++ b/kernel/trace/trace_probe_tmpl.h
+@@ -247,13 +247,9 @@ store_trace_args(void *data, struct trace_probe *tp, void *rec,
+               if (unlikely(arg->dynamic))
+                       *dl = make_data_loc(maxlen, dyndata - base);
+               ret = process_fetch_insn(arg->code, rec, dl, base);
+-              if (arg->dynamic) {
+-                      if (unlikely(ret < 0)) {
+-                              *dl = make_data_loc(0, dyndata - base);
+-                      } else {
+-                              dyndata += ret;
+-                              maxlen -= ret;
+-                      }
++              if (arg->dynamic && likely(ret > 0)) {
++                      dyndata += ret;
++                      maxlen -= ret;
+               }
+       }
+ }
+diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
+index 78ec1c16ccf4b..debc651015489 100644
+--- a/kernel/trace/trace_uprobe.c
++++ b/kernel/trace/trace_uprobe.c
+@@ -168,7 +168,8 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
+                        */
+                       ret++;
+               *(u32 *)dest = make_data_loc(ret, (void *)dst - base);
+-      }
++      } else
++              *(u32 *)dest = make_data_loc(0, (void *)dst - base);
+       return ret;
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.15/tty-fix-hang-on-tty-device-with-no_room-set.patch b/queue-5.15/tty-fix-hang-on-tty-device-with-no_room-set.patch
new file mode 100644 (file)
index 0000000..17db7ce
--- /dev/null
@@ -0,0 +1,116 @@
+From 04ea13fcf5ac39d5faed5c4a0f51f20aa9d4816a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Apr 2023 10:44:50 +0800
+Subject: tty: fix hang on tty device with no_room set
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Hui Li <caelli@tencent.com>
+
+[ Upstream commit 4903fde8047a28299d1fc79c1a0dcc255e928f12 ]
+
+It is possible to hang pty devices in this case, the reader was
+blocking at epoll on master side, the writer was sleeping at
+wait_woken inside n_tty_write on slave side, and the write buffer
+on tty_port was full, we found that the reader and writer would
+never be woken again and blocked forever.
+
+The problem was caused by a race between reader and kworker:
+n_tty_read(reader):  n_tty_receive_buf_common(kworker):
+copy_from_read_buf()|
+                    |room = N_TTY_BUF_SIZE - (ldata->read_head - tail)
+                    |room <= 0
+n_tty_kick_worker() |
+                    |ldata->no_room = true
+
+After writing to slave device, writer wakes up kworker to flush
+data on tty_port to reader, and the kworker finds that reader
+has no room to store data so room <= 0 is met. At this moment,
+reader consumes all the data on reader buffer and calls
+n_tty_kick_worker to check ldata->no_room which is false and
+reader quits reading. Then kworker sets ldata->no_room=true
+and quits too.
+
+If write buffer is not full, writer will wake kworker to flush data
+again after following writes, but if write buffer is full and writer
+goes to sleep, kworker will never be woken again and tty device is
+blocked.
+
+This problem can be solved with a check for read buffer size inside
+n_tty_receive_buf_common, if read buffer is empty and ldata->no_room
+is true, a call to n_tty_kick_worker is necessary to keep flushing
+data to reader.
+
+Cc: <stable@vger.kernel.org>
+Fixes: 42458f41d08f ("n_tty: Ensure reader restarts worker for next reader")
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Hui Li <caelli@tencent.com>
+Message-ID: <1680749090-14106-1-git-send-email-caelli@tencent.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_tty.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
+index 8f57448e1ce46..6259249b11670 100644
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -202,8 +202,8 @@ static void n_tty_kick_worker(struct tty_struct *tty)
+       struct n_tty_data *ldata = tty->disc_data;
+       /* Did the input worker stop? Restart it */
+-      if (unlikely(ldata->no_room)) {
+-              ldata->no_room = 0;
++      if (unlikely(READ_ONCE(ldata->no_room))) {
++              WRITE_ONCE(ldata->no_room, 0);
+               WARN_RATELIMIT(tty->port->itty == NULL,
+                               "scheduling with invalid itty\n");
+@@ -1661,7 +1661,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
+                       if (overflow && room < 0)
+                               ldata->read_head--;
+                       room = overflow;
+-                      ldata->no_room = flow && !room;
++                      WRITE_ONCE(ldata->no_room, flow && !room);
+               } else
+                       overflow = 0;
+@@ -1692,6 +1692,17 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
+       } else
+               n_tty_check_throttle(tty);
++      if (unlikely(ldata->no_room)) {
++              /*
++               * Barrier here is to ensure to read the latest read_tail in
++               * chars_in_buffer() and to make sure that read_tail is not loaded
++               * before ldata->no_room is set.
++               */
++              smp_mb();
++              if (!chars_in_buffer(tty))
++                      n_tty_kick_worker(tty);
++      }
++
+       up_read(&tty->termios_rwsem);
+       return rcvd;
+@@ -2252,8 +2263,14 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+               if (time)
+                       timeout = time;
+       }
+-      if (old_tail != ldata->read_tail)
++      if (old_tail != ldata->read_tail) {
++              /*
++               * Make sure no_room is not read in n_tty_kick_worker()
++               * before setting ldata->read_tail in copy_from_read_buf().
++               */
++              smp_mb();
+               n_tty_kick_worker(tty);
++      }
+       up_read(&tty->termios_rwsem);
+       remove_wait_queue(&tty->read_wait, &wait);
+-- 
+2.39.2
+