|
From: Ying X. <yin...@wi...> - 2013-10-29 02:23:11
|
On 10/28/2013 05:57 AM, Jon Maloy wrote:
> On 10/25/2013 06:40 AM, Ying Xue wrote:
>> When TIPC media is enabled by bearer, the "bearer" variable in the
>> media instance is first initialized with the bearer pointer under
>> tipc_net_lock protection; likewise, when media is disabled,
>> tipc_net_lock is also first held and its "bearer" variable is then
>> set to NULL. But, when the "bearer" variable is accessed in
>> recv_msg() and recv_notification(), tipc_net_lock is not taken. As
>> the context under which recv_msg() and recv_notification() run is
>> different with media enable/disable functions, a stale "bearer"
>> might be got by recv_msg() and recv_notification() occasionally.
>> Therefore, before the bearer variable is read, tipc_net_lock should
>> be held to get rid of the synchronous issue.
> Ying,
> I may have misunderstood something here, but to me it looks like this
> patch is obsoleted by patch #8 in this series, where you
> aggregate in the bearer struct in eth_media.
No, patch #8 doesn't obsolete the patch.
Although the bearer pointer protected by tipc_net_lock in the patch
appears in patch #8, tipc_net_lock is still useful for us in recv_msg()
because tipc_net_lock is used to protect media_hlist. Please see point
*(1) in below piece of code:
static inline struct hlist_head *media_hashfn(int ifindex)
{
return &media_hlist[ifindex & (NETDEV_HASHENTRIES - 1)];
}
static struct eth_media *media_get(int ifindex)
{
struct eth_media *eb_ptr;
struct hlist_head *head = media_hashfn(ifindex);
hlist_for_each_entry(eb_ptr, head, hlist)
if (eb_ptr->dev->ifindex == ifindex)
return eb_ptr;
return NULL;
}
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct eth_media *eb_ptr;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
return NET_RX_DROP;
}
read_lock_bh(&tipc_net_lock);
eb_ptr = media_get(dev->ifindex);<-------------point *(1)
if (likely(eb_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
tipc_recv_msg(buf, (struct tipc_bearer *)eb_ptr);
read_unlock_bh(&tipc_net_lock);
return NET_RX_SUCCESS;
}
}
read_unlock_bh(&tipc_net_lock);
kfree_skb(buf);
return NET_RX_DROP;
}
After RCU lock is involved, tipc_net_lock read lock will be replaced
with rcu_read_lock() to protect media_hlist on read side.
Threfore, now expanding the scope of protection of tipc_net_lock is an
appropriate time.
Regards,
Ying
I wouldn't mind
> submitting this anyway, since tipc_net_lock is going away eventually,
> but I suspect David M and others may make the same observation
> and ask the same question.
>
> ///jon
>
>>
>> Signed-off-by: Ying Xue <yin...@wi...>
>> ---
>> net/tipc/bearer.c | 2 --
>> net/tipc/eth_media.c | 13 ++++++++++++-
>> net/tipc/ib_media.c | 13 ++++++++++++-
>> net/tipc/link.c | 2 --
>> 4 files changed, 24 insertions(+), 6 deletions(-)
>>
>> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
>> index 17f9824..3bbd90b 100644
>> --- a/net/tipc/bearer.c
>> +++ b/net/tipc/bearer.c
>> @@ -404,7 +404,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>> struct tipc_link *l_ptr;
>> struct tipc_link *temp_l_ptr;
>>
>> - read_lock_bh(&tipc_net_lock);
>> pr_info("Blocking bearer <%s>\n", b_ptr->name);
>> atomic_add_unless(&b_ptr->blocked, 1, 1);
>> spin_lock_bh(&b_ptr->lock);
>> @@ -416,7 +415,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>> spin_unlock_bh(&n_ptr->lock);
>> }
>> spin_unlock_bh(&b_ptr->lock);
>> - read_unlock_bh(&tipc_net_lock);
>> return 0;
>> }
>>
>> diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
>> index 32d01e8..ffba0c5 100644
>> --- a/net/tipc/eth_media.c
>> +++ b/net/tipc/eth_media.c
>> @@ -36,6 +36,7 @@
>>
>> #include "core.h"
>> #include "bearer.h"
>> +#include "net.h"
>>
>> #define MAX_ETH_MEDIA MAX_BEARERS
>>
>> @@ -135,13 +136,16 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
>> return NET_RX_DROP;
>> }
>>
>> + read_lock_bh(&tipc_net_lock);
>> if (likely(eb_ptr->bearer)) {
>> if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
>> buf->next = NULL;
>> tipc_recv_msg(buf, eb_ptr->bearer);
>> + read_unlock_bh(&tipc_net_lock);
>> return NET_RX_SUCCESS;
>> }
>> }
>> + read_unlock_bh(&tipc_net_lock);
>> kfree_skb(buf);
>> return NET_RX_DROP;
>> }
>> @@ -254,8 +258,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
>> if (++eb_ptr == stop)
>> return NOTIFY_DONE; /* couldn't find device */
>> }
>> - if (!eb_ptr->bearer)
>> +
>> + read_lock_bh(&tipc_net_lock);
>> + if (!eb_ptr->bearer) {
>> + read_unlock_bh(&tipc_net_lock);
>> return NOTIFY_DONE; /* bearer had been disabled */
>> + }
>>
>> eb_ptr->bearer->mtu = dev->mtu;
>>
>> @@ -279,9 +287,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
>> break;
>> case NETDEV_UNREGISTER:
>> case NETDEV_CHANGENAME:
>> + read_unlock_bh(&tipc_net_lock);
>> tipc_disable_bearer(eb_ptr->bearer->name);
>> + read_lock_bh(&tipc_net_lock);
>> break;
>> }
>> + read_unlock_bh(&tipc_net_lock);
>> return NOTIFY_OK;
>> }
>>
>> diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
>> index 5241a5b..8ed7358 100644
>> --- a/net/tipc/ib_media.c
>> +++ b/net/tipc/ib_media.c
>> @@ -41,6 +41,7 @@
>> #include <linux/if_infiniband.h>
>> #include "core.h"
>> #include "bearer.h"
>> +#include "net.h"
>>
>> #define MAX_IB_MEDIA MAX_BEARERS
>>
>> @@ -128,13 +129,16 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
>> return NET_RX_DROP;
>> }
>>
>> + read_lock_bh(&tipc_net_lock);
>> if (likely(ib_ptr->bearer)) {
>> if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
>> buf->next = NULL;
>> tipc_recv_msg(buf, ib_ptr->bearer);
>> + read_unlock_bh(&tipc_net_lock);
>> return NET_RX_SUCCESS;
>> }
>> }
>> + read_unlock_bh(&tipc_net_lock);
>> kfree_skb(buf);
>> return NET_RX_DROP;
>> }
>> @@ -247,8 +251,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
>> if (++ib_ptr == stop)
>> return NOTIFY_DONE; /* couldn't find device */
>> }
>> - if (!ib_ptr->bearer)
>> +
>> + read_lock_bh(&tipc_net_lock);
>> + if (!ib_ptr->bearer) {
>> + read_unlock_bh(&tipc_net_lock);
>> return NOTIFY_DONE; /* bearer had been disabled */
>> + }
>>
>> ib_ptr->bearer->mtu = dev->mtu;
>>
>> @@ -272,9 +280,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
>> break;
>> case NETDEV_UNREGISTER:
>> case NETDEV_CHANGENAME:
>> + read_unlock_bh(&tipc_net_lock);
>> tipc_disable_bearer(ib_ptr->bearer->name);
>> + read_lock_bh(&tipc_net_lock);
>> break;
>> }
>> + read_unlock_bh(&tipc_net_lock);
>> return NOTIFY_OK;
>> }
>>
>> diff --git a/net/tipc/link.c b/net/tipc/link.c
>> index 0e7d50a..12c72d2 100644
>> --- a/net/tipc/link.c
>> +++ b/net/tipc/link.c
>> @@ -1491,7 +1491,6 @@ static int link_recv_buf_validate(struct sk_buff *buf)
>> */
>> void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
>> {
>> - read_lock_bh(&tipc_net_lock);
>> while (head) {
>> struct tipc_node *n_ptr;
>> struct tipc_link *l_ptr;
>> @@ -1687,7 +1686,6 @@ deliver:
>> cont:
>> kfree_skb(buf);
>> }
>> - read_unlock_bh(&tipc_net_lock);
>> }
>>
>> /**
>
>
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:26:51
|
When a TIPC media is started, it is registered to be linked into a
global media_list list, however, the media is not removed from the
list when it is stopped. But there has a special case that all TIPC
media instances are declared statically, so it cannot cause serious
problem like memory leak even if media instance is not removed from
the media_list list when TIPC module is unloaded.
As the media_list will be protected by RCU lock, without unregister
routine, we just see how a media instance is linked into media_list,
but cannot find where the media is removed from the list, which is
an very weird design. Therefore, to make TIPC code more readable the
tipc_unregister_media() is introduced to remove media instance from
media_list when TIPC module is stopped.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/bearer.c | 17 +++++++++++++++++
net/tipc/bearer.h | 1 +
net/tipc/eth_media.c | 1 +
net/tipc/ib_media.c | 1 +
4 files changed, 20 insertions(+)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 13aca03..25045ba 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -109,6 +109,23 @@ exit:
return res;
}
+void tipc_unregister_media(const struct tipc_media *m_ptr)
+{
+ struct tipc_media *m;
+ u32 i;
+
+ write_lock_bh(&tipc_net_lock);
+ for (i = 0; i < media_count; i++) {
+ m = media_list[i];
+ if (m_ptr == m) {
+ media_list[i] = NULL;
+ media_count--;
+ break;
+ }
+ }
+ write_unlock_bh(&tipc_net_lock);
+}
+
/**
* tipc_media_addr_printf - record media address in print buffer
*/
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 8695d4a..280c23d 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -160,6 +160,7 @@ extern struct tipc_bearer tipc_bearers[];
* TIPC routines available to supported media types
*/
int tipc_register_media(struct tipc_media *m_ptr);
+void tipc_unregister_media(const struct tipc_media *m_ptr);
void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr);
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 0ff0c94..a543ab2 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -371,5 +371,6 @@ void tipc_eth_media_stop(void)
flush_scheduled_work();
unregister_netdevice_notifier(¬ifier);
+ tipc_unregister_media(ð_media_info);
eth_started = 0;
}
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index 27abce3..d4f004b 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -367,5 +367,6 @@ void tipc_ib_media_stop(void)
flush_scheduled_work();
unregister_netdevice_notifier(¬ifier);
+ tipc_unregister_media(&ib_media_info);
ib_started = 0;
}
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:26:54
|
When TIPC media is enabled by bearer, the "bearer" variable in the
media instance is first initialized with the bearer pointer under
tipc_net_lock protection; likewise, when media is disabled,
tipc_net_lock is also first held and its "bearer" variable is then
set to NULL. But, when the "bearer" variable is accessed in
recv_msg() and recv_notification(), tipc_net_lock is not taken. As
the context under which recv_msg() and recv_notification() run is
different with media enable/disable functions, a stale "bearer"
might be got by recv_msg() and recv_notification() occasionally.
Therefore, before the bearer variable is read, tipc_net_lock should
be held to get rid of the synchronous issue.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/bearer.c | 2 --
net/tipc/eth_media.c | 13 ++++++++++++-
net/tipc/ib_media.c | 13 ++++++++++++-
net/tipc/link.c | 2 --
4 files changed, 24 insertions(+), 6 deletions(-)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 25045ba..c71da45 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -420,7 +420,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
struct tipc_link *l_ptr;
struct tipc_link *temp_l_ptr;
- read_lock_bh(&tipc_net_lock);
pr_info("Blocking bearer <%s>\n", b_ptr->name);
atomic_set(&b_ptr->blocked, 1);
spin_lock_bh(&b_ptr->lock);
@@ -432,7 +431,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
spin_unlock_bh(&n_ptr->lock);
}
spin_unlock_bh(&b_ptr->lock);
- read_unlock_bh(&tipc_net_lock);
return 0;
}
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index a543ab2..493609e 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -36,6 +36,7 @@
#include "core.h"
#include "bearer.h"
+#include "net.h"
#define MAX_ETH_MEDIA MAX_BEARERS
@@ -135,13 +136,16 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
return NET_RX_DROP;
}
+ read_lock_bh(&tipc_net_lock);
if (likely(eb_ptr->bearer)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
tipc_recv_msg(buf, eb_ptr->bearer);
+ read_unlock_bh(&tipc_net_lock);
return NET_RX_SUCCESS;
}
}
+ read_unlock_bh(&tipc_net_lock);
kfree_skb(buf);
return NET_RX_DROP;
}
@@ -254,8 +258,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
if (++eb_ptr == stop)
return NOTIFY_DONE; /* couldn't find device */
}
- if (!eb_ptr->bearer)
+
+ read_lock_bh(&tipc_net_lock);
+ if (!eb_ptr->bearer) {
+ read_unlock_bh(&tipc_net_lock);
return NOTIFY_DONE; /* bearer had been disabled */
+ }
eb_ptr->bearer->mtu = dev->mtu;
@@ -279,9 +287,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
+ read_unlock_bh(&tipc_net_lock);
tipc_disable_bearer(eb_ptr->bearer->name);
+ read_lock_bh(&tipc_net_lock);
break;
}
+ read_unlock_bh(&tipc_net_lock);
return NOTIFY_OK;
}
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index d4f004b..a0fd091 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -41,6 +41,7 @@
#include <linux/if_infiniband.h>
#include "core.h"
#include "bearer.h"
+#include "net.h"
#define MAX_IB_MEDIA MAX_BEARERS
@@ -128,13 +129,16 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
return NET_RX_DROP;
}
+ read_lock_bh(&tipc_net_lock);
if (likely(ib_ptr->bearer)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
tipc_recv_msg(buf, ib_ptr->bearer);
+ read_unlock_bh(&tipc_net_lock);
return NET_RX_SUCCESS;
}
}
+ read_unlock_bh(&tipc_net_lock);
kfree_skb(buf);
return NET_RX_DROP;
}
@@ -247,8 +251,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
if (++ib_ptr == stop)
return NOTIFY_DONE; /* couldn't find device */
}
- if (!ib_ptr->bearer)
+
+ read_lock_bh(&tipc_net_lock);
+ if (!ib_ptr->bearer) {
+ read_unlock_bh(&tipc_net_lock);
return NOTIFY_DONE; /* bearer had been disabled */
+ }
ib_ptr->bearer->mtu = dev->mtu;
@@ -272,9 +280,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
+ read_unlock_bh(&tipc_net_lock);
tipc_disable_bearer(ib_ptr->bearer->name);
+ read_lock_bh(&tipc_net_lock);
break;
}
+ read_unlock_bh(&tipc_net_lock);
return NOTIFY_OK;
}
diff --git a/net/tipc/link.c b/net/tipc/link.c
index df6dd34..3653bc8 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1576,7 +1576,6 @@ static int link_recv_buf_validate(struct sk_buff *buf)
*/
void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
{
- read_lock_bh(&tipc_net_lock);
while (head) {
struct tipc_node *n_ptr;
struct tipc_link *l_ptr;
@@ -1772,7 +1771,6 @@ deliver:
cont:
kfree_skb(buf);
}
- read_unlock_bh(&tipc_net_lock);
}
/**
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:26:56
|
When TIPC protocol handler is registered into networking stack by TIPC media, the media pointer is also attched to af_packet_priv of the protocol handler; when TIPC packets arrive at recv_msg(), media pointer can be got from af_packet_priv in TIPC protocol handler which is passed as one of arguments of recv_msg(). With the media pointer, packets can be injected into TIPC stack. Although this registration now works well for TIPC, the usage of af_packet_priv is totally wrong because af_packet_priv should defined only for AF_PACKET socket. About its more detailed discussion, please see below link: http://patchwork.ozlabs.org/patch/178044/ Therefore, in order to git rid of af_packet_priv from TIPC stack when TIPC protocol handler is registered, the dynamically allocated object of eth_media/ib_media is inserted into one hash list with one hash key to which the index of network device associated with the media is used; when TIPC packets reach recv_msg() from networking device, the index of the network device is used as hash key to find corresponding media object from the hash list. Signed-off-by: Ying Xue <yin...@wi...> --- net/tipc/eth_media.c | 116 ++++++++++++++++++++++++++++---------------------- net/tipc/ib_media.c | 103 ++++++++++++++++++++++++++------------------ 2 files changed, 126 insertions(+), 93 deletions(-) diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 493609e..29fda38 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -38,39 +38,44 @@ #include "bearer.h" #include "net.h" -#define MAX_ETH_MEDIA MAX_BEARERS - #define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */ /** * struct eth_media - Ethernet bearer data structure * @bearer: ptr to associated "generic" bearer structure + * @hlist: Ethernet media hash chain * @dev: ptr to associated Ethernet network device - * @tipc_packet_type: used in binding TIPC to Ethernet driver * @setup: work item used when enabling bearer * @cleanup: work item used when disabling bearer */ struct eth_media { struct tipc_bearer *bearer; + struct hlist_node hlist; struct net_device *dev; - struct packet_type tipc_packet_type; struct work_struct setup; struct work_struct cleanup; }; static struct tipc_media eth_media_info; -static struct eth_media eth_media_array[MAX_ETH_MEDIA]; +static struct hlist_head *media_hlist; static int eth_started; +static struct packet_type tipc_packet_type __read_mostly; -static int recv_notification(struct notifier_block *nb, unsigned long evt, - void *dv); -/* - * Network device notifier info - */ -static struct notifier_block notifier = { - .notifier_call = recv_notification, - .priority = 0 -}; +static inline struct hlist_head *media_hashfn(int ifindex) +{ + return &media_hlist[ifindex & (NETDEV_HASHENTRIES - 1)]; +} + +static struct eth_media *media_get(int ifindex) +{ + struct eth_media *eb_ptr; + struct hlist_head *head = media_hashfn(ifindex); + + hlist_for_each_entry(eb_ptr, head, hlist) + if (eb_ptr->dev->ifindex == ifindex) + return eb_ptr; + return NULL; +} /** * eth_media_addr_set - initialize Ethernet media address structure @@ -129,7 +134,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; + struct eth_media *eb_ptr; if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); @@ -137,7 +142,8 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, } read_lock_bh(&tipc_net_lock); - if (likely(eb_ptr->bearer)) { + eb_ptr = media_get(dev->ifindex); + if (likely(eb_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; tipc_recv_msg(buf, eb_ptr->bearer); @@ -155,10 +161,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, */ static void setup_media(struct work_struct *work) { - struct eth_media *eb_ptr = - container_of(work, struct eth_media, setup); - - dev_add_pack(&eb_ptr->tipc_packet_type); + dev_add_pack(&tipc_packet_type); } /** @@ -167,18 +170,8 @@ static void setup_media(struct work_struct *work) static int enable_media(struct tipc_bearer *tb_ptr) { struct net_device *dev; - struct eth_media *eb_ptr = ð_media_array[0]; - struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; + struct eth_media *eb_ptr; char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; - int pending_dev = 0; - - /* Find unused Ethernet bearer structure */ - while (eb_ptr->dev) { - if (!eb_ptr->bearer) - pending_dev++; - if (++eb_ptr == stop) - return pending_dev ? -EAGAIN : -EDQUOT; - } /* Find device with specified name */ dev = dev_get_by_name(&init_net, driver_name); @@ -186,12 +179,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) return -ENODEV; /* Create Ethernet bearer for device */ + eb_ptr = kzalloc(sizeof(*eb_ptr), GFP_ATOMIC); + if (!eb_ptr) + return -ENOMEM; + eb_ptr->dev = dev; - eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - eb_ptr->tipc_packet_type.dev = dev; - eb_ptr->tipc_packet_type.func = recv_msg; - eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; - INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); INIT_WORK(&eb_ptr->setup, setup_media); schedule_work(&eb_ptr->setup); @@ -204,6 +196,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); + hlist_add_head(&eb_ptr->hlist, media_hashfn(dev->ifindex)); return 0; } @@ -217,9 +210,9 @@ static void cleanup_media(struct work_struct *work) struct eth_media *eb_ptr = container_of(work, struct eth_media, cleanup); - dev_remove_pack(&eb_ptr->tipc_packet_type); + dev_remove_pack(&tipc_packet_type); dev_put(eb_ptr->dev); - eb_ptr->dev = NULL; + kfree(eb_ptr); } /** @@ -233,7 +226,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) { struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle; - eb_ptr->bearer = NULL; + hlist_del(&eb_ptr->hlist); INIT_WORK(&eb_ptr->cleanup, cleanup_media); schedule_work(&eb_ptr->cleanup); } @@ -248,19 +241,14 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct eth_media *eb_ptr = ð_media_array[0]; - struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; + struct eth_media *eb_ptr; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - while ((eb_ptr->dev != dev)) { - if (++eb_ptr == stop) - return NOTIFY_DONE; /* couldn't find device */ - } - read_lock_bh(&tipc_net_lock); - if (!eb_ptr->bearer) { + eb_ptr = media_get(dev->ifindex); + if (!eb_ptr) { read_unlock_bh(&tipc_net_lock); return NOTIFY_DONE; /* bearer had been disabled */ } @@ -349,6 +337,16 @@ static struct tipc_media eth_media_info = { .name = "eth" }; +static struct notifier_block notifier = { + .notifier_call = recv_notification, + .priority = 0 +}; + +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = recv_msg, +}; + /** * tipc_eth_media_start - activate Ethernet bearer support * @@ -357,18 +355,33 @@ static struct tipc_media eth_media_info = { */ int tipc_eth_media_start(void) { - int res; + int res, i; if (eth_started) return -EINVAL; + media_hlist = kmalloc(sizeof(*media_hlist) * NETDEV_HASHENTRIES, + GFP_KERNEL); + if (!media_hlist) + return -ENOMEM; + + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&media_hlist[i]); + res = tipc_register_media(ð_media_info); - if (res) + if (res) { + kfree(media_hlist); return res; + } res = register_netdevice_notifier(¬ifier); - if (!res) - eth_started = 1; + if (res) { + kfree(media_hlist); + tipc_unregister_media(ð_media_info); + return res; + } + + eth_started = 1; return res; } @@ -383,5 +396,6 @@ void tipc_eth_media_stop(void) flush_scheduled_work(); unregister_netdevice_notifier(¬ifier); tipc_unregister_media(ð_media_info); + kfree(media_hlist); eth_started = 0; } diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index a0fd091..3a38a8c 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -43,27 +43,42 @@ #include "bearer.h" #include "net.h" -#define MAX_IB_MEDIA MAX_BEARERS - /** * struct ib_media - Infiniband media data structure * @bearer: ptr to associated "generic" bearer structure + * @hlist: Infiniband media hash chain * @dev: ptr to associated Infiniband network device - * @tipc_packet_type: used in binding TIPC to Infiniband driver * @cleanup: work item used when disabling bearer */ struct ib_media { struct tipc_bearer *bearer; + struct hlist_node hlist; struct net_device *dev; - struct packet_type tipc_packet_type; struct work_struct setup; struct work_struct cleanup; }; static struct tipc_media ib_media_info; -static struct ib_media ib_media_array[MAX_IB_MEDIA]; +static struct hlist_head *media_hlist; static int ib_started; +static struct packet_type tipc_packet_type __read_mostly; + +static inline struct hlist_head *media_hashfn(int ifindex) +{ + return &media_hlist[ifindex & (NETDEV_HASHENTRIES - 1)]; +} + +static struct ib_media *media_get(int ifindex) +{ + struct ib_media *ib_ptr; + struct hlist_head *head = media_hashfn(ifindex); + + hlist_for_each_entry(ib_ptr, head, hlist) + if (ib_ptr->dev->ifindex == ifindex) + return ib_ptr; + return NULL; +} /** * ib_media_addr_set - initialize Infiniband media address structure @@ -122,7 +137,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; + struct ib_media *ib_ptr; if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); @@ -130,7 +145,8 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, } read_lock_bh(&tipc_net_lock); - if (likely(ib_ptr->bearer)) { + ib_ptr = media_get(dev->ifindex); + if (likely(ib_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; tipc_recv_msg(buf, ib_ptr->bearer); @@ -148,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, */ static void setup_media(struct work_struct *work) { - struct ib_media *ib_ptr = - container_of(work, struct ib_media, setup); - - dev_add_pack(&ib_ptr->tipc_packet_type); + dev_add_pack(&tipc_packet_type); } /** @@ -160,18 +173,8 @@ static void setup_media(struct work_struct *work) static int enable_media(struct tipc_bearer *tb_ptr) { struct net_device *dev; - struct ib_media *ib_ptr = &ib_media_array[0]; - struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; + struct ib_media *ib_ptr; char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; - int pending_dev = 0; - - /* Find unused InfiniBand bearer structure */ - while (ib_ptr->dev) { - if (!ib_ptr->bearer) - pending_dev++; - if (++ib_ptr == stop) - return pending_dev ? -EAGAIN : -EDQUOT; - } /* Find device with specified name */ dev = dev_get_by_name(&init_net, driver_name); @@ -179,12 +182,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) return -ENODEV; /* Create InfiniBand bearer for device */ + ib_ptr = kzalloc(sizeof(*ib_ptr), GFP_ATOMIC); + if (!ib_ptr) + return -ENOMEM; + ib_ptr->dev = dev; - ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - ib_ptr->tipc_packet_type.dev = dev; - ib_ptr->tipc_packet_type.func = recv_msg; - ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr; - INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list)); INIT_WORK(&ib_ptr->setup, setup_media); schedule_work(&ib_ptr->setup); @@ -197,6 +199,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); + hlist_add_head(&ib_ptr->hlist, media_hashfn(dev->ifindex)); return 0; } @@ -210,9 +213,9 @@ static void cleanup_bearer(struct work_struct *work) struct ib_media *ib_ptr = container_of(work, struct ib_media, cleanup); - dev_remove_pack(&ib_ptr->tipc_packet_type); + dev_remove_pack(&tipc_packet_type); dev_put(ib_ptr->dev); - ib_ptr->dev = NULL; + kfree(ib_ptr); } /** @@ -226,7 +229,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) { struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle; - ib_ptr->bearer = NULL; + hlist_del(&ib_ptr->hlist); INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); schedule_work(&ib_ptr->cleanup); } @@ -241,19 +244,14 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct ib_media *ib_ptr = &ib_media_array[0]; - struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; + struct ib_media *ib_ptr; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - while ((ib_ptr->dev != dev)) { - if (++ib_ptr == stop) - return NOTIFY_DONE; /* couldn't find device */ - } - read_lock_bh(&tipc_net_lock); - if (!ib_ptr->bearer) { + ib_ptr = media_get(dev->ifindex); + if (!ib_ptr) { read_unlock_bh(&tipc_net_lock); return NOTIFY_DONE; /* bearer had been disabled */ } @@ -294,6 +292,11 @@ static struct notifier_block notifier = { .priority = 0, }; +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = recv_msg, +}; + /** * ib_addr2str - convert InfiniBand address to string */ @@ -353,18 +356,33 @@ static struct tipc_media ib_media_info = { */ int tipc_ib_media_start(void) { - int res; + int res, i; if (ib_started) return -EINVAL; + media_hlist = kmalloc(sizeof(*media_hlist) * NETDEV_HASHENTRIES, + GFP_KERNEL); + if (!media_hlist) + return -ENOMEM; + + for (i = 0; i < NETDEV_HASHENTRIES; i++) + INIT_HLIST_HEAD(&media_hlist[i]); + res = tipc_register_media(&ib_media_info); - if (res) + if (res) { + kfree(media_hlist); return res; + } res = register_netdevice_notifier(¬ifier); - if (!res) - ib_started = 1; + if (res) { + kfree(media_hlist); + tipc_unregister_media(&ib_media_info); + return res; + } + + ib_started = 1; return res; } @@ -379,5 +397,6 @@ void tipc_ib_media_stop(void) flush_scheduled_work(); unregister_netdevice_notifier(¬ifier); tipc_unregister_media(&ib_media_info); + kfree(media_hlist); ib_started = 0; } -- 1.7.9.5 |
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:01
|
When TIPC packet handler is registered into networking stack, it's
enough to register once for all same type of media. So we should move
the registration/unregistration of TIPC packet handler to media start
and media stop routines.
In doing so, we can also delete all the work_struct related setup and
cleanup infrastructures because media start/stop routines are now
executed under process context.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/eth_media.c | 41 ++++++-----------------------------------
net/tipc/ib_media.c | 40 ++++++----------------------------------
2 files changed, 12 insertions(+), 69 deletions(-)
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 29fda38..6e9af12 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -45,21 +45,16 @@
* @bearer: ptr to associated "generic" bearer structure
* @hlist: Ethernet media hash chain
* @dev: ptr to associated Ethernet network device
- * @setup: work item used when enabling bearer
- * @cleanup: work item used when disabling bearer
*/
struct eth_media {
struct tipc_bearer *bearer;
struct hlist_node hlist;
struct net_device *dev;
- struct work_struct setup;
- struct work_struct cleanup;
};
static struct tipc_media eth_media_info;
static struct hlist_head *media_hlist;
static int eth_started;
-static struct packet_type tipc_packet_type __read_mostly;
static inline struct hlist_head *media_hashfn(int ifindex)
{
@@ -157,14 +152,6 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
}
/**
- * setup_media - setup association between Ethernet bearer and interface
- */
-static void setup_media(struct work_struct *work)
-{
- dev_add_pack(&tipc_packet_type);
-}
-
-/**
* enable_media - attach TIPC bearer to an Ethernet interface
*/
static int enable_media(struct tipc_bearer *tb_ptr)
@@ -184,8 +171,6 @@ static int enable_media(struct tipc_bearer *tb_ptr)
return -ENOMEM;
eb_ptr->dev = dev;
- INIT_WORK(&eb_ptr->setup, setup_media);
- schedule_work(&eb_ptr->setup);
/* Associate TIPC bearer with Ethernet bearer */
eb_ptr->bearer = tb_ptr;
@@ -201,34 +186,17 @@ static int enable_media(struct tipc_bearer *tb_ptr)
}
/**
- * cleanup_media - break association between Ethernet bearer and interface
- *
- * This routine must be invoked from a work queue because it can sleep.
- */
-static void cleanup_media(struct work_struct *work)
-{
- struct eth_media *eb_ptr =
- container_of(work, struct eth_media, cleanup);
-
- dev_remove_pack(&tipc_packet_type);
- dev_put(eb_ptr->dev);
- kfree(eb_ptr);
-}
-
-/**
* disable_media - detach TIPC bearer from an Ethernet interface
*
- * Mark Ethernet bearer as inactive so that incoming buffers are thrown away,
- * then get worker thread to complete bearer cleanup. (Can't do cleanup
- * here because cleanup code needs to sleep and caller holds spinlocks.)
+ * Mark Ethernet bearer as inactive so that incoming buffers are thrown away.
*/
static void disable_media(struct tipc_bearer *tb_ptr)
{
struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle;
hlist_del(&eb_ptr->hlist);
- INIT_WORK(&eb_ptr->cleanup, cleanup_media);
- schedule_work(&eb_ptr->cleanup);
+ dev_put(eb_ptr->dev);
+ kfree(eb_ptr);
}
/**
@@ -381,6 +349,8 @@ int tipc_eth_media_start(void)
return res;
}
+ dev_add_pack(&tipc_packet_type);
+
eth_started = 1;
return res;
}
@@ -395,6 +365,7 @@ void tipc_eth_media_stop(void)
flush_scheduled_work();
unregister_netdevice_notifier(¬ifier);
+ dev_remove_pack(&tipc_packet_type);
tipc_unregister_media(ð_media_info);
kfree(media_hlist);
eth_started = 0;
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index 3a38a8c..02ea44c 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -48,21 +48,17 @@
* @bearer: ptr to associated "generic" bearer structure
* @hlist: Infiniband media hash chain
* @dev: ptr to associated Infiniband network device
- * @cleanup: work item used when disabling bearer
*/
struct ib_media {
struct tipc_bearer *bearer;
struct hlist_node hlist;
struct net_device *dev;
- struct work_struct setup;
- struct work_struct cleanup;
};
static struct tipc_media ib_media_info;
static struct hlist_head *media_hlist;
static int ib_started;
-static struct packet_type tipc_packet_type __read_mostly;
static inline struct hlist_head *media_hashfn(int ifindex)
{
@@ -160,14 +156,6 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
}
/**
- * setup_bearer - setup association between InfiniBand bearer and interface
- */
-static void setup_media(struct work_struct *work)
-{
- dev_add_pack(&tipc_packet_type);
-}
-
-/**
* enable_media - attach TIPC bearer to an InfiniBand interface
*/
static int enable_media(struct tipc_bearer *tb_ptr)
@@ -187,8 +175,6 @@ static int enable_media(struct tipc_bearer *tb_ptr)
return -ENOMEM;
ib_ptr->dev = dev;
- INIT_WORK(&ib_ptr->setup, setup_media);
- schedule_work(&ib_ptr->setup);
/* Associate TIPC bearer with InfiniBand bearer */
ib_ptr->bearer = tb_ptr;
@@ -204,34 +190,17 @@ static int enable_media(struct tipc_bearer *tb_ptr)
}
/**
- * cleanup_bearer - break association between InfiniBand bearer and interface
- *
- * This routine must be invoked from a work queue because it can sleep.
- */
-static void cleanup_bearer(struct work_struct *work)
-{
- struct ib_media *ib_ptr =
- container_of(work, struct ib_media, cleanup);
-
- dev_remove_pack(&tipc_packet_type);
- dev_put(ib_ptr->dev);
- kfree(ib_ptr);
-}
-
-/**
* disable_media - detach TIPC bearer from an InfiniBand interface
*
- * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away,
- * then get worker thread to complete bearer cleanup. (Can't do cleanup
- * here because cleanup code needs to sleep and caller holds spinlocks.)
+ * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away.
*/
static void disable_media(struct tipc_bearer *tb_ptr)
{
struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle;
hlist_del(&ib_ptr->hlist);
- INIT_WORK(&ib_ptr->cleanup, cleanup_bearer);
- schedule_work(&ib_ptr->cleanup);
+ dev_put(ib_ptr->dev);
+ kfree(ib_ptr);
}
/**
@@ -382,6 +351,8 @@ int tipc_ib_media_start(void)
return res;
}
+ dev_add_pack(&tipc_packet_type);
+
ib_started = 1;
return res;
}
@@ -396,6 +367,7 @@ void tipc_ib_media_stop(void)
flush_scheduled_work();
unregister_netdevice_notifier(¬ifier);
+ dev_remove_pack(&tipc_packet_type);
tipc_unregister_media(&ib_media_info);
kfree(media_hlist);
ib_started = 0;
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:03
|
Since setup/cleanup work items are eliminated from eth_media/ib_media structure, it's meaningless to call flush_scheduled_work() in media stop routines. Signed-off-by: Ying Xue <yin...@wi...> --- net/tipc/eth_media.c | 1 - net/tipc/ib_media.c | 1 - 2 files changed, 2 deletions(-) diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 6e9af12..7641374 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -363,7 +363,6 @@ void tipc_eth_media_stop(void) if (!eth_started) return; - flush_scheduled_work(); unregister_netdevice_notifier(¬ifier); dev_remove_pack(&tipc_packet_type); tipc_unregister_media(ð_media_info); diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 02ea44c..fb38616 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -365,7 +365,6 @@ void tipc_ib_media_stop(void) if (!ib_started) return; - flush_scheduled_work(); unregister_netdevice_notifier(¬ifier); dev_remove_pack(&tipc_packet_type); tipc_unregister_media(&ib_media_info); -- 1.7.9.5 |
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:06
|
In current TIPC locking policy, tipc_net_lock protects two domains:
'node' and 'bearer' sub-domains. When one link instance is got from
"active_links" array in node sub-domain, tipc_net_lock(read) must be
held. Correspondingly, individual bearers may change status within a
tipc_net_lock(read), and it needs tipc_net_lock(write) to remove/add
any bearers. Obviously, this locking policy makes the two sub-domains
bound together closely.
To simplify the locking policy, we use one fine grained config_muex
lock to proect all resources associated with bearer/media like
media_list, tipc_bearers and media_hlist etc. But, even if the change
is made, tipc_net_lock is not removed from bearer domain until RCU
locks are involved to protect these global lists like media_list,
tipc_bearers and media_hlist in the future.
Additionally both initialised and uninitialised processes of TIPC
module have to be adjusted due to the locking policy change, so
tipc_core_start_net() and tipc_core_stop_net() become obsolete.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/bearer.c | 4 ++++
net/tipc/config.c | 4 ++--
net/tipc/config.h | 4 ++--
net/tipc/core.c | 37 ++++++-------------------------------
net/tipc/core.h | 1 -
net/tipc/eth_media.c | 5 ++++-
net/tipc/ib_media.c | 5 ++++-
net/tipc/net.c | 3 +++
8 files changed, 25 insertions(+), 38 deletions(-)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index c71da45..04621ee 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -85,6 +85,7 @@ int tipc_register_media(struct tipc_media *m_ptr)
{
int res = -EINVAL;
+ mutex_lock(&config_mutex);
write_lock_bh(&tipc_net_lock);
if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME)
@@ -104,6 +105,7 @@ int tipc_register_media(struct tipc_media *m_ptr)
res = 0;
exit:
write_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
if (res)
pr_warn("Media <%s> registration error\n", m_ptr->name);
return res;
@@ -114,6 +116,7 @@ void tipc_unregister_media(const struct tipc_media *m_ptr)
struct tipc_media *m;
u32 i;
+ mutex_lock(&config_mutex);
write_lock_bh(&tipc_net_lock);
for (i = 0; i < media_count; i++) {
m = media_list[i];
@@ -124,6 +127,7 @@ void tipc_unregister_media(const struct tipc_media *m_ptr)
}
}
write_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
}
/**
diff --git a/net/tipc/config.c b/net/tipc/config.c
index c301a9a..dc39fc4 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -42,7 +42,7 @@
#define REPLY_TRUNCATED "<truncated>\n"
-static DEFINE_MUTEX(config_mutex);
+DEFINE_MUTEX(config_mutex);
static struct tipc_server cfgsrv;
static const void *req_tlv_area; /* request message TLV area */
@@ -181,7 +181,7 @@ static struct sk_buff *cfg_set_own_addr(void)
if (tipc_own_addr)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
- tipc_core_start_net(addr);
+ tipc_net_start(addr);
return tipc_cfg_reply_none();
}
diff --git a/net/tipc/config.h b/net/tipc/config.h
index 1f252f3..3c079c2 100644
--- a/net/tipc/config.h
+++ b/net/tipc/config.h
@@ -37,10 +37,10 @@
#ifndef _TIPC_CONFIG_H
#define _TIPC_CONFIG_H
-/* ---------------------------------------------------------------------- */
-
#include "link.h"
+extern struct mutex config_mutex;
+
struct sk_buff *tipc_cfg_reply_alloc(int payload_size);
int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
void *tlv_data, int tlv_data_size);
diff --git a/net/tipc/core.c b/net/tipc/core.c
index fd4eeea..395167d 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -77,41 +77,13 @@ struct sk_buff *tipc_buf_acquire(u32 size)
}
/**
- * tipc_core_stop_net - shut down TIPC networking sub-systems
+ * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
*/
-static void tipc_core_stop_net(void)
+static void tipc_core_stop(void)
{
tipc_net_stop();
tipc_eth_media_stop();
tipc_ib_media_stop();
-}
-
-/**
- * start_net - start TIPC networking sub-systems
- */
-int tipc_core_start_net(unsigned long addr)
-{
- int res;
-
- tipc_net_start(addr);
- res = tipc_eth_media_start();
- if (res < 0)
- goto err;
- res = tipc_ib_media_start();
- if (res < 0)
- goto err;
- return res;
-
-err:
- tipc_core_stop_net();
- return res;
-}
-
-/**
- * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
- */
-static void tipc_core_stop(void)
-{
tipc_netlink_stop();
tipc_handler_stop();
tipc_cfg_stop();
@@ -146,6 +118,10 @@ static int tipc_core_start(void)
res = tipc_subscr_start();
if (!res)
res = tipc_cfg_init();
+ if (!res)
+ res = tipc_eth_media_start();
+ if (!res)
+ res = tipc_ib_media_start();
if (res)
tipc_core_stop();
@@ -178,7 +154,6 @@ static int __init tipc_init(void)
static void __exit tipc_exit(void)
{
- tipc_core_stop_net();
tipc_core_stop();
pr_info("Deactivated\n");
}
diff --git a/net/tipc/core.h b/net/tipc/core.h
index bef34ea..5402044 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -90,7 +90,6 @@ extern int tipc_random __read_mostly;
/*
* Routines available to privileged subsystems
*/
-int tipc_core_start_net(unsigned long);
int tipc_handler_start(void);
void tipc_handler_stop(void);
int tipc_netlink_start(void);
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 7641374..ddcc28b 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -36,7 +36,7 @@
#include "core.h"
#include "bearer.h"
-#include "net.h"
+#include "config.h"
#define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */
@@ -214,10 +214,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
+ mutex_lock(&config_mutex);
read_lock_bh(&tipc_net_lock);
eb_ptr = media_get(dev->ifindex);
if (!eb_ptr) {
read_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
return NOTIFY_DONE; /* bearer had been disabled */
}
@@ -249,6 +251,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
break;
}
read_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
return NOTIFY_OK;
}
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index fb38616..371badb 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -41,7 +41,7 @@
#include <linux/if_infiniband.h>
#include "core.h"
#include "bearer.h"
-#include "net.h"
+#include "config.h"
/**
* struct ib_media - Infiniband media data structure
@@ -218,10 +218,12 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
+ mutex_lock(&config_mutex);
read_lock_bh(&tipc_net_lock);
ib_ptr = media_get(dev->ifindex);
if (!ib_ptr) {
read_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
return NOTIFY_DONE; /* bearer had been disabled */
}
@@ -253,6 +255,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
break;
}
read_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
return NOTIFY_OK;
}
diff --git a/net/tipc/net.c b/net/tipc/net.c
index 7d305ec..94f4e45 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -195,11 +195,14 @@ void tipc_net_stop(void)
if (!tipc_own_addr)
return;
+
+ mutex_lock(&config_mutex);
write_lock_bh(&tipc_net_lock);
tipc_bearer_stop();
tipc_bclink_stop();
list_for_each_entry_safe(node, t_node, &tipc_node_list, list)
tipc_node_delete(node);
write_unlock_bh(&tipc_net_lock);
+ mutex_unlock(&config_mutex);
pr_info("Left network mode\n");
}
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:10
|
As tipc_bearers will be protected by RCU lock, tipc_bearers is
defined as static array where the data of tipc_bearer struct is
located in each array element. But since static array has not seen
with RCU, tipc_bearers should be redefined to a pointer array where
a pointer pointed to dynamically allocated instance of tipc_bearer
struct is located in each array element, allowing the pointer
array to be protected with RCU.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/bcast.c | 6 +++---
net/tipc/bearer.c | 53 ++++++++++++++++++++++++++++++++++++++---------------
net/tipc/bearer.h | 2 +-
3 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index c78f30c..0378fda 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -660,6 +660,7 @@ void tipc_bcbearer_sort(void)
{
struct tipc_bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
struct tipc_bcbearer_pair *bp_curr;
+ struct tipc_bearer *b;
int b_index;
int pri;
@@ -669,9 +670,8 @@ void tipc_bcbearer_sort(void)
memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
- struct tipc_bearer *b = &tipc_bearers[b_index];
-
- if (!b->active || !b->nodes.count)
+ b = bearer_list[b_index];
+ if (!b || !b->active || !b->nodes.count)
continue;
if (!bp_temp[b->priority].primary)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 04621ee..4971169 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -42,10 +42,9 @@
#define MAX_ADDR_STR 60
static struct tipc_media *media_list[MAX_MEDIA];
+struct tipc_bearer *bearer_list[MAX_BEARERS];
static u32 media_count;
-struct tipc_bearer tipc_bearers[MAX_BEARERS];
-
static void bearer_disable(struct tipc_bearer *b_ptr);
/**
@@ -228,8 +227,9 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
struct tipc_bearer *b_ptr;
u32 i;
- for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
- if (b_ptr->active && (!strcmp(b_ptr->name, name)))
+ for (i = 0; i < MAX_BEARERS; i++) {
+ b_ptr = bearer_list[i];
+ if (b_ptr && b_ptr->active && (!strcmp(b_ptr->name, name)))
return b_ptr;
}
return NULL;
@@ -244,8 +244,9 @@ struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
char *b_if_name;
u32 i;
- for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
- if (!b_ptr->active)
+ for (i = 0; i < MAX_BEARERS; i++) {
+ b_ptr = bearer_list[i];
+ if (!b_ptr || !b_ptr->active)
continue;
b_if_name = strchr(b_ptr->name, ':') + 1;
if (!strcmp(b_if_name, if_name))
@@ -270,7 +271,9 @@ struct sk_buff *tipc_bearer_get_names(void)
read_lock_bh(&tipc_net_lock);
for (i = 0; i < media_count; i++) {
for (j = 0; j < MAX_BEARERS; j++) {
- b_ptr = &tipc_bearers[j];
+ b_ptr = bearer_list[j];
+ if (!b_ptr)
+ continue;
if (b_ptr->active && (b_ptr->media == media_list[i])) {
tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
b_ptr->name,
@@ -354,17 +357,17 @@ restart:
bearer_id = MAX_BEARERS;
with_this_prio = 1;
for (i = MAX_BEARERS; i-- != 0; ) {
- if (!tipc_bearers[i].active) {
+ b_ptr = bearer_list[i];
+ if (!b_ptr || !b_ptr->active) {
bearer_id = i;
continue;
}
- if (!strcmp(name, tipc_bearers[i].name)) {
+ if (!strcmp(name, b_ptr->name)) {
pr_warn("Bearer <%s> rejected, already enabled\n",
name);
goto exit;
}
- if ((tipc_bearers[i].priority == priority) &&
- (++with_this_prio > 2)) {
+ if ((b_ptr->priority == priority) && (++with_this_prio > 2)) {
if (priority-- == 0) {
pr_warn("Bearer <%s> rejected, duplicate priority\n",
name);
@@ -381,7 +384,12 @@ restart:
goto exit;
}
- b_ptr = &tipc_bearers[bearer_id];
+ b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
+ if (!b_ptr) {
+ res = -ENOMEM;
+ goto exit;
+ }
+
strcpy(b_ptr->name, name);
atomic_set(&b_ptr->blocked, 0);
res = m_ptr->enable_media(b_ptr);
@@ -408,6 +416,9 @@ restart:
name);
goto exit;
}
+
+ bearer_list[bearer_id] = b_ptr;
+
pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
name,
tipc_addr_string_fill(addr_string, disc_domain), priority);
@@ -447,9 +458,17 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
{
struct tipc_link *l_ptr;
struct tipc_link *temp_l_ptr;
+ u32 i;
pr_info("Disabling bearer <%s>\n", b_ptr->name);
atomic_set(&b_ptr->blocked, 1);
+ for (i = 0; i < MAX_BEARERS; i++) {
+ if (b_ptr == bearer_list[i]) {
+ bearer_list[i] = NULL;
+ break;
+ }
+ }
+
spin_lock_bh(&b_ptr->lock);
b_ptr->media->disable_media(b_ptr);
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
@@ -458,7 +477,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
if (b_ptr->link_req)
tipc_disc_delete(b_ptr->link_req);
spin_unlock_bh(&b_ptr->lock);
- memset(b_ptr, 0, sizeof(struct tipc_bearer));
+ kfree(b_ptr);
}
int tipc_disable_bearer(const char *name)
@@ -481,11 +500,15 @@ int tipc_disable_bearer(const char *name)
void tipc_bearer_stop(void)
{
+ struct tipc_bearer *b_ptr;
u32 i;
for (i = 0; i < MAX_BEARERS; i++) {
- if (tipc_bearers[i].active)
- bearer_disable(&tipc_bearers[i]);
+ b_ptr = bearer_list[i];
+ if (b_ptr && b_ptr->active) {
+ bearer_disable(b_ptr);
+ bearer_list[i] = NULL;
+ }
}
media_count = 0;
}
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 280c23d..757eda9 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -154,7 +154,7 @@ struct tipc_bearer_names {
struct tipc_link;
-extern struct tipc_bearer tipc_bearers[];
+extern struct tipc_bearer *bearer_list[];
/*
* TIPC routines available to supported media types
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:12
|
In tipc_bearer struct there has usr_handle member pointing to media
object; in media struct, there is also a similar pointer called bearer
pointing to bearer object. When they access each other, one has to
use its pointer to access peer. But as the life cycle of both objects
is always same, now we let media struct contain bearer object directly,
having their relationship simpler.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/bearer.c | 19 +++++++------------
net/tipc/bearer.h | 4 +---
net/tipc/eth_media.c | 42 ++++++++++++++++++++++--------------------
net/tipc/ib_media.c | 42 ++++++++++++++++++++++--------------------
4 files changed, 52 insertions(+), 55 deletions(-)
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 4971169..485fcc0 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -384,21 +384,16 @@ restart:
goto exit;
}
- b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
- if (!b_ptr) {
- res = -ENOMEM;
- goto exit;
- }
-
- strcpy(b_ptr->name, name);
- atomic_set(&b_ptr->blocked, 0);
- res = m_ptr->enable_media(b_ptr);
- if (res) {
+ b_ptr = m_ptr->enable_media(name);
+ if (IS_ERR(b_ptr)) {
+ res = PTR_ERR(b_ptr);
pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
name, -res);
goto exit;
}
+ strcpy(b_ptr->name, name);
+ atomic_set(&b_ptr->blocked, 0);
b_ptr->identity = bearer_id;
b_ptr->media = m_ptr;
b_ptr->tolerance = m_ptr->tolerance;
@@ -470,14 +465,14 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
}
spin_lock_bh(&b_ptr->lock);
- b_ptr->media->disable_media(b_ptr);
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
tipc_link_delete(l_ptr);
}
if (b_ptr->link_req)
tipc_disc_delete(b_ptr->link_req);
spin_unlock_bh(&b_ptr->lock);
- kfree(b_ptr);
+
+ b_ptr->media->disable_media(b_ptr);
}
int tipc_disable_bearer(const char *name)
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 757eda9..6c6b3b5 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -91,7 +91,7 @@ struct tipc_media {
int (*send_msg)(struct sk_buff *buf,
struct tipc_bearer *b_ptr,
struct tipc_media_addr *dest);
- int (*enable_media)(struct tipc_bearer *b_ptr);
+ struct tipc_bearer *(*enable_media)(const char *name);
void (*disable_media)(struct tipc_bearer *b_ptr);
int (*addr2str)(struct tipc_media_addr *a, char *str_buf, int str_size);
int (*addr2msg)(struct tipc_media_addr *a, char *msg_area);
@@ -106,7 +106,6 @@ struct tipc_media {
/**
* struct tipc_bearer - TIPC bearer structure
- * @usr_handle: pointer to additional media-specific information about bearer
* @mtu: max packet size bearer can support
* @blocked: non-zero if bearer is blocked
* @lock: spinlock for controlling access to bearer
@@ -128,7 +127,6 @@ struct tipc_media {
* care of initializing all other fields.
*/
struct tipc_bearer {
- void *usr_handle; /* initalized by media */
u32 mtu; /* initalized by media */
atomic_t blocked;
struct tipc_media_addr addr; /* initalized by media */
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index ddcc28b..bf29413 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -42,12 +42,12 @@
/**
* struct eth_media - Ethernet bearer data structure
- * @bearer: ptr to associated "generic" bearer structure
+ * @bearer: generic bearer structure
* @hlist: Ethernet media hash chain
* @dev: ptr to associated Ethernet network device
*/
struct eth_media {
- struct tipc_bearer *bearer;
+ struct tipc_bearer bearer;
struct hlist_node hlist;
struct net_device *dev;
};
@@ -101,7 +101,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
if (!clone)
return 0;
- dev = ((struct eth_media *)(tb_ptr->usr_handle))->dev;
+ dev = ((struct eth_media *)(tb_ptr))->dev;
delta = dev->hard_header_len - skb_headroom(buf);
if ((delta > 0) &&
@@ -141,7 +141,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
if (likely(eb_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
- tipc_recv_msg(buf, eb_ptr->bearer);
+ tipc_recv_msg(buf, (struct tipc_bearer *)eb_ptr);
read_unlock_bh(&tipc_net_lock);
return NET_RX_SUCCESS;
}
@@ -154,27 +154,27 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
/**
* enable_media - attach TIPC bearer to an Ethernet interface
*/
-static int enable_media(struct tipc_bearer *tb_ptr)
+static struct tipc_bearer *enable_media(const char *name)
{
struct net_device *dev;
struct eth_media *eb_ptr;
- char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
+ struct tipc_bearer *tb_ptr;
+ char *driver_name = strchr(name, ':') + 1;
/* Find device with specified name */
dev = dev_get_by_name(&init_net, driver_name);
if (!dev)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
/* Create Ethernet bearer for device */
eb_ptr = kzalloc(sizeof(*eb_ptr), GFP_ATOMIC);
if (!eb_ptr)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
eb_ptr->dev = dev;
/* Associate TIPC bearer with Ethernet bearer */
- eb_ptr->bearer = tb_ptr;
- tb_ptr->usr_handle = (void *)eb_ptr;
+ tb_ptr = (struct tipc_bearer *)eb_ptr;
memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN);
tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH;
@@ -182,7 +182,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
tb_ptr->mtu = dev->mtu;
eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
hlist_add_head(&eb_ptr->hlist, media_hashfn(dev->ifindex));
- return 0;
+ return tb_ptr;
}
/**
@@ -192,7 +192,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
*/
static void disable_media(struct tipc_bearer *tb_ptr)
{
- struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle;
+ struct eth_media *eb_ptr = (struct eth_media *)tb_ptr;
hlist_del(&eb_ptr->hlist);
dev_put(eb_ptr->dev);
@@ -210,6 +210,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct eth_media *eb_ptr;
+ struct tipc_bearer *b_ptr;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
@@ -223,30 +224,31 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
return NOTIFY_DONE; /* bearer had been disabled */
}
- eb_ptr->bearer->mtu = dev->mtu;
+ b_ptr = (struct tipc_bearer *)eb_ptr;
+ b_ptr->mtu = dev->mtu;
switch (evt) {
case NETDEV_CHANGE:
if (netif_carrier_ok(dev))
- atomic_set(&eb_ptr->bearer->blocked, 0);
+ atomic_set(&b_ptr->blocked, 0);
else
- tipc_block_bearer(eb_ptr->bearer);
+ tipc_block_bearer(b_ptr);
break;
case NETDEV_UP:
- atomic_set(&eb_ptr->bearer->blocked, 0);
+ atomic_set(&b_ptr->blocked, 0);
break;
case NETDEV_DOWN:
- tipc_block_bearer(eb_ptr->bearer);
+ tipc_block_bearer(b_ptr);
break;
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
- tipc_block_bearer(eb_ptr->bearer);
- atomic_set(&eb_ptr->bearer->blocked, 0);
+ tipc_block_bearer(b_ptr);
+ atomic_set(&b_ptr->blocked, 0);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
read_unlock_bh(&tipc_net_lock);
- tipc_disable_bearer(eb_ptr->bearer->name);
+ tipc_disable_bearer(b_ptr->name);
read_lock_bh(&tipc_net_lock);
break;
}
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index 371badb..696d1c3 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -45,13 +45,13 @@
/**
* struct ib_media - Infiniband media data structure
- * @bearer: ptr to associated "generic" bearer structure
+ * @bearer: generic bearer structure
* @hlist: Infiniband media hash chain
* @dev: ptr to associated Infiniband network device
*/
struct ib_media {
- struct tipc_bearer *bearer;
+ struct tipc_bearer bearer;
struct hlist_node hlist;
struct net_device *dev;
};
@@ -105,7 +105,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
if (!clone)
return 0;
- dev = ((struct ib_media *)(tb_ptr->usr_handle))->dev;
+ dev = ((struct ib_media *)(tb_ptr))->dev;
delta = dev->hard_header_len - skb_headroom(buf);
if ((delta > 0) &&
@@ -145,7 +145,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
if (likely(ib_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
- tipc_recv_msg(buf, ib_ptr->bearer);
+ tipc_recv_msg(buf, (struct tipc_bearer *)ib_ptr);
read_unlock_bh(&tipc_net_lock);
return NET_RX_SUCCESS;
}
@@ -158,27 +158,27 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
/**
* enable_media - attach TIPC bearer to an InfiniBand interface
*/
-static int enable_media(struct tipc_bearer *tb_ptr)
+static struct tipc_bearer *enable_media(const char *name)
{
struct net_device *dev;
struct ib_media *ib_ptr;
- char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
+ struct tipc_bearer *tb_ptr;
+ char *driver_name = strchr(name, ':') + 1;
/* Find device with specified name */
dev = dev_get_by_name(&init_net, driver_name);
if (!dev)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
/* Create InfiniBand bearer for device */
ib_ptr = kzalloc(sizeof(*ib_ptr), GFP_ATOMIC);
if (!ib_ptr)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
ib_ptr->dev = dev;
/* Associate TIPC bearer with InfiniBand bearer */
- ib_ptr->bearer = tb_ptr;
- tb_ptr->usr_handle = (void *)ib_ptr;
+ tb_ptr = (struct tipc_bearer *)ib_ptr;
memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN);
tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB;
@@ -186,7 +186,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
tb_ptr->mtu = dev->mtu;
ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
hlist_add_head(&ib_ptr->hlist, media_hashfn(dev->ifindex));
- return 0;
+ return tb_ptr;
}
/**
@@ -196,7 +196,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
*/
static void disable_media(struct tipc_bearer *tb_ptr)
{
- struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle;
+ struct ib_media *ib_ptr = (struct ib_media *)tb_ptr;
hlist_del(&ib_ptr->hlist);
dev_put(ib_ptr->dev);
@@ -214,6 +214,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct ib_media *ib_ptr;
+ struct tipc_bearer *b_ptr;
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
@@ -227,30 +228,31 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
return NOTIFY_DONE; /* bearer had been disabled */
}
- ib_ptr->bearer->mtu = dev->mtu;
+ b_ptr = (struct tipc_bearer *)ib_ptr;
+ b_ptr->mtu = dev->mtu;
switch (evt) {
case NETDEV_CHANGE:
if (netif_carrier_ok(dev))
- atomic_set(&ib_ptr->bearer->blocked, 0);
+ atomic_set(&b_ptr->blocked, 0);
else
- tipc_block_bearer(ib_ptr->bearer);
+ tipc_block_bearer(b_ptr);
break;
case NETDEV_UP:
- atomic_set(&ib_ptr->bearer->blocked, 0);
+ atomic_set(&b_ptr->blocked, 0);
break;
case NETDEV_DOWN:
- tipc_block_bearer(ib_ptr->bearer);
+ tipc_block_bearer(b_ptr);
break;
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
- tipc_block_bearer(ib_ptr->bearer);
- atomic_set(&ib_ptr->bearer->blocked, 0);
+ tipc_block_bearer(b_ptr);
+ atomic_set(&b_ptr->blocked, 0);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
read_unlock_bh(&tipc_net_lock);
- tipc_disable_bearer(ib_ptr->bearer->name);
+ tipc_disable_bearer(b_ptr->name);
read_lock_bh(&tipc_net_lock);
break;
}
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:15
|
A trivial optimization is made for tipc_disc_recv_msg() by adding a
common unwind section to reduce duplicated code.
Signed-off-by: Ying Xue <yin...@wi...>
---
net/tipc/discover.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index d8b49fb..8f86fcf 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -199,8 +199,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
/* delayed rediscovery */
} else {
disc_dupl_alert(b_ptr, orig, &media_addr);
- tipc_node_unlock(n_ptr);
- return;
+ goto exit;
}
n_ptr->signature = signature;
}
@@ -218,8 +217,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
if (addr_mismatch) {
if (tipc_link_is_up(link)) {
disc_dupl_alert(b_ptr, orig, &media_addr);
- tipc_node_unlock(n_ptr);
- return;
+ goto exit;
} else {
memcpy(&link->media_addr, &media_addr,
sizeof(media_addr));
@@ -230,10 +228,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
/* Create a link endpoint for this bearer, if necessary */
if (!link) {
link = tipc_link_create(n_ptr, b_ptr, &media_addr);
- if (!link) {
- tipc_node_unlock(n_ptr);
- return;
- }
+ if (!link)
+ goto exit;
}
/* Accept discovery message & send response, if necessary */
@@ -247,7 +243,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
kfree_skb(rbuf);
}
}
-
+exit:
tipc_node_unlock(n_ptr);
}
--
1.7.9.5
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 08:27:18
|
When the 'links' list of tipc_bearer structure is traversed in tipc_block_bearer() to reset all links owned by the bearer and and each link entry from the list is removed in bearer_disable() to delete all links attached to the bearer, the list is always protected by its bearer lock, however, when one new link entry is inserted into the list when link is created, the bearer lock isn't held. So it's unsafe for us at the moment. Signed-off-by: Ying Xue <yin...@wi...> --- net/tipc/discover.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 8f86fcf..f4c3682 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -157,6 +157,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) if (!n_ptr) return; } + + spin_lock_bh(&b_ptr->lock); tipc_node_lock(n_ptr); /* Prepare to validate requesting node's signature and media address */ @@ -245,6 +247,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } exit: tipc_node_unlock(n_ptr); + spin_unlock_bh(&b_ptr->lock); } /** -- 1.7.9.5 |
|
From: Erik H. <eri...@er...> - 2013-08-08 08:52:11
|
On Thu, Aug 08, 2013 at 04:26:16PM +0800, Ying Xue wrote:
> When TIPC media is enabled by bearer, the "bearer" variable in the
> media instance is first initialized with the bearer pointer under
> tipc_net_lock protection; likewise, when media is disabled,
> tipc_net_lock is also first held and its "bearer" variable is then
> set to NULL. But, when the "bearer" variable is accessed in
> recv_msg() and recv_notification(), tipc_net_lock is not taken. As
> the context under which recv_msg() and recv_notification() run is
> different with media enable/disable functions, a stale "bearer"
> might be got by recv_msg() and recv_notification() occasionally.
> Therefore, before the bearer variable is read, tipc_net_lock should
> be held to get rid of the synchronous issue.
>
> Signed-off-by: Ying Xue <yin...@wi...>
> ---
> net/tipc/bearer.c | 2 --
> net/tipc/eth_media.c | 13 ++++++++++++-
> net/tipc/ib_media.c | 13 ++++++++++++-
> net/tipc/link.c | 2 --
> 4 files changed, 24 insertions(+), 6 deletions(-)
>
> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
> index 25045ba..c71da45 100644
> --- a/net/tipc/bearer.c
> +++ b/net/tipc/bearer.c
> @@ -420,7 +420,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
> struct tipc_link *l_ptr;
> struct tipc_link *temp_l_ptr;
>
> - read_lock_bh(&tipc_net_lock);
> pr_info("Blocking bearer <%s>\n", b_ptr->name);
> atomic_set(&b_ptr->blocked, 1);
> spin_lock_bh(&b_ptr->lock);
> @@ -432,7 +431,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
> spin_unlock_bh(&n_ptr->lock);
> }
> spin_unlock_bh(&b_ptr->lock);
> - read_unlock_bh(&tipc_net_lock);
> return 0;
> }
I'm missing a motivation in the commit message why it's safe do bearer blocking
outside of tipc_net_lock protection.
By the way, shouldn't this have been done in the last patch from the
"non controversial" patchset?
tipc: convert 'blocked' flag in struct tipc_bearer to atomic_t
//E
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 09:08:12
|
On 08/08/2013 04:52 PM, Erik Hugne wrote:
> On Thu, Aug 08, 2013 at 04:26:16PM +0800, Ying Xue wrote:
>> When TIPC media is enabled by bearer, the "bearer" variable in the
>> media instance is first initialized with the bearer pointer under
>> tipc_net_lock protection; likewise, when media is disabled,
>> tipc_net_lock is also first held and its "bearer" variable is then
>> set to NULL. But, when the "bearer" variable is accessed in
>> recv_msg() and recv_notification(), tipc_net_lock is not taken. As
>> the context under which recv_msg() and recv_notification() run is
>> different with media enable/disable functions, a stale "bearer"
>> might be got by recv_msg() and recv_notification() occasionally.
>> Therefore, before the bearer variable is read, tipc_net_lock should
>> be held to get rid of the synchronous issue.
>>
>> Signed-off-by: Ying Xue <yin...@wi...>
>> ---
>> net/tipc/bearer.c | 2 --
>> net/tipc/eth_media.c | 13 ++++++++++++-
>> net/tipc/ib_media.c | 13 ++++++++++++-
>> net/tipc/link.c | 2 --
>> 4 files changed, 24 insertions(+), 6 deletions(-)
>>
>> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
>> index 25045ba..c71da45 100644
>> --- a/net/tipc/bearer.c
>> +++ b/net/tipc/bearer.c
>> @@ -420,7 +420,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>> struct tipc_link *l_ptr;
>> struct tipc_link *temp_l_ptr;
>>
>> - read_lock_bh(&tipc_net_lock);
>> pr_info("Blocking bearer <%s>\n", b_ptr->name);
>> atomic_set(&b_ptr->blocked, 1);
>> spin_lock_bh(&b_ptr->lock);
>> @@ -432,7 +431,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>> spin_unlock_bh(&n_ptr->lock);
>> }
>> spin_unlock_bh(&b_ptr->lock);
>> - read_unlock_bh(&tipc_net_lock);
>> return 0;
>> }
>
> I'm missing a motivation in the commit message why it's safe do bearer blocking
> outside of tipc_net_lock protection.
Please notice we now place tipc_net_lock(read) lock into
recv_notification(), and recv_notification() is the only user of
tipc_block_bearer(). So in tipc_block_bearer(), tipc_net_lock is not
useful, but it's still protected by tipc_net_lock.
> By the way, shouldn't this have been done in the last patch from the
> "non controversial" patchset?
This decision should be made by Jon right now :)
Regards,
Ying
> tipc: convert 'blocked' flag in struct tipc_bearer to atomic_t
>
> //E
>
>
|
|
From: Jon M. <ma...@do...> - 2013-08-09 03:59:38
|
On 08/08/2013 05:07 AM, Ying Xue wrote:
> On 08/08/2013 04:52 PM, Erik Hugne wrote:
>> On Thu, Aug 08, 2013 at 04:26:16PM +0800, Ying Xue wrote:
>>> When TIPC media is enabled by bearer, the "bearer" variable in the
>>> media instance is first initialized with the bearer pointer under
>>> tipc_net_lock protection; likewise, when media is disabled,
>>> tipc_net_lock is also first held and its "bearer" variable is then
>>> set to NULL. But, when the "bearer" variable is accessed in
>>> recv_msg() and recv_notification(), tipc_net_lock is not taken. As
>>> the context under which recv_msg() and recv_notification() run is
>>> different with media enable/disable functions, a stale "bearer"
>>> might be got by recv_msg() and recv_notification() occasionally.
>>> Therefore, before the bearer variable is read, tipc_net_lock should
>>> be held to get rid of the synchronous issue.
>>>
>>> Signed-off-by: Ying Xue <yin...@wi...>
>>> ---
>>> net/tipc/bearer.c | 2 --
>>> net/tipc/eth_media.c | 13 ++++++++++++-
>>> net/tipc/ib_media.c | 13 ++++++++++++-
>>> net/tipc/link.c | 2 --
>>> 4 files changed, 24 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
>>> index 25045ba..c71da45 100644
>>> --- a/net/tipc/bearer.c
>>> +++ b/net/tipc/bearer.c
>>> @@ -420,7 +420,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>>> struct tipc_link *l_ptr;
>>> struct tipc_link *temp_l_ptr;
>>>
>>> - read_lock_bh(&tipc_net_lock);
>>> pr_info("Blocking bearer <%s>\n", b_ptr->name);
>>> atomic_set(&b_ptr->blocked, 1);
>>> spin_lock_bh(&b_ptr->lock);
>>> @@ -432,7 +431,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>>> spin_unlock_bh(&n_ptr->lock);
>>> }
>>> spin_unlock_bh(&b_ptr->lock);
>>> - read_unlock_bh(&tipc_net_lock);
>>> return 0;
>>> }
>> I'm missing a motivation in the commit message why it's safe do bearer blocking
>> outside of tipc_net_lock protection.
> Please notice we now place tipc_net_lock(read) lock into
> recv_notification(), and recv_notification() is the only user of
> tipc_block_bearer(). So in tipc_block_bearer(), tipc_net_lock is not
> useful, but it's still protected by tipc_net_lock.
>
>> By the way, shouldn't this have been done in the last patch from the
>> "non controversial" patchset?
Just in case you wonder: I am holding these patches because I see that
David's backlog is long. This according to Paul's recommendation.
///jon
> This decision should be made by Jon right now :)
>
> Regards,
> Ying
>
>> tipc: convert 'blocked' flag in struct tipc_bearer to atomic_t
>>
>> //E
>>
>>
|
|
From: Erik H. <eri...@er...> - 2013-08-08 09:16:55
|
On Thu, Aug 08, 2013 at 04:26:17PM +0800, Ying Xue wrote:
> [...]
> -static int recv_notification(struct notifier_block *nb, unsigned long evt,
> - void *dv);
> -/*
> - * Network device notifier info
> - */
> -static struct notifier_block notifier = {
> - .notifier_call = recv_notification,
> - .priority = 0
> -};
> +static inline struct hlist_head *media_hashfn(int ifindex)
> +{
> + return &media_hlist[ifindex & (NETDEV_HASHENTRIES - 1)];
> +}
> +
> +static struct eth_media *media_get(int ifindex)
> +{
> + struct eth_media *eb_ptr;
> + struct hlist_head *head = media_hashfn(ifindex);
> +
> + hlist_for_each_entry(eb_ptr, head, hlist)
> + if (eb_ptr->dev->ifindex == ifindex)
> + return eb_ptr;
> + return NULL;
> +}
The patch diff size can be reduced by moving these functions
before recv_notification.
> [...]
> @@ -155,10 +161,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
> */
> static void setup_media(struct work_struct *work)
> {
> - struct eth_media *eb_ptr =
> - container_of(work, struct eth_media, setup);
> -
> - dev_add_pack(&eb_ptr->tipc_packet_type);
> + dev_add_pack(&tipc_packet_type);
> }
I think this is wrong, we want to register tipc_packet_type handler once, not
for each ethernet bearer enabled. I suggest this function is dropped, and that
we call dev_add_pack immediately when the tipc module is loaded in
eth_media_start instead.
After writing the comments for this, i see that it's actually done in the
next patch. Not good to add code in one patch only to move/remove it in the
subsequent one. I suggest that this patch is merged with:
tipc: move registration of TIPC packet handler to media start
> [...]
> @@ -217,9 +210,9 @@ static void cleanup_media(struct work_struct *work)
> struct eth_media *eb_ptr =
> container_of(work, struct eth_media, cleanup);
>
> - dev_remove_pack(&eb_ptr->tipc_packet_type);
> + dev_remove_pack(&tipc_packet_type);
> dev_put(eb_ptr->dev);
> - eb_ptr->dev = NULL;
> + kfree(eb_ptr);
> }
Same here, drop this function, free the bearer immediately in disable_media()
and call dev_remove_pack when we do eth_media_stop instead.
> [...]
> @@ -148,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
> */
> static void setup_media(struct work_struct *work)
> {
> - struct ib_media *ib_ptr =
> - container_of(work, struct ib_media, setup);
> -
> - dev_add_pack(&ib_ptr->tipc_packet_type);
> + dev_add_pack(&tipc_packet_type);
> }
Same comment as for ethernet media/dev_add_pack.
> [...]
> @@ -210,9 +213,9 @@ static void cleanup_bearer(struct work_struct *work)
> struct ib_media *ib_ptr =
> container_of(work, struct ib_media, cleanup);
>
> - dev_remove_pack(&ib_ptr->tipc_packet_type);
> + dev_remove_pack(&tipc_packet_type);
> dev_put(ib_ptr->dev);
> - ib_ptr->dev = NULL;
> + kfree(ib_ptr);
> }
Same comment as for ethernet media/dev_remove_pack
|
|
From: Ying X. <yin...@wi...> - 2013-08-08 09:45:08
|
On 08/08/2013 05:16 PM, Erik Hugne wrote:
> On Thu, Aug 08, 2013 at 04:26:17PM +0800, Ying Xue wrote:
>> [...]
>> -static int recv_notification(struct notifier_block *nb, unsigned long evt,
>> - void *dv);
>> -/*
>> - * Network device notifier info
>> - */
>> -static struct notifier_block notifier = {
>> - .notifier_call = recv_notification,
>> - .priority = 0
>> -};
>> +static inline struct hlist_head *media_hashfn(int ifindex)
>> +{
>> + return &media_hlist[ifindex & (NETDEV_HASHENTRIES - 1)];
>> +}
>> +
>> +static struct eth_media *media_get(int ifindex)
>> +{
>> + struct eth_media *eb_ptr;
>> + struct hlist_head *head = media_hashfn(ifindex);
>> +
>> + hlist_for_each_entry(eb_ptr, head, hlist)
>> + if (eb_ptr->dev->ifindex == ifindex)
>> + return eb_ptr;
>> + return NULL;
>> +}
>
> The patch diff size can be reduced by moving these functions
> before recv_notification.
>
>> [...]
>> @@ -155,10 +161,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
>> */
>> static void setup_media(struct work_struct *work)
>> {
>> - struct eth_media *eb_ptr =
>> - container_of(work, struct eth_media, setup);
>> -
>> - dev_add_pack(&eb_ptr->tipc_packet_type);
>> + dev_add_pack(&tipc_packet_type);
>> }
>
> I think this is wrong, we want to register tipc_packet_type handler once, not
> for each ethernet bearer enabled.
No, here is not wrong absolutely because we one tipc protocol handler is
registered when now each bearer/media is enabled. So when media/bearer
is disabled, protocol handler should be removed too.
I suggest this function is dropped, and that
> we call dev_add_pack immediately when the tipc module is loaded in
> eth_media_start instead.
>
> After writing the comments for this, i see that it's actually done in the
> next patch. Not good to add code in one patch only to move/remove it in the
> subsequent one. I suggest that this patch is merged with:
> tipc: move registration of TIPC packet handler to media start
>
On one hand, the patch is already a bit big, but merging them will make
it more bigger; on another hand, most of patches in this series are not
final versions. When we involve RCU, we have to change many codes which
are added/modified by the series. In all, by my understanding this needs
more skills or even tricks about how to divide patch.
Additionally, there have no much differences between v1 and v2.
Beside changelogs being revised, what most of works are done in v2 is
that patches in v1 are reorganized again.
In conclusion, sometimes I am very confused about how to divide patches,
having reviewers more understandable for our made patches.
But, by my experience, smaller patches seem a little better :)
Regards,
Ying
>> [...]
>> @@ -217,9 +210,9 @@ static void cleanup_media(struct work_struct *work)
>> struct eth_media *eb_ptr =
>> container_of(work, struct eth_media, cleanup);
>>
>> - dev_remove_pack(&eb_ptr->tipc_packet_type);
>> + dev_remove_pack(&tipc_packet_type);
>> dev_put(eb_ptr->dev);
>> - eb_ptr->dev = NULL;
>> + kfree(eb_ptr);
>> }
>
> Same here, drop this function, free the bearer immediately in disable_media()
> and call dev_remove_pack when we do eth_media_stop instead.
>
>> [...]
>> @@ -148,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
>> */
>> static void setup_media(struct work_struct *work)
>> {
>> - struct ib_media *ib_ptr =
>> - container_of(work, struct ib_media, setup);
>> -
>> - dev_add_pack(&ib_ptr->tipc_packet_type);
>> + dev_add_pack(&tipc_packet_type);
>> }
>
> Same comment as for ethernet media/dev_add_pack.
>
>> [...]
>> @@ -210,9 +213,9 @@ static void cleanup_bearer(struct work_struct *work)
>> struct ib_media *ib_ptr =
>> container_of(work, struct ib_media, cleanup);
>>
>> - dev_remove_pack(&ib_ptr->tipc_packet_type);
>> + dev_remove_pack(&tipc_packet_type);
>> dev_put(ib_ptr->dev);
>> - ib_ptr->dev = NULL;
>> + kfree(ib_ptr);
>> }
>
> Same comment as for ethernet media/dev_remove_pack
>
>
>
|
|
From: Jon M. <ma...@do...> - 2013-08-09 03:57:08
|
On 08/08/2013 05:07 AM, Ying Xue wrote:
> On 08/08/2013 04:52 PM, Erik Hugne wrote:
>> On Thu, Aug 08, 2013 at 04:26:16PM +0800, Ying Xue wrote:
>>> When TIPC media is enabled by bearer, the "bearer" variable in the
>>> media instance is first initialized with the bearer pointer under
>>> tipc_net_lock protection; likewise, when media is disabled,
>>> tipc_net_lock is also first held and its "bearer" variable is then
>>> set to NULL. But, when the "bearer" variable is accessed in
>>> recv_msg() and recv_notification(), tipc_net_lock is not taken. As
>>> the context under which recv_msg() and recv_notification() run is
>>> different with media enable/disable functions, a stale "bearer"
>>> might be got by recv_msg() and recv_notification() occasionally.
>>> Therefore, before the bearer variable is read, tipc_net_lock should
>>> be held to get rid of the synchronous issue.
>>>
>>> Signed-off-by: Ying Xue <yin...@wi...>
>>> ---
>>> net/tipc/bearer.c | 2 --
>>> net/tipc/eth_media.c | 13 ++++++++++++-
>>> net/tipc/ib_media.c | 13 ++++++++++++-
>>> net/tipc/link.c | 2 --
>>> 4 files changed, 24 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
>>> index 25045ba..c71da45 100644
>>> --- a/net/tipc/bearer.c
>>> +++ b/net/tipc/bearer.c
>>> @@ -420,7 +420,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>>> struct tipc_link *l_ptr;
>>> struct tipc_link *temp_l_ptr;
>>>
>>> - read_lock_bh(&tipc_net_lock);
>>> pr_info("Blocking bearer <%s>\n", b_ptr->name);
>>> atomic_set(&b_ptr->blocked, 1);
>>> spin_lock_bh(&b_ptr->lock);
>>> @@ -432,7 +431,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>>> spin_unlock_bh(&n_ptr->lock);
>>> }
>>> spin_unlock_bh(&b_ptr->lock);
>>> - read_unlock_bh(&tipc_net_lock);
>>> return 0;
>>> }
>> I'm missing a motivation in the commit message why it's safe do bearer blocking
>> outside of tipc_net_lock protection.
> Please notice we now place tipc_net_lock(read) lock into
> recv_notification(), and recv_notification() is the only user of
> tipc_block_bearer(). So in tipc_block_bearer(), tipc_net_lock is not
> useful, but it's still protected by tipc_net_lock.
>
>> By the way, shouldn't this have been done in the last patch from the
>> "non controversial" patchset?
> This decision should be made by Jon right now :)
Ok. Decision made: Let's keep them separate ;). Otherwise I will have to
improve the motivation for the introduction of the atomic_t.
I am even questioning the need for this change.
This means that all future callers of tipc_block_bearer() will have to take
net_lock. So why don't we keep it where it is, in one place?
I also notice that we access b_ptr just two lines before we grab the
bearer lock, in the pr_info() call. We know that this is safe, but there
will be questions. Why don't we move this inside the lock?
>
> Regards,
> Ying
>
>> tipc: convert 'blocked' flag in struct tipc_bearer to atomic_t
>>
>> //E
>>
>>
|
|
From: Ying X. <yin...@wi...> - 2013-08-09 06:26:24
|
On 08/09/2013 11:56 AM, Jon Maloy wrote:
> On 08/08/2013 05:07 AM, Ying Xue wrote:
>> On 08/08/2013 04:52 PM, Erik Hugne wrote:
>>> On Thu, Aug 08, 2013 at 04:26:16PM +0800, Ying Xue wrote:
>>>> When TIPC media is enabled by bearer, the "bearer" variable in the
>>>> media instance is first initialized with the bearer pointer under
>>>> tipc_net_lock protection; likewise, when media is disabled,
>>>> tipc_net_lock is also first held and its "bearer" variable is then
>>>> set to NULL. But, when the "bearer" variable is accessed in
>>>> recv_msg() and recv_notification(), tipc_net_lock is not taken. As
>>>> the context under which recv_msg() and recv_notification() run is
>>>> different with media enable/disable functions, a stale "bearer"
>>>> might be got by recv_msg() and recv_notification() occasionally.
>>>> Therefore, before the bearer variable is read, tipc_net_lock should
>>>> be held to get rid of the synchronous issue.
>>>>
>>>> Signed-off-by: Ying Xue <yin...@wi...>
>>>> ---
>>>> net/tipc/bearer.c | 2 --
>>>> net/tipc/eth_media.c | 13 ++++++++++++-
>>>> net/tipc/ib_media.c | 13 ++++++++++++-
>>>> net/tipc/link.c | 2 --
>>>> 4 files changed, 24 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
>>>> index 25045ba..c71da45 100644
>>>> --- a/net/tipc/bearer.c
>>>> +++ b/net/tipc/bearer.c
>>>> @@ -420,7 +420,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>>>> struct tipc_link *l_ptr;
>>>> struct tipc_link *temp_l_ptr;
>>>>
>>>> - read_lock_bh(&tipc_net_lock);
>>>> pr_info("Blocking bearer <%s>\n", b_ptr->name);
>>>> atomic_set(&b_ptr->blocked, 1);
>>>> spin_lock_bh(&b_ptr->lock);
>>>> @@ -432,7 +431,6 @@ int tipc_block_bearer(struct tipc_bearer *b_ptr)
>>>> spin_unlock_bh(&n_ptr->lock);
>>>> }
>>>> spin_unlock_bh(&b_ptr->lock);
>>>> - read_unlock_bh(&tipc_net_lock);
>>>> return 0;
>>>> }
>>> I'm missing a motivation in the commit message why it's safe do bearer blocking
>>> outside of tipc_net_lock protection.
>> Please notice we now place tipc_net_lock(read) lock into
>> recv_notification(), and recv_notification() is the only user of
>> tipc_block_bearer(). So in tipc_block_bearer(), tipc_net_lock is not
>> useful, but it's still protected by tipc_net_lock.
>>
>>> By the way, shouldn't this have been done in the last patch from the
>>> "non controversial" patchset?
>> This decision should be made by Jon right now :)
> Ok. Decision made: Let's keep them separate ;). Otherwise I will have to
> improve the motivation for the introduction of the atomic_t.
>
> I am even questioning the need for this change.
> This means that all future callers of tipc_block_bearer() will have to take
> net_lock. So why don't we keep it where it is, in one place?
First of all, the question is that tipc_block_bearer() currently only
has one user - recv_notification(); secondly, in recv_notification(), we
have to hold net_lock because ib_ptr->bearer/eb_ptr->bearer must be
protected by net_lock too. So net_lock should be removed from
tipc_block_bearer().
In fact, if you carefully take a look at the patch again, you will find
another changes in recv_notification() like:
@@ -254,8 +258,12 @@ static int recv_notification(struct notifier_block
*nb, unsigned long evt,
[...]
read_lock_bh(&tipc_net_lock);
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
+ read_unlock_bh(&tipc_net_lock);
tipc_disable_bearer(eb_ptr->bearer->name);
+ read_lock_bh(&tipc_net_lock);
break;
}
+ read_unlock_bh(&tipc_net_lock);
return NOTIFY_OK;
}
Above changes are safe for us because tipc_disable_bearer() will find
b_ptr handler with name. But tipc_block_bearer() now directly access
b_ptr, it's unsafe if we do the same thing like tipc_disable_bearer().
However, holding net_lock read lock will disappear in
recv_notification() if we involve RCU lock.
> I also notice that we access b_ptr just two lines before we grab the
> bearer lock, in the pr_info() call. We know that this is safe, but there
> will be questions. Why don't we move this inside the lock?
>
b_ptr->name is never changed, and blocked variable is converted to
atomic_t. Actually not only b_ptr->name is without the scope of bearer
lock protection in tipc_block_bearer(), but also in other places we also
don't hold bearer lock when accessing bearer name.
Regards,
Ying
>>
>> Regards,
>> Ying
>>
>>> tipc: convert 'blocked' flag in struct tipc_bearer to atomic_t
>>>
>>> //E
>>>
>>>
>
>
>
|
|
From: Paul G. <pau...@wi...> - 2013-09-06 23:29:30
|
[[PATCH net-next v2 00/10] media/bearer changes part of "purge the big tipc_net lock"] On 08/08/2013 (Thu 16:26) Ying Xue wrote: > v2 Changes: I'm ignoring these changes, in assuming that the Jon changes will be appearing 1st. And note that I'll be not looking at the tipc mail content for a week or more due to local obligations I have. But continue on to improve/develop/bugfix! Thanks, Paul -- > - revise changelogs of all relevant patches. > - drop the patch "[PATCH net-next v1 06/30] tipc: avoid to launch > different thread to call link_state_event". As Jason said, it's > meaningful to let tipc_link_start() run in tasklet context. > - merge patch "PATCH net-next v1 01/30] tipc: remove bearer setup > works" into patch #4 (move registration of TIPC packet handler to > media start). > - divide patch "PATCH net-next v1 10/30] tipc: convert static media > array to hash list" into two patches like patch #2 and patch #3. > - merge patch #13 "[PATCH net-next v1 13/30] tipc: move functions of > registering media into tipc_core_start routine", patch #14 "[PATCH > net-next v1 14/30] tipc: eliminate tipc core net start/stop routines" > and patch #15 "[PATCH net-next v1 15/30] tipc: use config_mutex to > protect tipc_net_stop routine" to one patch #6. > - divide patch #16 into two patches: patch #7 and patch #8. > - add a new patch #9. > - now the mapping relationship between v1 and v2 will be: > 1. old patch #1 is to new patch #4; > 2. old patch #2, #3 and #4 are included into the small > non-controversial series; > 3. old patch #4 is dropped in the series. > 4. old patch #9 is mapped to patch #1. > 5. old patch #10 is divided into patch #2 and #3. > 6. old patch #11 is mapped to patch #4. > 7. old patch #12 is mapped to patch #5. > 8. old patch #13, #14 and #15 is patch #6. > 9. old patch #16 is divided into patch #7 and #8. > 10. old patch #17 is mapped to patch #10. > 11. the rest of patches in v1 will be sent out recently. > > Ying Xue (10): > tipc: involve tipc_unregister_media routine > tipc: make bearer variable in media structure synchronous > tipc: get rid of af_packet_priv usage when register TIPC protocol > handler > tipc: move registration of TIPC packet handler to media start > tipc: remove flush_scheduled_work() from media stop routines > tipc: expand config_muex usage > tipc: convert tipc_bearers array to pointer array > tipc: make media structure contain tipc_bearer object > tipc: add common unwind section to reduce duplicated code > tipc: use bearer lock to protect links list when link is created > > net/tipc/bcast.c | 6 +- > net/tipc/bearer.c | 81 ++++++++++++++------ > net/tipc/bearer.h | 7 +- > net/tipc/config.c | 4 +- > net/tipc/config.h | 4 +- > net/tipc/core.c | 37 ++------- > net/tipc/core.h | 1 - > net/tipc/discover.c | 17 ++--- > net/tipc/eth_media.c | 203 +++++++++++++++++++++++++------------------------- > net/tipc/ib_media.c | 189 ++++++++++++++++++++++++---------------------- > net/tipc/link.c | 2 - > net/tipc/net.c | 3 + > 12 files changed, 286 insertions(+), 268 deletions(-) > > -- > 1.7.9.5 > |
|
From: Jon M. <ma...@do...> - 2013-09-24 10:28:11
|
Ying, These patches don't apply any more on top of the small-patches set. Can you please resubmit once David has applied the small patches? ///jon On 08/08/2013 03:26 AM, Ying Xue wrote: > v2 Changes: > - revise changelogs of all relevant patches. > - drop the patch "[PATCH net-next v1 06/30] tipc: avoid to launch > different thread to call link_state_event". As Jason said, it's > meaningful to let tipc_link_start() run in tasklet context. > - merge patch "PATCH net-next v1 01/30] tipc: remove bearer setup > works" into patch #4 (move registration of TIPC packet handler to > media start). > - divide patch "PATCH net-next v1 10/30] tipc: convert static media > array to hash list" into two patches like patch #2 and patch #3. > - merge patch #13 "[PATCH net-next v1 13/30] tipc: move functions of > registering media into tipc_core_start routine", patch #14 "[PATCH > net-next v1 14/30] tipc: eliminate tipc core net start/stop routines" > and patch #15 "[PATCH net-next v1 15/30] tipc: use config_mutex to > protect tipc_net_stop routine" to one patch #6. > - divide patch #16 into two patches: patch #7 and patch #8. > - add a new patch #9. > - now the mapping relationship between v1 and v2 will be: > 1. old patch #1 is to new patch #4; > 2. old patch #2, #3 and #4 are included into the small > non-controversial series; > 3. old patch #4 is dropped in the series. > 4. old patch #9 is mapped to patch #1. > 5. old patch #10 is divided into patch #2 and #3. > 6. old patch #11 is mapped to patch #4. > 7. old patch #12 is mapped to patch #5. > 8. old patch #13, #14 and #15 is patch #6. > 9. old patch #16 is divided into patch #7 and #8. > 10. old patch #17 is mapped to patch #10. > 11. the rest of patches in v1 will be sent out recently. > > Ying Xue (10): > tipc: involve tipc_unregister_media routine > tipc: make bearer variable in media structure synchronous > tipc: get rid of af_packet_priv usage when register TIPC protocol > handler > tipc: move registration of TIPC packet handler to media start > tipc: remove flush_scheduled_work() from media stop routines > tipc: expand config_muex usage > tipc: convert tipc_bearers array to pointer array > tipc: make media structure contain tipc_bearer object > tipc: add common unwind section to reduce duplicated code > tipc: use bearer lock to protect links list when link is created > > net/tipc/bcast.c | 6 +- > net/tipc/bearer.c | 81 ++++++++++++++------ > net/tipc/bearer.h | 7 +- > net/tipc/config.c | 4 +- > net/tipc/config.h | 4 +- > net/tipc/core.c | 37 ++------- > net/tipc/core.h | 1 - > net/tipc/discover.c | 17 ++--- > net/tipc/eth_media.c | 203 +++++++++++++++++++++++++------------------------- > net/tipc/ib_media.c | 189 ++++++++++++++++++++++++---------------------- > net/tipc/link.c | 2 - > net/tipc/net.c | 3 + > 12 files changed, 286 insertions(+), 268 deletions(-) > |
|
From: Ying X. <yin...@wi...> - 2013-09-25 03:05:45
|
On 09/24/2013 06:13 PM, Jon Maloy wrote: > Ying, > These patches don't apply any more on top of the small-patches set. > Can you please resubmit once David has applied the small patches? > OK, I will do as soon as possible. Regards, Ying > ///jon > > On 08/08/2013 03:26 AM, Ying Xue wrote: >> v2 Changes: >> - revise changelogs of all relevant patches. >> - drop the patch "[PATCH net-next v1 06/30] tipc: avoid to launch >> different thread to call link_state_event". As Jason said, it's >> meaningful to let tipc_link_start() run in tasklet context. >> - merge patch "PATCH net-next v1 01/30] tipc: remove bearer setup >> works" into patch #4 (move registration of TIPC packet handler to >> media start). >> - divide patch "PATCH net-next v1 10/30] tipc: convert static media >> array to hash list" into two patches like patch #2 and patch #3. >> - merge patch #13 "[PATCH net-next v1 13/30] tipc: move functions of >> registering media into tipc_core_start routine", patch #14 "[PATCH >> net-next v1 14/30] tipc: eliminate tipc core net start/stop routines" >> and patch #15 "[PATCH net-next v1 15/30] tipc: use config_mutex to >> protect tipc_net_stop routine" to one patch #6. >> - divide patch #16 into two patches: patch #7 and patch #8. >> - add a new patch #9. >> - now the mapping relationship between v1 and v2 will be: >> 1. old patch #1 is to new patch #4; >> 2. old patch #2, #3 and #4 are included into the small >> non-controversial series; >> 3. old patch #4 is dropped in the series. >> 4. old patch #9 is mapped to patch #1. >> 5. old patch #10 is divided into patch #2 and #3. >> 6. old patch #11 is mapped to patch #4. >> 7. old patch #12 is mapped to patch #5. >> 8. old patch #13, #14 and #15 is patch #6. >> 9. old patch #16 is divided into patch #7 and #8. >> 10. old patch #17 is mapped to patch #10. >> 11. the rest of patches in v1 will be sent out recently. >> >> Ying Xue (10): >> tipc: involve tipc_unregister_media routine >> tipc: make bearer variable in media structure synchronous >> tipc: get rid of af_packet_priv usage when register TIPC protocol >> handler >> tipc: move registration of TIPC packet handler to media start >> tipc: remove flush_scheduled_work() from media stop routines >> tipc: expand config_muex usage >> tipc: convert tipc_bearers array to pointer array >> tipc: make media structure contain tipc_bearer object >> tipc: add common unwind section to reduce duplicated code >> tipc: use bearer lock to protect links list when link is created >> >> net/tipc/bcast.c | 6 +- >> net/tipc/bearer.c | 81 ++++++++++++++------ >> net/tipc/bearer.h | 7 +- >> net/tipc/config.c | 4 +- >> net/tipc/config.h | 4 +- >> net/tipc/core.c | 37 ++------- >> net/tipc/core.h | 1 - >> net/tipc/discover.c | 17 ++--- >> net/tipc/eth_media.c | 203 +++++++++++++++++++++++++------------------------- >> net/tipc/ib_media.c | 189 ++++++++++++++++++++++++---------------------- >> net/tipc/link.c | 2 - >> net/tipc/net.c | 3 + >> 12 files changed, 286 insertions(+), 268 deletions(-) >> > > |