]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.19
authorSasha Levin <sashal@kernel.org>
Sat, 10 Sep 2022 17:15:15 +0000 (13:15 -0400)
committerSasha Levin <sashal@kernel.org>
Sat, 10 Sep 2022 17:15:15 +0000 (13:15 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.19/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch [new file with mode: 0644]
queue-5.19/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch [new file with mode: 0644]
queue-5.19/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch [new file with mode: 0644]
queue-5.19/series
queue-5.19/smb3-missing-inode-locks-in-zero-range.patch [new file with mode: 0644]

diff --git a/queue-5.19/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch b/queue-5.19/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch
new file mode 100644 (file)
index 0000000..39c52e3
--- /dev/null
@@ -0,0 +1,81 @@
+From 5ad3746c25ab98e6a12f0ea9f0d7af964749bee6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Jul 2022 18:38:15 -1000
+Subject: cgroup: Elide write-locking threadgroup_rwsem when updating csses on
+ an empty subtree
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 671c11f0619e5ccb380bcf0f062f69ba95fc974a ]
+
+cgroup_update_dfl_csses() write-lock the threadgroup_rwsem as updating the
+csses can trigger process migrations. However, if the subtree doesn't
+contain any tasks, there aren't gonna be any cgroup migrations. This
+condition can be trivially detected by testing whether
+mgctx.preloaded_src_csets is empty. Elide write-locking threadgroup_rwsem if
+the subtree is empty.
+
+After this optimization, the usage pattern of creating a cgroup, enabling
+the necessary controllers, and then seeding it with CLONE_INTO_CGROUP and
+then removing the cgroup after it becomes empty doesn't need to write-lock
+threadgroup_rwsem at all.
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Cc: Christian Brauner <brauner@kernel.org>
+Cc: Michal Koutný <mkoutny@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/cgroup.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index ce95aee05e8ae..ed4d6bf85e725 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -2950,12 +2950,11 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
+       struct cgroup_subsys_state *d_css;
+       struct cgroup *dsct;
+       struct css_set *src_cset;
++      bool has_tasks;
+       int ret;
+       lockdep_assert_held(&cgroup_mutex);
+-      percpu_down_write(&cgroup_threadgroup_rwsem);
+-
+       /* look up all csses currently attached to @cgrp's subtree */
+       spin_lock_irq(&css_set_lock);
+       cgroup_for_each_live_descendant_pre(dsct, d_css, cgrp) {
+@@ -2966,6 +2965,16 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
+       }
+       spin_unlock_irq(&css_set_lock);
++      /*
++       * We need to write-lock threadgroup_rwsem while migrating tasks.
++       * However, if there are no source csets for @cgrp, changing its
++       * controllers isn't gonna produce any task migrations and the
++       * write-locking can be skipped safely.
++       */
++      has_tasks = !list_empty(&mgctx.preloaded_src_csets);
++      if (has_tasks)
++              percpu_down_write(&cgroup_threadgroup_rwsem);
++
+       /* NULL dst indicates self on default hierarchy */
+       ret = cgroup_migrate_prepare_dst(&mgctx);
+       if (ret)
+@@ -2985,7 +2994,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
+       ret = cgroup_migrate_execute(&mgctx);
+ out_finish:
+       cgroup_migrate_finish(&mgctx);
+-      percpu_up_write(&cgroup_threadgroup_rwsem);
++      if (has_tasks)
++              percpu_up_write(&cgroup_threadgroup_rwsem);
+       return ret;
+ }
+-- 
+2.35.1
+
diff --git a/queue-5.19/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch b/queue-5.19/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch
new file mode 100644 (file)
index 0000000..ba26422
--- /dev/null
@@ -0,0 +1,207 @@
+From 46d39bc2faa71f684f98fb0413124b08dab18a3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 15 Aug 2022 13:27:38 -1000
+Subject: cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock
+
+From: Tejun Heo <tj@kernel.org>
+
+[ Upstream commit 4f7e7236435ca0abe005c674ebd6892c6e83aeb3 ]
+
+Bringing up a CPU may involve creating and destroying tasks which requires
+read-locking threadgroup_rwsem, so threadgroup_rwsem nests inside
+cpus_read_lock(). However, cpuset's ->attach(), which may be called with
+thredagroup_rwsem write-locked, also wants to disable CPU hotplug and
+acquires cpus_read_lock(), leading to a deadlock.
+
+Fix it by guaranteeing that ->attach() is always called with CPU hotplug
+disabled and removing cpus_read_lock() call from cpuset_attach().
+
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Reviewed-and-tested-by: Imran Khan <imran.f.khan@oracle.com>
+Reported-and-tested-by: Xuewen Yan <xuewen.yan@unisoc.com>
+Fixes: 05c7b7a92cc8 ("cgroup/cpuset: Fix a race between cpuset_attach() and cpu hotplug")
+Cc: stable@vger.kernel.org # v5.17+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/cgroup/cgroup.c | 77 +++++++++++++++++++++++++++++-------------
+ kernel/cgroup/cpuset.c |  3 +-
+ 2 files changed, 55 insertions(+), 25 deletions(-)
+
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index ed4d6bf85e725..e702ca368539a 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -2346,6 +2346,47 @@ int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen)
+ }
+ EXPORT_SYMBOL_GPL(task_cgroup_path);
++/**
++ * cgroup_attach_lock - Lock for ->attach()
++ * @lock_threadgroup: whether to down_write cgroup_threadgroup_rwsem
++ *
++ * cgroup migration sometimes needs to stabilize threadgroups against forks and
++ * exits by write-locking cgroup_threadgroup_rwsem. However, some ->attach()
++ * implementations (e.g. cpuset), also need to disable CPU hotplug.
++ * Unfortunately, letting ->attach() operations acquire cpus_read_lock() can
++ * lead to deadlocks.
++ *
++ * Bringing up a CPU may involve creating and destroying tasks which requires
++ * read-locking threadgroup_rwsem, so threadgroup_rwsem nests inside
++ * cpus_read_lock(). If we call an ->attach() which acquires the cpus lock while
++ * write-locking threadgroup_rwsem, the locking order is reversed and we end up
++ * waiting for an on-going CPU hotplug operation which in turn is waiting for
++ * the threadgroup_rwsem to be released to create new tasks. For more details:
++ *
++ *   http://lkml.kernel.org/r/20220711174629.uehfmqegcwn2lqzu@wubuntu
++ *
++ * Resolve the situation by always acquiring cpus_read_lock() before optionally
++ * write-locking cgroup_threadgroup_rwsem. This allows ->attach() to assume that
++ * CPU hotplug is disabled on entry.
++ */
++static void cgroup_attach_lock(bool lock_threadgroup)
++{
++      cpus_read_lock();
++      if (lock_threadgroup)
++              percpu_down_write(&cgroup_threadgroup_rwsem);
++}
++
++/**
++ * cgroup_attach_unlock - Undo cgroup_attach_lock()
++ * @lock_threadgroup: whether to up_write cgroup_threadgroup_rwsem
++ */
++static void cgroup_attach_unlock(bool lock_threadgroup)
++{
++      if (lock_threadgroup)
++              percpu_up_write(&cgroup_threadgroup_rwsem);
++      cpus_read_unlock();
++}
++
+ /**
+  * cgroup_migrate_add_task - add a migration target task to a migration context
+  * @task: target task
+@@ -2822,8 +2863,7 @@ int cgroup_attach_task(struct cgroup *dst_cgrp, struct task_struct *leader,
+ }
+ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup,
+-                                           bool *locked)
+-      __acquires(&cgroup_threadgroup_rwsem)
++                                           bool *threadgroup_locked)
+ {
+       struct task_struct *tsk;
+       pid_t pid;
+@@ -2840,12 +2880,8 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup,
+        * Therefore, we can skip the global lock.
+        */
+       lockdep_assert_held(&cgroup_mutex);
+-      if (pid || threadgroup) {
+-              percpu_down_write(&cgroup_threadgroup_rwsem);
+-              *locked = true;
+-      } else {
+-              *locked = false;
+-      }
++      *threadgroup_locked = pid || threadgroup;
++      cgroup_attach_lock(*threadgroup_locked);
+       rcu_read_lock();
+       if (pid) {
+@@ -2876,17 +2912,14 @@ struct task_struct *cgroup_procs_write_start(char *buf, bool threadgroup,
+       goto out_unlock_rcu;
+ out_unlock_threadgroup:
+-      if (*locked) {
+-              percpu_up_write(&cgroup_threadgroup_rwsem);
+-              *locked = false;
+-      }
++      cgroup_attach_unlock(*threadgroup_locked);
++      *threadgroup_locked = false;
+ out_unlock_rcu:
+       rcu_read_unlock();
+       return tsk;
+ }
+-void cgroup_procs_write_finish(struct task_struct *task, bool locked)
+-      __releases(&cgroup_threadgroup_rwsem)
++void cgroup_procs_write_finish(struct task_struct *task, bool threadgroup_locked)
+ {
+       struct cgroup_subsys *ss;
+       int ssid;
+@@ -2894,8 +2927,8 @@ void cgroup_procs_write_finish(struct task_struct *task, bool locked)
+       /* release reference from cgroup_procs_write_start() */
+       put_task_struct(task);
+-      if (locked)
+-              percpu_up_write(&cgroup_threadgroup_rwsem);
++      cgroup_attach_unlock(threadgroup_locked);
++
+       for_each_subsys(ss, ssid)
+               if (ss->post_attach)
+                       ss->post_attach();
+@@ -2972,8 +3005,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
+        * write-locking can be skipped safely.
+        */
+       has_tasks = !list_empty(&mgctx.preloaded_src_csets);
+-      if (has_tasks)
+-              percpu_down_write(&cgroup_threadgroup_rwsem);
++      cgroup_attach_lock(has_tasks);
+       /* NULL dst indicates self on default hierarchy */
+       ret = cgroup_migrate_prepare_dst(&mgctx);
+@@ -2994,8 +3026,7 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
+       ret = cgroup_migrate_execute(&mgctx);
+ out_finish:
+       cgroup_migrate_finish(&mgctx);
+-      if (has_tasks)
+-              percpu_up_write(&cgroup_threadgroup_rwsem);
++      cgroup_attach_unlock(has_tasks);
+       return ret;
+ }
+@@ -4943,13 +4974,13 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
+       struct task_struct *task;
+       const struct cred *saved_cred;
+       ssize_t ret;
+-      bool locked;
++      bool threadgroup_locked;
+       dst_cgrp = cgroup_kn_lock_live(of->kn, false);
+       if (!dst_cgrp)
+               return -ENODEV;
+-      task = cgroup_procs_write_start(buf, threadgroup, &locked);
++      task = cgroup_procs_write_start(buf, threadgroup, &threadgroup_locked);
+       ret = PTR_ERR_OR_ZERO(task);
+       if (ret)
+               goto out_unlock;
+@@ -4975,7 +5006,7 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
+       ret = cgroup_attach_task(dst_cgrp, task, threadgroup);
+ out_finish:
+-      cgroup_procs_write_finish(task, locked);
++      cgroup_procs_write_finish(task, threadgroup_locked);
+ out_unlock:
+       cgroup_kn_unlock(of->kn);
+diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
+index 58aadfda9b8b3..1f3a55297f39d 100644
+--- a/kernel/cgroup/cpuset.c
++++ b/kernel/cgroup/cpuset.c
+@@ -2289,7 +2289,7 @@ static void cpuset_attach(struct cgroup_taskset *tset)
+       cgroup_taskset_first(tset, &css);
+       cs = css_cs(css);
+-      cpus_read_lock();
++      lockdep_assert_cpus_held();     /* see cgroup_attach_lock() */
+       percpu_down_write(&cpuset_rwsem);
+       guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
+@@ -2343,7 +2343,6 @@ static void cpuset_attach(struct cgroup_taskset *tset)
+               wake_up(&cpuset_attach_wq);
+       percpu_up_write(&cpuset_rwsem);
+-      cpus_read_unlock();
+ }
+ /* The various types of files and directories in a cpuset file system */
+-- 
+2.35.1
+
diff --git a/queue-5.19/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch b/queue-5.19/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch
new file mode 100644 (file)
index 0000000..88876ee
--- /dev/null
@@ -0,0 +1,280 @@
+From 418b7341a3521740fe9aed455bbb0bd4e3a4fc08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Aug 2022 16:08:34 -0300
+Subject: cifs: remove useless parameter 'is_fsctl' from SMB2_ioctl()
+
+From: Enzo Matsumiya <ematsumiya@suse.de>
+
+[ Upstream commit 400d0ad63b190895e29f43bc75b1260111d3fd34 ]
+
+SMB2_ioctl() is always called with is_fsctl = true, so doesn't make any
+sense to have it at all.
+
+Thus, always set SMB2_0_IOCTL_IS_FSCTL flag on the request.
+
+Also, as per MS-SMB2 3.3.5.15 "Receiving an SMB2 IOCTL Request", servers
+must fail the request if the request flags is zero anyway.
+
+Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/smb2file.c  |  1 -
+ fs/cifs/smb2ops.c   | 35 +++++++++++++----------------------
+ fs/cifs/smb2pdu.c   | 20 +++++++++-----------
+ fs/cifs/smb2proto.h |  4 ++--
+ 4 files changed, 24 insertions(+), 36 deletions(-)
+
+diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
+index f5dcc4940b6da..9dfd2dd612c25 100644
+--- a/fs/cifs/smb2file.c
++++ b/fs/cifs/smb2file.c
+@@ -61,7 +61,6 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
+               nr_ioctl_req.Reserved = 0;
+               rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
+                       fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY,
+-                      true /* is_fsctl */,
+                       (char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
+                       CIFSMaxBufSize, NULL, NULL /* no return info */);
+               if (rc == -EOPNOTSUPP) {
+diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
+index 3898ec2632dc4..33357846a01b1 100644
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -680,7 +680,7 @@ SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
+       struct cifs_ses *ses = tcon->ses;
+       rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
+-                      FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
++                      FSCTL_QUERY_NETWORK_INTERFACE_INFO,
+                       NULL /* no data input */, 0 /* no data input */,
+                       CIFSMaxBufSize, (char **)&out_buf, &ret_data_len);
+       if (rc == -EOPNOTSUPP) {
+@@ -1609,9 +1609,8 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
+       struct resume_key_req *res_key;
+       rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
+-                      FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
+-                      NULL, 0 /* no input */, CIFSMaxBufSize,
+-                      (char **)&res_key, &ret_data_len);
++                      FSCTL_SRV_REQUEST_RESUME_KEY, NULL, 0 /* no input */,
++                      CIFSMaxBufSize, (char **)&res_key, &ret_data_len);
+       if (rc == -EOPNOTSUPP) {
+               pr_warn_once("Server share %s does not support copy range\n", tcon->treeName);
+@@ -1753,7 +1752,7 @@ smb2_ioctl_query_info(const unsigned int xid,
+               rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
+               rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID,
+-                                   qi.info_type, true, buffer, qi.output_buffer_length,
++                                   qi.info_type, buffer, qi.output_buffer_length,
+                                    CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE -
+                                    MAX_SMB2_CLOSE_RESPONSE_SIZE);
+               free_req1_func = SMB2_ioctl_free;
+@@ -1929,9 +1928,8 @@ smb2_copychunk_range(const unsigned int xid,
+               retbuf = NULL;
+               rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
+                       trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
+-                      true /* is_fsctl */, (char *)pcchunk,
+-                      sizeof(struct copychunk_ioctl), CIFSMaxBufSize,
+-                      (char **)&retbuf, &ret_data_len);
++                      (char *)pcchunk, sizeof(struct copychunk_ioctl),
++                      CIFSMaxBufSize, (char **)&retbuf, &ret_data_len);
+               if (rc == 0) {
+                       if (ret_data_len !=
+                                       sizeof(struct copychunk_ioctl_rsp)) {
+@@ -2091,7 +2089,6 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
+-                      true /* is_fctl */,
+                       &setsparse, 1, CIFSMaxBufSize, NULL, NULL);
+       if (rc) {
+               tcon->broken_sparse_sup = true;
+@@ -2174,7 +2171,6 @@ smb2_duplicate_extents(const unsigned int xid,
+       rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
+                       trgtfile->fid.volatile_fid,
+                       FSCTL_DUPLICATE_EXTENTS_TO_FILE,
+-                      true /* is_fsctl */,
+                       (char *)&dup_ext_buf,
+                       sizeof(struct duplicate_extents_to_file),
+                       CIFSMaxBufSize, NULL,
+@@ -2209,7 +2205,6 @@ smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
+       return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid,
+                       FSCTL_SET_INTEGRITY_INFORMATION,
+-                      true /* is_fsctl */,
+                       (char *)&integr_info,
+                       sizeof(struct fsctl_set_integrity_information_req),
+                       CIFSMaxBufSize, NULL,
+@@ -2262,7 +2257,6 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid,
+                       FSCTL_SRV_ENUMERATE_SNAPSHOTS,
+-                      true /* is_fsctl */,
+                       NULL, 0 /* no input data */, max_response_size,
+                       (char **)&retbuf,
+                       &ret_data_len);
+@@ -2982,7 +2976,6 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
+       do {
+               rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
+                               FSCTL_DFS_GET_REFERRALS,
+-                              true /* is_fsctl */,
+                               (char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
+                               (char **)&dfs_rsp, &dfs_rsp_size);
+               if (!is_retryable_error(rc))
+@@ -3189,8 +3182,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
+       rc = SMB2_ioctl_init(tcon, server,
+                            &rqst[1], fid.persistent_fid,
+-                           fid.volatile_fid, FSCTL_GET_REPARSE_POINT,
+-                           true /* is_fctl */, NULL, 0,
++                           fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
+                            CIFSMaxBufSize -
+                            MAX_SMB2_CREATE_RESPONSE_SIZE -
+                            MAX_SMB2_CLOSE_RESPONSE_SIZE);
+@@ -3370,8 +3362,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
+       rc = SMB2_ioctl_init(tcon, server,
+                            &rqst[1], COMPOUND_FID,
+-                           COMPOUND_FID, FSCTL_GET_REPARSE_POINT,
+-                           true /* is_fctl */, NULL, 0,
++                           COMPOUND_FID, FSCTL_GET_REPARSE_POINT, NULL, 0,
+                            CIFSMaxBufSize -
+                            MAX_SMB2_CREATE_RESPONSE_SIZE -
+                            MAX_SMB2_CLOSE_RESPONSE_SIZE);
+@@ -3641,7 +3632,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
+       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+-                      cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, true,
++                      cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+                       (char *)&fsctl_buf,
+                       sizeof(struct file_zero_data_information),
+                       0, NULL, NULL);
+@@ -3702,7 +3693,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+-                      true /* is_fctl */, (char *)&fsctl_buf,
++                      (char *)&fsctl_buf,
+                       sizeof(struct file_zero_data_information),
+                       CIFSMaxBufSize, NULL, NULL);
+       filemap_invalidate_unlock(inode->i_mapping);
+@@ -3764,7 +3755,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,
+       in_data.length = cpu_to_le64(len);
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid,
+-                      FSCTL_QUERY_ALLOCATED_RANGES, true,
++                      FSCTL_QUERY_ALLOCATED_RANGES,
+                       (char *)&in_data, sizeof(in_data),
+                       1024 * sizeof(struct file_allocated_range_buffer),
+                       (char **)&out_data, &out_data_len);
+@@ -4085,7 +4076,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid,
+-                      FSCTL_QUERY_ALLOCATED_RANGES, true,
++                      FSCTL_QUERY_ALLOCATED_RANGES,
+                       (char *)&in_data, sizeof(in_data),
+                       sizeof(struct file_allocated_range_buffer),
+                       (char **)&out_data, &out_data_len);
+@@ -4145,7 +4136,7 @@ static int smb3_fiemap(struct cifs_tcon *tcon,
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid,
+-                      FSCTL_QUERY_ALLOCATED_RANGES, true,
++                      FSCTL_QUERY_ALLOCATED_RANGES,
+                       (char *)&in_data, sizeof(in_data),
+                       1024 * sizeof(struct file_allocated_range_buffer),
+                       (char **)&out_data, &out_data_len);
+diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
+index ba58d7fd54f9e..31d37afae741f 100644
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -1174,7 +1174,7 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
+       }
+       rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
+-              FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */,
++              FSCTL_VALIDATE_NEGOTIATE_INFO,
+               (char *)pneg_inbuf, inbuflen, CIFSMaxBufSize,
+               (char **)&pneg_rsp, &rsplen);
+       if (rc == -EOPNOTSUPP) {
+@@ -3053,7 +3053,7 @@ int
+ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+               struct smb_rqst *rqst,
+               u64 persistent_fid, u64 volatile_fid, u32 opcode,
+-              bool is_fsctl, char *in_data, u32 indatalen,
++              char *in_data, u32 indatalen,
+               __u32 max_response_size)
+ {
+       struct smb2_ioctl_req *req;
+@@ -3128,10 +3128,8 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
+       req->hdr.CreditCharge =
+               cpu_to_le16(DIV_ROUND_UP(max(indatalen, max_response_size),
+                                        SMB2_MAX_BUFFER_SIZE));
+-      if (is_fsctl)
+-              req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
+-      else
+-              req->Flags = 0;
++      /* always an FSCTL (for now) */
++      req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
+       /* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */
+       if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO)
+@@ -3158,9 +3156,9 @@ SMB2_ioctl_free(struct smb_rqst *rqst)
+  */
+ int
+ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+-         u64 volatile_fid, u32 opcode, bool is_fsctl,
+-         char *in_data, u32 indatalen, u32 max_out_data_len,
+-         char **out_data, u32 *plen /* returned data len */)
++         u64 volatile_fid, u32 opcode, char *in_data, u32 indatalen,
++         u32 max_out_data_len, char **out_data,
++         u32 *plen /* returned data len */)
+ {
+       struct smb_rqst rqst;
+       struct smb2_ioctl_rsp *rsp = NULL;
+@@ -3202,7 +3200,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+       rc = SMB2_ioctl_init(tcon, server,
+                            &rqst, persistent_fid, volatile_fid, opcode,
+-                           is_fsctl, in_data, indatalen, max_out_data_len);
++                           in_data, indatalen, max_out_data_len);
+       if (rc)
+               goto ioctl_exit;
+@@ -3294,7 +3292,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
+                       cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
+       rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
+-                      FSCTL_SET_COMPRESSION, true /* is_fsctl */,
++                      FSCTL_SET_COMPRESSION,
+                       (char *)&fsctl_input /* data input */,
+                       2 /* in data len */, CIFSMaxBufSize /* max out data */,
+                       &ret_data /* out data */, NULL);
+diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
+index a69f1eed1cfe5..d57d7202dc367 100644
+--- a/fs/cifs/smb2proto.h
++++ b/fs/cifs/smb2proto.h
+@@ -147,13 +147,13 @@ extern int SMB2_open_init(struct cifs_tcon *tcon,
+ extern void SMB2_open_free(struct smb_rqst *rqst);
+ extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
+                    u64 persistent_fid, u64 volatile_fid, u32 opcode,
+-                   bool is_fsctl, char *in_data, u32 indatalen, u32 maxoutlen,
++                   char *in_data, u32 indatalen, u32 maxoutlen,
+                    char **out_data, u32 *plen /* returned data len */);
+ extern int SMB2_ioctl_init(struct cifs_tcon *tcon,
+                          struct TCP_Server_Info *server,
+                          struct smb_rqst *rqst,
+                          u64 persistent_fid, u64 volatile_fid, u32 opcode,
+-                         bool is_fsctl, char *in_data, u32 indatalen,
++                         char *in_data, u32 indatalen,
+                          __u32 max_response_size);
+ extern void SMB2_ioctl_free(struct smb_rqst *rqst);
+ extern int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
+-- 
+2.35.1
+
index a4bba0bf95b99619f179037707c48444a001d194..56d87347be6036f1524ddc496b43c7ce9e7f3270 100644 (file)
@@ -57,3 +57,7 @@ drm-i915-slpc-let-s-fix-the-pcode-min-freq-table-setup-for-slpc.patch
 drm-i915-implement-waedplinkratedatareload.patch
 scsi-mpt3sas-fix-use-after-free-warning.patch
 scsi-lpfc-add-missing-destroy_workqueue-in-error-path.patch
+cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch
+cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch
+cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch
+smb3-missing-inode-locks-in-zero-range.patch
diff --git a/queue-5.19/smb3-missing-inode-locks-in-zero-range.patch b/queue-5.19/smb3-missing-inode-locks-in-zero-range.patch
new file mode 100644 (file)
index 0000000..9407789
--- /dev/null
@@ -0,0 +1,118 @@
+From cdb09e66500470f2aeabb1d416a99158549f77cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Aug 2022 01:01:36 -0500
+Subject: smb3: missing inode locks in zero range
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit c919c164fc87bcca8e80b3b9224492fa5b6455ba ]
+
+smb3 fallocate zero range was not grabbing the inode or filemap_invalidate
+locks so could have race with pagemap reinstantiating the page.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/smb2ops.c | 55 ++++++++++++++++++++++++++---------------------
+ 1 file changed, 30 insertions(+), 25 deletions(-)
+
+diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
+index 33357846a01b1..e8a8daa82ed76 100644
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -3590,26 +3590,43 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
+       return pntsd;
+ }
++static long smb3_zero_data(struct file *file, struct cifs_tcon *tcon,
++                           loff_t offset, loff_t len, unsigned int xid)
++{
++      struct cifsFileInfo *cfile = file->private_data;
++      struct file_zero_data_information fsctl_buf;
++
++      cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
++
++      fsctl_buf.FileOffset = cpu_to_le64(offset);
++      fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
++
++      return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
++                        cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
++                        (char *)&fsctl_buf,
++                        sizeof(struct file_zero_data_information),
++                        0, NULL, NULL);
++}
++
+ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
+                           loff_t offset, loff_t len, bool keep_size)
+ {
+       struct cifs_ses *ses = tcon->ses;
+-      struct inode *inode;
+-      struct cifsInodeInfo *cifsi;
++      struct inode *inode = file_inode(file);
++      struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct cifsFileInfo *cfile = file->private_data;
+-      struct file_zero_data_information fsctl_buf;
+       long rc;
+       unsigned int xid;
+       __le64 eof;
+       xid = get_xid();
+-      inode = d_inode(cfile->dentry);
+-      cifsi = CIFS_I(inode);
+-
+       trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
+                             ses->Suid, offset, len);
++      inode_lock(inode);
++      filemap_invalidate_lock(inode->i_mapping);
++
+       /*
+        * We zero the range through ioctl, so we need remove the page caches
+        * first, otherwise the data may be inconsistent with the server.
+@@ -3617,26 +3634,12 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
+       truncate_pagecache_range(inode, offset, offset + len - 1);
+       /* if file not oplocked can't be sure whether asking to extend size */
+-      if (!CIFS_CACHE_READ(cifsi))
+-              if (keep_size == false) {
+-                      rc = -EOPNOTSUPP;
+-                      trace_smb3_zero_err(xid, cfile->fid.persistent_fid,
+-                              tcon->tid, ses->Suid, offset, len, rc);
+-                      free_xid(xid);
+-                      return rc;
+-              }
+-
+-      cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
+-
+-      fsctl_buf.FileOffset = cpu_to_le64(offset);
+-      fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
++      rc = -EOPNOTSUPP;
++      if (keep_size == false && !CIFS_CACHE_READ(cifsi))
++              goto zero_range_exit;
+-      rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+-                      cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+-                      (char *)&fsctl_buf,
+-                      sizeof(struct file_zero_data_information),
+-                      0, NULL, NULL);
+-      if (rc)
++      rc = smb3_zero_data(file, tcon, offset, len, xid);
++      if (rc < 0)
+               goto zero_range_exit;
+       /*
+@@ -3649,6 +3652,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
+       }
+  zero_range_exit:
++      filemap_invalidate_unlock(inode->i_mapping);
++      inode_unlock(inode);
+       free_xid(xid);
+       if (rc)
+               trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
+-- 
+2.35.1
+