rework device hotplug handling some more, add device_lock/device_unlock to prevent...
[project/netifd.git] / device.c
index ccba9d3..0a33f67 100644 (file)
--- a/device.c
+++ b/device.c
@@ -41,6 +41,20 @@ const struct config_param_list device_attr_list = {
        .params = dev_attrs,
 };
 
+static int __devlock = 0;
+
+void device_lock(void)
+{
+       __devlock++;
+}
+
+void device_unlock(void)
+{
+       __devlock--;
+       if (!__devlock)
+               device_free_unused(NULL);
+}
+
 static struct device *
 simple_device_create(const char *name, struct blob_attr *attr)
 {
@@ -172,6 +186,8 @@ alias_notify_device(const char *name, struct device *dev)
 {
        struct alias_device *alias;
 
+       device_lock();
+
        alias = avl_find_element(&aliases, name, alias, avl);
        if (!alias)
                return;
@@ -179,8 +195,7 @@ alias_notify_device(const char *name, struct device *dev)
        alias->cleanup = !dev;
        if (dev) {
                if (dev != alias->dep.dev) {
-                       if (alias->dep.dev)
-                               device_remove_user(&alias->dep);
+                       device_remove_user(&alias->dep);
                        strcpy(alias->dev.ifname, dev->ifname);
                        device_add_user(&alias->dep, dev);
                }
@@ -190,6 +205,8 @@ alias_notify_device(const char *name, struct device *dev)
 
        if (!dev && alias->dep.dev && !alias->dep.dev->active)
                device_remove_user(&alias->dep);
+
+       device_unlock();
 }
 
 static int set_device_state(struct device *dev, bool state)
@@ -396,6 +413,10 @@ void device_remove_user(struct device_user *dep)
 {
        struct device *dev = dep->dev;
 
+       if (!dep->dev)
+               return;
+
+       dep->hotplug = false;
        if (dep->claimed)
                device_release(dep);
 
@@ -430,7 +451,7 @@ device_init_pending(void)
        }
 }
 
-enum dev_change_type
+static enum dev_change_type
 device_reload_config(struct device *dev, struct blob_attr *attr)
 {
        struct blob_attr *tb[__DEV_ATTR_MAX];
@@ -442,7 +463,7 @@ device_reload_config(struct device *dev, struct blob_attr *attr)
        if (cfg == &device_attr_list) {
                memset(tb, 0, sizeof(tb));
 
-               if (dev->config)
+               if (attr)
                        blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb,
                                blob_data(attr), blob_len(attr));
 
@@ -452,9 +473,9 @@ device_reload_config(struct device *dev, struct blob_attr *attr)
                return DEV_CONFIG_RECREATE;
 }
 
-static enum dev_change_type
-device_check_config(struct device *dev, const struct device_type *type,
-                   struct blob_attr *attr)
+enum dev_change_type
+device_set_config(struct device *dev, const struct device_type *type,
+                 struct blob_attr *attr)
 {
        if (type != dev->type)
                return DEV_CONFIG_RECREATE;
@@ -525,7 +546,7 @@ device_create(const char *name, const struct device_type *type,
        odev = device_get(name, false);
        if (odev) {
                odev->current_config = true;
-               change = device_check_config(odev, type, config);
+               change = device_set_config(odev, type, config);
                switch (change) {
                case DEV_CONFIG_APPLIED:
                        D(DEVICE, "Device '%s': config applied\n", odev->ifname);