summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2007-10-16 23:31:02 -0700
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-17 08:43:04 -0700
commit244f6385c2891e366a7de5f6746ccc257efd8952 (patch)
tree09d51e0f55d9e88dad48941cc0a63e0253306e47
parent074406fa6309ab8b0aca15496b16b3653e58c03d (diff)
downloadlinux-244f6385c2891e366a7de5f6746ccc257efd8952.tar.gz
linux-244f6385c2891e366a7de5f6746ccc257efd8952.tar.bz2
linux-244f6385c2891e366a7de5f6746ccc257efd8952.zip
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>
-rw-r--r--fs/fuse/dir.c61
-rw-r--r--fs/fuse/file.c8
-rw-r--r--fs/fuse/fuse_i.h5
3 files changed, 31 insertions, 43 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);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index fb1713e76756..f3ef2bde983b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -106,14 +106,6 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir)
if (err)
return err;
- /* If opening the root node, no lookup has been performed on
- it, so the attributes must be refreshed */
- if (get_node_id(inode) == FUSE_ROOT_ID) {
- err = fuse_do_getattr(inode);
- if (err)
- return err;
- }
-
ff = fuse_file_alloc();
if (!ff)
return -ENOMEM;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 60683b787250..e0555d68b4a7 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -533,11 +533,6 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
void fuse_abort_conn(struct fuse_conn *fc);
/**
- * Get the attributes of a file
- */
-int fuse_do_getattr(struct inode *inode);
-
-/**
* Invalidate inode attributes
*/
void fuse_invalidate_attr(struct inode *inode);