|
@@ -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);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|