diff options
Diffstat (limited to 'kernel/dir.c')
-rw-r--r-- | kernel/dir.c | 101 |
1 files changed, 68 insertions, 33 deletions
diff --git a/kernel/dir.c b/kernel/dir.c index a2887b6..66dac79 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -20,6 +20,33 @@ #include <linux/namei.h> #endif +#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 @@ -29,10 +56,13 @@ /* * Calculate the time in jiffies until a dentry/attributes are valid */ -static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec) +static u64 time_to_jiffies(unsigned long sec, unsigned long nsec) { - struct timespec ts = {sec, nsec}; - return jiffies + timespec_to_jiffies(&ts); + if (sec || nsec) { + struct timespec ts = {sec, nsec}; + return get_jiffies_64() + timespec_to_jiffies(&ts); + } else + return 0; } /* @@ -41,7 +71,8 @@ static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec) */ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) { - entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec); + fuse_dentry_settime(entry, + 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); @@ -53,7 +84,7 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o) */ void fuse_invalidate_attr(struct inode *inode) { - get_fuse_inode(inode)->i_time = jiffies - 1; + get_fuse_inode(inode)->i_time = 0; } /* @@ -66,7 +97,7 @@ void fuse_invalidate_attr(struct inode *inode) */ static void fuse_invalidate_entry_cache(struct dentry *entry) { - entry->d_time = jiffies - 1; + fuse_dentry_settime(entry, 0); } /* @@ -85,7 +116,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; @@ -109,7 +139,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) if (inode && is_bad_inode(inode)) return 0; - else if (time_after(jiffies, entry->d_time)) { + else if (fuse_dentry_time(entry) < get_jiffies_64()) { int err; struct fuse_entry_out outarg; struct fuse_conn *fc; @@ -262,6 +292,20 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, #ifdef HAVE_LOOKUP_INSTANTIATE_FILP /* + * 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 * * If the filesystem doesn't support this, then fall back to separate @@ -274,6 +318,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; @@ -284,9 +329,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(); @@ -299,7 +349,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; @@ -322,25 +371,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); @@ -350,6 +397,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; } #endif @@ -366,7 +415,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; @@ -488,7 +536,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; @@ -520,7 +567,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; @@ -550,8 +596,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; @@ -598,7 +642,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; @@ -627,7 +670,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; @@ -700,7 +742,7 @@ static int fuse_revalidate(struct dentry *entry) if (!fuse_allow_task(fc, current)) return -EACCES; if (get_node_id(inode) != FUSE_ROOT_ID && - time_before_eq(jiffies, fi->i_time)) + fi->i_time >= get_jiffies_64()) return 0; return fuse_do_getattr(inode); @@ -725,7 +767,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; @@ -882,7 +923,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; @@ -1048,7 +1088,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; @@ -1145,7 +1184,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; @@ -1184,7 +1222,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; @@ -1234,7 +1271,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; @@ -1278,7 +1314,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; |