svn commit: r365787 - head/sys/fs/tmpfs

Konstantin Belousov kib at FreeBSD.org
Tue Sep 15 22:19:17 UTC 2020


Author: kib
Date: Tue Sep 15 22:19:16 2020
New Revision: 365787
URL: https://svnweb.freebsd.org/changeset/base/365787

Log:
  Add tmpfs page cache read support.
  
  Or it could be explained as lockless (for vnode lock) reads.  Reads
  are performed from the node tn_obj object.  Tmpfs regular vnode object
  lifecycle is significantly different from the normal OBJT_VNODE: it is
  alive as far as ref_count > 0.
  
  Ensure liveness of the tmpfs VREG node and consequently v_object
  inside VOP_READ_PGCACHE by referencing tmpfs node in tmpfs_open().
  Provide custom tmpfs fo_close() method on file, to ensure that close
  is paired with open.
  
  Add tmpfs VOP_READ_PGCACHE that takes advantage of all tmpfs quirks.
  It is quite cheap in code size sense to support page-ins for read for
  tmpfs even if we do not own tmpfs vnode lock.  Also, we can handle
  holes in tmpfs node without additional efforts, and do not have
  limitation of the transfer size.
  
  Reviewed by:	markj
  Discussed with and benchmarked by:	mjg (previous version)
  Tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  Differential revision:	https://reviews.freebsd.org/D26346

Modified:
  head/sys/fs/tmpfs/tmpfs.h
  head/sys/fs/tmpfs/tmpfs_subr.c
  head/sys/fs/tmpfs/tmpfs_vfsops.c
  head/sys/fs/tmpfs/tmpfs_vnops.c

Modified: head/sys/fs/tmpfs/tmpfs.h
==============================================================================
--- head/sys/fs/tmpfs/tmpfs.h	Tue Sep 15 22:13:21 2020	(r365786)
+++ head/sys/fs/tmpfs/tmpfs.h	Tue Sep 15 22:19:16 2020	(r365787)
@@ -287,6 +287,7 @@ struct tmpfs_node {
 			 * a position within the file is accessed.
 			 */
 			vm_object_t		tn_aobj;	/* (c) */
+			struct tmpfs_mount	*tn_tmp;	/* (c) */
 		} tn_reg;
 	} tn_spec;	/* (v) */
 };
@@ -415,6 +416,7 @@ void	tmpfs_ref_node(struct tmpfs_node *node);
 int	tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount *, enum vtype,
 	    uid_t uid, gid_t gid, mode_t mode, struct tmpfs_node *,
 	    const char *, dev_t, struct tmpfs_node **);
+int	tmpfs_fo_close(struct file *fp, struct thread *td);
 void	tmpfs_free_node(struct tmpfs_mount *, struct tmpfs_node *);
 bool	tmpfs_free_node_locked(struct tmpfs_mount *, struct tmpfs_node *, bool);
 void	tmpfs_free_tmp(struct tmpfs_mount *);
@@ -557,6 +559,8 @@ tmpfs_update_getattr(struct vnode *vp)
 	if (__predict_false(node->tn_status & update_flags) != 0)
 		tmpfs_update(vp);
 }
+
+extern struct fileops tmpfs_fnops;
 
 #endif /* _KERNEL */
 

Modified: head/sys/fs/tmpfs/tmpfs_subr.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_subr.c	Tue Sep 15 22:13:21 2020	(r365786)
+++ head/sys/fs/tmpfs/tmpfs_subr.c	Tue Sep 15 22:19:16 2020	(r365787)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/random.h>
 #include <sys/refcount.h>
 #include <sys/rwlock.h>
+#include <sys/smr.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
@@ -340,6 +341,7 @@ tmpfs_alloc_node(struct mount *mp, struct tmpfs_mount 
 		/* OBJ_TMPFS is set together with the setting of vp->v_object */
 		vm_object_set_flag(obj, OBJ_TMPFS_NODE);
 		VM_OBJECT_WUNLOCK(obj);
+		nnode->tn_reg.tn_tmp = tmp;
 		break;
 
 	default:
@@ -697,6 +699,7 @@ loop:
 		vp->v_object = object;
 		object->un_pager.swp.swp_tmpfs = vp;
 		vm_object_set_flag(object, OBJ_TMPFS);
+		vp->v_irflag |= VIRF_PGREAD;
 		VI_UNLOCK(vp);
 		VM_OBJECT_WUNLOCK(object);
 		break;

Modified: head/sys/fs/tmpfs/tmpfs_vfsops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vfsops.c	Tue Sep 15 22:13:21 2020	(r365786)
+++ head/sys/fs/tmpfs/tmpfs_vfsops.c	Tue Sep 15 22:19:16 2020	(r365787)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/dirent.h>
+#include <sys/file.h>
 #include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/mount.h>
@@ -662,6 +663,8 @@ static int
 tmpfs_init(struct vfsconf *conf)
 {
 	tmpfs_subr_init();
+	memcpy(&tmpfs_fnops, &vnops, sizeof(struct fileops));
+	tmpfs_fnops.fo_close = tmpfs_fo_close;
 	return (0);
 }
 

Modified: head/sys/fs/tmpfs/tmpfs_vnops.c
==============================================================================
--- head/sys/fs/tmpfs/tmpfs_vnops.c	Tue Sep 15 22:13:21 2020	(r365786)
+++ head/sys/fs/tmpfs/tmpfs_vnops.c	Tue Sep 15 22:19:16 2020	(r365787)
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/dirent.h>
 #include <sys/fcntl.h>
+#include <sys/file.h>
 #include <sys/limits.h>
 #include <sys/lockf.h>
 #include <sys/lock.h>
@@ -276,22 +277,25 @@ tmpfs_mknod(struct vop_mknod_args *v)
 	return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 }
 
+struct fileops tmpfs_fnops;
+
 static int
 tmpfs_open(struct vop_open_args *v)
 {
-	struct vnode *vp = v->a_vp;
-	int mode = v->a_mode;
-
-	int error;
+	struct vnode *vp;
 	struct tmpfs_node *node;
+	struct file *fp;
+	int error, mode;
 
-	MPASS(VOP_ISLOCKED(vp));
-
+	vp = v->a_vp;
+	mode = v->a_mode;
 	node = VP_TO_TMPFS_NODE(vp);
 
-	/* The file is still active but all its names have been removed
+	/*
+	 * The file is still active but all its names have been removed
 	 * (e.g. by a "rmdir $(pwd)").  It cannot be opened any more as
-	 * it is about to die. */
+	 * it is about to die.
+	 */
 	if (node->tn_links < 1)
 		return (ENOENT);
 
@@ -306,8 +310,13 @@ tmpfs_open(struct vop_open_args *v)
 		vnode_create_vobject(vp, node->tn_size, v->a_td);
 	}
 
-	MPASS(VOP_ISLOCKED(vp));
-	return error;
+	fp = v->a_fp;
+	if (error == 0 && fp != NULL && vp->v_type == VREG) {
+		tmpfs_ref_node(node);
+		finit_vnode(fp, mode, node, &tmpfs_fnops);
+	}
+
+	return (error);
 }
 
 static int
@@ -321,6 +330,19 @@ tmpfs_close(struct vop_close_args *v)
 	return (0);
 }
 
+int
+tmpfs_fo_close(struct file *fp, struct thread *td)
+{
+	struct tmpfs_node *node;
+
+	node = fp->f_data;
+	if (node != NULL) {
+		MPASS(node->tn_type == VREG);
+		tmpfs_free_node(node->tn_reg.tn_tmp, node);
+	}
+	return (vnops.fo_close(fp, td));
+}
+
 /*
  * VOP_FPLOOKUP_VEXEC routines are subject to special circumstances, see
  * the comment above cache_fplookup for details.
@@ -567,6 +589,47 @@ tmpfs_read(struct vop_read_args *v)
 }
 
 static int
+tmpfs_read_pgcache(struct vop_read_pgcache_args *v)
+{
+	struct vnode *vp;
+	struct tmpfs_node *node;
+	vm_object_t object;
+	off_t size;
+	int error;
+
+	vp = v->a_vp;
+	MPASS((vp->v_irflag & VIRF_PGREAD) != 0);
+
+	if (v->a_uio->uio_offset < 0)
+		return (EINVAL);
+
+	error = EJUSTRETURN;
+	vfs_smr_enter();
+
+	node = VP_TO_TMPFS_NODE_SMR(vp);
+	if (node == NULL)
+		goto out_smr;
+	MPASS(node->tn_type == VREG);
+	MPASS(node->tn_refcount >= 1);
+	object = node->tn_reg.tn_aobj;
+	if (object == NULL)
+		goto out_smr;
+
+	MPASS((object->flags & (OBJ_ANON | OBJ_DEAD | OBJ_TMPFS_NODE)) ==
+	    OBJ_TMPFS_NODE);
+	if (!VN_IS_DOOMED(vp)) {
+		/* size cannot become shorter due to rangelock. */
+		size = node->tn_size;
+		vfs_smr_exit();
+		error = uiomove_object(object, size, v->a_uio);
+		return (error);
+	}
+out_smr:
+	vfs_smr_exit();
+	return (error);
+}
+
+static int
 tmpfs_write(struct vop_write_args *v)
 {
 	struct vnode *vp;
@@ -1721,6 +1784,7 @@ struct vop_vector tmpfs_vnodeop_entries = {
 	.vop_getattr =			tmpfs_getattr,
 	.vop_setattr =			tmpfs_setattr,
 	.vop_read =			tmpfs_read,
+	.vop_read_pgcache =		tmpfs_read_pgcache,
 	.vop_write =			tmpfs_write,
 	.vop_fsync =			tmpfs_fsync,
 	.vop_remove =			tmpfs_remove,


More information about the svn-src-head mailing list