diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index a058b664859c..8c5d156284a0 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -705,10 +705,12 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr, stat->blksize = (1 << inode->i_blkbits); } -static int fuse_do_getattr(struct inode *inode, struct kstat *stat) +static int fuse_do_getattr(struct inode *inode, struct kstat *stat, + struct file *file) { int err; - struct fuse_attr_out arg; + struct fuse_getattr_in inarg; + struct fuse_attr_out outarg; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_req *req; u64 attr_version; @@ -721,24 +723,35 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat) attr_version = fc->attr_version; spin_unlock(&fc->lock); + memset(&inarg, 0, sizeof(inarg)); + /* Directories have separate file-handle space */ + if (file && S_ISREG(inode->i_mode)) { + struct fuse_file *ff = file->private_data; + + inarg.getattr_flags |= FUSE_GETATTR_FH; + inarg.fh = ff->fh; + } req->in.h.opcode = FUSE_GETATTR; 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; req->out.numargs = 1; - req->out.args[0].size = sizeof(arg); - req->out.args[0].value = &arg; + 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) { - if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) { + if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) { make_bad_inode(inode); err = -EIO; } else { - fuse_change_attributes(inode, &arg.attr, - attr_timeout(&arg), + fuse_change_attributes(inode, &outarg.attr, + attr_timeout(&outarg), attr_version); if (stat) - fuse_fillattr(inode, &arg.attr, stat); + fuse_fillattr(inode, &outarg.attr, stat); } } return err; @@ -833,7 +846,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { struct fuse_inode *fi = get_fuse_inode(inode); if (fi->i_time < get_jiffies_64()) { - err = fuse_do_getattr(inode, NULL); + err = fuse_do_getattr(inode, NULL, NULL); if (err) return err; @@ -848,7 +861,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) attributes. This is also needed, because the root node will at first have no permissions */ if (err == -EACCES && !refreshed) { - err = fuse_do_getattr(inode, NULL); + err = fuse_do_getattr(inode, NULL, NULL); if (!err) err = generic_permission(inode, mask, NULL); } @@ -864,7 +877,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) if (refreshed) return -EACCES; - err = fuse_do_getattr(inode, NULL); + err = fuse_do_getattr(inode, NULL, NULL); if (!err && !(inode->i_mode & S_IXUGO)) return -EACCES; } @@ -1107,7 +1120,7 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, return -EACCES; if (fi->i_time < get_jiffies_64()) - err = fuse_do_getattr(inode, stat); + err = fuse_do_getattr(inode, stat, NULL); else { err = 0; generic_fillattr(inode, stat); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 2167fc4fcab8..6ef3973f4048 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -553,7 +553,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) arg->major = FUSE_KERNEL_VERSION; arg->minor = FUSE_KERNEL_MINOR_VERSION; arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; - arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; + arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_FILE_OPS; req->in.h.opcode = FUSE_INIT; req->in.numargs = 1; req->in.args[0].size = sizeof(*arg); diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 9fbe9d258e22..a50d0d9ac7ae 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -6,7 +6,14 @@ See the file COPYING. */ -/* This file defines the kernel interface of FUSE */ +/* + * This file defines the kernel interface of FUSE + * + * Protocol changelog: + * + * 7.9: + * - new fuse_getattr_in input argument of GETATTR + */ #include #include @@ -15,7 +22,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 8 +#define FUSE_KERNEL_MINOR_VERSION 9 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -91,12 +98,18 @@ struct fuse_file_lock { */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) +#define FUSE_FILE_OPS (1 << 2) /** * Release flags */ #define FUSE_RELEASE_FLUSH (1 << 0) +/** + * Getattr flags + */ +#define FUSE_GETATTR_FH (1 << 0) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ @@ -154,6 +167,12 @@ struct fuse_forget_in { __u64 nlookup; }; +struct fuse_getattr_in { + __u32 getattr_flags; + __u32 dummy; + __u64 fh; +}; + struct fuse_attr_out { __u64 attr_valid; /* Cache timeout for the attributes */ __u32 attr_valid_nsec;