Commit d576a5e8 authored by Neil Horman's avatar Neil Horman Committed by Christoph Hellwig

bnx2fc: Improve stats update mechanism

Recently had this warning reported:

[  290.489047] Call Trace:
[  290.489053]  [<ffffffff8169efec>] dump_stack+0x19/0x1b
[  290.489055]  [<ffffffff810ac7a9>] __might_sleep+0x179/0x230
[  290.489057]  [<ffffffff816a4ad5>] mutex_lock_nested+0x55/0x520
[  290.489061]  [<ffffffffa01b9905>] ? bnx2fc_l2_rcv_thread+0xc5/0x4c0 [bnx2fc]
[  290.489065]  [<ffffffffa0174c1a>] fc_vport_id_lookup+0x3a/0xa0 [libfc]
[  290.489068]  [<ffffffffa01b9a6c>] bnx2fc_l2_rcv_thread+0x22c/0x4c0 [bnx2fc]
[  290.489070]  [<ffffffffa01b9840>] ? bnx2fc_vport_destroy+0x110/0x110 [bnx2fc]
[  290.489073]  [<ffffffff8109e0cd>] kthread+0xed/0x100
[  290.489075]  [<ffffffff8109dfe0>] ? insert_kthread_work+0x80/0x80
[  290.489077]  [<ffffffff816b2fec>] ret_from_fork+0x7c/0xb0
[  290.489078]  [<ffffffff8109dfe0>] ? insert_kthread_work+0x80/0x80

Its due to the fact that we call a potentially sleeping function from the bnx2fc
rcv path with preemption disabled (via the get_cpu call embedded in the per-cpu
variable stats lookup in bnx2fc_l2_rcv_thread.

Easy enough fix, we can just move the stats collection later in the function
where we are sure we won't preempt or sleep.  This also allows us to not have to
enable pre-emption when doing a per-cpu lookup, since we're certain not to get
rescheduled.
Signed-off-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Acked-by: default avatarEddie Wai <eddie.wai@broadcom.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 9172b763
...@@ -516,23 +516,17 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) ...@@ -516,23 +516,17 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
skb_pull(skb, sizeof(struct fcoe_hdr)); skb_pull(skb, sizeof(struct fcoe_hdr));
fr_len = skb->len - sizeof(struct fcoe_crc_eof); fr_len = skb->len - sizeof(struct fcoe_crc_eof);
stats = per_cpu_ptr(lport->stats, get_cpu());
stats->RxFrames++;
stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
fp = (struct fc_frame *)skb; fp = (struct fc_frame *)skb;
fc_frame_init(fp); fc_frame_init(fp);
fr_dev(fp) = lport; fr_dev(fp) = lport;
fr_sof(fp) = hp->fcoe_sof; fr_sof(fp) = hp->fcoe_sof;
if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) {
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
fr_eof(fp) = crc_eof.fcoe_eof; fr_eof(fp) = crc_eof.fcoe_eof;
fr_crc(fp) = crc_eof.fcoe_crc32; fr_crc(fp) = crc_eof.fcoe_crc32;
if (pskb_trim(skb, fr_len)) { if (pskb_trim(skb, fr_len)) {
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
...@@ -544,7 +538,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) ...@@ -544,7 +538,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
port = lport_priv(vn_port); port = lport_priv(vn_port);
if (!ether_addr_equal(port->data_src_addr, dest_mac)) { if (!ether_addr_equal(port->data_src_addr, dest_mac)) {
BNX2FC_HBA_DBG(lport, "fpma mismatch\n"); BNX2FC_HBA_DBG(lport, "fpma mismatch\n");
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
...@@ -552,7 +545,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) ...@@ -552,7 +545,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA &&
fh->fh_type == FC_TYPE_FCP) { fh->fh_type == FC_TYPE_FCP) {
/* Drop FCP data. We dont this in L2 path */ /* Drop FCP data. We dont this in L2 path */
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
...@@ -562,7 +554,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) ...@@ -562,7 +554,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
case ELS_LOGO: case ELS_LOGO:
if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) {
/* drop non-FIP LOGO */ /* drop non-FIP LOGO */
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
...@@ -572,22 +563,23 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) ...@@ -572,22 +563,23 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
if (fh->fh_r_ctl == FC_RCTL_BA_ABTS) { if (fh->fh_r_ctl == FC_RCTL_BA_ABTS) {
/* Drop incoming ABTS */ /* Drop incoming ABTS */
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
stats = per_cpu_ptr(lport->stats, smp_processor_id());
stats->RxFrames++;
stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
if (le32_to_cpu(fr_crc(fp)) != if (le32_to_cpu(fr_crc(fp)) !=
~crc32(~0, skb->data, fr_len)) { ~crc32(~0, skb->data, fr_len)) {
if (stats->InvalidCRCCount < 5) if (stats->InvalidCRCCount < 5)
printk(KERN_WARNING PFX "dropping frame with " printk(KERN_WARNING PFX "dropping frame with "
"CRC error\n"); "CRC error\n");
stats->InvalidCRCCount++; stats->InvalidCRCCount++;
put_cpu();
kfree_skb(skb); kfree_skb(skb);
return; return;
} }
put_cpu();
fc_exch_recv(lport, fp); fc_exch_recv(lport, fp);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment