]> git.hungrycats.org Git - linux/commitdiff
net: count hw_addr syncs so that unsync works properly.
authorVlad Yasevich <vyasevic@redhat.com>
Tue, 2 Apr 2013 21:10:07 +0000 (17:10 -0400)
committerBen Hutchings <ben@decadent.org.uk>
Mon, 13 May 2013 14:02:35 +0000 (15:02 +0100)
[ Upstream commit 4543fbefe6e06a9e40d9f2b28d688393a299f079 ]

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>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
include/linux/netdevice.h
net/core/dev_addr_lists.c

index 00ca32bd50aded582c4a139d377ad86d5308177e..8c43fd17d140ad98c2e8fc66ce80b5251a913107 100644 (file)
@@ -225,9 +225,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;
 };
 
index 0387da0e1b5da92f4743ba46f9ae279abb0d432f..cd094146e4195523634259cfeca38fc9d75b7e5b 100644 (file)
@@ -57,7 +57,7 @@ static int __hw_addr_add_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++;
        return 0;
@@ -155,7 +155,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);
@@ -176,7 +176,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);
                }