Commit a1c1f5ea authored by Einar Lueck's avatar Einar Lueck Committed by David S. Miller

ctcm rollback in case of errors

Group device now cleanly reacts to failures during channel start and
implements a clean rollback.
Signed-off-by: default avatarEinar Lueck <elelueck@de.ibm.com>
Signed-off-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d816d423
...@@ -1530,11 +1530,16 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) ...@@ -1530,11 +1530,16 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
struct net_device *dev; struct net_device *dev;
struct ccw_device *cdev0; struct ccw_device *cdev0;
struct ccw_device *cdev1; struct ccw_device *cdev1;
struct channel *readc;
struct channel *writec;
int ret; int ret;
int result;
priv = dev_get_drvdata(&cgdev->dev); priv = dev_get_drvdata(&cgdev->dev);
if (!priv) if (!priv) {
return -ENODEV; result = -ENODEV;
goto out_err_result;
}
cdev0 = cgdev->cdev[0]; cdev0 = cgdev->cdev[0];
cdev1 = cgdev->cdev[1]; cdev1 = cgdev->cdev[1];
...@@ -1545,31 +1550,40 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) ...@@ -1545,31 +1550,40 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev));
ret = add_channel(cdev0, type, priv); ret = add_channel(cdev0, type, priv);
if (ret) if (ret) {
return ret; result = ret;
goto out_err_result;
}
ret = add_channel(cdev1, type, priv); ret = add_channel(cdev1, type, priv);
if (ret) if (ret) {
return ret; result = ret;
goto out_remove_channel1;
}
ret = ccw_device_set_online(cdev0); ret = ccw_device_set_online(cdev0);
if (ret != 0) { if (ret != 0) {
/* may be ok to fail now - can be done later */
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
"%s(%s) set_online rc=%d", "%s(%s) set_online rc=%d",
CTCM_FUNTAIL, read_id, ret); CTCM_FUNTAIL, read_id, ret);
result = -EIO;
goto out_remove_channel2;
} }
ret = ccw_device_set_online(cdev1); ret = ccw_device_set_online(cdev1);
if (ret != 0) { if (ret != 0) {
/* may be ok to fail now - can be done later */
CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE, CTCM_DBF_TEXT_(TRACE, CTC_DBF_NOTICE,
"%s(%s) set_online rc=%d", "%s(%s) set_online rc=%d",
CTCM_FUNTAIL, write_id, ret); CTCM_FUNTAIL, write_id, ret);
result = -EIO;
goto out_ccw1;
} }
dev = ctcm_init_netdevice(priv); dev = ctcm_init_netdevice(priv);
if (dev == NULL) if (dev == NULL) {
goto out; result = -ENODEV;
goto out_ccw2;
}
for (direction = READ; direction <= WRITE; direction++) { for (direction = READ; direction <= WRITE; direction++) {
priv->channel[direction] = priv->channel[direction] =
...@@ -1587,12 +1601,14 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) ...@@ -1587,12 +1601,14 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
/* sysfs magic */ /* sysfs magic */
SET_NETDEV_DEV(dev, &cgdev->dev); SET_NETDEV_DEV(dev, &cgdev->dev);
if (register_netdev(dev)) if (register_netdev(dev)) {
result = -ENODEV;
goto out_dev; goto out_dev;
}
if (ctcm_add_attributes(&cgdev->dev)) { if (ctcm_add_attributes(&cgdev->dev)) {
unregister_netdev(dev); result = -ENODEV;
goto out_dev; goto out_unregister;
} }
strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name));
...@@ -1608,13 +1624,22 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) ...@@ -1608,13 +1624,22 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev)
priv->channel[WRITE]->id, priv->protocol); priv->channel[WRITE]->id, priv->protocol);
return 0; return 0;
out_unregister:
unregister_netdev(dev);
out_dev: out_dev:
ctcm_free_netdevice(dev); ctcm_free_netdevice(dev);
out: out_ccw2:
ccw_device_set_offline(cgdev->cdev[1]); ccw_device_set_offline(cgdev->cdev[1]);
out_ccw1:
ccw_device_set_offline(cgdev->cdev[0]); ccw_device_set_offline(cgdev->cdev[0]);
out_remove_channel2:
return -ENODEV; readc = channel_get(type, read_id, READ);
channel_remove(readc);
out_remove_channel1:
writec = channel_get(type, write_id, WRITE);
channel_remove(writec);
out_err_result:
return result;
} }
/** /**
......
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