aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
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 /fs/fuse/dir.c
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>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c84
1 files changed, 24 insertions, 60 deletions
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)