forked from luck/tmp_suning_uos_patched
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: Vlad Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e2409d8343
commit
4543fbefe6
|
@ -210,9 +210,9 @@ struct netdev_hw_addr {
|
|||
#define NETDEV_HW_ADDR_T_SLAVE 3
|
||||
#define NETDEV_HW_ADDR_T_UNICAST 4
|
||||
#define NETDEV_HW_ADDR_T_MULTICAST 5
|
||||
bool synced;
|
||||
bool global_use;
|
||||
int refcount;
|
||||
int synced;
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
|
|||
ha->type = addr_type;
|
||||
ha->refcount = 1;
|
||||
ha->global_use = global;
|
||||
ha->synced = false;
|
||||
ha->synced = 0;
|
||||
list_add_tail_rcu(&ha->list, &list->list);
|
||||
list->count++;
|
||||
|
||||
|
@ -165,7 +165,7 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
|
|||
addr_len, ha->type);
|
||||
if (err)
|
||||
break;
|
||||
ha->synced = true;
|
||||
ha->synced++;
|
||||
ha->refcount++;
|
||||
} else if (ha->refcount == 1) {
|
||||
__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,
|
|||
if (ha->synced) {
|
||||
__hw_addr_del(to_list, ha->addr,
|
||||
addr_len, ha->type);
|
||||
ha->synced = false;
|
||||
ha->synced--;
|
||||
__hw_addr_del(from_list, ha->addr,
|
||||
addr_len, ha->type);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user