18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/net/sunrpc/sched.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Scheduling for synchronous and asynchronous RPC requests. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1996 Olaf Kirch, <okir@monad.swb.de> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * TCP NFS related read + write fixes 108c2ecf20Sopenharmony_ci * (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/mempool.h> 198c2ecf20Sopenharmony_ci#include <linux/smp.h> 208c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 218c2ecf20Sopenharmony_ci#include <linux/mutex.h> 228c2ecf20Sopenharmony_ci#include <linux/freezer.h> 238c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h> 268c2ecf20Sopenharmony_ci#include <linux/sunrpc/metrics.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "sunrpc.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 318c2ecf20Sopenharmony_ci#include <trace/events/sunrpc.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * RPC slabs and memory pools 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#define RPC_BUFFER_MAXSIZE (2048) 378c2ecf20Sopenharmony_ci#define RPC_BUFFER_POOLSIZE (8) 388c2ecf20Sopenharmony_ci#define RPC_TASK_POOLSIZE (8) 398c2ecf20Sopenharmony_cistatic struct kmem_cache *rpc_task_slabp __read_mostly; 408c2ecf20Sopenharmony_cistatic struct kmem_cache *rpc_buffer_slabp __read_mostly; 418c2ecf20Sopenharmony_cistatic mempool_t *rpc_task_mempool __read_mostly; 428c2ecf20Sopenharmony_cistatic mempool_t *rpc_buffer_mempool __read_mostly; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void rpc_async_schedule(struct work_struct *); 458c2ecf20Sopenharmony_cistatic void rpc_release_task(struct rpc_task *task); 468c2ecf20Sopenharmony_cistatic void __rpc_queue_timer_fn(struct work_struct *); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * RPC tasks sit here while waiting for conditions to improve. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic struct rpc_wait_queue delay_queue; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * rpciod-related stuff 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistruct workqueue_struct *rpciod_workqueue __read_mostly; 578c2ecf20Sopenharmony_cistruct workqueue_struct *xprtiod_workqueue __read_mostly; 588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(xprtiod_workqueue); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciunsigned long 618c2ecf20Sopenharmony_cirpc_task_timeout(const struct rpc_task *task) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci unsigned long timeout = READ_ONCE(task->tk_timeout); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (timeout != 0) { 668c2ecf20Sopenharmony_ci unsigned long now = jiffies; 678c2ecf20Sopenharmony_ci if (time_before(now, timeout)) 688c2ecf20Sopenharmony_ci return timeout - now; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_task_timeout); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci * Disable the timer for a given RPC task. Should be called with 768c2ecf20Sopenharmony_ci * queue->lock and bh_disabled in order to avoid races within 778c2ecf20Sopenharmony_ci * rpc_run_timer(). 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistatic void 808c2ecf20Sopenharmony_ci__rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci if (list_empty(&task->u.tk_wait.timer_list)) 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci task->tk_timeout = 0; 858c2ecf20Sopenharmony_ci list_del(&task->u.tk_wait.timer_list); 868c2ecf20Sopenharmony_ci if (list_empty(&queue->timer_list.list)) 878c2ecf20Sopenharmony_ci cancel_delayed_work(&queue->timer_list.dwork); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void 918c2ecf20Sopenharmony_cirpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci unsigned long now = jiffies; 948c2ecf20Sopenharmony_ci queue->timer_list.expires = expires; 958c2ecf20Sopenharmony_ci if (time_before_eq(expires, now)) 968c2ecf20Sopenharmony_ci expires = 0; 978c2ecf20Sopenharmony_ci else 988c2ecf20Sopenharmony_ci expires -= now; 998c2ecf20Sopenharmony_ci mod_delayed_work(rpciod_workqueue, &queue->timer_list.dwork, expires); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * Set up a timer for the current task. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic void 1068c2ecf20Sopenharmony_ci__rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task, 1078c2ecf20Sopenharmony_ci unsigned long timeout) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci task->tk_timeout = timeout; 1108c2ecf20Sopenharmony_ci if (list_empty(&queue->timer_list.list) || time_before(timeout, queue->timer_list.expires)) 1118c2ecf20Sopenharmony_ci rpc_set_queue_timer(queue, timeout); 1128c2ecf20Sopenharmony_ci list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci if (queue->priority != priority) { 1188c2ecf20Sopenharmony_ci queue->priority = priority; 1198c2ecf20Sopenharmony_ci queue->nr = 1U << priority; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci rpc_set_waitqueue_priority(queue, queue->maxpriority); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* 1298c2ecf20Sopenharmony_ci * Add a request to a queue list 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_cistatic void 1328c2ecf20Sopenharmony_ci__rpc_list_enqueue_task(struct list_head *q, struct rpc_task *task) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct rpc_task *t; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci list_for_each_entry(t, q, u.tk_wait.list) { 1378c2ecf20Sopenharmony_ci if (t->tk_owner == task->tk_owner) { 1388c2ecf20Sopenharmony_ci list_add_tail(&task->u.tk_wait.links, 1398c2ecf20Sopenharmony_ci &t->u.tk_wait.links); 1408c2ecf20Sopenharmony_ci /* Cache the queue head in task->u.tk_wait.list */ 1418c2ecf20Sopenharmony_ci task->u.tk_wait.list.next = q; 1428c2ecf20Sopenharmony_ci task->u.tk_wait.list.prev = NULL; 1438c2ecf20Sopenharmony_ci return; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&task->u.tk_wait.links); 1478c2ecf20Sopenharmony_ci list_add_tail(&task->u.tk_wait.list, q); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* 1518c2ecf20Sopenharmony_ci * Remove request from a queue list 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_cistatic void 1548c2ecf20Sopenharmony_ci__rpc_list_dequeue_task(struct rpc_task *task) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct list_head *q; 1578c2ecf20Sopenharmony_ci struct rpc_task *t; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (task->u.tk_wait.list.prev == NULL) { 1608c2ecf20Sopenharmony_ci list_del(&task->u.tk_wait.links); 1618c2ecf20Sopenharmony_ci return; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci if (!list_empty(&task->u.tk_wait.links)) { 1648c2ecf20Sopenharmony_ci t = list_first_entry(&task->u.tk_wait.links, 1658c2ecf20Sopenharmony_ci struct rpc_task, 1668c2ecf20Sopenharmony_ci u.tk_wait.links); 1678c2ecf20Sopenharmony_ci /* Assume __rpc_list_enqueue_task() cached the queue head */ 1688c2ecf20Sopenharmony_ci q = t->u.tk_wait.list.next; 1698c2ecf20Sopenharmony_ci list_add_tail(&t->u.tk_wait.list, q); 1708c2ecf20Sopenharmony_ci list_del(&task->u.tk_wait.links); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci list_del(&task->u.tk_wait.list); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* 1768c2ecf20Sopenharmony_ci * Add new request to a priority queue. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_cistatic void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, 1798c2ecf20Sopenharmony_ci struct rpc_task *task, 1808c2ecf20Sopenharmony_ci unsigned char queue_priority) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci if (unlikely(queue_priority > queue->maxpriority)) 1838c2ecf20Sopenharmony_ci queue_priority = queue->maxpriority; 1848c2ecf20Sopenharmony_ci __rpc_list_enqueue_task(&queue->tasks[queue_priority], task); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* 1888c2ecf20Sopenharmony_ci * Add new request to wait queue. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistatic void __rpc_add_wait_queue(struct rpc_wait_queue *queue, 1918c2ecf20Sopenharmony_ci struct rpc_task *task, 1928c2ecf20Sopenharmony_ci unsigned char queue_priority) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&task->u.tk_wait.timer_list); 1958c2ecf20Sopenharmony_ci if (RPC_IS_PRIORITY(queue)) 1968c2ecf20Sopenharmony_ci __rpc_add_wait_queue_priority(queue, task, queue_priority); 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]); 1998c2ecf20Sopenharmony_ci task->tk_waitqueue = queue; 2008c2ecf20Sopenharmony_ci queue->qlen++; 2018c2ecf20Sopenharmony_ci /* barrier matches the read in rpc_wake_up_task_queue_locked() */ 2028c2ecf20Sopenharmony_ci smp_wmb(); 2038c2ecf20Sopenharmony_ci rpc_set_queued(task); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* 2078c2ecf20Sopenharmony_ci * Remove request from a priority queue. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic void __rpc_remove_wait_queue_priority(struct rpc_task *task) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci __rpc_list_dequeue_task(task); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* 2158c2ecf20Sopenharmony_ci * Remove request from queue. 2168c2ecf20Sopenharmony_ci * Note: must be called with spin lock held. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_cistatic void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci __rpc_disable_timer(queue, task); 2218c2ecf20Sopenharmony_ci if (RPC_IS_PRIORITY(queue)) 2228c2ecf20Sopenharmony_ci __rpc_remove_wait_queue_priority(task); 2238c2ecf20Sopenharmony_ci else 2248c2ecf20Sopenharmony_ci list_del(&task->u.tk_wait.list); 2258c2ecf20Sopenharmony_ci queue->qlen--; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci int i; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci spin_lock_init(&queue->lock); 2338c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(queue->tasks); i++) 2348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&queue->tasks[i]); 2358c2ecf20Sopenharmony_ci queue->maxpriority = nr_queues - 1; 2368c2ecf20Sopenharmony_ci rpc_reset_waitqueue_priority(queue); 2378c2ecf20Sopenharmony_ci queue->qlen = 0; 2388c2ecf20Sopenharmony_ci queue->timer_list.expires = 0; 2398c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&queue->timer_list.dwork, __rpc_queue_timer_fn); 2408c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&queue->timer_list.list); 2418c2ecf20Sopenharmony_ci rpc_assign_waitqueue_name(queue, qname); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_civoid rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci __rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_civoid rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci __rpc_init_priority_wait_queue(queue, qname, 1); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_init_wait_queue); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_civoid rpc_destroy_wait_queue(struct rpc_wait_queue *queue) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&queue->timer_list.dwork); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int rpc_wait_bit_killable(struct wait_bit_key *key, int mode) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci freezable_schedule_unsafe(); 2658c2ecf20Sopenharmony_ci if (signal_pending_state(mode, current)) 2668c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) 2718c2ecf20Sopenharmony_cistatic void rpc_task_set_debuginfo(struct rpc_task *task) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci static atomic_t rpc_pid; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci task->tk_pid = atomic_inc_return(&rpc_pid); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci#else 2788c2ecf20Sopenharmony_cistatic inline void rpc_task_set_debuginfo(struct rpc_task *task) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci#endif 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void rpc_set_active(struct rpc_task *task) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci rpc_task_set_debuginfo(task); 2868c2ecf20Sopenharmony_ci set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); 2878c2ecf20Sopenharmony_ci trace_rpc_task_begin(task, NULL); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* 2918c2ecf20Sopenharmony_ci * Mark an RPC call as having completed by clearing the 'active' bit 2928c2ecf20Sopenharmony_ci * and then waking up all tasks that were sleeping. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_cistatic int rpc_complete_task(struct rpc_task *task) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci void *m = &task->tk_runstate; 2978c2ecf20Sopenharmony_ci wait_queue_head_t *wq = bit_waitqueue(m, RPC_TASK_ACTIVE); 2988c2ecf20Sopenharmony_ci struct wait_bit_key k = __WAIT_BIT_KEY_INITIALIZER(m, RPC_TASK_ACTIVE); 2998c2ecf20Sopenharmony_ci unsigned long flags; 3008c2ecf20Sopenharmony_ci int ret; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci trace_rpc_task_complete(task, NULL); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci spin_lock_irqsave(&wq->lock, flags); 3058c2ecf20Sopenharmony_ci clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); 3068c2ecf20Sopenharmony_ci ret = atomic_dec_and_test(&task->tk_count); 3078c2ecf20Sopenharmony_ci if (waitqueue_active(wq)) 3088c2ecf20Sopenharmony_ci __wake_up_locked_key(wq, TASK_NORMAL, &k); 3098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wq->lock, flags); 3108c2ecf20Sopenharmony_ci return ret; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci/* 3148c2ecf20Sopenharmony_ci * Allow callers to wait for completion of an RPC call 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * Note the use of out_of_line_wait_on_bit() rather than wait_on_bit() 3178c2ecf20Sopenharmony_ci * to enforce taking of the wq->lock and hence avoid races with 3188c2ecf20Sopenharmony_ci * rpc_complete_task(). 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ciint __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *action) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci if (action == NULL) 3238c2ecf20Sopenharmony_ci action = rpc_wait_bit_killable; 3248c2ecf20Sopenharmony_ci return out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE, 3258c2ecf20Sopenharmony_ci action, TASK_KILLABLE); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci/* 3308c2ecf20Sopenharmony_ci * Make an RPC task runnable. 3318c2ecf20Sopenharmony_ci * 3328c2ecf20Sopenharmony_ci * Note: If the task is ASYNC, and is being made runnable after sitting on an 3338c2ecf20Sopenharmony_ci * rpc_wait_queue, this must be called with the queue spinlock held to protect 3348c2ecf20Sopenharmony_ci * the wait queue operation. 3358c2ecf20Sopenharmony_ci * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(), 3368c2ecf20Sopenharmony_ci * which is needed to ensure that __rpc_execute() doesn't loop (due to the 3378c2ecf20Sopenharmony_ci * lockless RPC_IS_QUEUED() test) before we've had a chance to test 3388c2ecf20Sopenharmony_ci * the RPC_TASK_RUNNING flag. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_cistatic void rpc_make_runnable(struct workqueue_struct *wq, 3418c2ecf20Sopenharmony_ci struct rpc_task *task) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci bool need_wakeup = !rpc_test_and_set_running(task); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci rpc_clear_queued(task); 3468c2ecf20Sopenharmony_ci if (!need_wakeup) 3478c2ecf20Sopenharmony_ci return; 3488c2ecf20Sopenharmony_ci if (RPC_IS_ASYNC(task)) { 3498c2ecf20Sopenharmony_ci INIT_WORK(&task->u.tk_work, rpc_async_schedule); 3508c2ecf20Sopenharmony_ci queue_work(wq, &task->u.tk_work); 3518c2ecf20Sopenharmony_ci } else 3528c2ecf20Sopenharmony_ci wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/* 3568c2ecf20Sopenharmony_ci * Prepare for sleeping on a wait queue. 3578c2ecf20Sopenharmony_ci * By always appending tasks to the list we ensure FIFO behavior. 3588c2ecf20Sopenharmony_ci * NB: An RPC task will only receive interrupt-driven events as long 3598c2ecf20Sopenharmony_ci * as it's on a wait queue. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_cistatic void __rpc_do_sleep_on_priority(struct rpc_wait_queue *q, 3628c2ecf20Sopenharmony_ci struct rpc_task *task, 3638c2ecf20Sopenharmony_ci unsigned char queue_priority) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci trace_rpc_task_sleep(task, q); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci __rpc_add_wait_queue(q, task, queue_priority); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void __rpc_sleep_on_priority(struct rpc_wait_queue *q, 3718c2ecf20Sopenharmony_ci struct rpc_task *task, 3728c2ecf20Sopenharmony_ci unsigned char queue_priority) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(RPC_IS_QUEUED(task))) 3758c2ecf20Sopenharmony_ci return; 3768c2ecf20Sopenharmony_ci __rpc_do_sleep_on_priority(q, task, queue_priority); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void __rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q, 3808c2ecf20Sopenharmony_ci struct rpc_task *task, unsigned long timeout, 3818c2ecf20Sopenharmony_ci unsigned char queue_priority) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(RPC_IS_QUEUED(task))) 3848c2ecf20Sopenharmony_ci return; 3858c2ecf20Sopenharmony_ci if (time_is_after_jiffies(timeout)) { 3868c2ecf20Sopenharmony_ci __rpc_do_sleep_on_priority(q, task, queue_priority); 3878c2ecf20Sopenharmony_ci __rpc_add_timer(q, task, timeout); 3888c2ecf20Sopenharmony_ci } else 3898c2ecf20Sopenharmony_ci task->tk_status = -ETIMEDOUT; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void rpc_set_tk_callback(struct rpc_task *task, rpc_action action) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci if (action && !WARN_ON_ONCE(task->tk_callback != NULL)) 3958c2ecf20Sopenharmony_ci task->tk_callback = action; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic bool rpc_sleep_check_activated(struct rpc_task *task) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci /* We shouldn't ever put an inactive task to sleep */ 4018c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!RPC_IS_ACTIVATED(task))) { 4028c2ecf20Sopenharmony_ci task->tk_status = -EIO; 4038c2ecf20Sopenharmony_ci rpc_put_task_async(task); 4048c2ecf20Sopenharmony_ci return false; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci return true; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_civoid rpc_sleep_on_timeout(struct rpc_wait_queue *q, struct rpc_task *task, 4108c2ecf20Sopenharmony_ci rpc_action action, unsigned long timeout) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 4138c2ecf20Sopenharmony_ci return; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci rpc_set_tk_callback(task, action); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* 4188c2ecf20Sopenharmony_ci * Protect the queue operations. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci spin_lock(&q->lock); 4218c2ecf20Sopenharmony_ci __rpc_sleep_on_priority_timeout(q, task, timeout, task->tk_priority); 4228c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on_timeout); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_civoid rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, 4278c2ecf20Sopenharmony_ci rpc_action action) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 4308c2ecf20Sopenharmony_ci return; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci rpc_set_tk_callback(task, action); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci WARN_ON_ONCE(task->tk_timeout != 0); 4358c2ecf20Sopenharmony_ci /* 4368c2ecf20Sopenharmony_ci * Protect the queue operations. 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci spin_lock(&q->lock); 4398c2ecf20Sopenharmony_ci __rpc_sleep_on_priority(q, task, task->tk_priority); 4408c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_civoid rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q, 4458c2ecf20Sopenharmony_ci struct rpc_task *task, unsigned long timeout, int priority) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 4488c2ecf20Sopenharmony_ci return; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci priority -= RPC_PRIORITY_LOW; 4518c2ecf20Sopenharmony_ci /* 4528c2ecf20Sopenharmony_ci * Protect the queue operations. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ci spin_lock(&q->lock); 4558c2ecf20Sopenharmony_ci __rpc_sleep_on_priority_timeout(q, task, timeout, priority); 4568c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on_priority_timeout); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_civoid rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, 4618c2ecf20Sopenharmony_ci int priority) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci if (!rpc_sleep_check_activated(task)) 4648c2ecf20Sopenharmony_ci return; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci WARN_ON_ONCE(task->tk_timeout != 0); 4678c2ecf20Sopenharmony_ci priority -= RPC_PRIORITY_LOW; 4688c2ecf20Sopenharmony_ci /* 4698c2ecf20Sopenharmony_ci * Protect the queue operations. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci spin_lock(&q->lock); 4728c2ecf20Sopenharmony_ci __rpc_sleep_on_priority(q, task, priority); 4738c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_sleep_on_priority); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/** 4788c2ecf20Sopenharmony_ci * __rpc_do_wake_up_task_on_wq - wake up a single rpc_task 4798c2ecf20Sopenharmony_ci * @wq: workqueue on which to run task 4808c2ecf20Sopenharmony_ci * @queue: wait queue 4818c2ecf20Sopenharmony_ci * @task: task to be woken up 4828c2ecf20Sopenharmony_ci * 4838c2ecf20Sopenharmony_ci * Caller must hold queue->lock, and have cleared the task queued flag. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_cistatic void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq, 4868c2ecf20Sopenharmony_ci struct rpc_wait_queue *queue, 4878c2ecf20Sopenharmony_ci struct rpc_task *task) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci /* Has the task been executed yet? If not, we cannot wake it up! */ 4908c2ecf20Sopenharmony_ci if (!RPC_IS_ACTIVATED(task)) { 4918c2ecf20Sopenharmony_ci printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task); 4928c2ecf20Sopenharmony_ci return; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci trace_rpc_task_wakeup(task, queue); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci __rpc_remove_wait_queue(queue, task); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci rpc_make_runnable(wq, task); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/* 5038c2ecf20Sopenharmony_ci * Wake up a queued task while the queue lock is being held 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_cistatic struct rpc_task * 5068c2ecf20Sopenharmony_cirpc_wake_up_task_on_wq_queue_action_locked(struct workqueue_struct *wq, 5078c2ecf20Sopenharmony_ci struct rpc_wait_queue *queue, struct rpc_task *task, 5088c2ecf20Sopenharmony_ci bool (*action)(struct rpc_task *, void *), void *data) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci if (RPC_IS_QUEUED(task)) { 5118c2ecf20Sopenharmony_ci smp_rmb(); 5128c2ecf20Sopenharmony_ci if (task->tk_waitqueue == queue) { 5138c2ecf20Sopenharmony_ci if (action == NULL || action(task, data)) { 5148c2ecf20Sopenharmony_ci __rpc_do_wake_up_task_on_wq(wq, queue, task); 5158c2ecf20Sopenharmony_ci return task; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci return NULL; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/* 5238c2ecf20Sopenharmony_ci * Wake up a queued task while the queue lock is being held 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_cistatic void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, 5268c2ecf20Sopenharmony_ci struct rpc_task *task) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue, 5298c2ecf20Sopenharmony_ci task, NULL, NULL); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* 5338c2ecf20Sopenharmony_ci * Wake up a task on a specific queue 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_civoid rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci if (!RPC_IS_QUEUED(task)) 5388c2ecf20Sopenharmony_ci return; 5398c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 5408c2ecf20Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 5418c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic bool rpc_task_action_set_status(struct rpc_task *task, void *status) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci task->tk_status = *(int *)status; 5488c2ecf20Sopenharmony_ci return true; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic void 5528c2ecf20Sopenharmony_cirpc_wake_up_task_queue_set_status_locked(struct rpc_wait_queue *queue, 5538c2ecf20Sopenharmony_ci struct rpc_task *task, int status) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue, 5568c2ecf20Sopenharmony_ci task, rpc_task_action_set_status, &status); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * rpc_wake_up_queued_task_set_status - wake up a task and set task->tk_status 5618c2ecf20Sopenharmony_ci * @queue: pointer to rpc_wait_queue 5628c2ecf20Sopenharmony_ci * @task: pointer to rpc_task 5638c2ecf20Sopenharmony_ci * @status: integer error value 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * If @task is queued on @queue, then it is woken up, and @task->tk_status is 5668c2ecf20Sopenharmony_ci * set to the value of @status. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_civoid 5698c2ecf20Sopenharmony_cirpc_wake_up_queued_task_set_status(struct rpc_wait_queue *queue, 5708c2ecf20Sopenharmony_ci struct rpc_task *task, int status) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci if (!RPC_IS_QUEUED(task)) 5738c2ecf20Sopenharmony_ci return; 5748c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 5758c2ecf20Sopenharmony_ci rpc_wake_up_task_queue_set_status_locked(queue, task, status); 5768c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci/* 5808c2ecf20Sopenharmony_ci * Wake up the next task on a priority queue. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_cistatic struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct list_head *q; 5858c2ecf20Sopenharmony_ci struct rpc_task *task; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* 5888c2ecf20Sopenharmony_ci * Service the privileged queue. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci q = &queue->tasks[RPC_NR_PRIORITY - 1]; 5918c2ecf20Sopenharmony_ci if (queue->maxpriority > RPC_PRIORITY_PRIVILEGED && !list_empty(q)) { 5928c2ecf20Sopenharmony_ci task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 5938c2ecf20Sopenharmony_ci goto out; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Service a batch of tasks from a single owner. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_ci q = &queue->tasks[queue->priority]; 6008c2ecf20Sopenharmony_ci if (!list_empty(q) && queue->nr) { 6018c2ecf20Sopenharmony_ci queue->nr--; 6028c2ecf20Sopenharmony_ci task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 6038c2ecf20Sopenharmony_ci goto out; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* 6078c2ecf20Sopenharmony_ci * Service the next queue. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci do { 6108c2ecf20Sopenharmony_ci if (q == &queue->tasks[0]) 6118c2ecf20Sopenharmony_ci q = &queue->tasks[queue->maxpriority]; 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci q = q - 1; 6148c2ecf20Sopenharmony_ci if (!list_empty(q)) { 6158c2ecf20Sopenharmony_ci task = list_first_entry(q, struct rpc_task, u.tk_wait.list); 6168c2ecf20Sopenharmony_ci goto new_queue; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci } while (q != &queue->tasks[queue->priority]); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci rpc_reset_waitqueue_priority(queue); 6218c2ecf20Sopenharmony_ci return NULL; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cinew_queue: 6248c2ecf20Sopenharmony_ci rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0])); 6258c2ecf20Sopenharmony_ciout: 6268c2ecf20Sopenharmony_ci return task; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci if (RPC_IS_PRIORITY(queue)) 6328c2ecf20Sopenharmony_ci return __rpc_find_next_queued_priority(queue); 6338c2ecf20Sopenharmony_ci if (!list_empty(&queue->tasks[0])) 6348c2ecf20Sopenharmony_ci return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list); 6358c2ecf20Sopenharmony_ci return NULL; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci/* 6398c2ecf20Sopenharmony_ci * Wake up the first task on the wait queue. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_cistruct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, 6428c2ecf20Sopenharmony_ci struct rpc_wait_queue *queue, 6438c2ecf20Sopenharmony_ci bool (*func)(struct rpc_task *, void *), void *data) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci struct rpc_task *task = NULL; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 6488c2ecf20Sopenharmony_ci task = __rpc_find_next_queued(queue); 6498c2ecf20Sopenharmony_ci if (task != NULL) 6508c2ecf20Sopenharmony_ci task = rpc_wake_up_task_on_wq_queue_action_locked(wq, queue, 6518c2ecf20Sopenharmony_ci task, func, data); 6528c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci return task; 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci/* 6588c2ecf20Sopenharmony_ci * Wake up the first task on the wait queue. 6598c2ecf20Sopenharmony_ci */ 6608c2ecf20Sopenharmony_cistruct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue, 6618c2ecf20Sopenharmony_ci bool (*func)(struct rpc_task *, void *), void *data) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci return rpc_wake_up_first_on_wq(rpciod_workqueue, queue, func, data); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_first); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic bool rpc_wake_up_next_func(struct rpc_task *task, void *data) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci return true; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* 6738c2ecf20Sopenharmony_ci * Wake up the next task on the wait queue. 6748c2ecf20Sopenharmony_ci*/ 6758c2ecf20Sopenharmony_cistruct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_next); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/** 6828c2ecf20Sopenharmony_ci * rpc_wake_up_locked - wake up all rpc_tasks 6838c2ecf20Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 6848c2ecf20Sopenharmony_ci * 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_cistatic void rpc_wake_up_locked(struct rpc_wait_queue *queue) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct rpc_task *task; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci for (;;) { 6918c2ecf20Sopenharmony_ci task = __rpc_find_next_queued(queue); 6928c2ecf20Sopenharmony_ci if (task == NULL) 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/** 6998c2ecf20Sopenharmony_ci * rpc_wake_up - wake up all rpc_tasks 7008c2ecf20Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 7018c2ecf20Sopenharmony_ci * 7028c2ecf20Sopenharmony_ci * Grabs queue->lock 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_civoid rpc_wake_up(struct rpc_wait_queue *queue) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 7078c2ecf20Sopenharmony_ci rpc_wake_up_locked(queue); 7088c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci/** 7138c2ecf20Sopenharmony_ci * rpc_wake_up_status_locked - wake up all rpc_tasks and set their status value. 7148c2ecf20Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 7158c2ecf20Sopenharmony_ci * @status: status value to set 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_cistatic void rpc_wake_up_status_locked(struct rpc_wait_queue *queue, int status) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct rpc_task *task; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci for (;;) { 7228c2ecf20Sopenharmony_ci task = __rpc_find_next_queued(queue); 7238c2ecf20Sopenharmony_ci if (task == NULL) 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci rpc_wake_up_task_queue_set_status_locked(queue, task, status); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci/** 7308c2ecf20Sopenharmony_ci * rpc_wake_up_status - wake up all rpc_tasks and set their status value. 7318c2ecf20Sopenharmony_ci * @queue: rpc_wait_queue on which the tasks are sleeping 7328c2ecf20Sopenharmony_ci * @status: status value to set 7338c2ecf20Sopenharmony_ci * 7348c2ecf20Sopenharmony_ci * Grabs queue->lock 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_civoid rpc_wake_up_status(struct rpc_wait_queue *queue, int status) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 7398c2ecf20Sopenharmony_ci rpc_wake_up_status_locked(queue, status); 7408c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_wake_up_status); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void __rpc_queue_timer_fn(struct work_struct *work) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct rpc_wait_queue *queue = container_of(work, 7478c2ecf20Sopenharmony_ci struct rpc_wait_queue, 7488c2ecf20Sopenharmony_ci timer_list.dwork.work); 7498c2ecf20Sopenharmony_ci struct rpc_task *task, *n; 7508c2ecf20Sopenharmony_ci unsigned long expires, now, timeo; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 7538c2ecf20Sopenharmony_ci expires = now = jiffies; 7548c2ecf20Sopenharmony_ci list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) { 7558c2ecf20Sopenharmony_ci timeo = task->tk_timeout; 7568c2ecf20Sopenharmony_ci if (time_after_eq(now, timeo)) { 7578c2ecf20Sopenharmony_ci trace_rpc_task_timeout(task, task->tk_action); 7588c2ecf20Sopenharmony_ci task->tk_status = -ETIMEDOUT; 7598c2ecf20Sopenharmony_ci rpc_wake_up_task_queue_locked(queue, task); 7608c2ecf20Sopenharmony_ci continue; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci if (expires == now || time_after(expires, timeo)) 7638c2ecf20Sopenharmony_ci expires = timeo; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci if (!list_empty(&queue->timer_list.list)) 7668c2ecf20Sopenharmony_ci rpc_set_queue_timer(queue, expires); 7678c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic void __rpc_atrun(struct rpc_task *task) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci if (task->tk_status == -ETIMEDOUT) 7738c2ecf20Sopenharmony_ci task->tk_status = 0; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci/* 7778c2ecf20Sopenharmony_ci * Run a task at a later time 7788c2ecf20Sopenharmony_ci */ 7798c2ecf20Sopenharmony_civoid rpc_delay(struct rpc_task *task, unsigned long delay) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci rpc_sleep_on_timeout(&delay_queue, task, __rpc_atrun, jiffies + delay); 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_delay); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/* 7868c2ecf20Sopenharmony_ci * Helper to call task->tk_ops->rpc_call_prepare 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_civoid rpc_prepare_task(struct rpc_task *task) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci task->tk_ops->rpc_call_prepare(task, task->tk_calldata); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic void 7948c2ecf20Sopenharmony_cirpc_init_task_statistics(struct rpc_task *task) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci /* Initialize retry counters */ 7978c2ecf20Sopenharmony_ci task->tk_garb_retry = 2; 7988c2ecf20Sopenharmony_ci task->tk_cred_retry = 2; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* starting timestamp */ 8018c2ecf20Sopenharmony_ci task->tk_start = ktime_get(); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic void 8058c2ecf20Sopenharmony_cirpc_reset_task_statistics(struct rpc_task *task) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci task->tk_timeouts = 0; 8088c2ecf20Sopenharmony_ci task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_SENT); 8098c2ecf20Sopenharmony_ci rpc_init_task_statistics(task); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci/* 8138c2ecf20Sopenharmony_ci * Helper that calls task->tk_ops->rpc_call_done if it exists 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_civoid rpc_exit_task(struct rpc_task *task) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci trace_rpc_task_end(task, task->tk_action); 8188c2ecf20Sopenharmony_ci task->tk_action = NULL; 8198c2ecf20Sopenharmony_ci if (task->tk_ops->rpc_count_stats) 8208c2ecf20Sopenharmony_ci task->tk_ops->rpc_count_stats(task, task->tk_calldata); 8218c2ecf20Sopenharmony_ci else if (task->tk_client) 8228c2ecf20Sopenharmony_ci rpc_count_iostats(task, task->tk_client->cl_metrics); 8238c2ecf20Sopenharmony_ci if (task->tk_ops->rpc_call_done != NULL) { 8248c2ecf20Sopenharmony_ci task->tk_ops->rpc_call_done(task, task->tk_calldata); 8258c2ecf20Sopenharmony_ci if (task->tk_action != NULL) { 8268c2ecf20Sopenharmony_ci /* Always release the RPC slot and buffer memory */ 8278c2ecf20Sopenharmony_ci xprt_release(task); 8288c2ecf20Sopenharmony_ci rpc_reset_task_statistics(task); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_civoid rpc_signal_task(struct rpc_task *task) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci struct rpc_wait_queue *queue; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (!RPC_IS_ACTIVATED(task)) 8388c2ecf20Sopenharmony_ci return; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci trace_rpc_task_signalled(task, task->tk_action); 8418c2ecf20Sopenharmony_ci set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate); 8428c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 8438c2ecf20Sopenharmony_ci queue = READ_ONCE(task->tk_waitqueue); 8448c2ecf20Sopenharmony_ci if (queue) 8458c2ecf20Sopenharmony_ci rpc_wake_up_queued_task_set_status(queue, task, -ERESTARTSYS); 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_civoid rpc_exit(struct rpc_task *task, int status) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci task->tk_status = status; 8518c2ecf20Sopenharmony_ci task->tk_action = rpc_exit_task; 8528c2ecf20Sopenharmony_ci rpc_wake_up_queued_task(task->tk_waitqueue, task); 8538c2ecf20Sopenharmony_ci} 8548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_exit); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_civoid rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci if (ops->rpc_release != NULL) 8598c2ecf20Sopenharmony_ci ops->rpc_release(calldata); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/* 8638c2ecf20Sopenharmony_ci * This is the RPC `scheduler' (or rather, the finite state machine). 8648c2ecf20Sopenharmony_ci */ 8658c2ecf20Sopenharmony_cistatic void __rpc_execute(struct rpc_task *task) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci struct rpc_wait_queue *queue; 8688c2ecf20Sopenharmony_ci int task_is_async = RPC_IS_ASYNC(task); 8698c2ecf20Sopenharmony_ci int status = 0; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci WARN_ON_ONCE(RPC_IS_QUEUED(task)); 8728c2ecf20Sopenharmony_ci if (RPC_IS_QUEUED(task)) 8738c2ecf20Sopenharmony_ci return; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci for (;;) { 8768c2ecf20Sopenharmony_ci void (*do_action)(struct rpc_task *); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* 8798c2ecf20Sopenharmony_ci * Perform the next FSM step or a pending callback. 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci * tk_action may be NULL if the task has been killed. 8828c2ecf20Sopenharmony_ci * In particular, note that rpc_killall_tasks may 8838c2ecf20Sopenharmony_ci * do this at any time, so beware when dereferencing. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci do_action = task->tk_action; 8868c2ecf20Sopenharmony_ci if (task->tk_callback) { 8878c2ecf20Sopenharmony_ci do_action = task->tk_callback; 8888c2ecf20Sopenharmony_ci task->tk_callback = NULL; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci if (!do_action) 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci trace_rpc_task_run_action(task, do_action); 8938c2ecf20Sopenharmony_ci do_action(task); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* 8968c2ecf20Sopenharmony_ci * Lockless check for whether task is sleeping or not. 8978c2ecf20Sopenharmony_ci */ 8988c2ecf20Sopenharmony_ci if (!RPC_IS_QUEUED(task)) 8998c2ecf20Sopenharmony_ci continue; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci /* 9028c2ecf20Sopenharmony_ci * Signalled tasks should exit rather than sleep. 9038c2ecf20Sopenharmony_ci */ 9048c2ecf20Sopenharmony_ci if (RPC_SIGNALLED(task)) { 9058c2ecf20Sopenharmony_ci task->tk_rpc_status = -ERESTARTSYS; 9068c2ecf20Sopenharmony_ci rpc_exit(task, -ERESTARTSYS); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* 9108c2ecf20Sopenharmony_ci * The queue->lock protects against races with 9118c2ecf20Sopenharmony_ci * rpc_make_runnable(). 9128c2ecf20Sopenharmony_ci * 9138c2ecf20Sopenharmony_ci * Note that once we clear RPC_TASK_RUNNING on an asynchronous 9148c2ecf20Sopenharmony_ci * rpc_task, rpc_make_runnable() can assign it to a 9158c2ecf20Sopenharmony_ci * different workqueue. We therefore cannot assume that the 9168c2ecf20Sopenharmony_ci * rpc_task pointer may still be dereferenced. 9178c2ecf20Sopenharmony_ci */ 9188c2ecf20Sopenharmony_ci queue = task->tk_waitqueue; 9198c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 9208c2ecf20Sopenharmony_ci if (!RPC_IS_QUEUED(task)) { 9218c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 9228c2ecf20Sopenharmony_ci continue; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci rpc_clear_running(task); 9258c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 9268c2ecf20Sopenharmony_ci if (task_is_async) 9278c2ecf20Sopenharmony_ci return; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* sync task: sleep here */ 9308c2ecf20Sopenharmony_ci trace_rpc_task_sync_sleep(task, task->tk_action); 9318c2ecf20Sopenharmony_ci status = out_of_line_wait_on_bit(&task->tk_runstate, 9328c2ecf20Sopenharmony_ci RPC_TASK_QUEUED, rpc_wait_bit_killable, 9338c2ecf20Sopenharmony_ci TASK_KILLABLE); 9348c2ecf20Sopenharmony_ci if (status < 0) { 9358c2ecf20Sopenharmony_ci /* 9368c2ecf20Sopenharmony_ci * When a sync task receives a signal, it exits with 9378c2ecf20Sopenharmony_ci * -ERESTARTSYS. In order to catch any callbacks that 9388c2ecf20Sopenharmony_ci * clean up after sleeping on some queue, we don't 9398c2ecf20Sopenharmony_ci * break the loop here, but go around once more. 9408c2ecf20Sopenharmony_ci */ 9418c2ecf20Sopenharmony_ci trace_rpc_task_signalled(task, task->tk_action); 9428c2ecf20Sopenharmony_ci set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate); 9438c2ecf20Sopenharmony_ci task->tk_rpc_status = -ERESTARTSYS; 9448c2ecf20Sopenharmony_ci rpc_exit(task, -ERESTARTSYS); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci trace_rpc_task_sync_wake(task, task->tk_action); 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* Release all resources associated with the task */ 9508c2ecf20Sopenharmony_ci rpc_release_task(task); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci/* 9548c2ecf20Sopenharmony_ci * User-visible entry point to the scheduler. 9558c2ecf20Sopenharmony_ci * 9568c2ecf20Sopenharmony_ci * This may be called recursively if e.g. an async NFS task updates 9578c2ecf20Sopenharmony_ci * the attributes and finds that dirty pages must be flushed. 9588c2ecf20Sopenharmony_ci * NOTE: Upon exit of this function the task is guaranteed to be 9598c2ecf20Sopenharmony_ci * released. In particular note that tk_release() will have 9608c2ecf20Sopenharmony_ci * been called, so your task memory may have been freed. 9618c2ecf20Sopenharmony_ci */ 9628c2ecf20Sopenharmony_civoid rpc_execute(struct rpc_task *task) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci bool is_async = RPC_IS_ASYNC(task); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci rpc_set_active(task); 9678c2ecf20Sopenharmony_ci rpc_make_runnable(rpciod_workqueue, task); 9688c2ecf20Sopenharmony_ci if (!is_async) { 9698c2ecf20Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 9708c2ecf20Sopenharmony_ci __rpc_execute(task); 9718c2ecf20Sopenharmony_ci memalloc_nofs_restore(pflags); 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic void rpc_async_schedule(struct work_struct *work) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci __rpc_execute(container_of(work, struct rpc_task, u.tk_work)); 9808c2ecf20Sopenharmony_ci memalloc_nofs_restore(pflags); 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/** 9848c2ecf20Sopenharmony_ci * rpc_malloc - allocate RPC buffer resources 9858c2ecf20Sopenharmony_ci * @task: RPC task 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci * A single memory region is allocated, which is split between the 9888c2ecf20Sopenharmony_ci * RPC call and RPC reply that this task is being used for. When 9898c2ecf20Sopenharmony_ci * this RPC is retired, the memory is released by calling rpc_free. 9908c2ecf20Sopenharmony_ci * 9918c2ecf20Sopenharmony_ci * To prevent rpciod from hanging, this allocator never sleeps, 9928c2ecf20Sopenharmony_ci * returning -ENOMEM and suppressing warning if the request cannot 9938c2ecf20Sopenharmony_ci * be serviced immediately. The caller can arrange to sleep in a 9948c2ecf20Sopenharmony_ci * way that is safe for rpciod. 9958c2ecf20Sopenharmony_ci * 9968c2ecf20Sopenharmony_ci * Most requests are 'small' (under 2KiB) and can be serviced from a 9978c2ecf20Sopenharmony_ci * mempool, ensuring that NFS reads and writes can always proceed, 9988c2ecf20Sopenharmony_ci * and that there is good locality of reference for these buffers. 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ciint rpc_malloc(struct rpc_task *task) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci struct rpc_rqst *rqst = task->tk_rqstp; 10038c2ecf20Sopenharmony_ci size_t size = rqst->rq_callsize + rqst->rq_rcvsize; 10048c2ecf20Sopenharmony_ci struct rpc_buffer *buf; 10058c2ecf20Sopenharmony_ci gfp_t gfp = GFP_NOFS; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (RPC_IS_ASYNC(task)) 10088c2ecf20Sopenharmony_ci gfp = GFP_NOWAIT | __GFP_NOWARN; 10098c2ecf20Sopenharmony_ci if (RPC_IS_SWAPPER(task)) 10108c2ecf20Sopenharmony_ci gfp |= __GFP_MEMALLOC; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci size += sizeof(struct rpc_buffer); 10138c2ecf20Sopenharmony_ci if (size <= RPC_BUFFER_MAXSIZE) 10148c2ecf20Sopenharmony_ci buf = mempool_alloc(rpc_buffer_mempool, gfp); 10158c2ecf20Sopenharmony_ci else 10168c2ecf20Sopenharmony_ci buf = kmalloc(size, gfp); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (!buf) 10198c2ecf20Sopenharmony_ci return -ENOMEM; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci buf->len = size; 10228c2ecf20Sopenharmony_ci rqst->rq_buffer = buf->data; 10238c2ecf20Sopenharmony_ci rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize; 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_malloc); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci/** 10298c2ecf20Sopenharmony_ci * rpc_free - free RPC buffer resources allocated via rpc_malloc 10308c2ecf20Sopenharmony_ci * @task: RPC task 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci */ 10338c2ecf20Sopenharmony_civoid rpc_free(struct rpc_task *task) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci void *buffer = task->tk_rqstp->rq_buffer; 10368c2ecf20Sopenharmony_ci size_t size; 10378c2ecf20Sopenharmony_ci struct rpc_buffer *buf; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci buf = container_of(buffer, struct rpc_buffer, data); 10408c2ecf20Sopenharmony_ci size = buf->len; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (size <= RPC_BUFFER_MAXSIZE) 10438c2ecf20Sopenharmony_ci mempool_free(buf, rpc_buffer_mempool); 10448c2ecf20Sopenharmony_ci else 10458c2ecf20Sopenharmony_ci kfree(buf); 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_free); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci/* 10508c2ecf20Sopenharmony_ci * Creation and deletion of RPC task structures 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_cistatic void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci memset(task, 0, sizeof(*task)); 10558c2ecf20Sopenharmony_ci atomic_set(&task->tk_count, 1); 10568c2ecf20Sopenharmony_ci task->tk_flags = task_setup_data->flags; 10578c2ecf20Sopenharmony_ci task->tk_ops = task_setup_data->callback_ops; 10588c2ecf20Sopenharmony_ci task->tk_calldata = task_setup_data->callback_data; 10598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&task->tk_task); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; 10628c2ecf20Sopenharmony_ci task->tk_owner = current->tgid; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Initialize workqueue for async tasks */ 10658c2ecf20Sopenharmony_ci task->tk_workqueue = task_setup_data->workqueue; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci task->tk_xprt = rpc_task_get_xprt(task_setup_data->rpc_client, 10688c2ecf20Sopenharmony_ci xprt_get(task_setup_data->rpc_xprt)); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci task->tk_op_cred = get_rpccred(task_setup_data->rpc_op_cred); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (task->tk_ops->rpc_call_prepare != NULL) 10738c2ecf20Sopenharmony_ci task->tk_action = rpc_prepare_task; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci rpc_init_task_statistics(task); 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic struct rpc_task * 10798c2ecf20Sopenharmony_cirpc_alloc_task(void) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci/* 10858c2ecf20Sopenharmony_ci * Create a new task for the specified client. 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_cistruct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci struct rpc_task *task = setup_data->task; 10908c2ecf20Sopenharmony_ci unsigned short flags = 0; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (task == NULL) { 10938c2ecf20Sopenharmony_ci task = rpc_alloc_task(); 10948c2ecf20Sopenharmony_ci flags = RPC_TASK_DYNAMIC; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci rpc_init_task(task, setup_data); 10988c2ecf20Sopenharmony_ci task->tk_flags |= flags; 10998c2ecf20Sopenharmony_ci return task; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci/* 11038c2ecf20Sopenharmony_ci * rpc_free_task - release rpc task and perform cleanups 11048c2ecf20Sopenharmony_ci * 11058c2ecf20Sopenharmony_ci * Note that we free up the rpc_task _after_ rpc_release_calldata() 11068c2ecf20Sopenharmony_ci * in order to work around a workqueue dependency issue. 11078c2ecf20Sopenharmony_ci * 11088c2ecf20Sopenharmony_ci * Tejun Heo states: 11098c2ecf20Sopenharmony_ci * "Workqueue currently considers two work items to be the same if they're 11108c2ecf20Sopenharmony_ci * on the same address and won't execute them concurrently - ie. it 11118c2ecf20Sopenharmony_ci * makes a work item which is queued again while being executed wait 11128c2ecf20Sopenharmony_ci * for the previous execution to complete. 11138c2ecf20Sopenharmony_ci * 11148c2ecf20Sopenharmony_ci * If a work function frees the work item, and then waits for an event 11158c2ecf20Sopenharmony_ci * which should be performed by another work item and *that* work item 11168c2ecf20Sopenharmony_ci * recycles the freed work item, it can create a false dependency loop. 11178c2ecf20Sopenharmony_ci * There really is no reliable way to detect this short of verifying 11188c2ecf20Sopenharmony_ci * every memory free." 11198c2ecf20Sopenharmony_ci * 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_cistatic void rpc_free_task(struct rpc_task *task) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci unsigned short tk_flags = task->tk_flags; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci put_rpccred(task->tk_op_cred); 11268c2ecf20Sopenharmony_ci rpc_release_calldata(task->tk_ops, task->tk_calldata); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (tk_flags & RPC_TASK_DYNAMIC) 11298c2ecf20Sopenharmony_ci mempool_free(task, rpc_task_mempool); 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic void rpc_async_release(struct work_struct *work) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci unsigned int pflags = memalloc_nofs_save(); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci rpc_free_task(container_of(work, struct rpc_task, u.tk_work)); 11378c2ecf20Sopenharmony_ci memalloc_nofs_restore(pflags); 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic void rpc_release_resources_task(struct rpc_task *task) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci xprt_release(task); 11438c2ecf20Sopenharmony_ci if (task->tk_msg.rpc_cred) { 11448c2ecf20Sopenharmony_ci if (!(task->tk_flags & RPC_TASK_CRED_NOREF)) 11458c2ecf20Sopenharmony_ci put_cred(task->tk_msg.rpc_cred); 11468c2ecf20Sopenharmony_ci task->tk_msg.rpc_cred = NULL; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci rpc_task_release_client(task); 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic void rpc_final_put_task(struct rpc_task *task, 11528c2ecf20Sopenharmony_ci struct workqueue_struct *q) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci if (q != NULL) { 11558c2ecf20Sopenharmony_ci INIT_WORK(&task->u.tk_work, rpc_async_release); 11568c2ecf20Sopenharmony_ci queue_work(q, &task->u.tk_work); 11578c2ecf20Sopenharmony_ci } else 11588c2ecf20Sopenharmony_ci rpc_free_task(task); 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cistatic void rpc_do_put_task(struct rpc_task *task, struct workqueue_struct *q) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&task->tk_count)) { 11648c2ecf20Sopenharmony_ci rpc_release_resources_task(task); 11658c2ecf20Sopenharmony_ci rpc_final_put_task(task, q); 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_civoid rpc_put_task(struct rpc_task *task) 11708c2ecf20Sopenharmony_ci{ 11718c2ecf20Sopenharmony_ci rpc_do_put_task(task, NULL); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_put_task); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_civoid rpc_put_task_async(struct rpc_task *task) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci rpc_do_put_task(task, task->tk_workqueue); 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rpc_put_task_async); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic void rpc_release_task(struct rpc_task *task) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci WARN_ON_ONCE(RPC_IS_QUEUED(task)); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci rpc_release_resources_task(task); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* 11888c2ecf20Sopenharmony_ci * Note: at this point we have been removed from rpc_clnt->cl_tasks, 11898c2ecf20Sopenharmony_ci * so it should be safe to use task->tk_count as a test for whether 11908c2ecf20Sopenharmony_ci * or not any other processes still hold references to our rpc_task. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci if (atomic_read(&task->tk_count) != 1 + !RPC_IS_ASYNC(task)) { 11938c2ecf20Sopenharmony_ci /* Wake up anyone who may be waiting for task completion */ 11948c2ecf20Sopenharmony_ci if (!rpc_complete_task(task)) 11958c2ecf20Sopenharmony_ci return; 11968c2ecf20Sopenharmony_ci } else { 11978c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&task->tk_count)) 11988c2ecf20Sopenharmony_ci return; 11998c2ecf20Sopenharmony_ci } 12008c2ecf20Sopenharmony_ci rpc_final_put_task(task, task->tk_workqueue); 12018c2ecf20Sopenharmony_ci} 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ciint rpciod_up(void) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci return try_module_get(THIS_MODULE) ? 0 : -EINVAL; 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_civoid rpciod_down(void) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci/* 12148c2ecf20Sopenharmony_ci * Start up the rpciod workqueue. 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_cistatic int rpciod_start(void) 12178c2ecf20Sopenharmony_ci{ 12188c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* 12218c2ecf20Sopenharmony_ci * Create the rpciod thread and wait for it to start. 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_ci wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 12248c2ecf20Sopenharmony_ci if (!wq) 12258c2ecf20Sopenharmony_ci goto out_failed; 12268c2ecf20Sopenharmony_ci rpciod_workqueue = wq; 12278c2ecf20Sopenharmony_ci /* Note: highpri because network receive is latency sensitive */ 12288c2ecf20Sopenharmony_ci wq = alloc_workqueue("xprtiod", WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_HIGHPRI, 0); 12298c2ecf20Sopenharmony_ci if (!wq) 12308c2ecf20Sopenharmony_ci goto free_rpciod; 12318c2ecf20Sopenharmony_ci xprtiod_workqueue = wq; 12328c2ecf20Sopenharmony_ci return 1; 12338c2ecf20Sopenharmony_cifree_rpciod: 12348c2ecf20Sopenharmony_ci wq = rpciod_workqueue; 12358c2ecf20Sopenharmony_ci rpciod_workqueue = NULL; 12368c2ecf20Sopenharmony_ci destroy_workqueue(wq); 12378c2ecf20Sopenharmony_ciout_failed: 12388c2ecf20Sopenharmony_ci return 0; 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_cistatic void rpciod_stop(void) 12428c2ecf20Sopenharmony_ci{ 12438c2ecf20Sopenharmony_ci struct workqueue_struct *wq = NULL; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (rpciod_workqueue == NULL) 12468c2ecf20Sopenharmony_ci return; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci wq = rpciod_workqueue; 12498c2ecf20Sopenharmony_ci rpciod_workqueue = NULL; 12508c2ecf20Sopenharmony_ci destroy_workqueue(wq); 12518c2ecf20Sopenharmony_ci wq = xprtiod_workqueue; 12528c2ecf20Sopenharmony_ci xprtiod_workqueue = NULL; 12538c2ecf20Sopenharmony_ci destroy_workqueue(wq); 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_civoid 12578c2ecf20Sopenharmony_cirpc_destroy_mempool(void) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci rpciod_stop(); 12608c2ecf20Sopenharmony_ci mempool_destroy(rpc_buffer_mempool); 12618c2ecf20Sopenharmony_ci mempool_destroy(rpc_task_mempool); 12628c2ecf20Sopenharmony_ci kmem_cache_destroy(rpc_task_slabp); 12638c2ecf20Sopenharmony_ci kmem_cache_destroy(rpc_buffer_slabp); 12648c2ecf20Sopenharmony_ci rpc_destroy_wait_queue(&delay_queue); 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ciint 12688c2ecf20Sopenharmony_cirpc_init_mempool(void) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci /* 12718c2ecf20Sopenharmony_ci * The following is not strictly a mempool initialisation, 12728c2ecf20Sopenharmony_ci * but there is no harm in doing it here 12738c2ecf20Sopenharmony_ci */ 12748c2ecf20Sopenharmony_ci rpc_init_wait_queue(&delay_queue, "delayq"); 12758c2ecf20Sopenharmony_ci if (!rpciod_start()) 12768c2ecf20Sopenharmony_ci goto err_nomem; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci rpc_task_slabp = kmem_cache_create("rpc_tasks", 12798c2ecf20Sopenharmony_ci sizeof(struct rpc_task), 12808c2ecf20Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, 12818c2ecf20Sopenharmony_ci NULL); 12828c2ecf20Sopenharmony_ci if (!rpc_task_slabp) 12838c2ecf20Sopenharmony_ci goto err_nomem; 12848c2ecf20Sopenharmony_ci rpc_buffer_slabp = kmem_cache_create("rpc_buffers", 12858c2ecf20Sopenharmony_ci RPC_BUFFER_MAXSIZE, 12868c2ecf20Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, 12878c2ecf20Sopenharmony_ci NULL); 12888c2ecf20Sopenharmony_ci if (!rpc_buffer_slabp) 12898c2ecf20Sopenharmony_ci goto err_nomem; 12908c2ecf20Sopenharmony_ci rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE, 12918c2ecf20Sopenharmony_ci rpc_task_slabp); 12928c2ecf20Sopenharmony_ci if (!rpc_task_mempool) 12938c2ecf20Sopenharmony_ci goto err_nomem; 12948c2ecf20Sopenharmony_ci rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE, 12958c2ecf20Sopenharmony_ci rpc_buffer_slabp); 12968c2ecf20Sopenharmony_ci if (!rpc_buffer_mempool) 12978c2ecf20Sopenharmony_ci goto err_nomem; 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_cierr_nomem: 13008c2ecf20Sopenharmony_ci rpc_destroy_mempool(); 13018c2ecf20Sopenharmony_ci return -ENOMEM; 13028c2ecf20Sopenharmony_ci} 1303