Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+42 −17
Original line number Original line Diff line number Diff line
@@ -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)
	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)
	/* 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)
			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;
}
}


/**
/**