diff options
Diffstat (limited to 'net/9p/trans_fd.c')
-rw-r--r-- | net/9p/trans_fd.c | 860 |
1 files changed, 406 insertions, 454 deletions
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index bc5b6965981b..334d39cc5ba3 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
@@ -61,7 +61,6 @@ struct p9_fd_opts { | |||
61 | u16 port; | 61 | u16 port; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | |||
65 | /** | 64 | /** |
66 | * struct p9_trans_fd - transport state | 65 | * struct p9_trans_fd - transport state |
67 | * @rd: reference to file to read from | 66 | * @rd: reference to file to read from |
@@ -206,30 +205,11 @@ struct p9_mux_rpc { | |||
206 | wait_queue_head_t wqueue; | 205 | wait_queue_head_t wqueue; |
207 | }; | 206 | }; |
208 | 207 | ||
209 | static int p9_poll_proc(void *); | ||
210 | static void p9_read_work(struct work_struct *work); | ||
211 | static void p9_write_work(struct work_struct *work); | ||
212 | static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, | ||
213 | poll_table *p); | ||
214 | static int p9_fd_write(struct p9_client *client, void *v, int len); | ||
215 | static int p9_fd_read(struct p9_client *client, void *v, int len); | ||
216 | |||
217 | static DEFINE_SPINLOCK(p9_poll_lock); | 208 | static DEFINE_SPINLOCK(p9_poll_lock); |
218 | static LIST_HEAD(p9_poll_pending_list); | 209 | static LIST_HEAD(p9_poll_pending_list); |
219 | static struct workqueue_struct *p9_mux_wq; | 210 | static struct workqueue_struct *p9_mux_wq; |
220 | static struct task_struct *p9_poll_task; | 211 | static struct task_struct *p9_poll_task; |
221 | 212 | ||
222 | static void p9_conn_destroy(struct p9_conn *); | ||
223 | static unsigned int p9_fd_poll(struct p9_client *client, | ||
224 | struct poll_table_struct *pt); | ||
225 | |||
226 | #ifdef P9_NONBLOCK | ||
227 | static int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, | ||
228 | p9_conn_req_callback cb, void *a); | ||
229 | #endif /* P9_NONBLOCK */ | ||
230 | |||
231 | static void p9_conn_cancel(struct p9_conn *m, int err); | ||
232 | |||
233 | static u16 p9_mux_get_tag(struct p9_conn *m) | 213 | static u16 p9_mux_get_tag(struct p9_conn *m) |
234 | { | 214 | { |
235 | int tag; | 215 | int tag; |
@@ -267,303 +247,38 @@ static void p9_mux_poll_stop(struct p9_conn *m) | |||
267 | } | 247 | } |
268 | 248 | ||
269 | /** | 249 | /** |
270 | * p9_conn_create - allocate and initialize the per-session mux data | 250 | * p9_conn_cancel - cancel all pending requests with error |
271 | * @client: client instance | 251 | * @m: mux data |
272 | * | 252 | * @err: error code |
273 | * Note: Creates the polling task if this is the first session. | ||
274 | */ | ||
275 | |||
276 | static struct p9_conn *p9_conn_create(struct p9_client *client) | ||
277 | { | ||
278 | int i, n; | ||
279 | struct p9_conn *m; | ||
280 | |||
281 | P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); | ||
282 | m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); | ||
283 | if (!m) | ||
284 | return ERR_PTR(-ENOMEM); | ||
285 | |||
286 | spin_lock_init(&m->lock); | ||
287 | INIT_LIST_HEAD(&m->mux_list); | ||
288 | m->client = client; | ||
289 | m->tagpool = p9_idpool_create(); | ||
290 | if (IS_ERR(m->tagpool)) { | ||
291 | kfree(m); | ||
292 | return ERR_PTR(-ENOMEM); | ||
293 | } | ||
294 | |||
295 | INIT_LIST_HEAD(&m->req_list); | ||
296 | INIT_LIST_HEAD(&m->unsent_req_list); | ||
297 | INIT_WORK(&m->rq, p9_read_work); | ||
298 | INIT_WORK(&m->wq, p9_write_work); | ||
299 | INIT_LIST_HEAD(&m->poll_pending_link); | ||
300 | init_poll_funcptr(&m->pt, p9_pollwait); | ||
301 | |||
302 | n = p9_fd_poll(client, &m->pt); | ||
303 | if (n & POLLIN) { | ||
304 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); | ||
305 | set_bit(Rpending, &m->wsched); | ||
306 | } | ||
307 | |||
308 | if (n & POLLOUT) { | ||
309 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); | ||
310 | set_bit(Wpending, &m->wsched); | ||
311 | } | ||
312 | |||
313 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { | ||
314 | if (IS_ERR(m->poll_wait[i].wait_addr)) { | ||
315 | p9_mux_poll_stop(m); | ||
316 | kfree(m); | ||
317 | /* return the error code */ | ||
318 | return (void *)m->poll_wait[i].wait_addr; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | return m; | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * p9_mux_destroy - cancels all pending requests and frees mux resources | ||
327 | * @m: mux to destroy | ||
328 | * | ||
329 | */ | ||
330 | |||
331 | static void p9_conn_destroy(struct p9_conn *m) | ||
332 | { | ||
333 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, | ||
334 | m->mux_list.prev, m->mux_list.next); | ||
335 | |||
336 | p9_mux_poll_stop(m); | ||
337 | cancel_work_sync(&m->rq); | ||
338 | cancel_work_sync(&m->wq); | ||
339 | |||
340 | p9_conn_cancel(m, -ECONNRESET); | ||
341 | |||
342 | m->client = NULL; | ||
343 | p9_idpool_destroy(m->tagpool); | ||
344 | kfree(m); | ||
345 | } | ||
346 | |||
347 | static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
348 | { | ||
349 | struct p9_poll_wait *pwait = | ||
350 | container_of(wait, struct p9_poll_wait, wait); | ||
351 | struct p9_conn *m = pwait->conn; | ||
352 | unsigned long flags; | ||
353 | DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); | ||
354 | |||
355 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
356 | if (list_empty(&m->poll_pending_link)) | ||
357 | list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); | ||
358 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
359 | |||
360 | /* perform the default wake up operation */ | ||
361 | return default_wake_function(&dummy_wait, mode, sync, key); | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * p9_pollwait - add poll task to the wait queue | ||
366 | * @filp: file pointer being polled | ||
367 | * @wait_address: wait_q to block on | ||
368 | * @p: poll state | ||
369 | * | ||
370 | * called by files poll operation to add v9fs-poll task to files wait queue | ||
371 | */ | ||
372 | |||
373 | static void | ||
374 | p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) | ||
375 | { | ||
376 | struct p9_conn *m = container_of(p, struct p9_conn, pt); | ||
377 | struct p9_poll_wait *pwait = NULL; | ||
378 | int i; | ||
379 | |||
380 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { | ||
381 | if (m->poll_wait[i].wait_addr == NULL) { | ||
382 | pwait = &m->poll_wait[i]; | ||
383 | break; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | if (!pwait) { | ||
388 | P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); | ||
389 | return; | ||
390 | } | ||
391 | |||
392 | if (!wait_address) { | ||
393 | P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); | ||
394 | pwait->wait_addr = ERR_PTR(-EIO); | ||
395 | return; | ||
396 | } | ||
397 | |||
398 | pwait->conn = m; | ||
399 | pwait->wait_addr = wait_address; | ||
400 | init_waitqueue_func_entry(&pwait->wait, p9_pollwake); | ||
401 | add_wait_queue(wait_address, &pwait->wait); | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * p9_poll_mux - polls a mux and schedules read or write works if necessary | ||
406 | * @m: connection to poll | ||
407 | * | ||
408 | */ | ||
409 | |||
410 | static void p9_poll_mux(struct p9_conn *m) | ||
411 | { | ||
412 | int n; | ||
413 | |||
414 | if (m->err < 0) | ||
415 | return; | ||
416 | |||
417 | n = p9_fd_poll(m->client, NULL); | ||
418 | if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { | ||
419 | P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); | ||
420 | if (n >= 0) | ||
421 | n = -ECONNRESET; | ||
422 | p9_conn_cancel(m, n); | ||
423 | } | ||
424 | |||
425 | if (n & POLLIN) { | ||
426 | set_bit(Rpending, &m->wsched); | ||
427 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); | ||
428 | if (!test_and_set_bit(Rworksched, &m->wsched)) { | ||
429 | P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); | ||
430 | queue_work(p9_mux_wq, &m->rq); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | if (n & POLLOUT) { | ||
435 | set_bit(Wpending, &m->wsched); | ||
436 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); | ||
437 | if ((m->wsize || !list_empty(&m->unsent_req_list)) | ||
438 | && !test_and_set_bit(Wworksched, &m->wsched)) { | ||
439 | P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); | ||
440 | queue_work(p9_mux_wq, &m->wq); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * p9_poll_proc - poll worker thread | ||
447 | * @a: thread state and arguments | ||
448 | * | ||
449 | * polls all v9fs transports for new events and queues the appropriate | ||
450 | * work to the work queue | ||
451 | * | ||
452 | */ | ||
453 | |||
454 | static int p9_poll_proc(void *a) | ||
455 | { | ||
456 | unsigned long flags; | ||
457 | |||
458 | P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); | ||
459 | repeat: | ||
460 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
461 | while (!list_empty(&p9_poll_pending_list)) { | ||
462 | struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, | ||
463 | struct p9_conn, | ||
464 | poll_pending_link); | ||
465 | list_del_init(&conn->poll_pending_link); | ||
466 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
467 | |||
468 | p9_poll_mux(conn); | ||
469 | |||
470 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
471 | } | ||
472 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
473 | |||
474 | set_current_state(TASK_INTERRUPTIBLE); | ||
475 | if (list_empty(&p9_poll_pending_list)) { | ||
476 | P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); | ||
477 | schedule(); | ||
478 | } | ||
479 | __set_current_state(TASK_RUNNING); | ||
480 | |||
481 | if (!kthread_should_stop()) | ||
482 | goto repeat; | ||
483 | |||
484 | P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * p9_write_work - called when a transport can send some data | ||
490 | * @work: container for work to be done | ||
491 | * | 253 | * |
492 | */ | 254 | */ |
493 | 255 | ||
494 | static void p9_write_work(struct work_struct *work) | 256 | void p9_conn_cancel(struct p9_conn *m, int err) |
495 | { | 257 | { |
496 | int n, err; | 258 | struct p9_req *req, *rtmp; |
497 | struct p9_conn *m; | 259 | LIST_HEAD(cancel_list); |
498 | struct p9_req *req; | ||
499 | |||
500 | m = container_of(work, struct p9_conn, wq); | ||
501 | |||
502 | if (m->err < 0) { | ||
503 | clear_bit(Wworksched, &m->wsched); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | if (!m->wsize) { | ||
508 | if (list_empty(&m->unsent_req_list)) { | ||
509 | clear_bit(Wworksched, &m->wsched); | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | spin_lock(&m->lock); | ||
514 | again: | ||
515 | req = list_entry(m->unsent_req_list.next, struct p9_req, | ||
516 | req_list); | ||
517 | list_move_tail(&req->req_list, &m->req_list); | ||
518 | if (req->err == ERREQFLUSH) | ||
519 | goto again; | ||
520 | |||
521 | m->wbuf = req->tcall->sdata; | ||
522 | m->wsize = req->tcall->size; | ||
523 | m->wpos = 0; | ||
524 | spin_unlock(&m->lock); | ||
525 | } | ||
526 | 260 | ||
527 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, | 261 | P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); |
528 | m->wsize); | 262 | m->err = err; |
529 | clear_bit(Wpending, &m->wsched); | 263 | spin_lock(&m->lock); |
530 | err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); | 264 | list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { |
531 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); | 265 | list_move(&req->req_list, &cancel_list); |
532 | if (err == -EAGAIN) { | ||
533 | clear_bit(Wworksched, &m->wsched); | ||
534 | return; | ||
535 | } | 266 | } |
536 | 267 | list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { | |
537 | if (err < 0) | 268 | list_move(&req->req_list, &cancel_list); |
538 | goto error; | ||
539 | else if (err == 0) { | ||
540 | err = -EREMOTEIO; | ||
541 | goto error; | ||
542 | } | 269 | } |
270 | spin_unlock(&m->lock); | ||
543 | 271 | ||
544 | m->wpos += err; | 272 | list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { |
545 | if (m->wpos == m->wsize) | 273 | list_del(&req->req_list); |
546 | m->wpos = m->wsize = 0; | 274 | if (!req->err) |
275 | req->err = err; | ||
547 | 276 | ||
548 | if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { | 277 | if (req->cb) |
549 | if (test_and_clear_bit(Wpending, &m->wsched)) | 278 | (*req->cb) (req, req->cba); |
550 | n = POLLOUT; | ||
551 | else | 279 | else |
552 | n = p9_fd_poll(m->client, NULL); | 280 | kfree(req->rcall); |
553 | 281 | } | |
554 | if (n & POLLOUT) { | ||
555 | P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); | ||
556 | queue_work(p9_mux_wq, &m->wq); | ||
557 | } else | ||
558 | clear_bit(Wworksched, &m->wsched); | ||
559 | } else | ||
560 | clear_bit(Wworksched, &m->wsched); | ||
561 | |||
562 | return; | ||
563 | |||
564 | error: | ||
565 | p9_conn_cancel(m, err); | ||
566 | clear_bit(Wworksched, &m->wsched); | ||
567 | } | 282 | } |
568 | 283 | ||
569 | static void process_request(struct p9_conn *m, struct p9_req *req) | 284 | static void process_request(struct p9_conn *m, struct p9_req *req) |
@@ -599,6 +314,66 @@ static void process_request(struct p9_conn *m, struct p9_req *req) | |||
599 | } | 314 | } |
600 | } | 315 | } |
601 | 316 | ||
317 | static unsigned int | ||
318 | p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) | ||
319 | { | ||
320 | int ret, n; | ||
321 | struct p9_trans_fd *ts = NULL; | ||
322 | |||
323 | if (client && client->status == Connected) | ||
324 | ts = client->trans; | ||
325 | |||
326 | if (!ts) | ||
327 | return -EREMOTEIO; | ||
328 | |||
329 | if (!ts->rd->f_op || !ts->rd->f_op->poll) | ||
330 | return -EIO; | ||
331 | |||
332 | if (!ts->wr->f_op || !ts->wr->f_op->poll) | ||
333 | return -EIO; | ||
334 | |||
335 | ret = ts->rd->f_op->poll(ts->rd, pt); | ||
336 | if (ret < 0) | ||
337 | return ret; | ||
338 | |||
339 | if (ts->rd != ts->wr) { | ||
340 | n = ts->wr->f_op->poll(ts->wr, pt); | ||
341 | if (n < 0) | ||
342 | return n; | ||
343 | ret = (ret & ~POLLOUT) | (n & ~POLLIN); | ||
344 | } | ||
345 | |||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * p9_fd_read- read from a fd | ||
351 | * @client: client instance | ||
352 | * @v: buffer to receive data into | ||
353 | * @len: size of receive buffer | ||
354 | * | ||
355 | */ | ||
356 | |||
357 | static int p9_fd_read(struct p9_client *client, void *v, int len) | ||
358 | { | ||
359 | int ret; | ||
360 | struct p9_trans_fd *ts = NULL; | ||
361 | |||
362 | if (client && client->status != Disconnected) | ||
363 | ts = client->trans; | ||
364 | |||
365 | if (!ts) | ||
366 | return -EREMOTEIO; | ||
367 | |||
368 | if (!(ts->rd->f_flags & O_NONBLOCK)) | ||
369 | P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); | ||
370 | |||
371 | ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); | ||
372 | if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) | ||
373 | client->status = Disconnected; | ||
374 | return ret; | ||
375 | } | ||
376 | |||
602 | /** | 377 | /** |
603 | * p9_read_work - called when there is some data to be read from a transport | 378 | * p9_read_work - called when there is some data to be read from a transport |
604 | * @work: container of work to be done | 379 | * @work: container of work to be done |
@@ -749,6 +524,275 @@ error: | |||
749 | } | 524 | } |
750 | 525 | ||
751 | /** | 526 | /** |
527 | * p9_fd_write - write to a socket | ||
528 | * @client: client instance | ||
529 | * @v: buffer to send data from | ||
530 | * @len: size of send buffer | ||
531 | * | ||
532 | */ | ||
533 | |||
534 | static int p9_fd_write(struct p9_client *client, void *v, int len) | ||
535 | { | ||
536 | int ret; | ||
537 | mm_segment_t oldfs; | ||
538 | struct p9_trans_fd *ts = NULL; | ||
539 | |||
540 | if (client && client->status != Disconnected) | ||
541 | ts = client->trans; | ||
542 | |||
543 | if (!ts) | ||
544 | return -EREMOTEIO; | ||
545 | |||
546 | if (!(ts->wr->f_flags & O_NONBLOCK)) | ||
547 | P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); | ||
548 | |||
549 | oldfs = get_fs(); | ||
550 | set_fs(get_ds()); | ||
551 | /* The cast to a user pointer is valid due to the set_fs() */ | ||
552 | ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); | ||
553 | set_fs(oldfs); | ||
554 | |||
555 | if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) | ||
556 | client->status = Disconnected; | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * p9_write_work - called when a transport can send some data | ||
562 | * @work: container for work to be done | ||
563 | * | ||
564 | */ | ||
565 | |||
566 | static void p9_write_work(struct work_struct *work) | ||
567 | { | ||
568 | int n, err; | ||
569 | struct p9_conn *m; | ||
570 | struct p9_req *req; | ||
571 | |||
572 | m = container_of(work, struct p9_conn, wq); | ||
573 | |||
574 | if (m->err < 0) { | ||
575 | clear_bit(Wworksched, &m->wsched); | ||
576 | return; | ||
577 | } | ||
578 | |||
579 | if (!m->wsize) { | ||
580 | if (list_empty(&m->unsent_req_list)) { | ||
581 | clear_bit(Wworksched, &m->wsched); | ||
582 | return; | ||
583 | } | ||
584 | |||
585 | spin_lock(&m->lock); | ||
586 | again: | ||
587 | req = list_entry(m->unsent_req_list.next, struct p9_req, | ||
588 | req_list); | ||
589 | list_move_tail(&req->req_list, &m->req_list); | ||
590 | if (req->err == ERREQFLUSH) | ||
591 | goto again; | ||
592 | |||
593 | m->wbuf = req->tcall->sdata; | ||
594 | m->wsize = req->tcall->size; | ||
595 | m->wpos = 0; | ||
596 | spin_unlock(&m->lock); | ||
597 | } | ||
598 | |||
599 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, | ||
600 | m->wsize); | ||
601 | clear_bit(Wpending, &m->wsched); | ||
602 | err = p9_fd_write(m->client, m->wbuf + m->wpos, m->wsize - m->wpos); | ||
603 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err); | ||
604 | if (err == -EAGAIN) { | ||
605 | clear_bit(Wworksched, &m->wsched); | ||
606 | return; | ||
607 | } | ||
608 | |||
609 | if (err < 0) | ||
610 | goto error; | ||
611 | else if (err == 0) { | ||
612 | err = -EREMOTEIO; | ||
613 | goto error; | ||
614 | } | ||
615 | |||
616 | m->wpos += err; | ||
617 | if (m->wpos == m->wsize) | ||
618 | m->wpos = m->wsize = 0; | ||
619 | |||
620 | if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { | ||
621 | if (test_and_clear_bit(Wpending, &m->wsched)) | ||
622 | n = POLLOUT; | ||
623 | else | ||
624 | n = p9_fd_poll(m->client, NULL); | ||
625 | |||
626 | if (n & POLLOUT) { | ||
627 | P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); | ||
628 | queue_work(p9_mux_wq, &m->wq); | ||
629 | } else | ||
630 | clear_bit(Wworksched, &m->wsched); | ||
631 | } else | ||
632 | clear_bit(Wworksched, &m->wsched); | ||
633 | |||
634 | return; | ||
635 | |||
636 | error: | ||
637 | p9_conn_cancel(m, err); | ||
638 | clear_bit(Wworksched, &m->wsched); | ||
639 | } | ||
640 | |||
641 | static int p9_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
642 | { | ||
643 | struct p9_poll_wait *pwait = | ||
644 | container_of(wait, struct p9_poll_wait, wait); | ||
645 | struct p9_conn *m = pwait->conn; | ||
646 | unsigned long flags; | ||
647 | DECLARE_WAITQUEUE(dummy_wait, p9_poll_task); | ||
648 | |||
649 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
650 | if (list_empty(&m->poll_pending_link)) | ||
651 | list_add_tail(&m->poll_pending_link, &p9_poll_pending_list); | ||
652 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
653 | |||
654 | /* perform the default wake up operation */ | ||
655 | return default_wake_function(&dummy_wait, mode, sync, key); | ||
656 | } | ||
657 | |||
658 | /** | ||
659 | * p9_pollwait - add poll task to the wait queue | ||
660 | * @filp: file pointer being polled | ||
661 | * @wait_address: wait_q to block on | ||
662 | * @p: poll state | ||
663 | * | ||
664 | * called by files poll operation to add v9fs-poll task to files wait queue | ||
665 | */ | ||
666 | |||
667 | static void | ||
668 | p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) | ||
669 | { | ||
670 | struct p9_conn *m = container_of(p, struct p9_conn, pt); | ||
671 | struct p9_poll_wait *pwait = NULL; | ||
672 | int i; | ||
673 | |||
674 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { | ||
675 | if (m->poll_wait[i].wait_addr == NULL) { | ||
676 | pwait = &m->poll_wait[i]; | ||
677 | break; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | if (!pwait) { | ||
682 | P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n"); | ||
683 | return; | ||
684 | } | ||
685 | |||
686 | if (!wait_address) { | ||
687 | P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n"); | ||
688 | pwait->wait_addr = ERR_PTR(-EIO); | ||
689 | return; | ||
690 | } | ||
691 | |||
692 | pwait->conn = m; | ||
693 | pwait->wait_addr = wait_address; | ||
694 | init_waitqueue_func_entry(&pwait->wait, p9_pollwake); | ||
695 | add_wait_queue(wait_address, &pwait->wait); | ||
696 | } | ||
697 | |||
698 | /** | ||
699 | * p9_conn_create - allocate and initialize the per-session mux data | ||
700 | * @client: client instance | ||
701 | * | ||
702 | * Note: Creates the polling task if this is the first session. | ||
703 | */ | ||
704 | |||
705 | static struct p9_conn *p9_conn_create(struct p9_client *client) | ||
706 | { | ||
707 | int i, n; | ||
708 | struct p9_conn *m; | ||
709 | |||
710 | P9_DPRINTK(P9_DEBUG_MUX, "client %p msize %d\n", client, client->msize); | ||
711 | m = kzalloc(sizeof(struct p9_conn), GFP_KERNEL); | ||
712 | if (!m) | ||
713 | return ERR_PTR(-ENOMEM); | ||
714 | |||
715 | spin_lock_init(&m->lock); | ||
716 | INIT_LIST_HEAD(&m->mux_list); | ||
717 | m->client = client; | ||
718 | m->tagpool = p9_idpool_create(); | ||
719 | if (IS_ERR(m->tagpool)) { | ||
720 | kfree(m); | ||
721 | return ERR_PTR(-ENOMEM); | ||
722 | } | ||
723 | |||
724 | INIT_LIST_HEAD(&m->req_list); | ||
725 | INIT_LIST_HEAD(&m->unsent_req_list); | ||
726 | INIT_WORK(&m->rq, p9_read_work); | ||
727 | INIT_WORK(&m->wq, p9_write_work); | ||
728 | INIT_LIST_HEAD(&m->poll_pending_link); | ||
729 | init_poll_funcptr(&m->pt, p9_pollwait); | ||
730 | |||
731 | n = p9_fd_poll(client, &m->pt); | ||
732 | if (n & POLLIN) { | ||
733 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); | ||
734 | set_bit(Rpending, &m->wsched); | ||
735 | } | ||
736 | |||
737 | if (n & POLLOUT) { | ||
738 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); | ||
739 | set_bit(Wpending, &m->wsched); | ||
740 | } | ||
741 | |||
742 | for (i = 0; i < ARRAY_SIZE(m->poll_wait); i++) { | ||
743 | if (IS_ERR(m->poll_wait[i].wait_addr)) { | ||
744 | p9_mux_poll_stop(m); | ||
745 | kfree(m); | ||
746 | /* return the error code */ | ||
747 | return (void *)m->poll_wait[i].wait_addr; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | return m; | ||
752 | } | ||
753 | |||
754 | /** | ||
755 | * p9_poll_mux - polls a mux and schedules read or write works if necessary | ||
756 | * @m: connection to poll | ||
757 | * | ||
758 | */ | ||
759 | |||
760 | static void p9_poll_mux(struct p9_conn *m) | ||
761 | { | ||
762 | int n; | ||
763 | |||
764 | if (m->err < 0) | ||
765 | return; | ||
766 | |||
767 | n = p9_fd_poll(m->client, NULL); | ||
768 | if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { | ||
769 | P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n); | ||
770 | if (n >= 0) | ||
771 | n = -ECONNRESET; | ||
772 | p9_conn_cancel(m, n); | ||
773 | } | ||
774 | |||
775 | if (n & POLLIN) { | ||
776 | set_bit(Rpending, &m->wsched); | ||
777 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m); | ||
778 | if (!test_and_set_bit(Rworksched, &m->wsched)) { | ||
779 | P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m); | ||
780 | queue_work(p9_mux_wq, &m->rq); | ||
781 | } | ||
782 | } | ||
783 | |||
784 | if (n & POLLOUT) { | ||
785 | set_bit(Wpending, &m->wsched); | ||
786 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m); | ||
787 | if ((m->wsize || !list_empty(&m->unsent_req_list)) | ||
788 | && !test_and_set_bit(Wworksched, &m->wsched)) { | ||
789 | P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m); | ||
790 | queue_work(p9_mux_wq, &m->wq); | ||
791 | } | ||
792 | } | ||
793 | } | ||
794 | |||
795 | /** | ||
752 | * p9_send_request - send 9P request | 796 | * p9_send_request - send 9P request |
753 | * The function can sleep until the request is scheduled for sending. | 797 | * The function can sleep until the request is scheduled for sending. |
754 | * The function can be interrupted. Return from the function is not | 798 | * The function can be interrupted. Return from the function is not |
@@ -1005,69 +1049,6 @@ p9_fd_rpc(struct p9_client *client, struct p9_fcall *tc, struct p9_fcall **rc) | |||
1005 | return err; | 1049 | return err; |
1006 | } | 1050 | } |
1007 | 1051 | ||
1008 | #ifdef P9_NONBLOCK | ||
1009 | /** | ||
1010 | * p9_conn_rpcnb - sends 9P request without waiting for response. | ||
1011 | * @m: mux data | ||
1012 | * @tc: request to be sent | ||
1013 | * @cb: callback function to be called when response arrives | ||
1014 | * @a: value to pass to the callback function | ||
1015 | * | ||
1016 | */ | ||
1017 | |||
1018 | int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc, | ||
1019 | p9_conn_req_callback cb, void *a) | ||
1020 | { | ||
1021 | int err; | ||
1022 | struct p9_req *req; | ||
1023 | |||
1024 | req = p9_send_request(m, tc, cb, a); | ||
1025 | if (IS_ERR(req)) { | ||
1026 | err = PTR_ERR(req); | ||
1027 | P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err); | ||
1028 | return PTR_ERR(req); | ||
1029 | } | ||
1030 | |||
1031 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); | ||
1032 | return 0; | ||
1033 | } | ||
1034 | #endif /* P9_NONBLOCK */ | ||
1035 | |||
1036 | /** | ||
1037 | * p9_conn_cancel - cancel all pending requests with error | ||
1038 | * @m: mux data | ||
1039 | * @err: error code | ||
1040 | * | ||
1041 | */ | ||
1042 | |||
1043 | void p9_conn_cancel(struct p9_conn *m, int err) | ||
1044 | { | ||
1045 | struct p9_req *req, *rtmp; | ||
1046 | LIST_HEAD(cancel_list); | ||
1047 | |||
1048 | P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err); | ||
1049 | m->err = err; | ||
1050 | spin_lock(&m->lock); | ||
1051 | list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { | ||
1052 | list_move(&req->req_list, &cancel_list); | ||
1053 | } | ||
1054 | list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { | ||
1055 | list_move(&req->req_list, &cancel_list); | ||
1056 | } | ||
1057 | spin_unlock(&m->lock); | ||
1058 | |||
1059 | list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) { | ||
1060 | list_del(&req->req_list); | ||
1061 | if (!req->err) | ||
1062 | req->err = err; | ||
1063 | |||
1064 | if (req->cb) | ||
1065 | (*req->cb) (req, req->cba); | ||
1066 | else | ||
1067 | kfree(req->rcall); | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | /** | 1052 | /** |
1072 | * parse_options - parse mount options into session structure | 1053 | * parse_options - parse mount options into session structure |
1073 | * @options: options string passed from mount | 1054 | * @options: options string passed from mount |
@@ -1177,97 +1158,25 @@ static int p9_socket_open(struct p9_client *client, struct socket *csocket) | |||
1177 | } | 1158 | } |
1178 | 1159 | ||
1179 | /** | 1160 | /** |
1180 | * p9_fd_read- read from a fd | 1161 | * p9_mux_destroy - cancels all pending requests and frees mux resources |
1181 | * @client: client instance | 1162 | * @m: mux to destroy |
1182 | * @v: buffer to receive data into | ||
1183 | * @len: size of receive buffer | ||
1184 | * | ||
1185 | */ | ||
1186 | |||
1187 | static int p9_fd_read(struct p9_client *client, void *v, int len) | ||
1188 | { | ||
1189 | int ret; | ||
1190 | struct p9_trans_fd *ts = NULL; | ||
1191 | |||
1192 | if (client && client->status != Disconnected) | ||
1193 | ts = client->trans; | ||
1194 | |||
1195 | if (!ts) | ||
1196 | return -EREMOTEIO; | ||
1197 | |||
1198 | if (!(ts->rd->f_flags & O_NONBLOCK)) | ||
1199 | P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n"); | ||
1200 | |||
1201 | ret = kernel_read(ts->rd, ts->rd->f_pos, v, len); | ||
1202 | if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) | ||
1203 | client->status = Disconnected; | ||
1204 | return ret; | ||
1205 | } | ||
1206 | |||
1207 | /** | ||
1208 | * p9_fd_write - write to a socket | ||
1209 | * @client: client instance | ||
1210 | * @v: buffer to send data from | ||
1211 | * @len: size of send buffer | ||
1212 | * | 1163 | * |
1213 | */ | 1164 | */ |
1214 | 1165 | ||
1215 | static int p9_fd_write(struct p9_client *client, void *v, int len) | 1166 | static void p9_conn_destroy(struct p9_conn *m) |
1216 | { | ||
1217 | int ret; | ||
1218 | mm_segment_t oldfs; | ||
1219 | struct p9_trans_fd *ts = NULL; | ||
1220 | |||
1221 | if (client && client->status != Disconnected) | ||
1222 | ts = client->trans; | ||
1223 | |||
1224 | if (!ts) | ||
1225 | return -EREMOTEIO; | ||
1226 | |||
1227 | if (!(ts->wr->f_flags & O_NONBLOCK)) | ||
1228 | P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n"); | ||
1229 | |||
1230 | oldfs = get_fs(); | ||
1231 | set_fs(get_ds()); | ||
1232 | /* The cast to a user pointer is valid due to the set_fs() */ | ||
1233 | ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos); | ||
1234 | set_fs(oldfs); | ||
1235 | |||
1236 | if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN) | ||
1237 | client->status = Disconnected; | ||
1238 | return ret; | ||
1239 | } | ||
1240 | |||
1241 | static unsigned int | ||
1242 | p9_fd_poll(struct p9_client *client, struct poll_table_struct *pt) | ||
1243 | { | 1167 | { |
1244 | int ret, n; | 1168 | P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m, |
1245 | struct p9_trans_fd *ts = NULL; | 1169 | m->mux_list.prev, m->mux_list.next); |
1246 | |||
1247 | if (client && client->status == Connected) | ||
1248 | ts = client->trans; | ||
1249 | |||
1250 | if (!ts) | ||
1251 | return -EREMOTEIO; | ||
1252 | |||
1253 | if (!ts->rd->f_op || !ts->rd->f_op->poll) | ||
1254 | return -EIO; | ||
1255 | |||
1256 | if (!ts->wr->f_op || !ts->wr->f_op->poll) | ||
1257 | return -EIO; | ||
1258 | 1170 | ||
1259 | ret = ts->rd->f_op->poll(ts->rd, pt); | 1171 | p9_mux_poll_stop(m); |
1260 | if (ret < 0) | 1172 | cancel_work_sync(&m->rq); |
1261 | return ret; | 1173 | cancel_work_sync(&m->wq); |
1262 | 1174 | ||
1263 | if (ts->rd != ts->wr) { | 1175 | p9_conn_cancel(m, -ECONNRESET); |
1264 | n = ts->wr->f_op->poll(ts->wr, pt); | ||
1265 | if (n < 0) | ||
1266 | return n; | ||
1267 | ret = (ret & ~POLLOUT) | (n & ~POLLIN); | ||
1268 | } | ||
1269 | 1176 | ||
1270 | return ret; | 1177 | m->client = NULL; |
1178 | p9_idpool_destroy(m->tagpool); | ||
1179 | kfree(m); | ||
1271 | } | 1180 | } |
1272 | 1181 | ||
1273 | /** | 1182 | /** |
@@ -1492,6 +1401,49 @@ static struct p9_trans_module p9_fd_trans = { | |||
1492 | .owner = THIS_MODULE, | 1401 | .owner = THIS_MODULE, |
1493 | }; | 1402 | }; |
1494 | 1403 | ||
1404 | /** | ||
1405 | * p9_poll_proc - poll worker thread | ||
1406 | * @a: thread state and arguments | ||
1407 | * | ||
1408 | * polls all v9fs transports for new events and queues the appropriate | ||
1409 | * work to the work queue | ||
1410 | * | ||
1411 | */ | ||
1412 | |||
1413 | static int p9_poll_proc(void *a) | ||
1414 | { | ||
1415 | unsigned long flags; | ||
1416 | |||
1417 | P9_DPRINTK(P9_DEBUG_MUX, "start %p\n", current); | ||
1418 | repeat: | ||
1419 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
1420 | while (!list_empty(&p9_poll_pending_list)) { | ||
1421 | struct p9_conn *conn = list_first_entry(&p9_poll_pending_list, | ||
1422 | struct p9_conn, | ||
1423 | poll_pending_link); | ||
1424 | list_del_init(&conn->poll_pending_link); | ||
1425 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
1426 | |||
1427 | p9_poll_mux(conn); | ||
1428 | |||
1429 | spin_lock_irqsave(&p9_poll_lock, flags); | ||
1430 | } | ||
1431 | spin_unlock_irqrestore(&p9_poll_lock, flags); | ||
1432 | |||
1433 | set_current_state(TASK_INTERRUPTIBLE); | ||
1434 | if (list_empty(&p9_poll_pending_list)) { | ||
1435 | P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n"); | ||
1436 | schedule(); | ||
1437 | } | ||
1438 | __set_current_state(TASK_RUNNING); | ||
1439 | |||
1440 | if (!kthread_should_stop()) | ||
1441 | goto repeat; | ||
1442 | |||
1443 | P9_DPRINTK(P9_DEBUG_MUX, "finish\n"); | ||
1444 | return 0; | ||
1445 | } | ||
1446 | |||
1495 | int p9_trans_fd_init(void) | 1447 | int p9_trans_fd_init(void) |
1496 | { | 1448 | { |
1497 | p9_mux_wq = create_workqueue("v9fs"); | 1449 | p9_mux_wq = create_workqueue("v9fs"); |