Christian Brauner (Amutable)exec_state: relocate dumpable information6b1c66c5 months agoHistory
1738 lines · 47.6 KB · C
RawDownload
	set_current_state(TASK_INTERRUPTIBLE);	/* mb paired w/ kthread_stop */ 	if (kthread_should_stop()) {		__set_current_state(TASK_RUNNING);		raw_spin_lock_irq(&worker->lock);		worker->task = NULL;		raw_spin_unlock_irq(&worker->lock);		return 0;	} 	work = NULL;	raw_spin_lock_irq(&worker->lock);	if (!list_empty(&worker->work_list)) {		work = list_first_entry(&worker->work_list,					struct kthread_work, node);		list_del_init(&work->node);	}	worker->current_work = work;	raw_spin_unlock_irq(&worker->lock); 	if (work) {		kthread_work_func_t func = work->func;		__set_current_state(TASK_RUNNING);		trace_sched_kthread_work_execute_start(work);		work->func(work);		/*		 * Avoid dereferencing work after this point.  The trace		 * event only cares about the address.		 */		trace_sched_kthread_work_execute_end(work, func);	} else if (!freezing(current)) {		schedule();	} else {		/*		 * Handle the case where the current remains		 * TASK_INTERRUPTIBLE. try_to_freeze() expects		 * the current to be TASK_RUNNING.		 */		__set_current_state(TASK_RUNNING);	} 	try_to_freeze();	cond_resched();	goto repeat;}EXPORT_SYMBOL_GPL(kthread_worker_fn); static __printf(3, 0) struct kthread_worker *__kthread_create_worker_on_node(unsigned int flags, int node,				const char namefmt[], va_list args){	struct kthread_worker *worker;	struct task_struct *task; 	worker = kzalloc_obj(*worker);	if (!worker)		return ERR_PTR(-ENOMEM); 	kthread_init_worker(worker); 	task = __kthread_create_on_node(kthread_worker_fn, worker,					node, namefmt, args);	if (IS_ERR(task))		goto fail_task; 	worker->flags = flags;	worker->task = task; 	return worker; fail_task:	kfree(worker);	return ERR_CAST(task);} /** * kthread_create_worker_on_node - create a kthread worker * @flags: flags modifying the default behavior of the worker * @node: task structure for the thread is allocated on this node * @namefmt: printf-style name for the kthread worker (task). * * Returns a pointer to the allocated worker on success, ERR_PTR(-ENOMEM) * when the needed structures could not get allocated, and ERR_PTR(-EINTR) * when the caller was killed by a fatal signal. */struct kthread_worker *kthread_create_worker_on_node(unsigned int flags, int node, const char namefmt[], ...){	struct kthread_worker *worker;	va_list args; 	va_start(args, namefmt);	worker = __kthread_create_worker_on_node(flags, node, namefmt, args);	va_end(args); 	return worker;}EXPORT_SYMBOL(kthread_create_worker_on_node); /** * kthread_create_worker_on_cpu - create a kthread worker and bind it *	to a given CPU and the associated NUMA node. * @cpu: CPU number * @flags: flags modifying the default behavior of the worker * @namefmt: printf-style name for the thread. Format is restricted *	     to "name.*%u". Code fills in cpu number. * * Use a valid CPU number if you want to bind the kthread worker * to the given CPU and the associated NUMA node. * * A good practice is to add the cpu number also into the worker name. * For example, use kthread_create_worker_on_cpu(cpu, "helper/%d", cpu). * * CPU hotplug: * The kthread worker API is simple and generic. It just provides a way * to create, use, and destroy workers. * * It is up to the API user how to handle CPU hotplug. They have to decide * how to handle pending work items, prevent queuing new ones, and * restore the functionality when the CPU goes off and on. There are a * few catches: * *    - CPU affinity gets lost when it is scheduled on an offline CPU. * *    - The worker might not exist when the CPU was off when the user *      created the workers. * * Good practice is to implement two CPU hotplug callbacks and to * destroy/create the worker when the CPU goes down/up. * * Return: * The pointer to the allocated worker on success, ERR_PTR(-ENOMEM) * when the needed structures could not get allocated, and ERR_PTR(-EINTR) * when the caller was killed by a fatal signal. */struct kthread_worker *kthread_create_worker_on_cpu(int cpu, unsigned int flags,			     const char namefmt[]){	struct kthread_worker *worker; 	worker = kthread_create_worker_on_node(flags, cpu_to_node(cpu), namefmt, cpu);	if (!IS_ERR(worker))		kthread_bind(worker->task, cpu); 	return worker;}EXPORT_SYMBOL(kthread_create_worker_on_cpu); /* * Returns true when the work could not be queued at the moment. * It happens when it is already pending in a worker list * or when it is being cancelled. */static inline bool queuing_blocked(struct kthread_worker *worker,				   struct kthread_work *work){	lockdep_assert_held(&worker->lock); 	return !list_empty(&work->node) || work->canceling;} static void kthread_insert_work_sanity_check(struct kthread_worker *worker,					     struct kthread_work *work){	lockdep_assert_held(&worker->lock);	WARN_ON_ONCE(!list_empty(&work->node));	/* Do not use a work with >1 worker, see kthread_queue_work() */	WARN_ON_ONCE(work->worker && work->worker != worker);} /* insert @work before @pos in @worker */static void kthread_insert_work(struct kthread_worker *worker,				struct kthread_work *work,				struct list_head *pos){	kthread_insert_work_sanity_check(worker, work); 	trace_sched_kthread_work_queue_work(worker, work); 	list_add_tail(&work->node, pos);	work->worker = worker;	if (!worker->current_work && likely(worker->task))		wake_up_process(worker->task);} /** * kthread_queue_work - queue a kthread_work * @worker: target kthread_worker * @work: kthread_work to queue * * Queue @work to work processor @task for async execution.  @task * must have been created with kthread_create_worker().  Returns %true * if @work was successfully queued, %false if it was already pending. * * Reinitialize the work if it needs to be used by another worker. * For example, when the worker was stopped and started again. */bool kthread_queue_work(struct kthread_worker *worker,			struct kthread_work *work){	bool ret = false;	unsigned long flags; 	raw_spin_lock_irqsave(&worker->lock, flags);	if (!queuing_blocked(worker, work)) {		kthread_insert_work(worker, work, &worker->work_list);		ret = true;	}	raw_spin_unlock_irqrestore(&worker->lock, flags);	return ret;}EXPORT_SYMBOL_GPL(kthread_queue_work); /** * kthread_delayed_work_timer_fn - callback that queues the associated kthread *	delayed work when the timer expires. * @t: pointer to the expired timer * * The format of the function is defined by struct timer_list. * It should have been called from irqsafe timer with irq already off. */void kthread_delayed_work_timer_fn(struct timer_list *t){	struct kthread_delayed_work *dwork = timer_container_of(dwork, t,								timer);	struct kthread_work *work = &dwork->work;	struct kthread_worker *worker = work->worker;	unsigned long flags; 	/*	 * This might happen when a pending work is reinitialized.	 * It means that it is used a wrong way.	 */	if (WARN_ON_ONCE(!worker))		return; 	raw_spin_lock_irqsave(&worker->lock, flags);	/* Work must not be used with >1 worker, see kthread_queue_work(). */	WARN_ON_ONCE(work->worker != worker); 	/* Move the work from worker->delayed_work_list. */	WARN_ON_ONCE(list_empty(&work->node));	list_del_init(&work->node);	if (!work->canceling)		kthread_insert_work(worker, work, &worker->work_list); 	raw_spin_unlock_irqrestore(&worker->lock, flags);}EXPORT_SYMBOL(kthread_delayed_work_timer_fn); static void __kthread_queue_delayed_work(struct kthread_worker *worker,					 struct kthread_delayed_work *dwork,					 unsigned long delay){	struct timer_list *timer = &dwork->timer;	struct kthread_work *work = &dwork->work; 	WARN_ON_ONCE(timer->function != kthread_delayed_work_timer_fn); 	/*	 * If @delay is 0, queue @dwork->work immediately.  This is for	 * both optimization and correctness.  The earliest @timer can	 * expire is on the closest next tick and delayed_work users depend	 * on that there's no such delay when @delay is 0.	 */	if (!delay) {		kthread_insert_work(worker, work, &worker->work_list);		return;	} 	/* Be paranoid and try to detect possible races already now. */	kthread_insert_work_sanity_check(worker, work); 	list_add(&work->node, &worker->delayed_work_list);	work->worker = worker;	timer->expires = jiffies + delay;	add_timer(timer);} /** * kthread_queue_delayed_work - queue the associated kthread work *	after a delay. * @worker: target kthread_worker * @dwork: kthread_delayed_work to queue * @delay: number of jiffies to wait before queuing * * If the work has not been pending it starts a timer that will queue * the work after the given @delay. If @delay is zero, it queues the * work immediately. * * Return: %false if the @work has already been pending. It means that * either the timer was running or the work was queued. It returns %true * otherwise. */bool kthread_queue_delayed_work(struct kthread_worker *worker,				struct kthread_delayed_work *dwork,				unsigned long delay){	struct kthread_work *work = &dwork->work;	unsigned long flags;	bool ret = false; 	raw_spin_lock_irqsave(&worker->lock, flags); 	if (!queuing_blocked(worker, work)) {		__kthread_queue_delayed_work(worker, dwork, delay);		ret = true;	} 	raw_spin_unlock_irqrestore(&worker->lock, flags);	return ret;}EXPORT_SYMBOL_GPL(kthread_queue_delayed_work); struct kthread_flush_work {	struct kthread_work	work;	struct completion	done;}; static void kthread_flush_work_fn(struct kthread_work *work){	struct kthread_flush_work *fwork =		container_of(work, struct kthread_flush_work, work);	complete(&fwork->done);} /** * kthread_flush_work - flush a kthread_work * @work: work to flush * * If @work is queued or executing, wait for it to finish execution. */void kthread_flush_work(struct kthread_work *work){	struct kthread_flush_work fwork = {		KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn),		COMPLETION_INITIALIZER_ONSTACK(fwork.done),	};	struct kthread_worker *worker;	bool noop = false; 	worker = work->worker;	if (!worker)		return; 	raw_spin_lock_irq(&worker->lock);	/* Work must not be used with >1 worker, see kthread_queue_work(). */	WARN_ON_ONCE(work->worker != worker); 	if (!list_empty(&work->node))		kthread_insert_work(worker, &fwork.work, work->node.next);	else if (worker->current_work == work)		kthread_insert_work(worker, &fwork.work,				    worker->work_list.next);	else		noop = true; 	raw_spin_unlock_irq(&worker->lock); 	if (!noop)		wait_for_completion(&fwork.done);}EXPORT_SYMBOL_GPL(kthread_flush_work); /* * Make sure that the timer is neither set nor running and could * not manipulate the work list_head any longer. * * The function is called under worker->lock. The lock is temporary * released but the timer can't be set again in the meantime. */static void kthread_cancel_delayed_work_timer(struct kthread_work *work,					      unsigned long *flags){	struct kthread_delayed_work *dwork =		container_of(work, struct kthread_delayed_work, work);	struct kthread_worker *worker = work->worker; 	/*	 * timer_delete_sync() must be called to make sure that the timer	 * callback is not running. The lock must be temporary released	 * to avoid a deadlock with the callback. In the meantime,	 * any queuing is blocked by setting the canceling counter.	 */	work->canceling++;	raw_spin_unlock_irqrestore(&worker->lock, *flags);	timer_delete_sync(&dwork->timer);	raw_spin_lock_irqsave(&worker->lock, *flags);	work->canceling--;} /* * This function removes the work from the worker queue. * * It is called under worker->lock. The caller must make sure that * the timer used by delayed work is not running, e.g. by calling * kthread_cancel_delayed_work_timer(). * * The work might still be in use when this function finishes. See the * current_work proceed by the worker. * * Return: %true if @work was pending and successfully canceled, *	%false if @work was not pending */static bool __kthread_cancel_work(struct kthread_work *work){	/*	 * Try to remove the work from a worker list. It might either	 * be from worker->work_list or from worker->delayed_work_list.	 */	if (!list_empty(&work->node)) {		list_del_init(&work->node);		return true;	} 	return false;} /** * kthread_mod_delayed_work - modify delay of or queue a kthread delayed work * @worker: kthread worker to use * @dwork: kthread delayed work to queue * @delay: number of jiffies to wait before queuing * * If @dwork is idle, equivalent to kthread_queue_delayed_work(). Otherwise, * modify @dwork's timer so that it expires after @delay. If @delay is zero, * @work is guaranteed to be queued immediately. * * Return: %false if @dwork was idle and queued, %true otherwise. * * A special case is when the work is being canceled in parallel. * It might be caused either by the real kthread_cancel_delayed_work_sync() * or yet another kthread_mod_delayed_work() call. We let the other command * win and return %true here. The return value can be used for reference * counting and the number of queued works stays the same. Anyway, the caller * is supposed to synchronize these operations a reasonable way. * * This function is safe to call from any context including IRQ handler. * See __kthread_cancel_work() and kthread_delayed_work_timer_fn() * for details. */bool kthread_mod_delayed_work(struct kthread_worker *worker,			      struct kthread_delayed_work *dwork,			      unsigned long delay){	struct kthread_work *work = &dwork->work;	unsigned long flags;	int ret; 	raw_spin_lock_irqsave(&worker->lock, flags); 	/* Do not bother with canceling when never queued. */	if (!work->worker) {		ret = false;		goto fast_queue;	} 	/* Work must not be used with >1 worker, see kthread_queue_work() */	WARN_ON_ONCE(work->worker != worker); 	/*	 * Temporary cancel the work but do not fight with another command	 * that is canceling the work as well.	 *	 * It is a bit tricky because of possible races with another	 * mod_delayed_work() and cancel_delayed_work() callers.	 *	 * The timer must be canceled first because worker->lock is released	 * when doing so. But the work can be removed from the queue (list)	 * only when it can be queued again so that the return value can	 * be used for reference counting.	 */	kthread_cancel_delayed_work_timer(work, &flags);	if (work->canceling) {		/* The number of works in the queue does not change. */		ret = true;		goto out;	}	ret = __kthread_cancel_work(work); fast_queue:	__kthread_queue_delayed_work(worker, dwork, delay);out:	raw_spin_unlock_irqrestore(&worker->lock, flags);	return ret;}EXPORT_SYMBOL_GPL(kthread_mod_delayed_work); static bool __kthread_cancel_work_sync(struct kthread_work *work, bool is_dwork){	struct kthread_worker *worker = work->worker;	unsigned long flags;	int ret = false; 	if (!worker)		goto out; 	raw_spin_lock_irqsave(&worker->lock, flags);	/* Work must not be used with >1 worker, see kthread_queue_work(). */

Lines 1001–1500 of 1738. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t