diff options
-rw-r--r-- | fs/fuse/dir.c | 14 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 7 | ||||
-rw-r--r-- | fs/fuse/inode.c | 25 | ||||
-rw-r--r-- | fs/fuse/readdir.c | 2 |
4 files changed, 40 insertions, 8 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index e7f63e60118c..3db9d26d341e 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -255,7 +255,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) goto invalid; forget_all_cached_acls(inode); - fuse_change_attributes(inode, &outarg.attr, + fuse_change_attributes(inode, &outarg.attr, NULL, ATTR_TIMEOUT(&outarg), attr_version); fuse_change_entry_timeout(entry, &outarg); @@ -1213,8 +1213,8 @@ static int fuse_do_statx(struct inode *inode, struct file *file, fuse_statx_to_attr(&outarg.stat, &attr); if ((sx->mask & STATX_BASIC_STATS) == STATX_BASIC_STATS) { - fuse_change_attributes(inode, &attr, ATTR_TIMEOUT(&outarg), - attr_version); + fuse_change_attributes(inode, &attr, &outarg.stat, + ATTR_TIMEOUT(&outarg), attr_version); } stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME); stat->btime.tv_sec = sx->btime.tv_sec; @@ -1261,7 +1261,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat, fuse_make_bad(inode); err = -EIO; } else { - fuse_change_attributes(inode, &outarg.attr, + fuse_change_attributes(inode, &outarg.attr, NULL, ATTR_TIMEOUT(&outarg), attr_version); if (stat) @@ -1316,6 +1316,10 @@ retry: generic_fillattr(&nop_mnt_idmap, inode, stat); stat->mode = fi->orig_i_mode; stat->ino = fi->orig_ino; + if (test_bit(FUSE_I_BTIME, &fi->state)) { + stat->btime = fi->i_btime; + stat->result_mask |= STATX_BTIME; + } } return err; @@ -1952,7 +1956,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, /* FIXME: clear I_DIRTY_SYNC? */ } - fuse_change_attributes_common(inode, &outarg.attr, + fuse_change_attributes_common(inode, &outarg.attr, NULL, ATTR_TIMEOUT(&outarg), fuse_get_cache_mask(inode)); oldsize = inode->i_size; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 43c7b58d8ab7..bf0b85d0b95c 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -88,6 +88,9 @@ struct fuse_inode { preserve the original mode */ umode_t orig_i_mode; + /* Cache birthtime */ + struct timespec64 i_btime; + /** 64 bit inode number */ u64 orig_ino; @@ -167,6 +170,8 @@ enum { FUSE_I_SIZE_UNSTABLE, /* Bad inode */ FUSE_I_BAD, + /* Has btime */ + FUSE_I_BTIME, }; struct fuse_conn; @@ -1064,9 +1069,11 @@ void fuse_init_symlink(struct inode *inode); * Change attributes of an inode */ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, + struct fuse_statx *sx, u64 attr_valid, u64 attr_version); void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, + struct fuse_statx *sx, u64 attr_valid, u32 cache_mask); u32 fuse_get_cache_mask(struct inode *inode); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 2a4d192502e7..d47606206ec3 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -163,6 +163,7 @@ static ino_t fuse_squash_ino(u64 ino64) } void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, + struct fuse_statx *sx, u64 attr_valid, u32 cache_mask) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -198,6 +199,25 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, inode->i_ctime.tv_sec = attr->ctime; inode->i_ctime.tv_nsec = attr->ctimensec; } + if (sx) { + /* Sanitize nsecs */ + sx->btime.tv_nsec = + min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1); + + /* + * Btime has been queried, cache is valid (whether or not btime + * is available or not) so clear STATX_BTIME from inval_mask. + * + * Availability of the btime attribute is indicated in + * FUSE_I_BTIME + */ + set_mask_bits(&fi->inval_mask, STATX_BTIME, 0); + if (sx->mask & STATX_BTIME) { + set_bit(FUSE_I_BTIME, &fi->state); + fi->i_btime.tv_sec = sx->btime.tv_sec; + fi->i_btime.tv_nsec = sx->btime.tv_nsec; + } + } if (attr->blksize != 0) inode->i_blkbits = ilog2(attr->blksize); @@ -237,6 +257,7 @@ u32 fuse_get_cache_mask(struct inode *inode) } void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, + struct fuse_statx *sx, u64 attr_valid, u64 attr_version) { struct fuse_conn *fc = get_fuse_conn(inode); @@ -271,7 +292,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, } old_mtime = inode->i_mtime; - fuse_change_attributes_common(inode, attr, attr_valid, cache_mask); + fuse_change_attributes_common(inode, attr, sx, attr_valid, cache_mask); oldsize = inode->i_size; /* @@ -409,7 +430,7 @@ done: spin_lock(&fi->lock); fi->nlookup++; spin_unlock(&fi->lock); - fuse_change_attributes(inode, attr, attr_valid, attr_version); + fuse_change_attributes(inode, attr, NULL, attr_valid, attr_version); return inode; } diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index c58447be5e4d..9e6d587b3e67 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -223,7 +223,7 @@ retry: spin_unlock(&fi->lock); forget_all_cached_acls(inode); - fuse_change_attributes(inode, &o->attr, + fuse_change_attributes(inode, &o->attr, NULL, ATTR_TIMEOUT(o), attr_version); /* |