cmake: fix build by reordering the cflags definitions
[project/netifd.git] / device.c
index bb39ea7f8d71b46c750a770b771a5bc33d362bb9..1e892191d0ec95203b65b601e16be25a2e5762d3 100644 (file)
--- a/device.c
+++ b/device.c
@@ -99,18 +99,6 @@ device_type_get(const char *tname)
        return NULL;
 }
 
-void device_lock(void)
-{
-       __devlock++;
-}
-
-void device_unlock(void)
-{
-       __devlock--;
-       if (!__devlock)
-               device_free_unused(NULL);
-}
-
 static int device_vlan_len(struct kvlist *kv, const void *data)
 {
        return sizeof(unsigned int);
@@ -484,6 +472,17 @@ static void __init dev_init(void)
        avl_init(&devices, avl_strcmp, true, NULL);
 }
 
+static int device_release_cb(void *ctx, struct safe_list *list)
+{
+       struct device_user *dep = container_of(list, struct device_user, list);
+
+       if (!dep->dev || !dep->claimed)
+               return 0;
+
+       device_release(dep);
+       return 0;
+}
+
 static int device_broadcast_cb(void *ctx, struct safe_list *list)
 {
        struct device_user *dep = container_of(list, struct device_user, list);
@@ -783,6 +782,8 @@ void device_set_present(struct device *dev, bool state)
        D(DEVICE, "%s '%s' %s present\n", dev->type->name, dev->ifname, state ? "is now" : "is no longer" );
        dev->sys_present = state;
        device_refresh_present(dev);
+       if (!state)
+               safe_list_for_each(&dev->users, device_release_cb, NULL);
 }
 
 void device_set_link(struct device *dev, bool state)
@@ -895,14 +896,27 @@ device_free(struct device *dev)
 }
 
 static void
-__device_free_unused(struct device *dev)
+__device_free_unused(struct uloop_timeout *timeout)
 {
-       if (!safe_list_empty(&dev->users) ||
-               !safe_list_empty(&dev->aliases) ||
-           dev->current_config || __devlock)
-               return;
+       struct device *dev, *tmp;
+
+       avl_for_each_element_safe(&devices, dev, avl, tmp) {
+               if (!safe_list_empty(&dev->users) ||
+                       !safe_list_empty(&dev->aliases) ||
+                       dev->current_config)
+                       continue;
+
+               device_free(dev);
+       }
+}
+
+void device_free_unused(void)
+{
+       static struct uloop_timeout free_timer = {
+               .cb = __device_free_unused,
+       };
 
-       device_free(dev);
+       uloop_timeout_set(&free_timer, 1);
 }
 
 void device_remove_user(struct device_user *dep)
@@ -919,19 +933,7 @@ void device_remove_user(struct device_user *dep)
        safe_list_del(&dep->list);
        dep->dev = NULL;
        D(DEVICE, "Remove user for device '%s', refcount=%d\n", dev->ifname, device_refcount(dev));
-       __device_free_unused(dev);
-}
-
-void
-device_free_unused(struct device *dev)
-{
-       struct device *tmp;
-
-       if (dev)
-               return __device_free_unused(dev);
-
-       avl_for_each_element_safe(&devices, dev, avl, tmp)
-               __device_free_unused(dev);
+       device_free_unused();
 }
 
 void
@@ -1035,14 +1037,18 @@ device_apply_config(struct device *dev, struct device_type *type,
 static void
 device_replace(struct device *dev, struct device *odev)
 {
-       struct device_user *dep, *tmp;
+       struct device_user *dep;
 
        __devlock++;
        if (odev->present)
                device_set_present(odev, false);
 
-       list_for_each_entry_safe(dep, tmp, &odev->users.list, list.list) {
+       while (!list_empty(&odev->users.list)) {
+               dep = list_first_entry(&odev->users.list, struct device_user, list.list);
                device_release(dep);
+               if (!dep->dev)
+                       continue;
+
                safe_list_del(&dep->list);
                __device_add_user(dep, dev);
        }