Linux 7.2.14
Greg Kroah-Hartman
maintainerI'm announcing the release of the 7.2.14 kernel.
All users of the 7.2 kernel series must upgrade.
The updated 7.2.y git tree can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-7.2.y
and can be browsed at the normal kernel.org git web browser:
https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary
thanks,
greg k-h
------------
Makefile | 2 crypto/asymmetric_keys/restrict.c | 8 fs/coredump.c | 18 - fs/ntfs/file.c | 32 - include/linux/io_uring_types.h | 5 include/linux/key-type.h | 1 include/linux/key.h | 5 include/linux/sched.h | 2 include/linux/sched/signal.h | 27 + io_uring/cancel.c | 43 ++ io_uring/cancel.h | 2 io_uring/fdinfo.c | 14 io_uring/futex.c | 32 + io_uring/io-wq.c | 126 ++++++- io_uring/io_uring.c | 180 +++++++--- io_uring/io_uring.h | 44 ++ io_uring/kbuf.c | 2 io_uring/loop.c | 8 io_uring/mpscq.h | 14 io_uring/napi.c | 4 io_uring/net.c | 26 + io_uring/openclose.c | 11 io_uring/poll.c | 38 +- io_uring/register.c | 54 ++- io_uring/rw.c | 18 - io_uring/sqpoll.c | 7 io_uring/timeout.c | 102 ++++- io_uring/tw.c | 36 +- io_uring/uring_cmd.c | 2 io_uring/wait.c | 48 ++ io_uring/wait.h | 15 io_uring/waitid.c | 19 - io_uring/zcrx.c | 2 kernel/exit.c | 5 kernel/fork.c | 9 kernel/pid_namespace.c | 3 kernel/ptrace.c | 6 kernel/sched/ext/ext.c | 14 kernel/sched/fair.c | 16 kernel/signal.c | 4 kernel/trace/ftrace.c | 4 kernel/trace/trace.c | 21 + kernel/trace/trace_events_filter.c | 6 kernel/trace/trace_events_hist.c | 33 - kernel/trace/trace_events_synth.c | 10 kernel/trace/trace_synth.h | 1 kernel/trace/trace_syscalls.c | 2 mm/damon/core.c | 22 - mm/damon/sysfs.c | 19 + net/bluetooth/l2cap_core.c | 7 net/bluetooth/l2cap_sock.c | 2 security/keys/key.c | 13 security/keys/keyctl.c | 15 security/keys/keyring.c | 152 ++++---- security/keys/process_keys.c | 5 security/keys/trusted-keys/trusted_tpm1.c | 4 security/keys/trusted-keys/trusted_tpm2.c | 2 tools/dma/Makefile | 4 tools/testing/selftests/ftrace/test.d/filter/event-filter-incomplete.tc | 24 + 59 files changed, 1036 insertions(+), 314 deletions(-)
Aaron Ahmed (1):
ftrace: Initialize modname and offset in print_rec()
Adrian Martinez (1):
KEYS: Fix key_reject_and_link() race with keyring restriction
Austin Schuh (1):
io_uring/wait: wake real-time waiters from hard interrupt context
Cen Zhang (4):
keys: Avoid the owner account dereference in named keyring lookup
keys: Check the authorization payload in process keyring searches
keys: Protect the type name while describing a key
keys: Protect the read method check against type removal
Christian Brauner (10):
io-wq: order the exit bit against worker creation task work
coredump: hold RCU while releasing parked threads
signal: don't retarget shared signals in a dying thread group
signal: only SIGKILL and the freezers interrupt a coredumping task
ptrace: refuse to change the signal mask of a user worker
fork: release the files of a failed fork after sched_cancel_fork()
exit: hang up the tty before closing the files
signal: allow taks to temporarily block TIF_NOTIFY_SIGNAL
coredump: prevent TIF_NOTIFY_SIGNAL from interrupting coredumps
pid_namespace: prevent TIF_NOTIFY_SIGNAL from interrupting the reaper
David Carlier (2):
tracing: Hold trace_types_lock when updating modules in persistent instances
tracing: Hold trace_types_lock when resetting last boot data from readers
Donggeun Yoo (3):
tracing: Save the event file instead of the compatible histogram
tracing: Unregister field variable histograms when the command fails
tracing: Fix 64-bit and signed histogram fields on 32-bit kernels
Greg Kroah-Hartman (1):
Linux 7.2.14
Haoran Wang (1):
tracing/syscalls: Use copy_from_user for the faultable syscall buffer
Hongling Zeng (2):
ntfs: fix race between fallocate and mmap reads
ntfs: take invalidate_lock in ntfs_filemap_page_mkwrite()
Hui Su (1):
sched/fair: Avoid overflow in place_entity()
Jens Axboe (6):
io_uring/timeout: don't put a sequence target behind the last flush io_uring/timeout: don't flush with the sequence behind the last flush io_uring/timeout: don't lose a cancel as io-wq arms a timeout io_uring/poll: don't loop on HUP with multiple references
io_uring: end the drain when the drain request completes
io_uring: keep the drain active when a deferred drain request is started
Josef Bacik (43):
io_uring/waitid: own the request before clearing ->head io_uring/cmd: don't leave list poison in ->hash_node io_uring/wait: don't spin on a stuck overflow list io_uring/io-wq: don't lose the signal that ends work io_uring/io-wq: don't hide a link from cancellations
io_uring: don't flood a cancelling task with task_work
io_uring: don't lose the DEFER_TASKRUN wake up io_uring/cancel: rearm local work wake up before sleep io_uring/mpscq: disable preemption while pushing io_uring/io-wq: don't go to sleep on pending work io_uring/io-wq: don't strand work when a worker exits io_uring/io-wq: don't exit with a creation pending io_uring/io-wq: let cancel find picked up hashed work io_uring/poll: don't lose a cancel as io-wq arms poll
io_uring: don't lose a cancel as io-wq parks a request io_uring/cancel: don't forget that the work was running io_uring/cancel: recognize "no timeout" on 32-bit io_uring/cancel: let CANCEL_ALL find parked requests
io_uring: wake ring pollers for local task_work io_uring/wait: look at all CQ waiters on wake up io_uring/poll: drop stale double poll entry on rearm io_uring/futex: allocate private hash before waiting
io_uring: drop the CQE cache if a refill fails
io_uring: don't split 128b SQEs at the SQPOLL cap io_uring/register: don't wrap 32b CQEs when resizing io_uring/register: handle index wrap when resizing io_uring/register: keep 128b SQEs intact on resize io_uring/fdinfo: fix CQE dump of CQE32 rings io_uring/timeout: don't skip over reached sequences io_uring/timeout: keep repeat count on multishot update io_uring/timeout: use the right clock for ABS updates io_uring/wait: no early -ETIME if min_wait finds work io_uring/napi: make stale entries time out after 60s io_uring/napi: don't busy poll past an expired timeout io_uring/zcrx: fix buffer offsets in areas above 4GB io_uring/kbuf: handle index wrap in last buffer check io_uring/sqpoll: let the thread sleep on disabled rings io_uring/openclose: keep the lock in io_pipe_fixed()
io_uring: don't pass restart error codes to userspace io_uring/net: don't retry recv on uncommitted buffers io_uring/timeout: no ABS update of multishot timeouts io_uring/timeout: don't end a linked timeout with 1
io_uring: look up the file before queueing to io-wq
Juanlu Herrero (1):
io_uring/poll: avoid retry wakeup loss when dropping ownership
Junyeong Lee (1):
io_uring/waitid: prevent cancel reference wrap
Kuba Piecuch (1):
sched_ext: Wait for SCX_OPSS_DISPATCHING before moving tasks off DSQs
Kyle Zeng (2):
tracing: Reject incomplete event filter expressions
keys: make keyring indexes independent of kernel addresses
Lee Jones (1):
tracing/histograms: Verify event_call identity when updating synth_event refcount
Pauli Virtanen (1):
Bluetooth: L2CAP: refuse __l2cap_chan_add if chan already has conn
SJ Park (1):
mm/damon/core: error damos_commit_quota_goal() for zero target_value
Sasha Levin (1):
tools/dma: fix building with O=
Srish Srinivasan (1):
keys/trusted_keys: return immediately after TPM unseal failure
Stefano Garzarella (1):
KEYS: trusted: Fix blob allocation size in tpm2_key_decode()
Tamaki Yanagawa (1):
io_uring/net: keep recv buffer select length within MAX_RW_COUNT
Weiming Shi (1):
asymmetric_keys: reject trust keys without IDs
Greg Kroah-Hartman
maintainerMakefile +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 7 PATCHLEVEL = 2 -SUBLEVEL = 13 +SUBLEVEL = 14 EXTRAVERSION = NAME = Baby Opossum Posse
crypto/asymmetric_keys/restrict.c +6 -2
@@ -243,10 +243,14 @@ static int key_or_keyring_common(struct key *dest_keyring,if (IS_ERR (key)) key =NULL ; }else if (trusted->type == &key_type_asymmetric) { +const struct asymmetric_key_ids *kids;const struct asymmetric_key_id **signer_ids; - signer_ids = (const struct asymmetric_key_id **) -asymmetric_key_ids (trusted)->id; + kids =asymmetric_key_ids (trusted); +if (!kids) +return -ENOKEY ; + + signer_ids = (const struct asymmetric_key_id **)kids->id;/* * The auth_ids come from the candidate key (the
fs/coredump.c +10 -8
@@ -508,7 +508,9 @@ static int zap_threads(struct task_struct *tsk,int nr = -EAGAIN ;spin_lock_irq (&tsk->sighand->siglock); -if (!(signal->flags &SIGNAL_GROUP_EXIT ) && !signal->group_exec_task) { +/* A freeze requested before the dump would be lost with TIF_SIGPENDING. */ +if (!(signal->flags &SIGNAL_GROUP_EXIT ) && !signal->group_exec_task && + !freezing (tsk) && !(tsk->jobctl &JOBCTL_TRAP_FREEZE )) {/* Allow SIGKILL, see prepare_signal() */ signal->core_state = core_state; nr =zap_process (signal, exit_code);
@@ -562,6 +564,8 @@ static void coredump_finish(bool core_dumped) current->signal->core_state =NULL ;spin_unlock_irq (¤t->sighand->siglock); +/* A released thread may exit and be freed before it is woken. */ +guard (rcu)();while ((curr = next) !=NULL ) { next = curr->next; task = curr->task;
@@ -570,6 +574,7 @@ static void coredump_finish(bool core_dumped)* ->task == NULL before we read ->next. */ smp_mb (); +/* Any wakeup now lets the thread exit, rcu keeps it alive. */ curr->task =NULL ;wake_up_process (task); }
@@ -577,13 +582,8 @@ static void coredump_finish(bool core_dumped)static bool dump_interrupted (void ) { -/* -* SIGKILL or freezing() interrupt the coredumping. Perhaps we -* can do try_to_freeze() and check __fatal_signal_pending(), -* but then we need to teach dump_write() to restart and clear -* TIF_SIGPENDING. -*/ -return fatal_signal_pending (current) ||freezing (current); +/* Only SIGKILL and the freezers set it after zap_threads(). */ +return task_sigpending (current); }static void wait_for_dump_helpers (struct file *file)
@@ -1196,6 +1196,8 @@ void vfs_coredump(const kernel_siginfo_t *siginfo)if (coredump_wait (siginfo->si_signo, &core_state) <0 )return ; +/* Task work must not cut the dump short, see signal_pending(). */ +guard (no_notify_signal)(); scoped_with_creds(cred) do_coredump(&cn, &cprm, &argv, &argc, binfmt);coredump_cleanup (&cn, &cprm);
fs/ntfs/file.c +17 -15
@@ -620,12 +620,20 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)static vm_fault_t ntfs_filemap_page_mkwrite (struct vm_fault *vmf) {struct inode *inode =file_inode (vmf->vma->vm_file); +struct address_space *mapping = inode->i_mapping;vm_fault_t ret;sb_start_pagefault (inode->i_sb);file_update_time (vmf->vma->vm_file); +/* +* Serialize against truncate/fallocate which hold the lock +* exclusively while invalidating pagecache and changing extents. +*/ +filemap_invalidate_lock_shared (mapping); ret =iomap_page_mkwrite (vmf, &ntfs_page_mkwrite_iomap_ops,NULL ); +filemap_invalidate_unlock_shared (mapping); +sb_end_pagefault (inode->i_sb);return ret; }
@@ -1061,7 +1069,6 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t offset, loff_t lestruct ntfs_volume *vol = ni->vol;int err =0 ;loff_t old_size; -bool map_locked = false;if (mode & ~(NTFS_FALLOC_FL_SUPPORTED ))return -EOPNOTSUPP ;
@@ -1090,16 +1097,12 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t offset, loff_t leinode_lock (vi);if (NInoCompressed (ni) ||NInoEncrypted (ni)) { - err = -EOPNOTSUPP ; - goto out; +inode_unlock (vi); +return -EOPNOTSUPP ; }inode_dio_wait (vi); -if (mode & (FALLOC_FL_PUNCH_HOLE |FALLOC_FL_COLLAPSE_RANGE | -FALLOC_FL_INSERT_RANGE )) { -filemap_invalidate_lock (vi->i_mapping); - map_locked = true; - } +filemap_invalidate_lock (vi->i_mapping);switch (mode &FALLOC_FL_MODE_MASK ) {case FALLOC_FL_ALLOCATE_RANGE :
@@ -1124,14 +1127,13 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t offset, loff_t le err =file_modified (file); out: -if (map_locked) -filemap_invalidate_unlock (vi->i_mapping); +if (!err && mode ==0 &&NInoNonResident (ni) && + offset > old_size) { +truncate_pagecache (vi, old_size); +pagecache_isize_extended (vi, old_size, offset); + } +filemap_invalidate_unlock (vi->i_mapping);if (!err) { -if (mode ==0 &&NInoNonResident (ni) && - offset > old_size) { -truncate_pagecache (vi, old_size); -pagecache_isize_extended (vi, old_size, offset); - }NInoSetFileNameDirty (ni);inode_set_mtime_to_ts (vi,inode_set_ctime_current (vi));mark_inode_dirty (vi);
include/linux/io_uring_types.h +5 -0
@@ -513,8 +513,13 @@ struct io_ring_ctx {u32 iowq_limits[2 ];struct callback_head poll_wq_task_work; +/* deferred ->poll_wq wake up for local task_work */ +struct rcu_head poll_wq_rcu; +atomic_t poll_wq_rcu_pending;struct list_head defer_list;unsigned nr_drained; +/* drain request dispatched from ->defer_list, until it completes */ +struct io_kiocb *drain_req;/* protected by ->completion_lock */ unsigned nr_req_allocated;
include/linux/key-type.h +1 -0
@@ -161,6 +161,7 @@ struct key_type { const void *in, const void *in2);/* internal fields */ +atomic64_t index_id;/* Opaque keyring index ID */ struct list_head link;/* link in types list */ struct lock_class_key lock_class;/* key->sem lock class */ } __randomize_layout;
include/linux/key.h +5 -0
@@ -107,6 +107,7 @@ struct keyring_name;struct key_tag {struct rcu_head rcu; +atomic64_t index_id;/* Opaque keyring index ID */ refcount_t usage;bool removed;/* T when subject removed */ };
@@ -129,6 +130,8 @@ struct keyring_index_key {struct key_type *type;struct key_tag *domain_tag;/* Domain of operation */ const char *description; +u64 type_id;/* Cached index IDs */ +u64 domain_id; };union key_payload {
@@ -251,6 +254,8 @@ struct key {struct key_type *type;/* type of key */ struct key_tag *domain_tag;/* Domain of operation */ char *description; +u64 type_id; +u64 domain_id; }; };
include/linux/sched.h +1 -1
@@ -1805,7 +1805,7 @@ extern struct pid __rcu *cad_pid;* I am cleaning dirty pages from some other bdi. */ #define PF_KTHREAD 0x00200000/* I am a kernel thread */ #define PF_RANDOMIZE 0x00400000/* Randomize virtual address space */ -#define PF__HOLE__00800000 0x00800000 +#define PF_NO_NOTIFY_SIGNAL 0x00800000/* see no_notify_signal_save() */ #define PF__HOLE__01000000 0x01000000#define PF__HOLE__02000000 0x02000000#define PF_NO_SETAFFINITY 0x04000000/* Userland is not allowed to meddle with cpus_mask */
include/linux/sched/signal.h +25 -2
@@ -2,6 +2,7 @@#ifndef _LINUX_SCHED_SIGNAL_H#define _LINUX_SCHED_SIGNAL_H +#include <linux/cleanup.h> #include <linux/rculist.h> #include <linux/signal.h> #include <linux/sched.h>
@@ -384,14 +385,36 @@ static inline int task_sigpending(struct task_struct *p)return unlikely (test_tsk_thread_flag (p,TIF_SIGPENDING )); } +/* Prevent TIF_NOTIFY_SIGNAL from interrupting this task. */ +static inline unsigned int no_notify_signal_save (void ) +{ +unsigned int flags = current->flags; + + current->flags |=PF_NO_NOTIFY_SIGNAL ; +return flags; +} + +/* Restore the previous PF_NO_NOTIFY_SIGNAL state. */ +static inline void no_notify_signal_restore (unsigned int flags) +{ +current_restore_flags (flags,PF_NO_NOTIFY_SIGNAL ); +} + +DEFINE_LOCK_GUARD_0 (no_notify_signal, + _T->flags =no_notify_signal_save (), +no_notify_signal_restore (_T->flags), + unsigned int flags) +static inline int signal_pending (struct task_struct *p) {/* * TIF_NOTIFY_SIGNAL isn't really a signal, but it requires the same * behavior in terms of ensuring that we break out of wait loops -* so that notify signal callbacks can be processed. +* so that notify signal callbacks can be processed. Not for a task +* that asked not to be interrupted by it, see no_notify_signal_save(). */ -if (unlikely (test_tsk_thread_flag (p,TIF_NOTIFY_SIGNAL ))) +if (unlikely (test_tsk_thread_flag (p,TIF_NOTIFY_SIGNAL )) && +likely (!(READ_ONCE (p->flags) &PF_NO_NOTIFY_SIGNAL )))return 1 ;return task_sigpending (p); }
io_uring/cancel.c +38 -5
85 lines not on this page · raw message
io_uring/cancel.h +2 -0
@@ -11,6 +11,8 @@ struct io_cancel_data {u8 opcode;u32 flags;int seq; +/* io_try_cancel() has found it being run by io-wq, and flagged it */ +bool running; };int io_async_cancel_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe);
io_uring/fdinfo.c +10 -4
@@ -154,11 +154,17 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) cq_entries =min (cq_tail - cq_head, ctx->cq_entries);for (i =0 ; i < cq_entries; i++) {struct io_uring_cqe *cqe; -bool cqe32 = false; +bool cqe32 = false, two_entries = false; - cqe = &r->cqes[(cq_head & cq_mask)]; -if (cqe->flags &IORING_CQE_F_32 || ctx->flags &IORING_SETUP_CQE32 ) +if (ctx->flags &IORING_SETUP_CQE32 ) { +/* all entries have twice the size */ + cqe = &r->cqes[(cq_head & cq_mask) <<1 ]; cqe32 = true; + }else { + cqe = &r->cqes[(cq_head & cq_mask)]; + two_entries = cqe->flags &IORING_CQE_F_32 ; + cqe32 = two_entries; + }seq_printf (m,"%5u: user_data:%llu, res:%d, flags:%x" , cq_head & cq_mask, cqe->user_data, cqe->res, cqe->flags);
@@ -167,7 +173,7 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) cqe->big_cqe[0], cqe->big_cqe[1]);seq_printf (m,"\n" ); cq_head++; -if (cqe32) { +if (two_entries) { cq_head++; i++; }
io_uring/futex.c +28 -4
@@ -152,6 +152,24 @@ int io_futex_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)return 0 ; } +/* +* A wait on a private futex does not block the submitter. Even a single +* threaded task can go on and have the mm private hash installed by clone() +* or prctl(), which does not pick up waiters from the global hash. Make +* sure the private hash exists before the first waiter is queued. +*/ +static int io_futex_prep_private (struct io_kiocb *req) +{ +int ret =futex_hash_allocate_default (); + +if (unlikely (ret)) +return ret; + +/* inflight tracking only needed for mm private hash */ +io_req_track_inflight (req); +return 0 ; +} +int io_futex_wait_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe) { struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
@@ -161,9 +179,8 @@ int io_futex_wait_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)if (unlikely (ret))return ret; -/* inflight tracking only needed for mm private hash */ if (!(iof->futex_flags &FLAGS_SHARED )) -io_req_track_inflight (req); +return io_futex_prep_private (req);return 0 ; }
@@ -213,10 +230,13 @@ int io_futexv_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)return ret; } -/* inflight tracking only needed for mm private hash */ for (i =0 ; i < iof->futex_nr; i++) {if (!(ifd->futexv[i].w.flags &FLAGS_SHARED )) { -io_req_track_inflight (req); + ret =io_futex_prep_private (req); +if (ret) { +kfree (ifd); +return ret; + }break ; } }
@@ -283,6 +303,8 @@ int io_futexv_wait(struct io_kiocb *req, unsigned int issue_flags)*/ __set_current_state (TASK_RUNNING );hlist_add_head (&req->hash_node, &ctx->futex_list); +if (io_wq_cancel_seen (req, issue_flags)) +__io_futex_cancel (req); }else { iof->futexv_unqueued =1 ;if (woken !=-1 )
@@ -323,6 +345,8 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags) &ifd->q, NULL, NULL);if (!ret) {hlist_add_head (&req->hash_node, &ctx->futex_list); +if (io_wq_cancel_seen (req, issue_flags)) +__io_futex_cancel (req);io_ring_submit_unlock (ctx, issue_flags);return IOU_ISSUE_SKIP_COMPLETE ;
io_uring/io-wq.c +109 -17
229 lines not on this page · raw message
io_uring/io_uring.c +141 -39
320 lines not on this page · raw message
io_uring/io_uring.h +43 -1
62 lines not on this page · raw message
io_uring/kbuf.c +1 -1
@@ -203,7 +203,7 @@ static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len,if (unlikely (tail == head))return sel; -if (head +1 == tail) +if ((__u16)(head +1 ) == tail) req->flags |=REQ_F_BL_EMPTY ; buf =io_ring_head_to_buf (br, head, bl->mask);
io_uring/loop.c +1 -7
@@ -9,12 +9,6 @@ static inline int io_loop_nr_cqes(const struct io_ring_ctx *ctx,return lp->cq_wait_idx -READ_ONCE (ctx->rings->cq.tail); } -static inline void io_loop_wait_start (struct io_ring_ctx *ctx,unsigned nr_wait) -{ -atomic_set (&ctx->cq_wait_nr, nr_wait); -set_current_state (TASK_INTERRUPTIBLE ); -} -static inline void io_loop_wait_finish (struct io_ring_ctx *ctx) {__set_current_state (TASK_RUNNING );
@@ -24,7 +18,7 @@ static inline void io_loop_wait_finish(struct io_ring_ctx *ctx)static void io_loop_wait (struct io_ring_ctx *ctx,struct iou_loop_params *lp,unsigned nr_wait) { -io_loop_wait_start (ctx, nr_wait); +io_cq_wait_arm (ctx, nr_wait); if (unlikely(io_local_work_pending(ctx) || io_loop_nr_cqes(ctx, lp) <= 0) ||
io_uring/mpscq.h +11 -3
@@ -25,9 +25,10 @@* its predecessor. In between, the tail end of the queue is not yet reachable * from the head. mpscq_pop() detects this and returns NULL, while mpscq_empty() * reports false. The consumer must not treat such a NULL as "queue empty" - it -* should retry later. The window is two instructions wide, but a producer can -* be preempted inside it, so the consumer must not spin on it while holding -* resources the producer might need to make progress. +* should retry later. The window is two instructions wide and the producer +* can't be preempted inside it, but it can be interrupted, so the consumer must +* not spin on it while holding resources the producer might need to make +* progress. * * The consumer side only supports a single consumer at a time, callers must * provide their own serialization for it. The stub node is what allows the
@@ -69,6 +70,12 @@ static inline bool mpscq_push(struct mpscq *q, struct llist_node *node)struct llist_node *prev; node->next =NULL ; +/* +* All the consumer can do about a node that isn't linked yet is to try +* again. If it is what preempted us, and we don't get to run as long +* as it does, that never ends. +*/ +preempt_disable ();/* * xchg() implies a full barrier, so the initialization of the * entry (including ->next above) is visible before the node can
@@ -77,6 +84,7 @@ static inline bool mpscq_push(struct mpscq *q, struct llist_node *node)*/ prev =xchg (&q->tail, node);WRITE_ONCE (prev->next, node); +preempt_enable ();return prev == &q->stub; }
io_uring/napi.c +3 -1
@@ -6,7 +6,7 @@ #ifdef CONFIG_NET_RX_BUSY_POLL /* Timeout for cleanout of stale entries. */ -#define NAPI_TIMEOUT (60 * SEC_CONVERSION) +#define NAPI_TIMEOUT (60 * HZ) struct io_napi_entry { unsigned int napi_id;
@@ -378,6 +378,8 @@ void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq)if (iowq->timeout !=KTIME_MAX ) {ktime_t dt =ktime_sub (iowq->timeout,io_get_time (ctx)); +/* an absolute timeout may have passed already */ + dt =max_t (ktime_t, dt,0 ); iowq->napi_busy_poll_dt =min_t (u64, iowq->napi_busy_poll_dt, dt); }
io_uring/net.c +24 -2
@@ -511,6 +511,24 @@ static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret)return nbufs; } +/* +* A receive that is retried after a partial transfer keeps writing to what it +* has mapped. io_net_kbuf_recyle() only commits what was filled so far, which +* takes a buffer out of circulation if it's a single one that is consumed as a +* whole. The tail of an incrementally consumed buffer, or the yet unused +* buffers of a bundle, would be up for grabs. They can't be committed in +* advance either, the CQE has no way to tell if they end up not being used. +*/ +static bool io_net_kbuf_can_retry (struct io_kiocb *req, +struct io_buffer_list *bl, +struct io_async_msghdr *kmsg) +{ +/* not ring provided, or committed at selection time */ +if (!(req->flags &REQ_F_BUFFERS_COMMIT )) +return true; +return !(bl->flags &IOBL_INC ) &&iter_is_ubuf (&kmsg->msg.msg_iter); +} +static int io_net_kbuf_recyle (struct io_kiocb *req,struct io_buffer_list *bl,struct io_async_msghdr *kmsg,int len) {
@@ -1122,7 +1140,8 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)io_kbuf_recycle (req, sel.buf_list, issue_flags);return IOU_RETRY ; } -if (ret >0 &&io_net_retry (sock, flags)) { +if (ret >0 &&io_net_retry (sock, flags) && +io_net_kbuf_can_retry (req, sel.buf_list, kmsg)) { sr->done_io += ret;return io_net_kbuf_recyle (req, sel.buf_list, kmsg, ret); }
@@ -1209,6 +1228,8 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg *sel =io_buffer_select (req, &len, sr->buf_group, issue_flags);if (!sel->addr)return -ENOBUFS ; +/* ring provided buffers can be up to 4G, keep len an int */ + len =min_t (size_t, len,MAX_RW_COUNT ); sr->buf = sel->addr; sr->len = len; map_ubuf:
@@ -1283,7 +1304,8 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)io_kbuf_recycle (req, sel.buf_list, issue_flags);return IOU_RETRY ; } -if (ret >0 &&io_net_retry (sock, flags)) { +if (ret >0 &&io_net_retry (sock, flags) && +io_net_kbuf_can_retry (req, sel.buf_list, kmsg)) { sr->len -= ret; sr->buf += ret; sr->done_io += ret;
io_uring/openclose.c +7 -4
@@ -375,13 +375,16 @@ static int io_pipe_fixed(struct io_kiocb *req, struct file **files, fds[1 ] = alloc_slot ? ret : slot -1 ; files[1 ] =NULL ; -io_ring_submit_unlock (ctx, issue_flags); - -if (!copy_to_user (p->fds, fds,sizeof (fds))) +/* +* Hang on to the lock. If this fails, the slots have to be cleared, and +* they must still hold what was put there. +*/ +if (!copy_to_user (p->fds, fds,sizeof (fds))) { +io_ring_submit_unlock (ctx, issue_flags);return 0 ; + } ret = -EFAULT ; -io_ring_submit_lock (ctx, issue_flags); err:if (fds[0 ] !=-1 )io_fixed_fd_remove (ctx, fds[0 ]);
io_uring/poll.c +34 -4
@@ -241,12 +241,14 @@ static inline void io_poll_execute(struct io_kiocb *req, int res,*/ static int io_poll_check_events (struct io_kiocb *req,io_tw_token_t tw) { +bool again;int v;if (unlikely (tw.cancel))return -ECANCELED ; do { + again = false; v = atomic_read(&req->poll_refs); if (unlikely(v != 1)) {
@@ -310,9 +312,15 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw) }else {int ret; -/* multiple refs and HUP, ensure we loop once more */ -if ((req->cqe.res & (POLLHUP |POLLRDHUP )) && v !=1 ) - v--; +/* +* Multiple refs and HUP, ensure we loop once more. Drop +* down to one ref now, so the next pass ends unless a +* wake up came in. +*/ +if ((req->cqe.res & (POLLHUP |POLLRDHUP )) && v !=1 ) { +atomic_sub (v -1 , &req->poll_refs); + again = true; + } ret =io_poll_issue (req, tw);if (ret ==IOU_COMPLETE )
@@ -330,7 +338,8 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)* Release all references, retry if someone tried to restart * task_work while we were executing it. */ - }while (atomic_sub_return (v, &req->poll_refs) &IO_POLL_REF_MASK ); + v &=IO_POLL_REF_MASK ; + }while (again ||atomic_cmpxchg (&req->poll_refs, v,0 ) != v);io_napi_add (req);return IOU_POLL_NO_ACTION ;
@@ -617,6 +626,18 @@ static int __io_arm_poll_handler(struct io_kiocb *req,io_poll_add_hash (req, issue_flags); +/* +* Whoever tried to cancel the request while io-wq was running it has +* flagged the work item. If it searched the hash table before the +* request got there it found nothing, and it won't come back. Both +* the search and the insertion are done with ->uring_lock held, and +* the flag is set before the search. If the search came first, +* the flag is visible by now. +*/ +if (ipt->owning && + (atomic_read (&req->work.flags) &IO_WQ_WORK_CANCEL )) +io_poll_mark_cancelled (req); +if (mask && (poll->events &EPOLLET ) &&io_poll_can_finish_inline (req, ipt)) {__io_poll_execute (req, mask,0 );
@@ -906,6 +927,15 @@ int io_poll_add(struct io_kiocb *req, unsigned int issue_flags) ipt.pt._qproc = io_poll_queue_proc; +/* +* A poll update or a spurious wake up arms the request again. Forget +* the entries of the previous round like io_arm_apoll() does, a stale +* second entry would be taken for a third wait queue. +*/ +if (req_has_async_data (req)) +io_req_async_data_free (req); + req->flags &= ~(REQ_F_SINGLE_POLL |REQ_F_DOUBLE_POLL ); + ret =__io_arm_poll_handler (req, poll, &ipt, poll->events, issue_flags);if (ret >0 ) {io_req_set_res (req, ipt.result_mask,0 );
io_uring/register.c +51 -3
95 lines not on this page · raw message
io_uring/rw.c +0 -18
@@ -624,24 +624,6 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)smp_store_release (&req->iopoll_completed,1 ); } -static inline ssize_t io_fixup_restart_res (ssize_t ret) -{ -switch (ret) { -case -ERESTARTSYS : -case -ERESTARTNOINTR : -case -ERESTARTNOHAND : -case -ERESTART_RESTARTBLOCK : -/* -* We can't just restart the syscall, since previously -* submitted sqes may already be in progress. Just fail -* this IO with EINTR. -*/ -return -EINTR ; -default : -return ret; - } -} -static inline void io_rw_done (struct io_kiocb *req,ssize_t ret) { struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
io_uring/sqpoll.c +7 -0
@@ -380,6 +380,13 @@ static int io_sq_thread(void *data)*/ smp_mb__after_atomic (); +/* +* Nothing gets submitted before the ring is +* enabled, which comes with a wake up. +*/ +if (READ_ONCE (ctx->flags) &IORING_SETUP_R_DISABLED ) +continue ; +if (io_sqring_entries (ctx)) { needs_sched = false;break ;
io_uring/timeout.c +80 -22
174 lines not on this page · raw message
io_uring/tw.c +35 -1
@@ -148,6 +148,37 @@ static void io_ctx_mark_taskrun(struct io_ring_ctx *ctx) } } +static void io_poll_wq_wake_rcu (struct rcu_head *rcu) +{ + struct io_ring_ctx *ctx = container_of(rcu, struct io_ring_ctx, + poll_wq_rcu); + +atomic_set (&ctx->poll_wq_rcu_pending,0 ); +io_poll_wq_wake (ctx); +percpu_ref_put (&ctx->refs); +} + +/* +* io_uring_poll() reports pending local work as EPOLLIN, as it takes a trip to +* the kernel to turn it into CQEs. Let those know who are asleep already. +*/ +static void io_local_work_wake_poll (struct io_ring_ctx *ctx,unsigned int flags) +{ +if (!(flags &IOU_F_TWQ_IN_WAKE )) { +io_poll_wq_wake (ctx); +return ; + } +/* +* Called from a wake up handler with some wait queue lock held, this +* one could lead back to it. Do it from a clean context. +*/ +if (!wq_has_sleeper (&ctx->poll_wq) || +atomic_xchg (&ctx->poll_wq_rcu_pending,1 )) +return ; +percpu_ref_get (&ctx->refs); +call_rcu_hurry (&ctx->poll_wq_rcu, io_poll_wq_wake_rcu); +} +void io_req_local_work_add (struct io_kiocb *req,unsigned flags) {struct io_ring_ctx *ctx = req->ctx;
@@ -165,7 +196,7 @@ void io_req_local_work_add(struct io_kiocb *req, unsigned flags)/* * The xchg() in mpscq_push() implies a full barrier, which pairs with -* the barrier in set_current_state() on the io_cqring_wait() side. This +* the barrier in io_cq_wait_arm() on the io_cqring_wait() side. This * ensures that either we see the updated ->cq_wait_nr, or waiters going * to sleep will observe the work added to the list, which is similar to * the wait/wake task state sync.
@@ -174,6 +205,9 @@ void io_req_local_work_add(struct io_kiocb *req, unsigned flags)io_ctx_mark_taskrun (ctx);if (data_race (ctx->int_flags) &IO_RING_F_HAS_EVFD )io_eventfd_signal (ctx, false, flags &IOU_F_TWQ_IN_WAKE ); +/* whoever sets the flag wakes ->poll_wq afterwards */ +if (data_race (ctx->int_flags) &IO_RING_F_POLL_ACTIVATED ) +io_local_work_wake_poll (ctx, flags); }/*
io_uring/uring_cmd.c +1 -1
@@ -87,7 +87,7 @@ static void io_uring_cmd_del_cancelable(struct io_uring_cmd *cmd, cmd->flags &= ~IORING_URING_CMD_CANCELABLE ;io_ring_submit_lock (ctx, issue_flags); -hlist_del (&req->hash_node); +hlist_del_init (&req->hash_node);io_ring_submit_unlock (ctx, issue_flags); }
io_uring/wait.c +37 -11
99 lines not on this page · raw message
io_uring/wait.h +15 -0
@@ -14,6 +14,21 @@*/ #define IO_CQ_WAKE_INIT (-1) +/* +* Start a wait cycle of the current task. The add that uses up ->cq_wait_nr +* may be one that queued its entry long ago and only now gets to look at the +* count. As nobody else wakes us after that, it has to find us sleeping, hence +* the task state must be visible before the count is. The barrier pairs with +* the xchg() in mpscq_push(), see io_req_local_work_add(). +*/ +static inline void io_cq_wait_arm (struct io_ring_ctx *ctx,int nr_wait) +{ +__set_current_state (TASK_INTERRUPTIBLE ); +atomic_set_release (&ctx->cq_wait_nr, nr_wait); +/* order the above against looking at the work list */ +smp_mb (); +} +struct ext_arg {size_t argsz;struct timespec64 ts;
io_uring/waitid.c +15 -4
@@ -154,9 +154,12 @@ static bool __io_waitid_cancel(struct io_kiocb *req, bool copy_si)/* * Mark us canceled regardless of ownership. This will prevent a -* potential retry from a spurious wakeup. +* potential retry from a spurious wakeup. Only the first cancel +* attempt should take a reference for the ownership handoff. */ -atomic_or (IO_WAITID_CANCEL_FLAG , &iw->refs); +if (atomic_fetch_or (IO_WAITID_CANCEL_FLAG , &iw->refs) & +IO_WAITID_CANCEL_FLAG ) +return false;/* claim ownership */ if (atomic_fetch_inc (&iw->refs) &IO_WAITID_REF_MASK )
@@ -265,12 +268,18 @@ static int io_waitid_wait(struct wait_queue_entry *wait, unsigned mode,return 0 ;list_del_init (&wait->entry); -smp_store_release (&iw->head,NULL ); -/* cancel is in progress */ +/* +* Cancel or issue is in progress. Leave ->head alone, so that whoever +* owns the request has to take the wait queue lock, which we hold, +* before it can complete and free it. +*/ if (atomic_fetch_inc (&iw->refs) &IO_WAITID_REF_MASK )return 1 ; +/* pairs with the smp_load_acquire() in io_waitid_remove_wq() */ +smp_store_release (&iw->head,NULL ); + req->io_task_work.func = io_waitid_cb;__io_req_task_work_add (req,IOU_F_TWQ_IN_WAKE );return 1 ;
@@ -343,6 +352,8 @@ int io_waitid(struct io_kiocb *req, unsigned int issue_flags)* a waitqueue callback, or if someone cancels it. */ if (!io_waitid_drop_issue_ref (req)) { +if (io_wq_cancel_seen (req, issue_flags)) +__io_waitid_cancel (req, true);io_ring_submit_unlock (ctx, issue_flags);return IOU_ISSUE_SKIP_COMPLETE ; }
io_uring/zcrx.c +1 -1
@@ -1474,7 +1474,7 @@ static bool io_zcrx_queue_cqe(struct io_kiocb *req, struct net_iov *niov, cqe->flags |=IORING_CQE_F_32 ; area =io_zcrx_iov_to_area (niov); - offset = off + (net_iov_idx (niov) << ifq->niov_shift); + offset = off + ((u64 )net_iov_idx (niov) << ifq->niov_shift); rcqe = (struct io_uring_zcrx_cqe *)(cqe +1 ); rcqe->off = offset + ((u64 )area->area_id <<IORING_ZCRX_AREA_SHIFT ); rcqe->__pad =0 ;
kernel/exit.c +3 -2
@@ -979,10 +979,11 @@ void __noreturn do_exit(long code)exit_sem (tsk);exit_shm (tsk); -exit_files (tsk); -exit_fs (tsk); +/* Hang the tty up before the last close of it can clear the session. */ if (group_dead)disassociate_ctty (1 ); +exit_files (tsk); +exit_fs (tsk);exit_nsproxy_namespaces (tsk);exit_task_work (tsk);exit_thread (tsk);
kernel/fork.c +6 -3
@@ -1658,6 +1658,7 @@ static int copy_files(u64 clone_flags, struct task_struct *tsk,if (clone_flags &CLONE_FILES ) {atomic_inc (&oldf->count); + tsk->files = oldf;return 0 ; }
@@ -2181,6 +2182,8 @@ __latent_entropy struct task_struct *copy_process(INIT_LIST_HEAD (&p->sibling);rcu_copy_process (p); p->vfork_done =NULL ; +/* Set by copy_files(), exit_files() on the error path skips NULL. */ + p->files =NULL ;spin_lock_init (&p->alloc_lock);init_sigpending (&p->pending);
@@ -2282,7 +2285,7 @@ __latent_entropy struct task_struct *copy_process( goto bad_fork_cleanup_semundo; retval =copy_fs (clone_flags, p);if (retval) - goto bad_fork_cleanup_files; + goto bad_fork_cleanup_semundo; retval =copy_sighand (clone_flags, p);if (retval) goto bad_fork_cleanup_fs;
@@ -2596,8 +2599,6 @@ __latent_entropy struct task_struct *copy_process(__cleanup_sighand (p->sighand); bad_fork_cleanup_fs:exit_fs (p);/* blocking */ -bad_fork_cleanup_files: -exit_files (p);/* blocking */ bad_fork_cleanup_semundo:exit_sem (p); bad_fork_cleanup_security:
@@ -2608,6 +2609,8 @@ __latent_entropy struct task_struct *copy_process(perf_event_free_task (p); bad_fork_sched_cancel_fork:sched_cancel_fork (p); +/* ->release() of a file may need scx_fork_rwsem for write. */ +exit_files (p);/* blocking */ bad_fork_cleanup_policy:lockdep_free_task (p);#ifdef CONFIG_NUMA
kernel/pid_namespace.c +2 -1
@@ -238,9 +238,10 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)* kernel_wait4() will also block until our children traced from the * parent namespace are detached and become EXIT_DEAD. */ +/* Task work must not busy-loop the reaper, see signal_pending(). */ +guard (no_notify_signal)();do {clear_thread_flag (TIF_SIGPENDING ); -clear_thread_flag (TIF_NOTIFY_SIGNAL ); rc =kernel_wait4 (-1 ,NULL , __WALL,NULL ); }while (rc != -ECHILD );
kernel/ptrace.c +6 -0
@@ -1227,6 +1227,12 @@ int ptrace_request(struct task_struct *child, long request,case PTRACE_SETSIGMASK : {sigset_t new_set; +/* A user worker only ever takes SIGKILL and SIGSTOP. */ +if (child->flags &PF_USER_WORKER ) { + ret = -EPERM ; +break ; + } +if (addr !=sizeof (sigset_t)) { ret = -EINVAL ;break ;
kernel/sched/ext/ext.c +12 -2
@@ -2292,6 +2292,8 @@ static void move_local_task_to_local_dsq(struct scx_sched *sch,lockdep_assert_rq_held (dst_rq);WARN_ON_ONCE (p->scx.holding_cpu >=0 ); +if (unlikely (atomic_long_read_acquire (&p->scx.ops_state) ==SCX_OPSS_DISPATCHING )) +wait_ops_state (p,SCX_OPSS_DISPATCHING );if (enq_flags & (SCX_ENQ_HEAD |SCX_ENQ_PREEMPT ))list_add (&p->scx.dsq_list.node, &dst_dsq->list);
@@ -2462,8 +2464,13 @@ static bool unlink_dsq_and_lock_src_rq(struct task_struct *p,raw_spin_rq_lock (src_rq);/* task_rq couldn't have changed if we're still the holding cpu */ -return likely (p->scx.holding_cpu == cpu) && - !WARN_ON_ONCE (src_rq !=task_rq (p)); +if (likely (p->scx.holding_cpu == cpu) && !WARN_ON_ONCE (src_rq !=task_rq (p))) { +if (unlikely (atomic_long_read_acquire (&p->scx.ops_state) ==SCX_OPSS_DISPATCHING )) +wait_ops_state (p,SCX_OPSS_DISPATCHING ); +return true; + } + +return false; } static bool consume_remote_task(struct rq *this_rq,
@@ -2511,6 +2518,9 @@ static struct rq *move_task_between_dsqs(struct scx_sched *sch,lockdep_assert_held (&src_dsq->lock);lockdep_assert_rq_held (src_rq); +if (unlikely (atomic_long_read_acquire (&p->scx.ops_state) ==SCX_OPSS_DISPATCHING )) +wait_ops_state (p,SCX_OPSS_DISPATCHING ); +if (dst_dsq->id ==SCX_DSQ_LOCAL ) { dst_rq = container_of(dst_dsq, struct rq, scx.local_dsq); if (src_rq != dst_rq &&
kernel/sched/fair.c +12 -4
@@ -6250,12 +6250,20 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) load = cfs_rq->sum_weight;if (curr && curr->on_rq) load +=avg_vruntime_weight (cfs_rq, curr->load.weight); - - weight =avg_vruntime_weight (cfs_rq, se->load.weight); - lag *= load + weight;if (WARN_ON_ONCE (!load)) load =1 ; - lag =div64_long (lag, load); + + weight =avg_vruntime_weight (cfs_rq, se->load.weight); + +/* +* Rewrite, because the product (W + w_i)*vl'_i might +* overflow s64: +* +* vl_i = (W + w_i)*vl'_i / W +* = (W*vl'_i + w_i*vl'_i) / W +* = vl'_i + w_i*vl'_i/W +*/ + lag +=div64_long (lag * weight, load);/* * A heavy entity (relative to the tree) will pull the
kernel/signal.c +4 -0
@@ -3181,6 +3181,10 @@ static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which)sigset_t retarget;struct task_struct *t; +/* Nobody dequeues them in a dying group, see get_signal(). */ +if (tsk->signal->flags &SIGNAL_GROUP_EXIT ) +return ; +sigandsets (&retarget, &tsk->signal->shared_pending.signal, which);if (sigisemptyset (&retarget))return ;
kernel/trace/ftrace.c +2 -2
@@ -4426,9 +4426,9 @@ subsys_initcall(ftrace_check_for_weak_functions);static int print_rec (struct seq_file *m,unsigned long ip) { -unsigned long offset; +unsigned long offset =0 ;char str[KSYM_SYMBOL_LEN ]; -char *modname; +char *modname =NULL ;const char *ret; ret =kallsyms_lookup (ip,NULL , &offset, &modname, str);
kernel/trace/trace.c +18 -3
@@ -3614,6 +3614,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)return single_release (inode, file); } +static bool __update_last_data_if_empty (struct trace_array *tr);static bool update_last_data_if_empty (struct trace_array *tr);static int tracing_open (struct inode *inode,struct file *file)
@@ -4706,7 +4707,7 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,int tracer_init (struct tracer *t,struct trace_array *tr) {tracing_reset_online_cpus (&tr->array_buffer); -update_last_data_if_empty (tr); +__update_last_data_if_empty (tr);return t->init (tr); }
@@ -5385,8 +5386,10 @@ static int tracing_wait_pipe(struct file *filp)return 1 ; } -static bool update_last_data_if_empty (struct trace_array *tr) +static bool __update_last_data_if_empty (struct trace_array *tr) { +lockdep_assert_held (&trace_types_lock); +if (!(tr->flags &TRACE_ARRAY_FL_LAST_BOOT ))return false;
@@ -5401,6 +5404,16 @@ static bool update_last_data_if_empty(struct trace_array *tr)return true; } +static bool update_last_data_if_empty (struct trace_array *tr) +{ +/* Avoid the lock on the read path unless this is a last boot buffer */ +if (!(tr->flags &TRACE_ARRAY_FL_LAST_BOOT )) +return false; + +guard (mutex)(&trace_types_lock); +return __update_last_data_if_empty (tr); +} +/* * Consumer reader. */
@@ -6493,7 +6506,7 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)ring_buffer_set_clock (tr->snapshot_buffer.buffer, trace_clocks[i].func);tracing_reset_online_cpus (&tr->snapshot_buffer);#endif -update_last_data_if_empty (tr); +__update_last_data_if_empty (tr);if (tr->scratch && !(tr->flags &TRACE_ARRAY_FL_LAST_BOOT )) {struct trace_scratch *tscratch = tr->scratch;
@@ -9261,6 +9274,8 @@ static void trace_module_record(struct module *mod, bool add)struct trace_array *tr;unsigned long flags; +guard (mutex)(&trace_types_lock); +list_for_each_entry (tr, &ftrace_trace_arrays, list) { flags = tr->flags & (TRACE_ARRAY_FL_BOOT |TRACE_ARRAY_FL_LAST_BOOT );/* Update any persistent trace array that has already been started */
kernel/trace/trace_events_filter.c +6 -0
@@ -595,6 +595,12 @@ predicate_parse(const char *str, int nr_parens, int nr_preds, top--;/* #12 */ } } +/* Only the inner loop can complete a non-empty expression. */ +if (N ) { + ret = -EINVAL ; +parse_error (pe,FILT_ERR_INVALID_FILTER , ptr - str); + goto out_free; + } out:if (top != op_stack) {/* Too many '(' */
kernel/trace/trace_events_hist.c +14 -19
@@ -467,7 +467,7 @@ static u64 hist_field_unary_minus(struct hist_field *hist_field, { \type *addr = (type *)(event + hist_field->field->offset); \ \ -return (u64 )(unsigned long )*addr; \ +return (u64)*addr; \ }DEFINE_HIST_FIELD_FN (s64);
@@ -550,7 +550,7 @@ struct field_var { };struct field_var_hist { -struct hist_trigger_data *hist_data; +struct trace_event_file *file;char *cmd; };
@@ -3099,8 +3099,8 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,return ERR_PTR (-ENOMEM ); } -/* Save the compatible histogram information */ - var_hist->hist_data = hist_data; +/* Needed to remove the histogram when the target goes away */ + var_hist->file = file;/* Create the new histogram with our variable */ ret = event_hist_trigger_parse(&trigger_hist_cmd, file,
@@ -3115,20 +3115,18 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,kfree (cmd); + n = target_hist_data->n_field_var_hists; + target_hist_data->field_var_hists[n] = var_hist; + target_hist_data->n_field_var_hists++; +/* If we can't find the variable, something went wrong */ event_var =find_synthetic_field_var (target_hist_data, subsys_name, event_name, field_name);if (IS_ERR_OR_NULL (event_var)) { -kfree (var_hist->cmd); -kfree (var_hist);hist_err (tr,HIST_ERR_SYNTH_VAR_NOT_FOUND ,errpos (field_name));return ERR_PTR (-EINVAL ); } - n = target_hist_data->n_field_var_hists; - target_hist_data->field_var_hists[n] = var_hist; - target_hist_data->n_field_var_hists++; -return event_var; }
@@ -6331,7 +6329,7 @@ static void unregister_field_var_hists(struct hist_trigger_data *hist_data)int ret;for (i =0 ; i < hist_data->n_field_var_hists; i++) { - file = hist_data->field_var_hists[i]->hist_data->event_file; + file = hist_data->field_var_hists[i]->file; cmd = hist_data->field_var_hists[i]->cmd; ret =event_hist_trigger_parse (&trigger_hist_cmd, file,"!hist" ,"hist" , cmd);
@@ -6781,7 +6779,6 @@ static void hist_unreg_all(struct trace_event_file *file)struct event_trigger_data *test, *n;struct hist_trigger_data *hist_data;struct synth_event *se; -const char *se_name;lockdep_assert_held (&event_mutex);
@@ -6794,8 +6791,7 @@ static void hist_unreg_all(struct trace_event_file *file)list_del_rcu (&test->list);trace_event_trigger_enable_disable (file,0 ); - se_name =trace_event_name (file->event_call); - se =find_synth_event (se_name); + se =find_synth_event_call (file->event_call);if (se) se->ref--;
@@ -6819,7 +6815,6 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,struct hist_trigger_data *hist_data;char *param, *filter, *p, *start;struct synth_event *se; -const char *se_name;bool remove;int ret =0 ;
@@ -6913,8 +6908,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops, }event_trigger_unregister (cmd_ops, file, glob+1 , trigger_data); - se_name =trace_event_name (file->event_call); - se =find_synth_event (se_name); + se =find_synth_event_call (file->event_call);if (se) se->ref--; ret =0 ;
@@ -6949,8 +6943,7 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,if (ret) goto out_unreg; - se_name =trace_event_name (file->event_call); - se =find_synth_event (se_name); + se =find_synth_event_call (file->event_call);if (se) se->ref++; out:
@@ -6967,6 +6960,8 @@ static int event_hist_trigger_parse(struct event_command *cmd_ops,trigger_data_free (trigger_data); +unregister_field_var_hists (hist_data); +destroy_hist_data (hist_data); goto out; }
kernel/trace/trace_events_synth.c +10 -0
@@ -914,6 +914,16 @@ struct synth_event *find_synth_event(const char *name)return NULL ; } +struct synth_event *find_synth_event_call (struct trace_event_call *call) +{ +struct synth_event *se; +const char *name; + + name =trace_event_name (call); + se =find_synth_event (name); +return se && &se->call == call ? se :NULL ; +} +static struct trace_event_fields synth_event_fields_array[] = { { .type =TRACE_FUNCTION_TYPE , .define_fields = synth_event_define_fields },
kernel/trace/trace_synth.h +1 -0
@@ -37,5 +37,6 @@ struct synth_event { };extern struct synth_event *find_synth_event (const char *name); +extern struct synth_event *find_synth_event_call (struct trace_event_call *call);#endif /* __TRACE_SYNTH_H */
kernel/trace/trace_syscalls.c +1 -1
@@ -682,7 +682,7 @@ static int syscall_copy_user_array(char *buf, const char __user *ptr,for (int i =0 ; i < args->uargs; i++, buf +=SYSCALL_FAULT_ARG_SZ ) { ptr = (char __user *)args->ptr_array[i]; - ret =__copy_from_user (buf, ptr, size); + ret =copy_from_user (buf, ptr, size); args->read[i] = ret ?-1 : size; }return 0 ;
mm/damon/core.c +16 -6
@@ -999,15 +999,18 @@ static void damos_commit_quota_goal_union( } } -static void damos_commit_quota_goal ( +static int damos_commit_quota_goal (struct damos_quota_goal *dst,struct damos_quota_goal *src) { +if (!src->target_value) +return -EINVAL ; dst->metric = src->metric; dst->target_value = src->target_value;if (dst->metric ==DAMOS_QUOTA_USER_INPUT ) dst->current_value = src->current_value;/* keep last_psi_total as is, since it will be updated in next cycle */ damos_commit_quota_goal_union (dst, src); +return 0 ; }/**
@@ -1025,14 +1028,17 @@ static void damos_commit_quota_goal(int damos_commit_quota_goals (struct damos_quota *dst,struct damos_quota *src) {struct damos_quota_goal *dst_goal, *next, *src_goal, *new_goal; -int i =0 , j =0 ; +int i =0 , j =0 , err;damos_for_each_quota_goal_safe (dst_goal, next, dst) { src_goal =damos_nth_quota_goal (i++, src); -if (src_goal) -damos_commit_quota_goal (dst_goal, src_goal); -else +if (src_goal) { + err =damos_commit_quota_goal (dst_goal, src_goal); +if (err) +return err; + }else {damos_destroy_quota_goal (dst_goal); + } }damos_for_each_quota_goal_safe (src_goal, next, src) {if (j++ < i)
@@ -1041,7 +1047,11 @@ int damos_commit_quota_goals(struct damos_quota *dst, struct damos_quota *src) src_goal->metric, src_goal->target_value);if (!new_goal)return -ENOMEM ; -damos_commit_quota_goal (new_goal, src_goal); + err =damos_commit_quota_goal (new_goal, src_goal); +if (err) { +damos_free_quota_goal (new_goal); +return err; + }damos_add_quota_goal (dst, new_goal); }return 0 ;
mm/damon/sysfs.c +19 -0
@@ -2226,6 +2226,20 @@ static int damon_sysfs_repeat_call_fn(void *data)return 0 ; } +static bool damon_sysfs_valid_start_ctx (struct damon_ctx *ctx) +{ +struct damos *s; +struct damos_quota_goal *g; + +damon_for_each_scheme (s, ctx) { +damos_for_each_quota_goal (g, &s->quota) { +if (!g->target_value) +return false; + } + } +return true; +} +static int damon_sysfs_turn_damon_on (struct damon_sysfs_kdamond *kdamond) {struct damon_ctx *ctx;
@@ -2251,6 +2265,11 @@ static int damon_sysfs_turn_damon_on(struct damon_sysfs_kdamond *kdamond)kfree (repeat_call_control);return PTR_ERR (ctx); } +if (!damon_sysfs_valid_start_ctx (ctx)) { +kfree (repeat_call_control); +damon_destroy_ctx (ctx); +return -EINVAL ; + } err =damon_start (&ctx,1 , false);if (err) {kfree (repeat_call_control);
net/bluetooth/l2cap_core.c +6 -1
@@ -622,6 +622,10 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)BT_DBG ("conn %p, psm 0x%2.2x, dcid 0x%4.4x" , conn,__le16_to_cpu (chan->psm), chan->dcid); +/* Caller must ensure l2cap_chan is linked to l2cap_conn only once */ +if (WARN_ON_ONCE (chan->conn ||test_bit (FLAG_DEL , &chan->flags))) +return ; + conn->disc_reason =HCI_ERROR_REMOTE_USER_TERM ; chan->conn =l2cap_conn_get (conn);
@@ -7412,7 +7416,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, } } -if (cid &&__l2cap_get_chan_by_dcid (conn, cid)) { +if ((cid &&__l2cap_get_chan_by_dcid (conn, cid)) || chan->conn || +test_bit (FLAG_DEL , &chan->flags)) {hci_conn_drop (hcon); err = -EBUSY ; goto chan_unlock;
net/bluetooth/l2cap_sock.c +2 -0
@@ -109,6 +109,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, ireturn -EINVAL ; } +l2cap_chan_lock (chan);lock_sock (sk);if (sk->sk_state !=BT_OPEN ) {
@@ -174,6 +175,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, i done:release_sock (sk); +l2cap_chan_unlock (chan);return err; }
security/keys/key.c +10 -3
@@ -588,11 +588,18 @@ int key_reject_and_link(struct key *key, ret = -EBUSY ;if (keyring) { -if (keyring->restrict_link) -return -EPERM ; - link_ret =__key_link_lock (keyring, &key->index_key);if (link_ret ==0 ) { +/* +* Check the restriction under the keyring semaphore. +* keyring_restrict() installs it while holding the +* semaphore, so testing it beforehand races with a +* concurrent restriction install. +*/ +if (keyring->restrict_link) { +__key_link_end (keyring, &key->index_key, edit); +return -EPERM ; + } link_ret =__key_link_begin (keyring, &key->index_key, &edit);if (link_ret <0 )__key_link_end (keyring, &key->index_key, edit);
security/keys/keyctl.c +8 -7
@@ -677,12 +677,14 @@ long keyctl_describe_key(key_serial_t keyid,/* calculate how much information we're going to return */ ret = -ENOMEM ; +down_read (&key->sem); infobuf =kasprintf (GFP_KERNEL ,"%s;%d;%d;%08x;" , key->type->name,from_kuid_munged (current_user_ns (), key->uid),from_kgid_munged (current_user_ns (), key->gid), key->perm); +up_read (&key->sem);if (!infobuf) goto error2; infolen =strlen (infobuf);
@@ -806,8 +808,12 @@ static long __keyctl_read_key(struct key *key, char *buffer, size_t buflen)down_read (&key->sem); ret =key_validate (key); -if (ret ==0 ) - ret = key->type->read (key, buffer, buflen); +if (ret ==0 ) { +if (key->type->read) + ret = key->type->read (key, buffer, buflen); +else + ret = -EOPNOTSUPP ; + }up_read (&key->sem);return ret; }
@@ -861,11 +867,6 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)/* the key is probably readable - now try to read it */ can_read_key: -if (!key->type->read) { - ret = -EOPNOTSUPP ; - goto key_put_out; - } -if (!buffer || !buflen) {/* Get the key length from the read method */ ret =__keyctl_read_key (key,NULL ,0 );
security/keys/keyring.c +81 -71
232 lines not on this page · raw message
security/keys/process_keys.c +2 -3
@@ -556,9 +556,8 @@ key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx) ) {const struct cred *cred = ctx->cred; -if (key_validate (cred->request_key_auth) ==0 ) { - rka = ctx->cred->request_key_auth->payload.data[0 ]; - + rka =dereference_key_rcu (cred->request_key_auth); +if (rka &&key_validate (cred->request_key_auth) ==0 ) {//// was search_process_keyrings() [ie. recursive] ctx->cred = rka->cred; key_ref =search_cred_keyrings_rcu (ctx);
security/keys/trusted-keys/trusted_tpm1.c +3 -1
@@ -928,8 +928,10 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob) ret =tpm2_unseal_trusted (chip, p, options); else ret =key_unseal (p, options); -if (ret <0 ) +if (ret <0 ) {pr_info ("key_unseal failed (%d)\n" , ret); + goto out; + }if (options->pcrlock) { ret =pcrlock (options->pcrlock);
security/keys/trusted-keys/trusted_tpm2.c +1 -1
@@ -116,7 +116,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,if (ctx.priv_len + ctx.pub_len >MAX_BLOB_SIZE )return -EINVAL ; - blob =kmalloc (ctx.priv_len + ctx.pub_len +4 ,GFP_KERNEL ); + blob =kmalloc (ctx.priv_len + ctx.pub_len,GFP_KERNEL );if (!blob)return -ENOMEM ;
tools/dma/Makefile +2 -2
@@ -38,8 +38,8 @@ prepare: $(OUTPUT)include/linux/map_benchmark.h FORCE: DMA_MAP_BENCHMARK = dma_map_benchmark -$(DMA_MAP_BENCHMARK): prepare FORCE - $(CC) $(CFLAGS) $(DMA_MAP_BENCHMARK).c -o $(DMA_MAP_BENCHMARK) +$(OUTPUT)$(DMA_MAP_BENCHMARK): prepare FORCE + $(CC) $(CFLAGS) $(DMA_MAP_BENCHMARK).c -o $@ clean: rm -f $(ALL_PROGRAMS)
tools/testing/selftests/ftrace/test.d/filter/event-filter-incomplete.tc new file +24 -0
@@ -0,0 +1,24 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: event filter - reject incomplete logical expressions +# requires: events/sched/sched_switch/filter +# flags: instance + +filter=events/sched/sched_switch/filter + +for base in \ + 'common_pid == 1' \ + 'common_pid == 1 || common_pid == 2' \ + 'common_pid == 1 && common_pid == 2' \ + '!(common_pid == 1 || common_pid == 2)' +do + printf '%s' "$base" > "$filter" + for tail in '&&' '||' '&& !' '|| !' '&& !! ' '|| !! '; do + if printf '%s' "$base $tail" > "$filter" 2>/dev/null; then + echo "Accepted incomplete filter: $base $tail" + exit_fail + fi + done +done + +echo 0 > "$filter"