162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/net/sunrpc/sched.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Scheduling for synchronous and asynchronous RPC requests. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1996 Olaf Kirch, <okir@monad.swb.de> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * TCP NFS related read + write fixes 1062306a36Sopenharmony_ci * (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/sched.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/mempool.h> 1962306a36Sopenharmony_ci#include <linux/smp.h> 2062306a36Sopenharmony_ci#include <linux/spinlock.h> 2162306a36Sopenharmony_ci#include <linux/mutex.h> 2262306a36Sopenharmony_ci#include <linux/freezer.h> 2362306a36Sopenharmony_ci#include <linux/sched/mm.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 2662306a36Sopenharmony_ci#include <linux/sunrpc/metrics.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "sunrpc.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 3162306a36Sopenharmony_ci#include <trace/events/sunrpc.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * RPC slabs and memory pools 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci#define RPC_BUFFER_MAXSIZE (2048) 3762306a36Sopenharmony_ci#define RPC_BUFFER_POOLSIZE (8) 3862306a36Sopenharmony_ci#define RPC_TASK_POOLSIZE (8) 3962306a36Sopenharmony_cistatic struct kmem_cache *rpc_task_slabp __read_mostly; 4062306a36Sopenharmony_cistatic struct kmem_cache *rpc_buffer_slabp __read_mostly; 4162306a36Sopenharmony_cistatic mempool_t *rpc_task_mempool __read_mostly; 4262306a36Sopenharmony_cistatic mempool_t *rpc_buffer_mempool __read_mostly; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void rpc_async_schedule(struct work_struct *); 4562306a36Sopenharmony_cistatic void rpc_release_task(struct rpc_task *task); 4662306a36Sopenharmony_cistatic void __rpc_queue_timer_fn(struct work_struct *); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * RPC tasks sit here while waiting for conditions to improve. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic struct rpc_wait_queue delay_queue; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * rpciod-related stuff 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistruct workqueue_struct *rpciod_workqueue __read_mostly; 5762306a36Sopenharmony_cistruct workqueue_struct *xprtiod_workqueue __read_mostly; 5862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xprtiod_workqueue); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cigfp_t rpc_task_gfp_mask(void) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci if (current->flags & PF_WQ_WORKER) 6362306a36Sopenharmony_ci return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN; 6462306a36Sopenharmony_ci return GFP_KERNEL; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_task_gfp_mask); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cibool rpc_task_set_rpc_status(struct rpc_task *task, int rpc_status) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci if (cmpxchg(&task->tk_rpc_status, 0, rpc_status) == 0) 7162306a36Sopenharmony_ci return true; 7262306a36Sopenharmony_ci return false; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciunsigned long 7662306a36Sopenharmony_cirpc_task_timeout(const struct rpc_task *task) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned long timeout = READ_ONCE(task->tk_timeout); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (timeout != 0) { 8162306a36Sopenharmony_ci unsigned long now = jiffies; 8262306a36Sopenharmony_ci if (time_before(now, timeout)) 8362306a36Sopenharmony_ci return timeout - now; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_task_timeout); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * Disable the timer for a given RPC task. Should be called with 9162306a36Sopenharmony_ci * queue->lock and bh_disabled in order to avoid races within 9262306a36Sopenharmony_ci * rpc_run_timer(). 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistatic void 9562306a36Sopenharmony_ci__rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci if (list_empty(&task->u.tk_wait.timer_list)) 9862306a36Sopenharmony_ci return; 9962306a36Sopenharmony_ci task->tk_timeout = 0; 10062306a36Sopenharmony_ci list_del(&task->u.tk_wait.timer_list); 10162306a36Sopenharmony_ci if (list_empty(&queue->timer_list.list)) 10262306a36Sopenharmony_ci cancel_delayed_work(&queue->timer_list.dwork); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void 10662306a36Sopenharmony_cirpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci unsigned long now = jiffies; 10962306a36Sopenharmony_ci queue->timer_list.expires = expires; 11062306a36Sopenharmony_ci if (time_before_eq(expires, now)) 11162306a36Sopenharmony_ci expires = 0; 11262306a36Sopenharmony_ci else 11362306a36Sopenharmony_ci expires -= now; 11462306a36Sopenharmony_ci mod_delayed_work(rpciod_workqueue, &queue->timer_list.dwork, expires); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * Set up a timer for the current task. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_cistatic void 12162306a36Sopenharmony_ci__rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task, 12262306a36Sopenharmony_ci unsigned long timeout) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci task->tk_timeout = timeout; 12562306a36Sopenharmony_ci if (list_empty(&queue->timer_list.list) || time_before(timeout, queue->timer_list.expires)) 12662306a36Sopenharmony_ci rpc_set_queue_timer(queue, timeout); 12762306a36Sopenharmony_ci list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci if (queue->priority != priority) { 13362306a36Sopenharmony_ci queue->priority = priority; 13462306a36Sopenharmony_ci queue->nr = 1U << priority; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci rpc_set_waitqueue_priority(queue, queue->maxpriority); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Add a request to a queue list 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic void 14762306a36Sopenharmony_ci__rpc_list_enqueue_task(struct list_head *q, struct rpc_task *task) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct rpc_task *t; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci list_for_each_entry(t, q, u.tk_wait.list) { 15262306a36Sopenharmony_ci if (t->tk_owner == task->tk_owner) { 15362306a36Sopenharmony_ci list_add_tail(&task->u.tk_wait.links, 15462306a36Sopenharmony_ci &t->u.tk_wait.links); 15562306a36Sopenharmony_ci /* Cache the queue head in task->u.tk_wait.list */ 15662306a36Sopenharmony_ci task->u.tk_wait.list.next = q; 15762306a36Sopenharmony_ci task->u.tk_wait.list.prev = NULL; 15862306a36Sopenharmony_ci return; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci INIT_LIST_HEAD(&task->u.tk_wait.links); 16262306a36Sopenharmony_ci list_add_tail(&task->u.tk_wait.list, q); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * Remove request from a queue list 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_cistatic void 16962306a36Sopenharmony_ci__rpc_list_dequeue_task(struct rpc_task *task) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct list_head *q; 17262306a36Sopenharmony_ci struct rpc_task *t; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (task->u.tk_wait.list.prev == NULL) { 17562306a36Sopenharmony_ci list_del(&task->u.tk_wait.links); 17662306a36Sopenharmony_ci return; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci if (!list_empty(&task->u.tk_wait.links)) { 17962306a36Sopenharmony_ci t = list_first_entry(&task->u.tk_wait.links, 18062306a36Sopenharmony_ci struct rpc_task, 18162306a36Sopenharmony_ci u.tk_wait.links); 18262306a36Sopenharmony_ci /* Assume __rpc_list_enqueue_task() cached the queue head */ 18362306a36Sopenharmony_ci q = t->u.tk_wait.list.next; 18462306a36Sopenharmony_ci list_add_tail(&t->u.tk_wait.list, q); 18562306a36Sopenharmony_ci list_del(&task->u.tk_wait.links); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci list_del(&task->u.tk_wait.list); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * Add new request to a priority queue. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_cistatic void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, 19462306a36Sopenharmony_ci struct rpc_task *task, 19562306a36Sopenharmony_ci unsigned char queue_priority) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci if (unlikely(queue_priority > queue->maxpriority)) 19862306a36Sopenharmony_ci queue_priority = queue->maxpriority; 19962306a36Sopenharmony_ci __rpc_list_enqueue_task(&queue->tasks[queue_priority], task); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* 20362306a36Sopenharmony_ci * Add new request to wait queue. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_cistatic void __rpc_add_wait_queue(struct rpc_wait_queue *queue, 20662306a36Sopenharmony_ci struct rpc_task *task, 20762306a36Sopenharmony_ci unsigned char queue_priority) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci INIT_LIST_HEAD(&task->u.tk_wait.timer_list); 21062306a36Sopenharmony_ci if (RPC_IS_PRIORITY(queue)) 21162306a36Sopenharmony_ci __rpc_add_wait_queue_priority(queue, task, queue_priority); 21262306a36Sopenharmony_ci else 21362306a36Sopenharmony_ci list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); 21462306a36Sopenharmony_ci task->tk_waitqueue = queue; 21562306a36Sopenharmony_ci queue->qlen++; 21662306a36Sopenharmony_ci /* barrier matches the read in rpc_wake_up_task_queue_locked() */ 21762306a36Sopenharmony_ci smp_wmb(); 21862306a36Sopenharmony_ci rpc_set_queued(task); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * Remove request from a priority queue. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic void __rpc_remove_wait_queue_priority(struct rpc_task *task) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci __rpc_list_dequeue_task(task); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/* 23062306a36Sopenharmony_ci * Remove request from queue. 23162306a36Sopenharmony_ci * Note: must be called with spin lock held. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci __rpc_disable_timer(queue, task); 23662306a36Sopenharmony_ci if (RPC_IS_PRIORITY(queue)) 23762306a36Sopenharmony_ci __rpc_remove_wait_queue_priority(task); 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci list_del(&task->u.tk_wait.list); 24062306a36Sopenharmony_ci queue->qlen--; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int i; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci spin_lock_init(&queue->lock); 24862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(queue->tasks); i++) 24962306a36Sopenharmony_ci INIT_LIST_HEAD(&queue->tasks[i]); 25062306a36Sopenharmony_ci queue->maxpriority = nr_queues - 1; 25162306a36Sopenharmony_ci rpc_reset_waitqueue_priority(queue); 25262306a36Sopenharmony_ci queue->qlen = 0; 25362306a36Sopenharmony_ci queue->timer_list.expires = 0; 25462306a36Sopenharmony_ci INIT_DELAYED_WORK(&queue->timer_list.dwork, __rpc_queue_timer_fn); 25562306a36Sopenharmony_ci INIT_LIST_HEAD(&queue->timer_list.list); 25662306a36Sopenharmony_ci rpc_assign_waitqueue_name(queue, qname); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci __rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_civoid rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci __rpc_init_priority_wait_queue(queue, qname, 1); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_wait_queue); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_civoid rpc_destroy_wait_queue(struct rpc_wait_queue *queue) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci cancel_delayed_work_sync(&queue->timer_list.dwork); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int rpc_wait_bit_killable(struct wait_bit_key *key, int mode) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci schedule(); 28062306a36Sopenharmony_ci if (signal_pending_state(mode, current)) 28162306a36Sopenharmony_ci return -ERESTARTSYS; 28262306a36Sopenharmony_ci return 0; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) 28662306a36Sopenharmony_cistatic void rpc_task_set_debuginfo(struct rpc_task *task) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct rpc_clnt *clnt = task->tk_client; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Might be a task carrying a reverse-direction operation */ 29162306a36Sopenharmony_ci if (!clnt) { 29262306a36Sopenharmony_ci static atomic_t rpc_pid; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci task->tk_pid = atomic_inc_return(&rpc_pid); 29562306a36Sopenharmony_ci return; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci task->tk_pid = atomic_inc_return(&clnt->cl_pid); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci#else 30162306a36Sopenharmony_cistatic inline void rpc_task_set_debuginfo(struct rpc_task *task) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci#endif 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void rpc_set_active(struct rpc_task *task) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci rpc_task_set_debuginfo(task); 30962306a36Sopenharmony_ci set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); 31062306a36Sopenharmony_ci trace_rpc_task_begin(task, NULL); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/* 31462306a36Sopenharmony_ci * Mark an RPC call as having completed by clearing the 'active' bit 31562306a36Sopenharmony_ci * and then waking up all tasks that were sleeping. 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_cistatic int rpc_complete_task(struct rpc_task *task) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci void *m = &task->tk_runstate; 32062306a36Sopenharmony_ci wait_queue_head_t *wq = bit_waitqueue(m, RPC_TASK_ACTIVE); 32162306a36Sopenharmony_ci struct wait_bit_key k = __WAIT_BIT_KEY_INITIALIZER(m, RPC_TASK_ACTIVE); 32262306a36Sopenharmony_ci unsigned long flags; 32362306a36Sopenharmony_ci int ret; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci trace_rpc_task_complete(task, NULL); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci spin_lock_irqsave(&wq->lock, flags); 32862306a36Sopenharmony_ci clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); 32962306a36Sopenharmony_ci ret = atomic_dec_and_test(&task->tk_count); 33062306a36Sopenharmony_ci if (waitqueue_active(wq)) 33162306a36Sopenharmony_ci __wake_up_locked_key(wq, TASK_NORMAL, &k); 33262306a36Sopenharmony_ci spin_unlock_irqrestore(&wq->lock, flags); 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/* 33762306a36Sopenharmony_ci * Allow callers to wait for completion of an RPC call 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Note the use of out_of_line_wait_on_bit() rather than wait_on_bit() 34062306a36Sopenharmony_ci * to enforce taking of the wq->lock and hence avoid races with 34162306a36Sopenharmony_ci * rpc_complete_task(). 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ciint rpc_wait_for_completion_task(struct rpc_task *task) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci return out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE, 34662306a36Sopenharmony_ci rpc_wait_bit_killable, TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wait_for_completion_task); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * Make an RPC task runnable. 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * Note: If the task is ASYNC, and is being made runnable after sitting on an 35462306a36Sopenharmony_ci * rpc_wait_queue, this must be called with the queue spinlock held to protect 35562306a36Sopenharmony_ci * the wait queue operation. 35662306a36Sopenharmony_ci * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(), 35762306a36Sopenharmony_ci * which is needed to ensure that __rpc_execute() doesn't loop (due to the 35862306a36Sopenharmony_ci * lockless RPC_IS_QUEUED() test) before we've had a chance to test 35962306a36Sopenharmony_ci * the RPC_TASK_RUNNING flag. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_cistatic void rpc_make_runnable(struct workqueue_struct *wq, 36262306a36Sopenharmony_ci struct rpc_task *task) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci bool need_wakeup = !rpc_test_and_set_running(task); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci rpc_clear_queued(task); 36762306a36Sopenharmony_ci if (!need_wakeup) 36862306a36Sopenharmony_ci return; 36962306a36Sopenharmony_ci if (RPC_IS_ASYNC(task)) { 37062306a36Sopenharmony_ci INIT_WORK(&task->u.tk_work, rpc_async_schedule); 37162306a36Sopenharmony_ci queue_work(wq, &task->u.tk_work); 37262306a36Sopenharmony_ci } else 37362306a36Sopenharmony_ci wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* 37762306a36Sopenharmony_ci * Prepare for sleeping on a wait queue. 37862306a36Sopenharmony_ci * By always appending tasks to the list we ensure FIFO behavior. 37962306a36Sopenharmony_ci * NB: An RPC task will only receive interrupt-driven events as long 38062306a36Sopenharmony_ci * as it's on a wait queue. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic void __rpc_do_sleep_on_priority(struct rpc_wait_queue *q, 38362306a36Sopenharmony_ci struct rpc_task *task, 38462306a36Sopenharmony_ci unsigned char queue_priority) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci trace_rpc_task_sleep(task, q); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci __rpc_add_wait_queue(q, task, queue_priority); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void __rpc_sleep_on_priority(struct rpc_wait_queue *q, 39262306a36Sopenharmony_ci struct rpc_task *task, 39362306a36Sopenharmony_ci unsigned char queue_priority) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci if (WARN_ON_ONCE(RPC_IS_QUEUED(task))) 39662306a36Sopenharmony_ci return; 39762306a36Sopenharmony_ci __rpc_do_sleep_on_priority(q, task, queue_priority); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void __rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q, 40162306a36Sopenharmony_ci struct rpc_task *task, unsigned long timeout, 40262306a36Sopenharmony_ci unsigned char queue_priority) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci if (WARN_ON_ONCE(RPC_IS_QUEUED(task))) 40562306a36Sopenharmony_ci return; 40662306a36Sopenharmony_ci if (time_is_after_jiffies(timeout)) { 40762306a36Sopenharmony_ci __rpc_do_sleep_on_priority(q, task, queue_priority); 40862306a36Sopenharmony_ci __rpc_add_timer(q, task, timeout); 40962306a36Sopenharmony_ci } else 41062306a36Sopenharmony_ci task->tk_status = -ETIMEDOUT; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void rpc_set_tk_callback(struct rpc_task *task, rpc_action action) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci if (action && !WARN_ON_ONCE(task->tk_callback != NULL)) 41662306a36Sopenharmony_ci task->tk_callback = action; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic bool rpc_sleep_check_activated(struct rpc_task *task) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci /* We shouldn't ever put an inactive task to sleep */ 42262306a36Sopenharmony_ci if (WARN_ON_ONCE(!RPC_IS_ACTIVATED(task))) { 42362306a36Sopenharmony_ci task->tk_status = -EIO; 42462306a36Sopenharmony_ci rpc_put_task_async(task); 42562306a36Sopenharmony_ci return false; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci return true; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_civoid rpc_sleep_on_timeout(struct rpc_wait_queue *q, struct rpc_task *task, 43162306a36Sopenharmony_ci rpc_action action, unsigned long timeout) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 43462306a36Sopenharmony_ci return; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rpc_set_tk_callback(task, action); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * Protect the queue operations. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci spin_lock(&q->lock); 44262306a36Sopenharmony_ci __rpc_sleep_on_priority_timeout(q, task, timeout, task->tk_priority); 44362306a36Sopenharmony_ci spin_unlock(&q->lock); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on_timeout); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_civoid rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, 44862306a36Sopenharmony_ci rpc_action action) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 45162306a36Sopenharmony_ci return; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci rpc_set_tk_callback(task, action); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci WARN_ON_ONCE(task->tk_timeout != 0); 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * Protect the queue operations. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci spin_lock(&q->lock); 46062306a36Sopenharmony_ci __rpc_sleep_on_priority(q, task, task->tk_priority); 46162306a36Sopenharmony_ci spin_unlock(&q->lock); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_civoid rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q, 46662306a36Sopenharmony_ci struct rpc_task *task, unsigned long timeout, int priority) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 46962306a36Sopenharmony_ci return; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci priority -= RPC_PRIORITY_LOW; 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * Protect the queue operations. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci spin_lock(&q->lock); 47662306a36Sopenharmony_ci __rpc_sleep_on_priority_timeout(q, task, timeout, priority); 47762306a36Sopenharmony_ci spin_unlock(&q->lock); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on_priority_timeout); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_civoid rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, 48262306a36Sopenharmony_ci int priority) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 48562306a36Sopenharmony_ci return; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci WARN_ON_ONCE(task->tk_timeout != 0); 48862306a36Sopenharmony_ci priority -= RPC_PRIORITY_LOW; 48962306a36Sopenharmony_ci /* 49062306a36Sopenharmony_ci * Protect the queue operations. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci spin_lock(&q->lock); 49362306a36Sopenharmony_ci __rpc_sleep_on_priority(q, task, priority); 49462306a36Sopenharmony_ci spin_unlock(&q->lock); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on_priority); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/** 49962306a36Sopenharmony_ci * __rpc_do_wake_up_task_on_wq - wake up a single rpc_task 50062306a36Sopenharmony_ci * @wq: workqueue on which to run task 50162306a36Sopenharmony_ci * @queue: wait queue 50262306a36Sopenharmony_ci * @task: task to be woken up 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * Caller must hold queue->lock, and have cleared the task queued flag. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistatic void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq, 50762306a36Sopenharmony_ci struct rpc_wait_queue *queue, 50862306a36Sopenharmony_ci struct rpc_task *task) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci /* Has the task been executed yet? If not, we cannot wake it up! */ 51162306a36Sopenharmony_ci if (!RPC_IS_ACTIVATED(task)) { 51262306a36Sopenharmony_ci printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task); 51362306a36Sopenharmony_ci return; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci trace_rpc_task_wakeup(task, queue); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci __rpc_remove_wait_queue(queue, task); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci rpc_make_runnable(wq, task); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* 52462306a36Sopenharmony_ci * Wake up a queued task while the queue lock is being held 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_cistatic struct rpc_task * 52762306a36Sopenharmony_cirpc_wake_up_task_on_wq_queue_action_locked(struct workqueue_struct *wq, 52862306a36Sopenharmony_ci struct rpc_wait_queue *queue, struct rpc_task *task, 52962306a36Sopenharmony_ci bool (*action)(struct rpc_task *, void *), void *data) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci if (RPC_IS_QUEUED(task)) { 53262306a36Sopenharmony_ci smp_rmb(); 53362306a36Sopenharmony_ci if (task->tk_waitqueue == queue) { 53462306a36Sopenharmony_ci if (action == NULL || action(task, data)) { 53562306a36Sopenharmony_ci __rpc_do_wake_up_task_on_wq(wq, queue, task); 53662306a36Sopenharmony_ci return task; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci return NULL; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/* 54462306a36Sopenharmony_ci * Wake up a queued task while the queue lock is being held 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_cistatic void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, 54762306a36Sopenharmony_ci struct rpc_task *task) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue, 55062306a36Sopenharmony_ci task, NULL, NULL); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* 55462306a36Sopenharmony_ci * Wake up a task on a specific queue 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_civoid rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci if (!RPC_IS_QUEUED(task)) 55962306a36Sopenharmony_ci return; 56062306a36Sopenharmony_ci spin_lock(&queue->lock); 56162306a36Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 56262306a36Sopenharmony_ci spin_unlock(&queue->lock); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic bool rpc_task_action_set_status(struct rpc_task *task, void *status) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci task->tk_status = *(int *)status; 56962306a36Sopenharmony_ci return true; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic void 57362306a36Sopenharmony_cirpc_wake_up_task_queue_set_status_locked(struct rpc_wait_queue *queue, 57462306a36Sopenharmony_ci struct rpc_task *task, int status) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue, 57762306a36Sopenharmony_ci task, rpc_task_action_set_status, &status); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/** 58162306a36Sopenharmony_ci * rpc_wake_up_queued_task_set_status - wake up a task and set task->tk_status 58262306a36Sopenharmony_ci * @queue: pointer to rpc_wait_queue 58362306a36Sopenharmony_ci * @task: pointer to rpc_task 58462306a36Sopenharmony_ci * @status: integer error value 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * If @task is queued on @queue, then it is woken up, and @task->tk_status is 58762306a36Sopenharmony_ci * set to the value of @status. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_civoid 59062306a36Sopenharmony_cirpc_wake_up_queued_task_set_status(struct rpc_wait_queue *queue, 59162306a36Sopenharmony_ci struct rpc_task *task, int status) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci if (!RPC_IS_QUEUED(task)) 59462306a36Sopenharmony_ci return; 59562306a36Sopenharmony_ci spin_lock(&queue->lock); 59662306a36Sopenharmony_ci rpc_wake_up_task_queue_set_status_locked(queue, task, status); 59762306a36Sopenharmony_ci spin_unlock(&queue->lock); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/* 60162306a36Sopenharmony_ci * Wake up the next task on a priority queue. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_cistatic struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct list_head *q; 60662306a36Sopenharmony_ci struct rpc_task *task; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* 60962306a36Sopenharmony_ci * Service the privileged queue. 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_ci q = &queue->tasks[RPC_NR_PRIORITY - 1]; 61262306a36Sopenharmony_ci if (queue->maxpriority > RPC_PRIORITY_PRIVILEGED && !list_empty(q)) { 61362306a36Sopenharmony_ci task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 61462306a36Sopenharmony_ci goto out; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* 61862306a36Sopenharmony_ci * Service a batch of tasks from a single owner. 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci q = &queue->tasks[queue->priority]; 62162306a36Sopenharmony_ci if (!list_empty(q) && queue->nr) { 62262306a36Sopenharmony_ci queue->nr--; 62362306a36Sopenharmony_ci task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 62462306a36Sopenharmony_ci goto out; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* 62862306a36Sopenharmony_ci * Service the next queue. 62962306a36Sopenharmony_ci */ 63062306a36Sopenharmony_ci do { 63162306a36Sopenharmony_ci if (q == &queue->tasks[0]) 63262306a36Sopenharmony_ci q = &queue->tasks[queue->maxpriority]; 63362306a36Sopenharmony_ci else 63462306a36Sopenharmony_ci q = q - 1; 63562306a36Sopenharmony_ci if (!list_empty(q)) { 63662306a36Sopenharmony_ci task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 63762306a36Sopenharmony_ci goto new_queue; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci } while (q != &queue->tasks[queue->priority]); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci rpc_reset_waitqueue_priority(queue); 64262306a36Sopenharmony_ci return NULL; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cinew_queue: 64562306a36Sopenharmony_ci rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0])); 64662306a36Sopenharmony_ciout: 64762306a36Sopenharmony_ci return task; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci if (RPC_IS_PRIORITY(queue)) 65362306a36Sopenharmony_ci return __rpc_find_next_queued_priority(queue); 65462306a36Sopenharmony_ci if (!list_empty(&queue->tasks[0])) 65562306a36Sopenharmony_ci return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list); 65662306a36Sopenharmony_ci return NULL; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* 66062306a36Sopenharmony_ci * Wake up the first task on the wait queue. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_cistruct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, 66362306a36Sopenharmony_ci struct rpc_wait_queue *queue, 66462306a36Sopenharmony_ci bool (*func)(struct rpc_task *, void *), void *data) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct rpc_task *task = NULL; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci spin_lock(&queue->lock); 66962306a36Sopenharmony_ci task = __rpc_find_next_queued(queue); 67062306a36Sopenharmony_ci if (task != NULL) 67162306a36Sopenharmony_ci task = rpc_wake_up_task_on_wq_queue_action_locked(wq, queue, 67262306a36Sopenharmony_ci task, func, data); 67362306a36Sopenharmony_ci spin_unlock(&queue->lock); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return task; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* 67962306a36Sopenharmony_ci * Wake up the first task on the wait queue. 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_cistruct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, 68262306a36Sopenharmony_ci bool (*func)(struct rpc_task *, void *), void *data) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci return rpc_wake_up_first_on_wq(rpciod_workqueue, queue, func, data); 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_first); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic bool rpc_wake_up_next_func(struct rpc_task *task, void *data) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci return true; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/* 69462306a36Sopenharmony_ci * Wake up the next task on the wait queue. 69562306a36Sopenharmony_ci*/ 69662306a36Sopenharmony_cistruct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL); 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_next); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci/** 70362306a36Sopenharmony_ci * rpc_wake_up_locked - wake up all rpc_tasks 70462306a36Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_cistatic void rpc_wake_up_locked(struct rpc_wait_queue *queue) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct rpc_task *task; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci for (;;) { 71262306a36Sopenharmony_ci task = __rpc_find_next_queued(queue); 71362306a36Sopenharmony_ci if (task == NULL) 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci/** 72062306a36Sopenharmony_ci * rpc_wake_up - wake up all rpc_tasks 72162306a36Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 72262306a36Sopenharmony_ci * 72362306a36Sopenharmony_ci * Grabs queue->lock 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_civoid rpc_wake_up(struct rpc_wait_queue *queue) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci spin_lock(&queue->lock); 72862306a36Sopenharmony_ci rpc_wake_up_locked(queue); 72962306a36Sopenharmony_ci spin_unlock(&queue->lock); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci/** 73462306a36Sopenharmony_ci * rpc_wake_up_status_locked - wake up all rpc_tasks and set their status value. 73562306a36Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 73662306a36Sopenharmony_ci * @status: status value to set 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_cistatic void rpc_wake_up_status_locked(struct rpc_wait_queue *queue, int status) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct rpc_task *task; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci for (;;) { 74362306a36Sopenharmony_ci task = __rpc_find_next_queued(queue); 74462306a36Sopenharmony_ci if (task == NULL) 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci rpc_wake_up_task_queue_set_status_locked(queue, task, status); 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci/** 75162306a36Sopenharmony_ci * rpc_wake_up_status - wake up all rpc_tasks and set their status value. 75262306a36Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 75362306a36Sopenharmony_ci * @status: status value to set 75462306a36Sopenharmony_ci * 75562306a36Sopenharmony_ci * Grabs queue->lock 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_civoid rpc_wake_up_status(struct rpc_wait_queue *queue, int status) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci spin_lock(&queue->lock); 76062306a36Sopenharmony_ci rpc_wake_up_status_locked(queue, status); 76162306a36Sopenharmony_ci spin_unlock(&queue->lock); 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_status); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic void __rpc_queue_timer_fn(struct work_struct *work) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct rpc_wait_queue *queue = container_of(work, 76862306a36Sopenharmony_ci struct rpc_wait_queue, 76962306a36Sopenharmony_ci timer_list.dwork.work); 77062306a36Sopenharmony_ci struct rpc_task *task, *n; 77162306a36Sopenharmony_ci unsigned long expires, now, timeo; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci spin_lock(&queue->lock); 77462306a36Sopenharmony_ci expires = now = jiffies; 77562306a36Sopenharmony_ci list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) { 77662306a36Sopenharmony_ci timeo = task->tk_timeout; 77762306a36Sopenharmony_ci if (time_after_eq(now, timeo)) { 77862306a36Sopenharmony_ci trace_rpc_task_timeout(task, task->tk_action); 77962306a36Sopenharmony_ci task->tk_status = -ETIMEDOUT; 78062306a36Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 78162306a36Sopenharmony_ci continue; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci if (expires == now || time_after(expires, timeo)) 78462306a36Sopenharmony_ci expires = timeo; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci if (!list_empty(&queue->timer_list.list)) 78762306a36Sopenharmony_ci rpc_set_queue_timer(queue, expires); 78862306a36Sopenharmony_ci spin_unlock(&queue->lock); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic void __rpc_atrun(struct rpc_task *task) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci if (task->tk_status == -ETIMEDOUT) 79462306a36Sopenharmony_ci task->tk_status = 0; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* 79862306a36Sopenharmony_ci * Run a task at a later time 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_civoid rpc_delay(struct rpc_task *task, unsigned long delay) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci rpc_sleep_on_timeout(&delay_queue, task, __rpc_atrun, jiffies + delay); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_delay); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci/* 80762306a36Sopenharmony_ci * Helper to call task->tk_ops->rpc_call_prepare 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_civoid rpc_prepare_task(struct rpc_task *task) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci task->tk_ops->rpc_call_prepare(task, task->tk_calldata); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic void 81562306a36Sopenharmony_cirpc_init_task_statistics(struct rpc_task *task) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci /* Initialize retry counters */ 81862306a36Sopenharmony_ci task->tk_garb_retry = 2; 81962306a36Sopenharmony_ci task->tk_cred_retry = 2; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* starting timestamp */ 82262306a36Sopenharmony_ci task->tk_start = ktime_get(); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic void 82662306a36Sopenharmony_cirpc_reset_task_statistics(struct rpc_task *task) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci task->tk_timeouts = 0; 82962306a36Sopenharmony_ci task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_SENT); 83062306a36Sopenharmony_ci rpc_init_task_statistics(task); 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci/* 83462306a36Sopenharmony_ci * Helper that calls task->tk_ops->rpc_call_done if it exists 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_civoid rpc_exit_task(struct rpc_task *task) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci trace_rpc_task_end(task, task->tk_action); 83962306a36Sopenharmony_ci task->tk_action = NULL; 84062306a36Sopenharmony_ci if (task->tk_ops->rpc_count_stats) 84162306a36Sopenharmony_ci task->tk_ops->rpc_count_stats(task, task->tk_calldata); 84262306a36Sopenharmony_ci else if (task->tk_client) 84362306a36Sopenharmony_ci rpc_count_iostats(task, task->tk_client->cl_metrics); 84462306a36Sopenharmony_ci if (task->tk_ops->rpc_call_done != NULL) { 84562306a36Sopenharmony_ci trace_rpc_task_call_done(task, task->tk_ops->rpc_call_done); 84662306a36Sopenharmony_ci task->tk_ops->rpc_call_done(task, task->tk_calldata); 84762306a36Sopenharmony_ci if (task->tk_action != NULL) { 84862306a36Sopenharmony_ci /* Always release the RPC slot and buffer memory */ 84962306a36Sopenharmony_ci xprt_release(task); 85062306a36Sopenharmony_ci rpc_reset_task_statistics(task); 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_civoid rpc_signal_task(struct rpc_task *task) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct rpc_wait_queue *queue; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!RPC_IS_ACTIVATED(task)) 86062306a36Sopenharmony_ci return; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (!rpc_task_set_rpc_status(task, -ERESTARTSYS)) 86362306a36Sopenharmony_ci return; 86462306a36Sopenharmony_ci trace_rpc_task_signalled(task, task->tk_action); 86562306a36Sopenharmony_ci set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate); 86662306a36Sopenharmony_ci smp_mb__after_atomic(); 86762306a36Sopenharmony_ci queue = READ_ONCE(task->tk_waitqueue); 86862306a36Sopenharmony_ci if (queue) 86962306a36Sopenharmony_ci rpc_wake_up_queued_task(queue, task); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_civoid rpc_task_try_cancel(struct rpc_task *task, int error) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct rpc_wait_queue *queue; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (!rpc_task_set_rpc_status(task, error)) 87762306a36Sopenharmony_ci return; 87862306a36Sopenharmony_ci queue = READ_ONCE(task->tk_waitqueue); 87962306a36Sopenharmony_ci if (queue) 88062306a36Sopenharmony_ci rpc_wake_up_queued_task(queue, task); 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_civoid rpc_exit(struct rpc_task *task, int status) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci task->tk_status = status; 88662306a36Sopenharmony_ci task->tk_action = rpc_exit_task; 88762306a36Sopenharmony_ci rpc_wake_up_queued_task(task->tk_waitqueue, task); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_exit); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_civoid rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci if (ops->rpc_release != NULL) 89462306a36Sopenharmony_ci ops->rpc_release(calldata); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic bool xprt_needs_memalloc(struct rpc_xprt *xprt, struct rpc_task *tk) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci if (!xprt) 90062306a36Sopenharmony_ci return false; 90162306a36Sopenharmony_ci if (!atomic_read(&xprt->swapper)) 90262306a36Sopenharmony_ci return false; 90362306a36Sopenharmony_ci return test_bit(XPRT_LOCKED, &xprt->state) && xprt->snd_task == tk; 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci/* 90762306a36Sopenharmony_ci * This is the RPC `scheduler' (or rather, the finite state machine). 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_cistatic void __rpc_execute(struct rpc_task *task) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct rpc_wait_queue *queue; 91262306a36Sopenharmony_ci int task_is_async = RPC_IS_ASYNC(task); 91362306a36Sopenharmony_ci int status = 0; 91462306a36Sopenharmony_ci unsigned long pflags = current->flags; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci WARN_ON_ONCE(RPC_IS_QUEUED(task)); 91762306a36Sopenharmony_ci if (RPC_IS_QUEUED(task)) 91862306a36Sopenharmony_ci return; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci for (;;) { 92162306a36Sopenharmony_ci void (*do_action)(struct rpc_task *); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci /* 92462306a36Sopenharmony_ci * Perform the next FSM step or a pending callback. 92562306a36Sopenharmony_ci * 92662306a36Sopenharmony_ci * tk_action may be NULL if the task has been killed. 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_ci do_action = task->tk_action; 92962306a36Sopenharmony_ci /* Tasks with an RPC error status should exit */ 93062306a36Sopenharmony_ci if (do_action && do_action != rpc_exit_task && 93162306a36Sopenharmony_ci (status = READ_ONCE(task->tk_rpc_status)) != 0) { 93262306a36Sopenharmony_ci task->tk_status = status; 93362306a36Sopenharmony_ci do_action = rpc_exit_task; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci /* Callbacks override all actions */ 93662306a36Sopenharmony_ci if (task->tk_callback) { 93762306a36Sopenharmony_ci do_action = task->tk_callback; 93862306a36Sopenharmony_ci task->tk_callback = NULL; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci if (!do_action) 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci if (RPC_IS_SWAPPER(task) || 94362306a36Sopenharmony_ci xprt_needs_memalloc(task->tk_xprt, task)) 94462306a36Sopenharmony_ci current->flags |= PF_MEMALLOC; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci trace_rpc_task_run_action(task, do_action); 94762306a36Sopenharmony_ci do_action(task); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* 95062306a36Sopenharmony_ci * Lockless check for whether task is sleeping or not. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci if (!RPC_IS_QUEUED(task)) { 95362306a36Sopenharmony_ci cond_resched(); 95462306a36Sopenharmony_ci continue; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* 95862306a36Sopenharmony_ci * The queue->lock protects against races with 95962306a36Sopenharmony_ci * rpc_make_runnable(). 96062306a36Sopenharmony_ci * 96162306a36Sopenharmony_ci * Note that once we clear RPC_TASK_RUNNING on an asynchronous 96262306a36Sopenharmony_ci * rpc_task, rpc_make_runnable() can assign it to a 96362306a36Sopenharmony_ci * different workqueue. We therefore cannot assume that the 96462306a36Sopenharmony_ci * rpc_task pointer may still be dereferenced. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_ci queue = task->tk_waitqueue; 96762306a36Sopenharmony_ci spin_lock(&queue->lock); 96862306a36Sopenharmony_ci if (!RPC_IS_QUEUED(task)) { 96962306a36Sopenharmony_ci spin_unlock(&queue->lock); 97062306a36Sopenharmony_ci continue; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci /* Wake up any task that has an exit status */ 97362306a36Sopenharmony_ci if (READ_ONCE(task->tk_rpc_status) != 0) { 97462306a36Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 97562306a36Sopenharmony_ci spin_unlock(&queue->lock); 97662306a36Sopenharmony_ci continue; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci rpc_clear_running(task); 97962306a36Sopenharmony_ci spin_unlock(&queue->lock); 98062306a36Sopenharmony_ci if (task_is_async) 98162306a36Sopenharmony_ci goto out; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci /* sync task: sleep here */ 98462306a36Sopenharmony_ci trace_rpc_task_sync_sleep(task, task->tk_action); 98562306a36Sopenharmony_ci status = out_of_line_wait_on_bit(&task->tk_runstate, 98662306a36Sopenharmony_ci RPC_TASK_QUEUED, rpc_wait_bit_killable, 98762306a36Sopenharmony_ci TASK_KILLABLE|TASK_FREEZABLE); 98862306a36Sopenharmony_ci if (status < 0) { 98962306a36Sopenharmony_ci /* 99062306a36Sopenharmony_ci * When a sync task receives a signal, it exits with 99162306a36Sopenharmony_ci * -ERESTARTSYS. In order to catch any callbacks that 99262306a36Sopenharmony_ci * clean up after sleeping on some queue, we don't 99362306a36Sopenharmony_ci * break the loop here, but go around once more. 99462306a36Sopenharmony_ci */ 99562306a36Sopenharmony_ci rpc_signal_task(task); 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci trace_rpc_task_sync_wake(task, task->tk_action); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* Release all resources associated with the task */ 100162306a36Sopenharmony_ci rpc_release_task(task); 100262306a36Sopenharmony_ciout: 100362306a36Sopenharmony_ci current_restore_flags(pflags, PF_MEMALLOC); 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci/* 100762306a36Sopenharmony_ci * User-visible entry point to the scheduler. 100862306a36Sopenharmony_ci * 100962306a36Sopenharmony_ci * This may be called recursively if e.g. an async NFS task updates 101062306a36Sopenharmony_ci * the attributes and finds that dirty pages must be flushed. 101162306a36Sopenharmony_ci * NOTE: Upon exit of this function the task is guaranteed to be 101262306a36Sopenharmony_ci * released. In particular note that tk_release() will have 101362306a36Sopenharmony_ci * been called, so your task memory may have been freed. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_civoid rpc_execute(struct rpc_task *task) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci bool is_async = RPC_IS_ASYNC(task); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci rpc_set_active(task); 102062306a36Sopenharmony_ci rpc_make_runnable(rpciod_workqueue, task); 102162306a36Sopenharmony_ci if (!is_async) { 102262306a36Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 102362306a36Sopenharmony_ci __rpc_execute(task); 102462306a36Sopenharmony_ci memalloc_nofs_restore(pflags); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic void rpc_async_schedule(struct work_struct *work) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); 103362306a36Sopenharmony_ci memalloc_nofs_restore(pflags); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci/** 103762306a36Sopenharmony_ci * rpc_malloc - allocate RPC buffer resources 103862306a36Sopenharmony_ci * @task: RPC task 103962306a36Sopenharmony_ci * 104062306a36Sopenharmony_ci * A single memory region is allocated, which is split between the 104162306a36Sopenharmony_ci * RPC call and RPC reply that this task is being used for. When 104262306a36Sopenharmony_ci * this RPC is retired, the memory is released by calling rpc_free. 104362306a36Sopenharmony_ci * 104462306a36Sopenharmony_ci * To prevent rpciod from hanging, this allocator never sleeps, 104562306a36Sopenharmony_ci * returning -ENOMEM and suppressing warning if the request cannot 104662306a36Sopenharmony_ci * be serviced immediately. The caller can arrange to sleep in a 104762306a36Sopenharmony_ci * way that is safe for rpciod. 104862306a36Sopenharmony_ci * 104962306a36Sopenharmony_ci * Most requests are 'small' (under 2KiB) and can be serviced from a 105062306a36Sopenharmony_ci * mempool, ensuring that NFS reads and writes can always proceed, 105162306a36Sopenharmony_ci * and that there is good locality of reference for these buffers. 105262306a36Sopenharmony_ci */ 105362306a36Sopenharmony_ciint rpc_malloc(struct rpc_task *task) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct rpc_rqst *rqst = task->tk_rqstp; 105662306a36Sopenharmony_ci size_t size = rqst->rq_callsize + rqst->rq_rcvsize; 105762306a36Sopenharmony_ci struct rpc_buffer *buf; 105862306a36Sopenharmony_ci gfp_t gfp = rpc_task_gfp_mask(); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci size += sizeof(struct rpc_buffer); 106162306a36Sopenharmony_ci if (size <= RPC_BUFFER_MAXSIZE) { 106262306a36Sopenharmony_ci buf = kmem_cache_alloc(rpc_buffer_slabp, gfp); 106362306a36Sopenharmony_ci /* Reach for the mempool if dynamic allocation fails */ 106462306a36Sopenharmony_ci if (!buf && RPC_IS_ASYNC(task)) 106562306a36Sopenharmony_ci buf = mempool_alloc(rpc_buffer_mempool, GFP_NOWAIT); 106662306a36Sopenharmony_ci } else 106762306a36Sopenharmony_ci buf = kmalloc(size, gfp); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (!buf) 107062306a36Sopenharmony_ci return -ENOMEM; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci buf->len = size; 107362306a36Sopenharmony_ci rqst->rq_buffer = buf->data; 107462306a36Sopenharmony_ci rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize; 107562306a36Sopenharmony_ci return 0; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_malloc); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/** 108062306a36Sopenharmony_ci * rpc_free - free RPC buffer resources allocated via rpc_malloc 108162306a36Sopenharmony_ci * @task: RPC task 108262306a36Sopenharmony_ci * 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_civoid rpc_free(struct rpc_task *task) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci void *buffer = task->tk_rqstp->rq_buffer; 108762306a36Sopenharmony_ci size_t size; 108862306a36Sopenharmony_ci struct rpc_buffer *buf; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci buf = container_of(buffer, struct rpc_buffer, data); 109162306a36Sopenharmony_ci size = buf->len; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (size <= RPC_BUFFER_MAXSIZE) 109462306a36Sopenharmony_ci mempool_free(buf, rpc_buffer_mempool); 109562306a36Sopenharmony_ci else 109662306a36Sopenharmony_ci kfree(buf); 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_free); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci/* 110162306a36Sopenharmony_ci * Creation and deletion of RPC task structures 110262306a36Sopenharmony_ci */ 110362306a36Sopenharmony_cistatic void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci memset(task, 0, sizeof(*task)); 110662306a36Sopenharmony_ci atomic_set(&task->tk_count, 1); 110762306a36Sopenharmony_ci task->tk_flags = task_setup_data->flags; 110862306a36Sopenharmony_ci task->tk_ops = task_setup_data->callback_ops; 110962306a36Sopenharmony_ci task->tk_calldata = task_setup_data->callback_data; 111062306a36Sopenharmony_ci INIT_LIST_HEAD(&task->tk_task); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; 111362306a36Sopenharmony_ci task->tk_owner = current->tgid; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* Initialize workqueue for async tasks */ 111662306a36Sopenharmony_ci task->tk_workqueue = task_setup_data->workqueue; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci task->tk_xprt = rpc_task_get_xprt(task_setup_data->rpc_client, 111962306a36Sopenharmony_ci xprt_get(task_setup_data->rpc_xprt)); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci task->tk_op_cred = get_rpccred(task_setup_data->rpc_op_cred); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci if (task->tk_ops->rpc_call_prepare != NULL) 112462306a36Sopenharmony_ci task->tk_action = rpc_prepare_task; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci rpc_init_task_statistics(task); 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic struct rpc_task *rpc_alloc_task(void) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct rpc_task *task; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci task = kmem_cache_alloc(rpc_task_slabp, rpc_task_gfp_mask()); 113462306a36Sopenharmony_ci if (task) 113562306a36Sopenharmony_ci return task; 113662306a36Sopenharmony_ci return mempool_alloc(rpc_task_mempool, GFP_NOWAIT); 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci/* 114062306a36Sopenharmony_ci * Create a new task for the specified client. 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_cistruct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci struct rpc_task *task = setup_data->task; 114562306a36Sopenharmony_ci unsigned short flags = 0; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (task == NULL) { 114862306a36Sopenharmony_ci task = rpc_alloc_task(); 114962306a36Sopenharmony_ci if (task == NULL) { 115062306a36Sopenharmony_ci rpc_release_calldata(setup_data->callback_ops, 115162306a36Sopenharmony_ci setup_data->callback_data); 115262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci flags = RPC_TASK_DYNAMIC; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci rpc_init_task(task, setup_data); 115862306a36Sopenharmony_ci task->tk_flags |= flags; 115962306a36Sopenharmony_ci return task; 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci/* 116362306a36Sopenharmony_ci * rpc_free_task - release rpc task and perform cleanups 116462306a36Sopenharmony_ci * 116562306a36Sopenharmony_ci * Note that we free up the rpc_task _after_ rpc_release_calldata() 116662306a36Sopenharmony_ci * in order to work around a workqueue dependency issue. 116762306a36Sopenharmony_ci * 116862306a36Sopenharmony_ci * Tejun Heo states: 116962306a36Sopenharmony_ci * "Workqueue currently considers two work items to be the same if they're 117062306a36Sopenharmony_ci * on the same address and won't execute them concurrently - ie. it 117162306a36Sopenharmony_ci * makes a work item which is queued again while being executed wait 117262306a36Sopenharmony_ci * for the previous execution to complete. 117362306a36Sopenharmony_ci * 117462306a36Sopenharmony_ci * If a work function frees the work item, and then waits for an event 117562306a36Sopenharmony_ci * which should be performed by another work item and *that* work item 117662306a36Sopenharmony_ci * recycles the freed work item, it can create a false dependency loop. 117762306a36Sopenharmony_ci * There really is no reliable way to detect this short of verifying 117862306a36Sopenharmony_ci * every memory free." 117962306a36Sopenharmony_ci * 118062306a36Sopenharmony_ci */ 118162306a36Sopenharmony_cistatic void rpc_free_task(struct rpc_task *task) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci unsigned short tk_flags = task->tk_flags; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci put_rpccred(task->tk_op_cred); 118662306a36Sopenharmony_ci rpc_release_calldata(task->tk_ops, task->tk_calldata); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (tk_flags & RPC_TASK_DYNAMIC) 118962306a36Sopenharmony_ci mempool_free(task, rpc_task_mempool); 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic void rpc_async_release(struct work_struct *work) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci rpc_free_task(container_of(work, struct rpc_task, u.tk_work)); 119762306a36Sopenharmony_ci memalloc_nofs_restore(pflags); 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic void rpc_release_resources_task(struct rpc_task *task) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci xprt_release(task); 120362306a36Sopenharmony_ci if (task->tk_msg.rpc_cred) { 120462306a36Sopenharmony_ci if (!(task->tk_flags & RPC_TASK_CRED_NOREF)) 120562306a36Sopenharmony_ci put_cred(task->tk_msg.rpc_cred); 120662306a36Sopenharmony_ci task->tk_msg.rpc_cred = NULL; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci rpc_task_release_client(task); 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic void rpc_final_put_task(struct rpc_task *task, 121262306a36Sopenharmony_ci struct workqueue_struct *q) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci if (q != NULL) { 121562306a36Sopenharmony_ci INIT_WORK(&task->u.tk_work, rpc_async_release); 121662306a36Sopenharmony_ci queue_work(q, &task->u.tk_work); 121762306a36Sopenharmony_ci } else 121862306a36Sopenharmony_ci rpc_free_task(task); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic void rpc_do_put_task(struct rpc_task *task, struct workqueue_struct *q) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci if (atomic_dec_and_test(&task->tk_count)) { 122462306a36Sopenharmony_ci rpc_release_resources_task(task); 122562306a36Sopenharmony_ci rpc_final_put_task(task, q); 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci} 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_civoid rpc_put_task(struct rpc_task *task) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci rpc_do_put_task(task, NULL); 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_put_task); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_civoid rpc_put_task_async(struct rpc_task *task) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci rpc_do_put_task(task, task->tk_workqueue); 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_put_task_async); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_cistatic void rpc_release_task(struct rpc_task *task) 124262306a36Sopenharmony_ci{ 124362306a36Sopenharmony_ci WARN_ON_ONCE(RPC_IS_QUEUED(task)); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci rpc_release_resources_task(task); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* 124862306a36Sopenharmony_ci * Note: at this point we have been removed from rpc_clnt->cl_tasks, 124962306a36Sopenharmony_ci * so it should be safe to use task->tk_count as a test for whether 125062306a36Sopenharmony_ci * or not any other processes still hold references to our rpc_task. 125162306a36Sopenharmony_ci */ 125262306a36Sopenharmony_ci if (atomic_read(&task->tk_count) != 1 + !RPC_IS_ASYNC(task)) { 125362306a36Sopenharmony_ci /* Wake up anyone who may be waiting for task completion */ 125462306a36Sopenharmony_ci if (!rpc_complete_task(task)) 125562306a36Sopenharmony_ci return; 125662306a36Sopenharmony_ci } else { 125762306a36Sopenharmony_ci if (!atomic_dec_and_test(&task->tk_count)) 125862306a36Sopenharmony_ci return; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci rpc_final_put_task(task, task->tk_workqueue); 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ciint rpciod_up(void) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci return try_module_get(THIS_MODULE) ? 0 : -EINVAL; 126662306a36Sopenharmony_ci} 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_civoid rpciod_down(void) 126962306a36Sopenharmony_ci{ 127062306a36Sopenharmony_ci module_put(THIS_MODULE); 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci/* 127462306a36Sopenharmony_ci * Start up the rpciod workqueue. 127562306a36Sopenharmony_ci */ 127662306a36Sopenharmony_cistatic int rpciod_start(void) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci struct workqueue_struct *wq; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* 128162306a36Sopenharmony_ci * Create the rpciod thread and wait for it to start. 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ci wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 128462306a36Sopenharmony_ci if (!wq) 128562306a36Sopenharmony_ci goto out_failed; 128662306a36Sopenharmony_ci rpciod_workqueue = wq; 128762306a36Sopenharmony_ci wq = alloc_workqueue("xprtiod", WQ_UNBOUND | WQ_MEM_RECLAIM, 0); 128862306a36Sopenharmony_ci if (!wq) 128962306a36Sopenharmony_ci goto free_rpciod; 129062306a36Sopenharmony_ci xprtiod_workqueue = wq; 129162306a36Sopenharmony_ci return 1; 129262306a36Sopenharmony_cifree_rpciod: 129362306a36Sopenharmony_ci wq = rpciod_workqueue; 129462306a36Sopenharmony_ci rpciod_workqueue = NULL; 129562306a36Sopenharmony_ci destroy_workqueue(wq); 129662306a36Sopenharmony_ciout_failed: 129762306a36Sopenharmony_ci return 0; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic void rpciod_stop(void) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct workqueue_struct *wq = NULL; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (rpciod_workqueue == NULL) 130562306a36Sopenharmony_ci return; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci wq = rpciod_workqueue; 130862306a36Sopenharmony_ci rpciod_workqueue = NULL; 130962306a36Sopenharmony_ci destroy_workqueue(wq); 131062306a36Sopenharmony_ci wq = xprtiod_workqueue; 131162306a36Sopenharmony_ci xprtiod_workqueue = NULL; 131262306a36Sopenharmony_ci destroy_workqueue(wq); 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_civoid 131662306a36Sopenharmony_cirpc_destroy_mempool(void) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci rpciod_stop(); 131962306a36Sopenharmony_ci mempool_destroy(rpc_buffer_mempool); 132062306a36Sopenharmony_ci mempool_destroy(rpc_task_mempool); 132162306a36Sopenharmony_ci kmem_cache_destroy(rpc_task_slabp); 132262306a36Sopenharmony_ci kmem_cache_destroy(rpc_buffer_slabp); 132362306a36Sopenharmony_ci rpc_destroy_wait_queue(&delay_queue); 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ciint 132762306a36Sopenharmony_cirpc_init_mempool(void) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci /* 133062306a36Sopenharmony_ci * The following is not strictly a mempool initialisation, 133162306a36Sopenharmony_ci * but there is no harm in doing it here 133262306a36Sopenharmony_ci */ 133362306a36Sopenharmony_ci rpc_init_wait_queue(&delay_queue, "delayq"); 133462306a36Sopenharmony_ci if (!rpciod_start()) 133562306a36Sopenharmony_ci goto err_nomem; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci rpc_task_slabp = kmem_cache_create("rpc_tasks", 133862306a36Sopenharmony_ci sizeof(struct rpc_task), 133962306a36Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, 134062306a36Sopenharmony_ci NULL); 134162306a36Sopenharmony_ci if (!rpc_task_slabp) 134262306a36Sopenharmony_ci goto err_nomem; 134362306a36Sopenharmony_ci rpc_buffer_slabp = kmem_cache_create("rpc_buffers", 134462306a36Sopenharmony_ci RPC_BUFFER_MAXSIZE, 134562306a36Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, 134662306a36Sopenharmony_ci NULL); 134762306a36Sopenharmony_ci if (!rpc_buffer_slabp) 134862306a36Sopenharmony_ci goto err_nomem; 134962306a36Sopenharmony_ci rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE, 135062306a36Sopenharmony_ci rpc_task_slabp); 135162306a36Sopenharmony_ci if (!rpc_task_mempool) 135262306a36Sopenharmony_ci goto err_nomem; 135362306a36Sopenharmony_ci rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE, 135462306a36Sopenharmony_ci rpc_buffer_slabp); 135562306a36Sopenharmony_ci if (!rpc_buffer_mempool) 135662306a36Sopenharmony_ci goto err_nomem; 135762306a36Sopenharmony_ci return 0; 135862306a36Sopenharmony_cierr_nomem: 135962306a36Sopenharmony_ci rpc_destroy_mempool(); 136062306a36Sopenharmony_ci return -ENOMEM; 136162306a36Sopenharmony_ci} 1362