aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2013-05-03 15:34:15 -0400
committerRobert Love <robert.w.love@intel.com>2013-05-10 13:19:23 -0400
commitfb00cc2353ca22b3278f72d73e65a33486d1dbc7 (patch)
tree2a9d5adb4e83604d9e1ef5a343b0cfa7d64fd5aa
parent732bdb9d141879b1b5b357f934553fe827c1f46b (diff)
libfc: extend ex_lock to protect all of fc_seq_send
This warning was reported recently: WARNING: at drivers/scsi/libfc/fc_exch.c:478 fc_seq_send+0x14f/0x160 [libfc]() (Not tainted) Hardware name: ProLiant DL120 G7 Modules linked in: tcm_fc target_core_iblock target_core_file target_core_pscsi target_core_mod configfs dm_round_robin dm_multipath 8021q garp stp llc bnx2fc cnic uio fcoe libfcoe libfc scsi_transport_fc scsi_tgt autofs4 sunrpc pcc_cpufreq ipv6 hpilo hpwdt e1000e microcode iTCO_wdt iTCO_vendor_support serio_raw shpchp ixgbe dca mdio sg ext4 mbcache jbd2 sd_mod crc_t10dif pata_acpi ata_generic ata_piix hpsa dm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan] Pid: 5464, comm: target_completi Not tainted 2.6.32-272.el6.x86_64 #1 Call Trace: [<ffffffff8106b747>] ? warn_slowpath_common+0x87/0xc0 [<ffffffff8106b79a>] ? warn_slowpath_null+0x1a/0x20 [<ffffffffa025f7df>] ? fc_seq_send+0x14f/0x160 [libfc] [<ffffffffa035cbce>] ? ft_queue_status+0x16e/0x210 [tcm_fc] [<ffffffffa030a660>] ? target_complete_ok_work+0x0/0x4b0 [target_core_mod] [<ffffffffa030a766>] ? target_complete_ok_work+0x106/0x4b0 [target_core_mod] [<ffffffffa030a660>] ? target_complete_ok_work+0x0/0x4b0 [target_core_mod] [<ffffffff8108c760>] ? worker_thread+0x170/0x2a0 [<ffffffff810920d0>] ? autoremove_wake_function+0x0/0x40 [<ffffffff8108c5f0>] ? worker_thread+0x0/0x2a0 [<ffffffff81091d66>] ? kthread+0x96/0xa0 [<ffffffff8100c14a>] ? child_rip+0xa/0x20 [<ffffffff81091cd0>] ? kthread+0x0/0xa0 [<ffffffff8100c140>] ? child_rip+0x0/0x20 It occurs because fc_seq_send can have multiple contexts executing within it at the same time, and fc_seq_send doesn't consistently use the ep->ex_lock that protects this structure. Because of that, its possible for one context to clear the INIT bit in the ep->esb_state field while another checks it, leading to the above stack trace generated by the WARN_ON in the function. We should probably undertake the effort to convert access to the fc_exch structures to use rcu, but that a larger work item. To just fix this specific issue, we can just extend the ex_lock protection through the entire fc_seq_send path Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Reported-by: Gris Ge <fge@redhat.com> CC: Robert Love <robert.w.love@intel.com> Signed-off-by: Robert Love <robert.w.love@intel.com>
-rw-r--r--drivers/scsi/libfc/fc_exch.c37
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index c772d8d27159..8b928c67e4b9 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -463,13 +463,7 @@ static void fc_exch_delete(struct fc_exch *ep)
463 fc_exch_release(ep); /* drop hold for exch in mp */ 463 fc_exch_release(ep); /* drop hold for exch in mp */
464} 464}
465 465
466/** 466static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp,
467 * fc_seq_send() - Send a frame using existing sequence/exchange pair
468 * @lport: The local port that the exchange will be sent on
469 * @sp: The sequence to be sent
470 * @fp: The frame to be sent on the exchange
471 */
472static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
473 struct fc_frame *fp) 467 struct fc_frame *fp)
474{ 468{
475 struct fc_exch *ep; 469 struct fc_exch *ep;
@@ -479,7 +473,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
479 u8 fh_type = fh->fh_type; 473 u8 fh_type = fh->fh_type;
480 474
481 ep = fc_seq_exch(sp); 475 ep = fc_seq_exch(sp);
482 WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); 476 WARN_ON(!(ep->esb_stat & ESB_ST_SEQ_INIT));
483 477
484 f_ctl = ntoh24(fh->fh_f_ctl); 478 f_ctl = ntoh24(fh->fh_f_ctl);
485 fc_exch_setup_hdr(ep, fp, f_ctl); 479 fc_exch_setup_hdr(ep, fp, f_ctl);
@@ -502,17 +496,34 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
502 error = lport->tt.frame_send(lport, fp); 496 error = lport->tt.frame_send(lport, fp);
503 497
504 if (fh_type == FC_TYPE_BLS) 498 if (fh_type == FC_TYPE_BLS)
505 return error; 499 goto out;
506 500
507 /* 501 /*
508 * Update the exchange and sequence flags, 502 * Update the exchange and sequence flags,
509 * assuming all frames for the sequence have been sent. 503 * assuming all frames for the sequence have been sent.
510 * We can only be called to send once for each sequence. 504 * We can only be called to send once for each sequence.
511 */ 505 */
512 spin_lock_bh(&ep->ex_lock);
513 ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */ 506 ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */
514 if (f_ctl & FC_FC_SEQ_INIT) 507 if (f_ctl & FC_FC_SEQ_INIT)
515 ep->esb_stat &= ~ESB_ST_SEQ_INIT; 508 ep->esb_stat &= ~ESB_ST_SEQ_INIT;
509out:
510 return error;
511}
512
513/**
514 * fc_seq_send() - Send a frame using existing sequence/exchange pair
515 * @lport: The local port that the exchange will be sent on
516 * @sp: The sequence to be sent
517 * @fp: The frame to be sent on the exchange
518 */
519static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
520 struct fc_frame *fp)
521{
522 struct fc_exch *ep;
523 int error;
524 ep = fc_seq_exch(sp);
525 spin_lock_bh(&ep->ex_lock);
526 error = fc_seq_send_locked(lport, sp, fp);
516 spin_unlock_bh(&ep->ex_lock); 527 spin_unlock_bh(&ep->ex_lock);
517 return error; 528 return error;
518} 529}
@@ -629,7 +640,7 @@ static int fc_exch_abort_locked(struct fc_exch *ep,
629 if (fp) { 640 if (fp) {
630 fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid, 641 fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid,
631 FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); 642 FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
632 error = fc_seq_send(ep->lp, sp, fp); 643 error = fc_seq_send_locked(ep->lp, sp, fp);
633 } else 644 } else
634 error = -ENOBUFS; 645 error = -ENOBUFS;
635 return error; 646 return error;
@@ -1132,7 +1143,7 @@ static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp,
1132 f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; 1143 f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT;
1133 f_ctl |= ep->f_ctl; 1144 f_ctl |= ep->f_ctl;
1134 fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0); 1145 fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0);
1135 fc_seq_send(ep->lp, sp, fp); 1146 fc_seq_send_locked(ep->lp, sp, fp);
1136} 1147}
1137 1148
1138/** 1149/**
@@ -1307,8 +1318,8 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
1307 ap->ba_low_seq_cnt = htons(sp->cnt); 1318 ap->ba_low_seq_cnt = htons(sp->cnt);
1308 } 1319 }
1309 sp = fc_seq_start_next_locked(sp); 1320 sp = fc_seq_start_next_locked(sp);
1310 spin_unlock_bh(&ep->ex_lock);
1311 fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS); 1321 fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS);
1322 spin_unlock_bh(&ep->ex_lock);
1312 fc_frame_free(rx_fp); 1323 fc_frame_free(rx_fp);
1313 return; 1324 return;
1314 1325