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 *);