summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-02-11 09:02:21 +0000
committerkib <kib@FreeBSD.org>2015-02-11 09:02:21 +0000
commit7ca5c317aee117a4f147780b44663907203afc11 (patch)
tree544d9b4141cc31e9d2012916d768135800fbd2ca
parentf5a4512544e1004f761b474f350ae4ebd61bb09c (diff)
downloadFreeBSD-src-7ca5c317aee117a4f147780b44663907203afc11.zip
FreeBSD-src-7ca5c317aee117a4f147780b44663907203afc11.tar.gz
MFC r277828:
Update mtime for tmpfs files modified through memory mapping. MFC r277969: Update both ctime and mtime for writes to tmpfs files. MFC r277972: Remove single-use boolean. MFC r278151: Remove duplicated assignment.
-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.c17
-rw-r--r--sys/vm/vm_fault.c6
-rw-r--r--sys/vm/vm_object.c7
-rw-r--r--sys/vm/vm_object.h1
7 files changed, 80 insertions, 12 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 fed5792..383b478 100644
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -1417,6 +1417,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;
+ 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 |
+ TMPFS_NODE_CHANGED;
+ }
+ 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 21b2821..7af143b 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>
@@ -417,11 +418,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..885f84c 100644
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/fs/tmpfs/tmpfs_vnops.c
@@ -453,7 +453,6 @@ tmpfs_write(struct vop_write_args *v)
struct tmpfs_node *node;
off_t oldsize;
int error, ioflag;
- boolean_t extended;
vp = v->a_vp;
uio = v->a_uio;
@@ -473,8 +472,7 @@ tmpfs_write(struct vop_write_args *v)
return (EFBIG);
if (vn_rlimit_fsize(vp, uio, uio->uio_td))
return (EFBIG);
- extended = uio->uio_offset + uio->uio_resid > node->tn_size;
- if (extended) {
+ if (uio->uio_offset + uio->uio_resid > node->tn_size) {
error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid,
FALSE);
if (error != 0)
@@ -483,7 +481,7 @@ tmpfs_write(struct vop_write_args *v)
error = uiomove_object(node->tn_reg.tn_aobj, node->tn_size, uio);
node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
- (extended ? TMPFS_NODE_CHANGED : 0);
+ TMPFS_NODE_CHANGED;
if (node->tn_mode & (S_ISUID | S_ISGID)) {
if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0))
node->tn_mode &= ~(S_ISUID | S_ISGID);
@@ -505,6 +503,7 @@ tmpfs_fsync(struct vop_fsync_args *v)
MPASS(VOP_ISLOCKED(vp));
+ tmpfs_check_mtime(vp);
tmpfs_update(vp);
return 0;
@@ -1222,16 +1221,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
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 3f3c62b..dfbc2bd 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -358,11 +358,13 @@ RetryFault:;
(fault_flags & (VM_FAULT_CHANGE_WIRING | VM_FAULT_DIRTY)) == 0 &&
/* avoid calling vm_object_set_writeable_dirty() */
((prot & VM_PROT_WRITE) == 0 ||
- fs.first_object->type != OBJT_VNODE ||
+ (fs.first_object->type != OBJT_VNODE &&
+ (fs.first_object->flags & OBJ_TMPFS_NODE) == 0) ||
(fs.first_object->flags & OBJ_MIGHTBEDIRTY) != 0)) {
VM_OBJECT_RLOCK(fs.first_object);
if ((prot & VM_PROT_WRITE) != 0 &&
- fs.first_object->type == OBJT_VNODE &&
+ (fs.first_object->type == OBJT_VNODE ||
+ (fs.first_object->flags & OBJ_TMPFS_NODE) != 0) &&
(fs.first_object->flags & OBJ_MIGHTBEDIRTY) == 0)
goto fast_failed;
m = vm_page_lookup(fs.first_object, fs.first_pindex);
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 40fcad6..9324fb2 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -2200,8 +2200,13 @@ vm_object_set_writeable_dirty(vm_object_t object)
{
VM_OBJECT_ASSERT_WLOCKED(object);
- if (object->type != OBJT_VNODE)
+ if (object->type != OBJT_VNODE) {
+ if ((object->flags & OBJ_TMPFS_NODE) != 0) {
+ KASSERT(object->type == OBJT_SWAP, ("non-swap tmpfs"));
+ vm_object_set_flag(object, OBJ_TMPFS_DIRTY);
+ }
return;
+ }
object->generation++;
if ((object->flags & OBJ_MIGHTBEDIRTY) != 0)
return;
diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h
index 48ba743..8f65b42 100644
--- a/sys/vm/vm_object.h
+++ b/sys/vm/vm_object.h
@@ -187,6 +187,7 @@ struct vm_object {
#define OBJ_PIPWNT 0x0040 /* paging in progress wanted */
#define OBJ_MIGHTBEDIRTY 0x0100 /* object might be dirty, only for vnode */
#define OBJ_TMPFS_NODE 0x0200 /* object belongs to tmpfs VREG node */
+#define OBJ_TMPFS_DIRTY 0x0400 /* dirty tmpfs obj */
#define OBJ_COLORED 0x1000 /* pg_color is defined */
#define OBJ_ONEMAPPING 0x2000 /* One USE (a single, non-forked) mapping flag */
#define OBJ_DISCONNECTWNT 0x4000 /* disconnect from vnode wanted */
OpenPOWER on IntegriCloud