From c0866286f10964e61ec10c8c605ef86e65fbbd38 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Sat, 3 Aug 2013 10:45:53 +0000 Subject: fcoe: ensure that skb placed on the fip_recv_list are unshared Recently had this Oops reported to me on the 3.10 kernel: [ 807.554955] BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 [ 807.562799] IP: [] skb_dequeue+0x47/0x70 [ 807.568296] PGD 20c889067 PUD 20c8b8067 PMD 0 [ 807.572769] Oops: 0002 [#1] SMP [ 807.655597] Hardware name: Dell Inc. PowerEdge R415/0DDT2D, BIOS 1.8.6 12/06/2011 [ 807.663079] Workqueue: events fcoe_ctlr_recv_work [libfcoe] [ 807.668656] task: ffff88020b42a160 ti: ffff88020ae6c000 task.ti: ffff88020ae6c000 [ 807.676126] RIP: 0010:[] [] skb_dequeue+0x47/0x70 [ 807.684046] RSP: 0000:ffff88020ae6dd70 EFLAGS: 00010097 [ 807.689349] RAX: 0000000000000246 RBX: ffff8801d04d6700 RCX: 0000000000000000 [ 807.696474] RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff88020df26434 [ 807.703598] RBP: ffff88020ae6dd88 R08: 00000000000173e0 R09: ffff880216e173e0 [ 807.710723] R10: ffffffff814e5897 R11: ffffea0007413580 R12: ffff88020df26420 [ 807.717847] R13: ffff88020df26434 R14: 0000000000000004 R15: ffff8801d04c42ce [ 807.724972] FS: 00007fdaab6048c0(0000) GS:ffff880216e00000(0000) knlGS:0000000000000000 [ 807.733049] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 807.738785] CR2: 0000000000000008 CR3: 000000020cbc9000 CR4: 00000000000006f0 [ 807.745910] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 807.753033] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 807.760156] Stack: [ 807.762162] ffff8801d04d6700 0000000000000001 ffff88020df26400 ffff88020ae6de20 [ 807.769586] ffffffffa0444409 ffff88020b046a00 ffff88020ae6dde8 ffffffff810105be [ 807.777008] ffff88020b42a868 0000000000000000 ffff88020df264a8 ffff88020df26348 [ 807.784431] Call Trace: [ 807.786885] [] fcoe_ctlr_recv_work+0x59/0x9a0 [libfcoe] [ 807.793755] [] ? __switch_to+0x13e/0x4a0 [ 807.799324] [] process_one_work+0x176/0x420 [ 807.805151] [] worker_thread+0x11b/0x3a0 [ 807.810717] [] ? rescuer_thread+0x350/0x350 [ 807.816545] [] kthread+0xc0/0xd0 [ 807.821416] [] ? insert_kthread_work+0x40/0x40 [ 807.827503] [] ret_from_fork+0x7c/0xb0 [ 807.832897] [] ? insert_kthread_work+0x40/0x40 [ 807.858500] RIP [] skb_dequeue+0x47/0x70 [ 807.864076] RSP [ 807.867558] CR2: 0000000000000008 Looks like the root cause is the fact that the packet recieve function fcoe_ctlr_recv enqueues the skb to a sk_buff_head_list prior to ensuring that the skb is unshared. This can happen when multiple packet listeners recieve an skb, as the deliver_skb function just increments skb->users for each handler. As a result, having multiple users of a single skb results in multiple manipulators of its methods, implying list corruption, and the oops recorded above. The fix is pretty easy, just make sure that we clone the skb if its got multiple users with the skb_share_check function, like other protocols do. Signed-off-by: Neil Horman Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe_ctlr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 203415e0251..35b1fb73bd6 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1453,6 +1453,9 @@ err: */ void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) { + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return; skb_queue_tail(&fip->fip_recv_list, skb); schedule_work(&fip->recv_work); } -- cgit v1.2.3-70-g09d2 From 8b6124345207e4c2141bed78f1bf7c4f526a6d19 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Sat, 3 Aug 2013 10:45:54 +0000 Subject: fcoe: make sure fcoe frames are unshared prior to manipulating them Based on my last patch I noticed that fcoe_rcv has a simmilar problem, in that it manipulates the passed in skb without checking to see if it has other users. Making manipulations to a shared skb can result in various corruptions. Easy fix, just make sure the skb is unshared prior to doing anything with it. Signed-off-by: Neil Horman Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 07453bbf05e..f9b0302f9ba 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1452,6 +1452,12 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, skb_tail_pointer(skb), skb_end_pointer(skb), skb->csum, skb->dev ? skb->dev->name : ""); + + skb = skb_share_check(skb, GFP_ATOMIC); + + if (skb == NULL) + return NET_RX_DROP; + eh = eth_hdr(skb); if (is_fip_mode(ctlr) && -- cgit v1.2.3-70-g09d2 From 34bac2ef5981666261fcf6932f4cd718b820323f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Sat, 3 Aug 2013 10:45:55 +0000 Subject: fcoe: cleanup return codes from fcoe_rcv the return codes from fcoe_rcv should be NET_RX_*, not 0 or -1. Signed-off-by: Neil Horman Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index f9b0302f9ba..134ca3b471b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1546,13 +1546,13 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, wake_up_process(fps->thread); spin_unlock(&fps->fcoe_rx_list.lock); - return 0; + return NET_RX_SUCCESS; err: per_cpu_ptr(lport->stats, get_cpu())->ErrorFrames++; put_cpu(); err2: kfree_skb(skb); - return -1; + return NET_RX_DROP; } /** -- cgit v1.2.3-70-g09d2 From 41463a8851cd334341d143fbed558fa0c2e6865b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Aug 2013 15:41:22 +0000 Subject: fcoe: Declare fcoe_ctlr_mode_set() static The function fcoe_ctlr_mode_set() is local, hence declare it static. Signed-off-by: Bart Van Assche Cc: Neil Horman Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe_ctlr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 35b1fb73bd6..9e83a790aa6 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -2828,8 +2828,8 @@ unlock: * disabled, so that should ensure that this routine is only called * when nothing is happening. */ -void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip, - enum fip_state fip_mode) +static void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip, + enum fip_state fip_mode) { void *priv; -- cgit v1.2.3-70-g09d2 From 465b87bfe96a5b257804fd89aa982319e8c58064 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Aug 2013 15:42:09 +0000 Subject: fcoe: Add missing newlines in debug messages FCoE debug statements must end in a newline. Add one where it is missing. Signed-off-by: Bart Van Assche Cc: Neil Horman Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe.c | 12 ++++++------ drivers/scsi/fcoe/fcoe_sysfs.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 134ca3b471b..dff40b2fccb 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1440,14 +1440,14 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, ctlr = fcoe_to_ctlr(fcoe); lport = ctlr->lp; if (unlikely(!lport)) { - FCOE_NETDEV_DBG(netdev, "Cannot find hba structure"); + FCOE_NETDEV_DBG(netdev, "Cannot find hba structure\n"); goto err2; } if (!lport->link_up) goto err2; - FCOE_NETDEV_DBG(netdev, "skb_info: len:%d data_len:%d head:%p " - "data:%p tail:%p end:%p sum:%d dev:%s", + FCOE_NETDEV_DBG(netdev, + "skb_info: len:%d data_len:%d head:%p data:%p tail:%p end:%p sum:%d dev:%s\n", skb->len, skb->data_len, skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->csum, skb->dev ? skb->dev->name : ""); @@ -1794,13 +1794,13 @@ static void fcoe_recv_frame(struct sk_buff *skb) lport = fr->fr_dev; if (unlikely(!lport)) { if (skb->destructor != fcoe_percpu_flush_done) - FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb"); + FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb\n"); kfree_skb(skb); return; } - FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d " - "head:%p data:%p tail:%p end:%p sum:%d dev:%s", + FCOE_NETDEV_DBG(skb->dev, + "skb_info: len:%d data_len:%d head:%p data:%p tail:%p end:%p sum:%d dev:%s\n", skb->len, skb->data_len, skb->head, skb->data, skb_tail_pointer(skb), skb_end_pointer(skb), skb->csum, diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index c9382d6eee7..922c9deeb24 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -300,29 +300,29 @@ static ssize_t store_ctlr_mode(struct device *dev, switch (ctlr->enabled) { case FCOE_CTLR_ENABLED: - LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled."); + LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled.\n"); return -EBUSY; case FCOE_CTLR_DISABLED: if (!ctlr->f->set_fcoe_ctlr_mode) { LIBFCOE_SYSFS_DBG(ctlr, - "Mode change not supported by LLD."); + "Mode change not supported by LLD.\n"); return -ENOTSUPP; } ctlr->mode = fcoe_parse_mode(mode); if (ctlr->mode == FIP_CONN_TYPE_UNKNOWN) { - LIBFCOE_SYSFS_DBG(ctlr, - "Unknown mode %s provided.", buf); + LIBFCOE_SYSFS_DBG(ctlr, "Unknown mode %s provided.\n", + buf); return -EINVAL; } ctlr->f->set_fcoe_ctlr_mode(ctlr); - LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.", buf); + LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.\n", buf); return count; case FCOE_CTLR_UNUSED: default: - LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported."); + LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.\n"); return -ENOTSUPP; }; } -- cgit v1.2.3-70-g09d2 From 1c2c1b4fbd413fd814807768d2aba9023722ed76 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 14 Aug 2013 15:42:46 +0000 Subject: fcoe: Reduce fcoe_sysfs_fcf_add() stack usage This patch fixes the following compiler warning: drivers/scsi/fcoe/fcoe_ctlr.c: In function fcoe_sysfs_fcf_add: drivers/scsi/fcoe/fcoe_ctlr.c:211:1: warning: the frame size of 1480 bytes is larger than 1024 bytes [-Wframe-larger-than=] Signed-off-by: Bart Van Assche Cc: Neil Horman Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe_ctlr.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 9e83a790aa6..692c6535fe7 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -164,28 +164,30 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) { struct fcoe_ctlr *fip = new->fip; struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); - struct fcoe_fcf_device temp, *fcf_dev; - int rc = 0; + struct fcoe_fcf_device *temp, *fcf_dev; + int rc = -ENOMEM; LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n", new->fabric_name, new->fcf_mac); + temp = kzalloc(sizeof(*temp), GFP_KERNEL); + if (!temp) + goto out; + mutex_lock(&ctlr_dev->lock); - temp.fabric_name = new->fabric_name; - temp.switch_name = new->switch_name; - temp.fc_map = new->fc_map; - temp.vfid = new->vfid; - memcpy(temp.mac, new->fcf_mac, ETH_ALEN); - temp.priority = new->pri; - temp.fka_period = new->fka_period; - temp.selected = 0; /* default to unselected */ - - fcf_dev = fcoe_fcf_device_add(ctlr_dev, &temp); - if (unlikely(!fcf_dev)) { - rc = -ENOMEM; - goto out; - } + temp->fabric_name = new->fabric_name; + temp->switch_name = new->switch_name; + temp->fc_map = new->fc_map; + temp->vfid = new->vfid; + memcpy(temp->mac, new->fcf_mac, ETH_ALEN); + temp->priority = new->pri; + temp->fka_period = new->fka_period; + temp->selected = 0; /* default to unselected */ + + fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp); + if (unlikely(!fcf_dev)) + goto unlock; /* * The fcoe_sysfs layer can return a CONNECTED fcf that @@ -204,9 +206,13 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) list_add(&new->list, &fip->fcfs); fip->fcf_count++; + rc = 0; -out: +unlock: mutex_unlock(&ctlr_dev->lock); + +out: + kfree(temp); return rc; } -- cgit v1.2.3-70-g09d2 From 9d34876f820d55c94bd0b2a2ed3d2e2976cbd997 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Thu, 5 Sep 2013 07:47:27 +0000 Subject: libfcoe: Make fcoe_sysfs optional / fix fnic NULL exception fnic doesn't use any of the create/destroy/enable/disable interfaces either from the (legacy) module paramaters or the (new) fcoe_sysfs interfaces. When fcoe_sysfs was introduced fnic wasn't changed since it wasn't using the interfaces. libfcoe incorrectly assumed that that all of its users were using fcoe_sysfs and when adding and deleting FCFs would assume the existance of a fcoe_ctlr_device. fnic was not allocating this structure because it doesn't care about the standard user interfaces (fnic starts on link only). If/When libfcoe tried to use the fcoe_ctlr_device's lock for the first time a NULL pointer exception would be triggered. Since fnic doesn't care about sysfs or user interfaces, the solution is to drop libfcoe's assumption that all drivers are using fcoe_sysfs. This patch accomplishes this by changing some of the structure relationships. We need a way to determine when a LLD is using fcoe_sysfs or not and we can do that by checking for the existance of the fcoe_ctlr_device. Prior to this patch, it was assumed that the fcoe_ctlr structure was allocated with the fcoe_ctlr_device and immediately followed it in memory. To reach the fcoe_ctlr_device we would simply go back in memory from the fcoe_ctlr to get the fcoe_ctlr_device. Since fnic doesn't allocate the fcoe_ctlr_device, we cannot keep that assumption. This patch adds a pointer from the fcoe_ctlr to the fcoe_ctlr_device. For bnx2fc and fcoe we will continue to allocate the two structures together, but then we'll set the ctlr->cdev pointer to point at the fcoe_ctlr_device. fnic will not change and will continue to allocate the fcoe_ctlr itself, and ctlr->cdev will remain NULL. When libfcoe adds fcoe_fcf's to the fcoe_ctlr it will check if ctlr->cdev is set and only if so will it continue to interact with fcoe_sysfs. Signed-off-by: Robert Love Acked-by: Neil Horman Tested-by: Hiral Patel --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 1 + drivers/scsi/fcoe/fcoe.c | 1 + drivers/scsi/fcoe/fcoe_ctlr.c | 94 ++++++++++++++++++++++++++------------- include/scsi/libfcoe.h | 7 ++- 4 files changed, 71 insertions(+), 32 deletions(-) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 69ac55495c1..27f2cc4b97a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1381,6 +1381,7 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, return NULL; } ctlr = fcoe_ctlr_device_priv(ctlr_dev); + ctlr->cdev = ctlr_dev; interface = fcoe_ctlr_priv(ctlr); dev_hold(netdev); kref_init(&interface->kref); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index dff40b2fccb..8626988e12a 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -408,6 +408,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, } ctlr = fcoe_ctlr_device_priv(ctlr_dev); + ctlr->cdev = ctlr_dev; fcoe = fcoe_ctlr_priv(ctlr); dev_hold(netdev); diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 692c6535fe7..75efdbc54ef 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -160,10 +160,16 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) } EXPORT_SYMBOL(fcoe_ctlr_init); +/** + * fcoe_sysfs_fcf_add() - Add a fcoe_fcf{,_device} to a fcoe_ctlr{,_device} + * @new: The newly discovered FCF + * + * Called with fip->ctlr_mutex held + */ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) { struct fcoe_ctlr *fip = new->fip; - struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); + struct fcoe_ctlr_device *ctlr_dev; struct fcoe_fcf_device *temp, *fcf_dev; int rc = -ENOMEM; @@ -174,8 +180,6 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) if (!temp) goto out; - mutex_lock(&ctlr_dev->lock); - temp->fabric_name = new->fabric_name; temp->switch_name = new->switch_name; temp->fc_map = new->fc_map; @@ -185,55 +189,83 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) temp->fka_period = new->fka_period; temp->selected = 0; /* default to unselected */ - fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp); - if (unlikely(!fcf_dev)) - goto unlock; - /* - * The fcoe_sysfs layer can return a CONNECTED fcf that - * has a priv (fcf was never deleted) or a CONNECTED fcf - * that doesn't have a priv (fcf was deleted). However, - * libfcoe will always delete FCFs before trying to add - * them. This is ensured because both recv_adv and - * age_fcfs are protected by the the fcoe_ctlr's mutex. - * This means that we should never get a FCF with a - * non-NULL priv pointer. + * If ctlr_dev doesn't exist then it means we're a libfcoe user + * who doesn't use fcoe_syfs and didn't allocate a fcoe_ctlr_device. + * fnic would be an example of a driver with this behavior. In this + * case we want to add the fcoe_fcf to the fcoe_ctlr list, but we + * don't want to make sysfs changes. */ - BUG_ON(fcf_dev->priv); - fcf_dev->priv = new; - new->fcf_dev = fcf_dev; + ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); + if (ctlr_dev) { + mutex_lock(&ctlr_dev->lock); + fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp); + if (unlikely(!fcf_dev)) { + rc = -ENOMEM; + goto out; + } + + /* + * The fcoe_sysfs layer can return a CONNECTED fcf that + * has a priv (fcf was never deleted) or a CONNECTED fcf + * that doesn't have a priv (fcf was deleted). However, + * libfcoe will always delete FCFs before trying to add + * them. This is ensured because both recv_adv and + * age_fcfs are protected by the the fcoe_ctlr's mutex. + * This means that we should never get a FCF with a + * non-NULL priv pointer. + */ + BUG_ON(fcf_dev->priv); + + fcf_dev->priv = new; + new->fcf_dev = fcf_dev; + mutex_unlock(&ctlr_dev->lock); + } list_add(&new->list, &fip->fcfs); fip->fcf_count++; rc = 0; -unlock: - mutex_unlock(&ctlr_dev->lock); - out: kfree(temp); return rc; } +/** + * fcoe_sysfs_fcf_del() - Remove a fcoe_fcf{,_device} to a fcoe_ctlr{,_device} + * @new: The FCF to be removed + * + * Called with fip->ctlr_mutex held + */ static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new) { struct fcoe_ctlr *fip = new->fip; - struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip); + struct fcoe_ctlr_device *cdev; struct fcoe_fcf_device *fcf_dev; list_del(&new->list); fip->fcf_count--; - mutex_lock(&ctlr_dev->lock); - - fcf_dev = fcoe_fcf_to_fcf_dev(new); - WARN_ON(!fcf_dev); - new->fcf_dev = NULL; - fcoe_fcf_device_delete(fcf_dev); - kfree(new); - - mutex_unlock(&ctlr_dev->lock); + /* + * If ctlr_dev doesn't exist then it means we're a libfcoe user + * who doesn't use fcoe_syfs and didn't allocate a fcoe_ctlr_device + * or a fcoe_fcf_device. + * + * fnic would be an example of a driver with this behavior. In this + * case we want to remove the fcoe_fcf from the fcoe_ctlr list (above), + * but we don't want to make sysfs changes. + */ + cdev = fcoe_ctlr_to_ctlr_dev(fip); + if (cdev) { + mutex_lock(&cdev->lock); + fcf_dev = fcoe_fcf_to_fcf_dev(new); + WARN_ON(!fcf_dev); + new->fcf_dev = NULL; + fcoe_fcf_device_delete(fcf_dev); + kfree(new); + mutex_unlock(&cdev->lock); + } } /** diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 4427393115e..de7e3ee60f0 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -90,6 +90,7 @@ enum fip_state { * @lp: &fc_lport: libfc local port. * @sel_fcf: currently selected FCF, or NULL. * @fcfs: list of discovered FCFs. + * @cdev: (Optional) pointer to sysfs fcoe_ctlr_device. * @fcf_count: number of discovered FCF entries. * @sol_time: time when a multicast solicitation was last sent. * @sel_time: time after which to select an FCF. @@ -127,6 +128,7 @@ struct fcoe_ctlr { struct fc_lport *lp; struct fcoe_fcf *sel_fcf; struct list_head fcfs; + struct fcoe_ctlr_device *cdev; u16 fcf_count; unsigned long sol_time; unsigned long sel_time; @@ -168,8 +170,11 @@ static inline void *fcoe_ctlr_priv(const struct fcoe_ctlr *ctlr) return (void *)(ctlr + 1); } +/* + * This assumes that the fcoe_ctlr (x) is allocated with the fcoe_ctlr_device. + */ #define fcoe_ctlr_to_ctlr_dev(x) \ - (struct fcoe_ctlr_device *)(((struct fcoe_ctlr_device *)(x)) - 1) + (x)->cdev /** * struct fcoe_fcf - Fibre-Channel Forwarder -- cgit v1.2.3-70-g09d2 From 55d0ac5d2839fe270cea02fad44eed13750a0efd Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 8 Oct 2013 23:43:58 +0000 Subject: fcoe: Fix missing mutex_unlock in fcoe_sysfs_fcf_add error path In this pending patch: http://patchwork.open-fcoe.org/patch/104/ Tomas Henzl noted that the error path when fcoe_fcf_device_add fails, was missing a mutex_unlock call. Not sure what staet the integration of the above patch is in, but if you could either merge this with it, or apply it on top of what you already have, that would be great. Thanks! Signed-off-by: Neil Horman CC: thenzl@redhat.com Reported-by: thenzl@redhat.com Signed-off-by: Robert Love --- drivers/scsi/fcoe/fcoe_ctlr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 75efdbc54ef..2aba32f12f1 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -203,6 +203,7 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new) fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp); if (unlikely(!fcf_dev)) { rc = -ENOMEM; + mutex_unlock(&ctlr_dev->lock); goto out; } -- cgit v1.2.3-70-g09d2 From 6942df7f775107b504f10de42c81971f514d718d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 2 Sep 2013 03:32:33 +0000 Subject: scsi: Convert uses of compare_ether_addr to ether_addr_equal Preliminary to removing compare_ether_addr altogether: Use the new bool function ether_addr_equal to add some clarity and reduce the likelihood for misuse of compare_ether_addr for sorting. Done via cocci script: $ cat compare_ether_addr.cocci @@ expression a,b; @@ - !compare_ether_addr(a, b) + ether_addr_equal(a, b) @@ expression a,b; @@ - compare_ether_addr(a, b) + !ether_addr_equal(a, b) @@ expression a,b; @@ - !ether_addr_equal(a, b) == 0 + ether_addr_equal(a, b) @@ expression a,b; @@ - !ether_addr_equal(a, b) != 0 + !ether_addr_equal(a, b) @@ expression a,b; @@ - ether_addr_equal(a, b) == 0 + !ether_addr_equal(a, b) @@ expression a,b; @@ - ether_addr_equal(a, b) != 0 + ether_addr_equal(a, b) @@ expression a,b; @@ - !!ether_addr_equal(a, b) + ether_addr_equal(a, b) Signed-off-by: Joe Perches Signed-off-by: Robert Love --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 3 +-- drivers/scsi/fcoe/fcoe.c | 2 +- drivers/scsi/fcoe/fcoe_ctlr.c | 22 +++++++++++----------- drivers/scsi/fcoe/fcoe_sysfs.c | 2 +- drivers/scsi/fnic/fnic_fcs.c | 6 +++--- 5 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers/scsi/fcoe') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 27f2cc4b97a..23f6eea3fa7 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -542,8 +542,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id)); if (vn_port) { port = lport_priv(vn_port); - if (compare_ether_addr(port->data_src_addr, dest_mac) - != 0) { + if (!ether_addr_equal(port->data_src_addr, dest_mac)) { BNX2FC_HBA_DBG(lport, "fpma mismatch\n"); put_cpu(); kfree_skb(skb); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 8626988e12a..f3170008ae7 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1462,7 +1462,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, eh = eth_hdr(skb); if (is_fip_mode(ctlr) && - compare_ether_addr(eh->h_source, ctlr->dest_addr)) { + !ether_addr_equal(eh->h_source, ctlr->dest_addr)) { FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", eh->h_source); goto err; diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 2aba32f12f1..34a1b1f333b 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -339,7 +339,7 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip) spin_unlock_bh(&fip->ctlr_lock); sel = fip->sel_fcf; - if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr)) + if (sel && ether_addr_equal(sel->fcf_mac, fip->dest_addr)) goto unlock; if (!is_zero_ether_addr(fip->dest_addr)) { printk(KERN_NOTICE "libfcoe: host%d: " @@ -1039,7 +1039,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) if (fcf->switch_name == new.switch_name && fcf->fabric_name == new.fabric_name && fcf->fc_map == new.fc_map && - compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { + ether_addr_equal(fcf->fcf_mac, new.fcf_mac)) { found = 1; break; } @@ -1379,7 +1379,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, mp = (struct fip_mac_desc *)desc; if (dlen < sizeof(*mp)) goto err; - if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac)) + if (!ether_addr_equal(mp->fd_mac, fcf->fcf_mac)) goto err; desc_mask &= ~BIT(FIP_DT_MAC); break; @@ -1457,8 +1457,8 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, * 'port_id' is already validated, check MAC address and * wwpn */ - if (compare_ether_addr(fip->get_src_addr(vn_port), - vp->fd_mac) != 0 || + if (!ether_addr_equal(fip->get_src_addr(vn_port), + vp->fd_mac) || get_unaligned_be64(&vp->fd_wwpn) != vn_port->wwpn) continue; @@ -1521,12 +1521,12 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) goto drop; eh = eth_hdr(skb); if (fip->mode == FIP_MODE_VN2VN) { - if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && - compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) && - compare_ether_addr(eh->h_dest, fcoe_all_p2p)) + if (!ether_addr_equal(eh->h_dest, fip->ctl_src_addr) && + !ether_addr_equal(eh->h_dest, fcoe_all_vn2vn) && + !ether_addr_equal(eh->h_dest, fcoe_all_p2p)) goto drop; - } else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && - compare_ether_addr(eh->h_dest, fcoe_all_enode)) + } else if (!ether_addr_equal(eh->h_dest, fip->ctl_src_addr) && + !ether_addr_equal(eh->h_dest, fcoe_all_enode)) goto drop; fiph = (struct fip_header *)skb->data; op = ntohs(fiph->fip_op); @@ -1898,7 +1898,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, * address_mode flag to use FC_OUI-based Ethernet DA. * Otherwise we use the FCoE gateway addr */ - if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) { + if (ether_addr_equal(sa, (u8[6])FC_FCOE_FLOGI_MAC)) { fcoe_ctlr_map_dest(fip); } else { memcpy(fip->dest_addr, sa, ETH_ALEN); diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index 922c9deeb24..d0d9a2d6120 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -653,7 +653,7 @@ static int fcoe_fcf_device_match(struct fcoe_fcf_device *new, if (new->switch_name == old->switch_name && new->fabric_name == old->fabric_name && new->fc_map == old->fc_map && - compare_ether_addr(new->mac, old->mac) == 0) + ether_addr_equal(new->mac, old->mac)) return 1; return 0; } diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 006fa92a02d..902520c6538 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -651,13 +651,13 @@ void fnic_update_mac_locked(struct fnic *fnic, u8 *new) if (is_zero_ether_addr(new)) new = ctl; - if (!compare_ether_addr(data, new)) + if (ether_addr_equal(data, new)) return; FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "update_mac %pM\n", new); - if (!is_zero_ether_addr(data) && compare_ether_addr(data, ctl)) + if (!is_zero_ether_addr(data) && !ether_addr_equal(data, ctl)) vnic_dev_del_addr(fnic->vdev, data); memcpy(data, new, ETH_ALEN); - if (compare_ether_addr(new, ctl)) + if (!ether_addr_equal(new, ctl)) vnic_dev_add_addr(fnic->vdev, new); } -- cgit v1.2.3-70-g09d2