diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/fuse/dev.c | 9 | ||||
-rw-r--r-- | fs/fuse/dir.c | 84 | ||||
-rw-r--r-- | fs/fuse/file.c | 38 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 22 |
4 files changed, 69 insertions, 84 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ca6fc0e96d7c..e4ada021d087 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -731,13 +731,6 @@ static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique) | |||
731 | return NULL; | 731 | return NULL; |
732 | } | 732 | } |
733 | 733 | ||
734 | /* fget() needs to be done in this context */ | ||
735 | static void process_getdir(struct fuse_req *req) | ||
736 | { | ||
737 | struct fuse_getdir_out_i *arg = req->out.args[0].value; | ||
738 | arg->file = fget(arg->fd); | ||
739 | } | ||
740 | |||
741 | static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, | 734 | static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, |
742 | unsigned nbytes) | 735 | unsigned nbytes) |
743 | { | 736 | { |
@@ -817,8 +810,6 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, | |||
817 | if (!err) { | 810 | if (!err) { |
818 | if (req->interrupted) | 811 | if (req->interrupted) |
819 | err = -ENOENT; | 812 | err = -ENOENT; |
820 | else if (req->in.h.opcode == FUSE_GETDIR && !oh.error) | ||
821 | process_getdir(req); | ||
822 | } else if (!req->interrupted) | 813 | } else if (!req->interrupted) |
823 | req->out.h.error = -EIO; | 814 | req->out.h.error = -EIO; |
824 | request_end(fc, req); | 815 | request_end(fc, req); |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 65da6e1b6de5..cf5d1faed7af 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -519,70 +519,40 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file, | |||
519 | return 0; | 519 | return 0; |
520 | } | 520 | } |
521 | 521 | ||
522 | static int fuse_checkdir(struct file *cfile, struct file *file) | 522 | static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file, |
523 | struct inode *inode, loff_t pos, | ||
524 | size_t count) | ||
523 | { | 525 | { |
524 | struct inode *inode; | 526 | return fuse_send_read_common(req, file, inode, pos, count, 1); |
525 | if (!cfile) | ||
526 | return -EIO; | ||
527 | inode = cfile->f_dentry->d_inode; | ||
528 | if (!S_ISREG(inode->i_mode)) { | ||
529 | fput(cfile); | ||
530 | return -EIO; | ||
531 | } | ||
532 | |||
533 | file->private_data = cfile; | ||
534 | return 0; | ||
535 | } | 527 | } |
536 | 528 | ||
537 | static int fuse_getdir(struct file *file) | 529 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) |
538 | { | 530 | { |
531 | int err; | ||
532 | size_t nbytes; | ||
533 | struct page *page; | ||
539 | struct inode *inode = file->f_dentry->d_inode; | 534 | struct inode *inode = file->f_dentry->d_inode; |
540 | struct fuse_conn *fc = get_fuse_conn(inode); | 535 | struct fuse_conn *fc = get_fuse_conn(inode); |
541 | struct fuse_req *req = fuse_get_request(fc); | 536 | struct fuse_req *req = fuse_get_request_nonint(fc); |
542 | struct fuse_getdir_out_i outarg; | ||
543 | int err; | ||
544 | |||
545 | if (!req) | 537 | if (!req) |
546 | return -ERESTARTNOINTR; | 538 | return -EINTR; |
547 | 539 | ||
548 | req->in.h.opcode = FUSE_GETDIR; | 540 | page = alloc_page(GFP_KERNEL); |
549 | req->in.h.nodeid = get_node_id(inode); | 541 | if (!page) { |
550 | req->inode = inode; | 542 | fuse_put_request(fc, req); |
551 | req->out.numargs = 1; | 543 | return -ENOMEM; |
552 | req->out.args[0].size = sizeof(struct fuse_getdir_out); | 544 | } |
553 | req->out.args[0].value = &outarg; | 545 | req->num_pages = 1; |
554 | request_send(fc, req); | 546 | req->pages[0] = page; |
547 | nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE); | ||
555 | err = req->out.h.error; | 548 | err = req->out.h.error; |
556 | fuse_put_request(fc, req); | 549 | fuse_put_request(fc, req); |
557 | if (!err) | 550 | if (!err) |
558 | err = fuse_checkdir(outarg.file, file); | 551 | err = parse_dirfile(page_address(page), nbytes, file, dstbuf, |
559 | return err; | 552 | filldir); |
560 | } | ||
561 | |||
562 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | ||
563 | { | ||
564 | struct file *cfile = file->private_data; | ||
565 | char *buf; | ||
566 | int ret; | ||
567 | |||
568 | if (!cfile) { | ||
569 | ret = fuse_getdir(file); | ||
570 | if (ret) | ||
571 | return ret; | ||
572 | |||
573 | cfile = file->private_data; | ||
574 | } | ||
575 | 553 | ||
576 | buf = (char *) __get_free_page(GFP_KERNEL); | 554 | __free_page(page); |
577 | if (!buf) | 555 | return err; |
578 | return -ENOMEM; | ||
579 | |||
580 | ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE); | ||
581 | if (ret > 0) | ||
582 | ret = parse_dirfile(buf, ret, file, dstbuf, filldir); | ||
583 | |||
584 | free_page((unsigned long) buf); | ||
585 | return ret; | ||
586 | } | 556 | } |
587 | 557 | ||
588 | static char *read_link(struct dentry *dentry) | 558 | static char *read_link(struct dentry *dentry) |
@@ -637,18 +607,12 @@ static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) | |||
637 | 607 | ||
638 | static int fuse_dir_open(struct inode *inode, struct file *file) | 608 | static int fuse_dir_open(struct inode *inode, struct file *file) |
639 | { | 609 | { |
640 | file->private_data = NULL; | 610 | return fuse_open_common(inode, file, 1); |
641 | return 0; | ||
642 | } | 611 | } |
643 | 612 | ||
644 | static int fuse_dir_release(struct inode *inode, struct file *file) | 613 | static int fuse_dir_release(struct inode *inode, struct file *file) |
645 | { | 614 | { |
646 | struct file *cfile = file->private_data; | 615 | return fuse_release_common(inode, file, 1); |
647 | |||
648 | if (cfile) | ||
649 | fput(cfile); | ||
650 | |||
651 | return 0; | ||
652 | } | 616 | } |
653 | 617 | ||
654 | static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) | 618 | static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 6bc3fb26de39..224453557cf6 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | 14 | ||
15 | static int fuse_open(struct inode *inode, struct file *file) | 15 | int fuse_open_common(struct inode *inode, struct file *file, int isdir) |
16 | { | 16 | { |
17 | struct fuse_conn *fc = get_fuse_conn(inode); | 17 | struct fuse_conn *fc = get_fuse_conn(inode); |
18 | struct fuse_req *req; | 18 | struct fuse_req *req; |
@@ -56,7 +56,7 @@ static int fuse_open(struct inode *inode, struct file *file) | |||
56 | 56 | ||
57 | memset(&inarg, 0, sizeof(inarg)); | 57 | memset(&inarg, 0, sizeof(inarg)); |
58 | inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | 58 | inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); |
59 | req->in.h.opcode = FUSE_OPEN; | 59 | req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; |
60 | req->in.h.nodeid = get_node_id(inode); | 60 | req->in.h.nodeid = get_node_id(inode); |
61 | req->inode = inode; | 61 | req->inode = inode; |
62 | req->in.numargs = 1; | 62 | req->in.numargs = 1; |
@@ -85,7 +85,7 @@ static int fuse_open(struct inode *inode, struct file *file) | |||
85 | return err; | 85 | return err; |
86 | } | 86 | } |
87 | 87 | ||
88 | static int fuse_release(struct inode *inode, struct file *file) | 88 | int fuse_release_common(struct inode *inode, struct file *file, int isdir) |
89 | { | 89 | { |
90 | struct fuse_conn *fc = get_fuse_conn(inode); | 90 | struct fuse_conn *fc = get_fuse_conn(inode); |
91 | struct fuse_file *ff = file->private_data; | 91 | struct fuse_file *ff = file->private_data; |
@@ -94,7 +94,7 @@ static int fuse_release(struct inode *inode, struct file *file) | |||
94 | 94 | ||
95 | inarg->fh = ff->fh; | 95 | inarg->fh = ff->fh; |
96 | inarg->flags = file->f_flags & ~O_EXCL; | 96 | inarg->flags = file->f_flags & ~O_EXCL; |
97 | req->in.h.opcode = FUSE_RELEASE; | 97 | req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; |
98 | req->in.h.nodeid = get_node_id(inode); | 98 | req->in.h.nodeid = get_node_id(inode); |
99 | req->inode = inode; | 99 | req->inode = inode; |
100 | req->in.numargs = 1; | 100 | req->in.numargs = 1; |
@@ -107,6 +107,16 @@ static int fuse_release(struct inode *inode, struct file *file) | |||
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | static int fuse_open(struct inode *inode, struct file *file) | ||
111 | { | ||
112 | return fuse_open_common(inode, file, 0); | ||
113 | } | ||
114 | |||
115 | static int fuse_release(struct inode *inode, struct file *file) | ||
116 | { | ||
117 | return fuse_release_common(inode, file, 0); | ||
118 | } | ||
119 | |||
110 | static int fuse_flush(struct file *file) | 120 | static int fuse_flush(struct file *file) |
111 | { | 121 | { |
112 | struct inode *inode = file->f_dentry->d_inode; | 122 | struct inode *inode = file->f_dentry->d_inode; |
@@ -178,8 +188,9 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) | |||
178 | return err; | 188 | return err; |
179 | } | 189 | } |
180 | 190 | ||
181 | static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, | 191 | size_t fuse_send_read_common(struct fuse_req *req, struct file *file, |
182 | struct inode *inode, loff_t pos, size_t count) | 192 | struct inode *inode, loff_t pos, size_t count, |
193 | int isdir) | ||
183 | { | 194 | { |
184 | struct fuse_conn *fc = get_fuse_conn(inode); | 195 | struct fuse_conn *fc = get_fuse_conn(inode); |
185 | struct fuse_file *ff = file->private_data; | 196 | struct fuse_file *ff = file->private_data; |
@@ -189,7 +200,7 @@ static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, | |||
189 | inarg.fh = ff->fh; | 200 | inarg.fh = ff->fh; |
190 | inarg.offset = pos; | 201 | inarg.offset = pos; |
191 | inarg.size = count; | 202 | inarg.size = count; |
192 | req->in.h.opcode = FUSE_READ; | 203 | req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ; |
193 | req->in.h.nodeid = get_node_id(inode); | 204 | req->in.h.nodeid = get_node_id(inode); |
194 | req->inode = inode; | 205 | req->inode = inode; |
195 | req->file = file; | 206 | req->file = file; |
@@ -204,6 +215,13 @@ static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, | |||
204 | return req->out.args[0].size; | 215 | return req->out.args[0].size; |
205 | } | 216 | } |
206 | 217 | ||
218 | static inline size_t fuse_send_read(struct fuse_req *req, struct file *file, | ||
219 | struct inode *inode, loff_t pos, | ||
220 | size_t count) | ||
221 | { | ||
222 | return fuse_send_read_common(req, file, inode, pos, count, 0); | ||
223 | } | ||
224 | |||
207 | static int fuse_readpage(struct file *file, struct page *page) | 225 | static int fuse_readpage(struct file *file, struct page *page) |
208 | { | 226 | { |
209 | struct inode *inode = page->mapping->host; | 227 | struct inode *inode = page->mapping->host; |
@@ -293,8 +311,8 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, | |||
293 | return err; | 311 | return err; |
294 | } | 312 | } |
295 | 313 | ||
296 | static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, | 314 | static size_t fuse_send_write(struct fuse_req *req, struct file *file, |
297 | struct inode *inode, loff_t pos, size_t count) | 315 | struct inode *inode, loff_t pos, size_t count) |
298 | { | 316 | { |
299 | struct fuse_conn *fc = get_fuse_conn(inode); | 317 | struct fuse_conn *fc = get_fuse_conn(inode); |
300 | struct fuse_file *ff = file->private_data; | 318 | struct fuse_file *ff = file->private_data; |
@@ -332,7 +350,7 @@ static int fuse_commit_write(struct file *file, struct page *page, | |||
332 | unsigned offset, unsigned to) | 350 | unsigned offset, unsigned to) |
333 | { | 351 | { |
334 | int err; | 352 | int err; |
335 | ssize_t nres; | 353 | size_t nres; |
336 | unsigned count = to - offset; | 354 | unsigned count = to - offset; |
337 | struct inode *inode = page->mapping->host; | 355 | struct inode *inode = page->mapping->host; |
338 | struct fuse_conn *fc = get_fuse_conn(inode); | 356 | struct fuse_conn *fc = get_fuse_conn(inode); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 0af1ac646927..8593d5bae7a6 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -273,11 +273,6 @@ struct fuse_conn { | |||
273 | struct backing_dev_info bdi; | 273 | struct backing_dev_info bdi; |
274 | }; | 274 | }; |
275 | 275 | ||
276 | struct fuse_getdir_out_i { | ||
277 | int fd; | ||
278 | void *file; /* Used by kernel only */ | ||
279 | }; | ||
280 | |||
281 | static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) | 276 | static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) |
282 | { | 277 | { |
283 | return (struct fuse_conn **) &sb->s_fs_info; | 278 | return (struct fuse_conn **) &sb->s_fs_info; |
@@ -334,6 +329,23 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | |||
334 | unsigned long nodeid, u64 nlookup); | 329 | unsigned long nodeid, u64 nlookup); |
335 | 330 | ||
336 | /** | 331 | /** |
332 | * Send READ or READDIR request | ||
333 | */ | ||
334 | size_t fuse_send_read_common(struct fuse_req *req, struct file *file, | ||
335 | struct inode *inode, loff_t pos, size_t count, | ||
336 | int isdir); | ||
337 | |||
338 | /** | ||
339 | * Send OPEN or OPENDIR request | ||
340 | */ | ||
341 | int fuse_open_common(struct inode *inode, struct file *file, int isdir); | ||
342 | |||
343 | /** | ||
344 | * Send RELEASE or RELEASEDIR request | ||
345 | */ | ||
346 | int fuse_release_common(struct inode *inode, struct file *file, int isdir); | ||
347 | |||
348 | /** | ||
337 | * Initialise file operations on a regular file | 349 | * Initialise file operations on a regular file |
338 | */ | 350 | */ |
339 | void fuse_init_file_inode(struct inode *inode); | 351 | void fuse_init_file_inode(struct inode *inode); |