From: Sasha Levin Date: Sat, 10 Sep 2022 17:15:17 +0000 (-0400) Subject: Fixes for 5.10 X-Git-Tag: v5.19.9~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=abe4327d8680d5f49421068d25e02086af6bac88;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch b/queue-5.10/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch new file mode 100644 index 00000000000..1f73f46a4d2 --- /dev/null +++ b/queue-5.10/cgroup-elide-write-locking-threadgroup_rwsem-when-up.patch @@ -0,0 +1,81 @@ +From 2ffe7a95c24db7b85fe6e87d94c7613906c11a9e 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 5046c99deba86..1072843b25709 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -2908,12 +2908,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) { +@@ -2924,6 +2923,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) +@@ -2943,7 +2952,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.10/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch b/queue-5.10/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch new file mode 100644 index 00000000000..49ef0037bac --- /dev/null +++ b/queue-5.10/cgroup-fix-threadgroup_rwsem-cpus_read_lock-deadlock.patch @@ -0,0 +1,207 @@ +From e9b8e262c947e41d75475bd721e72326c3c73c6d 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 1072843b25709..684c16849eff3 100644 +--- a/kernel/cgroup/cgroup.c ++++ b/kernel/cgroup/cgroup.c +@@ -2304,6 +2304,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 +@@ -2780,8 +2821,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; +@@ -2798,12 +2838,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) { +@@ -2834,17 +2870,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; +@@ -2852,8 +2885,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(); +@@ -2930,8 +2963,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); +@@ -2952,8 +2984,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; + } + +@@ -4809,13 +4840,13 @@ static ssize_t cgroup_procs_write(struct kernfs_open_file *of, + 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, true, &locked); ++ task = cgroup_procs_write_start(buf, true, &threadgroup_locked); + ret = PTR_ERR_OR_ZERO(task); + if (ret) + goto out_unlock; +@@ -4841,7 +4872,7 @@ static ssize_t cgroup_procs_write(struct kernfs_open_file *of, + ret = cgroup_attach_task(dst_cgrp, task, true); + + 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 c51863b63f93a..b7830f1f1f3a5 100644 +--- a/kernel/cgroup/cpuset.c ++++ b/kernel/cgroup/cpuset.c +@@ -2212,7 +2212,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); + + /* prepare for attach */ +@@ -2268,7 +2268,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.10/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch b/queue-5.10/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch new file mode 100644 index 00000000000..a544decc05c --- /dev/null +++ b/queue-5.10/cifs-remove-useless-parameter-is_fsctl-from-smb2_ioc.patch @@ -0,0 +1,280 @@ +From f40a2d1dc665297fffe0aa428314e482e3ac6e64 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 2fa3ba354cc96..001c26daacbaa 100644 +--- a/fs/cifs/smb2file.c ++++ b/fs/cifs/smb2file.c +@@ -74,7 +74,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 b6d72e3c5ebad..0a20ae96fe243 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -587,7 +587,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) { +@@ -1470,9 +1470,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) { + cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc); +@@ -1611,7 +1610,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; +@@ -1787,9 +1786,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)) { +@@ -1949,7 +1947,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; +@@ -2032,7 +2029,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, +@@ -2067,7 +2063,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, +@@ -2120,7 +2115,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); +@@ -2762,7 +2756,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); + } while (rc == -EAGAIN); +@@ -2964,8 +2957,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); +@@ -3145,8 +3137,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); +@@ -3409,7 +3400,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); +@@ -3471,7 +3462,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); + free_xid(xid); +@@ -3530,7 +3521,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); +@@ -3771,7 +3762,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); +@@ -3831,7 +3822,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 24dd711fa9b95..7ee8abd1f79be 100644 +--- a/fs/cifs/smb2pdu.c ++++ b/fs/cifs/smb2pdu.c +@@ -1081,7 +1081,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) { +@@ -2922,7 +2922,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; +@@ -2997,10 +2997,8 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, + req->sync_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) +@@ -3027,9 +3025,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; +@@ -3071,7 +3069,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; + +@@ -3153,7 +3151,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 4eb0ca84355a6..ed2b4fb012a41 100644 +--- a/fs/cifs/smb2proto.h ++++ b/fs/cifs/smb2proto.h +@@ -155,13 +155,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.10/series b/queue-5.10/series index 393b43771b7..aa604464d97 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -30,3 +30,7 @@ nvmet-fix-a-use-after-free.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-punch-hole.patch diff --git a/queue-5.10/smb3-missing-inode-locks-in-punch-hole.patch b/queue-5.10/smb3-missing-inode-locks-in-punch-hole.patch new file mode 100644 index 00000000000..370b8029756 --- /dev/null +++ b/queue-5.10/smb3-missing-inode-locks-in-punch-hole.patch @@ -0,0 +1,62 @@ +From 5e09f79afe751fd85361525e654fbb50870cb556 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Aug 2022 02:10:56 -0500 +Subject: smb3: missing inode locks in punch hole + +From: David Howells + +[ Upstream commit ba0803050d610d5072666be727bca5e03e55b242 ] + +smb3 fallocate punch hole 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 | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index 0a20ae96fe243..11efd5289ec43 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -3430,7 +3430,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, + static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, + loff_t offset, loff_t len) + { +- struct inode *inode; ++ struct inode *inode = file_inode(file); + struct cifsFileInfo *cfile = file->private_data; + struct file_zero_data_information fsctl_buf; + long rc; +@@ -3439,14 +3439,12 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, + + xid = get_xid(); + +- inode = d_inode(cfile->dentry); +- ++ inode_lock(inode); + /* Need to make file sparse, if not already, before freeing range. */ + /* Consider adding equivalent for compressed since it could also work */ + if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) { + rc = -EOPNOTSUPP; +- free_xid(xid); +- return rc; ++ goto out; + } + + /* +@@ -3465,6 +3463,8 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, + (char *)&fsctl_buf, + sizeof(struct file_zero_data_information), + CIFSMaxBufSize, NULL, NULL); ++out: ++ inode_unlock(inode); + free_xid(xid); + return rc; + } +-- +2.35.1 +