diff options
author | Bart Van Assche <bart.vanassche@sandisk.com> | 2015-06-05 17:20:46 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Odin.com> | 2015-08-12 14:23:30 -0400 |
commit | f6979adeaab578f8ca14fdd32b06ddee0d9d3314 (patch) | |
tree | 81261d86cae0460cb67d6a085631c15c5528776d | |
parent | 660d0831d1494a6837b2f810d08b5be092c1f31d (diff) |
libfc: Fix fc_exch_recv_req() error path
Due to patch "libfc: Do not invoke the response handler after
fc_exch_done()" (commit ID 7030fd62) the lport_recv() call
in fc_exch_recv_req() is passed a dangling pointer. Avoid this
by moving the fc_frame_free() call from fc_invoke_resp() to its
callers. This patch fixes the following crash:
general protection fault: 0000 [#3] PREEMPT SMP
RIP: fc_lport_recv_req+0x72/0x280 [libfc]
Call Trace:
fc_exch_recv+0x642/0xde0 [libfc]
fcoe_percpu_receive_thread+0x46a/0x5ed [fcoe]
kthread+0x10a/0x120
ret_from_fork+0x42/0x70
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 1b3a09473452..30f9ef0c0d4f 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -733,8 +733,6 @@ static bool fc_invoke_resp(struct fc_exch *ep, struct fc_seq *sp, | |||
733 | if (resp) { | 733 | if (resp) { |
734 | resp(sp, fp, arg); | 734 | resp(sp, fp, arg); |
735 | res = true; | 735 | res = true; |
736 | } else if (!IS_ERR(fp)) { | ||
737 | fc_frame_free(fp); | ||
738 | } | 736 | } |
739 | 737 | ||
740 | spin_lock_bh(&ep->ex_lock); | 738 | spin_lock_bh(&ep->ex_lock); |
@@ -1596,7 +1594,8 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
1596 | * If new exch resp handler is valid then call that | 1594 | * If new exch resp handler is valid then call that |
1597 | * first. | 1595 | * first. |
1598 | */ | 1596 | */ |
1599 | fc_invoke_resp(ep, sp, fp); | 1597 | if (!fc_invoke_resp(ep, sp, fp)) |
1598 | fc_frame_free(fp); | ||
1600 | 1599 | ||
1601 | fc_exch_release(ep); | 1600 | fc_exch_release(ep); |
1602 | return; | 1601 | return; |
@@ -1695,7 +1694,8 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) | |||
1695 | fc_exch_hold(ep); | 1694 | fc_exch_hold(ep); |
1696 | if (!rc) | 1695 | if (!rc) |
1697 | fc_exch_delete(ep); | 1696 | fc_exch_delete(ep); |
1698 | fc_invoke_resp(ep, sp, fp); | 1697 | if (!fc_invoke_resp(ep, sp, fp)) |
1698 | fc_frame_free(fp); | ||
1699 | if (has_rec) | 1699 | if (has_rec) |
1700 | fc_exch_timer_set(ep, ep->r_a_tov); | 1700 | fc_exch_timer_set(ep, ep->r_a_tov); |
1701 | fc_exch_release(ep); | 1701 | fc_exch_release(ep); |