summaryrefslogtreecommitdiffstats
path: root/sys/fs/tmpfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/tmpfs')
-rw-r--r--sys/fs/tmpfs/tmpfs.h1
-rw-r--r--sys/fs/tmpfs/tmpfs_subr.c25
-rw-r--r--sys/fs/tmpfs/tmpfs_vfsops.c35
-rw-r--r--sys/fs/tmpfs/tmpfs_vnops.c11
4 files changed, 67 insertions, 5 deletions
diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h
index 445bf61..b077489 100644
--- a/sys/fs/tmpfs/tmpfs.h
+++ b/sys/fs/tmpfs/tmpfs.h
@@ -398,6 +398,7 @@ int tmpfs_alloc_vp(struct mount *, struct tmpfs_node *, int,
void tmpfs_free_vp(struct vnode *);
int tmpfs_alloc_file(struct vnode *, struct vnode **, struct vattr *,
struct componentname *, char *);
+void tmpfs_check_mtime(struct vnode *);
void tmpfs_dir_attach(struct vnode *, struct tmpfs_dirent *);
void tmpfs_dir_detach(struct vnode *, struct tmpfs_dirent *);
void tmpfs_dir_destroy(struct tmpfs_mount *, struct tmpfs_node *);
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c
index d0d9a15..c1930f1 100644
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -1415,6 +1415,31 @@ retry:
return (0);
}
+void
+tmpfs_check_mtime(struct vnode *vp)
+{
+ struct tmpfs_node *node;
+ struct vm_object *obj;
+
+ ASSERT_VOP_ELOCKED(vp, "check_mtime");
+ if (vp->v_type != VREG)
+ return;
+ node = VP_TO_TMPFS_NODE(vp);
+ obj = vp->v_object;
+ KASSERT((obj->flags & (OBJ_TMPFS_NODE | OBJ_TMPFS)) ==
+ (OBJ_TMPFS_NODE | OBJ_TMPFS), ("non-tmpfs obj"));
+ /* unlocked read */
+ if ((obj->flags & OBJ_TMPFS_DIRTY) != 0) {
+ VM_OBJECT_WLOCK(obj);
+ if ((obj->flags & OBJ_TMPFS_DIRTY) != 0) {
+ obj->flags &= ~OBJ_TMPFS_DIRTY;
+ node = VP_TO_TMPFS_NODE(vp);
+ node->tn_status |= TMPFS_NODE_MODIFIED;
+ }
+ VM_OBJECT_WUNLOCK(obj);
+ }
+}
+
/*
* Change flags of the given vnode.
* Caller should execute tmpfs_update on vp after a successful execution.
diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c
index fbd7a63..2942e5a 100644
--- a/sys/fs/tmpfs/tmpfs_vfsops.c
+++ b/sys/fs/tmpfs/tmpfs_vfsops.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/jail.h>
#include <sys/kernel.h>
+#include <sys/rwlock.h>
#include <sys/stat.h>
#include <sys/systm.h>
#include <sys/sysctl.h>
@@ -418,11 +419,45 @@ tmpfs_statfs(struct mount *mp, struct statfs *sbp)
static int
tmpfs_sync(struct mount *mp, int waitfor)
{
+ struct vnode *vp, *mvp;
+ struct vm_object *obj;
if (waitfor == MNT_SUSPEND) {
MNT_ILOCK(mp);
mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED;
MNT_IUNLOCK(mp);
+ } else if (waitfor == MNT_LAZY) {
+ /*
+ * Handle lazy updates of mtime from writes to mmaped
+ * regions. Use MNT_VNODE_FOREACH_ALL instead of
+ * MNT_VNODE_FOREACH_ACTIVE, since unmap of the
+ * tmpfs-backed vnode does not call vinactive(), due
+ * to vm object type is OBJT_SWAP.
+ */
+ MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {
+ if (vp->v_type != VREG) {
+ VI_UNLOCK(vp);
+ continue;
+ }
+ obj = vp->v_object;
+ KASSERT((obj->flags & (OBJ_TMPFS_NODE | OBJ_TMPFS)) ==
+ (OBJ_TMPFS_NODE | OBJ_TMPFS), ("non-tmpfs obj"));
+
+ /*
+ * Unlocked read, avoid taking vnode lock if
+ * not needed. Lost update will be handled on
+ * the next call.
+ */
+ if ((obj->flags & OBJ_TMPFS_DIRTY) == 0) {
+ VI_UNLOCK(vp);
+ continue;
+ }
+ if (vget(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK,
+ curthread) != 0)
+ continue;
+ tmpfs_check_mtime(vp);
+ vput(vp);
+ }
}
return (0);
}
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c
index c811b9a..65c5f82 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -505,6 +505,7 @@ tmpfs_fsync(struct vop_fsync_args *v)
MPASS(VOP_ISLOCKED(vp));
+ tmpfs_check_mtime(vp);
tmpfs_update(vp);
return 0;
@@ -1222,16 +1223,16 @@ tmpfs_readlink(struct vop_readlink_args *v)
static int
tmpfs_inactive(struct vop_inactive_args *v)
{
- struct vnode *vp = v->a_vp;
-
+ struct vnode *vp;
struct tmpfs_node *node;
+ vp = v->a_vp;
node = VP_TO_TMPFS_NODE(vp);
-
if (node->tn_links == 0)
vrecycle(vp);
-
- return 0;
+ else
+ tmpfs_check_mtime(vp);
+ return (0);
}
int
OpenPOWER on IntegriCloud