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)
{
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);
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)
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)
#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;
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;
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;
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;
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;
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;
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;
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;
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;
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);
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;
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
*/
FUSE_SETATTR = 4,
FUSE_READLINK = 5,
FUSE_SYMLINK = 6,
- FUSE_GETDIR = 7,
FUSE_MKNOD = 8,
FUSE_MKDIR = 9,
FUSE_UNLINK = 10,
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 */
struct fuse_attr attr;
};
-struct fuse_getdir_out {
- __u32 fd;
-};
-
struct fuse_mknod_in {
__u32 mode;
__u32 rdev;