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