diff options
author | 2010-03-24 23:18:17 +0000 | |
---|---|---|
committer | 2010-03-24 23:18:17 +0000 | |
commit | 848c61ac39fbea5325564efce8fcf0080c29d321 (patch) | |
tree | bf424407fe88147c0a693f4f31d0b5b66ae01a97 | |
parent | sync (diff) | |
download | wireguard-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.c | 8 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 6 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_proc.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 31 | ||||
-rw-r--r-- | sys/sys/file.h | 3 | ||||
-rw-r--r-- | sys/sys/proc.h | 3 |
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. */ |