diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 61 |
1 files changed, 31 insertions, 30 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 29fef75f236..9ee2a6bbfa3 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -663,7 +663,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, return err; } -int fuse_do_getattr(struct inode *inode) +static int fuse_do_getattr(struct inode *inode) { int err; struct fuse_attr_out arg; @@ -723,30 +723,6 @@ static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task) return 0; } -/* - * Check whether the inode attributes are still valid - * - * If the attribute validity timeout has expired, then fetch the fresh - * attributes with a 'getattr' request - * - * I'm not sure why cached attributes are never returned for the root - * inode, this is probably being too cautious. - */ -static int fuse_revalidate(struct dentry *entry) -{ - struct inode *inode = entry->d_inode; - struct fuse_inode *fi = get_fuse_inode(inode); - struct fuse_conn *fc = get_fuse_conn(inode); - - if (!fuse_allow_task(fc, current)) - return -EACCES; - if (get_node_id(inode) != FUSE_ROOT_ID && - fi->i_time >= get_jiffies_64()) - return 0; - - return fuse_do_getattr(inode); -} - static int fuse_access(struct inode *inode, int mask) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -794,16 +770,33 @@ static int fuse_access(struct inode *inode, int mask) static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_inode *fi = get_fuse_inode(inode); + bool refreshed = false; + int err = 0; if (!fuse_allow_task(fc, current)) return -EACCES; - else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { + + /* + * If attributes are needed, but are stale, refresh them + * before proceeding + */ + if (((fc->flags & FUSE_DEFAULT_PERMISSIONS) || (mask & MAY_EXEC)) && + fi->i_time < get_jiffies_64()) { + err = fuse_do_getattr(inode); + if (err) + return err; + + refreshed = true; + } + + if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { int err = generic_permission(inode, mask, NULL); /* If permission is denied, try to refresh file attributes. This is also needed, because the root node will at first have no permissions */ - if (err == -EACCES) { + if (err == -EACCES && !refreshed) { err = fuse_do_getattr(inode); if (!err) err = generic_permission(inode, mask, NULL); @@ -814,7 +807,6 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) noticed immediately, only after the attribute timeout has expired */ - return err; } else { int mode = inode->i_mode; if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO)) @@ -822,8 +814,8 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) return fuse_access(inode, mask); - return 0; } + return err; } static int parse_dirfile(char *buf, size_t nbytes, struct file *file, @@ -1052,7 +1044,16 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat) { struct inode *inode = entry->d_inode; - int err = fuse_revalidate(entry); + struct fuse_inode *fi = get_fuse_inode(inode); + struct fuse_conn *fc = get_fuse_conn(inode); + int err = 0; + + if (!fuse_allow_task(fc, current)) + return -EACCES; + + if (fi->i_time < get_jiffies_64()) + err = fuse_do_getattr(inode); + if (!err) generic_fillattr(inode, stat); |