[PATCH] dmaenginge.c: class_device_register() return value

From: Johannes Weiner
Date: Mon Mar 19 2007 - 15:37:57 EST


Hi,

this patch makes dma_async_device_register() in drivers/dma/dmaengine.c
handle a failing class_device_register(). Patched against Linus' git
tree, compile-tested.

I also thought about calling dma_async_device_unregister on failure, but
I was not quite sure if this would work. And I noticed that memory is
allocated for chan->local in dma_async_device_register() but I couldn't
find where it is released again.

I am quite new to this all, please give me feedback!


Signed-off-by: Johannes Weiner <hannes-kernel@xxxxxxxxxxxx>
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 322ee29..5560e39 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -316,8 +316,8 @@ EXPORT_SYMBOL(dma_async_client_chan_request);
int dma_async_device_register(struct dma_device *device)
{
static int id;
- int chancnt = 0;
- struct dma_chan* chan;
+ int chancnt, err;
+ struct dma_chan *chan, *last;

if (!device)
return -ENODEV;
@@ -326,9 +326,13 @@ int dma_async_device_register(struct dma_device *device)
kref_init(&device->refcount);
device->dev_id = id++;

+ err = chancnt = 0;
+
/* represent channels in sysfs. Probably want devs too */
list_for_each_entry(chan, &device->channels, device_node) {
chan->local = alloc_percpu(typeof(*chan->local));
+
+ /* Should this be handled less relaxed? */
if (chan->local == NULL)
continue;

@@ -339,7 +343,11 @@ int dma_async_device_register(struct dma_device *device)
device->dev_id, chan->chan_id);

kref_get(&device->refcount);
- class_device_register(&chan->class_dev);
+ err = class_device_register(&chan->class_dev);
+ if (err) {
+ last = chan;
+ goto err_dev_reg;
+ }
}

mutex_lock(&dma_list_mutex);
@@ -349,6 +357,22 @@ int dma_async_device_register(struct dma_device *device)
dma_chans_rebalance();

return 0;
+
+err_dev_reg:
+ list_for_each_entry(chan, &device->channels, device_node) {
+ kref_put(&device->refcount, dma_async_device_cleanup);
+
+ if (chan->local)
+ free_percpu(chan->local);
+
+ if (chan == last)
+ break;
+
+ class_device_unregister(&chan->class_dev);
+ }
+ wait_for_completion(&device->done);
+ device->dev_id = 0;
+ return err;
}
EXPORT_SYMBOL(dma_async_device_register);

diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 8e87261..c25f548 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -768,10 +768,13 @@ static int __devinit ioat_probe(struct pci_dev *pdev,
if (err)
goto err_self_test;

- dma_async_device_register(&device->common);
+ err = dma_async_device_register(&device->common)
+ if (err)
+ goto err_dev_reg;

return 0;

+err_dev_reg:
err_self_test:
err_irq:
pci_pool_destroy(device->completion_pool);