Blame view
net/sunrpc/sched.c
32.6 KB
457c89965 treewide: Add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
1da177e4c 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 [NET] SUNRPC: Fix... |
8 |
* |
1da177e4c 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 Linux-2.6.12-rc2 |
20 |
#include <linux/spinlock.h> |
4a3e2f711 [NET] sem2mutex: ... |
21 |
#include <linux/mutex.h> |
d310310cb Freezer / sunrpc ... |
22 |
#include <linux/freezer.h> |
a1231fda7 SUNRPC: Set memal... |
23 |
#include <linux/sched/mm.h> |
1da177e4c Linux-2.6.12-rc2 |
24 25 |
#include <linux/sunrpc/clnt.h> |
9dfe52a95 SUNRPC: Move call... |
26 |
#include <linux/sunrpc/metrics.h> |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
6951867b9 nfsd41: sunrpc: m... |
28 |
#include "sunrpc.h" |
82b0a4c3c SUNRPC: Add trace... |
29 30 |
#define CREATE_TRACE_POINTS #include <trace/events/sunrpc.h> |
1da177e4c 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 [PATCH] slab: rem... |
37 38 |
static struct kmem_cache *rpc_task_slabp __read_mostly; static struct kmem_cache *rpc_buffer_slabp __read_mostly; |
ba89966c1 [NET]: use __read... |
39 40 |
static mempool_t *rpc_task_mempool __read_mostly; static mempool_t *rpc_buffer_mempool __read_mostly; |
1da177e4c Linux-2.6.12-rc2 |
41 |
|
65f27f384 WorkStruct: Pass ... |
42 |
static void rpc_async_schedule(struct work_struct *); |
bde8f00ce [PATCH] NFS: Fix ... |
43 |
static void rpc_release_task(struct rpc_task *task); |
7e0a0e38f SUNRPC: Replace t... |
44 |
static void __rpc_queue_timer_fn(struct work_struct *); |
1da177e4c Linux-2.6.12-rc2 |
45 46 |
/* |
1da177e4c Linux-2.6.12-rc2 |
47 48 |
* RPC tasks sit here while waiting for conditions to improve. */ |
a4a874990 SUNRPC: Cleanup t... |
49 |
static struct rpc_wait_queue delay_queue; |
1da177e4c Linux-2.6.12-rc2 |
50 51 |
/* |
1da177e4c Linux-2.6.12-rc2 |
52 53 |
* rpciod-related stuff */ |
40a5f1b19 SUNRPC: RPC trans... |
54 55 |
struct workqueue_struct *rpciod_workqueue __read_mostly; struct workqueue_struct *xprtiod_workqueue __read_mostly; |
675dd90ad xprtrdma: Moderni... |
56 |
EXPORT_SYMBOL_GPL(xprtiod_workqueue); |
1da177e4c Linux-2.6.12-rc2 |
57 |
|
5efd1876e 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 Linux-2.6.12-rc2 |
71 |
/* |
1da177e4c 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 SUNRPC: Run rpc t... |
76 |
static void |
eb276c0e1 SUNRPC: Switch ta... |
77 |
__rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
78 |
{ |
6b2e68562 SUNRPC: Add funct... |
79 |
if (list_empty(&task->u.tk_wait.timer_list)) |
36df9aae3 SUNRPC: Add a tim... |
80 |
return; |
1da177e4c Linux-2.6.12-rc2 |
81 |
task->tk_timeout = 0; |
36df9aae3 SUNRPC: Add a tim... |
82 |
list_del(&task->u.tk_wait.timer_list); |
eb276c0e1 SUNRPC: Switch ta... |
83 |
if (list_empty(&queue->timer_list.list)) |
7e0a0e38f SUNRPC: Replace t... |
84 |
cancel_delayed_work(&queue->timer_list.dwork); |
36df9aae3 SUNRPC: Add a tim... |
85 86 87 88 89 |
} static void rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires) { |
7e0a0e38f 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 Linux-2.6.12-rc2 |
97 98 99 |
} /* |
1da177e4c Linux-2.6.12-rc2 |
100 101 |
* Set up a timer for the current task. */ |
5d00837b9 SUNRPC: Run rpc t... |
102 |
static void |
6b2e68562 SUNRPC: Add funct... |
103 104 |
__rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task, unsigned long timeout) |
1da177e4c Linux-2.6.12-rc2 |
105 |
{ |
6b2e68562 SUNRPC: Add funct... |
106 |
task->tk_timeout = timeout; |
7e0a0e38f 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 SUNRPC: Switch ta... |
109 |
list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list); |
1da177e4c Linux-2.6.12-rc2 |
110 |
} |
c05eecf63 SUNRPC: Don't all... |
111 112 |
static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority) { |
edd2e36fe SUNRPC: When chan... |
113 |
if (queue->priority != priority) { |
edd2e36fe SUNRPC: When chan... |
114 |
queue->priority = priority; |
f42f7c283 SUNRPC: Fix prior... |
115 |
queue->nr = 1U << priority; |
edd2e36fe SUNRPC: When chan... |
116 |
} |
c05eecf63 SUNRPC: Don't all... |
117 |
} |
c05eecf63 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 SUNRPC: Don't all... |
121 |
} |
1da177e4c Linux-2.6.12-rc2 |
122 |
/* |
f42f7c283 SUNRPC: Fix prior... |
123 |
* Add a request to a queue list |
1da177e4c Linux-2.6.12-rc2 |
124 |
*/ |
f42f7c283 SUNRPC: Fix prior... |
125 126 |
static void __rpc_list_enqueue_task(struct list_head *q, struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
127 |
{ |
1da177e4c Linux-2.6.12-rc2 |
128 |
struct rpc_task *t; |
1da177e4c Linux-2.6.12-rc2 |
129 |
list_for_each_entry(t, q, u.tk_wait.list) { |
3ff7576dd SUNRPC: Clean up ... |
130 |
if (t->tk_owner == task->tk_owner) { |
f42f7c283 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 Linux-2.6.12-rc2 |
136 137 138 |
return; } } |
f42f7c283 SUNRPC: Fix prior... |
139 |
INIT_LIST_HEAD(&task->u.tk_wait.links); |
1da177e4c Linux-2.6.12-rc2 |
140 141 142 143 |
list_add_tail(&task->u.tk_wait.list, q); } /* |
f42f7c283 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 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 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 Linux-2.6.12-rc2 |
191 |
{ |
6b2e68562 SUNRPC: Add funct... |
192 |
INIT_LIST_HEAD(&task->u.tk_wait.timer_list); |
1da177e4c Linux-2.6.12-rc2 |
193 |
if (RPC_IS_PRIORITY(queue)) |
3b27bad7f SUNRPC: Allow cal... |
194 |
__rpc_add_wait_queue_priority(queue, task, queue_priority); |
1da177e4c 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 SUNRPC: Add a new... |
199 |
task->tk_waitqueue = queue; |
e19b63daf SUNRPC: track len... |
200 |
queue->qlen++; |
1166fde6a SUNRPC: Add barri... |
201 202 |
/* barrier matches the read in rpc_wake_up_task_queue_locked() */ smp_wmb(); |
1da177e4c Linux-2.6.12-rc2 |
203 |
rpc_set_queued(task); |
1da177e4c 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 SUNRPC: Fix prior... |
211 |
__rpc_list_dequeue_task(task); |
1da177e4c Linux-2.6.12-rc2 |
212 213 214 215 216 217 |
} /* * Remove request from queue. * Note: must be called with spin lock held. */ |
96ef13b28 SUNRPC: Add a new... |
218 |
static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
219 |
{ |
eb276c0e1 SUNRPC: Switch ta... |
220 |
__rpc_disable_timer(queue, task); |
1da177e4c Linux-2.6.12-rc2 |
221 222 |
if (RPC_IS_PRIORITY(queue)) __rpc_remove_wait_queue_priority(task); |
f42f7c283 SUNRPC: Fix prior... |
223 224 |
else list_del(&task->u.tk_wait.list); |
e19b63daf SUNRPC: track len... |
225 |
queue->qlen--; |
1da177e4c Linux-2.6.12-rc2 |
226 |
} |
3ff7576dd SUNRPC: Clean up ... |
227 |
static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues) |
1da177e4c 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 SUNRPC: Clean up ... |
234 |
queue->maxpriority = nr_queues - 1; |
1da177e4c Linux-2.6.12-rc2 |
235 |
rpc_reset_waitqueue_priority(queue); |
36df9aae3 SUNRPC: Add a tim... |
236 |
queue->qlen = 0; |
7e0a0e38f SUNRPC: Replace t... |
237 |
queue->timer_list.expires = 0; |
66eb3add4 SUNRPC: Avoid RPC... |
238 |
INIT_DELAYED_WORK(&queue->timer_list.dwork, __rpc_queue_timer_fn); |
36df9aae3 SUNRPC: Add a tim... |
239 |
INIT_LIST_HEAD(&queue->timer_list.list); |
2f09c2421 SUNRPC: Ensure th... |
240 |
rpc_assign_waitqueue_name(queue, qname); |
1da177e4c Linux-2.6.12-rc2 |
241 242 243 244 |
} void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname) { |
3ff7576dd SUNRPC: Clean up ... |
245 |
__rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY); |
1da177e4c Linux-2.6.12-rc2 |
246 |
} |
689cf5c15 nfs: enforce FIFO... |
247 |
EXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue); |
1da177e4c Linux-2.6.12-rc2 |
248 249 250 |
void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) { |
3ff7576dd SUNRPC: Clean up ... |
251 |
__rpc_init_priority_wait_queue(queue, qname, 1); |
1da177e4c Linux-2.6.12-rc2 |
252 |
} |
e8914c65f SUNRPC: Restrict ... |
253 |
EXPORT_SYMBOL_GPL(rpc_init_wait_queue); |
1da177e4c Linux-2.6.12-rc2 |
254 |
|
f6a1cc893 SUNRPC: Add a (em... |
255 256 |
void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) { |
7e0a0e38f SUNRPC: Replace t... |
257 |
cancel_delayed_work_sync(&queue->timer_list.dwork); |
f6a1cc893 SUNRPC: Add a (em... |
258 259 |
} EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); |
dfd01f026 sched/wait: Fix t... |
260 |
static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode) |
44c288732 NFSv4: stateful N... |
261 |
{ |
416ad3c9c freezer: add unsa... |
262 |
freezable_schedule_unsafe(); |
dfd01f026 sched/wait: Fix t... |
263 264 |
if (signal_pending_state(mode, current)) return -ERESTARTSYS; |
44c288732 NFSv4: stateful N... |
265 266 |
return 0; } |
1306729b0 sunrpc: eliminate... |
267 |
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) |
c44fe7055 SUNRPC: Clean up ... |
268 269 270 |
static void rpc_task_set_debuginfo(struct rpc_task *task) { static atomic_t rpc_pid; |
c44fe7055 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 Fix a second pote... |
278 279 |
static void rpc_set_active(struct rpc_task *task) { |
c44fe7055 SUNRPC: Clean up ... |
280 |
rpc_task_set_debuginfo(task); |
58f9612c6 SUNRPC: Move rema... |
281 |
set_bit(RPC_TASK_ACTIVE, &task->tk_runstate); |
e671edb94 sunrpc: Simplify ... |
282 |
trace_rpc_task_begin(task, NULL); |
e6b3c4db6 Fix a second pote... |
283 |
} |
44c288732 NFSv4: stateful N... |
284 285 |
/* * Mark an RPC call as having completed by clearing the 'active' bit |
bf294b41c SUNRPC: Close a r... |
286 |
* and then waking up all tasks that were sleeping. |
44c288732 NFSv4: stateful N... |
287 |
*/ |
bf294b41c SUNRPC: Close a r... |
288 |
static int rpc_complete_task(struct rpc_task *task) |
44c288732 NFSv4: stateful N... |
289 |
{ |
bf294b41c 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 sunrpc: Simplify ... |
295 |
trace_rpc_task_complete(task, NULL); |
82b0a4c3c SUNRPC: Add trace... |
296 |
|
bf294b41c SUNRPC: Close a r... |
297 |
spin_lock_irqsave(&wq->lock, flags); |
e6b3c4db6 Fix a second pote... |
298 |
clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); |
bf294b41c SUNRPC: Close a r... |
299 300 |
ret = atomic_dec_and_test(&task->tk_count); if (waitqueue_active(wq)) |
ac5be6b47 userfaultfd: reve... |
301 |
__wake_up_locked_key(wq, TASK_NORMAL, &k); |
bf294b41c SUNRPC: Close a r... |
302 303 |
spin_unlock_irqrestore(&wq->lock, flags); return ret; |
44c288732 NFSv4: stateful N... |
304 305 306 307 |
} /* * Allow callers to wait for completion of an RPC call |
bf294b41c 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 NFSv4: stateful N... |
312 |
*/ |
c1221321b sched: Allow wait... |
313 |
int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *action) |
44c288732 NFSv4: stateful N... |
314 315 |
{ if (action == NULL) |
150030b78 NFS: Switch from ... |
316 |
action = rpc_wait_bit_killable; |
bf294b41c SUNRPC: Close a r... |
317 |
return out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE, |
150030b78 NFS: Switch from ... |
318 |
action, TASK_KILLABLE); |
44c288732 NFSv4: stateful N... |
319 |
} |
e8914c65f SUNRPC: Restrict ... |
320 |
EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); |
44c288732 NFSv4: stateful N... |
321 |
|
1da177e4c Linux-2.6.12-rc2 |
322 323 324 |
/* * Make an RPC task runnable. * |
506026c3e 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 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 Linux-2.6.12-rc2 |
332 |
*/ |
f1dc237c6 SUNRPC: Reduce la... |
333 334 |
static void rpc_make_runnable(struct workqueue_struct *wq, struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
335 |
{ |
a3c3cac5d SUNRPC: Prevent a... |
336 |
bool need_wakeup = !rpc_test_and_set_running(task); |
1da177e4c Linux-2.6.12-rc2 |
337 |
rpc_clear_queued(task); |
a3c3cac5d SUNRPC: Prevent a... |
338 |
if (!need_wakeup) |
cc4dc59e5 Subject: Re: [PAT... |
339 |
return; |
1da177e4c Linux-2.6.12-rc2 |
340 |
if (RPC_IS_ASYNC(task)) { |
65f27f384 WorkStruct: Pass ... |
341 |
INIT_WORK(&task->u.tk_work, rpc_async_schedule); |
f1dc237c6 SUNRPC: Reduce la... |
342 |
queue_work(wq, &task->u.tk_work); |
1da177e4c Linux-2.6.12-rc2 |
343 |
} else |
96651ab34 [PATCH] RPC: Shri... |
344 |
wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); |
1da177e4c Linux-2.6.12-rc2 |
345 346 347 |
} /* |
1da177e4c 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 SUNRPC: Don't sta... |
353 |
static void __rpc_do_sleep_on_priority(struct rpc_wait_queue *q, |
3b27bad7f SUNRPC: Allow cal... |
354 |
struct rpc_task *task, |
3b27bad7f SUNRPC: Allow cal... |
355 |
unsigned char queue_priority) |
1da177e4c Linux-2.6.12-rc2 |
356 |
{ |
e671edb94 sunrpc: Simplify ... |
357 |
trace_rpc_task_sleep(task, q); |
82b0a4c3c SUNRPC: Add trace... |
358 |
|
3b27bad7f SUNRPC: Allow cal... |
359 |
__rpc_add_wait_queue(q, task, queue_priority); |
6b2e68562 SUNRPC: Add funct... |
360 |
} |
1fab7dc47 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 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 SUNRPC: Don't sta... |
373 374 |
if (WARN_ON_ONCE(RPC_IS_QUEUED(task))) return; |
6b2e68562 SUNRPC: Add funct... |
375 |
if (time_is_after_jiffies(timeout)) { |
1fab7dc47 SUNRPC: Don't sta... |
376 |
__rpc_do_sleep_on_priority(q, task, queue_priority); |
6b2e68562 SUNRPC: Add funct... |
377 378 379 |
__rpc_add_timer(q, task, timeout); } else task->tk_status = -ETIMEDOUT; |
1da177e4c Linux-2.6.12-rc2 |
380 |
} |
87150aaed 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 Linux-2.6.12-rc2 |
388 |
{ |
58f9612c6 SUNRPC: Move rema... |
389 |
/* We shouldn't ever put an inactive task to sleep */ |
87150aaed SUNRPC: Refactor ... |
390 |
if (WARN_ON_ONCE(!RPC_IS_ACTIVATED(task))) { |
e454a7a83 SUNRPC: remove BU... |
391 392 |
task->tk_status = -EIO; rpc_put_task_async(task); |
87150aaed SUNRPC: Refactor ... |
393 |
return false; |
e454a7a83 SUNRPC: remove BU... |
394 |
} |
87150aaed SUNRPC: Refactor ... |
395 396 |
return true; } |
6b2e68562 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 SUNRPC: Remove th... |
408 |
spin_lock(&q->lock); |
6b2e68562 SUNRPC: Add funct... |
409 |
__rpc_sleep_on_priority_timeout(q, task, timeout, task->tk_priority); |
c049f8ea9 SUNRPC: Remove th... |
410 |
spin_unlock(&q->lock); |
6b2e68562 SUNRPC: Add funct... |
411 412 |
} EXPORT_SYMBOL_GPL(rpc_sleep_on_timeout); |
87150aaed 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 Fix a second pote... |
420 |
|
6b2e68562 SUNRPC: Add funct... |
421 |
WARN_ON_ONCE(task->tk_timeout != 0); |
1da177e4c Linux-2.6.12-rc2 |
422 423 424 |
/* * Protect the queue operations. */ |
c049f8ea9 SUNRPC: Remove th... |
425 |
spin_lock(&q->lock); |
87150aaed SUNRPC: Refactor ... |
426 |
__rpc_sleep_on_priority(q, task, task->tk_priority); |
c049f8ea9 SUNRPC: Remove th... |
427 |
spin_unlock(&q->lock); |
1da177e4c Linux-2.6.12-rc2 |
428 |
} |
e8914c65f SUNRPC: Restrict ... |
429 |
EXPORT_SYMBOL_GPL(rpc_sleep_on); |
1da177e4c Linux-2.6.12-rc2 |
430 |
|
6b2e68562 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 SUNRPC: Remove th... |
441 |
spin_lock(&q->lock); |
6b2e68562 SUNRPC: Add funct... |
442 |
__rpc_sleep_on_priority_timeout(q, task, timeout, priority); |
c049f8ea9 SUNRPC: Remove th... |
443 |
spin_unlock(&q->lock); |
6b2e68562 SUNRPC: Add funct... |
444 445 |
} EXPORT_SYMBOL_GPL(rpc_sleep_on_priority_timeout); |
3b27bad7f SUNRPC: Allow cal... |
446 |
void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, |
8357a9b60 SUNRPC: Remove un... |
447 |
int priority) |
3b27bad7f SUNRPC: Allow cal... |
448 |
{ |
87150aaed SUNRPC: Refactor ... |
449 |
if (!rpc_sleep_check_activated(task)) |
e454a7a83 SUNRPC: remove BU... |
450 |
return; |
87150aaed SUNRPC: Refactor ... |
451 |
|
6b2e68562 SUNRPC: Add funct... |
452 |
WARN_ON_ONCE(task->tk_timeout != 0); |
8357a9b60 SUNRPC: Remove un... |
453 |
priority -= RPC_PRIORITY_LOW; |
3b27bad7f SUNRPC: Allow cal... |
454 455 456 |
/* * Protect the queue operations. */ |
c049f8ea9 SUNRPC: Remove th... |
457 |
spin_lock(&q->lock); |
8357a9b60 SUNRPC: Remove un... |
458 |
__rpc_sleep_on_priority(q, task, priority); |
c049f8ea9 SUNRPC: Remove th... |
459 |
spin_unlock(&q->lock); |
3b27bad7f SUNRPC: Allow cal... |
460 |
} |
1e1093c7f NFSv4.1: Don't me... |
461 |
EXPORT_SYMBOL_GPL(rpc_sleep_on_priority); |
3b27bad7f SUNRPC: Allow cal... |
462 |
|
1da177e4c Linux-2.6.12-rc2 |
463 |
/** |
f1dc237c6 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 SUNRPC: Add a new... |
466 |
* @queue: wait queue |
1da177e4c 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 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 Linux-2.6.12-rc2 |
474 |
{ |
1da177e4c 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 sunrpc: Simplify ... |
481 |
trace_rpc_task_wakeup(task, queue); |
82b0a4c3c SUNRPC: Add trace... |
482 |
|
96ef13b28 SUNRPC: Add a new... |
483 |
__rpc_remove_wait_queue(queue, task); |
1da177e4c Linux-2.6.12-rc2 |
484 |
|
f1dc237c6 SUNRPC: Reduce la... |
485 |
rpc_make_runnable(wq, task); |
1da177e4c Linux-2.6.12-rc2 |
486 487 488 |
} /* |
96ef13b28 SUNRPC: Add a new... |
489 |
* Wake up a queued task while the queue lock is being held |
1da177e4c Linux-2.6.12-rc2 |
490 |
*/ |
359c48c04 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 Linux-2.6.12-rc2 |
495 |
{ |
1166fde6a SUNRPC: Add barri... |
496 497 |
if (RPC_IS_QUEUED(task)) { smp_rmb(); |
359c48c04 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 SUNRPC: Add barri... |
504 |
} |
359c48c04 SUNRPC: Add a hel... |
505 506 |
return NULL; } |
1da177e4c Linux-2.6.12-rc2 |
507 |
/* |
f1dc237c6 SUNRPC: Reduce la... |
508 509 |
* Wake up a queued task while the queue lock is being held */ |
691b45ddb SUNRPC: Remove rp... |
510 511 |
static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task) |
f1dc237c6 SUNRPC: Reduce la... |
512 |
{ |
691b45ddb SUNRPC: Remove rp... |
513 514 |
rpc_wake_up_task_on_wq_queue_action_locked(rpciod_workqueue, queue, task, NULL, NULL); |
2275cde4c SUNRPC: Queue lat... |
515 516 517 518 519 |
} /* * Wake up a task on a specific queue */ |
96ef13b28 SUNRPC: Add a new... |
520 |
void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
521 |
{ |
5ce970393 SUNRPC: Test whet... |
522 523 |
if (!RPC_IS_QUEUED(task)) return; |
c049f8ea9 SUNRPC: Remove th... |
524 |
spin_lock(&queue->lock); |
96ef13b28 SUNRPC: Add a new... |
525 |
rpc_wake_up_task_queue_locked(queue, task); |
c049f8ea9 SUNRPC: Remove th... |
526 |
spin_unlock(&queue->lock); |
1da177e4c Linux-2.6.12-rc2 |
527 |
} |
96ef13b28 SUNRPC: Add a new... |
528 |
EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task); |
359c48c04 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 SUNRPC: Remove th... |
558 |
spin_lock(&queue->lock); |
359c48c04 SUNRPC: Add a hel... |
559 |
rpc_wake_up_task_queue_set_status_locked(queue, task, status); |
c049f8ea9 SUNRPC: Remove th... |
560 |
spin_unlock(&queue->lock); |
359c48c04 SUNRPC: Add a hel... |
561 |
} |
96ef13b28 SUNRPC: Add a new... |
562 |
/* |
1da177e4c Linux-2.6.12-rc2 |
563 564 |
* Wake up the next task on a priority queue. */ |
961a828df SUNRPC: Fix poten... |
565 |
static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue) |
1da177e4c Linux-2.6.12-rc2 |
566 567 568 569 570 |
{ struct list_head *q; struct rpc_task *task; /* |
3ff7576dd SUNRPC: Clean up ... |
571 |
* Service a batch of tasks from a single owner. |
1da177e4c Linux-2.6.12-rc2 |
572 573 |
*/ q = &queue->tasks[queue->priority]; |
f42f7c283 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 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 SUNRPC: Fix prior... |
588 |
task = list_first_entry(q, struct rpc_task, u.tk_wait.list); |
1da177e4c 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 Linux-2.6.12-rc2 |
598 |
out: |
1da177e4c Linux-2.6.12-rc2 |
599 600 |
return task; } |
961a828df 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 Linux-2.6.12-rc2 |
609 |
/* |
961a828df SUNRPC: Fix poten... |
610 |
* Wake up the first task on the wait queue. |
1da177e4c Linux-2.6.12-rc2 |
611 |
*/ |
f1dc237c6 SUNRPC: Reduce la... |
612 613 |
struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, struct rpc_wait_queue *queue, |
961a828df SUNRPC: Fix poten... |
614 |
bool (*func)(struct rpc_task *, void *), void *data) |
1da177e4c Linux-2.6.12-rc2 |
615 616 |
{ struct rpc_task *task = NULL; |
c049f8ea9 SUNRPC: Remove th... |
617 |
spin_lock(&queue->lock); |
961a828df SUNRPC: Fix poten... |
618 |
task = __rpc_find_next_queued(queue); |
359c48c04 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 SUNRPC: Remove th... |
622 |
spin_unlock(&queue->lock); |
1da177e4c Linux-2.6.12-rc2 |
623 624 625 |
return task; } |
f1dc237c6 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 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 SUNRPC: Restrict ... |
649 |
EXPORT_SYMBOL_GPL(rpc_wake_up_next); |
1da177e4c Linux-2.6.12-rc2 |
650 651 |
/** |
d1296acac 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 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 SUNRPC: Remove th... |
676 |
spin_lock(&queue->lock); |
d1296acac 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 Linux-2.6.12-rc2 |
690 |
for (;;) { |
d1296acac SUNRPC: rpc_wake_... |
691 692 |
task = __rpc_find_next_queued(queue); if (task == NULL) |
1da177e4c Linux-2.6.12-rc2 |
693 |
break; |
d1296acac SUNRPC: rpc_wake_... |
694 |
rpc_wake_up_task_queue_set_status_locked(queue, task, status); |
1da177e4c Linux-2.6.12-rc2 |
695 |
} |
1da177e4c 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 SUNRPC: Remove th... |
707 |
spin_lock(&queue->lock); |
d1296acac SUNRPC: rpc_wake_... |
708 |
rpc_wake_up_status_locked(queue, status); |
c049f8ea9 SUNRPC: Remove th... |
709 |
spin_unlock(&queue->lock); |
1da177e4c Linux-2.6.12-rc2 |
710 |
} |
e8914c65f SUNRPC: Restrict ... |
711 |
EXPORT_SYMBOL_GPL(rpc_wake_up_status); |
1da177e4c Linux-2.6.12-rc2 |
712 |
|
7e0a0e38f SUNRPC: Replace t... |
713 |
static void __rpc_queue_timer_fn(struct work_struct *work) |
36df9aae3 SUNRPC: Add a tim... |
714 |
{ |
7e0a0e38f SUNRPC: Replace t... |
715 716 717 |
struct rpc_wait_queue *queue = container_of(work, struct rpc_wait_queue, timer_list.dwork.work); |
36df9aae3 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 SUNRPC: Add funct... |
724 |
timeo = task->tk_timeout; |
36df9aae3 SUNRPC: Add a tim... |
725 |
if (time_after_eq(now, timeo)) { |
721a1d388 SUNRPC: Remove dp... |
726 |
trace_rpc_task_timeout(task, task->tk_action); |
36df9aae3 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 SUNRPC: rpc_delay... |
738 739 |
static void __rpc_atrun(struct rpc_task *task) { |
6bd144160 SUNRPC: Don't let... |
740 741 |
if (task->tk_status == -ETIMEDOUT) task->tk_status = 0; |
8014793b1 SUNRPC: rpc_delay... |
742 |
} |
1da177e4c Linux-2.6.12-rc2 |
743 744 745 |
/* * Run a task at a later time */ |
8014793b1 SUNRPC: rpc_delay... |
746 |
void rpc_delay(struct rpc_task *task, unsigned long delay) |
1da177e4c Linux-2.6.12-rc2 |
747 |
{ |
6b2e68562 SUNRPC: Add funct... |
748 |
rpc_sleep_on_timeout(&delay_queue, task, __rpc_atrun, jiffies + delay); |
1da177e4c Linux-2.6.12-rc2 |
749 |
} |
e8914c65f SUNRPC: Restrict ... |
750 |
EXPORT_SYMBOL_GPL(rpc_delay); |
1da177e4c Linux-2.6.12-rc2 |
751 |
|
1da177e4c Linux-2.6.12-rc2 |
752 |
/* |
4ce70ada1 SUNRPC: Further c... |
753 754 |
* Helper to call task->tk_ops->rpc_call_prepare */ |
aae2006e9 nfs41: sunrpc: Ex... |
755 |
void rpc_prepare_task(struct rpc_task *task) |
4ce70ada1 SUNRPC: Further c... |
756 757 758 |
{ task->tk_ops->rpc_call_prepare(task, task->tk_calldata); } |
7fdcf13b2 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 SUNRPC: Fix up ta... |
775 |
task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_SENT); |
7fdcf13b2 SUNRPC: Fix the e... |
776 777 |
rpc_init_task_statistics(task); } |
4ce70ada1 SUNRPC: Further c... |
778 |
/* |
963d8fe53 RPC: Clean up RPC... |
779 |
* Helper that calls task->tk_ops->rpc_call_done if it exists |
d05fdb0ce [PATCH] RPC: Fix ... |
780 |
*/ |
abbcf28f2 SUNRPC: Yet more ... |
781 |
void rpc_exit_task(struct rpc_task *task) |
d05fdb0ce [PATCH] RPC: Fix ... |
782 |
{ |
a264abad5 SUNRPC: Capture c... |
783 |
trace_rpc_task_end(task, task->tk_action); |
abbcf28f2 SUNRPC: Yet more ... |
784 |
task->tk_action = NULL; |
9dfe52a95 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 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 [PATCH] RPC: Fix ... |
791 |
if (task->tk_action != NULL) { |
abbcf28f2 SUNRPC: Yet more ... |
792 793 |
/* Always release the RPC slot and buffer memory */ xprt_release(task); |
7fdcf13b2 SUNRPC: Fix the e... |
794 |
rpc_reset_task_statistics(task); |
d05fdb0ce [PATCH] RPC: Fix ... |
795 796 |
} } |
d05fdb0ce [PATCH] RPC: Fix ... |
797 |
} |
d9b6cd946 SUNRPC: Ensure th... |
798 |
|
ae67bd382 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 SUNRPC: Capture s... |
805 806 |
trace_rpc_task_signalled(task, task->tk_action); |
ae67bd382 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 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 SUNRPC: Remove re... |
817 |
rpc_wake_up_queued_task(task->tk_waitqueue, task); |
d9b6cd946 SUNRPC: Ensure th... |
818 819 |
} EXPORT_SYMBOL_GPL(rpc_exit); |
d05fdb0ce [PATCH] RPC: Fix ... |
820 |
|
bbd5a1f9f SUNRPC: Fix up mi... |
821 822 |
void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata) { |
a86dc496b SUNRPC: Remove th... |
823 |
if (ops->rpc_release != NULL) |
bbd5a1f9f SUNRPC: Fix up mi... |
824 |
ops->rpc_release(calldata); |
bbd5a1f9f SUNRPC: Fix up mi... |
825 |
} |
d05fdb0ce [PATCH] RPC: Fix ... |
826 |
/* |
1da177e4c Linux-2.6.12-rc2 |
827 828 |
* This is the RPC `scheduler' (or rather, the finite state machine). */ |
2efef837f RPC: Clean up rpc... |
829 |
static void __rpc_execute(struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
830 |
{ |
eb9b55ab4 SUNRPC: Tighten u... |
831 832 833 |
struct rpc_wait_queue *queue; int task_is_async = RPC_IS_ASYNC(task); int status = 0; |
1da177e4c Linux-2.6.12-rc2 |
834 |
|
2bd4eef87 SUNRPC: remove BU... |
835 836 837 |
WARN_ON_ONCE(RPC_IS_QUEUED(task)); if (RPC_IS_QUEUED(task)) return; |
1da177e4c Linux-2.6.12-rc2 |
838 |
|
d05fdb0ce [PATCH] RPC: Fix ... |
839 |
for (;;) { |
b55c59892 SUNRPC: Fix a rac... |
840 |
void (*do_action)(struct rpc_task *); |
1da177e4c Linux-2.6.12-rc2 |
841 842 |
/* |
21ead9ff3 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 Linux-2.6.12-rc2 |
848 |
*/ |
21ead9ff3 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 Linux-2.6.12-rc2 |
853 |
} |
21ead9ff3 SUNRPC: Micro-opt... |
854 855 |
if (!do_action) break; |
e671edb94 sunrpc: Simplify ... |
856 |
trace_rpc_task_run_action(task, do_action); |
b55c59892 SUNRPC: Fix a rac... |
857 |
do_action(task); |
1da177e4c 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 SUNRPC: Fix up ta... |
864 865 866 867 |
/* * Signalled tasks should exit rather than sleep. */ |
714fbc738 SUNRPC: RPC level... |
868 869 |
if (RPC_SIGNALLED(task)) { task->tk_rpc_status = -ERESTARTSYS; |
ae67bd382 SUNRPC: Fix up ta... |
870 |
rpc_exit(task, -ERESTARTSYS); |
714fbc738 SUNRPC: RPC level... |
871 |
} |
ae67bd382 SUNRPC: Fix up ta... |
872 |
|
eb9b55ab4 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 SUNRPC: Remove th... |
883 |
spin_lock(&queue->lock); |
eb9b55ab4 SUNRPC: Tighten u... |
884 |
if (!RPC_IS_QUEUED(task)) { |
c049f8ea9 SUNRPC: Remove th... |
885 |
spin_unlock(&queue->lock); |
1da177e4c Linux-2.6.12-rc2 |
886 887 |
continue; } |
eb9b55ab4 SUNRPC: Tighten u... |
888 |
rpc_clear_running(task); |
c049f8ea9 SUNRPC: Remove th... |
889 |
spin_unlock(&queue->lock); |
eb9b55ab4 SUNRPC: Tighten u... |
890 891 |
if (task_is_async) return; |
1da177e4c Linux-2.6.12-rc2 |
892 893 |
/* sync task: sleep here */ |
1466c2216 SUNRPC: Clean up ... |
894 |
trace_rpc_task_sync_sleep(task, task->tk_action); |
96651ab34 [PATCH] RPC: Shri... |
895 |
status = out_of_line_wait_on_bit(&task->tk_runstate, |
150030b78 NFS: Switch from ... |
896 897 |
RPC_TASK_QUEUED, rpc_wait_bit_killable, TASK_KILLABLE); |
ae67bd382 SUNRPC: Fix up ta... |
898 |
if (status < 0) { |
1da177e4c 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 SUNRPC: Capture s... |
905 |
trace_rpc_task_signalled(task, task->tk_action); |
ae67bd382 SUNRPC: Fix up ta... |
906 |
set_bit(RPC_TASK_SIGNALLED, &task->tk_runstate); |
714fbc738 SUNRPC: RPC level... |
907 |
task->tk_rpc_status = -ERESTARTSYS; |
96651ab34 [PATCH] RPC: Shri... |
908 |
rpc_exit(task, -ERESTARTSYS); |
1da177e4c Linux-2.6.12-rc2 |
909 |
} |
1466c2216 SUNRPC: Clean up ... |
910 |
trace_rpc_task_sync_wake(task, task->tk_action); |
1da177e4c Linux-2.6.12-rc2 |
911 |
} |
1da177e4c Linux-2.6.12-rc2 |
912 913 |
/* Release all resources associated with the task */ rpc_release_task(task); |
1da177e4c 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 RPC: Clean up rpc... |
925 |
void rpc_execute(struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
926 |
{ |
a76580fbf SUNRPC: Fix a pot... |
927 |
bool is_async = RPC_IS_ASYNC(task); |
44c288732 NFSv4: stateful N... |
928 |
rpc_set_active(task); |
f1dc237c6 SUNRPC: Reduce la... |
929 |
rpc_make_runnable(rpciod_workqueue, task); |
a76580fbf SUNRPC: Fix a pot... |
930 |
if (!is_async) |
d6a1ed08c SUNRPC: Reduce as... |
931 |
__rpc_execute(task); |
1da177e4c Linux-2.6.12-rc2 |
932 |
} |
65f27f384 WorkStruct: Pass ... |
933 |
static void rpc_async_schedule(struct work_struct *work) |
1da177e4c Linux-2.6.12-rc2 |
934 |
{ |
a1231fda7 SUNRPC: Set memal... |
935 |
unsigned int pflags = memalloc_nofs_save(); |
65f27f384 WorkStruct: Pass ... |
936 |
__rpc_execute(container_of(work, struct rpc_task, u.tk_work)); |
a1231fda7 SUNRPC: Set memal... |
937 |
memalloc_nofs_restore(pflags); |
1da177e4c Linux-2.6.12-rc2 |
938 |
} |
021071483 SUNRPC: switchabl... |
939 |
/** |
5fe6eaa1f 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 Linux-2.6.12-rc2 |
946 |
* |
c5a4dd8b7 SUNRPC: Eliminate... |
947 |
* To prevent rpciod from hanging, this allocator never sleeps, |
5fe6eaa1f 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 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 Linux-2.6.12-rc2 |
955 |
*/ |
5fe6eaa1f SUNRPC: Generaliz... |
956 |
int rpc_malloc(struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
957 |
{ |
5fe6eaa1f SUNRPC: Generaliz... |
958 959 |
struct rpc_rqst *rqst = task->tk_rqstp; size_t size = rqst->rq_callsize + rqst->rq_rcvsize; |
aa3d1faeb SUNRPC: Fix point... |
960 |
struct rpc_buffer *buf; |
12a3ad618 SUNRPC: Convert r... |
961 |
gfp_t gfp = GFP_NOFS; |
a564b8f03 nfs: enable swap ... |
962 963 |
if (RPC_IS_SWAPPER(task)) |
c4a7ca774 SUNRPC: Allow wai... |
964 |
gfp = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN; |
1da177e4c Linux-2.6.12-rc2 |
965 |
|
aa3d1faeb SUNRPC: Fix point... |
966 |
size += sizeof(struct rpc_buffer); |
c5a4dd8b7 SUNRPC: Eliminate... |
967 968 |
if (size <= RPC_BUFFER_MAXSIZE) buf = mempool_alloc(rpc_buffer_mempool, gfp); |
1da177e4c Linux-2.6.12-rc2 |
969 |
else |
c5a4dd8b7 SUNRPC: Eliminate... |
970 |
buf = kmalloc(size, gfp); |
ddce40df6 sunrpc: fix crash... |
971 972 |
if (!buf) |
5fe6eaa1f SUNRPC: Generaliz... |
973 |
return -ENOMEM; |
ddce40df6 sunrpc: fix crash... |
974 |
|
aa3d1faeb SUNRPC: Fix point... |
975 |
buf->len = size; |
5fe6eaa1f SUNRPC: Generaliz... |
976 |
rqst->rq_buffer = buf->data; |
68778945e SUNRPC: Separate ... |
977 |
rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize; |
5fe6eaa1f SUNRPC: Generaliz... |
978 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
979 |
} |
124448097 SUNRPC: add EXPOR... |
980 |
EXPORT_SYMBOL_GPL(rpc_malloc); |
1da177e4c Linux-2.6.12-rc2 |
981 |
|
021071483 SUNRPC: switchabl... |
982 |
/** |
3435c74ae SUNRPC: Generaliz... |
983 984 |
* rpc_free - free RPC buffer resources allocated via rpc_malloc * @task: RPC task |
021071483 SUNRPC: switchabl... |
985 986 |
* */ |
3435c74ae SUNRPC: Generaliz... |
987 |
void rpc_free(struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
988 |
{ |
3435c74ae SUNRPC: Generaliz... |
989 |
void *buffer = task->tk_rqstp->rq_buffer; |
aa3d1faeb SUNRPC: Fix point... |
990 991 |
size_t size; struct rpc_buffer *buf; |
021071483 SUNRPC: switchabl... |
992 |
|
aa3d1faeb SUNRPC: Fix point... |
993 994 |
buf = container_of(buffer, struct rpc_buffer, data); size = buf->len; |
c5a4dd8b7 SUNRPC: Eliminate... |
995 |
|
c5a4dd8b7 SUNRPC: Eliminate... |
996 997 998 999 |
if (size <= RPC_BUFFER_MAXSIZE) mempool_free(buf, rpc_buffer_mempool); else kfree(buf); |
1da177e4c Linux-2.6.12-rc2 |
1000 |
} |
124448097 SUNRPC: add EXPOR... |
1001 |
EXPORT_SYMBOL_GPL(rpc_free); |
1da177e4c Linux-2.6.12-rc2 |
1002 1003 1004 1005 |
/* * Creation and deletion of RPC task structures */ |
47fe06483 SUNRPC: Unexport ... |
1006 |
static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data) |
1da177e4c Linux-2.6.12-rc2 |
1007 1008 |
{ memset(task, 0, sizeof(*task)); |
44c288732 NFSv4: stateful N... |
1009 |
atomic_set(&task->tk_count, 1); |
84115e1cd 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 SUNRPC: Move rpc_... |
1013 |
INIT_LIST_HEAD(&task->tk_task); |
1da177e4c Linux-2.6.12-rc2 |
1014 |
|
3ff7576dd SUNRPC: Clean up ... |
1015 1016 |
task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; task->tk_owner = current->tgid; |
1da177e4c Linux-2.6.12-rc2 |
1017 1018 |
/* Initialize workqueue for async tasks */ |
32bfb5c0f SUNRPC: Allow the... |
1019 |
task->tk_workqueue = task_setup_data->workqueue; |
1da177e4c Linux-2.6.12-rc2 |
1020 |
|
a101b043c 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 SUNRPC: Allow cal... |
1023 |
|
1de7eea92 SUNRPC: add side ... |
1024 |
task->tk_op_cred = get_rpccred(task_setup_data->rpc_op_cred); |
84115e1cd SUNRPC: Cleanup o... |
1025 1026 |
if (task->tk_ops->rpc_call_prepare != NULL) task->tk_action = rpc_prepare_task; |
963d8fe53 RPC: Clean up RPC... |
1027 |
|
7fdcf13b2 SUNRPC: Fix the e... |
1028 |
rpc_init_task_statistics(task); |
1da177e4c Linux-2.6.12-rc2 |
1029 1030 1031 1032 1033 |
} static struct rpc_task * rpc_alloc_task(void) { |
12a3ad618 SUNRPC: Convert r... |
1034 |
return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); |
1da177e4c Linux-2.6.12-rc2 |
1035 |
} |
1da177e4c Linux-2.6.12-rc2 |
1036 |
/* |
90c5755ff SUNRPC: Kill rpc_... |
1037 |
* Create a new task for the specified client. |
1da177e4c Linux-2.6.12-rc2 |
1038 |
*/ |
84115e1cd SUNRPC: Cleanup o... |
1039 |
struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) |
1da177e4c Linux-2.6.12-rc2 |
1040 |
{ |
e8f5d77c8 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 SUNRPC: allow the... |
1046 1047 |
flags = RPC_TASK_DYNAMIC; } |
1da177e4c Linux-2.6.12-rc2 |
1048 |
|
84115e1cd SUNRPC: Cleanup o... |
1049 |
rpc_init_task(task, setup_data); |
e8f5d77c8 SUNRPC: allow the... |
1050 |
task->tk_flags |= flags; |
1da177e4c Linux-2.6.12-rc2 |
1051 |
return task; |
1da177e4c Linux-2.6.12-rc2 |
1052 |
} |
c6567ed14 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 SUNRPC: Allow the... |
1072 |
static void rpc_free_task(struct rpc_task *task) |
1da177e4c Linux-2.6.12-rc2 |
1073 |
{ |
c6567ed14 SUNRPC: Ensure th... |
1074 |
unsigned short tk_flags = task->tk_flags; |
1de7eea92 SUNRPC: add side ... |
1075 |
put_rpccred(task->tk_op_cred); |
c6567ed14 SUNRPC: Ensure th... |
1076 |
rpc_release_calldata(task->tk_ops, task->tk_calldata); |
1da177e4c Linux-2.6.12-rc2 |
1077 |
|
1466c2216 SUNRPC: Clean up ... |
1078 |
if (tk_flags & RPC_TASK_DYNAMIC) |
5e4424af9 SUNRPC: Remove no... |
1079 |
mempool_free(task, rpc_task_mempool); |
32bfb5c0f SUNRPC: Allow the... |
1080 1081 1082 1083 |
} static void rpc_async_release(struct work_struct *work) { |
a1231fda7 SUNRPC: Set memal... |
1084 |
unsigned int pflags = memalloc_nofs_save(); |
32bfb5c0f SUNRPC: Allow the... |
1085 |
rpc_free_task(container_of(work, struct rpc_task, u.tk_work)); |
a1231fda7 SUNRPC: Set memal... |
1086 |
memalloc_nofs_restore(pflags); |
32bfb5c0f SUNRPC: Allow the... |
1087 |
} |
bf294b41c SUNRPC: Close a r... |
1088 |
static void rpc_release_resources_task(struct rpc_task *task) |
32bfb5c0f SUNRPC: Allow the... |
1089 |
{ |
87ed50036 SUNRPC: Ensure we... |
1090 |
xprt_release(task); |
a271c5a0d NFS: Ensure that ... |
1091 |
if (task->tk_msg.rpc_cred) { |
7eac52648 SUNRPC: Add a fla... |
1092 1093 |
if (!(task->tk_flags & RPC_TASK_CRED_NOREF)) put_cred(task->tk_msg.rpc_cred); |
a271c5a0d NFS: Ensure that ... |
1094 1095 |
task->tk_msg.rpc_cred = NULL; } |
58f9612c6 SUNRPC: Move rema... |
1096 |
rpc_task_release_client(task); |
bf294b41c 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 SUNRPC: Allow the... |
1103 |
INIT_WORK(&task->u.tk_work, rpc_async_release); |
bf294b41c SUNRPC: Close a r... |
1104 |
queue_work(q, &task->u.tk_work); |
32bfb5c0f SUNRPC: Allow the... |
1105 1106 |
} else rpc_free_task(task); |
e6b3c4db6 Fix a second pote... |
1107 |
} |
bf294b41c 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 SUNRPC: Restrict ... |
1121 |
EXPORT_SYMBOL_GPL(rpc_put_task); |
e6b3c4db6 Fix a second pote... |
1122 |
|
bf294b41c 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 [PATCH] NFS: Fix ... |
1128 |
static void rpc_release_task(struct rpc_task *task) |
e6b3c4db6 Fix a second pote... |
1129 |
{ |
0a0c2a57b SUNRPC: remove BU... |
1130 |
WARN_ON_ONCE(RPC_IS_QUEUED(task)); |
1da177e4c Linux-2.6.12-rc2 |
1131 |
|
bf294b41c SUNRPC: Close a r... |
1132 |
rpc_release_resources_task(task); |
e6b3c4db6 Fix a second pote... |
1133 |
|
bf294b41c 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 Linux-2.6.12-rc2 |
1148 |
} |
b247bbf1d 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 Linux-2.6.12-rc2 |
1158 |
/* |
b247bbf1d SUNRPC: Fix a rac... |
1159 |
* Start up the rpciod workqueue. |
1da177e4c Linux-2.6.12-rc2 |
1160 |
*/ |
b247bbf1d SUNRPC: Fix a rac... |
1161 |
static int rpciod_start(void) |
1da177e4c Linux-2.6.12-rc2 |
1162 1163 |
{ struct workqueue_struct *wq; |
ab418d70e SUNRPC: Optimise ... |
1164 |
|
1da177e4c Linux-2.6.12-rc2 |
1165 1166 1167 |
/* * Create the rpciod thread and wait for it to start. */ |
f515f86b3 fix parallelism f... |
1168 |
wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); |
40a5f1b19 SUNRPC: RPC trans... |
1169 1170 |
if (!wq) goto out_failed; |
1da177e4c Linux-2.6.12-rc2 |
1171 |
rpciod_workqueue = wq; |
40a5f1b19 SUNRPC: RPC trans... |
1172 |
/* Note: highpri because network receive is latency sensitive */ |
90ea9f1b6 Make the xprtiod ... |
1173 |
wq = alloc_workqueue("xprtiod", WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_HIGHPRI, 0); |
40a5f1b19 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 Linux-2.6.12-rc2 |
1184 |
} |
b247bbf1d SUNRPC: Fix a rac... |
1185 |
static void rpciod_stop(void) |
1da177e4c Linux-2.6.12-rc2 |
1186 |
{ |
b247bbf1d SUNRPC: Fix a rac... |
1187 |
struct workqueue_struct *wq = NULL; |
ab418d70e SUNRPC: Optimise ... |
1188 |
|
b247bbf1d SUNRPC: Fix a rac... |
1189 1190 |
if (rpciod_workqueue == NULL) return; |
1da177e4c Linux-2.6.12-rc2 |
1191 |
|
b247bbf1d SUNRPC: Fix a rac... |
1192 1193 1194 |
wq = rpciod_workqueue; rpciod_workqueue = NULL; destroy_workqueue(wq); |
40a5f1b19 SUNRPC: RPC trans... |
1195 1196 1197 |
wq = xprtiod_workqueue; xprtiod_workqueue = NULL; destroy_workqueue(wq); |
1da177e4c Linux-2.6.12-rc2 |
1198 |
} |
1da177e4c Linux-2.6.12-rc2 |
1199 1200 1201 |
void rpc_destroy_mempool(void) { |
b247bbf1d SUNRPC: Fix a rac... |
1202 |
rpciod_stop(); |
17a9618e9 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 SUNRPC: Add a (em... |
1207 |
rpc_destroy_wait_queue(&delay_queue); |
1da177e4c Linux-2.6.12-rc2 |
1208 1209 1210 1211 1212 |
} int rpc_init_mempool(void) { |
f6a1cc893 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 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 mm: Remove slab d... |
1223 |
NULL); |
1da177e4c 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 mm: Remove slab d... |
1229 |
NULL); |
1da177e4c Linux-2.6.12-rc2 |
1230 1231 |
if (!rpc_buffer_slabp) goto err_nomem; |
93d2341c7 [PATCH] mempool: ... |
1232 1233 |
rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE, rpc_task_slabp); |
1da177e4c Linux-2.6.12-rc2 |
1234 1235 |
if (!rpc_task_mempool) goto err_nomem; |
93d2341c7 [PATCH] mempool: ... |
1236 1237 |
rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE, rpc_buffer_slabp); |
1da177e4c 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; } |