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