Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'wq-for-6.13-rc5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq

Pull workqueue fixes from Tejun Heo:

- Suppress a corner case spurious flush dependency warning

- Two trivial changes

* tag 'wq-for-6.13-rc5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
workqueue: add printf attribute to __alloc_workqueue()
workqueue: Do not warn when cancelling WQ_MEM_RECLAIM work from !WQ_MEM_RECLAIM worker
rust: add safety comment in workqueue traits

+30 -11
+14 -9
kernel/workqueue.c
··· 3680 3680 * check_flush_dependency - check for flush dependency sanity 3681 3681 * @target_wq: workqueue being flushed 3682 3682 * @target_work: work item being flushed (NULL for workqueue flushes) 3683 + * @from_cancel: are we called from the work cancel path 3683 3684 * 3684 3685 * %current is trying to flush the whole @target_wq or @target_work on it. 3685 - * If @target_wq doesn't have %WQ_MEM_RECLAIM, verify that %current is not 3686 - * reclaiming memory or running on a workqueue which doesn't have 3687 - * %WQ_MEM_RECLAIM as that can break forward-progress guarantee leading to 3688 - * a deadlock. 3686 + * If this is not the cancel path (which implies work being flushed is either 3687 + * already running, or will not be at all), check if @target_wq doesn't have 3688 + * %WQ_MEM_RECLAIM and verify that %current is not reclaiming memory or running 3689 + * on a workqueue which doesn't have %WQ_MEM_RECLAIM as that can break forward- 3690 + * progress guarantee leading to a deadlock. 3689 3691 */ 3690 3692 static void check_flush_dependency(struct workqueue_struct *target_wq, 3691 - struct work_struct *target_work) 3693 + struct work_struct *target_work, 3694 + bool from_cancel) 3692 3695 { 3693 - work_func_t target_func = target_work ? target_work->func : NULL; 3696 + work_func_t target_func; 3694 3697 struct worker *worker; 3695 3698 3696 - if (target_wq->flags & WQ_MEM_RECLAIM) 3699 + if (from_cancel || target_wq->flags & WQ_MEM_RECLAIM) 3697 3700 return; 3698 3701 3699 3702 worker = current_wq_worker(); 3703 + target_func = target_work ? target_work->func : NULL; 3700 3704 3701 3705 WARN_ONCE(current->flags & PF_MEMALLOC, 3702 3706 "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%ps", ··· 3984 3980 list_add_tail(&this_flusher.list, &wq->flusher_overflow); 3985 3981 } 3986 3982 3987 - check_flush_dependency(wq, NULL); 3983 + check_flush_dependency(wq, NULL, false); 3988 3984 3989 3985 mutex_unlock(&wq->mutex); 3990 3986 ··· 4159 4155 } 4160 4156 4161 4157 wq = pwq->wq; 4162 - check_flush_dependency(wq, work); 4158 + check_flush_dependency(wq, work, from_cancel); 4163 4159 4164 4160 insert_wq_barrier(pwq, barr, work, worker); 4165 4161 raw_spin_unlock_irq(&pool->lock); ··· 5645 5641 } while (activated); 5646 5642 } 5647 5643 5644 + __printf(1, 0) 5648 5645 static struct workqueue_struct *__alloc_workqueue(const char *fmt, 5649 5646 unsigned int flags, 5650 5647 int max_active, va_list args)
+16 -2
rust/kernel/workqueue.rs
··· 519 519 impl{T} HasWork<Self> for ClosureWork<T> { self.work } 520 520 } 521 521 522 - // SAFETY: TODO. 522 + // SAFETY: The `__enqueue` implementation in RawWorkItem uses a `work_struct` initialized with the 523 + // `run` method of this trait as the function pointer because: 524 + // - `__enqueue` gets the `work_struct` from the `Work` field, using `T::raw_get_work`. 525 + // - The only safe way to create a `Work` object is through `Work::new`. 526 + // - `Work::new` makes sure that `T::Pointer::run` is passed to `init_work_with_key`. 527 + // - Finally `Work` and `RawWorkItem` guarantee that the correct `Work` field 528 + // will be used because of the ID const generic bound. This makes sure that `T::raw_get_work` 529 + // uses the correct offset for the `Work` field, and `Work::new` picks the correct 530 + // implementation of `WorkItemPointer` for `Arc<T>`. 523 531 unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T> 524 532 where 525 533 T: WorkItem<ID, Pointer = Self>, ··· 545 537 } 546 538 } 547 539 548 - // SAFETY: TODO. 540 + // SAFETY: The `work_struct` raw pointer is guaranteed to be valid for the duration of the call to 541 + // the closure because we get it from an `Arc`, which means that the ref count will be at least 1, 542 + // and we don't drop the `Arc` ourselves. If `queue_work_on` returns true, it is further guaranteed 543 + // to be valid until a call to the function pointer in `work_struct` because we leak the memory it 544 + // points to, and only reclaim it if the closure returns false, or in `WorkItemPointer::run`, which 545 + // is what the function pointer in the `work_struct` must be pointing to, according to the safety 546 + // requirements of `WorkItemPointer`. 549 547 unsafe impl<T, const ID: u64> RawWorkItem<ID> for Arc<T> 550 548 where 551 549 T: WorkItem<ID, Pointer = Self>,