Commit 4543fbef authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller

net: count hw_addr syncs so that unsync works properly.

A few drivers use dev_uc_sync/unsync to synchronize the
address lists from master down to slave/lower devices.  In
some cases (bond/team) a single address list is synched down
to multiple devices.  At the time of unsync, we have a leak
in these lower devices, because "synced" is treated as a
boolean and the address will not be unsynced for anything after
the first device/call.

Treat "synced" as a count (same as refcount) and allow all
unsync calls to work.
Signed-off-by: default avatarVlad Yasevich <vyasevic@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e2409d83
...@@ -210,9 +210,9 @@ struct netdev_hw_addr { ...@@ -210,9 +210,9 @@ struct netdev_hw_addr {
#define NETDEV_HW_ADDR_T_SLAVE 3 #define NETDEV_HW_ADDR_T_SLAVE 3
#define NETDEV_HW_ADDR_T_UNICAST 4 #define NETDEV_HW_ADDR_T_UNICAST 4
#define NETDEV_HW_ADDR_T_MULTICAST 5 #define NETDEV_HW_ADDR_T_MULTICAST 5
bool synced;
bool global_use; bool global_use;
int refcount; int refcount;
int synced;
struct rcu_head rcu_head; struct rcu_head rcu_head;
}; };
......
...@@ -37,7 +37,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list, ...@@ -37,7 +37,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
ha->type = addr_type; ha->type = addr_type;
ha->refcount = 1; ha->refcount = 1;
ha->global_use = global; ha->global_use = global;
ha->synced = false; ha->synced = 0;
list_add_tail_rcu(&ha->list, &list->list); list_add_tail_rcu(&ha->list, &list->list);
list->count++; list->count++;
...@@ -165,7 +165,7 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list, ...@@ -165,7 +165,7 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
addr_len, ha->type); addr_len, ha->type);
if (err) if (err)
break; break;
ha->synced = true; ha->synced++;
ha->refcount++; ha->refcount++;
} else if (ha->refcount == 1) { } else if (ha->refcount == 1) {
__hw_addr_del(to_list, ha->addr, addr_len, ha->type); __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
...@@ -186,7 +186,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, ...@@ -186,7 +186,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
if (ha->synced) { if (ha->synced) {
__hw_addr_del(to_list, ha->addr, __hw_addr_del(to_list, ha->addr,
addr_len, ha->type); addr_len, ha->type);
ha->synced = false; ha->synced--;
__hw_addr_del(from_list, ha->addr, __hw_addr_del(from_list, ha->addr,
addr_len, ha->type); addr_len, ha->type);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment