svn commit: r356643 - in head/sys: cddl/contrib/opensolaris/uts/common/fs/zfs kern sys

Mateusz Guzik mjg at FreeBSD.org
Sat Jan 11 22:58:16 UTC 2020


Author: mjg
Date: Sat Jan 11 22:58:14 2020
New Revision: 356643
URL: https://svnweb.freebsd.org/changeset/base/356643

Log:
  vfs: prealloc vnodes in getnewvnode_reserve
  
  Having a reserved vnode count does not guarantee that getnewvnodes wont
  block later. Said blocking partially defeats the purpose of reserving in
  the first place.
  
  Preallocate instaed. The only consumer was always passing "1" as count
  and never nesting reservations.

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
  head/sys/kern/kern_thread.c
  head/sys/kern/subr_trap.c
  head/sys/kern/vfs_subr.c
  head/sys/sys/proc.h
  head/sys/sys/vnode.h

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_dir.c	Sat Jan 11 22:58:14 2020	(r356643)
@@ -815,7 +815,7 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t *
 		return (SET_ERROR(EDQUOT));
 	}
 
-	getnewvnode_reserve(1);
+	getnewvnode_reserve();
 
 	tx = dmu_tx_create(zfsvfs->z_os);
 	dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	Sat Jan 11 22:58:14 2020	(r356643)
@@ -1800,7 +1800,7 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int
 		goto out;
 	}
 
-	getnewvnode_reserve(1);
+	getnewvnode_reserve();
 
 	tx = dmu_tx_create(os);
 
@@ -2092,7 +2092,7 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, v
 	/*
 	 * Add a new entry to the directory.
 	 */
-	getnewvnode_reserve(1);
+	getnewvnode_reserve();
 	tx = dmu_tx_create(zfsvfs->z_os);
 	dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname);
 	dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
@@ -4003,7 +4003,7 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, v
 		return (SET_ERROR(EDQUOT));
 	}
 
-	getnewvnode_reserve(1);
+	getnewvnode_reserve();
 	tx = dmu_tx_create(zfsvfs->z_os);
 	fuid_dirtied = zfsvfs->z_fuid_dirty;
 	dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, MAX(1, len));

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	Sat Jan 11 22:58:14 2020	(r356643)
@@ -644,8 +644,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int b
 
 	zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
 
-	KASSERT(curthread->td_vp_reserv > 0,
-	    ("zfs_znode_alloc: getnewvnode without any vnodes reserved"));
+	KASSERT(curthread->td_vp_reserved != NULL,
+	    ("zfs_znode_alloc: getnewvnode without preallocated vnode"));
 	error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp);
 	if (error != 0) {
 		kmem_cache_free(znode_cache, zp);
@@ -1157,7 +1157,7 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t *
 	int err;
 
 	td = curthread;
-	getnewvnode_reserve(1);
+	getnewvnode_reserve();
 again:
 	*zpp = NULL;
 	ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num);

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/kern/kern_thread.c	Sat Jan 11 22:58:14 2020	(r356643)
@@ -82,7 +82,7 @@ _Static_assert(offsetof(struct thread, td_flags) == 0x
     "struct thread KBI td_flags");
 _Static_assert(offsetof(struct thread, td_pflags) == 0x104,
     "struct thread KBI td_pflags");
-_Static_assert(offsetof(struct thread, td_frame) == 0x478,
+_Static_assert(offsetof(struct thread, td_frame) == 0x480,
     "struct thread KBI td_frame");
 _Static_assert(offsetof(struct thread, td_emuldata) == 0x690,
     "struct thread KBI td_emuldata");

Modified: head/sys/kern/subr_trap.c
==============================================================================
--- head/sys/kern/subr_trap.c	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/kern/subr_trap.c	Sat Jan 11 22:58:14 2020	(r356643)
@@ -187,8 +187,8 @@ userret(struct thread *td, struct trapframe *frame)
 	}
 	KASSERT(td->td_pinned == 0 || (td->td_pflags & TDP_CALLCHAIN) != 0,
 	    ("userret: Returning with with pinned thread"));
-	KASSERT(td->td_vp_reserv == 0,
-	    ("userret: Returning while holding vnode reservation"));
+	KASSERT(td->td_vp_reserved == NULL,
+	    ("userret: Returning with preallocated vnode"));
 	KASSERT((td->td_flags & (TDF_SBDRY | TDF_SEINTR | TDF_SERESTART)) == 0,
 	    ("userret: Returning with stop signals deferred"));
 	KASSERT(td->td_su == NULL,

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/kern/vfs_subr.c	Sat Jan 11 22:58:14 2020	(r356643)
@@ -1527,40 +1527,29 @@ getnewvnode_wait(int suspended)
  * watermark handling works.
  */
 void
-getnewvnode_reserve(u_int count)
+getnewvnode_reserve(void)
 {
 	u_long rnumvnodes, rfreevnodes;
 	struct thread *td;
 
-	/* Pre-adjust like the pre-adjust in getnewvnode(), with any count. */
-	/* XXX no longer so quick, but this part is not racy. */
+	td = curthread;
+	MPASS(td->td_vp_reserved == NULL);
+
 	mtx_lock(&vnode_free_list_mtx);
 	rnumvnodes = atomic_load_long(&numvnodes);
 	rfreevnodes = atomic_load_long(&freevnodes);
-	if (rnumvnodes + count > desiredvnodes && rfreevnodes > wantfreevnodes)
-		vnlru_free_locked(ulmin(rnumvnodes + count - desiredvnodes,
+	if (rnumvnodes + 1 > desiredvnodes && rfreevnodes > wantfreevnodes)
+		vnlru_free_locked(ulmin(rnumvnodes + 1 - desiredvnodes,
 		    rfreevnodes - wantfreevnodes), NULL);
-	mtx_unlock(&vnode_free_list_mtx);
-
-	td = curthread;
-	/* First try to be quick and racy. */
-	if (atomic_fetchadd_long(&numvnodes, count) + count <= desiredvnodes) {
-		td->td_vp_reserv += count;
-		vcheckspace();	/* XXX no longer so quick, but more racy */
-		return;
-	} else
-		atomic_subtract_long(&numvnodes, count);
-
-	mtx_lock(&vnode_free_list_mtx);
-	while (count > 0) {
-		if (getnewvnode_wait(0) == 0) {
-			count--;
-			td->td_vp_reserv++;
-			atomic_add_long(&numvnodes, 1);
-		}
+	if (rnumvnodes + 1 > desiredvnodes) {
+		while (getnewvnode_wait(0) != 0)
+			continue;
 	}
 	vcheckspace();
+	atomic_add_long(&numvnodes, 1);
 	mtx_unlock(&vnode_free_list_mtx);
+
+	td->td_vp_reserved = uma_zalloc(vnode_zone, M_WAITOK);
 }
 
 /*
@@ -1577,8 +1566,11 @@ getnewvnode_drop_reserve(void)
 	struct thread *td;
 
 	td = curthread;
-	atomic_subtract_long(&numvnodes, td->td_vp_reserv);
-	td->td_vp_reserv = 0;
+	if (td->td_vp_reserved != NULL) {
+		atomic_subtract_long(&numvnodes, 1);
+		uma_zfree(vnode_zone, td->td_vp_reserved);
+		td->td_vp_reserved = NULL;
+	}
 }
 
 /*
@@ -1599,11 +1591,11 @@ getnewvnode(const char *tag, struct mount *mp, struct 
 	KASSERT(vops->registered,
 	    ("%s: not registered vector op %p\n", __func__, vops));
 
-	vp = NULL;
 	td = curthread;
-	if (td->td_vp_reserv > 0) {
-		td->td_vp_reserv -= 1;
-		goto alloc;
+	if (td->td_vp_reserved != NULL) {
+		vp = td->td_vp_reserved;
+		td->td_vp_reserved = NULL;
+		goto init;
 	}
 	mtx_lock(&vnode_free_list_mtx);
 	if (numvnodes < desiredvnodes)
@@ -1639,9 +1631,9 @@ getnewvnode(const char *tag, struct mount *mp, struct 
 	vcheckspace();
 	atomic_add_long(&numvnodes, 1);
 	mtx_unlock(&vnode_free_list_mtx);
-alloc:
-	counter_u64_add(vnodes_created, 1);
 	vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK);
+init:
+	counter_u64_add(vnodes_created, 1);
 	/*
 	 * Locks are given the generic name "vnode" when created.
 	 * Follow the historic practice of using the filesystem

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/sys/proc.h	Sat Jan 11 22:58:14 2020	(r356643)
@@ -297,7 +297,7 @@ struct thread {
 	struct osd	td_osd;		/* (k) Object specific data. */
 	struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */
 	pid_t		td_dbg_forked;	/* (c) Child pid for debugger. */
-	u_int		td_vp_reserv;	/* (k) Count of reserved vnodes. */
+	struct vnode	*td_vp_reserved;/* (k) Prealloated vnode. */
 	u_int		td_no_sleeping;	/* (k) Sleeping disabled count. */
 	void		*td_su;		/* (k) FFS SU private */
 	sbintime_t	td_sleeptimo;	/* (t) Sleep timeout. */

Modified: head/sys/sys/vnode.h
==============================================================================
--- head/sys/sys/vnode.h	Sat Jan 11 22:56:20 2020	(r356642)
+++ head/sys/sys/vnode.h	Sat Jan 11 22:58:14 2020	(r356643)
@@ -624,7 +624,7 @@ void	freebsd11_cvtnstat(struct stat *sb, struct nstat 
 int	freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost);
 int	getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
 	    struct vnode **vpp);
-void	getnewvnode_reserve(u_int count);
+void	getnewvnode_reserve(void);
 void	getnewvnode_drop_reserve(void);
 int	insmntque1(struct vnode *vp, struct mount *mp,
 	    void (*dtr)(struct vnode *, void *), void *dtr_arg);


More information about the svn-src-head mailing list