|
@@ -1,6 +1,6 @@
|
|
|
/*
|
|
|
FUSE: Filesystem in Userspace
|
|
|
- Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
|
|
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
|
|
|
|
|
|
This program can be distributed under the terms of the GNU GPL.
|
|
|
See the file COPYING.
|
|
@@ -79,7 +79,6 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
|
|
|
{
|
|
|
req->in.h.opcode = FUSE_LOOKUP;
|
|
|
req->in.h.nodeid = get_node_id(dir);
|
|
|
- req->inode = dir;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = entry->d_name.len + 1;
|
|
|
req->in.args[0].value = entry->d_name.name;
|
|
@@ -224,6 +223,20 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Synchronous release for the case when something goes wrong in CREATE_OPEN
|
|
|
+ */
|
|
|
+static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
|
|
|
+ u64 nodeid, int flags)
|
|
|
+{
|
|
|
+ struct fuse_req *req;
|
|
|
+
|
|
|
+ req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
|
|
|
+ req->force = 1;
|
|
|
+ request_send(fc, req);
|
|
|
+ fuse_put_request(fc, req);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Atomic create+open operation
|
|
|
*
|
|
@@ -237,6 +250,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
|
|
struct inode *inode;
|
|
|
struct fuse_conn *fc = get_fuse_conn(dir);
|
|
|
struct fuse_req *req;
|
|
|
+ struct fuse_req *forget_req;
|
|
|
struct fuse_open_in inarg;
|
|
|
struct fuse_open_out outopen;
|
|
|
struct fuse_entry_out outentry;
|
|
@@ -247,9 +261,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
|
|
if (fc->no_create)
|
|
|
return -ENOSYS;
|
|
|
|
|
|
+ forget_req = fuse_get_req(fc);
|
|
|
+ if (IS_ERR(forget_req))
|
|
|
+ return PTR_ERR(forget_req);
|
|
|
+
|
|
|
req = fuse_get_req(fc);
|
|
|
+ err = PTR_ERR(req);
|
|
|
if (IS_ERR(req))
|
|
|
- return PTR_ERR(req);
|
|
|
+ goto out_put_forget_req;
|
|
|
|
|
|
err = -ENOMEM;
|
|
|
ff = fuse_file_alloc();
|
|
@@ -262,7 +281,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
|
|
inarg.mode = mode;
|
|
|
req->in.h.opcode = FUSE_CREATE;
|
|
|
req->in.h.nodeid = get_node_id(dir);
|
|
|
- req->inode = dir;
|
|
|
req->in.numargs = 2;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -285,25 +303,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
|
|
if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
|
|
|
goto out_free_ff;
|
|
|
|
|
|
+ fuse_put_request(fc, req);
|
|
|
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
|
|
|
&outentry.attr);
|
|
|
- err = -ENOMEM;
|
|
|
if (!inode) {
|
|
|
flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
|
|
|
ff->fh = outopen.fh;
|
|
|
- /* Special release, with inode = NULL, this will
|
|
|
- trigger a 'forget' request when the release is
|
|
|
- complete */
|
|
|
- fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
|
|
|
- goto out_put_request;
|
|
|
+ fuse_sync_release(fc, ff, outentry.nodeid, flags);
|
|
|
+ fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
- fuse_put_request(fc, req);
|
|
|
+ fuse_put_request(fc, forget_req);
|
|
|
d_instantiate(entry, inode);
|
|
|
fuse_change_timeout(entry, &outentry);
|
|
|
file = lookup_instantiate_filp(nd, entry, generic_file_open);
|
|
|
if (IS_ERR(file)) {
|
|
|
ff->fh = outopen.fh;
|
|
|
- fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
|
|
|
+ fuse_sync_release(fc, ff, outentry.nodeid, flags);
|
|
|
return PTR_ERR(file);
|
|
|
}
|
|
|
fuse_finish_open(inode, file, ff, &outopen);
|
|
@@ -313,6 +329,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
|
|
|
fuse_file_free(ff);
|
|
|
out_put_request:
|
|
|
fuse_put_request(fc, req);
|
|
|
+ out_put_forget_req:
|
|
|
+ fuse_put_request(fc, forget_req);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -328,7 +346,6 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
|
|
|
int err;
|
|
|
|
|
|
req->in.h.nodeid = get_node_id(dir);
|
|
|
- req->inode = dir;
|
|
|
req->out.numargs = 1;
|
|
|
req->out.args[0].size = sizeof(outarg);
|
|
|
req->out.args[0].value = &outarg;
|
|
@@ -448,7 +465,6 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
|
|
|
|
|
|
req->in.h.opcode = FUSE_UNLINK;
|
|
|
req->in.h.nodeid = get_node_id(dir);
|
|
|
- req->inode = dir;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = entry->d_name.len + 1;
|
|
|
req->in.args[0].value = entry->d_name.name;
|
|
@@ -480,7 +496,6 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
|
|
|
|
|
|
req->in.h.opcode = FUSE_RMDIR;
|
|
|
req->in.h.nodeid = get_node_id(dir);
|
|
|
- req->inode = dir;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = entry->d_name.len + 1;
|
|
|
req->in.args[0].value = entry->d_name.name;
|
|
@@ -510,8 +525,6 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
|
|
|
inarg.newdir = get_node_id(newdir);
|
|
|
req->in.h.opcode = FUSE_RENAME;
|
|
|
req->in.h.nodeid = get_node_id(olddir);
|
|
|
- req->inode = olddir;
|
|
|
- req->inode2 = newdir;
|
|
|
req->in.numargs = 3;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -558,7 +571,6 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
|
|
|
memset(&inarg, 0, sizeof(inarg));
|
|
|
inarg.oldnodeid = get_node_id(inode);
|
|
|
req->in.h.opcode = FUSE_LINK;
|
|
|
- req->inode2 = inode;
|
|
|
req->in.numargs = 2;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -587,7 +599,6 @@ int fuse_do_getattr(struct inode *inode)
|
|
|
|
|
|
req->in.h.opcode = FUSE_GETATTR;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->out.numargs = 1;
|
|
|
req->out.args[0].size = sizeof(arg);
|
|
|
req->out.args[0].value = &arg;
|
|
@@ -679,7 +690,6 @@ static int fuse_access(struct inode *inode, int mask)
|
|
|
inarg.mask = mask;
|
|
|
req->in.h.opcode = FUSE_ACCESS;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -820,7 +830,6 @@ static char *read_link(struct dentry *dentry)
|
|
|
}
|
|
|
req->in.h.opcode = FUSE_READLINK;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->out.argvar = 1;
|
|
|
req->out.numargs = 1;
|
|
|
req->out.args[0].size = PAGE_SIZE - 1;
|
|
@@ -939,7 +948,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
|
|
|
iattr_to_fattr(attr, &inarg);
|
|
|
req->in.h.opcode = FUSE_SETATTR;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -1002,7 +1010,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
|
|
|
inarg.flags = flags;
|
|
|
req->in.h.opcode = FUSE_SETXATTR;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->in.numargs = 3;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -1041,7 +1048,6 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
|
|
|
inarg.size = size;
|
|
|
req->in.h.opcode = FUSE_GETXATTR;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->in.numargs = 2;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -1091,7 +1097,6 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
|
|
|
inarg.size = size;
|
|
|
req->in.h.opcode = FUSE_LISTXATTR;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = sizeof(inarg);
|
|
|
req->in.args[0].value = &inarg;
|
|
@@ -1135,7 +1140,6 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
|
|
|
|
|
|
req->in.h.opcode = FUSE_REMOVEXATTR;
|
|
|
req->in.h.nodeid = get_node_id(inode);
|
|
|
- req->inode = inode;
|
|
|
req->in.numargs = 1;
|
|
|
req->in.args[0].size = strlen(name) + 1;
|
|
|
req->in.args[0].value = name;
|