Forgot to release lock in pppx_del_session() error case...

Index: sys/net/if_pppx.c
===================================================================
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.81
diff -u -p -r1.81 if_pppx.c
--- sys/net/if_pppx.c   7 Apr 2020 07:11:22 -0000       1.81
+++ sys/net/if_pppx.c   7 Apr 2020 14:39:28 -0000
@@ -170,7 +170,8 @@ RBT_HEAD(pppx_ifs, pppx_if) pppx_ifs = R
 RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
 
 int            pppx_if_next_unit(void);
-struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
+struct pppx_if *pppx_if_find_locked(struct pppx_dev *, int, int);
+static inline struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
 int            pppx_add_session(struct pppx_dev *,
                    struct pipex_session_req *);
 int            pppx_del_session(struct pppx_dev *,
@@ -594,8 +595,19 @@ pppxclose(dev_t dev, int flags, int mode
 
        /* XXX */
        NET_LOCK();
-       while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
+       rw_enter_write(&pppx_ifs_lk);
+       while ((pxi = LIST_FIRST(&pxd->pxd_pxis))) {
+               if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
+                       panic("%s: pppx_ifs modified while lock was held",
+                               __func__);
+               LIST_REMOVE(pxi, pxi_list);
+               rw_exit_write(&pppx_ifs_lk);
+               
                pppx_if_destroy(pxd, pxi);
+               
+               rw_enter_write(&pppx_ifs_lk);
+       }
+       rw_exit_write(&pppx_ifs_lk);
        NET_UNLOCK();
 
        LIST_REMOVE(pxd, pxd_entry);
@@ -641,24 +653,37 @@ pppx_if_next_unit(void)
 }
 
 struct pppx_if *
-pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
+pppx_if_find_locked(struct pppx_dev *pxd, int session_id, int protocol)
 {
        struct pppx_if *s, *p;
+
+       rw_assert_anylock(&pppx_ifs_lk);
+
        s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
 
        s->pxi_key.pxik_session_id = session_id;
        s->pxi_key.pxik_protocol = protocol;
 
-       rw_enter_read(&pppx_ifs_lk);
        p = RBT_FIND(pppx_ifs, &pppx_ifs, s);
        if (p && p->pxi_ready == 0)
                p = NULL;
-       rw_exit_read(&pppx_ifs_lk);
 
        free(s, M_DEVBUF, sizeof(*s));
        return (p);
 }
 
+static inline struct pppx_if *
+pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
+{
+       struct pppx_if *pxi;
+
+       rw_enter_read(&pppx_ifs_lk);
+       pxi = pppx_if_find_locked(pxd, session_id, protocol);
+       rw_exit_read(&pppx_ifs_lk);
+
+       return pxi;
+}
+
 int
 pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
 {
@@ -948,14 +973,24 @@ pppx_del_session(struct pppx_dev *pxd, s
 {
        struct pppx_if *pxi;
 
-       pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
-       if (pxi == NULL)
+       rw_enter_write(&pppx_ifs_lk);
+       pxi = pppx_if_find_locked(pxd, req->pcr_session_id,
+           req->pcr_protocol);
+       if (pxi == NULL) {
+               rw_exit_write(&pppx_ifs_lk);
                return (EINVAL);
+       }
+
+       if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
+               panic("%s: pppx_ifs modified while lock was held", __func__);
+       LIST_REMOVE(pxi, pxi_list);
+       rw_exit_write(&pppx_ifs_lk);
 
        req->pcr_stat = pxi->pxi_session.stat;
 
        pppx_if_destroy(pxd, pxi);
-       return (0);
+
+       return 0;
 }
 
 int
@@ -1037,12 +1072,6 @@ pppx_if_destroy(struct pppx_dev *pxd, st
        NET_UNLOCK();
        if_detach(ifp);
        NET_LOCK();
-
-       rw_enter_write(&pppx_ifs_lk);
-       if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
-               panic("%s: pppx_ifs modified while lock was held", __func__);
-       LIST_REMOVE(pxi, pxi_list);
-       rw_exit_write(&pppx_ifs_lk);
 
        pool_put(pppx_if_pl, pxi);
 }

Reply via email to