diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2005-09-09 16:10:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-09 17:03:47 -0400 |
commit | 04730fef1f9c7277e5c730b193e681ac095b0507 (patch) | |
tree | 3694ea435eb38f10dadc5c8b6abd603a7e10f52e /fs/fuse/dir.c | |
parent | 413ef8cb302511d8e995e2b0e5517ee1a65b9c77 (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.c | 84 |
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 | ||
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) |