Commit 1c3333a2 authored by Dan Williams's avatar Dan Williams
Browse files

cxl/mem: Do not rely on device_add() side effects for dev_set_name() failures



While device_add() will happen to catch dev_set_name() failures it is a
broken pattern to follow given that the core may try to fall back to a
different name.

Add explicit checking for dev_set_name() failures to be cleaned up by
put_device(). Skip cdev_device_add() and proceed directly to
put_device() if the name set fails.

This type of bug is easier to see if 'alloc' is split from 'add'
operations that require put_device() on failure. So cxl_memdev_alloc()
is split out as a result.

Fixes: b39cb105 ("cxl/mem: Register CXL memX devices")
Reported-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/161728760514.2474381.1163928273337158134.stgit@dwillia2-desk3.amr.corp.intel.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 58775159
Loading
Loading
Loading
Loading
+29 −10
Original line number Diff line number Diff line
@@ -1180,7 +1180,7 @@ static void cxl_memdev_unregister(void *_cxlmd)
	put_device(dev);
}

static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm)
{
	struct pci_dev *pdev = cxlm->pdev;
	struct cxl_memdev *cxlmd;
@@ -1190,11 +1190,11 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)

	cxlmd = kzalloc(sizeof(*cxlmd), GFP_KERNEL);
	if (!cxlmd)
		return -ENOMEM;
		return ERR_PTR(-ENOMEM);

	rc = ida_alloc_range(&cxl_memdev_ida, 0, CXL_MEM_MAX_DEVS, GFP_KERNEL);
	if (rc < 0)
		goto err_id;
		goto err;
	cxlmd->id = rc;

	dev = &cxlmd->dev;
@@ -1203,10 +1203,31 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
	dev->bus = &cxl_bus_type;
	dev->devt = MKDEV(cxl_mem_major, cxlmd->id);
	dev->type = &cxl_memdev_type;
	dev_set_name(dev, "mem%d", cxlmd->id);

	cdev = &cxlmd->cdev;
	cdev_init(cdev, &cxl_memdev_fops);
	return cxlmd;

err:
	kfree(cxlmd);
	return ERR_PTR(rc);
}

static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
{
	struct cxl_memdev *cxlmd;
	struct device *dev;
	struct cdev *cdev;
	int rc;

	cxlmd = cxl_memdev_alloc(cxlm);
	if (IS_ERR(cxlmd))
		return PTR_ERR(cxlmd);

	dev = &cxlmd->dev;
	rc = dev_set_name(dev, "mem%d", cxlmd->id);
	if (rc)
		goto err;

	/*
	 * Activate ioctl operations, no cxl_memdev_rwsem manipulation
@@ -1214,23 +1235,21 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
	 */
	cxlmd->cxlm = cxlm;

	cdev = &cxlmd->cdev;
	rc = cdev_device_add(cdev, dev);
	if (rc)
		goto err_add;
		goto err;

	return devm_add_action_or_reset(dev->parent, cxl_memdev_unregister,
					cxlmd);

err_add:
err:
	/*
	 * The cdev was briefly live, shutdown any ioctl operations that
	 * saw that state.
	 */
	cxl_memdev_shutdown(cxlmd);
	ida_free(&cxl_memdev_ida, cxlmd->id);
err_id:
	kfree(cxlmd);

	put_device(dev);
	return rc;
}