From d9b2033e0de20e56097c9d9e9eab3f45fe1473be Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 26 May 2006 00:33:13 +0000 Subject: [PATCH] More MP work. * Incorporate fd_knlistsize initialization into fsetfd(). * Mark all fileops vectors as MPSAFE (but get the mplock for most of them). Clean up a number of fileops routines, mainly *_ioctl(). * Make crget(), crhold(), and crfree() MPSAFE. crfree still needs the mplock on the last release. Give ucred a spinlock to handle the crfree() 0 transition race. --- sys/kern/kern_descrip.c | 30 +++++++- sys/kern/kern_event.c | 51 ++++++++++---- sys/kern/kern_prot.c | 68 +++++++++++++----- sys/kern/sys_pipe.c | 114 +++++++++++++++++++++--------- sys/kern/sys_socket.c | 141 ++++++++++++++++++++++++++----------- sys/kern/vfs_vnops.c | 133 ++++++++++++++++++++++++---------- sys/opencrypto/cryptodev.c | 71 ++++++++++++++----- sys/sys/ucred.h | 10 ++- 8 files changed, 450 insertions(+), 168 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 50aba9af49..adc9e1be6f 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -70,7 +70,7 @@ * * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94 * $FreeBSD: src/sys/kern/kern_descrip.c,v 1.81.2.19 2004/02/28 00:43:31 tegge Exp $ - * $DragonFly: src/sys/kern/kern_descrip.c,v 1.63 2006/05/25 07:36:34 dillon Exp $ + * $DragonFly: src/sys/kern/kern_descrip.c,v 1.64 2006/05/26 00:33:09 dillon Exp $ */ #include "opt_compat.h" @@ -1295,6 +1295,10 @@ fsetfd_locked(struct filedesc *fdp, struct file *fp, int fd) fhold(fp); fdp->fd_files[fd].fp = fp; fdp->fd_files[fd].reserved = 0; + if (fp->f_type == DTYPE_KQUEUE) { + if (fdp->fd_knlistsize < 0) + fdp->fd_knlistsize = 0; + } } else { fdp->fd_files[fd].reserved = 0; fdreserve_locked(fdp, fd, -1); @@ -2433,6 +2437,9 @@ fildesc_drvinit(void *unused) make_dev(&fildesc_cdevsw, 2, UID_ROOT, GID_WHEEL, 0666, "stderr"); } +/* + * MPSAFE + */ struct fileops badfileops = { NULL, /* port */ NULL, /* clone */ @@ -2446,6 +2453,9 @@ struct fileops badfileops = { badfo_shutdown }; +/* + * MPSAFE + */ static int badfo_readwrite( struct file *fp, @@ -2456,18 +2466,27 @@ badfo_readwrite( return (EBADF); } +/* + * MPSAFE + */ static int badfo_ioctl(struct file *fp, u_long com, caddr_t data, struct ucred *cred) { return (EBADF); } +/* + * MPSAFE + */ static int badfo_poll(struct file *fp, int events, struct ucred *cred) { return (0); } +/* + * MPSAFE + */ static int badfo_kqfilter(struct file *fp, struct knote *kn) { @@ -2480,18 +2499,27 @@ badfo_stat(struct file *fp, struct stat *sb, struct ucred *cred) return (EBADF); } +/* + * MPSAFE + */ static int badfo_close(struct file *fp) { return (EBADF); } +/* + * MPSAFE + */ static int badfo_shutdown(struct file *fp, int how) { return (EBADF); } +/* + * MPSAFE + */ int nofo_shutdown(struct file *fp, int how) { diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index e656a8e3f8..e90ebed429 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_event.c,v 1.2.2.10 2004/04/04 07:03:14 cperciva Exp $ - * $DragonFly: src/sys/kern/kern_event.c,v 1.24 2006/05/22 21:21:21 dillon Exp $ + * $DragonFly: src/sys/kern/kern_event.c,v 1.25 2006/05/26 00:33:09 dillon Exp $ */ #include @@ -70,6 +70,9 @@ static int kqueue_stat(struct file *fp, struct stat *st, static int kqueue_close(struct file *fp); static void kqueue_wakeup(struct kqueue *kq); +/* + * MPSAFE + */ static struct fileops kqueueops = { NULL, /* port */ NULL, /* clone */ @@ -148,17 +151,23 @@ filt_fileattach(struct knote *kn) return (fo_kqfilter(kn->kn_fp, kn)); } -/*ARGSUSED*/ +/* + * MPALMOSTSAFE - acquires mplock + */ static int kqueue_kqfilter(struct file *fp, struct knote *kn) { struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data; - if (kn->kn_filter != EVFILT_READ) + get_mplock(); + if (kn->kn_filter != EVFILT_READ) { + rel_mplock(); return (1); + } kn->kn_fop = &kqread_filtops; SLIST_INSERT_HEAD(&kq->kq_sel.si_note, kn, kn_selnext); + rel_mplock(); return (0); } @@ -375,15 +384,15 @@ kqueue(struct kqueue_args *uap) fp->f_flag = FREAD | FWRITE; fp->f_type = DTYPE_KQUEUE; fp->f_ops = &kqueueops; + kq = malloc(sizeof(struct kqueue), M_KQUEUE, M_WAITOK | M_ZERO); TAILQ_INIT(&kq->kq_head); + kq->kq_fdp = fdp; fp->f_data = kq; + fsetfd(p, fp, fd); uap->sysmsg_result = fd; fdrop(fp); - if (fdp->fd_knlistsize < 0) - fdp->fd_knlistsize = 0; /* this process has a kq */ - kq->kq_fdp = fdp; return (error); } @@ -719,35 +728,43 @@ done: /* * XXX * This could be expanded to call kqueue_scan, if desired. + * + * MPSAFE */ -/*ARGSUSED*/ static int kqueue_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { return (ENXIO); } -/*ARGSUSED*/ +/* + * MPSAFE + */ static int kqueue_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { return (ENXIO); } -/*ARGSUSED*/ +/* + * MPSAFE + */ static int kqueue_ioctl(struct file *fp, u_long com, caddr_t data, struct ucred *cred) { return (ENOTTY); } -/*ARGSUSED*/ +/* + * MPALMOSTSAFE - acquires mplock + */ static int kqueue_poll(struct file *fp, int events, struct ucred *cred) { struct kqueue *kq = (struct kqueue *)fp->f_data; int revents = 0; + get_mplock(); crit_enter(); if (events & (POLLIN | POLLRDNORM)) { if (kq->kq_count) { @@ -758,10 +775,13 @@ kqueue_poll(struct file *fp, int events, struct ucred *cred) } } crit_exit(); + rel_mplock(); return (revents); } -/*ARGSUSED*/ +/* + * MPSAFE + */ static int kqueue_stat(struct file *fp, struct stat *st, struct ucred *cred) { @@ -774,7 +794,9 @@ kqueue_stat(struct file *fp, struct stat *st, struct ucred *cred) return (0); } -/*ARGSUSED*/ +/* + * MPALMOSTSAFE - acquires mplock + */ static int kqueue_close(struct file *fp) { @@ -786,6 +808,7 @@ kqueue_close(struct file *fp) int i; KKASSERT(p); + get_mplock(); fdp = p->p_fd; for (i = 0; i < fdp->fd_knlistsize; i++) { knp = &SLIST_FIRST(&fdp->fd_knlist[i]); @@ -821,16 +844,16 @@ kqueue_close(struct file *fp) } } } - free(kq, M_KQUEUE); fp->f_data = NULL; + rel_mplock(); + free(kq, M_KQUEUE); return (0); } static void kqueue_wakeup(struct kqueue *kq) { - if (kq->kq_state & KQ_SLEEP) { kq->kq_state &= ~KQ_SLEEP; wakeup(kq); diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index 67cc8b8773..4730cfc62f 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -37,7 +37,7 @@ * * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/kern_prot.c,v 1.53.2.9 2002/03/09 05:20:26 dd Exp $ - * $DragonFly: src/sys/kern/kern_prot.c,v 1.23 2006/03/23 20:55:07 drhodus Exp $ + * $DragonFly: src/sys/kern/kern_prot.c,v 1.24 2006/05/26 00:33:09 dillon Exp $ */ /* @@ -55,9 +55,12 @@ #include #include #include -#include #include #include +#include + +#include +#include static MALLOC_DEFINE(M_CRED, "cred", "credentials"); @@ -869,8 +872,30 @@ p_trespass(struct ucred *cr1, struct ucred *cr2) return (EPERM); } +/* + * MPSAFE + */ +static __inline void +_crinit(struct ucred *cr) +{ + bzero(cr, sizeof(*cr)); + cr->cr_ref = 1; + spin_init(&cr->cr_spin); +} + +/* + * MPSAFE + */ +void +crinit(struct ucred *cr) +{ + _crinit(cr); +} + /* * Allocate a zeroed cred structure. + * + * MPSAFE */ struct ucred * crget(void) @@ -878,45 +903,52 @@ crget(void) struct ucred *cr; MALLOC(cr, struct ucred *, sizeof(*cr), M_CRED, M_WAITOK); - bzero((caddr_t)cr, sizeof(*cr)); - cr->cr_ref = 1; + _crinit(cr); return (cr); } /* * Claim another reference to a ucred structure. Can be used with special * creds. + * + * It must be possible to call this routine with spinlocks held, meaning + * that this routine itself cannot obtain a spinlock. + * + * MPSAFE */ struct ucred * crhold(struct ucred *cr) { if (cr != NOCRED && cr != FSCRED) - cr->cr_ref++; + atomic_add_int(&cr->cr_ref, 1); return(cr); } /* - * Free a cred structure. - * Throws away space when ref count gets to 0. - * MPSAFE + * Drop a reference from the cred structure, free it if the reference count + * reaches 0. + * + * NOTE: because we used atomic_add_int() above, without a spinlock, we + * must also use atomic_subtract_int() below. A spinlock is required + * in crfree() to handle multiple callers racing the refcount to 0. + * + * MPALMOSTSAFE - acquires mplock on 1->0 transition of ref count */ void crfree(struct ucred *cr) { - /* Protect crfree() as a critical section as there - * appears to be a crfree race which can occur on - * SMP systems. - */ - crit_enter(); - if (cr->cr_ref == 0) + if (cr->cr_ref <= 0) panic("Freeing already free credential! %p", cr); - - if (--cr->cr_ref == 0) { + spin_lock_wr(&cr->cr_spin); + atomic_subtract_int(&cr->cr_ref, 1); + if (cr->cr_ref == 0) { + spin_unlock_wr(&cr->cr_spin); /* * Some callers of crget(), such as nfs_statfs(), * allocate a temporary credential, but don't * allocate a uidinfo structure. */ + get_mplock(); if (cr->cr_uidinfo != NULL) { uidrop(cr->cr_uidinfo); cr->cr_uidinfo = NULL; @@ -934,8 +966,10 @@ crfree(struct ucred *cr) cr->cr_prison = NULL; /* safety */ FREE((caddr_t)cr, M_CRED); + rel_mplock(); + } else { + spin_unlock_wr(&cr->cr_spin); } - crit_exit(); } /* diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 2864cca887..a3b9a4a85d 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -17,7 +17,7 @@ * are met. * * $FreeBSD: src/sys/kern/sys_pipe.c,v 1.60.2.13 2002/08/05 15:05:15 des Exp $ - * $DragonFly: src/sys/kern/sys_pipe.c,v 1.36 2006/05/22 21:21:21 dillon Exp $ + * $DragonFly: src/sys/kern/sys_pipe.c,v 1.37 2006/05/26 00:33:09 dillon Exp $ */ /* @@ -414,15 +414,19 @@ pipeselwakeup(cpipe) KNOTE(&cpipe->pipe_sel.si_note, 0); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE (acquires mplock) + */ static int pipe_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { - struct pipe *rpipe = (struct pipe *) fp->f_data; + struct pipe *rpipe; int error; int nread = 0; u_int size; + get_mplock(); + rpipe = (struct pipe *) fp->f_data; ++rpipe->pipe_busy; error = pipelock(rpipe, 1); if (error) @@ -622,6 +626,7 @@ unlocked_error: if ((rpipe->pipe_buffer.size - rpipe->pipe_buffer.cnt) >= PIPE_BUF) pipeselwakeup(rpipe); + rel_mplock(); return (error); } @@ -848,7 +853,10 @@ error2: return (error); } #endif - + +/* + * MPALMOSTSAFE - acquires mplock + */ static int pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { @@ -856,6 +864,7 @@ pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) int orig_resid; struct pipe *wpipe, *rpipe; + get_mplock(); rpipe = (struct pipe *) fp->f_data; wpipe = rpipe->pipe_peer; @@ -863,6 +872,7 @@ pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) * detect loss of pipe read side, issue SIGPIPE if lost. */ if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) { + rel_mplock(); return (EPIPE); } ++wpipe->pipe_busy; @@ -895,6 +905,7 @@ pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR); wakeup(wpipe); } + rel_mplock(); return(error); } @@ -1118,31 +1129,36 @@ pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) */ if (wpipe->pipe_buffer.cnt) pipeselwakeup(wpipe); - + rel_mplock(); return (error); } /* + * MPALMOSTSAFE - acquires mplock + * * we implement a very minimal set of ioctls for compatibility with sockets. */ int pipe_ioctl(struct file *fp, u_long cmd, caddr_t data, struct ucred *cred) { - struct pipe *mpipe = (struct pipe *)fp->f_data; + struct pipe *mpipe; + int error; - switch (cmd) { + get_mplock(); + mpipe = (struct pipe *)fp->f_data; + switch (cmd) { case FIONBIO: - return (0); - + error = 0; + break; case FIOASYNC: if (*(int *)data) { mpipe->pipe_state |= PIPE_ASYNC; } else { mpipe->pipe_state &= ~PIPE_ASYNC; } - return (0); - + error = 0; + break; case FIONREAD: if (mpipe->pipe_state & PIPE_DIRECTW) { *(int *)data = mpipe->pipe_map.xio_bytes - @@ -1150,35 +1166,45 @@ pipe_ioctl(struct file *fp, u_long cmd, caddr_t data, struct ucred *cred) } else { *(int *)data = mpipe->pipe_buffer.cnt; } - return (0); - + error = 0; + break; case FIOSETOWN: - return (fsetown(*(int *)data, &mpipe->pipe_sigio)); - + error = fsetown(*(int *)data, &mpipe->pipe_sigio); + break; case FIOGETOWN: *(int *)data = fgetown(mpipe->pipe_sigio); - return (0); - - /* This is deprecated, FIOSETOWN should be used instead. */ + error = 0; + break; case TIOCSPGRP: - return (fsetown(-(*(int *)data), &mpipe->pipe_sigio)); + /* This is deprecated, FIOSETOWN should be used instead. */ + error = fsetown(-(*(int *)data), &mpipe->pipe_sigio); + break; - /* This is deprecated, FIOGETOWN should be used instead. */ case TIOCGPGRP: + /* This is deprecated, FIOGETOWN should be used instead. */ *(int *)data = -fgetown(mpipe->pipe_sigio); - return (0); - + error = 0; + break; + default: + error = ENOTTY; + break; } - return (ENOTTY); + rel_mplock(); + return (error); } +/* + * MPALMOSTSAFE - acquires mplock + */ int pipe_poll(struct file *fp, int events, struct ucred *cred) { - struct pipe *rpipe = (struct pipe *)fp->f_data; + struct pipe *rpipe; struct pipe *wpipe; int revents = 0; + get_mplock(); + rpipe = (struct pipe *)fp->f_data; wpipe = rpipe->pipe_peer; if (events & (POLLIN | POLLRDNORM)) if ((rpipe->pipe_state & PIPE_DIRECTW) || @@ -1208,14 +1234,20 @@ pipe_poll(struct file *fp, int events, struct ucred *cred) wpipe->pipe_state |= PIPE_SEL; } } - + rel_mplock(); return (revents); } +/* + * MPALMOSTSAFE - acquires mplock + */ static int pipe_stat(struct file *fp, struct stat *ub, struct ucred *cred) { - struct pipe *pipe = (struct pipe *)fp->f_data; + struct pipe *pipe; + + get_mplock(); + pipe = (struct pipe *)fp->f_data; bzero((caddr_t)ub, sizeof(*ub)); ub->st_mode = S_IFIFO; @@ -1234,33 +1266,42 @@ pipe_stat(struct file *fp, struct stat *ub, struct ucred *cred) * st_flags, st_gen. * XXX (st_dev, st_ino) should be unique. */ + rel_mplock(); return (0); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ static int pipe_close(struct file *fp) { struct pipe *cpipe = (struct pipe *)fp->f_data; + get_mplock(); fp->f_ops = &badfileops; fp->f_data = NULL; funsetown(cpipe->pipe_sigio); pipeclose(cpipe); + rel_mplock(); return (0); } /* * Shutdown one or both directions of a full-duplex pipe. + * + * MPALMOSTSAFE - acquires mplock */ -/* ARGSUSED */ static int pipe_shutdown(struct file *fp, int how) { - struct pipe *rpipe = (struct pipe *)fp->f_data; + struct pipe *rpipe; struct pipe *wpipe; int error = EPIPE; + get_mplock(); + rpipe = (struct pipe *)fp->f_data; + switch(how) { case SHUT_RDWR: case SHUT_RD: @@ -1283,6 +1324,7 @@ pipe_shutdown(struct file *fp, int how) error = 0; } } + rel_mplock(); return (error); } @@ -1368,11 +1410,16 @@ pipeclose(struct pipe *cpipe) } } -/*ARGSUSED*/ +/* + * MPALMOSTSAFE - acquires mplock + */ static int pipe_kqfilter(struct file *fp, struct knote *kn) { - struct pipe *cpipe = (struct pipe *)kn->kn_fp->f_data; + struct pipe *cpipe; + + get_mplock(); + cpipe = (struct pipe *)kn->kn_fp->f_data; switch (kn->kn_filter) { case EVFILT_READ: @@ -1381,9 +1428,11 @@ pipe_kqfilter(struct file *fp, struct knote *kn) case EVFILT_WRITE: kn->kn_fop = &pipe_wfiltops; cpipe = cpipe->pipe_peer; - if (cpipe == NULL) + if (cpipe == NULL) { /* other end of pipe has been closed */ + rel_mplock(); return (EPIPE); + } break; default: return (1); @@ -1391,6 +1440,7 @@ pipe_kqfilter(struct file *fp, struct knote *kn) kn->kn_hook = (caddr_t)cpipe; SLIST_INSERT_HEAD(&cpipe->pipe_sel.si_note, kn, kn_selnext); + rel_mplock(); return (0); } diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c index 0a2b66a5e8..2ea343e67c 100644 --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -32,7 +32,7 @@ * * @(#)sys_socket.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/kern/sys_socket.c,v 1.28.2.2 2001/02/26 04:23:16 jlemon Exp $ - * $DragonFly: src/sys/kern/sys_socket.c,v 1.9 2006/05/06 02:43:12 dillon Exp $ + * $DragonFly: src/sys/kern/sys_socket.c,v 1.10 2006/05/26 00:33:09 dillon Exp $ */ #include @@ -59,38 +59,58 @@ struct fileops socketops = { soo_stat, soo_close, soo_shutdown }; -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { - struct socket *so = (struct socket *)fp->f_data; + struct socket *so; + int error; - return (so_pru_soreceive(so, NULL, uio, NULL, NULL, NULL)); + get_mplock(); + so = (struct socket *)fp->f_data; + error = so_pru_soreceive(so, NULL, uio, NULL, NULL, NULL); + rel_mplock(); + return (error); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) { - struct socket *so = (struct socket *)fp->f_data; + struct socket *so; + int error; - return (so_pru_sosend(so, NULL, uio, NULL, NULL, 0, uio->uio_td)); + get_mplock(); + so = (struct socket *)fp->f_data; + error = so_pru_sosend(so, NULL, uio, NULL, NULL, 0, uio->uio_td); + rel_mplock(); + return (error); } +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_ioctl(struct file *fp, u_long cmd, caddr_t data, struct ucred *cred) { - struct socket *so = (struct socket *)fp->f_data; + struct socket *so; + int error; - switch (cmd) { + get_mplock(); + so = (struct socket *)fp->f_data; + switch (cmd) { case FIONBIO: if (*(int *)data) so->so_state |= SS_NBIO; else so->so_state &= ~SS_NBIO; - return (0); - + error = 0; + break; case FIOASYNC: if (*(int *)data) { so->so_state |= SS_ASYNC; @@ -101,56 +121,77 @@ soo_ioctl(struct file *fp, u_long cmd, caddr_t data, struct ucred *cred) so->so_rcv.sb_flags &= ~SB_ASYNC; so->so_snd.sb_flags &= ~SB_ASYNC; } - return (0); - + error = 0; + break; case FIONREAD: *(int *)data = so->so_rcv.sb_cc; - return (0); - + error = 0; + break; case FIOSETOWN: - return (fsetown(*(int *)data, &so->so_sigio)); - + error = fsetown(*(int *)data, &so->so_sigio); + break; case FIOGETOWN: *(int *)data = fgetown(so->so_sigio); - return (0); - + error = 0; + break; case SIOCSPGRP: - return (fsetown(-(*(int *)data), &so->so_sigio)); - + error = fsetown(-(*(int *)data), &so->so_sigio); + break; case SIOCGPGRP: *(int *)data = -fgetown(so->so_sigio); - return (0); - + error = 0; + break; case SIOCATMARK: *(int *)data = (so->so_state&SS_RCVATMARK) != 0; - return (0); + error = 0; + break; + default: + /* + * Interface/routing/protocol specific ioctls: + * interface and routing ioctls should have a + * different entry since a socket's unnecessary + */ + if (IOCGROUP(cmd) == 'i') + error = ifioctl(so, cmd, data, cred); + else if (IOCGROUP(cmd) == 'r') + error = rtioctl(cmd, data, cred); + else + error = so_pru_control(so, cmd, data, NULL); + break; } - /* - * Interface/routing/protocol specific ioctls: - * interface and routing ioctls should have a - * different entry since a socket's unnecessary - */ - if (IOCGROUP(cmd) == 'i') - return (ifioctl(so, cmd, data, cred)); - if (IOCGROUP(cmd) == 'r') - return (rtioctl(cmd, data, cred)); - return (so_pru_control(so, cmd, data, NULL)); + rel_mplock(); + return (error); } +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_poll(struct file *fp, int events, struct ucred *cred) { - struct socket *so = (struct socket *)fp->f_data; - return (so_pru_sopoll(so, events, cred)); + struct socket *so; + int error; + + get_mplock(); + so = (struct socket *)fp->f_data; + error = so_pru_sopoll(so, events, cred); + rel_mplock(); + return (error); } +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_stat(struct file *fp, struct stat *ub, struct ucred *cred) { - struct socket *so = (struct socket *)fp->f_data; + struct socket *so; + int error; bzero((caddr_t)ub, sizeof (*ub)); ub->st_mode = S_IFSOCK; + get_mplock(); + so = (struct socket *)fp->f_data; /* * If SS_CANTRCVMORE is set, but there's still data left in the * receive buffer, the socket is still readable. @@ -163,30 +204,44 @@ soo_stat(struct file *fp, struct stat *ub, struct ucred *cred) ub->st_size = so->so_rcv.sb_cc; ub->st_uid = so->so_cred->cr_uid; ub->st_gid = so->so_cred->cr_gid; - return (so_pru_sense(so, ub)); + error = so_pru_sense(so, ub); + rel_mplock(); + return (error); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_close(struct file *fp) { - int error = 0; + int error; + get_mplock(); fp->f_ops = &badfileops; if (fp->f_data) error = soclose((struct socket *)fp->f_data); - fp->f_data = 0; + else + error = 0; + fp->f_data = NULL; + rel_mplock(); return (error); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ int soo_shutdown(struct file *fp, int how) { - int error = 0; + int error; + get_mplock(); if (fp->f_data) error = soshutdown((struct socket *)fp->f_data, how); + else + error = 0; + rel_mplock(); return (error); } diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 7cc4d6c11b..d705d83dc6 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -37,7 +37,7 @@ * * @(#)vfs_vnops.c 8.2 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/vfs_vnops.c,v 1.87.2.13 2002/12/29 18:19:53 dillon Exp $ - * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.39 2006/05/06 02:43:12 dillon Exp $ + * $DragonFly: src/sys/kern/vfs_vnops.c,v 1.40 2006/05/26 00:33:09 dillon Exp $ */ #include @@ -480,7 +480,7 @@ vn_rdwr_inchunks(enum uio_rw rw, struct vnode *vp, caddr_t base, int len, } /* - * File table vnode read routine. + * MPALMOSTSAFE - acquires mplock */ static int vn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) @@ -488,6 +488,7 @@ vn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) struct vnode *vp; int error, ioflag; + get_mplock(); KASSERT(uio->uio_td == curthread, ("uio_td %p is not td %p", uio->uio_td, curthread)); vp = (struct vnode *)fp->f_data; @@ -507,6 +508,7 @@ vn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) fp->f_offset = uio->uio_offset; fp->f_nextoff = uio->uio_offset; VOP_UNLOCK(vp, 0); + rel_mplock(); return (error); } @@ -515,6 +517,8 @@ vn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) * * This bypasses the VOP table and talks directly to the device. Most * filesystems just route to specfs and can make this optimization. + * + * MPALMOSTSAFE - acquires mplock */ static int svn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) @@ -524,19 +528,26 @@ svn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) int error; dev_t dev; + get_mplock(); KASSERT(uio->uio_td == curthread, ("uio_td %p is not td %p", uio->uio_td, curthread)); vp = (struct vnode *)fp->f_data; - if (vp == NULL || vp->v_type == VBAD) - return (EBADF); + if (vp == NULL || vp->v_type == VBAD) { + error = EBADF; + goto done; + } - if ((dev = vp->v_rdev) == NULL) - return (EBADF); + if ((dev = vp->v_rdev) == NULL) { + error = EBADF; + goto done; + } reference_dev(dev); - if (uio->uio_resid == 0) - return (0); + if (uio->uio_resid == 0) { + error = 0; + goto done; + } if ((flags & FOF_OFFSET) == 0) uio->uio_offset = fp->f_offset; @@ -553,11 +564,13 @@ svn_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags) if ((flags & FOF_OFFSET) == 0) fp->f_offset = uio->uio_offset; fp->f_nextoff = uio->uio_offset; +done: + rel_mplock(); return (error); } /* - * File table vnode write routine. + * MPALMOSTSAFE - acquires mplock */ static int vn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) @@ -565,6 +578,7 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) struct vnode *vp; int error, ioflag; + get_mplock(); KASSERT(uio->uio_td == curthread, ("uio_procp %p is not p %p", uio->uio_td, curthread)); vp = (struct vnode *)fp->f_data; @@ -590,6 +604,7 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) fp->f_offset = uio->uio_offset; fp->f_nextoff = uio->uio_offset; VOP_UNLOCK(vp, 0); + rel_mplock(); return (error); } @@ -598,6 +613,8 @@ vn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) * * This bypasses the VOP table and talks directly to the device. Most * filesystems just route to specfs and can make this optimization. + * + * MPALMOSTSAFE - acquires mplock */ static int svn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) @@ -607,18 +624,23 @@ svn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) int error; dev_t dev; + get_mplock(); KASSERT(uio->uio_td == curthread, ("uio_procp %p is not p %p", uio->uio_td, curthread)); vp = (struct vnode *)fp->f_data; - if (vp == NULL || vp->v_type == VBAD) - return (EBADF); + if (vp == NULL || vp->v_type == VBAD) { + error = EBADF; + goto done; + } if (vp->v_type == VREG) bwillwrite(); vp = (struct vnode *)fp->f_data; /* XXX needed? */ - if ((dev = vp->v_rdev) == NULL) - return (EBADF); + if ((dev = vp->v_rdev) == NULL) { + error = EBADF; + goto done; + } reference_dev(dev); if ((flags & FOF_OFFSET) == 0) @@ -642,19 +664,25 @@ svn_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags) if ((flags & FOF_OFFSET) == 0) fp->f_offset = uio->uio_offset; fp->f_nextoff = uio->uio_offset; - +done: + rel_mplock(); return (error); } /* - * File table vnode stat routine. + * MPALMOSTSAFE - acquires mplock */ static int vn_statfile(struct file *fp, struct stat *sb, struct ucred *cred) { - struct vnode *vp = (struct vnode *)fp->f_data; + struct vnode *vp; + int error; - return vn_stat(vp, sb, cred); + get_mplock(); + vp = (struct vnode *)fp->f_data; + error = vn_stat(vp, sb, cred); + rel_mplock(); + return (error); } int @@ -790,7 +818,7 @@ vn_stat(struct vnode *vp, struct stat *sb, struct ucred *cred) } /* - * File table vnode ioctl routine. + * MPALMOSTSAFE - acquires mplock */ static int vn_ioctl(struct file *fp, u_long com, caddr_t data, struct ucred *ucred) @@ -800,18 +828,22 @@ vn_ioctl(struct file *fp, u_long com, caddr_t data, struct ucred *ucred) struct vattr vattr; int error; + get_mplock(); + switch (vp->v_type) { case VREG: case VDIR: if (com == FIONREAD) { - error = VOP_GETATTR(vp, &vattr); - if (error) - return (error); + if ((error = VOP_GETATTR(vp, &vattr)) != 0) + break; *(int *)data = vattr.va_size - fp->f_offset; - return (0); + error = 0; + break; + } + if (com == FIONBIO || com == FIOASYNC) { /* XXX */ + error = 0; /* XXX */ + break; } - if (com == FIONBIO || com == FIOASYNC) /* XXX */ - return (0); /* XXX */ /* fall into ... */ default: #if 0 @@ -821,23 +853,30 @@ vn_ioctl(struct file *fp, u_long com, caddr_t data, struct ucred *ucred) case VCHR: case VBLK: if (com == FIODTYPE) { - if (vp->v_type != VCHR && vp->v_type != VBLK) - return (ENOTTY); + if (vp->v_type != VCHR && vp->v_type != VBLK) { + error = ENOTTY; + break; + } *(int *)data = dev_dflags(vp->v_rdev) & D_TYPEMASK; - return (0); + error = 0; + break; } error = VOP_IOCTL(vp, com, data, fp->f_flag, ucred); if (error == 0 && com == TIOCSCTTY) { struct proc *p = curthread->td_proc; struct session *sess; - if (p == NULL) - return (ENOTTY); + if (p == NULL) { + error = ENOTTY; + break; + } sess = p->p_session; /* Do nothing if reassigning same control tty */ - if (sess->s_ttyvp == vp) - return (0); + if (sess->s_ttyvp == vp) { + error = 0; + break; + } /* Get rid of reference to old control tty */ ovp = sess->s_ttyvp; @@ -846,17 +885,24 @@ vn_ioctl(struct file *fp, u_long com, caddr_t data, struct ucred *ucred) if (ovp) vrele(ovp); } - return (error); + break; } + rel_mplock(); + return (error); } /* - * File table vnode poll routine. + * MPALMOSTSAFE - acquires mplock */ static int vn_poll(struct file *fp, int events, struct ucred *cred) { - return (VOP_POLL(((struct vnode *)fp->f_data), events, cred)); + int error; + + get_mplock(); + error = VOP_POLL(((struct vnode *)fp->f_data), events, cred); + rel_mplock(); + return (error); } /* @@ -895,21 +941,30 @@ debug_vn_lock(struct vnode *vp, int flags, const char *filename, int line) } /* - * File table vnode close routine. + * MPALMOSTSAFE - acquires mplock */ static int vn_closefile(struct file *fp) { - int err; + int error; + get_mplock(); fp->f_ops = &badfileops; - err = vn_close(((struct vnode *)fp->f_data), fp->f_flag); - return(err); + error = vn_close(((struct vnode *)fp->f_data), fp->f_flag); + rel_mplock(); + return(error); } +/* + * MPALMOSTSAFE - acquires mplock + */ static int vn_kqfilter(struct file *fp, struct knote *kn) { + int error; - return (VOP_KQFILTER(((struct vnode *)fp->f_data), kn)); + get_mplock(); + error = VOP_KQFILTER(((struct vnode *)fp->f_data), kn); + rel_mplock(); + return (error); } diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index 7054dc1ceb..d17d2e2202 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -1,5 +1,5 @@ /* $FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.4.2.4 2003/06/03 00:09:02 sam Exp $ */ -/* $DragonFly: src/sys/opencrypto/cryptodev.c,v 1.15 2006/05/22 21:21:23 dillon Exp $ */ +/* $DragonFly: src/sys/opencrypto/cryptodev.c,v 1.16 2006/05/26 00:33:11 dillon Exp $ */ /* $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $ */ /* @@ -114,6 +114,9 @@ static int csefree(struct csession *); static int cryptodev_op(struct csession *, struct crypt_op *); static int cryptodev_key(struct crypt_kop *); +/* + * MPSAFE + */ static int cryptof_rw( struct file *fp, @@ -121,11 +124,12 @@ cryptof_rw( struct ucred *active_cred, int flags) { - return (EIO); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ static int cryptof_ioctl( struct file *fp, @@ -134,7 +138,7 @@ cryptof_ioctl( struct ucred *cred) { struct cryptoini cria, crie; - struct fcrypt *fcr = (struct fcrypt *)fp->f_data; + struct fcrypt *fcr; struct csession *cse; struct session_op *sop; struct crypt_op *cop; @@ -144,6 +148,9 @@ cryptof_ioctl( u_int32_t ses; int error = 0; + get_mplock(); + fcr = (struct fcrypt *)fp->f_data; + switch (cmd) { case CIOCGSESSION: sop = (struct session_op *)data; @@ -175,8 +182,11 @@ cryptof_ioctl( txform = &enc_xform_arc4; break; default: - return (EINVAL); + error = EINVAL; + break; } + if (error) + break; switch (sop->mac) { case 0: @@ -194,8 +204,10 @@ cryptof_ioctl( thash = &auth_hash_hmac_sha2_384; else if (sop->mackeylen == auth_hash_hmac_sha2_512.keysize) thash = &auth_hash_hmac_sha2_512; - else - return (EINVAL); + else { + error = EINVAL; + break; + } break; case CRYPTO_RIPEMD160_HMAC: thash = &auth_hash_hmac_ripemd_160_96; @@ -212,8 +224,11 @@ cryptof_ioctl( thash = &auth_hash_null; break; default: - return (EINVAL); + error = EINVAL; + break; } + if (error) + break; bzero(&crie, sizeof(crie)); bzero(&cria, sizeof(cria)); @@ -279,16 +294,20 @@ bail: case CIOCFSESSION: ses = *(u_int32_t *)data; cse = csefind(fcr, ses); - if (cse == NULL) - return (EINVAL); + if (cse == NULL) { + error = EINVAL; + break; + } csedelete(fcr, cse); error = csefree(cse); break; case CIOCCRYPT: cop = (struct crypt_op *)data; cse = csefind(fcr, cop->ses); - if (cse == NULL) - return (EINVAL); + if (cse == NULL) { + error = EINVAL; + break; + } error = cryptodev_op(cse, cop); break; case CIOCKEY: @@ -299,7 +318,9 @@ bail: break; default: error = EINVAL; + break; } + rel_mplock(); return (error); } @@ -567,14 +588,18 @@ fail: return (error); } -/* ARGSUSED */ +/* + * MPSAFE + */ static int cryptof_poll(struct file *fp, int events, struct ucred *active_cred) { return (0); } -/* ARGSUSED */ +/* + * MPSAFE + */ static int cryptof_kqfilter(struct file *fp, struct knote *kn) { @@ -582,27 +607,35 @@ cryptof_kqfilter(struct file *fp, struct knote *kn) return (0); } -/* ARGSUSED */ +/* + * MPSAFE + */ static int cryptof_stat(struct file *fp, struct stat *sb, struct ucred *cred) { return (EOPNOTSUPP); } -/* ARGSUSED */ +/* + * MPALMOSTSAFE - acquires mplock + */ static int cryptof_close(struct file *fp) { - struct fcrypt *fcr = (struct fcrypt *)fp->f_data; + struct fcrypt *fcr; struct csession *cse; + get_mplock(); + fcr = (struct fcrypt *)fp->f_data; while ((cse = TAILQ_FIRST(&fcr->csessions))) { TAILQ_REMOVE(&fcr->csessions, cse, next); (void)csefree(cse); } - FREE(fcr, M_XDATA); fp->f_data = NULL; - return 0; + rel_mplock(); + + FREE(fcr, M_XDATA); + return (0); } static struct csession * diff --git a/sys/sys/ucred.h b/sys/sys/ucred.h index 441e6ba4f4..4f98b7851e 100644 --- a/sys/sys/ucred.h +++ b/sys/sys/ucred.h @@ -32,7 +32,7 @@ * * @(#)ucred.h 8.4 (Berkeley) 1/9/95 * $FreeBSD: src/sys/sys/ucred.h,v 1.14.2.5 2002/03/09 05:20:25 dd Exp $ - * $DragonFly: src/sys/sys/ucred.h,v 1.7 2006/05/20 02:42:13 dillon Exp $ + * $DragonFly: src/sys/sys/ucred.h,v 1.8 2006/05/26 00:33:13 dillon Exp $ */ #ifndef _SYS_UCRED_H_ @@ -44,6 +44,9 @@ #ifndef _SYS_PARAM_H_ #include #endif +#ifndef _SYS_SPINLOCK_H_ +#include +#endif struct prison; @@ -54,7 +57,7 @@ struct prison; * Only the suser()/suser_cred() function should be used for this. */ struct ucred { - u_int cr_ref; /* reference count */ + int cr_ref; /* reference count */ uid_t cr_uid; /* effective user id */ short cr_ngroups; /* number of groups */ gid_t cr_groups[NGROUPS]; /* groups */ @@ -65,7 +68,7 @@ struct ucred { uid_t cr_svuid; /* Saved effective user id. */ gid_t cr_rgid; /* Real group id. */ gid_t cr_svgid; /* Saved effective group id. */ - int cr_refcnt; /* Number of references. */ + struct spinlock cr_spin; }; #define cr_gid cr_groups[0] #define NOCRED ((struct ucred *)0) /* no credential available */ @@ -95,6 +98,7 @@ struct ucred *cratom (struct ucred **pcr); struct ucred *crcopy (struct ucred *cr); struct ucred *crdup (struct ucred *cr); void crfree (struct ucred *cr); +void crinit (struct ucred *cr); struct ucred *crget (void); struct ucred *crhold (struct ucred *cr); void cru2x (struct ucred *cr, struct xucred *xcr); -- 2.41.0