linprocfs - Fix process exit / procfs vnode access race & stepping races
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 24 Aug 2012 00:00:49 +0000 (17:00 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 24 Aug 2012 00:00:49 +0000 (17:00 -0700)
* Taken from procfs, fix exit / vnode access races

* Fix stepping races.

sys/emulation/linux/i386/linprocfs/linprocfs.h
sys/emulation/linux/i386/linprocfs/linprocfs_subr.c
sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c

index aba5d72..33d3aaa 100644 (file)
@@ -167,6 +167,8 @@ int linprocfs_validfile (struct proc *);
 #define PROCFS_LOCKED  0x01
 #define PROCFS_WANT    0x02
 
 #define PROCFS_LOCKED  0x01
 #define PROCFS_WANT    0x02
 
+#define PFS_DEAD        0x80000000     /* or'd with pid */
+
 int    linprocfs_root (struct mount *, struct vnode **);
 int    linprocfs_rw (struct vop_read_args *);
 #endif /* _KERNEL */
 int    linprocfs_root (struct mount *, struct vnode **);
 int    linprocfs_rw (struct vop_read_args *);
 #endif /* _KERNEL */
index d2db8e3..6ad4d68 100644 (file)
@@ -456,7 +456,7 @@ restart:
                if (pfs->pfs_pid == pid) {
                        vp = PFSTOV(pfs);
                        vx_get(vp);
                if (pfs->pfs_pid == pid) {
                        vp = PFSTOV(pfs);
                        vx_get(vp);
-                       vgone_vxlocked(vp);
+                       pfs->pfs_pid |= PFS_DEAD;
                        vx_put(vp);
                        goto restart;
                }
                        vx_put(vp);
                        goto restart;
                }
index cc41daa..ff2d48c 100644 (file)
@@ -244,8 +244,10 @@ linprocfs_close(struct vop_close_args *ap)
                if ((ap->a_vp->v_opencount < 2)
                    && (p = linprocfs_pfind(pfs->pfs_pid))
                    && !(p->p_pfsflags & PF_LINGER)) {
                if ((ap->a_vp->v_opencount < 2)
                    && (p = linprocfs_pfind(pfs->pfs_pid))
                    && !(p->p_pfsflags & PF_LINGER)) {
+                       spin_lock(&p->p_spin);
                        p->p_stops = 0;
                        p->p_step = 0;
                        p->p_stops = 0;
                        p->p_step = 0;
+                       spin_unlock(&p->p_spin);
                        wakeup(&p->p_stype);
                }
                if (p)
                        wakeup(&p->p_stype);
                }
                if (p)
@@ -302,22 +304,27 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
          *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags;
        case PIOCSTATUS:
          psp = (struct procfs_status *)ap->a_data;
          *(unsigned int*)ap->a_data = (unsigned int)procp->p_pfsflags;
        case PIOCSTATUS:
          psp = (struct procfs_status *)ap->a_data;
-         psp->state = (procp->p_step == 0);
          psp->flags = procp->p_pfsflags;
          psp->events = procp->p_stops;
          psp->flags = procp->p_pfsflags;
          psp->events = procp->p_stops;
+         spin_lock(&procp->p_spin);
          if (procp->p_step) {
          if (procp->p_step) {
+           psp->state = 0;
            psp->why = procp->p_stype;
            psp->val = procp->p_xstat;
            psp->why = procp->p_stype;
            psp->val = procp->p_xstat;
+           spin_unlock(&procp->p_spin);
          } else {
          } else {
-           psp->why = psp->val = 0;    /* Not defined values */
+           psp->state = 1;
+           spin_unlock(&procp->p_spin);
+           psp->why = 0;       /* Not defined values */
+           psp->val = 0;       /* Not defined values */
          }
          break;
        case PIOCWAIT:
          psp = (struct procfs_status *)ap->a_data;
          spin_lock(&procp->p_spin);
          if (procp->p_step == 0) {
          }
          break;
        case PIOCWAIT:
          psp = (struct procfs_status *)ap->a_data;
          spin_lock(&procp->p_spin);
          if (procp->p_step == 0) {
-           spin_unlock(&procp->p_spin);
            tsleep_interlock(&procp->p_stype, PCATCH);
            tsleep_interlock(&procp->p_stype, PCATCH);
+           spin_unlock(&procp->p_spin);
            if (procp->p_stops == 0) {
                error = EINVAL;
                goto done;
            if (procp->p_stops == 0) {
                error = EINVAL;
                goto done;
@@ -404,8 +411,10 @@ linprocfs_bmap(struct vop_bmap_args *ap)
 static int
 linprocfs_inactive(struct vop_inactive_args *ap)
 {
 static int
 linprocfs_inactive(struct vop_inactive_args *ap)
 {
-       /*struct vnode *vp = ap->a_vp;*/
+       struct pfsnode *pfs = VTOPFS(ap->a_vp);
 
 
+       if (pfs->pfs_pid & PFS_DEAD)
+               vrecycle(ap->a_vp);
        return (0);
 }
 
        return (0);
 }