Commit 2f1e8196 authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: allow fine grained attr cache invaldation

This patch adds the infrastructure for more fine grained attribute
invalidation.  Currently only 'atime' is invalidated separately.

The use of this infrastructure is extended to the statx(2) interface, which
for now means that if only 'atime' is invalid and STATX_ATIME is not
specified in the mask argument, then no GETATTR request will be generated.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent edfa8728
...@@ -81,13 +81,18 @@ u64 entry_attr_timeout(struct fuse_entry_out *o) ...@@ -81,13 +81,18 @@ u64 entry_attr_timeout(struct fuse_entry_out *o)
return time_to_jiffies(o->attr_valid, o->attr_valid_nsec); return time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
} }
static void fuse_invalidate_attr_mask(struct inode *inode, u32 mask)
{
set_mask_bits(&get_fuse_inode(inode)->inval_mask, 0, mask);
}
/* /*
* Mark the attributes as stale, so that at the next call to * Mark the attributes as stale, so that at the next call to
* ->getattr() they will be fetched from userspace * ->getattr() they will be fetched from userspace
*/ */
void fuse_invalidate_attr(struct inode *inode) void fuse_invalidate_attr(struct inode *inode)
{ {
get_fuse_inode(inode)->i_time = 0; fuse_invalidate_attr_mask(inode, STATX_BASIC_STATS);
} }
static void fuse_dir_changed(struct inode *dir) static void fuse_dir_changed(struct inode *dir)
...@@ -103,7 +108,7 @@ static void fuse_dir_changed(struct inode *dir) ...@@ -103,7 +108,7 @@ static void fuse_dir_changed(struct inode *dir)
void fuse_invalidate_atime(struct inode *inode) void fuse_invalidate_atime(struct inode *inode)
{ {
if (!IS_RDONLY(inode)) if (!IS_RDONLY(inode))
fuse_invalidate_attr(inode); fuse_invalidate_attr_mask(inode, STATX_ATIME);
} }
/* /*
...@@ -917,7 +922,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, ...@@ -917,7 +922,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
} }
static int fuse_update_get_attr(struct inode *inode, struct file *file, static int fuse_update_get_attr(struct inode *inode, struct file *file,
struct kstat *stat, unsigned int flags) struct kstat *stat, u32 request_mask,
unsigned int flags)
{ {
struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_inode *fi = get_fuse_inode(inode);
int err = 0; int err = 0;
...@@ -927,6 +933,8 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, ...@@ -927,6 +933,8 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
sync = true; sync = true;
else if (flags & AT_STATX_DONT_SYNC) else if (flags & AT_STATX_DONT_SYNC)
sync = false; sync = false;
else if (request_mask & READ_ONCE(fi->inval_mask))
sync = true;
else else
sync = time_before64(fi->i_time, get_jiffies_64()); sync = time_before64(fi->i_time, get_jiffies_64());
...@@ -944,7 +952,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file, ...@@ -944,7 +952,7 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
int fuse_update_attributes(struct inode *inode, struct file *file) int fuse_update_attributes(struct inode *inode, struct file *file)
{ {
return fuse_update_get_attr(inode, file, NULL, 0); return fuse_update_get_attr(inode, file, NULL, STATX_BASIC_STATS, 0);
} }
int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid,
...@@ -1566,7 +1574,7 @@ static int fuse_getattr(const struct path *path, struct kstat *stat, ...@@ -1566,7 +1574,7 @@ static int fuse_getattr(const struct path *path, struct kstat *stat,
if (!fuse_allow_current_process(fc)) if (!fuse_allow_current_process(fc))
return -EACCES; return -EACCES;
return fuse_update_get_attr(inode, NULL, stat, flags); return fuse_update_get_attr(inode, NULL, stat, request_mask, flags);
} }
static const struct inode_operations fuse_dir_inode_operations = { static const struct inode_operations fuse_dir_inode_operations = {
......
...@@ -80,6 +80,9 @@ struct fuse_inode { ...@@ -80,6 +80,9 @@ struct fuse_inode {
/** Time in jiffies until the file attributes are valid */ /** Time in jiffies until the file attributes are valid */
u64 i_time; u64 i_time;
/* Which attributes are invalid */
u32 inval_mask;
/** The sticky bit in inode->i_mode may have been removed, so /** The sticky bit in inode->i_mode may have been removed, so
preserve the original mode */ preserve the original mode */
umode_t orig_i_mode; umode_t orig_i_mode;
......
...@@ -90,6 +90,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) ...@@ -90,6 +90,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
fi = get_fuse_inode(inode); fi = get_fuse_inode(inode);
fi->i_time = 0; fi->i_time = 0;
fi->inval_mask = 0;
fi->nodeid = 0; fi->nodeid = 0;
fi->nlookup = 0; fi->nlookup = 0;
fi->attr_version = 0; fi->attr_version = 0;
...@@ -164,6 +165,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, ...@@ -164,6 +165,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
fi->attr_version = ++fc->attr_version; fi->attr_version = ++fc->attr_version;
fi->i_time = attr_valid; fi->i_time = attr_valid;
WRITE_ONCE(fi->inval_mask, 0);
inode->i_ino = fuse_squash_ino(attr->ino); inode->i_ino = fuse_squash_ino(attr->ino);
inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment