summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortedu <tedu@openbsd.org>2010-03-24 23:18:17 +0000
committertedu <tedu@openbsd.org>2010-03-24 23:18:17 +0000
commit848c61ac39fbea5325564efce8fcf0080c29d321 (patch)
treebf424407fe88147c0a693f4f31d0b5b66ae01a97
parentsync (diff)
downloadwireguard-openbsd-848c61ac39fbea5325564efce8fcf0080c29d321.tar.xz
wireguard-openbsd-848c61ac39fbea5325564efce8fcf0080c29d321.zip
Add a rwlock around the filehead and allproc lists, mainly to protect
list walkers in sysctl that can block. As a reward, no more vslock. With some feedback from art, guenther, phessler. ok guenther.
-rw-r--r--sys/kern/kern_descrip.c8
-rw-r--r--sys/kern/kern_exit.c6
-rw-r--r--sys/kern/kern_fork.c4
-rw-r--r--sys/kern/kern_proc.c5
-rw-r--r--sys/kern/kern_sysctl.c31
-rw-r--r--sys/sys/file.h3
-rw-r--r--sys/sys/proc.h3
7 files changed, 49 insertions, 11 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 1620de45d2c..8efcc923f98 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_descrip.c,v 1.82 2009/07/09 22:29:56 thib Exp $ */
+/* $OpenBSD: kern_descrip.c,v 1.83 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
/*
@@ -68,6 +68,7 @@
* Descriptor management.
*/
struct filelist filehead; /* head of list of open files */
+struct rwlock fileheadlk;
int nfiles; /* actual number of open files */
static __inline void fd_used(struct filedesc *, int);
@@ -87,6 +88,7 @@ filedesc_init(void)
pool_init(&fdesc_pool, sizeof(struct filedesc0), 0, 0, 0, "fdescpl",
&pool_allocator_nointr);
LIST_INIT(&filehead);
+ rw_init(&fileheadlk, "filehead");
}
static __inline int
@@ -825,11 +827,13 @@ restart:
nfiles++;
fp = pool_get(&file_pool, PR_WAITOK|PR_ZERO);
fp->f_iflags = FIF_LARVAL;
+ rw_enter_write(&fileheadlk);
if ((fq = p->p_fd->fd_ofiles[0]) != NULL) {
LIST_INSERT_AFTER(fq, fp, f_list);
} else {
LIST_INSERT_HEAD(&filehead, fp, f_list);
}
+ rw_exit_write(&fileheadlk);
p->p_fd->fd_ofiles[i] = fp;
fp->f_count = 1;
fp->f_cred = p->p_ucred;
@@ -1088,7 +1092,9 @@ closef(struct file *fp, struct proc *p)
error = 0;
/* Free fp */
+ rw_enter_write(&fileheadlk);
LIST_REMOVE(fp, f_list);
+ rw_exit_write(&fileheadlk);
crfree(fp->f_cred);
#ifdef DIAGNOSTIC
if (fp->f_count != 0 || fp->f_usecount != 1)
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 6ce6154908f..3ff122b1621 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.89 2009/12/20 23:54:11 guenther Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.90 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -248,9 +248,11 @@ exit1(struct proc *p, int rv, int flags)
* deadproc list later (using the p_hash member), and
* wake up the reaper when we do.
*/
+ rw_enter_write(&allproclk);
LIST_REMOVE(p, p_hash);
LIST_REMOVE(p, p_list);
LIST_INSERT_HEAD(&zombproc, p, p_list);
+ rw_exit_write(&allproclk);
/*
* Give orphaned children to init(8).
@@ -564,7 +566,9 @@ proc_zap(struct proc *p)
* Unlink it from its process group and free it.
*/
leavepgrp(p);
+ rw_enter_write(&allproclk);
LIST_REMOVE(p, p_list); /* off zombproc */
+ rw_exit_write(&allproclk);
LIST_REMOVE(p, p_sibling);
/*
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index b701ee936cb..df6ffd8c7a0 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.108 2010/01/14 23:12:11 schwarze Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.109 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -414,7 +414,9 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
} while (pidtaken(lastpid));
p2->p_pid = lastpid;
+ rw_enter_write(&allproclk);
LIST_INSERT_HEAD(&allproc, p2, p_list);
+ rw_exit_write(&allproclk);
LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling);
LIST_INSERT_AFTER(p1, p2, p_pglist);
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index 8c2eb86af41..a54ca2ceef3 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_proc.c,v 1.41 2010/01/28 19:23:06 guenther Exp $ */
+/* $OpenBSD: kern_proc.c,v 1.42 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: kern_proc.c,v 1.14 1996/02/09 18:59:41 christos Exp $ */
/*
@@ -40,6 +40,7 @@
#include <sys/acct.h>
#include <sys/wait.h>
#include <sys/file.h>
+#include <sys/rwlock.h>
#include <ufs/ufs/quota.h>
#include <sys/uio.h>
#include <sys/malloc.h>
@@ -61,6 +62,7 @@ u_long pidhash;
struct pgrphashhead *pgrphashtbl;
u_long pgrphash;
struct proclist allproc;
+struct rwlock allproclk;
struct proclist zombproc;
struct pool proc_pool;
@@ -83,6 +85,7 @@ void
procinit(void)
{
LIST_INIT(&allproc);
+ rw_init(&allproclk, "allproc");
LIST_INIT(&zombproc);
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 69062cb558c..a446a07e24d 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sysctl.c,v 1.180 2010/01/10 03:37:50 guenther Exp $ */
+/* $OpenBSD: kern_sysctl.c,v 1.181 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
/*-
@@ -160,8 +160,13 @@ sys___sysctl(struct proc *p, void *v, register_t *retval)
switch (name[0]) {
case CTL_KERN:
fn = kern_sysctl;
- if (name[1] == KERN_VNODE) /* XXX */
+ switch (name[1]) { /* XXX */
+ case KERN_VNODE:
+ case KERN_FILE:
+ case KERN_FILE2:
dolock = 0;
+ break;
+ }
break;
case CTL_HW:
fn = hw_sysctl;
@@ -993,10 +998,12 @@ sysctl_file(char *where, size_t *sizep, struct proc *p)
/*
* followed by an array of file structures
*/
+ rw_enter_read(&fileheadlk);
LIST_FOREACH(fp, &filehead, f_list) {
if (buflen < sizeof(struct file)) {
*sizep = where - start;
- return (ENOMEM);
+ error = ENOMEM;
+ goto out;
}
/* Only let the superuser or the owner see some information */
@@ -1010,12 +1017,14 @@ sysctl_file(char *where, size_t *sizep, struct proc *p)
}
error = copyout(&cfile, where, sizeof (struct file));
if (error)
- return (error);
+ goto out;
buflen -= sizeof(struct file);
where += sizeof(struct file);
}
*sizep = where - start;
- return (0);
+out:
+ rw_exit_read(&fileheadlk);
+ return (error);
}
#ifndef SMALL_KERNEL
@@ -1219,11 +1228,13 @@ sysctl_file2(int *name, u_int namelen, char *where, size_t *sizep,
error = EINVAL;
break;
}
+ rw_enter_read(&fileheadlk);
LIST_FOREACH(fp, &filehead, f_list) {
if (fp->f_count == 0)
continue;
FILLIT(fp, NULL, 0, NULL, NULL);
}
+ rw_exit_read(&fileheadlk);
break;
case KERN_FILE_BYPID:
/* A arg of -1 indicates all processes */
@@ -1231,6 +1242,7 @@ sysctl_file2(int *name, u_int namelen, char *where, size_t *sizep,
error = EINVAL;
break;
}
+ rw_enter_read(&allproclk);
LIST_FOREACH(pp, &allproc, p_list) {
/* skip system, embryonic and undead processes */
if ((pp->p_flag & P_SYSTEM) ||
@@ -1241,6 +1253,7 @@ sysctl_file2(int *name, u_int namelen, char *where, size_t *sizep,
continue;
}
fdp = pp->p_fd;
+ fdplock(fdp);
if (pp->p_textvp)
FILLIT(NULL, NULL, KERN_FILE_TEXT, pp->p_textvp, pp);
if (fdp->fd_cdir)
@@ -1256,9 +1269,12 @@ sysctl_file2(int *name, u_int namelen, char *where, size_t *sizep,
continue;
FILLIT(fp, fdp, i, NULL, pp);
}
+ fdpunlock(fdp);
}
+ rw_exit_read(&allproclk);
break;
case KERN_FILE_BYUID:
+ rw_enter_read(&allproclk);
LIST_FOREACH(pp, &allproc, p_list) {
/* skip system, embryonic and undead processes */
if ((pp->p_flag & P_SYSTEM) ||
@@ -1269,6 +1285,7 @@ sysctl_file2(int *name, u_int namelen, char *where, size_t *sizep,
continue;
}
fdp = pp->p_fd;
+ fdplock(fdp);
if (fdp->fd_cdir)
FILLIT(NULL, NULL, KERN_FILE_CDIR, fdp->fd_cdir, pp);
if (fdp->fd_rdir)
@@ -1282,7 +1299,9 @@ sysctl_file2(int *name, u_int namelen, char *where, size_t *sizep,
continue;
FILLIT(fp, fdp, i, NULL, pp);
}
+ fdpunlock(fdp);
}
+ rw_exit_read(&allproclk);
break;
default:
error = EINVAL;
@@ -1336,6 +1355,7 @@ sysctl_doproc(int *name, u_int namelen, char *where, size_t *sizep)
elem_count = name[4];
kproc2 = malloc(sizeof(struct kinfo_proc2), M_TEMP, M_WAITOK);
}
+ rw_enter_read(&allproclk);
p = LIST_FIRST(&allproc);
doingzomb = 0;
again:
@@ -1447,6 +1467,7 @@ again:
*sizep = needed;
}
err:
+ rw_exit_read(&allproclk);
if (eproc)
free(eproc, M_TEMP);
if (kproc2)
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 82d76894cda..28474acf9f9 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.h,v 1.25 2009/06/04 00:24:01 blambert Exp $ */
+/* $OpenBSD: file.h,v 1.26 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: file.h,v 1.11 1995/03/26 20:24:13 jtc Exp $ */
/*
@@ -106,6 +106,7 @@ struct file {
LIST_HEAD(filelist, file);
extern struct filelist filehead; /* head of list of open files */
+extern struct rwlock fileheadlk;
extern int maxfiles; /* kernel limit on number of open files */
extern int nfiles; /* actual number of open files */
extern struct fileops vnops; /* vnode operations for files */
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 47548df5aee..c5144375bb7 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.123 2010/01/28 19:23:06 guenther Exp $ */
+/* $OpenBSD: proc.h,v 1.124 2010/03/24 23:18:17 tedu Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -395,6 +395,7 @@ extern int randompid; /* fork() should create random pid's */
LIST_HEAD(proclist, proc);
extern struct proclist allproc; /* List of all processes. */
+extern struct rwlock allproclk; /* also used for zombie list */
extern struct proclist zombproc; /* List of zombie processes. */
extern struct proc *initproc; /* Process slots for init, pager. */