X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/94ff46dc2849db4d43eaaf144872decc522aafb4..ea3f04195ba4a5034c9c8e9b726d4f7ce96f1832:/bsd/kern/kern_control.c diff --git a/bsd/kern/kern_control.c b/bsd/kern/kern_control.c index e41d1f103..5430ff820 100644 --- a/bsd/kern/kern_control.c +++ b/bsd/kern/kern_control.c @@ -85,6 +85,14 @@ struct kctl { u_int32_t lastunit; }; +#if DEVELOPMENT || DEBUG +enum ctl_status { + KCTL_DISCONNECTED = 0, + KCTL_CONNECTING = 1, + KCTL_CONNECTED = 2 +}; +#endif /* DEVELOPMENT || DEBUG */ + struct ctl_cb { TAILQ_ENTRY(ctl_cb) next; /* controller chain */ lck_mtx_t *mtx; @@ -94,6 +102,10 @@ struct ctl_cb { struct sockaddr_ctl sac; u_int32_t usecount; u_int32_t kcb_usecount; + u_int32_t require_clearing_count; +#if DEVELOPMENT || DEBUG + enum ctl_status status; +#endif /* DEVELOPMENT || DEBUG */ }; #ifndef ROUNDUP64 @@ -225,6 +237,12 @@ u_int32_t ctl_debug = 0; SYSCTL_INT(_net_systm_kctl, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_debug, 0, ""); +#if DEVELOPMENT || DEBUG +u_int32_t ctl_panic_debug = 0; +SYSCTL_INT(_net_systm_kctl, OID_AUTO, panicdebug, + CTLFLAG_RW | CTLFLAG_LOCKED, &ctl_panic_debug, 0, ""); +#endif /* DEVELOPMENT || DEBUG */ + #define KCTL_TBL_INC 16 static uintptr_t kctl_tbl_size = 0; @@ -353,24 +371,45 @@ ctl_sofreelastref(struct socket *so) } /* - * Use this function to serialize calls into the kctl subsystem + * Use this function and ctl_kcb_require_clearing to serialize + * critical calls into the kctl subsystem */ static void ctl_kcb_increment_use_count(struct ctl_cb *kcb, lck_mtx_t *mutex_held) { LCK_MTX_ASSERT(mutex_held, LCK_MTX_ASSERT_OWNED); - while (kcb->kcb_usecount > 0) { + while (kcb->require_clearing_count > 0) { + msleep(&kcb->require_clearing_count, mutex_held, PSOCK | PCATCH, "kcb_require_clearing", NULL); + } + kcb->kcb_usecount++; +} + +static void +ctl_kcb_require_clearing(struct ctl_cb *kcb, lck_mtx_t *mutex_held) +{ + assert(kcb->kcb_usecount != 0); + kcb->require_clearing_count++; + kcb->kcb_usecount--; + while (kcb->kcb_usecount > 0) { // we need to wait until no one else is running msleep(&kcb->kcb_usecount, mutex_held, PSOCK | PCATCH, "kcb_usecount", NULL); } kcb->kcb_usecount++; } static void -clt_kcb_decrement_use_count(struct ctl_cb *kcb) +ctl_kcb_done_clearing(struct ctl_cb *kcb) +{ + assert(kcb->require_clearing_count != 0); + kcb->require_clearing_count--; + wakeup((caddr_t)&kcb->require_clearing_count); +} + +static void +ctl_kcb_decrement_use_count(struct ctl_cb *kcb) { assert(kcb->kcb_usecount != 0); kcb->kcb_usecount--; - wakeup_one((caddr_t)&kcb->kcb_usecount); + wakeup((caddr_t)&kcb->kcb_usecount); } static int @@ -384,6 +423,7 @@ ctl_detach(struct socket *so) lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK); ctl_kcb_increment_use_count(kcb, mtx_held); + ctl_kcb_require_clearing(kcb, mtx_held); if (kcb->kctl != NULL && kcb->kctl->bind != NULL && kcb->userdata != NULL && !(so->so_state & SS_ISCONNECTED)) { @@ -398,8 +438,12 @@ ctl_detach(struct socket *so) } soisdisconnected(so); +#if DEVELOPMENT || DEBUG + kcb->status = KCTL_DISCONNECTED; +#endif /* DEVELOPMENT || DEBUG */ so->so_flags |= SOF_PCBCLEARING; - clt_kcb_decrement_use_count(kcb); + ctl_kcb_done_clearing(kcb); + ctl_kcb_decrement_use_count(kcb); return 0; } @@ -526,6 +570,9 @@ ctl_setup_kctl(struct socket *so, struct sockaddr *nam, struct proc *p) done: if (error) { soisdisconnected(so); +#if DEVELOPMENT || DEBUG + kcb->status = KCTL_DISCONNECTED; +#endif /* DEVELOPMENT || DEBUG */ lck_mtx_lock(ctl_mtx); TAILQ_REMOVE(&kctl->kcb_head, kcb, next); kcb->kctl = NULL; @@ -550,6 +597,7 @@ ctl_bind(struct socket *so, struct sockaddr *nam, struct proc *p) lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK); ctl_kcb_increment_use_count(kcb, mtx_held); + ctl_kcb_require_clearing(kcb, mtx_held); error = ctl_setup_kctl(so, nam, p); if (error) { @@ -570,7 +618,8 @@ ctl_bind(struct socket *so, struct sockaddr *nam, struct proc *p) socket_lock(so, 0); out: - clt_kcb_decrement_use_count(kcb); + ctl_kcb_done_clearing(kcb); + ctl_kcb_decrement_use_count(kcb); return error; } @@ -586,6 +635,14 @@ ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p) lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK); ctl_kcb_increment_use_count(kcb, mtx_held); + ctl_kcb_require_clearing(kcb, mtx_held); + +#if DEVELOPMENT || DEBUG + if (kcb->status != KCTL_DISCONNECTED && ctl_panic_debug) { + panic("kctl already connecting/connected"); + } + kcb->status = KCTL_CONNECTING; +#endif /* DEVELOPMENT || DEBUG */ error = ctl_setup_kctl(so, nam, p); if (error) { @@ -604,6 +661,9 @@ ctl_connect(struct socket *so, struct sockaddr *nam, struct proc *p) goto end; } soisconnected(so); +#if DEVELOPMENT || DEBUG + kcb->status = KCTL_CONNECTED; +#endif /* DEVELOPMENT || DEBUG */ end: if (error && kcb->kctl->disconnect) { @@ -622,6 +682,9 @@ end: } if (error) { soisdisconnected(so); +#if DEVELOPMENT || DEBUG + kcb->status = KCTL_DISCONNECTED; +#endif /* DEVELOPMENT || DEBUG */ lck_mtx_lock(ctl_mtx); TAILQ_REMOVE(&kcb->kctl->kcb_head, kcb, next); kcb->kctl = NULL; @@ -632,7 +695,8 @@ end: lck_mtx_unlock(ctl_mtx); } out: - clt_kcb_decrement_use_count(kcb); + ctl_kcb_done_clearing(kcb); + ctl_kcb_decrement_use_count(kcb); return error; } @@ -644,6 +708,7 @@ ctl_disconnect(struct socket *so) if ((kcb = (struct ctl_cb *)so->so_pcb)) { lck_mtx_t *mtx_held = socket_getlock(so, PR_F_WILLUNLOCK); ctl_kcb_increment_use_count(kcb, mtx_held); + ctl_kcb_require_clearing(kcb, mtx_held); struct kctl *kctl = kcb->kctl; if (kctl && kctl->disconnect) { @@ -654,6 +719,9 @@ ctl_disconnect(struct socket *so) } soisdisconnected(so); +#if DEVELOPMENT || DEBUG + kcb->status = KCTL_DISCONNECTED; +#endif /* DEVELOPMENT || DEBUG */ socket_unlock(so, 0); lck_mtx_lock(ctl_mtx); @@ -667,7 +735,8 @@ ctl_disconnect(struct socket *so) kctlstat.kcs_gencnt++; lck_mtx_unlock(ctl_mtx); socket_lock(so, 0); - clt_kcb_decrement_use_count(kcb); + ctl_kcb_done_clearing(kcb); + ctl_kcb_decrement_use_count(kcb); } return 0; } @@ -759,7 +828,7 @@ ctl_usr_rcvd(struct socket *so, int flags) ctl_sbrcv_trim(so); out: - clt_kcb_decrement_use_count(kcb); + ctl_kcb_decrement_use_count(kcb); return error; } @@ -803,7 +872,7 @@ ctl_send(struct socket *so, int flags, struct mbuf *m, if (error != 0) { OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_send_fail); } - clt_kcb_decrement_use_count(kcb); + ctl_kcb_decrement_use_count(kcb); return error; } @@ -867,7 +936,7 @@ ctl_send_list(struct socket *so, int flags, struct mbuf *m, if (error != 0) { OSIncrementAtomic64((SInt64 *)&kctlstat.kcs_send_list_fail); } - clt_kcb_decrement_use_count(kcb); + ctl_kcb_decrement_use_count(kcb); return error; } @@ -1376,7 +1445,7 @@ ctl_ctloutput(struct socket *so, struct sockopt *sopt) } out: - clt_kcb_decrement_use_count(kcb); + ctl_kcb_decrement_use_count(kcb); return error; }