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);
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);
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)
}
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)
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
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);
}