Lock tmpfs node tn_status updates done under the shared vnode lock.

If tmpfs vnode is only shared locked, tn_status field still needs
updates to note the access time modification.  Use the same locking
scheme as for UFS, protect tn_status with the node interlock + shared
vnode lock.

Fix nearby style.

Noted and reviewed by:	mjg
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2017-01-06 17:43:36 +00:00
parent 305b422966
commit 5dc1128656
4 changed files with 54 additions and 28 deletions

View File

@ -199,7 +199,9 @@ struct tmpfs_node {
* allocated for it or it has been reclaimed). */
struct vnode * tn_vnode;
/* interlock to protect tn_vpstate */
/* Interlock to protect tn_vpstate, and tn_status under shared
* vnode lock.
*/
struct mtx tn_interlock;
/* Identify if current node has vnode assiocate with
@ -420,6 +422,7 @@ int tmpfs_chtimes(struct vnode *, struct vattr *, struct ucred *cred,
void tmpfs_itimes(struct vnode *, const struct timespec *,
const struct timespec *);
void tmpfs_set_status(struct tmpfs_node *node, int status);
void tmpfs_update(struct vnode *);
int tmpfs_truncate(struct vnode *, off_t);

View File

@ -52,11 +52,11 @@ static int
tmpfs_fifo_close(struct vop_close_args *v)
{
struct tmpfs_node *node;
node = VP_TO_TMPFS_NODE(v->a_vp);
node->tn_status |= TMPFS_NODE_ACCESSED;
node = VP_TO_TMPFS_NODE(v->a_vp);
tmpfs_set_status(node, TMPFS_NODE_ACCESSED);
tmpfs_update(v->a_vp);
return fifo_specops.vop_close(v);
return (fifo_specops.vop_close(v));
}
/*

View File

@ -1092,9 +1092,9 @@ tmpfs_dir_getdotdent(struct tmpfs_node *node, struct uio *uio)
else
error = uiomove(&dent, dent.d_reclen, uio);
node->tn_status |= TMPFS_NODE_ACCESSED;
tmpfs_set_status(node, TMPFS_NODE_ACCESSED);
return error;
return (error);
}
/*
@ -1137,9 +1137,9 @@ tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio)
else
error = uiomove(&dent, dent.d_reclen, uio);
node->tn_status |= TMPFS_NODE_ACCESSED;
tmpfs_set_status(node, TMPFS_NODE_ACCESSED);
return error;
return (error);
}
/*
@ -1282,7 +1282,7 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int maxcookies,
node->tn_dir.tn_readdir_lastn = off;
node->tn_dir.tn_readdir_lastp = de;
node->tn_status |= TMPFS_NODE_ACCESSED;
tmpfs_set_status(node, TMPFS_NODE_ACCESSED);
return error;
}
@ -1735,15 +1735,25 @@ tmpfs_chtimes(struct vnode *vp, struct vattr *vap,
return (0);
}
/* Sync timestamps */
void
tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
tmpfs_set_status(struct tmpfs_node *node, int status)
{
if ((node->tn_status & status) == status)
return;
TMPFS_NODE_LOCK(node);
node->tn_status |= status;
TMPFS_NODE_UNLOCK(node);
}
/* Sync timestamps */
static void
tmpfs_itimes_locked(struct tmpfs_node *node, const struct timespec *acc,
const struct timespec *mod)
{
struct tmpfs_node *node;
struct timespec now;
node = VP_TO_TMPFS_NODE(vp);
TMPFS_ASSERT_LOCKED(node);
if ((node->tn_status & (TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
TMPFS_NODE_CHANGED)) == 0)
@ -1760,11 +1770,25 @@ tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
mod = &now;
node->tn_mtime = *mod;
}
if (node->tn_status & TMPFS_NODE_CHANGED) {
if (node->tn_status & TMPFS_NODE_CHANGED)
node->tn_ctime = now;
}
node->tn_status &=
~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | TMPFS_NODE_CHANGED);
node->tn_status &= ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
TMPFS_NODE_CHANGED);
}
void
tmpfs_itimes(struct vnode *vp, const struct timespec *acc,
const struct timespec *mod)
{
struct tmpfs_node *node;
ASSERT_VOP_LOCKED(vp, "tmpfs_itimes");
node = VP_TO_TMPFS_NODE(vp);
TMPFS_NODE_LOCK(node);
tmpfs_itimes_locked(node, acc, mod);
TMPFS_NODE_UNLOCK(node);
/* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */
random_harvest_queue(node, sizeof(*node), 1, RANDOM_FS_ATIME);
}
@ -1798,14 +1822,13 @@ tmpfs_truncate(struct vnode *vp, off_t length)
return (EFBIG);
error = tmpfs_reg_resize(vp, length, FALSE);
if (error == 0) {
if (error == 0)
node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
}
out:
tmpfs_update(vp);
return error;
return (error);
}
static __inline int

View File

@ -445,7 +445,7 @@ tmpfs_read(struct vop_read_args *v)
if (uio->uio_offset < 0)
return (EINVAL);
node = VP_TO_TMPFS_NODE(vp);
node->tn_status |= TMPFS_NODE_ACCESSED;
tmpfs_set_status(node, TMPFS_NODE_ACCESSED);
return (uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio));
}
@ -1082,8 +1082,8 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
v->a_cnp->cn_namelen));
/* Check flags to see if we are allowed to remove the directory. */
if (dnode->tn_flags & APPEND
|| node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) {
if ((dnode->tn_flags & APPEND) != 0 ||
(node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) != 0) {
error = EPERM;
goto out;
}
@ -1099,7 +1099,7 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
TMPFS_ASSERT_ELOCKED(node);
node->tn_links--;
node->tn_dir.tn_parent = NULL;
node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \
node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
TMPFS_NODE_MODIFIED;
TMPFS_NODE_UNLOCK(node);
@ -1107,8 +1107,8 @@ tmpfs_rmdir(struct vop_rmdir_args *v)
TMPFS_NODE_LOCK(dnode);
TMPFS_ASSERT_ELOCKED(dnode);
dnode->tn_links--;
dnode->tn_status |= TMPFS_NODE_ACCESSED | \
TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED;
dnode->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED |
TMPFS_NODE_MODIFIED;
TMPFS_NODE_UNLOCK(dnode);
cache_purge(dvp);
@ -1220,9 +1220,9 @@ tmpfs_readlink(struct vop_readlink_args *v)
error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid),
uio);
node->tn_status |= TMPFS_NODE_ACCESSED;
tmpfs_set_status(node, TMPFS_NODE_ACCESSED);
return error;
return (error);
}
static int