From 28836b5874b4d176b3acc6cc8b16bccbe5fff5a6 Mon Sep 17 00:00:00 2001 From: royger Date: Wed, 2 Dec 2015 10:23:54 +0000 Subject: MFC r291022: x86/intr: allow mutex recursion in intr_remove_handler Sponsored by: Citrix Systems R&D --- sys/x86/x86/intr_machdep.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'sys') diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c index 9a5e463..cc50321 100644 --- a/sys/x86/x86/intr_machdep.c +++ b/sys/x86/x86/intr_machdep.c @@ -197,19 +197,28 @@ int intr_remove_handler(void *cookie) { struct intsrc *isrc; - int error; + int error, mtx_owned; isrc = intr_handler_source(cookie); error = intr_event_remove_handler(cookie); if (error == 0) { - mtx_lock(&intr_table_lock); + /* + * Recursion is needed here so PICs can remove interrupts + * while resuming. It was previously not possible due to + * intr_resume holding the intr_table_lock and + * intr_remove_handler recursing on it. + */ + mtx_owned = mtx_owned(&intr_table_lock); + if (mtx_owned == 0) + mtx_lock(&intr_table_lock); isrc->is_handlers--; if (isrc->is_handlers == 0) { isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); isrc->is_pic->pic_disable_intr(isrc); } intrcnt_updatename(isrc); - mtx_unlock(&intr_table_lock); + if (mtx_owned == 0) + mtx_unlock(&intr_table_lock); } return (error); } -- cgit v1.1 From b1833e15625d0430c3295929d57b86e1959c9f6b Mon Sep 17 00:00:00 2001 From: royger Date: Wed, 2 Dec 2015 10:26:34 +0000 Subject: MFC r291023: xen/intr: properly dispose event channels on resume Sponsored by: Citrix Systems R&D --- sys/x86/xen/xen_intr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sys') diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c index fd36e68..20ebad5 100644 --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -711,7 +711,10 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled) xen_rebind_virq(isrc); break; default: + intr_remove_handler(isrc->xi_cookie); isrc->xi_cpu = 0; + isrc->xi_type = EVTCHN_TYPE_UNBOUND; + isrc->xi_cookie = NULL; break; } } -- cgit v1.1 From 904bdb8bc249483f4b14b6df43fb361e87b438da Mon Sep 17 00:00:00 2001 From: royger Date: Wed, 2 Dec 2015 12:58:20 +0000 Subject: Revert MFC of r291023: Due to the delta between HEAD and stable/10 event channel code, this fix is not needed on stable/10 and was also causing build issues. Revert it. --- sys/x86/xen/xen_intr.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sys') diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c index 20ebad5..fd36e68 100644 --- a/sys/x86/xen/xen_intr.c +++ b/sys/x86/xen/xen_intr.c @@ -711,10 +711,7 @@ xen_intr_resume(struct pic *unused, bool suspend_cancelled) xen_rebind_virq(isrc); break; default: - intr_remove_handler(isrc->xi_cookie); isrc->xi_cpu = 0; - isrc->xi_type = EVTCHN_TYPE_UNBOUND; - isrc->xi_cookie = NULL; break; } } -- cgit v1.1 From ccce6feaa419fbc5fc1c0f617f6ad974b07a58c4 Mon Sep 17 00:00:00 2001 From: fabient Date: Wed, 2 Dec 2015 17:26:37 +0000 Subject: MFC r291301: The r241129 description was wrong that the scenario is possible only for read locks on pcbs. The same race can happen with write lock semantics as well. The race scenario: - Two threads (1 and 2) locate pcb with writer semantics (INPLOOKUP_WLOCKPCB) and do in_pcbref() on it. - 1 and 2 both drop the inp hash lock. - Another thread (3) grabs the inp hash lock. Then it runs in_pcbfree(), which wlocks the pcb. They must happen faster than 1 or 2 come INP_WLOCK()! - 1 and 2 congest in INP_WLOCK(). - 3 does in_pcbremlists(), drops hash lock, and runs in_pcbrele_wlocked(), which doesn't free the pcb due to two references on it. Then it unlocks the pcb. - 1 (or 2) gets wlock on the pcb, runs in_pcbrele_wlocked(), which doesn't report inp as freed, due to 2 (or 1) still helding extra reference on it. The thread tries to do smth with a disconnected pcb and crashes. Submitted by: emeric.poupon@stormshield.eu Reviewed by: glebius@ Sponsored by: Stormshield Tested by: Cassiano Peixoto, Stormshield --- sys/netinet/in_pcb.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'sys') diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 4e75f13..0b296e0 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1148,8 +1148,17 @@ in_pcbrele_wlocked(struct inpcb *inp) INP_WLOCK_ASSERT(inp); - if (refcount_release(&inp->inp_refcount) == 0) + if (refcount_release(&inp->inp_refcount) == 0) { + /* + * If the inpcb has been freed, let the caller know, even if + * this isn't the last reference. + */ + if (inp->inp_flags2 & INP_FREED) { + INP_WUNLOCK(inp); + return (1); + } return (0); + } KASSERT(inp->inp_socket == NULL, ("%s: inp_socket != NULL", __func__)); -- cgit v1.1 From 68e44b1d7045a500ada4760ebd096f99e1544d2e Mon Sep 17 00:00:00 2001 From: rmacklem Date: Wed, 2 Dec 2015 21:48:34 +0000 Subject: MFC: r291035 The problem report was for a crash that happened when smbfs was trying to do a mount. Given the backtrace, it appears that the crash occurred when smb_vc_create() failed and then called smb_vc_put() with vcp->vc_iod == NULL. smb_vc_put() subsequently called smb_vc_disconnect() with vcp->vc_iod == NULL, causing the crash. This patch adds a check for vcp->vc_iod != NULL in smb_vc_disconnect() to avoid the crash. It also fixes the case in smb_vc_create() where kproc_create() fails so that it destroys the mutexes and sets vcp->vc_iod == NULL before free()'ing the iod structure. --- sys/netsmb/smb_conn.c | 4 +++- sys/netsmb/smb_iod.c | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sys') diff --git a/sys/netsmb/smb_conn.c b/sys/netsmb/smb_conn.c index d58bc72..adc171c 100644 --- a/sys/netsmb/smb_conn.c +++ b/sys/netsmb/smb_conn.c @@ -683,7 +683,9 @@ int smb_vc_disconnect(struct smb_vc *vcp) { - smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT | SMBIOD_EV_SYNC, NULL); + if (vcp->vc_iod != NULL) + smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT | + SMBIOD_EV_SYNC, NULL); return 0; } diff --git a/sys/netsmb/smb_iod.c b/sys/netsmb/smb_iod.c index ae5c6f7..412f816 100644 --- a/sys/netsmb/smb_iod.c +++ b/sys/netsmb/smb_iod.c @@ -690,6 +690,9 @@ smb_iod_create(struct smb_vc *vcp) RFNOWAIT, 0, "smbiod%d", iod->iod_id); if (error) { SMBERROR("can't start smbiod: %d", error); + vcp->vc_iod = NULL; + smb_sl_destroy(&iod->iod_rqlock); + smb_sl_destroy(&iod->iod_evlock); free(iod, M_SMBIOD); return error; } -- cgit v1.1