procfs - Fix blocked lock condition
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 5 Aug 2017 04:47:23 +0000 (21:47 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 6 Aug 2017 01:06:08 +0000 (18:06 -0700)
* Two procfs races can result in a lock being blocked forever.  Rip out
  the old single-variable global procfs lock and per-node lock and replace
  with a normal lockmgr lock.

* The original lock existed from a time when all of procfs was wrapped with
  a global lock.  This is no longer the case.

sys/vfs/procfs/procfs.h
sys/vfs/procfs/procfs_subr.c

index 105adb9..8ffd2b5 100644 (file)
@@ -70,7 +70,7 @@ struct pfsnode {
        u_short         pfs_mode;       /* mode bits for stat() */
        u_long          pfs_flags;      /* open flags */
        u_long          pfs_fileno;     /* unique file id */
-       pid_t           pfs_lockowner;  /* pfs lock owner */
+       struct lock     pfs_lock;       /* pfs locked */
 };
 
 #define PROCFS_NOTELEN 64      /* max length of a note (/proc/$pid/note) */
@@ -153,9 +153,6 @@ struct proc *pfs_pfind(pid_t);
 struct proc *pfs_zpfind(pid_t);
 void pfs_pdone(struct proc *);
 
-#define PROCFS_LOCKED  0x01
-#define PROCFS_WANT    0x02
-
 #define PFS_DEAD        0x80000000     /* or'd with pid */
 
 int    procfs_root (struct mount *, struct vnode **);
index 60f4b29..5b5f761 100644 (file)
@@ -50,7 +50,7 @@
 #define PFS_HMASK      (PFS_HSIZE - 1)
 
 static struct pfsnode *pfshead[PFS_HSIZE];
-static int pfsvplock;
+static struct lock     procfslk = LOCK_INITIALIZER("pvplk", 0, 0);
 
 #define PFSHASH(pid)   &pfshead[(pid) & PFS_HMASK]
 
@@ -124,12 +124,8 @@ loop:
         * otherwise lock the vp list while we call getnewvnode
         * since that can block.
         */
-       if (pfsvplock & PROCFS_LOCKED) {
-               pfsvplock |= PROCFS_WANT;
-               (void) tsleep((caddr_t) &pfsvplock, 0, "pfsavp", 0);
+       if (lockmgr(&procfslk, LK_EXCLUSIVE|LK_SLEEPFAIL))
                goto loop;
-       }
-       pfsvplock |= PROCFS_LOCKED;
 
        /*
         * Do the MALLOC before the getnewvnode since doing so afterward
@@ -155,8 +151,8 @@ loop:
        pfs->pfs_type = pfs_type;
        pfs->pfs_vnode = vp;
        pfs->pfs_flags = 0;
-       pfs->pfs_lockowner = 0;
        pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
+       lockinit(&pfs->pfs_lock, "pfslk", 0, 0);
 
        switch (pfs_type) {
        case Proot:     /* /proc = dr-xr-xr-x */
@@ -227,12 +223,7 @@ loop:
        *pp = pfs;
 
 out:
-       pfsvplock &= ~PROCFS_LOCKED;
-
-       if (pfsvplock & PROCFS_WANT) {
-               pfsvplock &= ~PROCFS_WANT;
-               wakeup((caddr_t) &pfsvplock);
-       }
+       lockmgr(&procfslk, LK_RELEASE);
 
        return (error);
 }
@@ -357,10 +348,7 @@ procfs_rw(struct vop_read_args *ap)
        lp = FIRST_LWP_IN_PROC(p);
        LWPHOLD(lp);
 
-       while (pfs->pfs_lockowner) {
-               tsleep(&pfs->pfs_lockowner, 0, "pfslck", 0);
-       }
-       pfs->pfs_lockowner = curproc->p_pid;
+       lockmgr(&pfs->pfs_lock, LK_EXCLUSIVE);
 
        switch (pfs->pfs_type) {
        case Pnote:
@@ -414,9 +402,7 @@ procfs_rw(struct vop_read_args *ap)
        }
        LWPRELE(lp);
 
-       pfs->pfs_lockowner = 0;
-       wakeup(&pfs->pfs_lockowner);
-
+       lockmgr(&pfs->pfs_lock, LK_RELEASE);
 out:
        pfs_pdone(p);