Fixed race on duplicate device registering or device unregistering while requesting master.
--- a/master/master.c Thu Sep 28 08:29:59 2006 +0000
+++ b/master/master.c Thu Sep 28 12:58:06 2006 +0000
@@ -109,6 +109,7 @@
master->index = index;
master->device = NULL;
+ init_MUTEX(&master->device_sem);
atomic_set(&master->available, 1);
INIT_LIST_HEAD(&master->slaves);
INIT_LIST_HEAD(&master->datagram_queue);
--- a/master/master.h Thu Sep 28 08:29:59 2006 +0000
+++ b/master/master.h Thu Sep 28 12:58:06 2006 +0000
@@ -45,6 +45,7 @@
#include <linux/sysfs.h>
#include <linux/timer.h>
#include <asm/atomic.h>
+#include <asm/semaphore.h>
#include "device.h"
#include "domain.h"
@@ -99,6 +100,7 @@
struct kobject kobj; /**< kobject */
ec_device_t *device; /**< EtherCAT device */
+ struct semaphore device_sem; /**< device semaphore */
ec_xmldev_t xmldev; /**< XML character device */
--- a/master/module.c Thu Sep 28 08:29:59 2006 +0000
+++ b/master/module.c Thu Sep 28 12:58:06 2006 +0000
@@ -290,15 +290,20 @@
if (!(master = ec_find_master(master_index))) return NULL;
+ if (down_interruptible(&master->device_sem)) {
+ EC_ERR("Interrupted while waiting for device!\n");
+ goto out_return;
+ }
+
if (master->device) {
EC_ERR("Master %i already has a device!\n", master_index);
- goto out_return;
+ goto out_up;
}
if (!(master->device =
(ec_device_t *) kmalloc(sizeof(ec_device_t), GFP_KERNEL))) {
EC_ERR("Failed to allocate device!\n");
- goto out_return;
+ goto out_up;
}
if (ec_device_init(master->device, master, net_dev, isr, module)) {
@@ -306,11 +311,14 @@
goto out_free;
}
+ up(&master->device_sem);
return master->device;
out_free:
kfree(master->device);
master->device = NULL;
+ out_up:
+ up(&master->device_sem);
out_return:
return NULL;
}
@@ -334,7 +342,10 @@
if (!(master = ec_find_master(master_index))) return;
+ down(&master->device_sem);
+
if (!master->device || master->device != device) {
+ up(&master->device_sem);
EC_WARN("Unable to unregister device!\n");
return;
}
@@ -342,6 +353,8 @@
ec_device_clear(master->device);
kfree(master->device);
master->device = NULL;
+
+ up(&master->device_sem);
}
/*****************************************************************************/
@@ -415,16 +428,25 @@
goto out_return;
}
+ if (down_interruptible(&master->device_sem)) {
+ EC_ERR("Interrupted while waiting for device!\n");
+ goto out_release;
+ }
+
if (!master->device) {
+ up(&master->device_sem);
EC_ERR("Master %i has no assigned device!\n", master_index);
goto out_release;
}
- if (!try_module_get(master->device->module)) { // possible race?
- EC_ERR("Failed to reserve device module!\n");
+ if (!try_module_get(master->device->module)) {
+ up(&master->device_sem);
+ EC_ERR("Device module is unloading!\n");
goto out_release;
}
+ up(&master->device_sem);
+
if (!master->device->link_state) {
EC_ERR("Link is DOWN.\n");
goto out_module_put;