diff options
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 113 |
1 files changed, 83 insertions, 30 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index fba571648a8e..e0c7ada08a1f 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | FUSE: Filesystem in Userspace | 2 | FUSE: Filesystem in Userspace |
3 | Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> | 3 | Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu> |
4 | 4 | ||
5 | This program can be distributed under the terms of the GNU GPL. | 5 | This program can be distributed under the terms of the GNU GPL. |
6 | See the file COPYING. | 6 | See the file COPYING. |
@@ -269,7 +269,7 @@ static void flush_bg_queue(struct fuse_conn *fc) | |||
269 | * Called with fc->lock, unlocks it | 269 | * Called with fc->lock, unlocks it |
270 | */ | 270 | */ |
271 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) | 271 | static void request_end(struct fuse_conn *fc, struct fuse_req *req) |
272 | __releases(fc->lock) | 272 | __releases(&fc->lock) |
273 | { | 273 | { |
274 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; | 274 | void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; |
275 | req->end = NULL; | 275 | req->end = NULL; |
@@ -293,13 +293,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) | |||
293 | wake_up(&req->waitq); | 293 | wake_up(&req->waitq); |
294 | if (end) | 294 | if (end) |
295 | end(fc, req); | 295 | end(fc, req); |
296 | else | 296 | fuse_put_request(fc, req); |
297 | fuse_put_request(fc, req); | ||
298 | } | 297 | } |
299 | 298 | ||
300 | static void wait_answer_interruptible(struct fuse_conn *fc, | 299 | static void wait_answer_interruptible(struct fuse_conn *fc, |
301 | struct fuse_req *req) | 300 | struct fuse_req *req) |
302 | __releases(fc->lock) __acquires(fc->lock) | 301 | __releases(&fc->lock) |
302 | __acquires(&fc->lock) | ||
303 | { | 303 | { |
304 | if (signal_pending(current)) | 304 | if (signal_pending(current)) |
305 | return; | 305 | return; |
@@ -317,7 +317,8 @@ static void queue_interrupt(struct fuse_conn *fc, struct fuse_req *req) | |||
317 | } | 317 | } |
318 | 318 | ||
319 | static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) | 319 | static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) |
320 | __releases(fc->lock) __acquires(fc->lock) | 320 | __releases(&fc->lock) |
321 | __acquires(&fc->lock) | ||
321 | { | 322 | { |
322 | if (!fc->no_interrupt) { | 323 | if (!fc->no_interrupt) { |
323 | /* Any signal may interrupt this */ | 324 | /* Any signal may interrupt this */ |
@@ -380,7 +381,7 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) | |||
380 | } | 381 | } |
381 | } | 382 | } |
382 | 383 | ||
383 | void request_send(struct fuse_conn *fc, struct fuse_req *req) | 384 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) |
384 | { | 385 | { |
385 | req->isreply = 1; | 386 | req->isreply = 1; |
386 | spin_lock(&fc->lock); | 387 | spin_lock(&fc->lock); |
@@ -399,8 +400,8 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req) | |||
399 | spin_unlock(&fc->lock); | 400 | spin_unlock(&fc->lock); |
400 | } | 401 | } |
401 | 402 | ||
402 | static void request_send_nowait_locked(struct fuse_conn *fc, | 403 | static void fuse_request_send_nowait_locked(struct fuse_conn *fc, |
403 | struct fuse_req *req) | 404 | struct fuse_req *req) |
404 | { | 405 | { |
405 | req->background = 1; | 406 | req->background = 1; |
406 | fc->num_background++; | 407 | fc->num_background++; |
@@ -414,11 +415,11 @@ static void request_send_nowait_locked(struct fuse_conn *fc, | |||
414 | flush_bg_queue(fc); | 415 | flush_bg_queue(fc); |
415 | } | 416 | } |
416 | 417 | ||
417 | static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) | 418 | static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) |
418 | { | 419 | { |
419 | spin_lock(&fc->lock); | 420 | spin_lock(&fc->lock); |
420 | if (fc->connected) { | 421 | if (fc->connected) { |
421 | request_send_nowait_locked(fc, req); | 422 | fuse_request_send_nowait_locked(fc, req); |
422 | spin_unlock(&fc->lock); | 423 | spin_unlock(&fc->lock); |
423 | } else { | 424 | } else { |
424 | req->out.h.error = -ENOTCONN; | 425 | req->out.h.error = -ENOTCONN; |
@@ -426,16 +427,16 @@ static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) | |||
426 | } | 427 | } |
427 | } | 428 | } |
428 | 429 | ||
429 | void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) | 430 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) |
430 | { | 431 | { |
431 | req->isreply = 0; | 432 | req->isreply = 0; |
432 | request_send_nowait(fc, req); | 433 | fuse_request_send_nowait(fc, req); |
433 | } | 434 | } |
434 | 435 | ||
435 | void request_send_background(struct fuse_conn *fc, struct fuse_req *req) | 436 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) |
436 | { | 437 | { |
437 | req->isreply = 1; | 438 | req->isreply = 1; |
438 | request_send_nowait(fc, req); | 439 | fuse_request_send_nowait(fc, req); |
439 | } | 440 | } |
440 | 441 | ||
441 | /* | 442 | /* |
@@ -443,10 +444,11 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req) | |||
443 | * | 444 | * |
444 | * fc->connected must have been checked previously | 445 | * fc->connected must have been checked previously |
445 | */ | 446 | */ |
446 | void request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req) | 447 | void fuse_request_send_background_locked(struct fuse_conn *fc, |
448 | struct fuse_req *req) | ||
447 | { | 449 | { |
448 | req->isreply = 1; | 450 | req->isreply = 1; |
449 | request_send_nowait_locked(fc, req); | 451 | fuse_request_send_nowait_locked(fc, req); |
450 | } | 452 | } |
451 | 453 | ||
452 | /* | 454 | /* |
@@ -539,8 +541,8 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) | |||
539 | BUG_ON(!cs->nr_segs); | 541 | BUG_ON(!cs->nr_segs); |
540 | cs->seglen = cs->iov[0].iov_len; | 542 | cs->seglen = cs->iov[0].iov_len; |
541 | cs->addr = (unsigned long) cs->iov[0].iov_base; | 543 | cs->addr = (unsigned long) cs->iov[0].iov_base; |
542 | cs->iov ++; | 544 | cs->iov++; |
543 | cs->nr_segs --; | 545 | cs->nr_segs--; |
544 | } | 546 | } |
545 | down_read(¤t->mm->mmap_sem); | 547 | down_read(¤t->mm->mmap_sem); |
546 | err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0, | 548 | err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0, |
@@ -589,9 +591,11 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page, | |||
589 | kunmap_atomic(mapaddr, KM_USER1); | 591 | kunmap_atomic(mapaddr, KM_USER1); |
590 | } | 592 | } |
591 | while (count) { | 593 | while (count) { |
592 | int err; | 594 | if (!cs->len) { |
593 | if (!cs->len && (err = fuse_copy_fill(cs))) | 595 | int err = fuse_copy_fill(cs); |
594 | return err; | 596 | if (err) |
597 | return err; | ||
598 | } | ||
595 | if (page) { | 599 | if (page) { |
596 | void *mapaddr = kmap_atomic(page, KM_USER1); | 600 | void *mapaddr = kmap_atomic(page, KM_USER1); |
597 | void *buf = mapaddr + offset; | 601 | void *buf = mapaddr + offset; |
@@ -631,9 +635,11 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes, | |||
631 | static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size) | 635 | static int fuse_copy_one(struct fuse_copy_state *cs, void *val, unsigned size) |
632 | { | 636 | { |
633 | while (size) { | 637 | while (size) { |
634 | int err; | 638 | if (!cs->len) { |
635 | if (!cs->len && (err = fuse_copy_fill(cs))) | 639 | int err = fuse_copy_fill(cs); |
636 | return err; | 640 | if (err) |
641 | return err; | ||
642 | } | ||
637 | fuse_copy_do(cs, &val, &size); | 643 | fuse_copy_do(cs, &val, &size); |
638 | } | 644 | } |
639 | return 0; | 645 | return 0; |
@@ -664,6 +670,8 @@ static int request_pending(struct fuse_conn *fc) | |||
664 | 670 | ||
665 | /* Wait until a request is available on the pending list */ | 671 | /* Wait until a request is available on the pending list */ |
666 | static void request_wait(struct fuse_conn *fc) | 672 | static void request_wait(struct fuse_conn *fc) |
673 | __releases(&fc->lock) | ||
674 | __acquires(&fc->lock) | ||
667 | { | 675 | { |
668 | DECLARE_WAITQUEUE(wait, current); | 676 | DECLARE_WAITQUEUE(wait, current); |
669 | 677 | ||
@@ -691,7 +699,7 @@ static void request_wait(struct fuse_conn *fc) | |||
691 | */ | 699 | */ |
692 | static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req, | 700 | static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req, |
693 | const struct iovec *iov, unsigned long nr_segs) | 701 | const struct iovec *iov, unsigned long nr_segs) |
694 | __releases(fc->lock) | 702 | __releases(&fc->lock) |
695 | { | 703 | { |
696 | struct fuse_copy_state cs; | 704 | struct fuse_copy_state cs; |
697 | struct fuse_in_header ih; | 705 | struct fuse_in_header ih; |
@@ -813,6 +821,34 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov, | |||
813 | return err; | 821 | return err; |
814 | } | 822 | } |
815 | 823 | ||
824 | static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size, | ||
825 | struct fuse_copy_state *cs) | ||
826 | { | ||
827 | struct fuse_notify_poll_wakeup_out outarg; | ||
828 | int err; | ||
829 | |||
830 | if (size != sizeof(outarg)) | ||
831 | return -EINVAL; | ||
832 | |||
833 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
834 | if (err) | ||
835 | return err; | ||
836 | |||
837 | return fuse_notify_poll_wakeup(fc, &outarg); | ||
838 | } | ||
839 | |||
840 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | ||
841 | unsigned int size, struct fuse_copy_state *cs) | ||
842 | { | ||
843 | switch (code) { | ||
844 | case FUSE_NOTIFY_POLL: | ||
845 | return fuse_notify_poll(fc, size, cs); | ||
846 | |||
847 | default: | ||
848 | return -EINVAL; | ||
849 | } | ||
850 | } | ||
851 | |||
816 | /* Look up request on processing list by unique ID */ | 852 | /* Look up request on processing list by unique ID */ |
817 | static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) | 853 | static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) |
818 | { | 854 | { |
@@ -876,9 +912,23 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov, | |||
876 | err = fuse_copy_one(&cs, &oh, sizeof(oh)); | 912 | err = fuse_copy_one(&cs, &oh, sizeof(oh)); |
877 | if (err) | 913 | if (err) |
878 | goto err_finish; | 914 | goto err_finish; |
915 | |||
916 | err = -EINVAL; | ||
917 | if (oh.len != nbytes) | ||
918 | goto err_finish; | ||
919 | |||
920 | /* | ||
921 | * Zero oh.unique indicates unsolicited notification message | ||
922 | * and error contains notification code. | ||
923 | */ | ||
924 | if (!oh.unique) { | ||
925 | err = fuse_notify(fc, oh.error, nbytes - sizeof(oh), &cs); | ||
926 | fuse_copy_finish(&cs); | ||
927 | return err ? err : nbytes; | ||
928 | } | ||
929 | |||
879 | err = -EINVAL; | 930 | err = -EINVAL; |
880 | if (!oh.unique || oh.error <= -1000 || oh.error > 0 || | 931 | if (oh.error <= -1000 || oh.error > 0) |
881 | oh.len != nbytes) | ||
882 | goto err_finish; | 932 | goto err_finish; |
883 | 933 | ||
884 | spin_lock(&fc->lock); | 934 | spin_lock(&fc->lock); |
@@ -966,6 +1016,8 @@ static unsigned fuse_dev_poll(struct file *file, poll_table *wait) | |||
966 | * This function releases and reacquires fc->lock | 1016 | * This function releases and reacquires fc->lock |
967 | */ | 1017 | */ |
968 | static void end_requests(struct fuse_conn *fc, struct list_head *head) | 1018 | static void end_requests(struct fuse_conn *fc, struct list_head *head) |
1019 | __releases(&fc->lock) | ||
1020 | __acquires(&fc->lock) | ||
969 | { | 1021 | { |
970 | while (!list_empty(head)) { | 1022 | while (!list_empty(head)) { |
971 | struct fuse_req *req; | 1023 | struct fuse_req *req; |
@@ -988,7 +1040,8 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head) | |||
988 | * locked). | 1040 | * locked). |
989 | */ | 1041 | */ |
990 | static void end_io_requests(struct fuse_conn *fc) | 1042 | static void end_io_requests(struct fuse_conn *fc) |
991 | __releases(fc->lock) __acquires(fc->lock) | 1043 | __releases(&fc->lock) |
1044 | __acquires(&fc->lock) | ||
992 | { | 1045 | { |
993 | while (!list_empty(&fc->io)) { | 1046 | while (!list_empty(&fc->io)) { |
994 | struct fuse_req *req = | 1047 | struct fuse_req *req = |
@@ -1002,11 +1055,11 @@ static void end_io_requests(struct fuse_conn *fc) | |||
1002 | wake_up(&req->waitq); | 1055 | wake_up(&req->waitq); |
1003 | if (end) { | 1056 | if (end) { |
1004 | req->end = NULL; | 1057 | req->end = NULL; |
1005 | /* The end function will consume this reference */ | ||
1006 | __fuse_get_request(req); | 1058 | __fuse_get_request(req); |
1007 | spin_unlock(&fc->lock); | 1059 | spin_unlock(&fc->lock); |
1008 | wait_event(req->waitq, !req->locked); | 1060 | wait_event(req->waitq, !req->locked); |
1009 | end(fc, req); | 1061 | end(fc, req); |
1062 | fuse_put_request(fc, req); | ||
1010 | spin_lock(&fc->lock); | 1063 | spin_lock(&fc->lock); |
1011 | } | 1064 | } |
1012 | } | 1065 | } |