Blame view

net/sunrpc/sched.c 32.6 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
  /*
   * linux/net/sunrpc/sched.c
   *
   * Scheduling for synchronous and asynchronous RPC requests.
   *
   * Copyright (C) 1996 Olaf Kirch, <okir@monad.swb.de>
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
15
16
17
18
19
   * TCP NFS related read + write fixes
   * (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie>
   */
  
  #include <linux/module.h>
  
  #include <linux/sched.h>
  #include <linux/interrupt.h>
  #include <linux/slab.h>
  #include <linux/mempool.h>
  #include <linux/smp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/spinlock.h>
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
21
  #include <linux/mutex.h>
d310310cb   Jeff Layton   Freezer / sunrpc ...
22
  #include <linux/freezer.h>
a1231fda7   Trond Myklebust   SUNRPC: Set memal...
23
  #include <linux/sched/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  
  #include <linux/sunrpc/clnt.h>
9dfe52a95   Dave Wysochanski   SUNRPC: Move call...
26
  #include <linux/sunrpc/metrics.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

6951867b9   Benny Halevy   nfsd41: sunrpc: m...
28
  #include "sunrpc.h"
82b0a4c3c   Trond Myklebust   SUNRPC: Add trace...
29
30
  #define CREATE_TRACE_POINTS
  #include <trace/events/sunrpc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
  /*
   * RPC slabs and memory pools
   */
  #define RPC_BUFFER_MAXSIZE	(2048)
  #define RPC_BUFFER_POOLSIZE	(8)
  #define RPC_TASK_POOLSIZE	(8)
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
37
38
  static struct kmem_cache	*rpc_task_slabp __read_mostly;
  static struct kmem_cache	*rpc_buffer_slabp __read_mostly;
ba89966c1   Eric Dumazet   [NET]: use __read...
39
40
  static mempool_t	*rpc_task_mempool __read_mostly;
  static mempool_t	*rpc_buffer_mempool __read_mostly;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41

65f27f384   David Howells   WorkStruct: Pass ...
42
  static void			rpc_async_schedule(struct work_struct *);
bde8f00ce   Trond Myklebust   [PATCH] NFS: Fix ...
43
  static void			 rpc_release_task(struct rpc_task *task);
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
44
  static void __rpc_queue_timer_fn(struct work_struct *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
   * RPC tasks sit here while waiting for conditions to improve.
   */
a4a874990   Trond Myklebust   SUNRPC: Cleanup t...
49
  static struct rpc_wait_queue delay_queue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
   * rpciod-related stuff
   */
40a5f1b19   Trond Myklebust   SUNRPC: RPC trans...
54
55
  struct workqueue_struct *rpciod_workqueue __read_mostly;
  struct workqueue_struct *xprtiod_workqueue __read_mostly;
675dd90ad   Chuck Lever   xprtrdma: Moderni...
56
  EXPORT_SYMBOL_GPL(xprtiod_workqueue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

5efd1876e   Trond Myklebust   SUNRPC: Fix up tr...
58
59
60
61
62
63
64
65
66
67
68
69
70
  unsigned long
  rpc_task_timeout(const struct rpc_task *task)
  {
  	unsigned long timeout = READ_ONCE(task->tk_timeout);
  
  	if (timeout != 0) {
  		unsigned long now = jiffies;
  		if (time_before(now, timeout))
  			return timeout - now;
  	}
  	return 0;
  }
  EXPORT_SYMBOL_GPL(rpc_task_timeout);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
   * Disable the timer for a given RPC task. Should be called with
   * queue->lock and bh_disabled in order to avoid races within
   * rpc_run_timer().
   */
5d00837b9   Trond Myklebust   SUNRPC: Run rpc t...
76
  static void
eb276c0e1   Trond Myklebust   SUNRPC: Switch ta...
77
  __rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  {
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
79
  	if (list_empty(&task->u.tk_wait.timer_list))
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
80
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  	task->tk_timeout = 0;
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
82
  	list_del(&task->u.tk_wait.timer_list);
eb276c0e1   Trond Myklebust   SUNRPC: Switch ta...
83
  	if (list_empty(&queue->timer_list.list))
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
84
  		cancel_delayed_work(&queue->timer_list.dwork);
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
85
86
87
88
89
  }
  
  static void
  rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires)
  {
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
90
91
92
93
94
95
96
  	unsigned long now = jiffies;
  	queue->timer_list.expires = expires;
  	if (time_before_eq(expires, now))
  		expires = 0;
  	else
  		expires -= now;
  	mod_delayed_work(rpciod_workqueue, &queue->timer_list.dwork, expires);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
   * Set up a timer for the current task.
   */
5d00837b9   Trond Myklebust   SUNRPC: Run rpc t...
102
  static void
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
103
104
  __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task,
  		unsigned long timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
106
  	task->tk_timeout = timeout;
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
107
108
  	if (list_empty(&queue->timer_list.list) || time_before(timeout, queue->timer_list.expires))
  		rpc_set_queue_timer(queue, timeout);
eb276c0e1   Trond Myklebust   SUNRPC: Switch ta...
109
  	list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  }
c05eecf63   Trond Myklebust   SUNRPC: Don't all...
111
112
  static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
  {
edd2e36fe   Trond Myklebust   SUNRPC: When chan...
113
  	if (queue->priority != priority) {
edd2e36fe   Trond Myklebust   SUNRPC: When chan...
114
  		queue->priority = priority;
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
115
  		queue->nr = 1U << priority;
edd2e36fe   Trond Myklebust   SUNRPC: When chan...
116
  	}
c05eecf63   Trond Myklebust   SUNRPC: Don't all...
117
  }
c05eecf63   Trond Myklebust   SUNRPC: Don't all...
118
119
120
  static void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
  {
  	rpc_set_waitqueue_priority(queue, queue->maxpriority);
c05eecf63   Trond Myklebust   SUNRPC: Don't all...
121
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  /*
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
123
   * Add a request to a queue list
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
   */
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
125
126
  static void
  __rpc_list_enqueue_task(struct list_head *q, struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  	struct rpc_task *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  	list_for_each_entry(t, q, u.tk_wait.list) {
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
130
  		if (t->tk_owner == task->tk_owner) {
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
131
132
133
134
135
  			list_add_tail(&task->u.tk_wait.links,
  					&t->u.tk_wait.links);
  			/* Cache the queue head in task->u.tk_wait.list */
  			task->u.tk_wait.list.next = q;
  			task->u.tk_wait.list.prev = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
  			return;
  		}
  	}
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
139
  	INIT_LIST_HEAD(&task->u.tk_wait.links);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  	list_add_tail(&task->u.tk_wait.list, q);
  }
  
  /*
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
   * Remove request from a queue list
   */
  static void
  __rpc_list_dequeue_task(struct rpc_task *task)
  {
  	struct list_head *q;
  	struct rpc_task *t;
  
  	if (task->u.tk_wait.list.prev == NULL) {
  		list_del(&task->u.tk_wait.links);
  		return;
  	}
  	if (!list_empty(&task->u.tk_wait.links)) {
  		t = list_first_entry(&task->u.tk_wait.links,
  				struct rpc_task,
  				u.tk_wait.links);
  		/* Assume __rpc_list_enqueue_task() cached the queue head */
  		q = t->u.tk_wait.list.next;
  		list_add_tail(&t->u.tk_wait.list, q);
  		list_del(&task->u.tk_wait.links);
  	}
  	list_del(&task->u.tk_wait.list);
  }
  
  /*
   * Add new request to a priority queue.
   */
  static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue,
  		struct rpc_task *task,
  		unsigned char queue_priority)
  {
  	if (unlikely(queue_priority > queue->maxpriority))
  		queue_priority = queue->maxpriority;
  	__rpc_list_enqueue_task(&queue->tasks[queue_priority], task);
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
   * Add new request to wait queue.
   *
   * Swapper tasks always get inserted at the head of the queue.
   * This should avoid many nasty memory deadlocks and hopefully
   * improve overall performance.
   * Everyone else gets appended to the queue to ensure proper FIFO behavior.
   */
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
188
189
190
  static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
  		struct rpc_task *task,
  		unsigned char queue_priority)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  {
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
192
  	INIT_LIST_HEAD(&task->u.tk_wait.timer_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  	if (RPC_IS_PRIORITY(queue))
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
194
  		__rpc_add_wait_queue_priority(queue, task, queue_priority);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
  	else if (RPC_IS_SWAPPER(task))
  		list_add(&task->u.tk_wait.list, &queue->tasks[0]);
  	else
  		list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
199
  	task->tk_waitqueue = queue;
e19b63daf   Chuck Lever   SUNRPC: track len...
200
  	queue->qlen++;
1166fde6a   Trond Myklebust   SUNRPC: Add barri...
201
202
  	/* barrier matches the read in rpc_wake_up_task_queue_locked() */
  	smp_wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	rpc_set_queued(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
210
  }
  
  /*
   * Remove request from a priority queue.
   */
  static void __rpc_remove_wait_queue_priority(struct rpc_task *task)
  {
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
211
  	__rpc_list_dequeue_task(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
  }
  
  /*
   * Remove request from queue.
   * Note: must be called with spin lock held.
   */
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
218
  static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  {
eb276c0e1   Trond Myklebust   SUNRPC: Switch ta...
220
  	__rpc_disable_timer(queue, task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
  	if (RPC_IS_PRIORITY(queue))
  		__rpc_remove_wait_queue_priority(task);
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
223
224
  	else
  		list_del(&task->u.tk_wait.list);
e19b63daf   Chuck Lever   SUNRPC: track len...
225
  	queue->qlen--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  }
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
227
  static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
233
  {
  	int i;
  
  	spin_lock_init(&queue->lock);
  	for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
  		INIT_LIST_HEAD(&queue->tasks[i]);
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
234
  	queue->maxpriority = nr_queues - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	rpc_reset_waitqueue_priority(queue);
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
236
  	queue->qlen = 0;
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
237
  	queue->timer_list.expires = 0;
66eb3add4   Trond Myklebust   SUNRPC: Avoid RPC...
238
  	INIT_DELAYED_WORK(&queue->timer_list.dwork, __rpc_queue_timer_fn);
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
239
  	INIT_LIST_HEAD(&queue->timer_list.list);
2f09c2421   Trond Myklebust   SUNRPC: Ensure th...
240
  	rpc_assign_waitqueue_name(queue, qname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
  }
  
  void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
  {
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
245
  	__rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  }
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
247
  EXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
  
  void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
  {
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
251
  	__rpc_init_priority_wait_queue(queue, qname, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
253
  EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254

f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
255
256
  void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
  {
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
257
  	cancel_delayed_work_sync(&queue->timer_list.dwork);
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
258
259
  }
  EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
dfd01f026   Peter Zijlstra   sched/wait: Fix t...
260
  static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
44c288732   Trond Myklebust   NFSv4: stateful N...
261
  {
416ad3c9c   Colin Cross   freezer: add unsa...
262
  	freezable_schedule_unsafe();
dfd01f026   Peter Zijlstra   sched/wait: Fix t...
263
264
  	if (signal_pending_state(mode, current))
  		return -ERESTARTSYS;
44c288732   Trond Myklebust   NFSv4: stateful N...
265
266
  	return 0;
  }
1306729b0   Jeff Layton   sunrpc: eliminate...
267
  #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
c44fe7055   Trond Myklebust   SUNRPC: Clean up ...
268
269
270
  static void rpc_task_set_debuginfo(struct rpc_task *task)
  {
  	static atomic_t rpc_pid;
c44fe7055   Trond Myklebust   SUNRPC: Clean up ...
271
272
273
274
275
276
277
  	task->tk_pid = atomic_inc_return(&rpc_pid);
  }
  #else
  static inline void rpc_task_set_debuginfo(struct rpc_task *task)
  {
  }
  #endif
e6b3c4db6   Trond Myklebust   Fix a second pote...
278
279
  static void rpc_set_active(struct rpc_task *task)
  {
c44fe7055   Trond Myklebust   SUNRPC: Clean up ...
280
  	rpc_task_set_debuginfo(task);
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
281
  	set_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
e671edb94   Chuck Lever   sunrpc: Simplify ...
282
  	trace_rpc_task_begin(task, NULL);
e6b3c4db6   Trond Myklebust   Fix a second pote...
283
  }
44c288732   Trond Myklebust   NFSv4: stateful N...
284
285
  /*
   * Mark an RPC call as having completed by clearing the 'active' bit
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
286
   * and then waking up all tasks that were sleeping.
44c288732   Trond Myklebust   NFSv4: stateful N...
287
   */
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
288
  static int rpc_complete_task(struct rpc_task *task)
44c288732   Trond Myklebust   NFSv4: stateful N...
289
  {
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
290
291
292
293
294
  	void *m = &task->tk_runstate;
  	wait_queue_head_t *wq = bit_waitqueue(m, RPC_TASK_ACTIVE);
  	struct wait_bit_key k = __WAIT_BIT_KEY_INITIALIZER(m, RPC_TASK_ACTIVE);
  	unsigned long flags;
  	int ret;
e671edb94   Chuck Lever   sunrpc: Simplify ...
295
  	trace_rpc_task_complete(task, NULL);
82b0a4c3c   Trond Myklebust   SUNRPC: Add trace...
296

bf294b41c   Trond Myklebust   SUNRPC: Close a r...
297
  	spin_lock_irqsave(&wq->lock, flags);
e6b3c4db6   Trond Myklebust   Fix a second pote...
298
  	clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
299
300
  	ret = atomic_dec_and_test(&task->tk_count);
  	if (waitqueue_active(wq))
ac5be6b47   Andrea Arcangeli   userfaultfd: reve...
301
  		__wake_up_locked_key(wq, TASK_NORMAL, &k);
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
302
303
  	spin_unlock_irqrestore(&wq->lock, flags);
  	return ret;
44c288732   Trond Myklebust   NFSv4: stateful N...
304
305
306
307
  }
  
  /*
   * Allow callers to wait for completion of an RPC call
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
308
309
310
311
   *
   * Note the use of out_of_line_wait_on_bit() rather than wait_on_bit()
   * to enforce taking of the wq->lock and hence avoid races with
   * rpc_complete_task().
44c288732   Trond Myklebust   NFSv4: stateful N...
312
   */
c1221321b   NeilBrown   sched: Allow wait...
313
  int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *action)
44c288732   Trond Myklebust   NFSv4: stateful N...
314
315
  {
  	if (action == NULL)
150030b78   Matthew Wilcox   NFS: Switch from ...
316
  		action = rpc_wait_bit_killable;
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
317
  	return out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
150030b78   Matthew Wilcox   NFS: Switch from ...
318
  			action, TASK_KILLABLE);
44c288732   Trond Myklebust   NFSv4: stateful N...
319
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
320
  EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
44c288732   Trond Myklebust   NFSv4: stateful N...
321

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
  /*
   * Make an RPC task runnable.
   *
506026c3e   Jeff Layton   sunrpc: clarify c...
325
326
327
   * Note: If the task is ASYNC, and is being made runnable after sitting on an
   * rpc_wait_queue, this must be called with the queue spinlock held to protect
   * the wait queue operation.
a3c3cac5d   Trond Myklebust   SUNRPC: Prevent a...
328
329
330
331
   * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(),
   * which is needed to ensure that __rpc_execute() doesn't loop (due to the
   * lockless RPC_IS_QUEUED() test) before we've had a chance to test
   * the RPC_TASK_RUNNING flag.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
   */
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
333
334
  static void rpc_make_runnable(struct workqueue_struct *wq,
  		struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  {
a3c3cac5d   Trond Myklebust   SUNRPC: Prevent a...
336
  	bool need_wakeup = !rpc_test_and_set_running(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	rpc_clear_queued(task);
a3c3cac5d   Trond Myklebust   SUNRPC: Prevent a...
338
  	if (!need_wakeup)
cc4dc59e5   Christophe Saout   Subject: Re: [PAT...
339
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  	if (RPC_IS_ASYNC(task)) {
65f27f384   David Howells   WorkStruct: Pass ...
341
  		INIT_WORK(&task->u.tk_work, rpc_async_schedule);
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
342
  		queue_work(wq, &task->u.tk_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  	} else
96651ab34   Trond Myklebust   [PATCH] RPC: Shri...
344
  		wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
349
350
351
352
   * Prepare for sleeping on a wait queue.
   * By always appending tasks to the list we ensure FIFO behavior.
   * NB: An RPC task will only receive interrupt-driven events as long
   * as it's on a wait queue.
   */
1fab7dc47   Trond Myklebust   SUNRPC: Don't sta...
353
  static void __rpc_do_sleep_on_priority(struct rpc_wait_queue *q,
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
354
  		struct rpc_task *task,
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
355
  		unsigned char queue_priority)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  {
e671edb94   Chuck Lever   sunrpc: Simplify ...
357
  	trace_rpc_task_sleep(task, q);
82b0a4c3c   Trond Myklebust   SUNRPC: Add trace...
358

3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
359
  	__rpc_add_wait_queue(q, task, queue_priority);
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
360
  }
1fab7dc47   Trond Myklebust   SUNRPC: Don't sta...
361
362
363
364
365
366
367
368
  static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
  		struct rpc_task *task,
  		unsigned char queue_priority)
  {
  	if (WARN_ON_ONCE(RPC_IS_QUEUED(task)))
  		return;
  	__rpc_do_sleep_on_priority(q, task, queue_priority);
  }
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
369
370
371
372
  static void __rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q,
  		struct rpc_task *task, unsigned long timeout,
  		unsigned char queue_priority)
  {
1fab7dc47   Trond Myklebust   SUNRPC: Don't sta...
373
374
  	if (WARN_ON_ONCE(RPC_IS_QUEUED(task)))
  		return;
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
375
  	if (time_is_after_jiffies(timeout)) {
1fab7dc47   Trond Myklebust   SUNRPC: Don't sta...
376
  		__rpc_do_sleep_on_priority(q, task, queue_priority);
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
377
378
379
  		__rpc_add_timer(q, task, timeout);
  	} else
  		task->tk_status = -ETIMEDOUT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  }
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
381
382
383
384
385
386
387
  static void rpc_set_tk_callback(struct rpc_task *task, rpc_action action)
  {
  	if (action && !WARN_ON_ONCE(task->tk_callback != NULL))
  		task->tk_callback = action;
  }
  
  static bool rpc_sleep_check_activated(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  {
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
389
  	/* We shouldn't ever put an inactive task to sleep */
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
390
  	if (WARN_ON_ONCE(!RPC_IS_ACTIVATED(task))) {
e454a7a83   Weston Andros Adamson   SUNRPC: remove BU...
391
392
  		task->tk_status = -EIO;
  		rpc_put_task_async(task);
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
393
  		return false;
e454a7a83   Weston Andros Adamson   SUNRPC: remove BU...
394
  	}
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
395
396
  	return true;
  }
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
397
398
399
400
401
402
403
404
405
406
407
  void rpc_sleep_on_timeout(struct rpc_wait_queue *q, struct rpc_task *task,
  				rpc_action action, unsigned long timeout)
  {
  	if (!rpc_sleep_check_activated(task))
  		return;
  
  	rpc_set_tk_callback(task, action);
  
  	/*
  	 * Protect the queue operations.
  	 */
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
408
  	spin_lock(&q->lock);
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
409
  	__rpc_sleep_on_priority_timeout(q, task, timeout, task->tk_priority);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
410
  	spin_unlock(&q->lock);
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
411
412
  }
  EXPORT_SYMBOL_GPL(rpc_sleep_on_timeout);
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
413
414
415
416
417
418
419
  void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
  				rpc_action action)
  {
  	if (!rpc_sleep_check_activated(task))
  		return;
  
  	rpc_set_tk_callback(task, action);
e6b3c4db6   Trond Myklebust   Fix a second pote...
420

6b2e68562   Trond Myklebust   SUNRPC: Add funct...
421
  	WARN_ON_ONCE(task->tk_timeout != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
  	/*
  	 * Protect the queue operations.
  	 */
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
425
  	spin_lock(&q->lock);
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
426
  	__rpc_sleep_on_priority(q, task, task->tk_priority);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
427
  	spin_unlock(&q->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
429
  EXPORT_SYMBOL_GPL(rpc_sleep_on);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430

6b2e68562   Trond Myklebust   SUNRPC: Add funct...
431
432
433
434
435
436
437
438
439
440
  void rpc_sleep_on_priority_timeout(struct rpc_wait_queue *q,
  		struct rpc_task *task, unsigned long timeout, int priority)
  {
  	if (!rpc_sleep_check_activated(task))
  		return;
  
  	priority -= RPC_PRIORITY_LOW;
  	/*
  	 * Protect the queue operations.
  	 */
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
441
  	spin_lock(&q->lock);
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
442
  	__rpc_sleep_on_priority_timeout(q, task, timeout, priority);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
443
  	spin_unlock(&q->lock);
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
444
445
  }
  EXPORT_SYMBOL_GPL(rpc_sleep_on_priority_timeout);
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
446
  void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
8357a9b60   Trond Myklebust   SUNRPC: Remove un...
447
  		int priority)
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
448
  {
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
449
  	if (!rpc_sleep_check_activated(task))
e454a7a83   Weston Andros Adamson   SUNRPC: remove BU...
450
  		return;
87150aaed   Trond Myklebust   SUNRPC: Refactor ...
451

6b2e68562   Trond Myklebust   SUNRPC: Add funct...
452
  	WARN_ON_ONCE(task->tk_timeout != 0);
8357a9b60   Trond Myklebust   SUNRPC: Remove un...
453
  	priority -= RPC_PRIORITY_LOW;
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
454
455
456
  	/*
  	 * Protect the queue operations.
  	 */
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
457
  	spin_lock(&q->lock);
8357a9b60   Trond Myklebust   SUNRPC: Remove un...
458
  	__rpc_sleep_on_priority(q, task, priority);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
459
  	spin_unlock(&q->lock);
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
460
  }
1e1093c7f   Trond Myklebust   NFSv4.1: Don't me...
461
  EXPORT_SYMBOL_GPL(rpc_sleep_on_priority);
3b27bad7f   Trond Myklebust   SUNRPC: Allow cal...
462

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  /**
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
464
465
   * __rpc_do_wake_up_task_on_wq - wake up a single rpc_task
   * @wq: workqueue on which to run task
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
466
   * @queue: wait queue
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
   * @task: task to be woken up
   *
   * Caller must hold queue->lock, and have cleared the task queued flag.
   */
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
471
472
473
  static void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq,
  		struct rpc_wait_queue *queue,
  		struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
  	/* Has the task been executed yet? If not, we cannot wake it up! */
  	if (!RPC_IS_ACTIVATED(task)) {
  		printk(KERN_ERR "RPC: Inactive task (%p) being woken up!
  ", task);
  		return;
  	}
e671edb94   Chuck Lever   sunrpc: Simplify ...
481
  	trace_rpc_task_wakeup(task, queue);
82b0a4c3c   Trond Myklebust   SUNRPC: Add trace...
482

96ef13b28   Trond Myklebust   SUNRPC: Add a new...
483
  	__rpc_remove_wait_queue(queue, task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484

f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
485
  	rpc_make_runnable(wq, task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
  }
  
  /*
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
489
   * Wake up a queued task while the queue lock is being held
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
   */
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
491
492
493
494
  static struct rpc_task *
  rpc_wake_up_task_on_wq_queue_action_locked(struct workqueue_struct *wq,
  		struct rpc_wait_queue *queue, struct rpc_task *task,
  		bool (*action)(struct rpc_task *, void *), void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  {
1166fde6a   Trond Myklebust   SUNRPC: Add barri...
496
497
  	if (RPC_IS_QUEUED(task)) {
  		smp_rmb();
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
498
499
500
501
502
503
  		if (task->tk_waitqueue == queue) {
  			if (action == NULL || action(task, data)) {
  				__rpc_do_wake_up_task_on_wq(wq, queue, task);
  				return task;
  			}
  		}
1166fde6a   Trond Myklebust   SUNRPC: Add barri...
504
  	}
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
505
506
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  /*
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
508
509
   * Wake up a queued task while the queue lock is being held
   */
691b45ddb   Chuck Lever   SUNRPC: Remove rp...
510
511
  static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue,
  					  struct rpc_task *task)
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
512
  {
691b45ddb   Chuck Lever   SUNRPC: Remove rp...
513
514
  	rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue,
  						   task, NULL, NULL);
2275cde4c   Trond Myklebust   SUNRPC: Queue lat...
515
516
517
518
519
  }
  
  /*
   * Wake up a task on a specific queue
   */
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
520
  void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  {
5ce970393   Trond Myklebust   SUNRPC: Test whet...
522
523
  	if (!RPC_IS_QUEUED(task))
  		return;
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
524
  	spin_lock(&queue->lock);
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
525
  	rpc_wake_up_task_queue_locked(queue, task);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
526
  	spin_unlock(&queue->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  }
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
528
  EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task);
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  static bool rpc_task_action_set_status(struct rpc_task *task, void *status)
  {
  	task->tk_status = *(int *)status;
  	return true;
  }
  
  static void
  rpc_wake_up_task_queue_set_status_locked(struct rpc_wait_queue *queue,
  		struct rpc_task *task, int status)
  {
  	rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue,
  			task, rpc_task_action_set_status, &status);
  }
  
  /**
   * rpc_wake_up_queued_task_set_status - wake up a task and set task->tk_status
   * @queue: pointer to rpc_wait_queue
   * @task: pointer to rpc_task
   * @status: integer error value
   *
   * If @task is queued on @queue, then it is woken up, and @task->tk_status is
   * set to the value of @status.
   */
  void
  rpc_wake_up_queued_task_set_status(struct rpc_wait_queue *queue,
  		struct rpc_task *task, int status)
  {
  	if (!RPC_IS_QUEUED(task))
  		return;
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
558
  	spin_lock(&queue->lock);
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
559
  	rpc_wake_up_task_queue_set_status_locked(queue, task, status);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
560
  	spin_unlock(&queue->lock);
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
561
  }
96ef13b28   Trond Myklebust   SUNRPC: Add a new...
562
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
   * Wake up the next task on a priority queue.
   */
961a828df   Trond Myklebust   SUNRPC: Fix poten...
565
  static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
  {
  	struct list_head *q;
  	struct rpc_task *task;
  
  	/*
3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
571
  	 * Service a batch of tasks from a single owner.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  	 */
  	q = &queue->tasks[queue->priority];
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
574
575
576
  	if (!list_empty(q) && --queue->nr) {
  		task = list_first_entry(q, struct rpc_task, u.tk_wait.list);
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
581
582
583
584
585
586
587
  	}
  
  	/*
  	 * Service the next queue.
  	 */
  	do {
  		if (q == &queue->tasks[0])
  			q = &queue->tasks[queue->maxpriority];
  		else
  			q = q - 1;
  		if (!list_empty(q)) {
f42f7c283   Trond Myklebust   SUNRPC: Fix prior...
588
  			task = list_first_entry(q, struct rpc_task, u.tk_wait.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
597
  			goto new_queue;
  		}
  	} while (q != &queue->tasks[queue->priority]);
  
  	rpc_reset_waitqueue_priority(queue);
  	return NULL;
  
  new_queue:
  	rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
  	return task;
  }
961a828df   Trond Myklebust   SUNRPC: Fix poten...
601
602
603
604
605
606
607
608
  static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue)
  {
  	if (RPC_IS_PRIORITY(queue))
  		return __rpc_find_next_queued_priority(queue);
  	if (!list_empty(&queue->tasks[0]))
  		return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list);
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  /*
961a828df   Trond Myklebust   SUNRPC: Fix poten...
610
   * Wake up the first task on the wait queue.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
   */
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
612
613
  struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq,
  		struct rpc_wait_queue *queue,
961a828df   Trond Myklebust   SUNRPC: Fix poten...
614
  		bool (*func)(struct rpc_task *, void *), void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
  {
  	struct rpc_task	*task = NULL;
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
617
  	spin_lock(&queue->lock);
961a828df   Trond Myklebust   SUNRPC: Fix poten...
618
  	task = __rpc_find_next_queued(queue);
359c48c04   Trond Myklebust   SUNRPC: Add a hel...
619
620
621
  	if (task != NULL)
  		task = rpc_wake_up_task_on_wq_queue_action_locked(wq, queue,
  				task, func, data);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
622
  	spin_unlock(&queue->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
623
624
625
  
  	return task;
  }
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
626
627
628
629
630
631
632
633
634
  
  /*
   * Wake up the first task on the wait queue.
   */
  struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue,
  		bool (*func)(struct rpc_task *, void *), void *data)
  {
  	return rpc_wake_up_first_on_wq(rpciod_workqueue, queue, func, data);
  }
961a828df   Trond Myklebust   SUNRPC: Fix poten...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  EXPORT_SYMBOL_GPL(rpc_wake_up_first);
  
  static bool rpc_wake_up_next_func(struct rpc_task *task, void *data)
  {
  	return true;
  }
  
  /*
   * Wake up the next task on the wait queue.
  */
  struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue)
  {
  	return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL);
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
649
  EXPORT_SYMBOL_GPL(rpc_wake_up_next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
  
  /**
d1296acac   Trond Myklebust   SUNRPC: rpc_wake_...
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
   * rpc_wake_up_locked - wake up all rpc_tasks
   * @queue: rpc_wait_queue on which the tasks are sleeping
   *
   */
  static void rpc_wake_up_locked(struct rpc_wait_queue *queue)
  {
  	struct rpc_task *task;
  
  	for (;;) {
  		task = __rpc_find_next_queued(queue);
  		if (task == NULL)
  			break;
  		rpc_wake_up_task_queue_locked(queue, task);
  	}
  }
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
   * rpc_wake_up - wake up all rpc_tasks
   * @queue: rpc_wait_queue on which the tasks are sleeping
   *
   * Grabs queue->lock
   */
  void rpc_wake_up(struct rpc_wait_queue *queue)
  {
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
676
  	spin_lock(&queue->lock);
d1296acac   Trond Myklebust   SUNRPC: rpc_wake_...
677
678
679
680
681
682
683
684
685
686
687
688
689
  	rpc_wake_up_locked(queue);
  	spin_unlock(&queue->lock);
  }
  EXPORT_SYMBOL_GPL(rpc_wake_up);
  
  /**
   * rpc_wake_up_status_locked - wake up all rpc_tasks and set their status value.
   * @queue: rpc_wait_queue on which the tasks are sleeping
   * @status: status value to set
   */
  static void rpc_wake_up_status_locked(struct rpc_wait_queue *queue, int status)
  {
  	struct rpc_task *task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
  	for (;;) {
d1296acac   Trond Myklebust   SUNRPC: rpc_wake_...
691
692
  		task = __rpc_find_next_queued(queue);
  		if (task == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  			break;
d1296acac   Trond Myklebust   SUNRPC: rpc_wake_...
694
  		rpc_wake_up_task_queue_set_status_locked(queue, task, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
701
702
703
704
705
706
  }
  
  /**
   * rpc_wake_up_status - wake up all rpc_tasks and set their status value.
   * @queue: rpc_wait_queue on which the tasks are sleeping
   * @status: status value to set
   *
   * Grabs queue->lock
   */
  void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
  {
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
707
  	spin_lock(&queue->lock);
d1296acac   Trond Myklebust   SUNRPC: rpc_wake_...
708
  	rpc_wake_up_status_locked(queue, status);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
709
  	spin_unlock(&queue->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
711
  EXPORT_SYMBOL_GPL(rpc_wake_up_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712

7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
713
  static void __rpc_queue_timer_fn(struct work_struct *work)
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
714
  {
7e0a0e38f   Trond Myklebust   SUNRPC: Replace t...
715
716
717
  	struct rpc_wait_queue *queue = container_of(work,
  			struct rpc_wait_queue,
  			timer_list.dwork.work);
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
718
719
720
721
722
723
  	struct rpc_task *task, *n;
  	unsigned long expires, now, timeo;
  
  	spin_lock(&queue->lock);
  	expires = now = jiffies;
  	list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) {
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
724
  		timeo = task->tk_timeout;
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
725
  		if (time_after_eq(now, timeo)) {
721a1d388   Chuck Lever   SUNRPC: Remove dp...
726
  			trace_rpc_task_timeout(task, task->tk_action);
36df9aae3   Trond Myklebust   SUNRPC: Add a tim...
727
728
729
730
731
732
733
734
735
736
737
  			task->tk_status = -ETIMEDOUT;
  			rpc_wake_up_task_queue_locked(queue, task);
  			continue;
  		}
  		if (expires == now || time_after(expires, timeo))
  			expires = timeo;
  	}
  	if (!list_empty(&queue->timer_list.list))
  		rpc_set_queue_timer(queue, expires);
  	spin_unlock(&queue->lock);
  }
8014793b1   Trond Myklebust   SUNRPC: rpc_delay...
738
739
  static void __rpc_atrun(struct rpc_task *task)
  {
6bd144160   Trond Myklebust   SUNRPC: Don't let...
740
741
  	if (task->tk_status == -ETIMEDOUT)
  		task->tk_status = 0;
8014793b1   Trond Myklebust   SUNRPC: rpc_delay...
742
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
  /*
   * Run a task at a later time
   */
8014793b1   Trond Myklebust   SUNRPC: rpc_delay...
746
  void rpc_delay(struct rpc_task *task, unsigned long delay)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  {
6b2e68562   Trond Myklebust   SUNRPC: Add funct...
748
  	rpc_sleep_on_timeout(&delay_queue, task, __rpc_atrun, jiffies + delay);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
750
  EXPORT_SYMBOL_GPL(rpc_delay);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  /*
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
753
754
   * Helper to call task->tk_ops->rpc_call_prepare
   */
aae2006e9   Andy Adamson   nfs41: sunrpc: Ex...
755
  void rpc_prepare_task(struct rpc_task *task)
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
756
757
758
  {
  	task->tk_ops->rpc_call_prepare(task, task->tk_calldata);
  }
7fdcf13b2   Trond Myklebust   SUNRPC: Fix the e...
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  static void
  rpc_init_task_statistics(struct rpc_task *task)
  {
  	/* Initialize retry counters */
  	task->tk_garb_retry = 2;
  	task->tk_cred_retry = 2;
  	task->tk_rebind_retry = 2;
  
  	/* starting timestamp */
  	task->tk_start = ktime_get();
  }
  
  static void
  rpc_reset_task_statistics(struct rpc_task *task)
  {
  	task->tk_timeouts = 0;
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
775
  	task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_SENT);
7fdcf13b2   Trond Myklebust   SUNRPC: Fix the e...
776
777
  	rpc_init_task_statistics(task);
  }
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
778
  /*
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
779
   * Helper that calls task->tk_ops->rpc_call_done if it exists
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
780
   */
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
781
  void rpc_exit_task(struct rpc_task *task)
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
782
  {
a264abad5   Chuck Lever   SUNRPC: Capture c...
783
  	trace_rpc_task_end(task, task->tk_action);
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
784
  	task->tk_action = NULL;
9dfe52a95   Dave Wysochanski   SUNRPC: Move call...
785
786
787
788
  	if (task->tk_ops->rpc_count_stats)
  		task->tk_ops->rpc_count_stats(task, task->tk_calldata);
  	else if (task->tk_client)
  		rpc_count_iostats(task, task->tk_client->cl_metrics);
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
789
790
  	if (task->tk_ops->rpc_call_done != NULL) {
  		task->tk_ops->rpc_call_done(task, task->tk_calldata);
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
791
  		if (task->tk_action != NULL) {
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
792
793
  			/* Always release the RPC slot and buffer memory */
  			xprt_release(task);
7fdcf13b2   Trond Myklebust   SUNRPC: Fix the e...
794
  			rpc_reset_task_statistics(task);
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
795
796
  		}
  	}
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
797
  }
d9b6cd946   Trond Myklebust   SUNRPC: Ensure th...
798

ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
799
800
801
802
803
804
  void rpc_signal_task(struct rpc_task *task)
  {
  	struct rpc_wait_queue *queue;
  
  	if (!RPC_IS_ACTIVATED(task))
  		return;
abf8af78a   Chuck Lever   SUNRPC: Capture s...
805
806
  
  	trace_rpc_task_signalled(task, task->tk_action);
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
807
808
809
810
811
812
  	set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate);
  	smp_mb__after_atomic();
  	queue = READ_ONCE(task->tk_waitqueue);
  	if (queue)
  		rpc_wake_up_queued_task_set_status(queue, task, -ERESTARTSYS);
  }
d9b6cd946   Trond Myklebust   SUNRPC: Ensure th...
813
814
815
816
  void rpc_exit(struct rpc_task *task, int status)
  {
  	task->tk_status = status;
  	task->tk_action = rpc_exit_task;
6b5f59001   Trond Myklebust   SUNRPC: Remove re...
817
  	rpc_wake_up_queued_task(task->tk_waitqueue, task);
d9b6cd946   Trond Myklebust   SUNRPC: Ensure th...
818
819
  }
  EXPORT_SYMBOL_GPL(rpc_exit);
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
820

bbd5a1f9f   Trond Myklebust   SUNRPC: Fix up mi...
821
822
  void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
  {
a86dc496b   Trond Myklebust   SUNRPC: Remove th...
823
  	if (ops->rpc_release != NULL)
bbd5a1f9f   Trond Myklebust   SUNRPC: Fix up mi...
824
  		ops->rpc_release(calldata);
bbd5a1f9f   Trond Myklebust   SUNRPC: Fix up mi...
825
  }
d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
826
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
   * This is the RPC `scheduler' (or rather, the finite state machine).
   */
2efef837f   Trond Myklebust   RPC: Clean up rpc...
829
  static void __rpc_execute(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
  {
eb9b55ab4   Trond Myklebust   SUNRPC: Tighten u...
831
832
833
  	struct rpc_wait_queue *queue;
  	int task_is_async = RPC_IS_ASYNC(task);
  	int status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834

2bd4eef87   Weston Andros Adamson   SUNRPC: remove BU...
835
836
837
  	WARN_ON_ONCE(RPC_IS_QUEUED(task));
  	if (RPC_IS_QUEUED(task))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838

d05fdb0ce   Trond Myklebust   [PATCH] RPC: Fix ...
839
  	for (;;) {
b55c59892   Trond Myklebust   SUNRPC: Fix a rac...
840
  		void (*do_action)(struct rpc_task *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
  
  		/*
21ead9ff3   Chuck Lever   SUNRPC: Micro-opt...
843
844
845
846
847
  		 * Perform the next FSM step or a pending callback.
  		 *
  		 * tk_action may be NULL if the task has been killed.
  		 * In particular, note that rpc_killall_tasks may
  		 * do this at any time, so beware when dereferencing.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  		 */
21ead9ff3   Chuck Lever   SUNRPC: Micro-opt...
849
850
851
852
  		do_action = task->tk_action;
  		if (task->tk_callback) {
  			do_action = task->tk_callback;
  			task->tk_callback = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  		}
21ead9ff3   Chuck Lever   SUNRPC: Micro-opt...
854
855
  		if (!do_action)
  			break;
e671edb94   Chuck Lever   sunrpc: Simplify ...
856
  		trace_rpc_task_run_action(task, do_action);
b55c59892   Trond Myklebust   SUNRPC: Fix a rac...
857
  		do_action(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
859
860
861
862
863
  
  		/*
  		 * Lockless check for whether task is sleeping or not.
  		 */
  		if (!RPC_IS_QUEUED(task))
  			continue;
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
864
865
866
867
  
  		/*
  		 * Signalled tasks should exit rather than sleep.
  		 */
714fbc738   Trond Myklebust   SUNRPC: RPC level...
868
869
  		if (RPC_SIGNALLED(task)) {
  			task->tk_rpc_status = -ERESTARTSYS;
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
870
  			rpc_exit(task, -ERESTARTSYS);
714fbc738   Trond Myklebust   SUNRPC: RPC level...
871
  		}
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
872

eb9b55ab4   Trond Myklebust   SUNRPC: Tighten u...
873
874
875
876
877
878
879
880
881
882
  		/*
  		 * The queue->lock protects against races with
  		 * rpc_make_runnable().
  		 *
  		 * Note that once we clear RPC_TASK_RUNNING on an asynchronous
  		 * rpc_task, rpc_make_runnable() can assign it to a
  		 * different workqueue. We therefore cannot assume that the
  		 * rpc_task pointer may still be dereferenced.
  		 */
  		queue = task->tk_waitqueue;
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
883
  		spin_lock(&queue->lock);
eb9b55ab4   Trond Myklebust   SUNRPC: Tighten u...
884
  		if (!RPC_IS_QUEUED(task)) {
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
885
  			spin_unlock(&queue->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
887
  			continue;
  		}
eb9b55ab4   Trond Myklebust   SUNRPC: Tighten u...
888
  		rpc_clear_running(task);
c049f8ea9   Trond Myklebust   SUNRPC: Remove th...
889
  		spin_unlock(&queue->lock);
eb9b55ab4   Trond Myklebust   SUNRPC: Tighten u...
890
891
  		if (task_is_async)
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
893
  
  		/* sync task: sleep here */
1466c2216   Chuck Lever   SUNRPC: Clean up ...
894
  		trace_rpc_task_sync_sleep(task, task->tk_action);
96651ab34   Trond Myklebust   [PATCH] RPC: Shri...
895
  		status = out_of_line_wait_on_bit(&task->tk_runstate,
150030b78   Matthew Wilcox   NFS: Switch from ...
896
897
  				RPC_TASK_QUEUED, rpc_wait_bit_killable,
  				TASK_KILLABLE);
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
898
  		if (status < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
903
904
  			/*
  			 * When a sync task receives a signal, it exits with
  			 * -ERESTARTSYS. In order to catch any callbacks that
  			 * clean up after sleeping on some queue, we don't
  			 * break the loop here, but go around once more.
  			 */
abf8af78a   Chuck Lever   SUNRPC: Capture s...
905
  			trace_rpc_task_signalled(task, task->tk_action);
ae67bd382   Trond Myklebust   SUNRPC: Fix up ta...
906
  			set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate);
714fbc738   Trond Myklebust   SUNRPC: RPC level...
907
  			task->tk_rpc_status = -ERESTARTSYS;
96651ab34   Trond Myklebust   [PATCH] RPC: Shri...
908
  			rpc_exit(task, -ERESTARTSYS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
  		}
1466c2216   Chuck Lever   SUNRPC: Clean up ...
910
  		trace_rpc_task_sync_wake(task, task->tk_action);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
  	/* Release all resources associated with the task */
  	rpc_release_task(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
919
920
921
922
923
924
  }
  
  /*
   * User-visible entry point to the scheduler.
   *
   * This may be called recursively if e.g. an async NFS task updates
   * the attributes and finds that dirty pages must be flushed.
   * NOTE: Upon exit of this function the task is guaranteed to be
   *	 released. In particular note that tk_release() will have
   *	 been called, so your task memory may have been freed.
   */
2efef837f   Trond Myklebust   RPC: Clean up rpc...
925
  void rpc_execute(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  {
a76580fbf   Trond Myklebust   SUNRPC: Fix a pot...
927
  	bool is_async = RPC_IS_ASYNC(task);
44c288732   Trond Myklebust   NFSv4: stateful N...
928
  	rpc_set_active(task);
f1dc237c6   Trond Myklebust   SUNRPC: Reduce la...
929
  	rpc_make_runnable(rpciod_workqueue, task);
a76580fbf   Trond Myklebust   SUNRPC: Fix a pot...
930
  	if (!is_async)
d6a1ed08c   Trond Myklebust   SUNRPC: Reduce as...
931
  		__rpc_execute(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  }
65f27f384   David Howells   WorkStruct: Pass ...
933
  static void rpc_async_schedule(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  {
a1231fda7   Trond Myklebust   SUNRPC: Set memal...
935
  	unsigned int pflags = memalloc_nofs_save();
65f27f384   David Howells   WorkStruct: Pass ...
936
  	__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
a1231fda7   Trond Myklebust   SUNRPC: Set memal...
937
  	memalloc_nofs_restore(pflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  }
021071483   Chuck Lever   SUNRPC: switchabl...
939
  /**
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
940
941
942
943
944
945
   * rpc_malloc - allocate RPC buffer resources
   * @task: RPC task
   *
   * A single memory region is allocated, which is split between the
   * RPC call and RPC reply that this task is being used for. When
   * this RPC is retired, the memory is released by calling rpc_free.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
   *
c5a4dd8b7   Chuck Lever   SUNRPC: Eliminate...
947
   * To prevent rpciod from hanging, this allocator never sleeps,
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
948
949
950
   * returning -ENOMEM and suppressing warning if the request cannot
   * be serviced immediately. The caller can arrange to sleep in a
   * way that is safe for rpciod.
c5a4dd8b7   Chuck Lever   SUNRPC: Eliminate...
951
952
953
954
   *
   * Most requests are 'small' (under 2KiB) and can be serviced from a
   * mempool, ensuring that NFS reads and writes can always proceed,
   * and that there is good locality of reference for these buffers.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
   */
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
956
  int rpc_malloc(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  {
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
958
959
  	struct rpc_rqst *rqst = task->tk_rqstp;
  	size_t size = rqst->rq_callsize + rqst->rq_rcvsize;
aa3d1faeb   Chuck Lever   SUNRPC: Fix point...
960
  	struct rpc_buffer *buf;
12a3ad618   Trond Myklebust   SUNRPC: Convert r...
961
  	gfp_t gfp = GFP_NOFS;
a564b8f03   Mel Gorman   nfs: enable swap ...
962
963
  
  	if (RPC_IS_SWAPPER(task))
c4a7ca774   Trond Myklebust   SUNRPC: Allow wai...
964
  		gfp = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965

aa3d1faeb   Chuck Lever   SUNRPC: Fix point...
966
  	size += sizeof(struct rpc_buffer);
c5a4dd8b7   Chuck Lever   SUNRPC: Eliminate...
967
968
  	if (size <= RPC_BUFFER_MAXSIZE)
  		buf = mempool_alloc(rpc_buffer_mempool, gfp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
969
  	else
c5a4dd8b7   Chuck Lever   SUNRPC: Eliminate...
970
  		buf = kmalloc(size, gfp);
ddce40df6   Peter Zijlstra   sunrpc: fix crash...
971
972
  
  	if (!buf)
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
973
  		return -ENOMEM;
ddce40df6   Peter Zijlstra   sunrpc: fix crash...
974

aa3d1faeb   Chuck Lever   SUNRPC: Fix point...
975
  	buf->len = size;
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
976
  	rqst->rq_buffer = buf->data;
68778945e   Chuck Lever   SUNRPC: Separate ...
977
  	rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize;
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
978
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
  }
124448097   \"Talpey, Thomas\   SUNRPC: add EXPOR...
980
  EXPORT_SYMBOL_GPL(rpc_malloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981

021071483   Chuck Lever   SUNRPC: switchabl...
982
  /**
3435c74ae   Chuck Lever   SUNRPC: Generaliz...
983
984
   * rpc_free - free RPC buffer resources allocated via rpc_malloc
   * @task: RPC task
021071483   Chuck Lever   SUNRPC: switchabl...
985
986
   *
   */
3435c74ae   Chuck Lever   SUNRPC: Generaliz...
987
  void rpc_free(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
  {
3435c74ae   Chuck Lever   SUNRPC: Generaliz...
989
  	void *buffer = task->tk_rqstp->rq_buffer;
aa3d1faeb   Chuck Lever   SUNRPC: Fix point...
990
991
  	size_t size;
  	struct rpc_buffer *buf;
021071483   Chuck Lever   SUNRPC: switchabl...
992

aa3d1faeb   Chuck Lever   SUNRPC: Fix point...
993
994
  	buf = container_of(buffer, struct rpc_buffer, data);
  	size = buf->len;
c5a4dd8b7   Chuck Lever   SUNRPC: Eliminate...
995

c5a4dd8b7   Chuck Lever   SUNRPC: Eliminate...
996
997
998
999
  	if (size <= RPC_BUFFER_MAXSIZE)
  		mempool_free(buf, rpc_buffer_mempool);
  	else
  		kfree(buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  }
124448097   \"Talpey, Thomas\   SUNRPC: add EXPOR...
1001
  EXPORT_SYMBOL_GPL(rpc_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
1005
  
  /*
   * Creation and deletion of RPC task structures
   */
47fe06483   Trond Myklebust   SUNRPC: Unexport ...
1006
  static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
  {
  	memset(task, 0, sizeof(*task));
44c288732   Trond Myklebust   NFSv4: stateful N...
1009
  	atomic_set(&task->tk_count, 1);
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1010
1011
1012
  	task->tk_flags  = task_setup_data->flags;
  	task->tk_ops = task_setup_data->callback_ops;
  	task->tk_calldata = task_setup_data->callback_data;
6529eba08   Trond Myklebust   SUNRPC: Move rpc_...
1013
  	INIT_LIST_HEAD(&task->tk_task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

3ff7576dd   Trond Myklebust   SUNRPC: Clean up ...
1015
1016
  	task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW;
  	task->tk_owner = current->tgid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
1018
  
  	/* Initialize workqueue for async tasks */
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1019
  	task->tk_workqueue = task_setup_data->workqueue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020

a101b043c   Trond Myklebust   SUNRPC: Fix trans...
1021
1022
  	task->tk_xprt = rpc_task_get_xprt(task_setup_data->rpc_client,
  			xprt_get(task_setup_data->rpc_xprt));
9d61498d5   Trond Myklebust   SUNRPC: Allow cal...
1023

1de7eea92   NeilBrown   SUNRPC: add side ...
1024
  	task->tk_op_cred = get_rpccred(task_setup_data->rpc_op_cred);
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1025
1026
  	if (task->tk_ops->rpc_call_prepare != NULL)
  		task->tk_action = rpc_prepare_task;
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1027

7fdcf13b2   Trond Myklebust   SUNRPC: Fix the e...
1028
  	rpc_init_task_statistics(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
1032
1033
  }
  
  static struct rpc_task *
  rpc_alloc_task(void)
  {
12a3ad618   Trond Myklebust   SUNRPC: Convert r...
1034
  	return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
  /*
90c5755ff   Trond Myklebust   SUNRPC: Kill rpc_...
1037
   * Create a new task for the specified client.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
   */
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1039
  struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
  {
e8f5d77c8   Trond Myklebust   SUNRPC: allow the...
1041
1042
1043
1044
1045
  	struct rpc_task	*task = setup_data->task;
  	unsigned short flags = 0;
  
  	if (task == NULL) {
  		task = rpc_alloc_task();
e8f5d77c8   Trond Myklebust   SUNRPC: allow the...
1046
1047
  		flags = RPC_TASK_DYNAMIC;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048

84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1049
  	rpc_init_task(task, setup_data);
e8f5d77c8   Trond Myklebust   SUNRPC: allow the...
1050
  	task->tk_flags |= flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1051
  	return task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  }
c6567ed14   Trond Myklebust   SUNRPC: Ensure th...
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
  /*
   * rpc_free_task - release rpc task and perform cleanups
   *
   * Note that we free up the rpc_task _after_ rpc_release_calldata()
   * in order to work around a workqueue dependency issue.
   *
   * Tejun Heo states:
   * "Workqueue currently considers two work items to be the same if they're
   * on the same address and won't execute them concurrently - ie. it
   * makes a work item which is queued again while being executed wait
   * for the previous execution to complete.
   *
   * If a work function frees the work item, and then waits for an event
   * which should be performed by another work item and *that* work item
   * recycles the freed work item, it can create a false dependency loop.
   * There really is no reliable way to detect this short of verifying
   * every memory free."
   *
   */
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1072
  static void rpc_free_task(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
  {
c6567ed14   Trond Myklebust   SUNRPC: Ensure th...
1074
  	unsigned short tk_flags = task->tk_flags;
1de7eea92   NeilBrown   SUNRPC: add side ...
1075
  	put_rpccred(task->tk_op_cred);
c6567ed14   Trond Myklebust   SUNRPC: Ensure th...
1076
  	rpc_release_calldata(task->tk_ops, task->tk_calldata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077

1466c2216   Chuck Lever   SUNRPC: Clean up ...
1078
  	if (tk_flags & RPC_TASK_DYNAMIC)
5e4424af9   Trond Myklebust   SUNRPC: Remove no...
1079
  		mempool_free(task, rpc_task_mempool);
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1080
1081
1082
1083
  }
  
  static void rpc_async_release(struct work_struct *work)
  {
a1231fda7   Trond Myklebust   SUNRPC: Set memal...
1084
  	unsigned int pflags = memalloc_nofs_save();
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1085
  	rpc_free_task(container_of(work, struct rpc_task, u.tk_work));
a1231fda7   Trond Myklebust   SUNRPC: Set memal...
1086
  	memalloc_nofs_restore(pflags);
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1087
  }
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1088
  static void rpc_release_resources_task(struct rpc_task *task)
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1089
  {
87ed50036   Trond Myklebust   SUNRPC: Ensure we...
1090
  	xprt_release(task);
a271c5a0d   OGAWA Hirofumi   NFS: Ensure that ...
1091
  	if (task->tk_msg.rpc_cred) {
7eac52648   Trond Myklebust   SUNRPC: Add a fla...
1092
1093
  		if (!(task->tk_flags & RPC_TASK_CRED_NOREF))
  			put_cred(task->tk_msg.rpc_cred);
a271c5a0d   OGAWA Hirofumi   NFS: Ensure that ...
1094
1095
  		task->tk_msg.rpc_cred = NULL;
  	}
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
1096
  	rpc_task_release_client(task);
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1097
1098
1099
1100
1101
1102
  }
  
  static void rpc_final_put_task(struct rpc_task *task,
  		struct workqueue_struct *q)
  {
  	if (q != NULL) {
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1103
  		INIT_WORK(&task->u.tk_work, rpc_async_release);
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1104
  		queue_work(q, &task->u.tk_work);
32bfb5c0f   Trond Myklebust   SUNRPC: Allow the...
1105
1106
  	} else
  		rpc_free_task(task);
e6b3c4db6   Trond Myklebust   Fix a second pote...
1107
  }
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
  
  static void rpc_do_put_task(struct rpc_task *task, struct workqueue_struct *q)
  {
  	if (atomic_dec_and_test(&task->tk_count)) {
  		rpc_release_resources_task(task);
  		rpc_final_put_task(task, q);
  	}
  }
  
  void rpc_put_task(struct rpc_task *task)
  {
  	rpc_do_put_task(task, NULL);
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
1121
  EXPORT_SYMBOL_GPL(rpc_put_task);
e6b3c4db6   Trond Myklebust   Fix a second pote...
1122

bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1123
1124
1125
1126
1127
  void rpc_put_task_async(struct rpc_task *task)
  {
  	rpc_do_put_task(task, task->tk_workqueue);
  }
  EXPORT_SYMBOL_GPL(rpc_put_task_async);
bde8f00ce   Trond Myklebust   [PATCH] NFS: Fix ...
1128
  static void rpc_release_task(struct rpc_task *task)
e6b3c4db6   Trond Myklebust   Fix a second pote...
1129
  {
0a0c2a57b   Weston Andros Adamson   SUNRPC: remove BU...
1130
  	WARN_ON_ONCE(RPC_IS_QUEUED(task));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131

bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1132
  	rpc_release_resources_task(task);
e6b3c4db6   Trond Myklebust   Fix a second pote...
1133

bf294b41c   Trond Myklebust   SUNRPC: Close a r...
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
  	/*
  	 * Note: at this point we have been removed from rpc_clnt->cl_tasks,
  	 * so it should be safe to use task->tk_count as a test for whether
  	 * or not any other processes still hold references to our rpc_task.
  	 */
  	if (atomic_read(&task->tk_count) != 1 + !RPC_IS_ASYNC(task)) {
  		/* Wake up anyone who may be waiting for task completion */
  		if (!rpc_complete_task(task))
  			return;
  	} else {
  		if (!atomic_dec_and_test(&task->tk_count))
  			return;
  	}
  	rpc_final_put_task(task, task->tk_workqueue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
  }
b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1149
1150
1151
1152
1153
1154
1155
1156
1157
  int rpciod_up(void)
  {
  	return try_module_get(THIS_MODULE) ? 0 : -EINVAL;
  }
  
  void rpciod_down(void)
  {
  	module_put(THIS_MODULE);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
  /*
b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1159
   * Start up the rpciod workqueue.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
   */
b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1161
  static int rpciod_start(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
  {
  	struct workqueue_struct *wq;
ab418d70e   Trond Myklebust   SUNRPC: Optimise ...
1164

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
  	/*
  	 * Create the rpciod thread and wait for it to start.
  	 */
f515f86b3   Olga Kornievskaia   fix parallelism f...
1168
  	wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
40a5f1b19   Trond Myklebust   SUNRPC: RPC trans...
1169
1170
  	if (!wq)
  		goto out_failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
  	rpciod_workqueue = wq;
40a5f1b19   Trond Myklebust   SUNRPC: RPC trans...
1172
  	/* Note: highpri because network receive is latency sensitive */
90ea9f1b6   Trond Myklebust   Make the xprtiod ...
1173
  	wq = alloc_workqueue("xprtiod", WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_HIGHPRI, 0);
40a5f1b19   Trond Myklebust   SUNRPC: RPC trans...
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  	if (!wq)
  		goto free_rpciod;
  	xprtiod_workqueue = wq;
  	return 1;
  free_rpciod:
  	wq = rpciod_workqueue;
  	rpciod_workqueue = NULL;
  	destroy_workqueue(wq);
  out_failed:
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
  }
b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1185
  static void rpciod_stop(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
  {
b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1187
  	struct workqueue_struct *wq = NULL;
ab418d70e   Trond Myklebust   SUNRPC: Optimise ...
1188

b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1189
1190
  	if (rpciod_workqueue == NULL)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191

b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1192
1193
1194
  	wq = rpciod_workqueue;
  	rpciod_workqueue = NULL;
  	destroy_workqueue(wq);
40a5f1b19   Trond Myklebust   SUNRPC: RPC trans...
1195
1196
1197
  	wq = xprtiod_workqueue;
  	xprtiod_workqueue = NULL;
  	destroy_workqueue(wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
1201
  void
  rpc_destroy_mempool(void)
  {
b247bbf1d   Trond Myklebust   SUNRPC: Fix a rac...
1202
  	rpciod_stop();
17a9618e9   Julia Lawall   SUNRPC: drop null...
1203
1204
1205
1206
  	mempool_destroy(rpc_buffer_mempool);
  	mempool_destroy(rpc_task_mempool);
  	kmem_cache_destroy(rpc_task_slabp);
  	kmem_cache_destroy(rpc_buffer_slabp);
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
1207
  	rpc_destroy_wait_queue(&delay_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
1209
1210
1211
1212
  }
  
  int
  rpc_init_mempool(void)
  {
f6a1cc893   Trond Myklebust   SUNRPC: Add a (em...
1213
1214
1215
1216
1217
1218
1219
  	/*
  	 * The following is not strictly a mempool initialisation,
  	 * but there is no harm in doing it here
  	 */
  	rpc_init_wait_queue(&delay_queue, "delayq");
  	if (!rpciod_start())
  		goto err_nomem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
1221
1222
  	rpc_task_slabp = kmem_cache_create("rpc_tasks",
  					     sizeof(struct rpc_task),
  					     0, SLAB_HWCACHE_ALIGN,
20c2df83d   Paul Mundt   mm: Remove slab d...
1223
  					     NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
1226
1227
1228
  	if (!rpc_task_slabp)
  		goto err_nomem;
  	rpc_buffer_slabp = kmem_cache_create("rpc_buffers",
  					     RPC_BUFFER_MAXSIZE,
  					     0, SLAB_HWCACHE_ALIGN,
20c2df83d   Paul Mundt   mm: Remove slab d...
1229
  					     NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
1231
  	if (!rpc_buffer_slabp)
  		goto err_nomem;
93d2341c7   Matthew Dobson   [PATCH] mempool: ...
1232
1233
  	rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE,
  						    rpc_task_slabp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
  	if (!rpc_task_mempool)
  		goto err_nomem;
93d2341c7   Matthew Dobson   [PATCH] mempool: ...
1236
1237
  	rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE,
  						      rpc_buffer_slabp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
1240
1241
1242
1243
1244
  	if (!rpc_buffer_mempool)
  		goto err_nomem;
  	return 0;
  err_nomem:
  	rpc_destroy_mempool();
  	return -ENOMEM;
  }