aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/fuse
diff options
context:
space:
mode:
authorAlan Somers <asomers@FreeBSD.org>2021-11-29 01:53:31 +0000
committerAlan Somers <asomers@FreeBSD.org>2021-12-14 22:15:53 +0000
commit0bade34633f997c22f5e4e0931df0d534f560a38 (patch)
tree8ce6983e469816891271229290a9d9d5a8df366f /sys/fs/fuse
parent000ce6dee1fa387d526762f8bc1946d13823312e (diff)
downloadsrc-0bade34633f997c22f5e4e0931df0d534f560a38.tar.gz
src-0bade34633f997c22f5e4e0931df0d534f560a38.zip
fusefs: update atime on reads when using cached attributes
When using cached attributes, whether or not the data cache is enabled, fusefs must update a file's atime whenever it reads from it, so long as it wasn't mounted with -o noatime. Update it in-kernel, and flush it to the server on close or during the next setattr operation. The downside is that close() will now frequently trigger a FUSE_SETATTR upcall. But if you care about performance, you should be using -o noatime anyway. Reviewed by: pfg Differential Revision: https://reviews.freebsd.org/D33145 (cherry picked from commit 91972cfcddf950d7a9c33df5a9171ada1805a144) fusefs: fix 32-bit build of the tests after 91972cfcddf (cherry picked from commit d109559ddbf7afe311c1f1795ece137071406db8)
Diffstat (limited to 'sys/fs/fuse')
-rw-r--r--sys/fs/fuse/fuse_internal.c11
-rw-r--r--sys/fs/fuse/fuse_io.c3
-rw-r--r--sys/fs/fuse/fuse_node.c12
-rw-r--r--sys/fs/fuse/fuse_node.h3
-rw-r--r--sys/fs/fuse/fuse_vnops.c10
5 files changed, 33 insertions, 6 deletions
diff --git a/sys/fs/fuse/fuse_internal.c b/sys/fs/fuse/fuse_internal.c
index ffa4a40095b2..403116593bd9 100644
--- a/sys/fs/fuse/fuse_internal.c
+++ b/sys/fs/fuse/fuse_internal.c
@@ -926,6 +926,7 @@ fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
struct fuse_getattr_in *fgai;
struct fuse_attr_out *fao;
off_t old_filesize = fvdat->cached_attrs.va_size;
+ struct timespec old_atime = fvdat->cached_attrs.va_atime;
struct timespec old_ctime = fvdat->cached_attrs.va_ctime;
struct timespec old_mtime = fvdat->cached_attrs.va_mtime;
enum vtype vtyp;
@@ -950,6 +951,10 @@ fuse_internal_do_getattr(struct vnode *vp, struct vattr *vap,
vtyp = IFTOVT(fao->attr.mode);
if (fvdat->flag & FN_SIZECHANGE)
fao->attr.size = old_filesize;
+ if (fvdat->flag & FN_ATIMECHANGE) {
+ fao->attr.atime = old_atime.tv_sec;
+ fao->attr.atimensec = old_atime.tv_nsec;
+ }
if (fvdat->flag & FN_CTIMECHANGE) {
fao->attr.ctime = old_ctime.tv_sec;
fao->attr.ctimensec = old_ctime.tv_nsec;
@@ -1209,6 +1214,10 @@ int fuse_internal_setattr(struct vnode *vp, struct vattr *vap,
fsai->valid |= FATTR_ATIME;
if (vap->va_vaflags & VA_UTIMES_NULL)
fsai->valid |= FATTR_ATIME_NOW;
+ } else if (fvdat->flag & FN_ATIMECHANGE) {
+ fsai->atime = fvdat->cached_attrs.va_atime.tv_sec;
+ fsai->atimensec = fvdat->cached_attrs.va_atime.tv_nsec;
+ fsai->valid |= FATTR_ATIME;
}
if (vap->va_mtime.tv_sec != VNOVAL) {
fsai->mtime = vap->va_mtime.tv_sec;
@@ -1257,7 +1266,7 @@ int fuse_internal_setattr(struct vnode *vp, struct vattr *vap,
}
if (err == 0) {
struct fuse_attr_out *fao = (struct fuse_attr_out*)fdi.answ;
- fuse_vnode_undirty_cached_timestamps(vp);
+ fuse_vnode_undirty_cached_timestamps(vp, true);
fuse_internal_cache_attrs(vp, &fao->attr, fao->attr_valid,
fao->attr_valid_nsec, NULL, false);
}
diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c
index a240217fcc08..78398a990d7d 100644
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -236,6 +236,7 @@ fuse_io_dispatch(struct vnode *vp, struct uio *uio, int ioflag,
switch (uio->uio_rw) {
case UIO_READ:
+ fuse_vnode_update(vp, FN_ATIMECHANGE);
if (directio) {
SDT_PROBE2(fusefs, , io, trace, 1,
"direct read of vnode");
@@ -616,7 +617,7 @@ retry:
fdisp_destroy(&fdi);
if (wrote_anything)
- fuse_vnode_undirty_cached_timestamps(vp);
+ fuse_vnode_undirty_cached_timestamps(vp, false);
return (err);
}
diff --git a/sys/fs/fuse/fuse_node.c b/sys/fs/fuse/fuse_node.c
index c8982c5a48a1..f74de2faa702 100644
--- a/sys/fs/fuse/fuse_node.c
+++ b/sys/fs/fuse/fuse_node.c
@@ -474,11 +474,13 @@ fuse_vnode_size(struct vnode *vp, off_t *filesize, struct ucred *cred,
}
void
-fuse_vnode_undirty_cached_timestamps(struct vnode *vp)
+fuse_vnode_undirty_cached_timestamps(struct vnode *vp, bool atime)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
fvdat->flag &= ~(FN_MTIMECHANGE | FN_CTIMECHANGE);
+ if (atime)
+ fvdat->flag &= ~FN_ATIMECHANGE;
}
/* Update a fuse file's cached timestamps */
@@ -486,7 +488,8 @@ void
fuse_vnode_update(struct vnode *vp, int flags)
{
struct fuse_vnode_data *fvdat = VTOFUD(vp);
- struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp));
+ struct mount *mp = vnode_mount(vp);
+ struct fuse_data *data = fuse_get_mpdata(mp);
struct timespec ts;
vfs_timestamp(&ts);
@@ -494,6 +497,11 @@ fuse_vnode_update(struct vnode *vp, int flags)
if (data->time_gran > 1)
ts.tv_nsec = rounddown(ts.tv_nsec, data->time_gran);
+ if (mp->mnt_flag & MNT_NOATIME)
+ flags &= ~FN_ATIMECHANGE;
+
+ if (flags & FN_ATIMECHANGE)
+ fvdat->cached_attrs.va_atime = ts;
if (flags & FN_MTIMECHANGE)
fvdat->cached_attrs.va_mtime = ts;
if (flags & FN_CTIMECHANGE)
diff --git a/sys/fs/fuse/fuse_node.h b/sys/fs/fuse/fuse_node.h
index 8f69ef9a08f3..3a33c57001dc 100644
--- a/sys/fs/fuse/fuse_node.h
+++ b/sys/fs/fuse/fuse_node.h
@@ -91,6 +91,7 @@
*/
#define FN_MTIMECHANGE 0x00000800
#define FN_CTIMECHANGE 0x00001000
+#define FN_ATIMECHANGE 0x00002000
struct fuse_vnode_data {
/** self **/
@@ -201,7 +202,7 @@ int fuse_vnode_savesize(struct vnode *vp, struct ucred *cred, pid_t pid);
int fuse_vnode_setsize(struct vnode *vp, off_t newsize, bool from_server);
-void fuse_vnode_undirty_cached_timestamps(struct vnode *vp);
+void fuse_vnode_undirty_cached_timestamps(struct vnode *vp, bool atime);
void fuse_vnode_update(struct vnode *vp, int flags);
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index 5630eeeb9e65..d0f4cae302c1 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -613,6 +613,7 @@ fuse_vnop_close(struct vop_close_args *ap)
int fflag = ap->a_fflag;
struct thread *td = ap->a_td;
pid_t pid = td->td_proc->p_pid;
+ struct fuse_vnode_data *fvdat = VTOFUD(vp);
int err = 0;
if (fuse_isdeadfs(vp))
@@ -623,8 +624,15 @@ fuse_vnop_close(struct vop_close_args *ap)
return 0;
err = fuse_flush(vp, cred, pid, fflag);
+ if (err == 0 && (fvdat->flag & FN_ATIMECHANGE)) {
+ struct vattr vap;
+
+ VATTR_NULL(&vap);
+ vap.va_atime = fvdat->cached_attrs.va_atime;
+ err = fuse_internal_setattr(vp, &vap, td, NULL);
+ }
/* TODO: close the file handle, if we're sure it's no longer used */
- if ((VTOFUD(vp)->flag & FN_SIZECHANGE) != 0) {
+ if ((fvdat->flag & FN_SIZECHANGE) != 0) {
fuse_vnode_savesize(vp, cred, td->td_proc->p_pid);
}
return err;