diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-10 10:43:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-10 10:43:54 -0500 |
commit | 7d44b0440147d83a65270205b22e7d365de28948 (patch) | |
tree | 0adc818f569f45912a19482773dabbf71b191b9d /fs/fuse/dev.c | |
parent | 0dc1488527a3c01383a50e5df7187219567586a3 (diff) | |
parent | 1baa26b2be92fe9917e2f7ef46d423b5dfa4da71 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: fix ioctl ABI
fuse: allow batching of FORGET requests
fuse: separate queue for FORGET requests
fuse: ioctl cleanup
Fix up trivial conflict in fs/fuse/inode.c due to RCU lookup having done
the RCU-freeing of the inode in fuse_destroy_inode().
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r-- | fs/fuse/dev.c | 156 |
1 files changed, 147 insertions, 9 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6e07696308dc..cf8d28d1fbad 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -251,6 +251,20 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | |||
251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
252 | } | 252 | } |
253 | 253 | ||
254 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, | ||
255 | u64 nodeid, u64 nlookup) | ||
256 | { | ||
257 | forget->forget_one.nodeid = nodeid; | ||
258 | forget->forget_one.nlookup = nlookup; | ||
259 | |||
260 | spin_lock(&fc->lock); | ||
261 | fc->forget_list_tail->next = forget; | ||
262 | fc->forget_list_tail = forget; | ||
263 | wake_up(&fc->waitq); | ||
264 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | ||
265 | spin_unlock(&fc->lock); | ||
266 | } | ||
267 | |||
254 | static void flush_bg_queue(struct fuse_conn *fc) | 268 | static void flush_bg_queue(struct fuse_conn *fc) |
255 | { | 269 | { |
256 | while (fc->active_background < fc->max_background && | 270 | while (fc->active_background < fc->max_background && |
@@ -438,12 +452,6 @@ static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) | |||
438 | } | 452 | } |
439 | } | 453 | } |
440 | 454 | ||
441 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) | ||
442 | { | ||
443 | req->isreply = 0; | ||
444 | fuse_request_send_nowait(fc, req); | ||
445 | } | ||
446 | |||
447 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) | 455 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) |
448 | { | 456 | { |
449 | req->isreply = 1; | 457 | req->isreply = 1; |
@@ -896,9 +904,15 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, | |||
896 | return err; | 904 | return err; |
897 | } | 905 | } |
898 | 906 | ||
907 | static int forget_pending(struct fuse_conn *fc) | ||
908 | { | ||
909 | return fc->forget_list_head.next != NULL; | ||
910 | } | ||
911 | |||
899 | static int request_pending(struct fuse_conn *fc) | 912 | static int request_pending(struct fuse_conn *fc) |
900 | { | 913 | { |
901 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts); | 914 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) || |
915 | forget_pending(fc); | ||
902 | } | 916 | } |
903 | 917 | ||
904 | /* Wait until a request is available on the pending list */ | 918 | /* Wait until a request is available on the pending list */ |
@@ -960,6 +974,120 @@ __releases(fc->lock) | |||
960 | return err ? err : reqsize; | 974 | return err ? err : reqsize; |
961 | } | 975 | } |
962 | 976 | ||
977 | static struct fuse_forget_link *dequeue_forget(struct fuse_conn *fc, | ||
978 | unsigned max, | ||
979 | unsigned *countp) | ||
980 | { | ||
981 | struct fuse_forget_link *head = fc->forget_list_head.next; | ||
982 | struct fuse_forget_link **newhead = &head; | ||
983 | unsigned count; | ||
984 | |||
985 | for (count = 0; *newhead != NULL && count < max; count++) | ||
986 | newhead = &(*newhead)->next; | ||
987 | |||
988 | fc->forget_list_head.next = *newhead; | ||
989 | *newhead = NULL; | ||
990 | if (fc->forget_list_head.next == NULL) | ||
991 | fc->forget_list_tail = &fc->forget_list_head; | ||
992 | |||
993 | if (countp != NULL) | ||
994 | *countp = count; | ||
995 | |||
996 | return head; | ||
997 | } | ||
998 | |||
999 | static int fuse_read_single_forget(struct fuse_conn *fc, | ||
1000 | struct fuse_copy_state *cs, | ||
1001 | size_t nbytes) | ||
1002 | __releases(fc->lock) | ||
1003 | { | ||
1004 | int err; | ||
1005 | struct fuse_forget_link *forget = dequeue_forget(fc, 1, NULL); | ||
1006 | struct fuse_forget_in arg = { | ||
1007 | .nlookup = forget->forget_one.nlookup, | ||
1008 | }; | ||
1009 | struct fuse_in_header ih = { | ||
1010 | .opcode = FUSE_FORGET, | ||
1011 | .nodeid = forget->forget_one.nodeid, | ||
1012 | .unique = fuse_get_unique(fc), | ||
1013 | .len = sizeof(ih) + sizeof(arg), | ||
1014 | }; | ||
1015 | |||
1016 | spin_unlock(&fc->lock); | ||
1017 | kfree(forget); | ||
1018 | if (nbytes < ih.len) | ||
1019 | return -EINVAL; | ||
1020 | |||
1021 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
1022 | if (!err) | ||
1023 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
1024 | fuse_copy_finish(cs); | ||
1025 | |||
1026 | if (err) | ||
1027 | return err; | ||
1028 | |||
1029 | return ih.len; | ||
1030 | } | ||
1031 | |||
1032 | static int fuse_read_batch_forget(struct fuse_conn *fc, | ||
1033 | struct fuse_copy_state *cs, size_t nbytes) | ||
1034 | __releases(fc->lock) | ||
1035 | { | ||
1036 | int err; | ||
1037 | unsigned max_forgets; | ||
1038 | unsigned count; | ||
1039 | struct fuse_forget_link *head; | ||
1040 | struct fuse_batch_forget_in arg = { .count = 0 }; | ||
1041 | struct fuse_in_header ih = { | ||
1042 | .opcode = FUSE_BATCH_FORGET, | ||
1043 | .unique = fuse_get_unique(fc), | ||
1044 | .len = sizeof(ih) + sizeof(arg), | ||
1045 | }; | ||
1046 | |||
1047 | if (nbytes < ih.len) { | ||
1048 | spin_unlock(&fc->lock); | ||
1049 | return -EINVAL; | ||
1050 | } | ||
1051 | |||
1052 | max_forgets = (nbytes - ih.len) / sizeof(struct fuse_forget_one); | ||
1053 | head = dequeue_forget(fc, max_forgets, &count); | ||
1054 | spin_unlock(&fc->lock); | ||
1055 | |||
1056 | arg.count = count; | ||
1057 | ih.len += count * sizeof(struct fuse_forget_one); | ||
1058 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
1059 | if (!err) | ||
1060 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
1061 | |||
1062 | while (head) { | ||
1063 | struct fuse_forget_link *forget = head; | ||
1064 | |||
1065 | if (!err) { | ||
1066 | err = fuse_copy_one(cs, &forget->forget_one, | ||
1067 | sizeof(forget->forget_one)); | ||
1068 | } | ||
1069 | head = forget->next; | ||
1070 | kfree(forget); | ||
1071 | } | ||
1072 | |||
1073 | fuse_copy_finish(cs); | ||
1074 | |||
1075 | if (err) | ||
1076 | return err; | ||
1077 | |||
1078 | return ih.len; | ||
1079 | } | ||
1080 | |||
1081 | static int fuse_read_forget(struct fuse_conn *fc, struct fuse_copy_state *cs, | ||
1082 | size_t nbytes) | ||
1083 | __releases(fc->lock) | ||
1084 | { | ||
1085 | if (fc->minor < 16 || fc->forget_list_head.next->next == NULL) | ||
1086 | return fuse_read_single_forget(fc, cs, nbytes); | ||
1087 | else | ||
1088 | return fuse_read_batch_forget(fc, cs, nbytes); | ||
1089 | } | ||
1090 | |||
963 | /* | 1091 | /* |
964 | * Read a single request into the userspace filesystem's buffer. This | 1092 | * Read a single request into the userspace filesystem's buffer. This |
965 | * function waits until a request is available, then removes it from | 1093 | * function waits until a request is available, then removes it from |
@@ -998,6 +1126,14 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, | |||
998 | return fuse_read_interrupt(fc, cs, nbytes, req); | 1126 | return fuse_read_interrupt(fc, cs, nbytes, req); |
999 | } | 1127 | } |
1000 | 1128 | ||
1129 | if (forget_pending(fc)) { | ||
1130 | if (list_empty(&fc->pending) || fc->forget_batch-- > 0) | ||
1131 | return fuse_read_forget(fc, cs, nbytes); | ||
1132 | |||
1133 | if (fc->forget_batch <= -8) | ||
1134 | fc->forget_batch = 16; | ||
1135 | } | ||
1136 | |||
1001 | req = list_entry(fc->pending.next, struct fuse_req, list); | 1137 | req = list_entry(fc->pending.next, struct fuse_req, list); |
1002 | req->state = FUSE_REQ_READING; | 1138 | req->state = FUSE_REQ_READING; |
1003 | list_move(&req->list, &fc->io); | 1139 | list_move(&req->list, &fc->io); |
@@ -1090,7 +1226,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos, | |||
1090 | if (!fc) | 1226 | if (!fc) |
1091 | return -EPERM; | 1227 | return -EPERM; |
1092 | 1228 | ||
1093 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1229 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
1094 | if (!bufs) | 1230 | if (!bufs) |
1095 | return -ENOMEM; | 1231 | return -ENOMEM; |
1096 | 1232 | ||
@@ -1626,7 +1762,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, | |||
1626 | if (!fc) | 1762 | if (!fc) |
1627 | return -EPERM; | 1763 | return -EPERM; |
1628 | 1764 | ||
1629 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1765 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
1630 | if (!bufs) | 1766 | if (!bufs) |
1631 | return -ENOMEM; | 1767 | return -ENOMEM; |
1632 | 1768 | ||
@@ -1770,6 +1906,8 @@ __acquires(fc->lock) | |||
1770 | flush_bg_queue(fc); | 1906 | flush_bg_queue(fc); |
1771 | end_requests(fc, &fc->pending); | 1907 | end_requests(fc, &fc->pending); |
1772 | end_requests(fc, &fc->processing); | 1908 | end_requests(fc, &fc->processing); |
1909 | while (forget_pending(fc)) | ||
1910 | kfree(dequeue_forget(fc, 1, NULL)); | ||
1773 | } | 1911 | } |
1774 | 1912 | ||
1775 | /* | 1913 | /* |