Skip to content

Commit

Permalink
fuse: add cache_mask
Browse files Browse the repository at this point in the history
If writeback_cache is enabled, then the size, mtime and ctime attributes of
regular files are always valid in the kernel's cache.  They are retrieved
from userspace only when the inode is freshly looked up.

Add a more generic "cache_mask", that indicates which attributes are
currently valid in cache.

This patch doesn't change behavior.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Miklos Szeredi committed Oct 28, 2021
1 parent 04d82db commit 4b52f05
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 9 deletions.
3 changes: 2 additions & 1 deletion fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1667,7 +1667,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
}

fuse_change_attributes_common(inode, &outarg.attr,
attr_timeout(&outarg));
attr_timeout(&outarg),
fuse_get_cache_mask(inode));
oldsize = inode->i_size;
/* see the comment in fuse_change_attributes() */
if (!is_wb || is_truncate)
Expand Down
4 changes: 3 additions & 1 deletion fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,9 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid, u64 attr_version);

void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid);
u64 attr_valid, u32 cache_mask);

u32 fuse_get_cache_mask(struct inode *inode);

/**
* Initialize the client device
Expand Down
31 changes: 24 additions & 7 deletions fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ static ino_t fuse_squash_ino(u64 ino64)
}

void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid)
u64 attr_valid, u32 cache_mask)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
Expand All @@ -184,9 +184,11 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
inode->i_atime.tv_sec = attr->atime;
inode->i_atime.tv_nsec = attr->atimensec;
/* mtime from server may be stale due to local buffered write */
if (!fc->writeback_cache || !S_ISREG(inode->i_mode)) {
if (!(cache_mask & STATX_MTIME)) {
inode->i_mtime.tv_sec = attr->mtime;
inode->i_mtime.tv_nsec = attr->mtimensec;
}
if (!(cache_mask & STATX_CTIME)) {
inode->i_ctime.tv_sec = attr->ctime;
inode->i_ctime.tv_nsec = attr->ctimensec;
}
Expand Down Expand Up @@ -218,12 +220,22 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
inode->i_flags &= ~S_NOSEC;
}

u32 fuse_get_cache_mask(struct inode *inode)
{
struct fuse_conn *fc = get_fuse_conn(inode);

if (!fc->writeback_cache || !S_ISREG(inode->i_mode))
return 0;

return STATX_MTIME | STATX_CTIME | STATX_SIZE;
}

void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid, u64 attr_version)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
bool is_wb = fc->writeback_cache && S_ISREG(inode->i_mode);
u32 cache_mask;
loff_t oldsize;
struct timespec64 old_mtime;

Expand All @@ -233,10 +245,15 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
* may update i_size. In these cases trust the cached value in the
* inode.
*/
if (is_wb) {
cache_mask = fuse_get_cache_mask(inode);
if (cache_mask & STATX_SIZE)
attr->size = i_size_read(inode);

if (cache_mask & STATX_MTIME) {
attr->mtime = inode->i_mtime.tv_sec;
attr->mtimensec = inode->i_mtime.tv_nsec;
}
if (cache_mask & STATX_CTIME) {
attr->ctime = inode->i_ctime.tv_sec;
attr->ctimensec = inode->i_ctime.tv_nsec;
}
Expand All @@ -248,19 +265,19 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
}

old_mtime = inode->i_mtime;
fuse_change_attributes_common(inode, attr, attr_valid);
fuse_change_attributes_common(inode, attr, attr_valid, cache_mask);

oldsize = inode->i_size;
/*
* In case of writeback_cache enabled, the cached writes beyond EOF
* extend local i_size without keeping userspace server in sync. So,
* attr->size coming from server can be stale. We cannot trust it.
*/
if (!is_wb)
if (!(cache_mask & STATX_SIZE))
i_size_write(inode, attr->size);
spin_unlock(&fi->lock);

if (!is_wb && S_ISREG(inode->i_mode)) {
if (!cache_mask && S_ISREG(inode->i_mode)) {
bool inval = false;

if (oldsize != attr->size) {
Expand Down

0 comments on commit 4b52f05

Please sign in to comment.