mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	task_work: add helper for more targeted task_work canceling
The only exported helper we have right now is task_work_cancel(), which cancels any task_work from a given task where func matches the queued work item. This is a bit too coarse for some use cases. Add a task_work_cancel_match() that allows to more specifically target individual work items outside of purely the callback function used. task_work_cancel() can be trivially implemented on top of that, hence do so. Reviewed-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									b2e720ace2
								
							
						
					
					
						commit
						c7aab1a7c5
					
				
					 2 changed files with 30 additions and 7 deletions
				
			
		|  | @ -22,6 +22,8 @@ enum task_work_notify_mode { | |||
| int task_work_add(struct task_struct *task, struct callback_head *twork, | ||||
| 			enum task_work_notify_mode mode); | ||||
| 
 | ||||
| struct callback_head *task_work_cancel_match(struct task_struct *task, | ||||
| 	bool (*match)(struct callback_head *, void *data), void *data); | ||||
| struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t); | ||||
| void task_work_run(void); | ||||
| 
 | ||||
|  |  | |||
|  | @ -59,18 +59,17 @@ int task_work_add(struct task_struct *task, struct callback_head *work, | |||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * task_work_cancel - cancel a pending work added by task_work_add() | ||||
|  * task_work_cancel_match - cancel a pending work added by task_work_add() | ||||
|  * @task: the task which should execute the work | ||||
|  * @func: identifies the work to remove | ||||
|  * | ||||
|  * Find the last queued pending work with ->func == @func and remove | ||||
|  * it from queue. | ||||
|  * @match: match function to call | ||||
|  * | ||||
|  * RETURNS: | ||||
|  * The found work or NULL if not found. | ||||
|  */ | ||||
| struct callback_head * | ||||
| task_work_cancel(struct task_struct *task, task_work_func_t func) | ||||
| task_work_cancel_match(struct task_struct *task, | ||||
| 		       bool (*match)(struct callback_head *, void *data), | ||||
| 		       void *data) | ||||
| { | ||||
| 	struct callback_head **pprev = &task->task_works; | ||||
| 	struct callback_head *work; | ||||
|  | @ -86,7 +85,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) | |||
| 	 */ | ||||
| 	raw_spin_lock_irqsave(&task->pi_lock, flags); | ||||
| 	while ((work = READ_ONCE(*pprev))) { | ||||
| 		if (work->func != func) | ||||
| 		if (!match(work, data)) | ||||
| 			pprev = &work->next; | ||||
| 		else if (cmpxchg(pprev, work, work->next) == work) | ||||
| 			break; | ||||
|  | @ -96,6 +95,28 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) | |||
| 	return work; | ||||
| } | ||||
| 
 | ||||
| static bool task_work_func_match(struct callback_head *cb, void *data) | ||||
| { | ||||
| 	return cb->func == data; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * task_work_cancel - cancel a pending work added by task_work_add() | ||||
|  * @task: the task which should execute the work | ||||
|  * @func: identifies the work to remove | ||||
|  * | ||||
|  * Find the last queued pending work with ->func == @func and remove | ||||
|  * it from queue. | ||||
|  * | ||||
|  * RETURNS: | ||||
|  * The found work or NULL if not found. | ||||
|  */ | ||||
| struct callback_head * | ||||
| task_work_cancel(struct task_struct *task, task_work_func_t func) | ||||
| { | ||||
| 	return task_work_cancel_match(task, task_work_func_match, func); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * task_work_run - execute the works added by task_work_add() | ||||
|  * | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Jens Axboe
						Jens Axboe