summaryrefslogtreecommitdiff
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c61
1 files changed, 31 insertions, 30 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 29fef75f2360..9ee2a6bbfa37 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);