fuse: refresh stale attributes in fuse_permission()
fuse_permission() didn't refresh inode attributes before using them, even if
the validity has already expired.
Thanks to Junjiro Okajima for spotting this.
Also remove some old code to unconditionally refresh the attributes on the
root inode.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 29fef75..9ee2a6b 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -663,7 +663,7 @@
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 @@
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_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 @@
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 @@
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 @@
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);