diff options
author | Cong Wang <amwang@redhat.com> | 2013-01-14 18:34:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-01-16 15:26:03 -0500 |
commit | f92d318023ff70a273690a91568597168ac32f05 (patch) | |
tree | 91d64d43a5111cfbc689956e27017c144c9205ba /net | |
parent | 7db11f7596e0e54f982b1897f8233056e5c67a7d (diff) |
netpoll: fix a rtnl lock assertion failure
v4: hold rtnl lock for the whole netpoll_setup()
v3: remove the comment
v2: use RCU read lock
This patch fixes the following warning:
[ 72.013864] RTNL: assertion failed at net/core/dev.c (4955)
[ 72.017758] Pid: 668, comm: netpoll-prep-v6 Not tainted 3.8.0-rc1+ #474
[ 72.019582] Call Trace:
[ 72.020295] [<ffffffff8176653d>] netdev_master_upper_dev_get+0x35/0x58
[ 72.022545] [<ffffffff81784edd>] netpoll_setup+0x61/0x340
[ 72.024846] [<ffffffff815d837e>] store_enabled+0x82/0xc3
[ 72.027466] [<ffffffff815d7e51>] netconsole_target_attr_store+0x35/0x37
[ 72.029348] [<ffffffff811c3479>] configfs_write_file+0xe2/0x10c
[ 72.030959] [<ffffffff8115d239>] vfs_write+0xaf/0xf6
[ 72.032359] [<ffffffff81978a05>] ? sysret_check+0x22/0x5d
[ 72.033824] [<ffffffff8115d453>] sys_write+0x5c/0x84
[ 72.035328] [<ffffffff819789d9>] system_call_fastpath+0x16/0x1b
In case of other races, hold rtnl lock for the entire netpoll_setup() function.
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/netpoll.c | 24 |
1 files changed, 10 insertions, 14 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 9f0506726101..a5ad1c1c4b18 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -1048,11 +1048,13 @@ int netpoll_setup(struct netpoll *np) | |||
1048 | struct in_device *in_dev; | 1048 | struct in_device *in_dev; |
1049 | int err; | 1049 | int err; |
1050 | 1050 | ||
1051 | rtnl_lock(); | ||
1051 | if (np->dev_name) | 1052 | if (np->dev_name) |
1052 | ndev = dev_get_by_name(&init_net, np->dev_name); | 1053 | ndev = __dev_get_by_name(&init_net, np->dev_name); |
1053 | if (!ndev) { | 1054 | if (!ndev) { |
1054 | np_err(np, "%s doesn't exist, aborting\n", np->dev_name); | 1055 | np_err(np, "%s doesn't exist, aborting\n", np->dev_name); |
1055 | return -ENODEV; | 1056 | err = -ENODEV; |
1057 | goto unlock; | ||
1056 | } | 1058 | } |
1057 | 1059 | ||
1058 | if (netdev_master_upper_dev_get(ndev)) { | 1060 | if (netdev_master_upper_dev_get(ndev)) { |
@@ -1066,15 +1068,14 @@ int netpoll_setup(struct netpoll *np) | |||
1066 | 1068 | ||
1067 | np_info(np, "device %s not up yet, forcing it\n", np->dev_name); | 1069 | np_info(np, "device %s not up yet, forcing it\n", np->dev_name); |
1068 | 1070 | ||
1069 | rtnl_lock(); | ||
1070 | err = dev_open(ndev); | 1071 | err = dev_open(ndev); |
1071 | rtnl_unlock(); | ||
1072 | 1072 | ||
1073 | if (err) { | 1073 | if (err) { |
1074 | np_err(np, "failed to open %s\n", ndev->name); | 1074 | np_err(np, "failed to open %s\n", ndev->name); |
1075 | goto put; | 1075 | goto put; |
1076 | } | 1076 | } |
1077 | 1077 | ||
1078 | rtnl_unlock(); | ||
1078 | atleast = jiffies + HZ/10; | 1079 | atleast = jiffies + HZ/10; |
1079 | atmost = jiffies + carrier_timeout * HZ; | 1080 | atmost = jiffies + carrier_timeout * HZ; |
1080 | while (!netif_carrier_ok(ndev)) { | 1081 | while (!netif_carrier_ok(ndev)) { |
@@ -1094,16 +1095,14 @@ int netpoll_setup(struct netpoll *np) | |||
1094 | np_notice(np, "carrier detect appears untrustworthy, waiting 4 seconds\n"); | 1095 | np_notice(np, "carrier detect appears untrustworthy, waiting 4 seconds\n"); |
1095 | msleep(4000); | 1096 | msleep(4000); |
1096 | } | 1097 | } |
1098 | rtnl_lock(); | ||
1097 | } | 1099 | } |
1098 | 1100 | ||
1099 | if (!np->local_ip.ip) { | 1101 | if (!np->local_ip.ip) { |
1100 | if (!np->ipv6) { | 1102 | if (!np->ipv6) { |
1101 | rcu_read_lock(); | 1103 | in_dev = __in_dev_get_rtnl(ndev); |
1102 | in_dev = __in_dev_get_rcu(ndev); | ||
1103 | |||
1104 | 1104 | ||
1105 | if (!in_dev || !in_dev->ifa_list) { | 1105 | if (!in_dev || !in_dev->ifa_list) { |
1106 | rcu_read_unlock(); | ||
1107 | np_err(np, "no IP address for %s, aborting\n", | 1106 | np_err(np, "no IP address for %s, aborting\n", |
1108 | np->dev_name); | 1107 | np->dev_name); |
1109 | err = -EDESTADDRREQ; | 1108 | err = -EDESTADDRREQ; |
@@ -1111,14 +1110,12 @@ int netpoll_setup(struct netpoll *np) | |||
1111 | } | 1110 | } |
1112 | 1111 | ||
1113 | np->local_ip.ip = in_dev->ifa_list->ifa_local; | 1112 | np->local_ip.ip = in_dev->ifa_list->ifa_local; |
1114 | rcu_read_unlock(); | ||
1115 | np_info(np, "local IP %pI4\n", &np->local_ip.ip); | 1113 | np_info(np, "local IP %pI4\n", &np->local_ip.ip); |
1116 | } else { | 1114 | } else { |
1117 | #if IS_ENABLED(CONFIG_IPV6) | 1115 | #if IS_ENABLED(CONFIG_IPV6) |
1118 | struct inet6_dev *idev; | 1116 | struct inet6_dev *idev; |
1119 | 1117 | ||
1120 | err = -EDESTADDRREQ; | 1118 | err = -EDESTADDRREQ; |
1121 | rcu_read_lock(); | ||
1122 | idev = __in6_dev_get(ndev); | 1119 | idev = __in6_dev_get(ndev); |
1123 | if (idev) { | 1120 | if (idev) { |
1124 | struct inet6_ifaddr *ifp; | 1121 | struct inet6_ifaddr *ifp; |
@@ -1133,7 +1130,6 @@ int netpoll_setup(struct netpoll *np) | |||
1133 | } | 1130 | } |
1134 | read_unlock_bh(&idev->lock); | 1131 | read_unlock_bh(&idev->lock); |
1135 | } | 1132 | } |
1136 | rcu_read_unlock(); | ||
1137 | if (err) { | 1133 | if (err) { |
1138 | np_err(np, "no IPv6 address for %s, aborting\n", | 1134 | np_err(np, "no IPv6 address for %s, aborting\n", |
1139 | np->dev_name); | 1135 | np->dev_name); |
@@ -1151,17 +1147,17 @@ int netpoll_setup(struct netpoll *np) | |||
1151 | /* fill up the skb queue */ | 1147 | /* fill up the skb queue */ |
1152 | refill_skbs(); | 1148 | refill_skbs(); |
1153 | 1149 | ||
1154 | rtnl_lock(); | ||
1155 | err = __netpoll_setup(np, ndev, GFP_KERNEL); | 1150 | err = __netpoll_setup(np, ndev, GFP_KERNEL); |
1156 | rtnl_unlock(); | ||
1157 | |||
1158 | if (err) | 1151 | if (err) |
1159 | goto put; | 1152 | goto put; |
1160 | 1153 | ||
1154 | rtnl_unlock(); | ||
1161 | return 0; | 1155 | return 0; |
1162 | 1156 | ||
1163 | put: | 1157 | put: |
1164 | dev_put(ndev); | 1158 | dev_put(ndev); |
1159 | unlock: | ||
1160 | rtnl_unlock(); | ||
1165 | return err; | 1161 | return err; |
1166 | } | 1162 | } |
1167 | EXPORT_SYMBOL(netpoll_setup); | 1163 | EXPORT_SYMBOL(netpoll_setup); |