aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2005-09-09 16:10:36 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 17:03:47 -0400
commit04730fef1f9c7277e5c730b193e681ac095b0507 (patch)
tree3694ea435eb38f10dadc5c8b6abd603a7e10f52e
parent413ef8cb302511d8e995e2b0e5517ee1a65b9c77 (diff)
[PATCH] fuse: transfer readdir data through device
This patch removes a long lasting "hack" in FUSE, which used a separate channel (a file descriptor refering to a disk-file) to transfer directory contents from userspace to the kernel. The patch adds three new operations (OPENDIR, READDIR, RELEASEDIR), which have semantics and implementation exactly maching the respective file operations (OPEN, READ, RELEASE). This simplifies the directory reading code. Also disk space is not necessary, which can be important in embedded systems. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/fuse/dev.c9
-rw-r--r--fs/fuse/dir.c84
-rw-r--r--fs/fuse/file.c38
-rw-r--r--fs/fuse/fuse_i.h22
-rw-r--r--include/linux/fuse.h10
5 files changed, 73 insertions, 90 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 */
735static 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
741static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, 734static 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
522static int fuse_checkdir(struct file *cfile, struct file *file) 522static 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
537static int fuse_getdir(struct file *file) 529static 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
562static 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
588static char *read_link(struct dentry *dentry) 558static 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
638static int fuse_dir_open(struct inode *inode, struct file *file) 608static 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
644static int fuse_dir_release(struct inode *inode, struct file *file) 613static 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
654static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) 618static 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
15static int fuse_open(struct inode *inode, struct file *file) 15int 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
88static int fuse_release(struct inode *inode, struct file *file) 88int 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
110static int fuse_open(struct inode *inode, struct file *file)
111{
112 return fuse_open_common(inode, file, 0);
113}
114
115static int fuse_release(struct inode *inode, struct file *file)
116{
117 return fuse_release_common(inode, file, 0);
118}
119
110static int fuse_flush(struct file *file) 120static 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
181static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, 191size_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
218static 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
207static int fuse_readpage(struct file *file, struct page *page) 225static 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
296static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, 314static 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
276struct fuse_getdir_out_i {
277 int fd;
278 void *file; /* Used by kernel only */
279};
280
281static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) 276static 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 */
334size_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 */
341int fuse_open_common(struct inode *inode, struct file *file, int isdir);
342
343/**
344 * Send RELEASE or RELEASEDIR request
345 */
346int 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 */
339void fuse_init_file_inode(struct inode *inode); 351void fuse_init_file_inode(struct inode *inode);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index e9b814e16c58..cdfaa51b9018 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -70,7 +70,6 @@ enum fuse_opcode {
70 FUSE_SETATTR = 4, 70 FUSE_SETATTR = 4,
71 FUSE_READLINK = 5, 71 FUSE_READLINK = 5,
72 FUSE_SYMLINK = 6, 72 FUSE_SYMLINK = 6,
73 FUSE_GETDIR = 7,
74 FUSE_MKNOD = 8, 73 FUSE_MKNOD = 8,
75 FUSE_MKDIR = 9, 74 FUSE_MKDIR = 9,
76 FUSE_UNLINK = 10, 75 FUSE_UNLINK = 10,
@@ -88,7 +87,10 @@ enum fuse_opcode {
88 FUSE_LISTXATTR = 23, 87 FUSE_LISTXATTR = 23,
89 FUSE_REMOVEXATTR = 24, 88 FUSE_REMOVEXATTR = 24,
90 FUSE_FLUSH = 25, 89 FUSE_FLUSH = 25,
91 FUSE_INIT = 26 90 FUSE_INIT = 26,
91 FUSE_OPENDIR = 27,
92 FUSE_READDIR = 28,
93 FUSE_RELEASEDIR = 29
92}; 94};
93 95
94/* Conservative buffer size for the client */ 96/* Conservative buffer size for the client */
@@ -120,10 +122,6 @@ struct fuse_attr_out {
120 struct fuse_attr attr; 122 struct fuse_attr attr;
121}; 123};
122 124
123struct fuse_getdir_out {
124 __u32 fd;
125};
126
127struct fuse_mknod_in { 125struct fuse_mknod_in {
128 __u32 mode; 126 __u32 mode;
129 __u32 rdev; 127 __u32 rdev;