Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 4 Feb 2020 19:03:38 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r357514 - head/sys/vm
Message-ID:  <202002041903.014J3cIZ040033@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Tue Feb  4 19:03:37 2020
New Revision: 357514
URL: https://svnweb.freebsd.org/changeset/base/357514

Log:
  Enable vm_object_mightbedirty() and vm_object_page_clean() for swap
  objects backing tmpfs vnodes data.
  
  The clean scan is limited to only remove write permissions from the
  mapped pages of the objects.  This fixes the issue that tmpfs vnode
  mtime is not updated from writes to the mmaped area after the initial
  page-in.
  
  Noted by:	mjg
  Reviewed by:	markj
  Discussed with:	jeff
  Tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week
  Differential revision:	https://reviews.freebsd.org/D23432

Modified:
  head/sys/vm/vm_object.c
  head/sys/vm/vm_object.h

Modified: head/sys/vm/vm_object.c
==============================================================================
--- head/sys/vm/vm_object.c	Tue Feb  4 19:01:17 2020	(r357513)
+++ head/sys/vm/vm_object.c	Tue Feb  4 19:03:37 2020	(r357514)
@@ -1017,6 +1017,10 @@ vm_object_page_remove_write(vm_page_t p, int flags, bo
  *	write out pages with PGA_NOSYNC set (originally comes from MAP_NOSYNC),
  *	leaving the object dirty.
  *
+ *	For swap objects backing tmpfs regular files, do not flush anything,
+ *	but remove write protection on the mapped pages to update mtime through
+ *	mmaped writes.
+ *
  *	When stuffing pages asynchronously, allow clustering.  XXX we need a
  *	synchronous clustering mode implementation.
  *
@@ -1038,8 +1042,7 @@ vm_object_page_clean(vm_object_t object, vm_ooffset_t 
 
 	VM_OBJECT_ASSERT_WLOCKED(object);
 
-	if (object->type != OBJT_VNODE || !vm_object_mightbedirty(object) ||
-	    object->resident_page_count == 0)
+	if (!vm_object_mightbedirty(object) || object->resident_page_count == 0)
 		return (TRUE);
 
 	pagerflags = (flags & (OBJPC_SYNC | OBJPC_INVAL)) != 0 ?
@@ -1072,32 +1075,36 @@ rescan:
 			vm_page_xunbusy(p);
 			continue;
 		}
+		if (object->type == OBJT_VNODE) {
+			n = vm_object_page_collect_flush(object, p, pagerflags,
+			    flags, &allclean, &eio);
+			if (eio) {
+				res = FALSE;
+				allclean = FALSE;
+			}
+			if (object->generation != curgeneration &&
+			    (flags & OBJPC_SYNC) != 0)
+				goto rescan;
 
-		n = vm_object_page_collect_flush(object, p, pagerflags,
-		    flags, &allclean, &eio);
-		if (eio) {
-			res = FALSE;
-			allclean = FALSE;
-		}
-		if (object->generation != curgeneration &&
-		    (flags & OBJPC_SYNC) != 0)
-			goto rescan;
-
-		/*
-		 * If the VOP_PUTPAGES() did a truncated write, so
-		 * that even the first page of the run is not fully
-		 * written, vm_pageout_flush() returns 0 as the run
-		 * length.  Since the condition that caused truncated
-		 * write may be permanent, e.g. exhausted free space,
-		 * accepting n == 0 would cause an infinite loop.
-		 *
-		 * Forwarding the iterator leaves the unwritten page
-		 * behind, but there is not much we can do there if
-		 * filesystem refuses to write it.
-		 */
-		if (n == 0) {
+			/*
+			 * If the VOP_PUTPAGES() did a truncated write, so
+			 * that even the first page of the run is not fully
+			 * written, vm_pageout_flush() returns 0 as the run
+			 * length.  Since the condition that caused truncated
+			 * write may be permanent, e.g. exhausted free space,
+			 * accepting n == 0 would cause an infinite loop.
+			 *
+			 * Forwarding the iterator leaves the unwritten page
+			 * behind, but there is not much we can do there if
+			 * filesystem refuses to write it.
+			 */
+			if (n == 0) {
+				n = 1;
+				allclean = FALSE;
+			}
+		} else {
 			n = 1;
-			allclean = FALSE;
+			vm_page_xunbusy(p);
 		}
 		np = vm_page_find_least(object, pi + n);
 	}
@@ -1105,7 +1112,12 @@ rescan:
 	VOP_FSYNC(vp, (pagerflags & VM_PAGER_PUT_SYNC) ? MNT_WAIT : 0);
 #endif
 
-	if (allclean)
+	/*
+	 * Leave updating cleangeneration for tmpfs objects to tmpfs
+	 * scan.  It needs to update mtime, which happens for other
+	 * filesystems during page writeouts.
+	 */
+	if (allclean && object->type == OBJT_VNODE)
 		object->cleangeneration = curgeneration;
 	return (res);
 }

Modified: head/sys/vm/vm_object.h
==============================================================================
--- head/sys/vm/vm_object.h	Tue Feb  4 19:01:17 2020	(r357513)
+++ head/sys/vm/vm_object.h	Tue Feb  4 19:03:37 2020	(r357514)
@@ -322,8 +322,15 @@ static __inline bool
 vm_object_mightbedirty(vm_object_t object)
 {
 
-	return (object->type == OBJT_VNODE &&
-	    object->generation != object->cleangeneration);
+	if (object->type != OBJT_VNODE) {
+		if ((object->flags & OBJ_TMPFS_NODE) == 0)
+			return (false);
+#ifdef KASSERT
+		KASSERT(object->type == OBJT_SWAP,
+		    ("TMPFS_NODE obj %p is not swap", object));
+#endif
+	}
+	return (object->generation != object->cleangeneration);
 }
 
 void vm_object_clear_flag(vm_object_t object, u_short bits);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202002041903.014J3cIZ040033>