Allow the kernel to be compile without KTRACE option.
[dragonfly.git] / sys / kern / sys_generic.c
index af8b687..5403dec 100644 (file)
@@ -68,7 +68,9 @@
 #endif
 #include <vm/vm.h>
 #include <vm/vm_page.h>
+
 #include <sys/file2.h>
+#include <sys/mplock2.h>
 
 #include <machine/limits.h>
 
@@ -82,8 +84,8 @@ static int    doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex,
 static int     pollscan (struct proc *, struct pollfd *, u_int, int *);
 static int     selscan (struct proc *, fd_mask **, fd_mask **,
                        int, int *);
-static int     dofileread(int, struct file *, struct uio *, int, int *);
-static int     dofilewrite(int, struct file *, struct uio *, int, int *);
+static int     dofileread(int, struct file *, struct uio *, int, size_t *);
+static int     dofilewrite(int, struct file *, struct uio *, int, size_t *);
 
 /*
  * Read system call.
@@ -98,6 +100,9 @@ sys_read(struct read_args *uap)
        struct iovec aiov;
        int error;
 
+       if ((ssize_t)uap->nbyte < 0)
+               error = EINVAL;
+
        aiov.iov_base = uap->buf;
        aiov.iov_len = uap->nbyte;
        auio.uio_iov = &aiov;
@@ -108,10 +113,7 @@ sys_read(struct read_args *uap)
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_td = td;
 
-       if (auio.uio_resid < 0)
-               error = EINVAL;
-       else
-               error = kern_preadv(uap->fd, &auio, 0, &uap->sysmsg_result);
+       error = kern_preadv(uap->fd, &auio, 0, &uap->sysmsg_szresult);
        return(error);
 }
 
@@ -129,6 +131,9 @@ sys_extpread(struct extpread_args *uap)
        int error;
        int flags;
 
+       if ((ssize_t)uap->nbyte < 0)
+               return(EINVAL);
+
        aiov.iov_base = uap->buf;
        aiov.iov_len = uap->nbyte;
        auio.uio_iov = &aiov;
@@ -143,10 +148,7 @@ sys_extpread(struct extpread_args *uap)
        if (uap->offset != (off_t)-1)
                flags |= O_FOFFSET;
 
-       if (auio.uio_resid < 0)
-               error = EINVAL;
-       else
-               error = kern_preadv(uap->fd, &auio, flags, &uap->sysmsg_result);
+       error = kern_preadv(uap->fd, &auio, flags, &uap->sysmsg_szresult);
        return(error);
 }
 
@@ -174,7 +176,7 @@ sys_readv(struct readv_args *uap)
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_td = td;
 
-       error = kern_preadv(uap->fd, &auio, 0, &uap->sysmsg_result);
+       error = kern_preadv(uap->fd, &auio, 0, &uap->sysmsg_szresult);
 
        iovec_free(&iov, aiov);
        return (error);
@@ -210,7 +212,7 @@ sys_extpreadv(struct extpreadv_args *uap)
        if (uap->offset != (off_t)-1)
                flags |= O_FOFFSET;
 
-       error = kern_preadv(uap->fd, &auio, flags, &uap->sysmsg_result);
+       error = kern_preadv(uap->fd, &auio, flags, &uap->sysmsg_szresult);
 
        iovec_free(&iov, aiov);
        return(error);
@@ -220,7 +222,7 @@ sys_extpreadv(struct extpreadv_args *uap)
  * MPSAFE
  */
 int
-kern_preadv(int fd, struct uio *auio, int flags, int *res)
+kern_preadv(int fd, struct uio *auio, int flags, size_t *res)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
@@ -234,8 +236,6 @@ kern_preadv(int fd, struct uio *auio, int flags, int *res)
                return (EBADF);
        if (flags & O_FOFFSET && fp->f_type != DTYPE_VNODE) {
                error = ESPIPE;
-       } else if (auio->uio_resid < 0) {
-               error = EINVAL;
        } else {
                error = dofileread(fd, fp, auio, flags, res);
        }
@@ -250,12 +250,12 @@ kern_preadv(int fd, struct uio *auio, int flags, int *res)
  * MPALMOSTSAFE - ktrace needs help
  */
 static int
-dofileread(int fd, struct file *fp, struct uio *auio, int flags, int *res)
+dofileread(int fd, struct file *fp, struct uio *auio, int flags, size_t *res)
 {
-       struct thread *td = curthread;
        int error;
-       int len;
+       size_t len;
 #ifdef KTRACE
+       struct thread *td = curthread;
        struct iovec *ktriov = NULL;
        struct uio ktruio;
 #endif
@@ -310,6 +310,9 @@ sys_write(struct write_args *uap)
        struct iovec aiov;
        int error;
 
+       if ((ssize_t)uap->nbyte < 0)
+               error = EINVAL;
+
        aiov.iov_base = (void *)(uintptr_t)uap->buf;
        aiov.iov_len = uap->nbyte;
        auio.uio_iov = &aiov;
@@ -320,10 +323,7 @@ sys_write(struct write_args *uap)
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_td = td;
 
-       if (auio.uio_resid < 0)
-               error = EINVAL;
-       else
-               error = kern_pwritev(uap->fd, &auio, 0, &uap->sysmsg_result);
+       error = kern_pwritev(uap->fd, &auio, 0, &uap->sysmsg_szresult);
 
        return(error);
 }
@@ -342,6 +342,9 @@ sys_extpwrite(struct extpwrite_args *uap)
        int error;
        int flags;
 
+       if ((ssize_t)uap->nbyte < 0)
+               error = EINVAL;
+
        aiov.iov_base = (void *)(uintptr_t)uap->buf;
        aiov.iov_len = uap->nbyte;
        auio.uio_iov = &aiov;
@@ -355,12 +358,7 @@ sys_extpwrite(struct extpwrite_args *uap)
        flags = uap->flags & O_FMASK;
        if (uap->offset != (off_t)-1)
                flags |= O_FOFFSET;
-
-       if (auio.uio_resid < 0)
-               error = EINVAL;
-       else
-               error = kern_pwritev(uap->fd, &auio, flags, &uap->sysmsg_result);
-
+       error = kern_pwritev(uap->fd, &auio, flags, &uap->sysmsg_szresult);
        return(error);
 }
 
@@ -386,7 +384,7 @@ sys_writev(struct writev_args *uap)
        auio.uio_segflg = UIO_USERSPACE;
        auio.uio_td = td;
 
-       error = kern_pwritev(uap->fd, &auio, 0, &uap->sysmsg_result);
+       error = kern_pwritev(uap->fd, &auio, 0, &uap->sysmsg_szresult);
 
        iovec_free(&iov, aiov);
        return (error);
@@ -422,7 +420,7 @@ sys_extpwritev(struct extpwritev_args *uap)
        if (uap->offset != (off_t)-1)
                flags |= O_FOFFSET;
 
-       error = kern_pwritev(uap->fd, &auio, flags, &uap->sysmsg_result);
+       error = kern_pwritev(uap->fd, &auio, flags, &uap->sysmsg_szresult);
 
        iovec_free(&iov, aiov);
        return(error);
@@ -432,7 +430,7 @@ sys_extpwritev(struct extpwritev_args *uap)
  * MPSAFE
  */
 int
-kern_pwritev(int fd, struct uio *auio, int flags, int *res)
+kern_pwritev(int fd, struct uio *auio, int flags, size_t *res)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
@@ -461,12 +459,12 @@ kern_pwritev(int fd, struct uio *auio, int flags, int *res)
  * MPALMOSTSAFE - ktrace needs help
  */
 static int
-dofilewrite(int fd, struct file *fp, struct uio *auio, int flags, int *res)
+dofilewrite(int fd, struct file *fp, struct uio *auio, int flags, size_t *res)
 {      
        struct thread *td = curthread;
        struct lwp *lp = td->td_lwp;
        int error;
-       int len;
+       size_t len;
 #ifdef KTRACE
        struct iovec *ktriov = NULL;
        struct uio ktruio;
@@ -517,12 +515,18 @@ dofilewrite(int fd, struct file *fp, struct uio *auio, int flags, int *res)
 
 /*
  * Ioctl system call
+ *
+ * MPALMOSTSAFE
  */
-/* ARGSUSED */
 int
 sys_ioctl(struct ioctl_args *uap)
 {
-       return(mapped_ioctl(uap->fd, uap->com, uap->data, NULL));
+       int error;
+
+       get_mplock();
+       error = mapped_ioctl(uap->fd, uap->com, uap->data, NULL, &uap->sysmsg);
+       rel_mplock();
+       return (error);
 }
 
 struct ioctl_map_entry {
@@ -537,7 +541,8 @@ struct ioctl_map_entry {
  * and appropriate conversions/conversion functions will be utilized.
  */
 int
-mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map)
+mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map,
+            struct sysmsg *msg)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
@@ -556,7 +561,7 @@ mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map)
        } ubuf;
 
        KKASSERT(p);
-       cred = p->p_ucred;
+       cred = td->td_ucred;
 
        fp = holdfp(p->p_fd, fd, FREAD|FWRITE);
        if (fp == NULL)
@@ -653,7 +658,7 @@ mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map)
        }
        if ((com & IOC_IN) != 0) {
                if (size != 0) {
-                       error = copyin(uspc_data, data, (u_int)size);
+                       error = copyin(uspc_data, data, (size_t)size);
                        if (error) {
                                if (memp != NULL)
                                        kfree(memp, M_IOCTLOPS);
@@ -667,7 +672,7 @@ mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map)
                 * Zero the buffer so the user always
                 * gets back something deterministic.
                 */
-               bzero(data, size);
+               bzero(data, (size_t)size);
        } else if ((com & IOC_VOID) != 0) {
                *(caddr_t *)data = uspc_data;
        }
@@ -686,7 +691,7 @@ mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map)
                        fp->f_flag |= FASYNC;
                else
                        fp->f_flag &= ~FASYNC;
-               error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, cred);
+               error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, cred, msg);
                break;
 
        default:
@@ -697,13 +702,13 @@ mapped_ioctl(int fd, u_long com, caddr_t uspc_data, struct ioctl_map *map)
                if (map != NULL && iomc->wrapfunc != NULL)
                        error = iomc->wrapfunc(fp, com, ocom, data, cred);
                else
-                       error = fo_ioctl(fp, com, data, cred);
+                       error = fo_ioctl(fp, com, data, cred, msg);
                /*
                 * Copy any data to user, size was
                 * already set and checked above.
                 */
                if (error == 0 && (com & IOC_OUT) != 0 && size != 0)
-                       error = copyout(data, uspc_data, (u_int)size);
+                       error = copyout(data, uspc_data, (size_t)size);
                break;
        }
        if (memp != NULL)
@@ -754,6 +759,8 @@ SYSCTL_INT(_kern, OID_AUTO, nselcoll, CTLFLAG_RD, &nselcoll, 0, "");
 
 /*
  * Select system call.
+ *
+ * MPALMOSTSAFE
  */
 int
 sys_select(struct select_args *uap)
@@ -780,8 +787,10 @@ sys_select(struct select_args *uap)
        /*
         * Do real work.
         */
+       get_mplock();
        error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
                        &uap->sysmsg_result);
+       rel_mplock();
 
        return (error);
 }
@@ -789,6 +798,8 @@ sys_select(struct select_args *uap)
 
 /*
  * Pselect system call.
+ *
+ * MPALMOSTSAFE
  */
 int
 sys_pselect(struct pselect_args *uap)
@@ -826,9 +837,12 @@ sys_pselect(struct pselect_args *uap)
                error = copyin(uap->sigmask, &sigmask, sizeof(sigmask));
                if (error)
                        return (error);
+               get_mplock();
                lp->lwp_oldsigmask = lp->lwp_sigmask;
                SIG_CANTMASK(sigmask);
                lp->lwp_sigmask = sigmask;
+       } else {
+               get_mplock();
        }
 
        /*
@@ -855,6 +869,7 @@ sys_pselect(struct pselect_args *uap)
                        lp->lwp_sigmask = lp->lwp_oldsigmask;
                }
        }
+       rel_mplock();
 
        return (error);
 }
@@ -959,15 +974,15 @@ retry:
                    24 * 60 * 60 * hz : tvtohz_high(&ttv);
        }
        crit_enter();
+       tsleep_interlock(&selwait, PCATCH);
        if ((lp->lwp_flag & LWP_SELECT) == 0 || nselcoll != ncoll) {
                crit_exit();
                goto retry;
        }
        lp->lwp_flag &= ~LWP_SELECT;
-
-       error = tsleep((caddr_t)&selwait, PCATCH, "select", timo);
-       
+       error = tsleep(&selwait, PCATCH | PINTERLOCKED, "select", timo);
        crit_exit();
+
        if (error == 0)
                goto retry;
 done:
@@ -1030,6 +1045,8 @@ selscan(struct proc *p, fd_mask **ibits, fd_mask **obits, int nfd, int *res)
 
 /*
  * Poll system call.
+ *
+ * MPALMOSTSAFE
  */
 int
 sys_poll(struct poll_args *uap)
@@ -1060,13 +1077,13 @@ sys_poll(struct poll_args *uap)
                bits = smallbits;
        error = copyin(uap->fds, bits, ni);
        if (error)
-               goto done;
+               goto done2;
        if (uap->timeout != INFTIM) {
                atv.tv_sec = uap->timeout / 1000;
                atv.tv_usec = (uap->timeout % 1000) * 1000;
                if (itimerfix(&atv)) {
                        error = EINVAL;
-                       goto done;
+                       goto done2;
                }
                getmicrouptime(&rtv);
                timevaladd(&atv, &rtv);
@@ -1075,32 +1092,37 @@ sys_poll(struct poll_args *uap)
                atv.tv_usec = 0;
        }
        timo = 0;
+       get_mplock();
 retry:
        ncoll = nselcoll;
        lp->lwp_flag |= LWP_SELECT;
        error = pollscan(p, bits, nfds, &uap->sysmsg_result);
        if (error || uap->sysmsg_result)
-               goto done;
+               goto done1;
        if (atv.tv_sec || atv.tv_usec) {
                getmicrouptime(&rtv);
                if (timevalcmp(&rtv, &atv, >=))
-                       goto done;
+                       goto done1;
                ttv = atv;
                timevalsub(&ttv, &rtv);
                timo = ttv.tv_sec > 24 * 60 * 60 ?
                    24 * 60 * 60 * hz : tvtohz_high(&ttv);
        } 
        crit_enter();
+       tsleep_interlock(&selwait, PCATCH);
        if ((lp->lwp_flag & LWP_SELECT) == 0 || nselcoll != ncoll) {
                crit_exit();
                goto retry;
        }
        lp->lwp_flag &= ~LWP_SELECT;
-       error = tsleep((caddr_t)&selwait, PCATCH, "poll", timo);
+       error = tsleep(&selwait, PCATCH | PINTERLOCKED, "poll", timo);
        crit_exit();
+
        if (error == 0)
                goto retry;
-done:
+done1:
+       rel_mplock();
+done2:
        lp->lwp_flag &= ~LWP_SELECT;
        /* poll is not restarted after signals... */
        if (error == ERESTART)
@@ -1156,6 +1178,8 @@ pollscan(struct proc *p, struct pollfd *fds, u_int nfd, int *res)
 /*
  * OpenBSD poll system call.
  * XXX this isn't quite a true representation..  OpenBSD uses select ops.
+ *
+ * MPSAFE
  */
 int
 sys_openbsd_poll(struct openbsd_poll_args *uap)
@@ -1220,8 +1244,16 @@ selwakeup(struct selinfo *sip)
        if (lp == NULL)
                return;
 
+       /*
+        * This is a temporary hack until the code can be rewritten.
+        * Check LWP_SELECT before assuming we can setrunnable().
+        * Otherwise we might catch the lwp before it actually goes to
+        * sleep.
+        */
        crit_enter();
-       if (lp->lwp_wchan == (caddr_t)&selwait) {
+       if (lp->lwp_flag & LWP_SELECT) {
+               lp->lwp_flag &= ~LWP_SELECT;
+       } else if (lp->lwp_wchan == (caddr_t)&selwait) {
                /*
                 * Flag the process to break the tsleep when
                 * setrunnable is called, but only call setrunnable
@@ -1230,8 +1262,6 @@ selwakeup(struct selinfo *sip)
                lp->lwp_flag |= LWP_BREAKTSLEEP;
                if (p->p_stat != SSTOP)
                        setrunnable(lp);
-       } else if (lp->lwp_flag & LWP_SELECT) {
-               lp->lwp_flag &= ~LWP_SELECT;
        }
        crit_exit();
 }