diff options
Diffstat (limited to 'net/9p')
-rw-r--r-- | net/9p/trans_fd.c | 252 |
1 files changed, 86 insertions, 166 deletions
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index 6dabbdb66651..f84592345573 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
@@ -44,7 +44,6 @@ | |||
44 | #define P9_PORT 564 | 44 | #define P9_PORT 564 |
45 | #define MAX_SOCK_BUF (64*1024) | 45 | #define MAX_SOCK_BUF (64*1024) |
46 | #define ERREQFLUSH 1 | 46 | #define ERREQFLUSH 1 |
47 | #define SCHED_TIMEOUT 10 | ||
48 | #define MAXPOLLWADDR 2 | 47 | #define MAXPOLLWADDR 2 |
49 | 48 | ||
50 | /** | 49 | /** |
@@ -135,17 +134,16 @@ struct p9_req { | |||
135 | struct list_head req_list; | 134 | struct list_head req_list; |
136 | }; | 135 | }; |
137 | 136 | ||
138 | struct p9_mux_poll_task { | 137 | struct p9_poll_wait { |
139 | struct task_struct *task; | 138 | struct p9_conn *conn; |
140 | struct list_head mux_list; | 139 | wait_queue_t wait; |
141 | int muxnum; | 140 | wait_queue_head_t *wait_addr; |
142 | }; | 141 | }; |
143 | 142 | ||
144 | /** | 143 | /** |
145 | * struct p9_conn - fd mux connection state information | 144 | * struct p9_conn - fd mux connection state information |
146 | * @lock: protects mux_list (?) | 145 | * @lock: protects mux_list (?) |
147 | * @mux_list: list link for mux to manage multiple connections (?) | 146 | * @mux_list: list link for mux to manage multiple connections (?) |
148 | * @poll_task: task polling on this connection | ||
149 | * @msize: maximum size for connection (dup) | 147 | * @msize: maximum size for connection (dup) |
150 | * @extended: 9p2000.u flag (dup) | 148 | * @extended: 9p2000.u flag (dup) |
151 | * @trans: reference to transport instance for this connection | 149 | * @trans: reference to transport instance for this connection |
@@ -171,7 +169,6 @@ struct p9_mux_poll_task { | |||
171 | struct p9_conn { | 169 | struct p9_conn { |
172 | spinlock_t lock; /* protect lock structure */ | 170 | spinlock_t lock; /* protect lock structure */ |
173 | struct list_head mux_list; | 171 | struct list_head mux_list; |
174 | struct p9_mux_poll_task *poll_task; | ||
175 | int msize; | 172 | int msize; |
176 | unsigned char extended; | 173 | unsigned char extended; |
177 | struct p9_trans *trans; | 174 | struct p9_trans *trans; |
@@ -185,8 +182,8 @@ struct p9_conn { | |||
185 | int wpos; | 182 | int wpos; |
186 | int wsize; | 183 | int wsize; |
187 | char *wbuf; | 184 | char *wbuf; |
188 | wait_queue_t poll_wait[MAXPOLLWADDR]; | 185 | struct list_head poll_pending_link; |
189 | wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; | 186 | struct p9_poll_wait poll_wait[MAXPOLLWADDR]; |
190 | poll_table pt; | 187 | poll_table pt; |
191 | struct work_struct rq; | 188 | struct work_struct rq; |
192 | struct work_struct wq; | 189 | struct work_struct wq; |
@@ -220,12 +217,10 @@ static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
220 | static int p9_fd_write(struct p9_trans *trans, void *v, int len); | 217 | static int p9_fd_write(struct p9_trans *trans, void *v, int len); |
221 | static int p9_fd_read(struct p9_trans *trans, void *v, int len); | 218 | static int p9_fd_read(struct p9_trans *trans, void *v, int len); |
222 | 219 | ||
223 | static DEFINE_MUTEX(p9_mux_task_lock); | 220 | static DEFINE_SPINLOCK(p9_poll_lock); |
221 | static LIST_HEAD(p9_poll_pending_list); | ||
224 | static struct workqueue_struct *p9_mux_wq; | 222 | static struct workqueue_struct *p9_mux_wq; |
225 | 223 | static struct task_struct *p9_poll_task; | |
226 | static int p9_mux_num; | ||
227 | static int p9_mux_poll_task_num; | ||
228 | static struct p9_mux_poll_task p9_mux_poll_tasks[100]; | ||
229 | 224 | ||
230 | static void p9_conn_destroy(struct p9_conn *); | 225 | static void p9_conn_destroy(struct p9_conn *); |
231 | static unsigned int p9_fd_poll(struct p9_trans *trans, | 226 | static unsigned int p9_fd_poll(struct p9_trans *trans, |
@@ -255,130 +250,23 @@ static void p9_mux_put_tag(struct p9_conn *m, u16 tag) | |||
255 | p9_idpool_put(tag, m->tagpool); | 250 | p9_idpool_put(tag, m->tagpool); |
256 | } | 251 | } |
257 | 252 | ||
258 | /** | 253 | static void p9_mux_poll_stop(struct p9_conn *m) |
259 | * p9_mux_calc_poll_procs - calculates the number of polling procs | ||
260 | * @muxnum: number of mounts | ||
261 | * | ||
262 | * Calculation is based on the number of mounted v9fs filesystems. | ||
263 | * The current implementation returns sqrt of the number of mounts. | ||
264 | */ | ||
265 | |||
266 | static int p9_mux_calc_poll_procs(int muxnum) | ||
267 | { | ||
268 | int n; | ||
269 | |||
270 | if (p9_mux_poll_task_num) | ||
271 | n = muxnum / p9_mux_poll_task_num + | ||
272 | (muxnum % p9_mux_poll_task_num ? 1 : 0); | ||
273 | else | ||
274 | n = 1; | ||
275 | |||
276 | if (n > ARRAY_SIZE(p9_mux_poll_tasks)) | ||
277 | n = ARRAY_SIZE(p9_mux_poll_tasks); | ||
278 | |||
279 | return n; | ||
280 | } | ||
281 | |||
282 | static int p9_mux_poll_start(struct p9_conn *m) | ||
283 | { | 254 | { |
284 | int i, n; | 255 | unsigned long flags; |
285 | struct p9_mux_poll_task *vpt, *vptlast; | 256 | int i; |
286 | struct task_struct *pproc; | ||
287 | |||
288 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num, | ||
289 | p9_mux_poll_task_num); | ||
290 | mutex_lock(&p9_mux_task_lock); | ||
291 | |||
292 | n = p9_mux_calc_poll_procs(p9_mux_num + 1); | ||
293 | if (n > p9_mux_poll_task_num) { | ||
294 | for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) { | ||
295 | if (p9_mux_poll_tasks[i].task == NULL) { | ||
296 | vpt = &p9_mux_poll_tasks[i]; | ||
297 | P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n", | ||
298 | vpt); | ||
299 | pproc = kthread_create(p9_poll_proc, vpt, | ||
300 | "v9fs-poll"); | ||
301 | |||
302 | if (!IS_ERR(pproc)) { | ||
303 | vpt->task = pproc; | ||
304 | INIT_LIST_HEAD(&vpt->mux_list); | ||
305 | vpt->muxnum = 0; | ||
306 | p9_mux_poll_task_num++; | ||
307 | wake_up_process(vpt->task); | ||
308 | } | ||
309 | break; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) | ||
314 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
315 | "warning: no free poll slots\n"); | ||
316 | } | ||
317 | 257 | ||
318 | n = (p9_mux_num + 1) / p9_mux_poll_task_num + | 258 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { |
319 | ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0); | 259 | struct p9_poll_wait *pwait = &m->poll_wait[i]; |
320 | |||
321 | vptlast = NULL; | ||
322 | for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) { | ||
323 | vpt = &p9_mux_poll_tasks[i]; | ||
324 | if (vpt->task != NULL) { | ||
325 | vptlast = vpt; | ||
326 | if (vpt->muxnum < n) { | ||
327 | P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i); | ||
328 | list_add(&m->mux_list, &vpt->mux_list); | ||
329 | vpt->muxnum++; | ||
330 | m->poll_task = vpt; | ||
331 | memset(&m->poll_waddr, 0, | ||
332 | sizeof(m->poll_waddr)); | ||
333 | init_poll_funcptr(&m->pt, p9_pollwait); | ||
334 | break; | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | 260 | ||
339 | if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) { | 261 | if (pwait->wait_addr) { |
340 | if (vptlast == NULL) { | 262 | remove_wait_queue(pwait->wait_addr, &pwait->wait); |
341 | mutex_unlock(&p9_mux_task_lock); | 263 | pwait->wait_addr = NULL; |
342 | return -ENOMEM; | ||
343 | } | 264 | } |
344 | |||
345 | P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i); | ||
346 | list_add(&m->mux_list, &vptlast->mux_list); | ||
347 | vptlast->muxnum++; | ||
348 | m->poll_task = vptlast; | ||
349 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | ||
350 | init_poll_funcptr(&m->pt, p9_pollwait); | ||
351 | } | 265 | } |
352 | 266 | ||
353 | p9_mux_num++; | 267 | spin_lock_irqsave(&p9_poll_lock, flags); |
354 | mutex_unlock(&p9_mux_task_lock); | 268 | list_del_init(&m->poll_pending_link); |
355 | 269 | spin_unlock_irqrestore(&p9_poll_lock, flags); | |
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static void p9_mux_poll_stop(struct p9_conn *m) | ||
360 | { | ||
361 | int i; | ||
362 | struct p9_mux_poll_task *vpt; | ||
363 | |||
364 | mutex_lock(&p9_mux_task_lock); | ||
365 | vpt = m->poll_task; | ||
366 | list_del(&m->mux_list); | ||
367 | for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { | ||
368 | if (m->poll_waddr[i] != NULL) { | ||
369 | remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); | ||
370 | m->poll_waddr[i] = NULL; | ||
371 | } | ||
372 | } | ||
373 | vpt->muxnum--; | ||
374 | if (!vpt->muxnum) { | ||
375 | P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt); | ||
376 | kthread_stop(vpt->task); | ||
377 | vpt->task = NULL; | ||
378 | p9_mux_poll_task_num--; | ||
379 | } | ||
380 | p9_mux_num--; | ||
381 | mutex_unlock(&p9_mux_task_lock); | ||
382 | } | 270 | } |
383 | 271 | ||
384 | /** | 272 | /** |
@@ -414,11 +302,8 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) | |||
414 | INIT_LIST_HEAD(&m->unsent_req_list); | 302 | INIT_LIST_HEAD(&m->unsent_req_list); |
415 | INIT_WORK(&m->rq, p9_read_work); | 303 | INIT_WORK(&m->rq, p9_read_work); |
416 | INIT_WORK(&m->wq, p9_write_work); | 304 | INIT_WORK(&m->wq, p9_write_work); |
417 | n = p9_mux_poll_start(m); | 305 | INIT_LIST_HEAD(&m->poll_pending_link); |
418 | if (n) { | 306 | init_poll_funcptr(&m->pt, p9_pollwait); |
419 | kfree(m); | ||
420 | return ERR_PTR(n); | ||
421 | } | ||
422 | 307 | ||
423 | n = p9_fd_poll(trans, &m->pt); | 308 | n = p9_fd_poll(trans, &m->pt); |
424 | if (n & POLLIN) { | 309 | if (n & POLLIN) { |
@@ -431,11 +316,12 @@ static struct p9_conn *p9_conn_create(struct p9_trans *trans) | |||
431 | set_bit(Wpending, &m->wsched); | 316 | set_bit(Wpending, &m->wsched); |
432 | } | 317 | } |
433 | 318 | ||
434 | for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { | 319 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { |
435 | if (IS_ERR(m->poll_waddr[i])) { | 320 | if (IS_ERR(m->poll_wait[i].wait_addr)) { |
436 | p9_mux_poll_stop(m); | 321 | p9_mux_poll_stop(m); |
437 | kfree(m); | 322 | kfree(m); |
438 | return (void *)m->poll_waddr; /* the error code */ | 323 | /* return the error code */ |
324 | return (void *)m->poll_wait[i].wait_addr; | ||
439 | } | 325 | } |
440 | } | 326 | } |
441 | 327 | ||
@@ -464,6 +350,23 @@ static void p9_conn_destroy(struct p9_conn *m) | |||
464 | kfree(m); | 350 | kfree(m); |
465 | } | 351 | } |
466 | 352 | ||
353 | static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
354 | { | ||
355 | struct p9_poll_wait *pwait = | ||
356 | container_of(wait, struct p9_poll_wait, wait); | ||
357 | struct p9_conn *m = pwait->conn; | ||
358 | unsigned long flags; | ||
359 | DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); | ||
360 | |||
361 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
362 | if (list_empty(&m->poll_pending_link)) | ||
363 | list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); | ||
364 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
365 | |||
366 | /* perform the default wake up operation */ | ||
367 | return default_wake_function(&dummy_wait, mode, sync, key); | ||
368 | } | ||
369 | |||
467 | /** | 370 | /** |
468 | * p9_pollwait - add poll task to the wait queue | 371 | * p9_pollwait - add poll task to the wait queue |
469 | * @filp: file pointer being polled | 372 | * @filp: file pointer being polled |
@@ -476,29 +379,32 @@ static void p9_conn_destroy(struct p9_conn *m) | |||
476 | static void | 379 | static void |
477 | p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) | 380 | p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) |
478 | { | 381 | { |
382 | struct p9_conn *m = container_of(p, struct p9_conn, pt); | ||
383 | struct p9_poll_wait *pwait = NULL; | ||
479 | int i; | 384 | int i; |
480 | struct p9_conn *m; | ||
481 | 385 | ||
482 | m = container_of(p, struct p9_conn, pt); | 386 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { |
483 | for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) | 387 | if (m->poll_wait[i].wait_addr == NULL) { |
484 | if (m->poll_waddr[i] == NULL) | 388 | pwait = &m->poll_wait[i]; |
485 | break; | 389 | break; |
390 | } | ||
391 | } | ||
486 | 392 | ||
487 | if (i >= ARRAY_SIZE(m->poll_waddr)) { | 393 | if (!pwait) { |
488 | P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); | 394 | P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); |
489 | return; | 395 | return; |
490 | } | 396 | } |
491 | 397 | ||
492 | m->poll_waddr[i] = wait_address; | ||
493 | |||
494 | if (!wait_address) { | 398 | if (!wait_address) { |
495 | P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); | 399 | P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); |
496 | m->poll_waddr[i] = ERR_PTR(-EIO); | 400 | pwait->wait_addr = ERR_PTR(-EIO); |
497 | return; | 401 | return; |
498 | } | 402 | } |
499 | 403 | ||
500 | init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); | 404 | pwait->conn = m; |
501 | add_wait_queue(wait_address, &m->poll_wait[i]); | 405 | pwait->wait_addr = wait_address; |
406 | init_waitqueue_func_entry(&pwait->wait, p9_pollwake); | ||
407 | add_wait_queue(wait_address, &pwait->wait); | ||
502 | } | 408 | } |
503 | 409 | ||
504 | /** | 410 | /** |
@@ -553,23 +459,34 @@ static void p9_poll_mux(struct p9_conn *m) | |||
553 | 459 | ||
554 | static int p9_poll_proc(void *a) | 460 | static int p9_poll_proc(void *a) |
555 | { | 461 | { |
556 | struct p9_conn *m, *mtmp; | 462 | unsigned long flags; |
557 | struct p9_mux_poll_task *vpt; | ||
558 | 463 | ||
559 | vpt = a; | 464 | P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); |
560 | P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt); | 465 | repeat: |
561 | while (!kthread_should_stop()) { | 466 | spin_lock_irqsave(&p9_poll_lock, flags); |
562 | set_current_state(TASK_INTERRUPTIBLE); | 467 | while (!list_empty(&p9_poll_pending_list)) { |
468 | struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, | ||
469 | struct p9_conn, | ||
470 | poll_pending_link); | ||
471 | list_del_init(&conn->poll_pending_link); | ||
472 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
563 | 473 | ||
564 | list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { | 474 | p9_poll_mux(conn); |
565 | p9_poll_mux(m); | ||
566 | } | ||
567 | 475 | ||
568 | P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); | 476 | spin_lock_irqsave(&p9_poll_lock, flags); |
569 | schedule_timeout(SCHED_TIMEOUT * HZ); | ||
570 | } | 477 | } |
478 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
571 | 479 | ||
480 | set_current_state(TASK_INTERRUPTIBLE); | ||
481 | if (list_empty(&p9_poll_pending_list)) { | ||
482 | P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); | ||
483 | schedule(); | ||
484 | } | ||
572 | __set_current_state(TASK_RUNNING); | 485 | __set_current_state(TASK_RUNNING); |
486 | |||
487 | if (!kthread_should_stop()) | ||
488 | goto repeat; | ||
489 | |||
573 | P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); | 490 | P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); |
574 | return 0; | 491 | return 0; |
575 | } | 492 | } |
@@ -1602,17 +1519,19 @@ static struct p9_trans_module p9_fd_trans = { | |||
1602 | 1519 | ||
1603 | int p9_trans_fd_init(void) | 1520 | int p9_trans_fd_init(void) |
1604 | { | 1521 | { |
1605 | int i; | ||
1606 | |||
1607 | for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) | ||
1608 | p9_mux_poll_tasks[i].task = NULL; | ||
1609 | |||
1610 | p9_mux_wq = create_workqueue("v9fs"); | 1522 | p9_mux_wq = create_workqueue("v9fs"); |
1611 | if (!p9_mux_wq) { | 1523 | if (!p9_mux_wq) { |
1612 | printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); | 1524 | printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n"); |
1613 | return -ENOMEM; | 1525 | return -ENOMEM; |
1614 | } | 1526 | } |
1615 | 1527 | ||
1528 | p9_poll_task = kthread_run(p9_poll_proc, NULL, "v9fs-poll"); | ||
1529 | if (IS_ERR(p9_poll_task)) { | ||
1530 | destroy_workqueue(p9_mux_wq); | ||
1531 | printk(KERN_WARNING "v9fs: mux: creating poll task failed\n"); | ||
1532 | return PTR_ERR(p9_poll_task); | ||
1533 | } | ||
1534 | |||
1616 | v9fs_register_trans(&p9_tcp_trans); | 1535 | v9fs_register_trans(&p9_tcp_trans); |
1617 | v9fs_register_trans(&p9_unix_trans); | 1536 | v9fs_register_trans(&p9_unix_trans); |
1618 | v9fs_register_trans(&p9_fd_trans); | 1537 | v9fs_register_trans(&p9_fd_trans); |
@@ -1622,6 +1541,7 @@ int p9_trans_fd_init(void) | |||
1622 | 1541 | ||
1623 | void p9_trans_fd_exit(void) | 1542 | void p9_trans_fd_exit(void) |
1624 | { | 1543 | { |
1544 | kthread_stop(p9_poll_task); | ||
1625 | v9fs_unregister_trans(&p9_tcp_trans); | 1545 | v9fs_unregister_trans(&p9_tcp_trans); |
1626 | v9fs_unregister_trans(&p9_unix_trans); | 1546 | v9fs_unregister_trans(&p9_unix_trans); |
1627 | v9fs_unregister_trans(&p9_fd_trans); | 1547 | v9fs_unregister_trans(&p9_fd_trans); |