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

Commit 3ee70591 authored by Jim Quigley's avatar Jim Quigley Committed by David S. Miller
Browse files

sunvdc: prevent sunvdc panic when mpgroup disk added to guest domain



Using mpgroup to define multiple paths for a virtual disk causes multiple
virtual-device-port ports to be created for that virtual device.
Each virtual-device-port port then gets a vdisk created for it by the Linux
sunvdc driver. As mpgroup is not supported by the Linux sunvdc driver it
cannot handle multiple ports for a single vdisk, leading to a kernel panic
at startup.

This fix prevents more than one vdisk per virtual-device-port being created
until full virtual disk multipathing (mpgroup) support is implemented.

Signed-off-by: default avatarJim Quigley <Jim.Quigley@oracle.com>
Reviewed-by: default avatarLiam Merwick <liam.merwick@oracle.com>
Reviewed-by: default avatarShannon Nelson <shannon.nelson@oracle.com>
Reviewed-by: default avatarAlexandre Chartre <alexandre.chartre@oracle.com>
Reviewed-by: default avatarAaron Young <aaron.young@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fdaccf74
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
@@ -875,6 +875,56 @@ static void print_version(void)
		printk(KERN_INFO "%s", version);
}

struct vdc_check_port_data {
	int	dev_no;
	char	*type;
};

static int vdc_device_probed(struct device *dev, void *arg)
{
	struct vio_dev *vdev = to_vio_dev(dev);
	struct vdc_check_port_data *port_data;

	port_data = (struct vdc_check_port_data *)arg;

	if ((vdev->dev_no == port_data->dev_no) &&
	    (!(strcmp((char *)&vdev->type, port_data->type))) &&
		dev_get_drvdata(dev)) {
		/* This device has already been configured
		 * by vdc_port_probe()
		 */
		return 1;
	} else {
		return 0;
	}
}

/* Determine whether the VIO device is part of an mpgroup
 * by locating all the virtual-device-port nodes associated
 * with the parent virtual-device node for the VIO device
 * and checking whether any of these nodes are vdc-ports
 * which have already been configured.
 *
 * Returns true if this device is part of an mpgroup and has
 * already been probed.
 */
static bool vdc_port_mpgroup_check(struct vio_dev *vdev)
{
	struct vdc_check_port_data port_data;
	struct device *dev;

	port_data.dev_no = vdev->dev_no;
	port_data.type = (char *)&vdev->type;

	dev = device_find_child(vdev->dev.parent, &port_data,
				vdc_device_probed);

	if (dev)
		return true;

	return false;
}

static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
{
	struct mdesc_handle *hp;
@@ -893,6 +943,14 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
		goto err_out_release_mdesc;
	}

	/* Check if this device is part of an mpgroup */
	if (vdc_port_mpgroup_check(vdev)) {
		printk(KERN_WARNING
			"VIO: Ignoring extra vdisk port %s",
			dev_name(&vdev->dev));
		goto err_out_release_mdesc;
	}

	port = kzalloc(sizeof(*port), GFP_KERNEL);
	err = -ENOMEM;
	if (!port) {
@@ -943,6 +1001,9 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
	if (err)
		goto err_out_free_tx_ring;

	/* Note that the device driver_data is used to determine
	 * whether the port has been probed.
	 */
	dev_set_drvdata(&vdev->dev, port);

	mdesc_release(hp);