Module Name:    src
Committed By:   ad
Date:           Sat May 23 18:28:06 UTC 2009

Modified Files:
        src/sys/kern: kern_descrip.c kern_lwp.c kern_proc.c
        src/sys/sys: filedesc.h

Log Message:
Make descriptor access and file allocation cheaper in many cases,
mostly by avoiding a bunch of atomic operations.


To generate a diff of this commit:
cvs rdiff -u -r1.190 -r1.191 src/sys/kern/kern_descrip.c
cvs rdiff -u -r1.130 -r1.131 src/sys/kern/kern_lwp.c
cvs rdiff -u -r1.151 -r1.152 src/sys/kern/kern_proc.c
cvs rdiff -u -r1.53 -r1.54 src/sys/sys/filedesc.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_descrip.c
diff -u src/sys/kern/kern_descrip.c:1.190 src/sys/kern/kern_descrip.c:1.191
--- src/sys/kern/kern_descrip.c:1.190	Sat Apr  4 10:12:51 2009
+++ src/sys/kern/kern_descrip.c	Sat May 23 18:28:05 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_descrip.c,v 1.190 2009/04/04 10:12:51 ad Exp $	*/
+/*	$NetBSD: kern_descrip.c,v 1.191 2009/05/23 18:28:05 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.190 2009/04/04 10:12:51 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.191 2009/05/23 18:28:05 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -346,16 +346,25 @@
 		return NULL;
 	}
 
-	/*
-	 * Now get a reference to the descriptor.   Issue a memory
-	 * barrier to ensure that we acquire the file pointer _after_
-	 * adding a reference.  If no memory barrier, we could fetch
-	 * a stale pointer.
-	 */
-	atomic_inc_uint(&ff->ff_refcnt);
+	/* Now get a reference to the descriptor. */
+	if (fdp->fd_refcnt == 1) {
+		/*
+		 * Single threaded: don't need to worry about concurrent
+		 * access (other than earlier calls to kqueue, which may
+		 * hold a reference to the descriptor).
+		 */
+		ff->ff_refcnt++;
+	} else {
+		/*
+		 * Issue a memory barrier to ensure that we acquire the file
+		 * pointer _after_ adding a reference.  If no memory
+		 * barrier, we could fetch a stale pointer.
+		 */
+		atomic_inc_uint(&ff->ff_refcnt);
 #ifndef __HAVE_ATOMIC_AS_MEMBAR
-	membar_enter();
+		membar_enter();
 #endif
+	}
 
 	/*
 	 * If the file is not open or is being closed then put the
@@ -387,6 +396,20 @@
 	KASSERT((ff->ff_refcnt & FR_MASK) > 0);
 	KASSERT(fd >= NDFDFILE || ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
 
+	if (fdp->fd_refcnt == 1) {
+		/*
+		 * Single threaded: don't need to worry about concurrent
+		 * access (other than earlier calls to kqueue, which may
+		 * hold a reference to the descriptor).
+		 */
+		if (__predict_false((ff->ff_refcnt & FR_CLOSING) != 0)) {
+			fd_close(fd);
+			return;
+		}
+		ff->ff_refcnt--;
+		return;
+	}
+
 	/*
 	 * Ensure that any use of the file is complete and globally
 	 * visible before dropping the final reference.  If no membar,
@@ -747,7 +770,9 @@
 	} else {
 		error = 0;
 	}
-	ffree(fp);
+	KASSERT(fp->f_count == 0);
+	KASSERT(fp->f_cred != NULL);
+	pool_cache_put(file_cache, fp);
 
 	return error;
 }
@@ -761,14 +786,10 @@
 	filedesc_t *fdp;
 	int i, lim, last, error;
 	u_int off, new;
-	fdfile_t *ff;
 
 	KASSERT(p == curproc || p == &proc0);
 
 	fdp = p->p_fd;
-	ff = pool_cache_get(fdfile_cache, PR_WAITOK);
-	KASSERT(ff->ff_refcnt == 0);
-	KASSERT(ff->ff_file == NULL);
 
 	/*
 	 * Search for a free descriptor starting at the higher
@@ -802,10 +823,10 @@
 		}
 		if (fdp->fd_ofiles[i] == NULL) {
 			KASSERT(i >= NDFDFILE);
-			fdp->fd_ofiles[i] = ff;
-		} else {
-		   	pool_cache_put(fdfile_cache, ff);
+			fdp->fd_ofiles[i] =
+			    pool_cache_get(fdfile_cache, PR_WAITOK);
 		}
+		KASSERT(fdp->fd_ofiles[i]->ff_refcnt == 0);
 		KASSERT(fdp->fd_ofiles[i]->ff_file == NULL);
 		fd_used(fdp, i);
 		if (want <= fdp->fd_freefile) {
@@ -821,7 +842,6 @@
 	/* No space in current array.  Let the caller expand and retry. */
 	error = (fdp->fd_nfiles >= lim) ? EMFILE : ENOSPC;
 	mutex_exit(&fdp->fd_lock);
-	pool_cache_put(fdfile_cache, ff);
 	return error;
 }
 
@@ -943,7 +963,7 @@
 	 * to other threads.
 	 */
 	if (oldnfiles > NDFILE) {
-		if ((fdp->fd_refcnt | p->p_nlwps) > 1) {
+		if (fdp->fd_refcnt > 1) {
 			fdp->fd_ofiles[-2] = (void *)fdp->fd_discard;
 			fdp->fd_discard = fdp->fd_ofiles - 2;
 		} else {
@@ -988,6 +1008,7 @@
 int
 fd_allocfile(file_t **resultfp, int *resultfd)
 {
+	kauth_cred_t cred;
 	file_t *fp;
 	proc_t *p;
 	int error;
@@ -1002,29 +1023,32 @@
 	}
 
 	fp = pool_cache_get(file_cache, PR_WAITOK);
+	if (fp == NULL) {
+		return ENFILE;
+	}
 	KASSERT(fp->f_count == 0);
 	KASSERT(fp->f_msgcount == 0);
 	KASSERT(fp->f_unpcount == 0);
-	fp->f_cred = kauth_cred_get();
-	kauth_cred_hold(fp->f_cred);
 
-	if (__predict_false(atomic_inc_uint_nv(&nfiles) >= maxfiles)) {
-		fd_abort(p, fp, *resultfd);
-		tablefull("file", "increase kern.maxfiles or MAXFILES");
-		return ENFILE;
+	/* Replace cached credentials if not what we need. */
+	cred = curlwp->l_cred;
+	if (__predict_false(cred != fp->f_cred)) {
+		kauth_cred_free(fp->f_cred);
+		kauth_cred_hold(cred);
+		fp->f_cred = cred;
 	}
 
 	/*
 	 * Don't allow recycled files to be scanned.
+	 * See uipc_usrreq.c.
 	 */
-	if ((fp->f_flag & FSCAN) != 0) {
+	if (__predict_false((fp->f_flag & FSCAN) != 0)) {
 		mutex_enter(&fp->f_lock);
 		atomic_and_uint(&fp->f_flag, ~FSCAN);
 		mutex_exit(&fp->f_lock);
 	}
 
 	fp->f_advice = 0;
-	fp->f_msgcount = 0;
 	fp->f_offset = 0;
 	*resultfp = fp;
 
@@ -1092,34 +1116,30 @@
 	mutex_exit(&fdp->fd_lock);
 
 	if (fp != NULL) {
-		ffree(fp);
+		KASSERT(fp->f_count == 0);
+		KASSERT(fp->f_cred != NULL);
+		pool_cache_put(file_cache, fp);
 	}
 }
 
-/*
- * Free a file descriptor.
- */
-void
-ffree(file_t *fp)
-{
-
-	KASSERT(fp->f_count == 0);
-
-	atomic_dec_uint(&nfiles);
-	kauth_cred_free(fp->f_cred);
-	pool_cache_put(file_cache, fp);
-}
-
 static int
 file_ctor(void *arg, void *obj, int flags)
 {
 	file_t *fp = obj;
 
 	memset(fp, 0, sizeof(*fp));
-	mutex_init(&fp->f_lock, MUTEX_DEFAULT, IPL_NONE);
 
 	mutex_enter(&filelist_lock);
+	if (__predict_false(nfiles >= maxfiles)) {
+		mutex_exit(&filelist_lock);
+		tablefull("file", "increase kern.maxfiles or MAXFILES");
+		return ENFILE;
+	}
+	nfiles++;
 	LIST_INSERT_HEAD(&filehead, fp, f_list);
+	mutex_init(&fp->f_lock, MUTEX_DEFAULT, IPL_NONE);
+	fp->f_cred = curlwp->l_cred;
+	kauth_cred_hold(fp->f_cred);
 	mutex_exit(&filelist_lock);
 
 	return 0;
@@ -1131,9 +1151,11 @@
 	file_t *fp = obj;
 
 	mutex_enter(&filelist_lock);
+	nfiles--;
 	LIST_REMOVE(fp, f_list);
 	mutex_exit(&filelist_lock);
 
+	kauth_cred_free(fp->f_cred);
 	mutex_destroy(&fp->f_lock);
 }
 
@@ -1260,6 +1282,16 @@
 }
 
 /*
+ * Acquire a hold on a filedesc structure.
+ */
+void
+fd_hold(void)
+{
+
+	atomic_inc_uint(&curlwp->l_fd->fd_refcnt);
+}
+
+/*
  * Copy a filedesc structure.
  */
 filedesc_t *

Index: src/sys/kern/kern_lwp.c
diff -u src/sys/kern/kern_lwp.c:1.130 src/sys/kern/kern_lwp.c:1.131
--- src/sys/kern/kern_lwp.c:1.130	Sat May 23 18:21:20 2009
+++ src/sys/kern/kern_lwp.c	Sat May 23 18:28:06 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_lwp.c,v 1.130 2009/05/23 18:21:20 ad Exp $	*/
+/*	$NetBSD: kern_lwp.c,v 1.131 2009/05/23 18:28:06 ad Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -210,7 +210,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.130 2009/05/23 18:21:20 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.131 2009/05/23 18:28:06 ad Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -236,6 +236,7 @@
 #include <sys/intr.h>
 #include <sys/lwpctl.h>
 #include <sys/atomic.h>
+#include <sys/filedesc.h>
 
 #include <uvm/uvm_extern.h>
 #include <uvm/uvm_object.h>
@@ -596,9 +597,20 @@
 	l2->l_inheritedprio = -1;
 	l2->l_flag = inmem ? LW_INMEM : 0;
 	l2->l_pflag = LP_MPSAFE;
-	l2->l_fd = p2->p_fd;
 	TAILQ_INIT(&l2->l_ld_locks);
 
+	/*
+	 * If not the first LWP in the process, grab a reference to the
+	 * descriptor table.
+	 */
+	l2->l_fd = p2->p_fd;
+	if (p2->p_nlwps != 0) {
+		KASSERT(l1->l_proc == p2);
+		fd_hold();
+	} else {
+		KASSERT(l1->l_proc != p2);
+	}
+
 	if (p2->p_flag & PK_SYSTEM) {
 		/* Mark it as a system LWP and not a candidate for swapping */
 		l2->l_flag |= LW_SYSTEM;
@@ -723,6 +735,7 @@
 	current = (l == curlwp);
 
 	KASSERT(current || (l->l_stat == LSIDL && l->l_target_cpu == NULL));
+	KASSERT(p == curproc);
 
 	/*
 	 * Verify that we hold no locks other than the kernel lock.
@@ -752,6 +765,9 @@
 	if (p->p_emul->e_lwp_exit)
 		(*p->p_emul->e_lwp_exit)(l);
 
+	/* Drop filedesc reference. */
+	fd_free();
+
 	/* Delete the specificdata while it's still safe to sleep. */
 	specificdata_fini(lwp_specificdata_domain, &l->l_specdataref);
 

Index: src/sys/kern/kern_proc.c
diff -u src/sys/kern/kern_proc.c:1.151 src/sys/kern/kern_proc.c:1.152
--- src/sys/kern/kern_proc.c:1.151	Sat Apr 25 15:06:31 2009
+++ src/sys/kern/kern_proc.c	Sat May 23 18:28:06 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_proc.c,v 1.151 2009/04/25 15:06:31 rmind Exp $	*/
+/*	$NetBSD: kern_proc.c,v 1.152 2009/05/23 18:28:06 ad Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.151 2009/04/25 15:06:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.152 2009/05/23 18:28:06 ad Exp $");
 
 #include "opt_kstack.h"
 #include "opt_maxuprc.h"
@@ -203,6 +203,7 @@
 	.l_psid = PS_NONE,
 	.l_pi_lenders = SLIST_HEAD_INITIALIZER(&lwp0.l_pi_lenders),
 	.l_name = __UNCONST("swapper"),
+	.l_fd = &filedesc0,
 };
 kauth_cred_t cred0;
 

Index: src/sys/sys/filedesc.h
diff -u src/sys/sys/filedesc.h:1.53 src/sys/sys/filedesc.h:1.54
--- src/sys/sys/filedesc.h:1.53	Tue Nov 18 11:36:58 2008
+++ src/sys/sys/filedesc.h	Sat May 23 18:28:05 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: filedesc.h,v 1.53 2008/11/18 11:36:58 pooka Exp $	*/
+/*	$NetBSD: filedesc.h,v 1.54 2009/05/23 18:28:05 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -87,7 +87,7 @@
 #define	NDENTRYSHIFT	5		/* bits per entry */
 #define	NDLOSLOTS(x)	(((x) + NDENTRIES - 1) >> NDENTRYSHIFT)
 #define	NDHISLOTS(x)	((NDLOSLOTS(x) + NDENTRIES - 1) >> NDENTRYSHIFT)
-#define	NDFDFILE	3		/* first 3 descriptors are free */
+#define	NDFDFILE	6		/* first 6 descriptors are free */
 
 /*
  * Process-private descriptor reference, one for each descriptor slot
@@ -182,6 +182,7 @@
 filedesc_t *fd_copy(void);
 filedesc_t *fd_init(filedesc_t *);
 void	fd_share(proc_t *);
+void	fd_hold(void);
 void	fd_clear(void);
 void	fd_free(void);
 void	fd_remove(filedesc_t *, unsigned);
@@ -214,7 +215,6 @@
 int	vnode_to_path(char *, size_t, struct vnode *, struct lwp *,
     struct proc *);
 
-void	ffree(file_t *);
 int	closef(file_t *);
 file_t *fgetdummy(void);
 void	fputdummy(file_t *);

Reply via email to