summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bridge.c4
-rw-r--r--device.c18
-rw-r--r--device.h5
-rw-r--r--interface.c4
-rw-r--r--vlan.c6
5 files changed, 26 insertions, 11 deletions
diff --git a/bridge.c b/bridge.c
index 3f8739c..c48381b 100644
--- a/bridge.c
+++ b/bridge.c
@@ -72,7 +72,7 @@ bridge_disable_member(struct bridge_member *bm)
return 0;
system_bridge_delif(&bst->dev, bm->dev.dev);
- device_release(bm->dev.dev);
+ device_release(&bm->dev);
return 0;
}
@@ -86,7 +86,7 @@ bridge_enable_member(struct bridge_member *bm)
if (!bm->present)
return 0;
- ret = device_claim(bm->dev.dev);
+ ret = device_claim(&bm->dev);
if (ret < 0)
goto error;
diff --git a/device.c b/device.c
index 0019b6c..c02335c 100644
--- a/device.c
+++ b/device.c
@@ -120,10 +120,15 @@ static int set_device_state(struct device *dev, bool state)
return 0;
}
-int device_claim(struct device *dev)
+int device_claim(struct device_user *dep)
{
+ struct device *dev = dep->dev;
int ret;
+ if (dep->claimed)
+ return 0;
+
+ dep->claimed = true;
DPRINTF("claim device %s, new refcount: %d\n", dev->ifname, dev->active + 1);
if (++dev->active != 1)
return 0;
@@ -138,8 +143,14 @@ int device_claim(struct device *dev)
return ret;
}
-void device_release(struct device *dev)
+void device_release(struct device_user *dep)
{
+ struct device *dev = dep->dev;
+
+ if (!dep->claimed)
+ return;
+
+ dep->claimed = false;
dev->active--;
DPRINTF("release device %s, new refcount: %d\n", dev->ifname, dev->active);
assert(dev->active >= 0);
@@ -254,6 +265,9 @@ void device_remove_user(struct device_user *dep)
{
struct device *dev = dep->dev;
+ if (dep->claimed)
+ device_release(dep);
+
list_del(&dep->list);
if (list_empty(&dev->users)) {
diff --git a/device.h b/device.h
index e11df1f..63ffb21 100644
--- a/device.h
+++ b/device.h
@@ -124,6 +124,7 @@ enum device_event {
struct device_user {
struct list_head list;
+ bool claimed;
struct device *dev;
void (*cb)(struct device_user *, enum device_event);
};
@@ -147,8 +148,8 @@ void device_add_user(struct device_user *dep, struct device *iface);
void device_remove_user(struct device_user *dep);
void device_set_present(struct device *dev, bool state);
-int device_claim(struct device *dev);
-void device_release(struct device *dev);
+int device_claim(struct device_user *dep);
+void device_release(struct device_user *dep);
int check_device_state(struct device *dev);
static inline void
diff --git a/interface.c b/interface.c
index f08fee0..f6c32f4 100644
--- a/interface.c
+++ b/interface.c
@@ -89,7 +89,7 @@ static void
mark_interface_down(struct interface *iface)
{
interface_del_ctx_addr(iface, NULL);
- device_release(iface->main_dev.dev);
+ device_release(&iface->main_dev);
iface->state = IFS_DOWN;
}
@@ -101,7 +101,7 @@ __interface_set_up(struct interface *iface)
if (iface->state != IFS_DOWN)
return 0;
- ret = device_claim(iface->main_dev.dev);
+ ret = device_claim(&iface->main_dev);
if (ret)
return ret;
diff --git a/vlan.c b/vlan.c
index 18cb939..d00cda0 100644
--- a/vlan.c
+++ b/vlan.c
@@ -32,18 +32,18 @@ static int vlan_set_device_state(struct device *dev, bool up)
if (!up) {
vldev->set_state(dev, false);
system_vlan_del(dev);
- device_release(vldev->dep.dev);
+ device_release(&vldev->dep);
return 0;
}
- ret = device_claim(vldev->dep.dev);
+ ret = device_claim(&vldev->dep);
if (ret)
return ret;
system_vlan_add(vldev->dep.dev, vldev->id);
ret = vldev->set_state(dev, true);
if (ret)
- device_release(vldev->dep.dev);
+ device_release(&vldev->dep);
return ret;
}