aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorCong Wang <amwang@redhat.com>2013-01-14 18:34:06 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-16 15:26:03 -0500
commitf92d318023ff70a273690a91568597168ac32f05 (patch)
tree91d64d43a5111cfbc689956e27017c144c9205ba /net/core
parent7db11f7596e0e54f982b1897f8233056e5c67a7d (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/core')
-rw-r--r--net/core/netpoll.c24
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
1163put: 1157put:
1164 dev_put(ndev); 1158 dev_put(ndev);
1159unlock:
1160 rtnl_unlock();
1165 return err; 1161 return err;
1166} 1162}
1167EXPORT_SYMBOL(netpoll_setup); 1163EXPORT_SYMBOL(netpoll_setup);