]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/message/i2o/device.c
i2o: Fix 32/64bit DMA locking
[linux-2.6-omap-h63xx.git] / drivers / message / i2o / device.c
index 489d7c5c49656d0c1fce8cdf17ba15a6a0041508..54c2e9ae23e5e98c9b10849bab02364a338e3185 100644 (file)
@@ -243,29 +243,41 @@ static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry)
 
        /* create user entries for this device */
        tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
-       if (tmp && (tmp != i2o_dev))
-               sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj,
-                                 "user");
+       if (tmp && (tmp != i2o_dev)) {
+               rc = sysfs_create_link(&i2o_dev->device.kobj,
+                                      &tmp->device.kobj, "user");
+               if (rc)
+                       goto unreg_dev;
+       }
 
        /* create user entries refering to this device */
        list_for_each_entry(tmp, &c->devices, list)
            if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
-               && (tmp != i2o_dev))
-               sysfs_create_link(&tmp->device.kobj,
-                                 &i2o_dev->device.kobj, "user");
+               && (tmp != i2o_dev)) {
+               rc = sysfs_create_link(&tmp->device.kobj,
+                                      &i2o_dev->device.kobj, "user");
+               if (rc)
+                       goto rmlink1;
+       }
 
        /* create parent entries for this device */
        tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
-       if (tmp && (tmp != i2o_dev))
-               sysfs_create_link(&i2o_dev->device.kobj, &tmp->device.kobj,
-                                 "parent");
+       if (tmp && (tmp != i2o_dev)) {
+               rc = sysfs_create_link(&i2o_dev->device.kobj,
+                                      &tmp->device.kobj, "parent");
+               if (rc)
+                       goto rmlink1;
+       }
 
        /* create parent entries refering to this device */
        list_for_each_entry(tmp, &c->devices, list)
            if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
-               && (tmp != i2o_dev))
-               sysfs_create_link(&tmp->device.kobj,
-                                 &i2o_dev->device.kobj, "parent");
+               && (tmp != i2o_dev)) {
+               rc = sysfs_create_link(&tmp->device.kobj,
+                                      &i2o_dev->device.kobj, "parent");
+               if (rc)
+                       goto rmlink2;
+       }
 
        i2o_driver_notify_device_add_all(i2o_dev);
 
@@ -273,6 +285,24 @@ static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry)
 
        return 0;
 
+rmlink2:
+       /* If link creating failed halfway, we loop whole list to cleanup.
+        * And we don't care wrong removing of link, because sysfs_remove_link
+        * will take care of it.
+        */
+       list_for_each_entry(tmp, &c->devices, list) {
+               if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+                       sysfs_remove_link(&tmp->device.kobj, "parent");
+       }
+       sysfs_remove_link(&i2o_dev->device.kobj, "parent");
+rmlink1:
+       list_for_each_entry(tmp, &c->devices, list)
+               if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+                       sysfs_remove_link(&tmp->device.kobj, "user");
+       sysfs_remove_link(&i2o_dev->device.kobj, "user");
+unreg_dev:
+       list_del(&i2o_dev->list);
+       device_unregister(&i2o_dev->device);
 err:
        kfree(i2o_dev);
        return rc;
@@ -437,7 +467,7 @@ int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
 
        res.virt = NULL;
 
-       if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL))
+       if (i2o_dma_alloc(dev, &res, reslen))
                return -ENOMEM;
 
        msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);