tmpfs: restore atime updates for reads from page cache.
Split TMPFS_NODE_ACCCESSED bit into dedicated byte that can be updated atomically without locks or (locked) atomics. tn_update_getattr() change also contains unrelated bug fix. Reported by: lwhsu PR: 249362 Reviewed by: markj (previous version) Discussed with: mjg Sponsored by: The FreeBSD Foundation Differential revision: https://reviews.freebsd.org/D26451
This commit is contained in:
parent
23f9071466
commit
016b7c7e39
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=365810
@ -173,11 +173,13 @@ struct tmpfs_node {
|
|||||||
* Node's internal status. This is used by several file system
|
* Node's internal status. This is used by several file system
|
||||||
* operations to do modifications to the node in a delayed
|
* operations to do modifications to the node in a delayed
|
||||||
* fashion.
|
* fashion.
|
||||||
|
*
|
||||||
|
* tn_accessed has a dedicated byte to allow update by store without
|
||||||
|
* using atomics. This provides a micro-optimization to e.g.
|
||||||
|
* tmpfs_read_pgcache().
|
||||||
*/
|
*/
|
||||||
int tn_status; /* (vi) */
|
uint8_t tn_status; /* (vi) */
|
||||||
#define TMPFS_NODE_ACCESSED (1 << 1)
|
uint8_t tn_accessed; /* unlocked */
|
||||||
#define TMPFS_NODE_MODIFIED (1 << 2)
|
|
||||||
#define TMPFS_NODE_CHANGED (1 << 3)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The node size. It does not necessarily match the real amount
|
* The node size. It does not necessarily match the real amount
|
||||||
@ -317,11 +319,16 @@ LIST_HEAD(tmpfs_node_list, tmpfs_node);
|
|||||||
#define TMPFS_ASSERT_LOCKED(node) (void)0
|
#define TMPFS_ASSERT_LOCKED(node) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* tn_vpstate */
|
||||||
#define TMPFS_VNODE_ALLOCATING 1
|
#define TMPFS_VNODE_ALLOCATING 1
|
||||||
#define TMPFS_VNODE_WANT 2
|
#define TMPFS_VNODE_WANT 2
|
||||||
#define TMPFS_VNODE_DOOMED 4
|
#define TMPFS_VNODE_DOOMED 4
|
||||||
#define TMPFS_VNODE_WRECLAIM 8
|
#define TMPFS_VNODE_WRECLAIM 8
|
||||||
|
|
||||||
|
/* tn_status */
|
||||||
|
#define TMPFS_NODE_MODIFIED 0x01
|
||||||
|
#define TMPFS_NODE_CHANGED 0x02
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal representation of a tmpfs mount point.
|
* Internal representation of a tmpfs mount point.
|
||||||
*/
|
*/
|
||||||
@ -452,6 +459,7 @@ int tmpfs_chtimes(struct vnode *, struct vattr *, struct ucred *cred,
|
|||||||
void tmpfs_itimes(struct vnode *, const struct timespec *,
|
void tmpfs_itimes(struct vnode *, const struct timespec *,
|
||||||
const struct timespec *);
|
const struct timespec *);
|
||||||
|
|
||||||
|
void tmpfs_set_accessed(struct tmpfs_mount *tm, struct tmpfs_node *node);
|
||||||
void tmpfs_set_status(struct tmpfs_mount *tm, struct tmpfs_node *node,
|
void tmpfs_set_status(struct tmpfs_mount *tm, struct tmpfs_node *node,
|
||||||
int status);
|
int status);
|
||||||
int tmpfs_truncate(struct vnode *, off_t);
|
int tmpfs_truncate(struct vnode *, off_t);
|
||||||
@ -551,12 +559,10 @@ static inline void
|
|||||||
tmpfs_update_getattr(struct vnode *vp)
|
tmpfs_update_getattr(struct vnode *vp)
|
||||||
{
|
{
|
||||||
struct tmpfs_node *node;
|
struct tmpfs_node *node;
|
||||||
int update_flags;
|
|
||||||
|
|
||||||
update_flags = TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED;
|
|
||||||
|
|
||||||
node = VP_TO_TMPFS_NODE(vp);
|
node = VP_TO_TMPFS_NODE(vp);
|
||||||
if (__predict_false(node->tn_status & update_flags) != 0)
|
if (__predict_false((node->tn_status & (TMPFS_NODE_MODIFIED |
|
||||||
|
TMPFS_NODE_CHANGED)) != 0 || node->tn_accessed))
|
||||||
tmpfs_update(vp);
|
tmpfs_update(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,8 +56,7 @@ tmpfs_fifo_close(struct vop_close_args *v)
|
|||||||
struct tmpfs_node *node;
|
struct tmpfs_node *node;
|
||||||
|
|
||||||
node = VP_TO_TMPFS_NODE(v->a_vp);
|
node = VP_TO_TMPFS_NODE(v->a_vp);
|
||||||
tmpfs_set_status(VFS_TO_TMPFS(v->a_vp->v_mount), node,
|
tmpfs_set_accessed(VFS_TO_TMPFS(v->a_vp->v_mount), node);
|
||||||
TMPFS_NODE_ACCESSED);
|
|
||||||
tmpfs_update(v->a_vp);
|
tmpfs_update(v->a_vp);
|
||||||
return (fifo_specops.vop_close(v));
|
return (fifo_specops.vop_close(v));
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ tmpfs_node_ctor(void *mem, int size, void *arg, int flags)
|
|||||||
node->tn_gen++;
|
node->tn_gen++;
|
||||||
node->tn_size = 0;
|
node->tn_size = 0;
|
||||||
node->tn_status = 0;
|
node->tn_status = 0;
|
||||||
|
node->tn_accessed = false;
|
||||||
node->tn_flags = 0;
|
node->tn_flags = 0;
|
||||||
node->tn_links = 0;
|
node->tn_links = 0;
|
||||||
node->tn_vnode = NULL;
|
node->tn_vnode = NULL;
|
||||||
@ -1098,8 +1099,8 @@ tmpfs_dir_attach(struct vnode *vp, struct tmpfs_dirent *de)
|
|||||||
tmpfs_dir_attach_dup(dnode, &xde->ud.td_duphead, de);
|
tmpfs_dir_attach_dup(dnode, &xde->ud.td_duphead, de);
|
||||||
}
|
}
|
||||||
dnode->tn_size += sizeof(struct tmpfs_dirent);
|
dnode->tn_size += sizeof(struct tmpfs_dirent);
|
||||||
dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
|
dnode->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
|
||||||
TMPFS_NODE_MODIFIED;
|
dnode->tn_accessed = true;
|
||||||
tmpfs_update(vp);
|
tmpfs_update(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1145,8 +1146,8 @@ tmpfs_dir_detach(struct vnode *vp, struct tmpfs_dirent *de)
|
|||||||
RB_REMOVE(tmpfs_dir, head, de);
|
RB_REMOVE(tmpfs_dir, head, de);
|
||||||
|
|
||||||
dnode->tn_size -= sizeof(struct tmpfs_dirent);
|
dnode->tn_size -= sizeof(struct tmpfs_dirent);
|
||||||
dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
|
dnode->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
|
||||||
TMPFS_NODE_MODIFIED;
|
dnode->tn_accessed = true;
|
||||||
tmpfs_update(vp);
|
tmpfs_update(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1199,7 +1200,7 @@ tmpfs_dir_getdotdent(struct tmpfs_mount *tm, struct tmpfs_node *node,
|
|||||||
else
|
else
|
||||||
error = uiomove(&dent, dent.d_reclen, uio);
|
error = uiomove(&dent, dent.d_reclen, uio);
|
||||||
|
|
||||||
tmpfs_set_status(tm, node, TMPFS_NODE_ACCESSED);
|
tmpfs_set_accessed(tm, node);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -1246,7 +1247,7 @@ tmpfs_dir_getdotdotdent(struct tmpfs_mount *tm, struct tmpfs_node *node,
|
|||||||
else
|
else
|
||||||
error = uiomove(&dent, dent.d_reclen, uio);
|
error = uiomove(&dent, dent.d_reclen, uio);
|
||||||
|
|
||||||
tmpfs_set_status(tm, node, TMPFS_NODE_ACCESSED);
|
tmpfs_set_accessed(tm, node);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -1391,8 +1392,8 @@ tmpfs_dir_getdents(struct tmpfs_mount *tm, struct tmpfs_node *node,
|
|||||||
node->tn_dir.tn_readdir_lastn = off;
|
node->tn_dir.tn_readdir_lastn = off;
|
||||||
node->tn_dir.tn_readdir_lastp = de;
|
node->tn_dir.tn_readdir_lastp = de;
|
||||||
|
|
||||||
tmpfs_set_status(tm, node, TMPFS_NODE_ACCESSED);
|
tmpfs_set_accessed(tm, node);
|
||||||
return error;
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1833,7 +1834,7 @@ tmpfs_chtimes(struct vnode *vp, struct vattr *vap,
|
|||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
if (vap->va_atime.tv_sec != VNOVAL)
|
if (vap->va_atime.tv_sec != VNOVAL)
|
||||||
node->tn_status |= TMPFS_NODE_ACCESSED;
|
node->tn_accessed = true;
|
||||||
|
|
||||||
if (vap->va_mtime.tv_sec != VNOVAL)
|
if (vap->va_mtime.tv_sec != VNOVAL)
|
||||||
node->tn_status |= TMPFS_NODE_MODIFIED;
|
node->tn_status |= TMPFS_NODE_MODIFIED;
|
||||||
@ -1861,6 +1862,14 @@ tmpfs_set_status(struct tmpfs_mount *tm, struct tmpfs_node *node, int status)
|
|||||||
TMPFS_NODE_UNLOCK(node);
|
TMPFS_NODE_UNLOCK(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tmpfs_set_accessed(struct tmpfs_mount *tm, struct tmpfs_node *node)
|
||||||
|
{
|
||||||
|
if (node->tn_accessed || tm->tm_ronly)
|
||||||
|
return;
|
||||||
|
atomic_store_8(&node->tn_accessed, true);
|
||||||
|
}
|
||||||
|
|
||||||
/* Sync timestamps */
|
/* Sync timestamps */
|
||||||
void
|
void
|
||||||
tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
|
tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
|
||||||
@ -1872,13 +1881,13 @@ tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
|
|||||||
ASSERT_VOP_LOCKED(vp, "tmpfs_itimes");
|
ASSERT_VOP_LOCKED(vp, "tmpfs_itimes");
|
||||||
node = VP_TO_TMPFS_NODE(vp);
|
node = VP_TO_TMPFS_NODE(vp);
|
||||||
|
|
||||||
if ((node->tn_status & (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
|
if (!node->tn_accessed &&
|
||||||
TMPFS_NODE_CHANGED)) == 0)
|
(node->tn_status & (TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED)) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vfs_timestamp(&now);
|
vfs_timestamp(&now);
|
||||||
TMPFS_NODE_LOCK(node);
|
TMPFS_NODE_LOCK(node);
|
||||||
if (node->tn_status & TMPFS_NODE_ACCESSED) {
|
if (node->tn_accessed) {
|
||||||
if (acc == NULL)
|
if (acc == NULL)
|
||||||
acc = &now;
|
acc = &now;
|
||||||
node->tn_atime = *acc;
|
node->tn_atime = *acc;
|
||||||
@ -1890,8 +1899,8 @@ tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
|
|||||||
}
|
}
|
||||||
if (node->tn_status & TMPFS_NODE_CHANGED)
|
if (node->tn_status & TMPFS_NODE_CHANGED)
|
||||||
node->tn_ctime = now;
|
node->tn_ctime = now;
|
||||||
node->tn_status &= ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
|
node->tn_status &= ~(TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED);
|
||||||
TMPFS_NODE_CHANGED);
|
node->tn_accessed = false;
|
||||||
TMPFS_NODE_UNLOCK(node);
|
TMPFS_NODE_UNLOCK(node);
|
||||||
|
|
||||||
/* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
|
/* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
|
||||||
|
@ -586,7 +586,7 @@ tmpfs_read(struct vop_read_args *v)
|
|||||||
if (uio->uio_offset < 0)
|
if (uio->uio_offset < 0)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
node = VP_TO_TMPFS_NODE(vp);
|
node = VP_TO_TMPFS_NODE(vp);
|
||||||
tmpfs_set_status(VFS_TO_TMPFS(vp->v_mount), node, TMPFS_NODE_ACCESSED);
|
tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node);
|
||||||
return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio));
|
return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,6 +622,7 @@ tmpfs_read_pgcache(struct vop_read_pgcache_args *v)
|
|||||||
if (!VN_IS_DOOMED(vp)) {
|
if (!VN_IS_DOOMED(vp)) {
|
||||||
/* size cannot become shorter due to rangelock. */
|
/* size cannot become shorter due to rangelock. */
|
||||||
size = node->tn_size;
|
size = node->tn_size;
|
||||||
|
tmpfs_set_accessed(node->tn_reg.tn_tmp, node);
|
||||||
vfs_smr_exit();
|
vfs_smr_exit();
|
||||||
error = uiomove_object(object, size, v->a_uio);
|
error = uiomove_object(object, size, v->a_uio);
|
||||||
return (error);
|
return (error);
|
||||||
@ -667,8 +668,8 @@ tmpfs_write(struct vop_write_args *v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio);
|
error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio);
|
||||||
node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
|
node->tn_status |= TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED;
|
||||||
TMPFS_NODE_CHANGED;
|
node->tn_accessed = true;
|
||||||
if (node->tn_mode & (S_ISUID | S_ISGID)) {
|
if (node->tn_mode & (S_ISUID | S_ISGID)) {
|
||||||
if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) {
|
if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID)) {
|
||||||
newmode = node->tn_mode & ~(S_ISUID | S_ISGID);
|
newmode = node->tn_mode & ~(S_ISUID | S_ISGID);
|
||||||
@ -744,7 +745,8 @@ tmpfs_remove(struct vop_remove_args *v)
|
|||||||
* reclaimed. */
|
* reclaimed. */
|
||||||
tmpfs_free_dirent(tmp, de);
|
tmpfs_free_dirent(tmp, de);
|
||||||
|
|
||||||
node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED;
|
node->tn_status |= TMPFS_NODE_CHANGED;
|
||||||
|
node->tn_accessed = true;
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -1317,15 +1319,15 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
|
|||||||
TMPFS_NODE_LOCK(node);
|
TMPFS_NODE_LOCK(node);
|
||||||
node->tn_links--;
|
node->tn_links--;
|
||||||
node->tn_dir.tn_parent = NULL;
|
node->tn_dir.tn_parent = NULL;
|
||||||
node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
|
node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
|
||||||
TMPFS_NODE_MODIFIED;
|
node->tn_accessed = true;
|
||||||
|
|
||||||
TMPFS_NODE_UNLOCK(node);
|
TMPFS_NODE_UNLOCK(node);
|
||||||
|
|
||||||
TMPFS_NODE_LOCK(dnode);
|
TMPFS_NODE_LOCK(dnode);
|
||||||
dnode->tn_links--;
|
dnode->tn_links--;
|
||||||
dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
|
dnode->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
|
||||||
TMPFS_NODE_MODIFIED;
|
dnode->tn_accessed = true;
|
||||||
TMPFS_NODE_UNLOCK(dnode);
|
TMPFS_NODE_UNLOCK(dnode);
|
||||||
|
|
||||||
if (tmpfs_use_nc(dvp)) {
|
if (tmpfs_use_nc(dvp)) {
|
||||||
@ -1444,7 +1446,7 @@ tmpfs_readlink(struct vop_readlink_args *v)
|
|||||||
|
|
||||||
error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
|
error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
|
||||||
uio);
|
uio);
|
||||||
tmpfs_set_status(VFS_TO_TMPFS(vp->v_mount), node, TMPFS_NODE_ACCESSED);
|
tmpfs_set_accessed(VFS_TO_TMPFS(vp->v_mount), node);
|
||||||
|
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user