+2004-12-01 Miklos Szeredi <miklos@szeredi.hu>
+
+ * kernel: clean up writing functions
+
+ * kernel: no allocation on write in direct_io mode
+
2004-11-30 Miklos Szeredi <miklos@szeredi.hu>
* kernel: clean up reading functions
fi
for f in dev.c dir.c file.c inode.c util.c fuse_i.h; do
- unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -D__user -DMODULE_LICENSE $f > $destdir/$f
+ unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -DHAVE_FS_SUBSYS -D__user -DMODULE_LICENSE $f > $destdir/$f
done
[#include <linux/fs.h>])
CFLAGS="$old_cflags"
fi
+
+AC_MSG_CHECKING([whether fs_subsys is declared])
+if grep -q fs_subsys $kernelsrc/include/linux/fs.h; then
+ AC_DEFINE(HAVE_FS_SUBSYS, 1, [Kernel defines fs_subsys])
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
AC_MSG_CHECKING([if kernel has extended attribute support])
if test -f $kernelsrc/include/linux/xattr.h; then
- AC_DEFINE(HAVE_KERNEL_XATTR, 1, [Kernel has xattr support],,)
+ AC_DEFINE(HAVE_KERNEL_XATTR, 1, [Kernel has xattr support])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
remove_wait_queue(&fc->waitq, &wait);
}
-static inline int copy_in_one(const void *src, size_t srclen,
- char __user **dstp, size_t *dstlenp)
+static inline int copy_in_page(char __user *buf, struct page *page,
+ unsigned offset, unsigned count)
{
- if (*dstlenp < srclen) {
+ char *tmpbuf = kmap(page);
+ int err = copy_to_user(buf, tmpbuf + offset, count);
+ kunmap(page);
+ return err;
+}
+
+static int copy_in_pages(struct fuse_req *req, size_t nbytes, char __user *buf)
+{
+ unsigned i;
+ unsigned offset = req->page_offset;
+ unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);
+ for (i = 0; i < req->num_pages && nbytes; i++) {
+ struct page *page = req->pages[i];
+ if (page && copy_in_page(buf, page, offset, count))
+ return -EFAULT;
+ nbytes -= count;
+ buf += count;
+ count = min(nbytes, (unsigned) PAGE_SIZE);
+ offset = 0;
+ }
+ return 0;
+}
+
+static inline int copy_in_one(struct fuse_req *req, size_t argsize,
+ const void *val, int islast, char __user *buf,
+ size_t nbytes)
+{
+ if (nbytes < argsize) {
printk("fuse_dev_read: buffer too small\n");
return -EINVAL;
}
-
- if (srclen && copy_to_user(*dstp, src, srclen))
+ if (islast && req->in.argpages)
+ return copy_in_pages(req, argsize, buf);
+ else if (argsize && copy_to_user(buf, val, argsize))
return -EFAULT;
-
- *dstp += srclen;
- *dstlenp -= srclen;
-
- return 0;
+ else
+ return 0;
}
-static inline int copy_in_args(struct fuse_in *in, char __user *buf,
- size_t nbytes)
+static int copy_in_args(struct fuse_req *req, char __user *buf, size_t nbytes)
{
- int err;
int i;
+ int err;
+ struct fuse_in *in = &req->in;
size_t orignbytes = nbytes;
-
- err = copy_in_one(&in->h, sizeof(in->h), &buf, &nbytes);
+ unsigned argsize;
+
+ argsize = sizeof(in->h);
+ err = copy_in_one(req, argsize, &in->h, 0, buf, nbytes);
if (err)
return err;
+ buf += argsize;
+ nbytes -= argsize;
+
for (i = 0; i < in->numargs; i++) {
struct fuse_in_arg *arg = &in->args[i];
- err = copy_in_one(arg->value, arg->size, &buf, &nbytes);
+ int islast = (i == in->numargs - 1);
+ err = copy_in_one(req, arg->size, arg->value, islast, buf,
+ nbytes);
if (err)
return err;
+
+ buf += arg->size;
+ nbytes -= arg->size;
}
return orignbytes - nbytes;
if (req == NULL)
return -EINTR;
- ret = copy_in_args(&req->in, buf, nbytes);
+ ret = copy_in_args(req, buf, nbytes);
spin_lock(&fuse_lock);
if (req->isreply) {
if (ret < 0) {
arg->file = fget(arg->fd);
}
-static int copy_out_pages(struct fuse_req *req, const char __user *buf,
- size_t nbytes)
+static inline int copy_out_page(const char __user *buf, struct page *page,
+ unsigned offset, unsigned count, int zeroing)
+{
+ int err = 0;
+ char *tmpbuf = kmap(page);
+ if (count < PAGE_SIZE && zeroing)
+ memset(tmpbuf, 0, PAGE_SIZE);
+ if (count)
+ err = copy_from_user(tmpbuf + offset, buf, count);
+ flush_dcache_page(page);
+ kunmap(page);
+ return err;
+}
+
+static int copy_out_pages(struct fuse_req *req, size_t nbytes,
+ const char __user *buf)
{
- unsigned count;
- unsigned page_offset;
- unsigned zeroing = req->out.page_zeroing;
unsigned i;
-
- req->out.args[0].size = nbytes;
- page_offset = req->page_offset;
- count = min(nbytes, (unsigned) PAGE_CACHE_SIZE - page_offset);
+ unsigned offset = req->page_offset;
+ unsigned zeroing = req->out.page_zeroing;
+ unsigned count = min(nbytes, (unsigned) PAGE_SIZE - offset);
+
for (i = 0; i < req->num_pages && (zeroing || nbytes); i++) {
struct page *page = req->pages[i];
- char *tmpbuf = kmap(page);
- int err = 0;
- if (count < PAGE_CACHE_SIZE && zeroing)
- memset(tmpbuf, 0, PAGE_CACHE_SIZE);
- if (count)
- err = copy_from_user(tmpbuf + page_offset, buf, count);
- flush_dcache_page(page);
- kunmap(page);
- if (err)
- return -EFAULT;
+ if (page && copy_out_page(buf, page, offset, count, zeroing))
+ return -EFAULT;
nbytes -= count;
buf += count;
- count = min(nbytes, (unsigned) PAGE_CACHE_SIZE);
- page_offset = 0;
+ count = min(nbytes, (unsigned) PAGE_SIZE);
+ offset = 0;
}
return 0;
}
-static inline int copy_out_one(struct fuse_out_arg *arg,
- const char __user **srcp,
- size_t *srclenp, int allowvar)
+static inline int copy_out_one(struct fuse_req *req, struct fuse_out_arg *arg,
+ int islast, const char __user *buf, size_t nbytes)
{
- size_t dstlen = arg->size;
- if (*srclenp < dstlen) {
- if (!allowvar) {
+ if (nbytes < arg->size) {
+ if (!islast || !req->out.argvar) {
printk("fuse_dev_write: write is short\n");
return -EINVAL;
}
- dstlen = *srclenp;
+ arg->size = nbytes;
}
-
- if (dstlen && copy_from_user(arg->value, *srcp, dstlen))
+ if (islast && req->out.argpages)
+ return copy_out_pages(req, arg->size, buf);
+ else if (arg->size && copy_from_user(arg->value, buf, arg->size))
return -EFAULT;
-
- *srcp += dstlen;
- *srclenp -= dstlen;
- arg->size = dstlen;
-
- return 0;
+ else
+ return 0;
}
-static inline int copy_out_args(struct fuse_req *req, const char __user *buf,
- size_t nbytes)
+static int copy_out_args(struct fuse_req *req, const char __user *buf,
+ size_t nbytes)
{
struct fuse_out *out = &req->out;
- int err;
int i;
buf += sizeof(struct fuse_out_header);
nbytes -= sizeof(struct fuse_out_header);
if (!out->h.error) {
- if (out->argpages) {
- if (nbytes <= out->args[0].size)
- return copy_out_pages(req, buf, nbytes);
- } else {
- for (i = 0; i < out->numargs; i++) {
- struct fuse_out_arg *arg = &out->args[i];
- int allowvar;
-
- if (out->argvar && i == out->numargs - 1)
- allowvar = 1;
- else
- allowvar = 0;
-
- err = copy_out_one(arg, &buf, &nbytes, allowvar);
- if (err)
- return err;
- }
+ for (i = 0; i < out->numargs; i++) {
+ struct fuse_out_arg *arg = &out->args[i];
+ int islast = (i == out->numargs - 1);
+ int err = copy_out_one(req, arg, islast, buf, nbytes);
+ if (err)
+ return err;
+ buf += arg->size;
+ nbytes -= arg->size;
}
}
-
if (nbytes != 0) {
printk("fuse_dev_write: write is long\n");
return -EINVAL;
printk("fuse_dev_write: write is short\n");
return -EINVAL;
}
-
if (copy_from_user(oh, buf, sizeof(struct fuse_out_header)))
return -EFAULT;
};
#ifdef KERNEL_2_6
-#ifndef FUSE_MAINLINE
+#ifndef HAVE_FS_SUBSYS
static decl_subsys(fs, NULL, NULL);
#endif
static decl_subsys(fuse, NULL, NULL);
{
int err;
-#ifndef FUSE_MAINLINE
+#ifndef HAVE_FS_SUBSYS
subsystem_register(&fs_subsys);
#endif
kset_set_kset_s(&fuse_subsys, fs_subsys);
err = subsys_create_file(&fuse_subsys, &fuse_attr_version);
if (err) {
subsystem_unregister(&fuse_subsys);
-#ifndef FUSE_MAINLINE
+#ifndef HAVE_FS_SUBSYS
subsystem_unregister(&fs_subsys);
#endif
return err;
{
subsys_remove_file(&fuse_subsys, &fuse_attr_version);
subsystem_unregister(&fuse_subsys);
-#ifndef FUSE_MAINLINE
+#ifndef HAVE_FS_SUBSYS
subsystem_unregister(&fs_subsys);
#endif
}
static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
{
unsigned long nodeid = *(unsigned long *) _nodeidp;
- struct fuse_inode *fi = INO_FI(inode);
- if (fi->nodeid == nodeid)
+ if (get_node_id(inode) == nodeid)
return 1;
else
return 0;
static int fuse_inode_set(struct inode *inode, void *_nodeidp)
{
unsigned long nodeid = *(unsigned long *) _nodeidp;
- struct fuse_inode *fi = INO_FI(inode);
- fi->nodeid = nodeid;
+ get_fuse_inode(inode)->nodeid = nodeid;
return 0;
}
int generation, struct fuse_attr *attr, int version)
{
struct inode *inode;
- struct fuse_conn *fc = SB_FC(sb);
+ struct fuse_conn *fc = get_fuse_conn_super(sb);
inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
if (!inode)
#else
static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
unsigned long nodeid = *(unsigned long *) _nodeidp;
- struct fuse_inode *fi = INO_FI(inode);
- if (inode->u.generic_ip && fi->nodeid == nodeid)
+ if (inode->u.generic_ip && get_node_id(inode) == nodeid)
return 1;
else
return 0;
return NULL;
if (!inode->u.generic_ip) {
- struct fuse_inode *fi = INO_FI(inode);
- fi->nodeid = nodeid;
+ get_fuse_inode(inode)->nodeid = nodeid;
inode->u.generic_ip = inode;
inode->i_generation = generation;
fuse_init_inode(inode, attr);
struct inode *dir, struct dentry *entry,
struct fuse_entry_out *outarg, int *version)
{
- struct fuse_inode *fi = INO_FI(dir);
req->in.h.opcode = FUSE_LOOKUP;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
struct fuse_entry_out *outarg, int *version)
{
- struct fuse_conn *fc = INO_FC(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req;
int err;
static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
struct inode **inodep)
{
- struct fuse_conn *fc = INO_FC(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
int err;
struct fuse_entry_out outarg;
int version;
return err;
if (inode) {
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
entry->d_time = time_to_jiffies(outarg.entry_valid,
outarg.entry_valid_nsec);
fi->i_time = time_to_jiffies(outarg.attr_valid,
static void fuse_invalidate_attr(struct inode *inode)
{
- struct fuse_inode *fi = INO_FI(inode);
- fi->i_time = jiffies - 1;
+ get_fuse_inode(inode)->i_time = jiffies - 1;
}
static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
entry->d_time = time_to_jiffies(outarg->entry_valid,
outarg->entry_valid_nsec);
- fi = INO_FI(inode);
+ fi = get_fuse_inode(inode);
fi->i_time = time_to_jiffies(outarg->attr_valid,
outarg->attr_valid_nsec);
static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
dev_t rdev)
{
- struct fuse_conn *fc = INO_FC(dir);
- struct fuse_inode *fi = INO_FI(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_request(fc);
struct fuse_mknod_in inarg;
struct fuse_entry_out outarg;
inarg.mode = mode;
inarg.rdev = new_encode_dev(rdev);
req->in.h.opcode = FUSE_MKNOD;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
{
- struct fuse_conn *fc = INO_FC(dir);
- struct fuse_inode *fi = INO_FI(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_request(fc);
struct fuse_mkdir_in inarg;
struct fuse_entry_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
req->in.h.opcode = FUSE_MKDIR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static int fuse_symlink(struct inode *dir, struct dentry *entry,
const char *link)
{
- struct fuse_conn *fc = INO_FC(dir);
- struct fuse_inode *fi = INO_FI(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req;
struct fuse_entry_out outarg;
unsigned len = strlen(link) + 1;
return -ERESTARTSYS;
req->in.h.opcode = FUSE_SYMLINK;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 2;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
static int fuse_unlink(struct inode *dir, struct dentry *entry)
{
- struct fuse_conn *fc = INO_FC(dir);
- struct fuse_inode *fi = INO_FI(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_request(fc);
int err;
return -ERESTARTSYS;
req->in.h.opcode = FUSE_UNLINK;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
static int fuse_rmdir(struct inode *dir, struct dentry *entry)
{
- struct fuse_conn *fc = INO_FC(dir);
- struct fuse_inode *fi = INO_FI(dir);
+ struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req = fuse_get_request(fc);
int err;
return -ERESTARTSYS;
req->in.h.opcode = FUSE_RMDIR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 1;
req->in.args[0].size = entry->d_name.len + 1;
req->in.args[0].value = entry->d_name.name;
static int fuse_rename(struct inode *olddir, struct dentry *oldent,
struct inode *newdir, struct dentry *newent)
{
- struct fuse_conn *fc = INO_FC(olddir);
- struct fuse_inode *oldfi = INO_FI(olddir);
- struct fuse_inode *newfi = INO_FI(newdir);
+ struct fuse_conn *fc = get_fuse_conn(olddir);
struct fuse_req *req = fuse_get_request(fc);
struct fuse_rename_in inarg;
int err;
return -ERESTARTSYS;
memset(&inarg, 0, sizeof(inarg));
- inarg.newdir = newfi->nodeid;
+ inarg.newdir = get_node_id(newdir);
req->in.h.opcode = FUSE_RENAME;
- req->in.h.nodeid = oldfi->nodeid;
+ req->in.h.nodeid = get_node_id(olddir);
req->in.numargs = 3;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
struct dentry *newent)
{
struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_inode *newfi = INO_FI(newdir);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req = fuse_get_request(fc);
struct fuse_link_in inarg;
struct fuse_entry_out outarg;
return -ERESTARTSYS;
memset(&inarg, 0, sizeof(inarg));
- inarg.newdir = newfi->nodeid;
+ inarg.newdir = get_node_id(newdir);
req->in.h.opcode = FUSE_LINK;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
int fuse_do_getattr(struct inode *inode)
{
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req = fuse_get_request(fc);
struct fuse_attr_out arg;
int err;
return -ERESTARTSYS;
req->in.h.opcode = FUSE_GETATTR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->out.numargs = 1;
req->out.args[0].size = sizeof(arg);
req->out.args[0].value = &arg;
request_send(fc, req);
err = req->out.h.error;
if (!err) {
+ struct fuse_inode *fi = get_fuse_inode(inode);
change_attributes(inode, &arg.attr);
fi->i_time = time_to_jiffies(arg.attr_valid,
arg.attr_valid_nsec);
static int fuse_revalidate(struct dentry *entry)
{
struct inode *inode = entry->d_inode;
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
- if (fi->nodeid == FUSE_ROOT_ID) {
+ if (get_node_id(inode) == FUSE_ROOT_ID) {
if (!(fc->flags & FUSE_ALLOW_OTHER) &&
current->fsuid != fc->uid &&
(!(fc->flags & FUSE_ALLOW_ROOT) ||
static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
{
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
(!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
static int fuse_getdir(struct file *file)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(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;
return -ERESTARTSYS;
req->in.h.opcode = FUSE_GETDIR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->out.numargs = 1;
req->out.args[0].size = sizeof(struct fuse_getdir_out);
req->out.args[0].value = &outarg;
static char *read_link(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req = fuse_get_request(fc);
char *link;
goto out;
}
req->in.h.opcode = FUSE_READLINK;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->out.argvar = 1;
req->out.numargs = 1;
req->out.args[0].size = PAGE_SIZE - 1;
static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{
struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_req *req;
struct fuse_setattr_in inarg;
struct fuse_attr_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.valid = iattr_to_fattr(attr, &inarg.attr);
req->in.h.opcode = FUSE_SETATTR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
return 0;
else if (entry->d_time && time_after(jiffies, entry->d_time)) {
struct inode *inode = entry->d_inode;
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_entry_out outarg;
int version;
int ret;
if (ret)
return 0;
- if (outarg.nodeid != fi->nodeid)
+ if (outarg.nodeid != get_node_id(inode))
return 0;
change_attributes(inode, &outarg.attr);
#endif
{
struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_setxattr_in inarg;
int err;
inarg.size = size;
inarg.flags = flags;
req->in.h.opcode = FUSE_SETXATTR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 3;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
void *value, size_t size)
{
struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
req->in.h.opcode = FUSE_GETXATTR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
{
struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
req->in.h.opcode = FUSE_LISTXATTR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static int fuse_removexattr(struct dentry *entry, const char *name)
{
struct inode *inode = entry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
int err;
return -ERESTARTSYS;
req->in.h.opcode = FUSE_REMOVEXATTR;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = strlen(name) + 1;
req->in.args[0].value = name;
static int fuse_open(struct inode *inode, struct file *file)
{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_open_in inarg;
struct fuse_open_out outarg;
/* If opening the root node, no lookup has been performed on
it, so the attributes must be refreshed */
- if (fi->nodeid == FUSE_ROOT_ID) {
+ if (get_node_id(inode) == FUSE_ROOT_ID) {
int err = fuse_do_getattr(inode);
if (err)
return err;
memset(&inarg, 0, sizeof(inarg));
inarg.flags = file->f_flags & ~O_EXCL;
req->in.h.opcode = FUSE_OPEN;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static int fuse_release(struct inode *inode, struct file *file)
{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_req *req = ff->release_req;
struct fuse_release_in inarg;
fuse_sync_inode(inode);
if (!list_empty(&ff->ff_list)) {
+ struct fuse_inode *fi = get_fuse_inode(inode);
down_write(&fi->write_sem);
list_del(&ff->ff_list);
up_write(&fi->write_sem);
inarg.fh = ff->fh;
inarg.flags = file->f_flags & ~O_EXCL;
req->in.h.opcode = FUSE_RELEASE;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static int fuse_flush(struct file *file)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_req *req = ff->release_req;
struct fuse_flush_in inarg;
memset(&inarg, 0, sizeof(inarg));
inarg.fh = ff->fh;
req->in.h.opcode = FUSE_FLUSH;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
{
struct inode *inode = de->d_inode;
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
struct fuse_req *req;
struct fuse_fsync_in inarg;
inarg.fh = ff->fh;
inarg.datasync = datasync;
req->in.h.opcode = FUSE_FSYNC;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
static void fuse_read_init(struct fuse_req *req, struct file *file,
struct inode *inode, loff_t pos, size_t count)
{
- struct fuse_inode *fi = INO_FI(inode);
struct fuse_file *ff = file->private_data;
struct fuse_read_in *inarg = &req->misc.read_in;
inarg->offset = pos;
inarg->size = count;
req->in.h.opcode = FUSE_READ;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
req->in.numargs = 1;
req->in.args[0].size = sizeof(struct fuse_read_in);
req->in.args[0].value = inarg;
+ req->out.argpages = 1;
req->out.argvar = 1;
+ req->out.page_zeroing = 1;
req->out.numargs = 1;
req->out.args[0].size = count;
}
static int fuse_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req = fuse_get_request_nonint(fc);
- loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
+ loff_t pos = (loff_t) page->index << PAGE_SHIFT;
int err;
- fuse_read_init(req, file, inode, pos, PAGE_CACHE_SIZE);
- req->out.argpages = 1;
- req->out.page_zeroing = 1;
+ fuse_read_init(req, file, inode, pos, PAGE_SIZE);
req->num_pages = 1;
req->pages[0] = page;
request_send(fc, req);
static void fuse_send_readpages(struct fuse_req *req, struct file *file,
struct inode *inode)
{
- struct fuse_conn *fc = INO_FC(inode);
- loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT;
- size_t count = req->num_pages << PAGE_CACHE_SHIFT;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ loff_t pos = (loff_t) req->pages[0]->index << PAGE_SHIFT;
+ size_t count = req->num_pages << PAGE_SHIFT;
fuse_read_init(req, file, inode, pos, count);
- req->out.argpages = 1;
- req->out.page_zeroing = 1;
request_send_async(fc, req, read_pages_end);
}
struct fuse_readpages_data *data = _data;
struct fuse_req *req = data->req;
struct inode *inode = data->inode;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (req->num_pages &&
(req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
- (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
+ (req->num_pages + 1) * PAGE_SIZE > fc->max_read ||
req->pages[req->num_pages - 1]->index + 1 != page->index)) {
- struct fuse_conn *fc = INO_FC(page->mapping->host);
+ struct fuse_conn *fc = get_fuse_conn(page->mapping->host);
fuse_send_readpages(req, data->file, inode);
data->req = req = fuse_get_request_nonint(fc);
}
struct list_head *pages, unsigned nr_pages)
{
struct inode *inode = mapping->host;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_readpages_data data;
data.req = fuse_get_request_nonint(fc);
#define FUSE_BLOCK_SHIFT 16
#define FUSE_BLOCK_SIZE (1UL << FUSE_BLOCK_SHIFT)
#define FUSE_BLOCK_MASK (~(FUSE_BLOCK_SIZE-1))
-#if (1UL << (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)) > FUSE_MAX_PAGES_PER_REQ
+#if (1UL << (FUSE_BLOCK_SHIFT - PAGE_SHIFT)) > FUSE_MAX_PAGES_PER_REQ
#error FUSE_BLOCK_SHIFT too large
#endif
struct inode *inode, unsigned start,
unsigned end)
{
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
loff_t pos;
size_t count;
int index;
struct page *page = grab_cache_page(inode->i_mapping, index);
if (!page)
goto out;
+ if (PageUptodate(page)) {
+ unlock_page(page);
+ page_cache_release(page);
+ page = NULL;
+ }
req->pages[req->num_pages++] = page;
}
- pos = (loff_t) start << PAGE_CACHE_SHIFT;
- count = req->num_pages << PAGE_CACHE_SHIFT;
+ pos = (loff_t) start << PAGE_SHIFT;
+ count = req->num_pages << PAGE_SHIFT;
fuse_read_init(req, file, inode, pos, count);
- req->out.argpages = 1;
- req->out.page_zeroing = 1;
request_send(fc, req);
err = req->out.h.error;
out:
for (i = 0; i < req->num_pages; i++) {
struct page *page = req->pages[i];
- if (!err)
- SetPageUptodate(page);
- unlock_page(page);
- page_cache_release(page);
+ if (page) {
+ if (!err)
+ SetPageUptodate(page);
+ unlock_page(page);
+ page_cache_release(page);
+ }
}
}
static int fuse_file_bigread(struct file *file, struct inode *inode,
loff_t pos, size_t count)
{
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
unsigned starti;
unsigned endi;
unsigned nexti;
if (end <= pos)
return 0;
- starti = (pos & FUSE_BLOCK_MASK) >> PAGE_CACHE_SHIFT;
- endi = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ starti = (pos & FUSE_BLOCK_MASK) >> PAGE_SHIFT;
+ endi = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
req = fuse_get_request(fc);
if (!req)
return -ERESTARTSYS;
for (; starti < endi; starti = nexti) {
- nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_CACHE_SHIFT);
+ nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_SHIFT);
nexti = min(nexti, endi);
if (!fuse_is_block_uptodate(inode, starti, nexti)) {
fuse_file_read_block(req, file, inode, starti, nexti);
}
#endif /* KERNEL_2_6 */
-static void fuse_release_user_pages(struct fuse_req *req)
+static void fuse_release_user_pages(struct fuse_req *req, int write)
{
unsigned i;
for (i = 0; i < req->num_pages; i++) {
- struct page *page = req->pages[i];
+ struct page *page = req->pages[i];
+ if (write) {
#ifdef KERNEL_2_6
- set_page_dirty_lock(page);
+ set_page_dirty_lock(page);
#else
- lock_page(page);
- set_page_dirty(page);
- unlock_page(page);
+ lock_page(page);
+ set_page_dirty(page);
+ unlock_page(page);
#endif
+ }
page_cache_release(page);
}
}
-static int fuse_get_user_pages(struct fuse_req *req, char __user *buf,
- unsigned nbytes)
+static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
+ unsigned nbytes, int write)
{
unsigned long user_addr = (unsigned long) buf;
- unsigned offset = user_addr & ~PAGE_CACHE_MASK;
+ unsigned offset = user_addr & ~PAGE_MASK;
int npages;
- nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_CACHE_SHIFT);
- npages = (nbytes + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
+ npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
- npages = get_user_pages(current, current->mm, user_addr, npages, 1, 0,
- req->pages, NULL);
+ npages = get_user_pages(current, current->mm, user_addr, npages, write,
+ 0, req->pages, NULL);
if (npages < 0)
return npages;
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
loff_t pos = *ppos;
ssize_t res = 0;
struct fuse_req *req = fuse_get_request(fc);
return -ERESTARTSYS;
while (count) {
- unsigned nbytes = min(count, fc->max_read);
unsigned nread;
unsigned ntmp;
- int err = fuse_get_user_pages(req, buf, nbytes);
+ unsigned nbytes = min(count, fc->max_read);
+ int err = fuse_get_user_pages(req, buf, nbytes, 1);
if (err) {
res = err;
break;
}
- ntmp = (req->num_pages << PAGE_CACHE_SHIFT) - req->page_offset;
+ ntmp = (req->num_pages << PAGE_SHIFT) - req->page_offset;
nbytes = min(nbytes, ntmp);
fuse_read_init(req, file, inode, pos, nbytes);
- req->out.argpages = 1;
+ req->out.page_zeroing = 0; /* set to 1 by default */
request_send(fc, req);
- fuse_release_user_pages(req);
+ fuse_release_user_pages(req, 1);
if (req->out.h.error) {
if (!res)
res = req->out.h.error;
buf += nread;
if (nread != nbytes)
break;
- fuse_reset_request(req);
+ if (count)
+ fuse_reset_request(req);
}
fuse_put_request(fc, req);
if (res > 0)
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
ssize_t res;
if (fc->flags & FUSE_DIRECT_IO)
return res;
}
-static ssize_t fuse_send_write(struct fuse_req *req, struct fuse_file *ff,
- struct inode *inode, const char *buf,
- loff_t pos, size_t count)
+static void fuse_write_init(struct fuse_req *req, struct fuse_file *ff,
+ struct inode *inode, loff_t pos, size_t count,
+ int iswritepage)
{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_write_in inarg;
- struct fuse_write_out outarg;
- ssize_t res;
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.writepage = 0;
- inarg.fh = ff->fh;
- inarg.offset = pos;
- inarg.size = count;
+ struct fuse_write_in *inarg = &req->misc.write.in;
+
+ inarg->writepage = iswritepage;
+ inarg->fh = ff->fh;
+ inarg->offset = pos;
+ inarg->size = count;
req->in.h.opcode = FUSE_WRITE;
- req->in.h.nodeid = fi->nodeid;
+ req->in.h.nodeid = get_node_id(inode);
+ if (iswritepage) {
+ req->in.h.uid = 0;
+ req->in.h.gid = 0;
+ req->in.h.pid = 0;
+ }
+ req->in.argpages = 1;
req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
+ req->in.args[0].size = sizeof(struct fuse_write_in);
+ req->in.args[0].value = inarg;
req->in.args[1].size = count;
- req->in.args[1].value = buf;
req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- res = req->out.h.error;
- if (!res) {
- if (outarg.size > count)
- return -EPROTO;
- else
- return outarg.size;
- }
- else
- return res;
-}
-
-static int write_buffer(struct inode *inode, struct file *file,
- struct page *page, unsigned offset, size_t count)
-{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_file *ff = file->private_data;
- char *buffer;
- ssize_t res;
- loff_t pos;
- struct fuse_req *req;
-
- req = fuse_get_request(fc);
- if (!req)
- return -ERESTARTSYS;
-
- pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
- buffer = kmap(page);
- res = fuse_send_write(req, ff, inode, buffer + offset, pos, count);
- fuse_put_request(fc, req);
- if (res >= 0) {
- if (res < count) {
- printk("fuse: short write\n");
- res = -EPROTO;
- } else
- res = 0;
- }
- kunmap(page);
- if (res)
- SetPageError(page);
- return res;
+ req->out.args[0].size = sizeof(struct fuse_write_out);
+ req->out.args[0].value = &req->misc.write.out;
}
static int get_write_count(struct inode *inode, struct page *page)
loff_t size = i_size_read(inode);
int count;
- end_index = size >> PAGE_CACHE_SHIFT;
+ end_index = size >> PAGE_SHIFT;
if (page->index < end_index)
- count = PAGE_CACHE_SIZE;
+ count = PAGE_SIZE;
else {
- count = size & (PAGE_CACHE_SIZE - 1);
+ count = size & (PAGE_SIZE - 1);
if (page->index > end_index || count == 0)
return 0;
}
return count;
}
+static inline struct fuse_file *get_write_file(struct fuse_inode *fi)
+{
+ BUG_ON(list_empty(&fi->write_files));
+ return list_entry(fi->write_files.next, struct fuse_file, ff_list);
+}
+
#ifdef KERNEL_2_6
static void write_page_end(struct fuse_conn *fc, struct fuse_req *req)
{
struct page *page = req->pages[0];
struct inode *inode = page->mapping->host;
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_write_out *outarg = req->out.args[0].value;
- if (!req->out.h.error && outarg->size != req->in.args[1].size) {
- printk("fuse: short write\n");
+ if (!req->out.h.error && outarg->size != req->in.args[1].size)
req->out.h.error = -EPROTO;
- }
if (req->out.h.error) {
SetPageError(page);
set_bit(AS_EIO, &page->mapping->flags);
}
up_read(&fi->write_sem);
-
end_page_writeback(page);
- kunmap(page);
fuse_put_request(fc, req);
}
-static void fuse_send_writepage(struct fuse_req *req, struct inode *inode,
- struct page *page, unsigned count)
-{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_write_in *inarg;
- struct fuse_file *ff;
- char *buffer;
-
- BUG_ON(list_empty(&fi->write_files));
- ff = list_entry(fi->write_files.next, struct fuse_file, ff_list);
-
- inarg = &req->misc.write.in;
- buffer = kmap(page);
- inarg->writepage = 1;
- inarg->fh = ff->fh;
- inarg->offset = ((loff_t) page->index << PAGE_CACHE_SHIFT);
- inarg->size = count;
- req->in.h.opcode = FUSE_WRITE;
- req->in.h.nodeid = fi->nodeid;
- req->in.h.uid = 0;
- req->in.h.gid = 0;
- req->in.h.pid = 0;
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(struct fuse_write_in);
- req->in.args[0].value = inarg;
- req->in.args[1].size = count;
- req->in.args[1].value = buffer;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(struct fuse_write_out);
- req->out.args[0].value = &req->misc.write.out;
- req->pages[0] = page;
- request_send_async(fc, req, write_page_end);
-}
-
static int fuse_writepage(struct page *page, struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_req *req;
int err;
else
down_read(&fi->write_sem);
if (locked) {
- unsigned count;
+ unsigned count = get_write_count(inode, page);
+ loff_t pos = (loff_t) page->index << PAGE_SHIFT;
err = 0;
- count = get_write_count(inode, page);
if (count) {
- SetPageWriteback(page);
- fuse_send_writepage(req, inode, page, count);
+ struct fuse_file *ff = get_write_file(fi);
+ SetPageWriteback(page);
+ fuse_write_init(req, ff, inode, pos, count, 1);
+ req->num_pages = 1;
+ req->pages[0] = page;
+ request_send_async(fc, req, write_page_end);
goto out;
}
up_read(&fi->write_sem);
return err;
}
#else
-static ssize_t fuse_send_writepage(struct fuse_req *req, struct fuse_file *ff,
- struct inode *inode, const char *buf,
- loff_t pos, size_t count)
-{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
- struct fuse_write_in inarg;
- struct fuse_write_out outarg;
- ssize_t res;
-
- memset(&inarg, 0, sizeof(inarg));
- inarg.writepage = 1;
- inarg.fh = ff->fh;
- inarg.offset = pos;
- inarg.size = count;
- req->in.h.opcode = FUSE_WRITE;
- req->in.h.nodeid = fi->nodeid;
- req->in.h.uid = 0;
- req->in.h.gid = 0;
- req->in.h.pid = 0;
- req->in.numargs = 2;
- req->in.args[0].size = sizeof(inarg);
- req->in.args[0].value = &inarg;
- req->in.args[1].size = count;
- req->in.args[1].value = buf;
- req->out.numargs = 1;
- req->out.args[0].size = sizeof(outarg);
- req->out.args[0].value = &outarg;
- request_send(fc, req);
- res = req->out.h.error;
- if (!res) {
- if (outarg.size > count)
- return -EPROTO;
- else
- return outarg.size;
- }
- else
- return res;
-}
-
-static int write_page_block(struct inode *inode, struct page *page)
+static int fuse_writepage(struct page *page)
{
- struct fuse_conn *fc = INO_FC(inode);
- struct fuse_inode *fi = INO_FI(inode);
- char *buffer;
- ssize_t res;
- loff_t pos;
+ int err;
unsigned count;
- struct fuse_req *req;
+ struct inode *inode = page->mapping->host;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_req *req = fuse_get_request_nonint(fc);
- req = fuse_get_request(fc);
- if (!req)
- return -ERESTARTSYS;
-
down_read(&fi->write_sem);
count = get_write_count(inode, page);
- res = 0;
+ err = 0;
if (count) {
- struct fuse_file *ff;
- BUG_ON(list_empty(&fi->write_files));
- ff = list_entry(fi->write_files.next, struct fuse_file, ff_list);
- pos = ((loff_t) page->index << PAGE_CACHE_SHIFT);
- buffer = kmap(page);
- res = fuse_send_writepage(req, ff, inode, buffer, pos, count);
- if (res >= 0) {
- if (res < count) {
- printk("fuse: short write\n");
- res = -EPROTO;
- } else
- res = 0;
- }
+ struct fuse_file *ff = get_write_file(fi);
+ loff_t pos = ((loff_t) page->index << PAGE_SHIFT);
+
+ fuse_write_init(req, ff, inode, pos, count, 1);
+ req->num_pages = 1;
+ req->pages[0] = page;
+ request_send(fc, req);
+ err = req->out.h.error;
+ if (!err && req->misc.write.out.size != count)
+ err = -EPROTO;
}
up_read(&fi->write_sem);
fuse_put_request(fc, req);
- kunmap(page);
- if (res)
+ if (err)
SetPageError(page);
- return res;
-}
-
-static int fuse_writepage(struct page *page)
-{
- int err = write_page_block(page->mapping->host, page);
unlock_page(page);
return err;
}
unsigned offset, unsigned to)
{
int err;
+ unsigned count = to - offset;
struct inode *inode = page->mapping->host;
+ struct fuse_file *ff = file->private_data;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_req *req = fuse_get_request(fc);
+ loff_t pos = ((loff_t) page->index << PAGE_SHIFT) + offset;
+ if (!req)
+ return -ERESTARTSYS;
- err = write_buffer(inode, file, page, offset, to - offset);
+ fuse_write_init(req, ff, inode, pos, count, 0);
+ req->num_pages = 1;
+ req->pages[0] = page;
+ req->page_offset = offset;
+ request_send(fc, req);
+ err = req->out.h.error;
+ if (!err && req->misc.write.out.size != count)
+ err = -EPROTO;
if (!err) {
- loff_t pos = (page->index << PAGE_CACHE_SHIFT) + to;
+ pos += count;
if (pos > i_size_read(inode))
i_size_write(inode, pos);
- if (offset == 0 && to == PAGE_CACHE_SIZE) {
+ if (offset == 0 && to == PAGE_SIZE) {
#ifdef KERNEL_2_6
clear_page_dirty(page);
#else
#endif
SetPageUptodate(page);
}
-
}
+ fuse_put_request(fc, req);
return err;
}
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
- char *tmpbuf;
- ssize_t res = 0;
loff_t pos = *ppos;
- struct fuse_req *req;
- size_t max_write = min(fc->max_write, (unsigned) PAGE_SIZE);
-
- req = fuse_get_request(fc);
+ ssize_t res = 0;
+ struct fuse_req *req = fuse_get_request(fc);
if (!req)
return -ERESTARTSYS;
- tmpbuf = (char *) __get_free_page(GFP_KERNEL);
- if (!tmpbuf) {
- fuse_put_request(fc, req);
- return -ENOMEM;
- }
-
while (count) {
- size_t nbytes = min(max_write, count);
- ssize_t res1;
- if (copy_from_user(tmpbuf, buf, nbytes)) {
- res = -EFAULT;
+ unsigned ntmp;
+ unsigned nwritten;
+ size_t nbytes = min(count, fc->max_write);
+ int err = fuse_get_user_pages(req, buf, nbytes, 0);
+ if (err) {
+ res = err;
break;
}
- res1 = fuse_send_write(req, ff, inode, tmpbuf, pos, nbytes);
- if (res1 < 0) {
- res = res1;
+ ntmp = (req->num_pages << PAGE_SHIFT) - req->page_offset;
+ nbytes = min(nbytes, ntmp);
+ fuse_write_init(req, ff, inode, pos, nbytes, 0);
+ request_send(fc, req);
+ fuse_release_user_pages(req, 0);
+ if (req->out.h.error) {
+ if (!res)
+ res = req->out.h.error;
break;
}
- res += res1;
- count -= res1;
- buf += res1;
- pos += res1;
- if (res1 < nbytes)
+ nwritten = req->misc.write.out.size;
+ count -= nwritten;
+ res += nwritten;
+ pos += nwritten;
+ buf += nwritten;
+ if (nwritten != nbytes)
break;
-
if (count)
fuse_reset_request(req);
}
- free_page((unsigned long) tmpbuf);
fuse_put_request(fc, req);
-
if (res > 0) {
if (pos > i_size_read(inode))
i_size_write(inode, pos);
size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (fc->flags & FUSE_DIRECT_IO) {
ssize_t res;
res = fuse_direct_write(file, buf, count, ppos);
up(&inode->i_sem);
return res;
+ return -EPERM;
}
else
return generic_file_write(file, buf, count, ppos);
static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
- struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (fc->flags & FUSE_DIRECT_IO)
return -ENODEV;
else {
if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) ==
(VM_WRITE | VM_SHARED)) {
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
struct fuse_file *ff = file->private_data;
if (!user_mmap && current->uid != 0)
doing the mount will be allowed to access the filesystem */
#define FUSE_ALLOW_OTHER (1 << 1)
-/** If the FUSE_KERNEL_CACHE flag is given, then files will be cached
- until the INVALIDATE operation is invoked */
+/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not
+ be flushed on open */
#define FUSE_KERNEL_CACHE (1 << 2)
#ifndef KERNEL_2_6
/** Allow FUSE to combine reads into 64k chunks. This is useful if
- the filesystem is better at handling large chunks. NOTE: in
- current implementation the raw throughput is worse for large reads
- than for small. */
+ the filesystem is better at handling large chunks */
#define FUSE_LARGE_READ (1 << 31)
#endif
/** Bypass the page cache for read and write operations */
/** FUSE specific inode data */
struct fuse_inode {
+ /** Unique ID, which identifies the inode between userspace
+ * and kernel */
unsigned long nodeid;
+
+ /** The request used for sending the FORGET message */
struct fuse_req *forget_req;
+
+ /** Semaphore protects the 'write_files' list, and against
+ truncate racing with async writeouts */
struct rw_semaphore write_sem;
+
+ /** Time in jiffies until the file attributes are valid */
unsigned long i_time;
- /* Files which can provide file handles in writepage.
- Protected by write_sem */
+
+ /* List of fuse_files which can provide file handles in
+ * writepage, protected by write_sem */
struct list_head write_files;
};
/** The request input */
struct fuse_in {
+ /** The request header */
struct fuse_in_header h;
+
+ /** True if the data for the last argument is in req->pages */
+ unsigned argpages:1;
+
+ /** Number of arguments */
unsigned numargs;
+
+ /** Array of arguments */
struct fuse_in_arg args[3];
};
void *file; /* Used by kernel only */
};
+static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb)
+{
#ifdef KERNEL_2_6
-#define SB_FC(sb) ((sb)->s_fs_info)
+ return (struct fuse_conn **) &sb->s_fs_info;
#else
-#define SB_FC(sb) ((sb)->u.generic_sbp)
+ return (struct fuse_conn **) &sb->u.generic_sbp;
#endif
-#define INO_FC(inode) SB_FC((inode)->i_sb)
-#define INO_FI(i) ((struct fuse_inode *) (((struct inode *)(i))+1))
+}
+
+static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
+{
+ return *get_fuse_conn_super_p(sb);
+}
+
+static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
+{
+ return get_fuse_conn_super(inode->i_sb);
+}
+
+static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
+{
+ return (struct fuse_inode *) (&inode[1]);
+}
+
+static inline unsigned long get_node_id(struct inode *inode)
+{
+ return get_fuse_inode(inode)->nodeid;
+}
/** Device operations */
extern struct file_operations fuse_dev_operations;
inode->u.generic_ip = NULL;
#endif
- fi = INO_FI(inode);
+ fi = get_fuse_inode(inode);
memset(fi, 0, sizeof(*fi));
fi->forget_req = fuse_request_alloc();
if (!fi->forget_req) {
static void fuse_destroy_inode(struct inode *inode)
{
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
BUG_ON(!list_empty(&fi->write_files));
if (fi->forget_req)
fuse_request_free(fi->forget_req);
static void fuse_clear_inode(struct inode *inode)
{
- struct fuse_conn *fc = INO_FC(inode);
-
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (fc) {
- struct fuse_inode *fi = INO_FI(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
fi->forget_req = NULL;
}
static void fuse_put_super(struct super_block *sb)
{
- struct fuse_conn *fc = SB_FC(sb);
+ struct fuse_conn *fc = get_fuse_conn_super(sb);
down(&fc->sb_sem);
spin_lock(&fuse_lock);
/* Flush all readers on this fs */
wake_up_all(&fc->waitq);
fuse_release_conn(fc);
- SB_FC(sb) = NULL;
+ *get_fuse_conn_super_p(sb) = NULL;
spin_unlock(&fuse_lock);
}
static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
{
- struct fuse_conn *fc = SB_FC(sb);
+ struct fuse_conn *fc = get_fuse_conn_super(sb);
struct fuse_req *req;
struct fuse_statfs_out outarg;
int err;
static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
{
- struct fuse_conn *fc = SB_FC(mnt->mnt_sb);
+ struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
seq_printf(m, ",uid=%u", fc->uid);
if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
int connectable)
{
struct inode *inode = dentry->d_inode;
- struct fuse_inode *fi = INO_FI(inode);
int len = *max_len;
int type = 1;
return 255;
len = 2;
- fh[0] = fi->nodeid;
+ fh[0] = get_fuse_inode(inode)->nodeid;
fh[1] = inode->i_generation;
if (connectable && !S_ISDIR(inode->i_mode)) {
struct inode *parent;
- struct fuse_inode *parent_fi;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
- parent_fi = INO_FI(parent);
- fh[2] = parent_fi->nodeid;
+ fh[2] = get_fuse_inode(parent)->nodeid;
fh[3] = parent->i_generation;
spin_unlock(&dentry->d_lock);
len = 4;
#endif
fc->max_write = FUSE_MAX_IN / 2;
- SB_FC(sb) = fc;
+ *get_fuse_conn_super_p(sb) = fc;
root = get_root_inode(sb, d.rootmode);
if (root == NULL) {
up(&fc->sb_sem);
fuse_release_conn(fc);
spin_unlock(&fuse_lock);
- SB_FC(sb) = NULL;
+ *get_fuse_conn_super_p(sb) = NULL;
return -EINVAL;
}