diff options
-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 | ||||
-rw-r--r-- | include/linux/fuse.h | 10 |
5 files changed, 73 insertions, 90 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index ca6fc0e96d7..e4ada021d08 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) return NULL; } -/* fget() needs to be done in this context */ -static void process_getdir(struct fuse_req *req) -{ - struct fuse_getdir_out_i *arg = req->out.args[0].value; - arg->file = fget(arg->fd); -} - static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out, unsigned nbytes) { @@ -817,8 +810,6 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov, if (!err) { if (req->interrupted) err = -ENOENT; - else if (req->in.h.opcode == FUSE_GETDIR && !oh.error) - process_getdir(req); } else if (!req->interrupted) req->out.h.error = -EIO; request_end(fc, req); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 65da6e1b6de..cf5d1faed7a 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, return 0; } -static int fuse_checkdir(struct file *cfile, struct file *file) +static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, + size_t count) { - struct inode *inode; - if (!cfile) - return -EIO; - inode = cfile->f_dentry->d_inode; - if (!S_ISREG(inode->i_mode)) { - fput(cfile); - return -EIO; - } - - file->private_data = cfile; - return 0; + return fuse_send_read_common(req, file, inode, pos, count, 1); } -static int fuse_getdir(struct file *file) +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) { + int err; + size_t nbytes; + struct page *page; struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_request(fc); - struct fuse_getdir_out_i outarg; - int err; - + struct fuse_req *req = fuse_get_request_nonint(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; - req->in.h.opcode = FUSE_GETDIR; - req->in.h.nodeid = get_node_id(inode); - req->inode = inode; - req->out.numargs = 1; - req->out.args[0].size = sizeof(struct fuse_getdir_out); - req->out.args[0].value = &outarg; - request_send(fc, req); + page = alloc_page(GFP_KERNEL); + if (!page) { + fuse_put_request(fc, req); + return -ENOMEM; + } + req->num_pages = 1; + req->pages[0] = page; + nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE); err = req->out.h.error; fuse_put_request(fc, req); if (!err) - err = fuse_checkdir(outarg.file, file); - return err; -} - -static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) -{ - struct file *cfile = file->private_data; - char *buf; - int ret; - - if (!cfile) { - ret = fuse_getdir(file); - if (ret) - return ret; - - cfile = file->private_data; - } + err = parse_dirfile(page_address(page), nbytes, file, dstbuf, + filldir); - buf = (char *) __get_free_page(GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE); - if (ret > 0) - ret = parse_dirfile(buf, ret, file, dstbuf, filldir); - - free_page((unsigned long) buf); - return ret; + __free_page(page); + return err; } static char *read_link(struct dentry *dentry) @@ -637,18 +607,12 @@ static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) static int fuse_dir_open(struct inode *inode, struct file *file) { - file->private_data = NULL; - return 0; + return fuse_open_common(inode, file, 1); } static int fuse_dir_release(struct inode *inode, struct file *file) { - struct file *cfile = file->private_data; - - if (cfile) - fput(cfile); - - return 0; + return fuse_release_common(inode, file, 1); } 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 6bc3fb26de3..224453557cf 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -12,7 +12,7 @@ #include <linux/slab.h> #include <linux/kernel.h> -static int fuse_open(struct inode *inode, struct file *file) +int fuse_open_common(struct inode *inode, struct file *file, int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; @@ -56,7 +56,7 @@ static int fuse_open(struct inode *inode, struct file *file) memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - req->in.h.opcode = FUSE_OPEN; + req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->in.numargs = 1; @@ -85,7 +85,7 @@ static int fuse_open(struct inode *inode, struct file *file) return err; } -static int fuse_release(struct inode *inode, struct file *file) +int fuse_release_common(struct inode *inode, struct file *file, int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; @@ -94,7 +94,7 @@ static int fuse_release(struct inode *inode, struct file *file) inarg->fh = ff->fh; inarg->flags = file->f_flags & ~O_EXCL; - req->in.h.opcode = FUSE_RELEASE; + req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->in.numargs = 1; @@ -107,6 +107,16 @@ static int fuse_release(struct inode *inode, struct file *file) return 0; } +static int fuse_open(struct inode *inode, struct file *file) +{ + return fuse_open_common(inode, file, 0); +} + +static int fuse_release(struct inode *inode, struct file *file) +{ + return fuse_release_common(inode, file, 0); +} + static int fuse_flush(struct file *file) { struct inode *inode = file->f_dentry->d_inode; @@ -178,8 +188,9 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) return err; } -static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) +size_t fuse_send_read_common(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, + int isdir) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; @@ -189,7 +200,7 @@ static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, inarg.fh = ff->fh; inarg.offset = pos; inarg.size = count; - req->in.h.opcode = FUSE_READ; + req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ; req->in.h.nodeid = get_node_id(inode); req->inode = inode; req->file = file; @@ -204,6 +215,13 @@ static ssize_t fuse_send_read(struct fuse_req *req, struct file *file, return req->out.args[0].size; } +static inline size_t fuse_send_read(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, + size_t count) +{ + return fuse_send_read_common(req, file, inode, pos, count, 0); +} + static int fuse_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; @@ -293,8 +311,8 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, return err; } -static ssize_t fuse_send_write(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) +static size_t fuse_send_write(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; @@ -332,7 +350,7 @@ static int fuse_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { int err; - ssize_t nres; + size_t nres; unsigned count = to - offset; struct inode *inode = page->mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 0af1ac64692..8593d5bae7a 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -273,11 +273,6 @@ struct fuse_conn { struct backing_dev_info bdi; }; -struct fuse_getdir_out_i { - int fd; - void *file; /* Used by kernel only */ -}; - static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) { return (struct fuse_conn **) &sb->s_fs_info; @@ -334,6 +329,23 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, unsigned long nodeid, u64 nlookup); /** + * Send READ or READDIR request + */ +size_t fuse_send_read_common(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, + int isdir); + +/** + * Send OPEN or OPENDIR request + */ +int fuse_open_common(struct inode *inode, struct file *file, int isdir); + +/** + * Send RELEASE or RELEASEDIR request + */ +int fuse_release_common(struct inode *inode, struct file *file, int isdir); + +/** * Initialise file operations on a regular file */ void fuse_init_file_inode(struct inode *inode); diff --git a/include/linux/fuse.h b/include/linux/fuse.h index e9b814e16c5..cdfaa51b901 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -70,7 +70,6 @@ enum fuse_opcode { FUSE_SETATTR = 4, FUSE_READLINK = 5, FUSE_SYMLINK = 6, - FUSE_GETDIR = 7, FUSE_MKNOD = 8, FUSE_MKDIR = 9, FUSE_UNLINK = 10, @@ -88,7 +87,10 @@ enum fuse_opcode { FUSE_LISTXATTR = 23, FUSE_REMOVEXATTR = 24, FUSE_FLUSH = 25, - FUSE_INIT = 26 + FUSE_INIT = 26, + FUSE_OPENDIR = 27, + FUSE_READDIR = 28, + FUSE_RELEASEDIR = 29 }; /* Conservative buffer size for the client */ @@ -120,10 +122,6 @@ struct fuse_attr_out { struct fuse_attr attr; }; -struct fuse_getdir_out { - __u32 fd; -}; - struct fuse_mknod_in { __u32 mode; __u32 rdev; |