From e320943a5a833c8e5e17729de802eed3d06a6f3e Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sat, 10 Sep 2022 13:15:15 -0400 Subject: [PATCH] Fixes for 5.19 Signed-off-by: Sasha Levin --- ...te-locking-threadgroup_rwsem-when-up.patch | 81 +++++ ...dgroup_rwsem-cpus_read_lock-deadlock.patch | 207 +++++++++++++ ...ess-parameter-is_fsctl-from-smb2_ioc.patch | 280 ++++++++++++++++++ queue-5.19/series | 4 + ...b3-missing-inode-locks-in-zero-range.patch | 118 ++++++++ 5 files changed, 690 insertions(+) create mode 100644 queue-5.19/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch create mode 100644 queue-5.19/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch create mode 100644 queue-5.19/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch create mode 100644 queue-5.19/smb3-missing-inode-locks-in-zero-range.patch 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 index 00000000000..39c52e3f8b7 --- /dev/null +++ b/queue-5.19/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch @@ -0,0 +1,81 @@ +From 5ad3746c25ab98e6a12f0ea9f0d7af964749bee6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Cc: Christian Brauner +Cc: Michal Koutný +Signed-off-by: Sasha Levin +--- + 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 index 00000000000..ba26422971c --- /dev/null +++ b/queue-5.19/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch @@ -0,0 +1,207 @@ +From 46d39bc2faa71f684f98fb0413124b08dab18a3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Aug 2022 13:27:38 -1000 +Subject: cgroup: Fix threadgroup_rwsem <-> cpus_read_lock() deadlock + +From: Tejun Heo + +[ 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 +Reviewed-and-tested-by: Imran Khan +Reported-and-tested-by: Xuewen Yan +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 +--- + 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 index 00000000000..88876ee3817 --- /dev/null +++ b/queue-5.19/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch @@ -0,0 +1,280 @@ +From 418b7341a3521740fe9aed455bbb0bd4e3a4fc08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Aug 2022 16:08:34 -0300 +Subject: cifs: remove useless parameter 'is_fsctl' from SMB2_ioctl() + +From: Enzo Matsumiya + +[ 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 +Reviewed-by: Tom Talpey +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-5.19/series b/queue-5.19/series index a4bba0bf95b..56d87347be6 100644 --- a/queue-5.19/series +++ b/queue-5.19/series @@ -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 index 00000000000..94077895cd4 --- /dev/null +++ b/queue-5.19/smb3-missing-inode-locks-in-zero-range.patch @@ -0,0 +1,118 @@ +From cdb09e66500470f2aeabb1d416a99158549f77cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Aug 2022 01:01:36 -0500 +Subject: smb3: missing inode locks in zero range + +From: David Howells + +[ 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 +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + 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 + -- 2.47.3