Print this page
OS-5518 devpoll write feigns success in the face of EINTR
OS-5520 epoll_ctl not allowed to emit EINTR
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
OS-5516 vmxnet3s declares wrong sdu
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Approved by: Bryan Cantrill <bryan@joyent.com>
OS-5511 epoll should not leave dangling polldat_t entries
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Bryan Cantrill <bryan@joyent.com>
OS-5260 lxbrand epoll_pwait needs sigset translation
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>

@@ -351,12 +351,13 @@
                                  */
                                 if (is_epoll) {
                                         pdp->pd_fp = NULL;
                                         pdp->pd_events = 0;
 
-                                        if (php != NULL) {
-                                                pollhead_delete(php, pdp);
+                                        if (pdp->pd_php != NULL) {
+                                                pollhead_delete(pdp->pd_php,
+                                                    pdp);
                                                 pdp->pd_php = NULL;
                                         }
 
                                         BT_CLEAR(pcp->pc_bitmap, fd);
                                         continue;

@@ -501,12 +502,13 @@
                                  */
                                 if (pdp->pd_events & POLLONESHOT) {
                                         pdp->pd_fp = NULL;
                                         pdp->pd_events = 0;
 
-                                        if (php != NULL) {
-                                                pollhead_delete(php, pdp);
+                                        if (pdp->pd_php != NULL) {
+                                                pollhead_delete(pdp->pd_php,
+                                                    pdp);
                                                 pdp->pd_php = NULL;
                                         }
 
                                         BT_CLEAR(pcp->pc_bitmap, fd);
                                 }

@@ -637,10 +639,11 @@
         pollfd_t        *pollfdp, *pfdp;
         dvpoll_epollfd_t *epfdp;
         uintptr_t       limit;
         int             error, size;
         ssize_t         uiosize;
+        size_t          copysize;
         nfds_t          pollfdnum;
         struct pollhead *php = NULL;
         polldat_t       *pdp;
         int             fd;
         file_t          *fp;

@@ -702,15 +705,23 @@
          * not supposed to function as a seekable device. To prevent offset
          * from growing and eventually exceed the maximum, reset the offset
          * here for every call.
          */
         uiop->uio_loffset = 0;
-        if ((error = uiomove((caddr_t)pollfdp, uiosize, UIO_WRITE, uiop))
-            != 0) {
+
+        /*
+         * Use uiocopy instead of uiomove when populating pollfdp, keeping
+         * uio_resid untouched for now.  Write syscalls will translate EINTR
+         * into a success if they detect "successfully transfered" data via an
+         * updated uio_resid.  Falsely suppressing such errors is disastrous.
+         */
+        if ((error = uiocopy((caddr_t)pollfdp, uiosize, UIO_WRITE, uiop,
+            &copysize)) != 0) {
                 kmem_free(pollfdp, uiosize);
                 return (error);
         }
+
         /*
          * We are about to enter the core portion of dpwrite(). Make sure this
          * write has exclusive access in this portion of the code, i.e., no
          * other writers in this code.
          *

@@ -979,10 +990,17 @@
         dpep->dpe_flag &= ~DP_WRITER_PRESENT;
         dpep->dpe_refcnt--;
         cv_broadcast(&dpep->dpe_cv);
         mutex_exit(&dpep->dpe_lock);
         kmem_free(pollfdp, uiosize);
+        if (error == 0) {
+                /*
+                 * The state of uio_resid is updated only after the pollcache
+                 * is successfully modified.
+                 */
+                uioskip(uiop, copysize);
+        }
         return (error);
 }
 
 #define DP_SIGMASK_RESTORE(ksetp) {                                     \
         if (ksetp != NULL) {                                            \

@@ -1121,17 +1139,21 @@
 
                 if (cmd == DP_PPOLL) {
                         void *setp = STRUCT_FGETP(dvpoll, dp_setp);
 
                         if (setp != NULL) {
+                                if ((mode & FKIOCTL) != 0) {
+                                        /* Use the signal set directly */
+                                        ksetp = (k_sigset_t *)setp;
+                                } else {
                                 if (copyin(setp, &set, sizeof (set))) {
                                         DP_REFRELE(dpep);
                                         return (EFAULT);
                                 }
-
                                 sigutok(&set, &kset);
                                 ksetp = &kset;
+                                }
 
                                 mutex_enter(&p->p_lock);
                                 schedctl_finish_sigblock(t);
                                 lwp->lwp_sigoldmask = t->t_hold;
                                 t->t_hold = *ksetp;

@@ -1277,10 +1299,14 @@
                 pollstate_exit(pcp);
 
                 DP_SIGMASK_RESTORE(ksetp);
 
                 if (error == 0 && fdcnt > 0) {
+                        /*
+                         * It should be noted that FKIOCTL does not influence
+                         * the copyout (vs bcopy) of dp_fds at this time.
+                         */
                         if (copyout(ps->ps_dpbuf,
                             STRUCT_FGETP(dvpoll, dp_fds), fdcnt * fdsize)) {
                                 DP_REFRELE(dpep);
                                 return (EFAULT);
                         }