/*
FUSE: Filesystem in Userspace
- Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
+ Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
#include <linux/sched.h>
#include <linux/namei.h>
-#if BITS_PER_LONG >= 64
-static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
-{
- entry->d_time = time;
-}
-
-static inline u64 fuse_dentry_time(struct dentry *entry)
-{
- return entry->d_time;
-}
-#else
-/*
- * On 32 bit archs store the high 32 bits of time in d_fsdata
- */
-static void fuse_dentry_settime(struct dentry *entry, u64 time)
-{
- entry->d_time = time;
- entry->d_fsdata = (void *) (unsigned long) (time >> 32);
-}
-
-static u64 fuse_dentry_time(struct dentry *entry)
-{
- return (u64) entry->d_time +
- ((u64) (unsigned long) entry->d_fsdata << 32);
-}
-#endif
-
/*
* FUSE caches dentries and attributes with separate timeout. The
* time in jiffies until the dentry/attributes are valid is stored in
/*
* Calculate the time in jiffies until a dentry/attributes are valid
*/
-static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
+static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
{
- if (sec || nsec) {
- struct timespec ts = {sec, nsec};
- return get_jiffies_64() + timespec_to_jiffies(&ts);
- } else
- return 0;
+ struct timespec ts = {sec, nsec};
+ return jiffies + timespec_to_jiffies(&ts);
}
/*
*/
static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
{
- fuse_dentry_settime(entry,
- time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
+ entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
if (entry->d_inode)
get_fuse_inode(entry->d_inode)->i_time =
time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
*/
void fuse_invalidate_attr(struct inode *inode)
{
- get_fuse_inode(inode)->i_time = 0;
+ get_fuse_inode(inode)->i_time = jiffies - 1;
}
/*
*/
static void fuse_invalidate_entry_cache(struct dentry *entry)
{
- fuse_dentry_settime(entry, 0);
+ entry->d_time = jiffies - 1;
}
/*
{
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;
if (inode && is_bad_inode(inode))
return 0;
- else if (fuse_dentry_time(entry) < get_jiffies_64()) {
+ else if (time_after(jiffies, entry->d_time)) {
int err;
struct fuse_entry_out outarg;
struct fuse_conn *fc;
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
*
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;
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))
- goto out_put_forget_req;
+ return PTR_ERR(req);
err = -ENOMEM;
ff = fuse_file_alloc();
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;
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;
- fuse_sync_release(fc, ff, outentry.nodeid, flags);
- fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
- return -ENOMEM;
+ /* 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_put_request(fc, forget_req);
+ fuse_put_request(fc, 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_sync_release(fc, ff, outentry.nodeid, flags);
+ fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
return PTR_ERR(file);
}
fuse_finish_open(inode, file, ff, &outopen);
fuse_file_free(ff);
out_put_request:
fuse_put_request(fc, req);
- out_put_forget_req:
- fuse_put_request(fc, forget_req);
return err;
}
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;
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;
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;
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;
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;
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;
if (!fuse_allow_task(fc, current))
return -EACCES;
if (get_node_id(inode) != FUSE_ROOT_ID &&
- fi->i_time >= get_jiffies_64())
+ time_before_eq(jiffies, fi->i_time))
return 0;
return fuse_do_getattr(inode);
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;
}
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;
}
}
-static void fuse_vmtruncate(struct inode *inode, loff_t offset)
-{
- struct fuse_conn *fc = get_fuse_conn(inode);
- int need_trunc;
-
- spin_lock(&fc->lock);
- need_trunc = inode->i_size > offset;
- i_size_write(inode, offset);
- spin_unlock(&fc->lock);
-
- if (need_trunc) {
- struct address_space *mapping = inode->i_mapping;
- unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
- truncate_inode_pages(mapping, offset);
- }
-}
-
/*
* Set attributes, and at the same time refresh them.
*
* Truncation is slightly complicated, because the 'truncate' request
* may fail, in which case we don't want to touch the mapping.
- * vmtruncate() doesn't allow for this case, so do the rlimit checking
- * and the actual truncation by hand.
+ * vmtruncate() doesn't allow for this case. So do the rlimit
+ * checking by hand and call vmtruncate() only after the file has
+ * actually been truncated.
*/
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;
make_bad_inode(inode);
err = -EIO;
} else {
- if (is_truncate)
- fuse_vmtruncate(inode, outarg.attr.size);
+ if (is_truncate) {
+ loff_t origsize = i_size_read(inode);
+ i_size_write(inode, outarg.attr.size);
+ if (origsize > outarg.attr.size)
+ vmtruncate(inode, outarg.attr.size);
+ }
fuse_change_attributes(inode, &outarg.attr);
fi->i_time = time_to_jiffies(outarg.attr_valid,
outarg.attr_valid_nsec);
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;
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;
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;
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;