/*
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;
struct fuse_req *req;
- struct fuse_req *forget_req;
/* Doesn't hurt to "reset" the validity timeout */
fuse_invalidate_entry_cache(entry);
return 0;
fc = get_fuse_conn(inode);
- req = fuse_get_req(fc);
- if (IS_ERR(req))
+ req = fuse_get_request(fc);
+ if (!req)
return 0;
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req)) {
- fuse_put_request(fc, req);
- return 0;
- }
-
fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
request_send(fc, req);
err = req->out.h.error;
- fuse_put_request(fc, req);
/* Zero nodeid is same as -ENOENT */
if (!err && !outarg.nodeid)
err = -ENOENT;
if (!err) {
struct fuse_inode *fi = get_fuse_inode(inode);
if (outarg.nodeid != get_node_id(inode)) {
- fuse_send_forget(fc, forget_req,
- outarg.nodeid, 1);
+ fuse_send_forget(fc, req, outarg.nodeid, 1);
return 0;
}
fi->nlookup ++;
}
- fuse_put_request(fc, forget_req);
+ fuse_put_request(fc, req);
if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
return 0;
struct inode *inode = NULL;
struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req;
- struct fuse_req *forget_req;
if (entry->d_name.len > FUSE_NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return ERR_PTR(PTR_ERR(req));
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req)) {
- fuse_put_request(fc, req);
- return ERR_PTR(PTR_ERR(forget_req));
- }
+ req = fuse_get_request(fc);
+ if (!req)
+ return ERR_PTR(-EINTR);
fuse_lookup_init(req, dir, entry, &outarg);
request_send(fc, req);
err = req->out.h.error;
- fuse_put_request(fc, req);
/* Zero nodeid is same as -ENOENT, but with valid timeout */
if (!err && outarg.nodeid &&
(invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode)))
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr);
if (!inode) {
- fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
+ fuse_send_forget(fc, req, outarg.nodeid, 1);
return ERR_PTR(-ENOMEM);
}
}
- fuse_put_request(fc, forget_req);
+ fuse_put_request(fc, req);
if (err && err != -ENOENT)
return ERR_PTR(err);
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;
struct file *file;
int flags = nd->intent.open.flags - 1;
+ err = -ENOSYS;
if (fc->no_create)
- return -ENOSYS;
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req))
- return PTR_ERR(forget_req);
+ goto out;
- req = fuse_get_req(fc);
- err = PTR_ERR(req);
- if (IS_ERR(req))
- goto out_put_forget_req;
+ err = -EINTR;
+ req = fuse_get_request(fc);
+ if (!req)
+ goto out;
- err = -ENOMEM;
ff = fuse_file_alloc();
if (!ff)
goto out_put_request;
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);
+ out:
return err;
}
struct fuse_entry_out outarg;
struct inode *inode;
int err;
- struct fuse_req *forget_req;
-
- forget_req = fuse_get_req(fc);
- if (IS_ERR(forget_req)) {
- fuse_put_request(fc, req);
- return PTR_ERR(forget_req);
- }
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;
request_send(fc, req);
err = req->out.h.error;
- fuse_put_request(fc, req);
- if (err)
- goto out_put_forget_req;
-
+ if (err) {
+ fuse_put_request(fc, req);
+ return err;
+ }
err = -EIO;
if (invalid_nodeid(outarg.nodeid))
- goto out_put_forget_req;
+ goto out_put_request;
if ((outarg.attr.mode ^ mode) & S_IFMT)
- goto out_put_forget_req;
+ goto out_put_request;
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr);
if (!inode) {
- fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
+ fuse_send_forget(fc, req, outarg.nodeid, 1);
return -ENOMEM;
}
- fuse_put_request(fc, forget_req);
+ fuse_put_request(fc, req);
if (dir_alias(inode)) {
iput(inode);
fuse_invalidate_attr(dir);
return 0;
- out_put_forget_req:
- fuse_put_request(fc, forget_req);
+ out_put_request:
+ fuse_put_request(fc, req);
return err;
}
{
struct fuse_mknod_in inarg;
struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
{
struct fuse_mkdir_in inarg;
struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(inarg));
inarg.mode = mode;
{
struct fuse_conn *fc = get_fuse_conn(dir);
unsigned len = strlen(link) + 1;
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
req->in.h.opcode = FUSE_SYMLINK;
req->in.numargs = 2;
{
int err;
struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
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;
{
int err;
struct fuse_conn *fc = get_fuse_conn(dir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
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;
int err;
struct fuse_rename_in inarg;
struct fuse_conn *fc = get_fuse_conn(olddir);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(inarg));
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;
struct fuse_link_in inarg;
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
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;
int err;
struct fuse_attr_out arg;
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ struct fuse_req *req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
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);
if (fc->no_access)
return 0;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(inarg));
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;
if (is_bad_inode(inode))
return -EIO;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
page = alloc_page(GFP_KERNEL);
if (!page) {
{
struct inode *inode = dentry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_req *req = fuse_get_req(fc);
+ struct fuse_req *req = fuse_get_request(fc);
char *link;
- if (IS_ERR(req))
- return ERR_PTR(PTR_ERR(req));
+ if (!req)
+ return ERR_PTR(-EINTR);
link = (char *) __get_free_page(GFP_KERNEL);
if (!link) {
}
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);
+ spin_lock(&fuse_lock);
need_trunc = inode->i_size > offset;
i_size_write(inode, offset);
- spin_unlock(&fc->lock);
+ spin_unlock(&fuse_lock);
if (need_trunc) {
struct address_space *mapping = inode->i_mapping;
}
}
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(inarg));
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;
if (fc->no_setxattr)
return -EOPNOTSUPP;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
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;
if (fc->no_getxattr)
return -EOPNOTSUPP;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(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;
if (fc->no_listxattr)
return -EOPNOTSUPP;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
memset(&inarg, 0, sizeof(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;
if (fc->no_removexattr)
return -EOPNOTSUPP;
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ req = fuse_get_request(fc);
+ if (!req)
+ return -EINTR;
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;
.removexattr = fuse_removexattr,
};
-static const struct file_operations fuse_dir_operations = {
+static struct file_operations fuse_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = fuse_readdir,