aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/devinet.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2007-12-16 16:31:14 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:58:10 -0500
commitc0ce9fb304871daa0dd2bf0efb1b241b9fa4a279 (patch)
tree3783b5871680d9cf5712c4aade60fc2e4c8e790f /net/ipv4/devinet.c
parent32e569b7277f13c4b27bb29c761189963e49ce7a (diff)
[IPV4]: Store the net pointer on devinet's ctl tables
Some handers and strategies of devinet sysctl tables need to know the net to propagate the ctl change to all the net devices. I use the (currently unused) extra2 pointer on the tables to get it. Holding the reference on the struct net is not possible, because otherwise we'll get a net->ctl_table->net circular dependency. But since the ctl tables are unregistered during the net destruction, this is safe to get it w/o additional protection. Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r--net/ipv4/devinet.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 82def2c1c650..8b2a44c4f82a 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1236,12 +1236,12 @@ errout:
1236 1236
1237#ifdef CONFIG_SYSCTL 1237#ifdef CONFIG_SYSCTL
1238 1238
1239static void devinet_copy_dflt_conf(int i) 1239static void devinet_copy_dflt_conf(struct net *net, int i)
1240{ 1240{
1241 struct net_device *dev; 1241 struct net_device *dev;
1242 1242
1243 read_lock(&dev_base_lock); 1243 read_lock(&dev_base_lock);
1244 for_each_netdev(&init_net, dev) { 1244 for_each_netdev(net, dev) {
1245 struct in_device *in_dev; 1245 struct in_device *in_dev;
1246 rcu_read_lock(); 1246 rcu_read_lock();
1247 in_dev = __in_dev_get_rcu(dev); 1247 in_dev = __in_dev_get_rcu(dev);
@@ -1252,7 +1252,7 @@ static void devinet_copy_dflt_conf(int i)
1252 read_unlock(&dev_base_lock); 1252 read_unlock(&dev_base_lock);
1253} 1253}
1254 1254
1255static void inet_forward_change(void) 1255static void inet_forward_change(struct net *net)
1256{ 1256{
1257 struct net_device *dev; 1257 struct net_device *dev;
1258 int on = IPV4_DEVCONF_ALL(FORWARDING); 1258 int on = IPV4_DEVCONF_ALL(FORWARDING);
@@ -1261,7 +1261,7 @@ static void inet_forward_change(void)
1261 IPV4_DEVCONF_DFLT(FORWARDING) = on; 1261 IPV4_DEVCONF_DFLT(FORWARDING) = on;
1262 1262
1263 read_lock(&dev_base_lock); 1263 read_lock(&dev_base_lock);
1264 for_each_netdev(&init_net, dev) { 1264 for_each_netdev(net, dev) {
1265 struct in_device *in_dev; 1265 struct in_device *in_dev;
1266 rcu_read_lock(); 1266 rcu_read_lock();
1267 in_dev = __in_dev_get_rcu(dev); 1267 in_dev = __in_dev_get_rcu(dev);
@@ -1282,12 +1282,13 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
1282 1282
1283 if (write) { 1283 if (write) {
1284 struct ipv4_devconf *cnf = ctl->extra1; 1284 struct ipv4_devconf *cnf = ctl->extra1;
1285 struct net *net = ctl->extra2;
1285 int i = (int *)ctl->data - cnf->data; 1286 int i = (int *)ctl->data - cnf->data;
1286 1287
1287 set_bit(i, cnf->state); 1288 set_bit(i, cnf->state);
1288 1289
1289 if (cnf == &ipv4_devconf_dflt) 1290 if (cnf == &ipv4_devconf_dflt)
1290 devinet_copy_dflt_conf(i); 1291 devinet_copy_dflt_conf(net, i);
1291 } 1292 }
1292 1293
1293 return ret; 1294 return ret;
@@ -1298,6 +1299,7 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1298 void __user *newval, size_t newlen) 1299 void __user *newval, size_t newlen)
1299{ 1300{
1300 struct ipv4_devconf *cnf; 1301 struct ipv4_devconf *cnf;
1302 struct net *net;
1301 int *valp = table->data; 1303 int *valp = table->data;
1302 int new; 1304 int new;
1303 int i; 1305 int i;
@@ -1333,12 +1335,13 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
1333 *valp = new; 1335 *valp = new;
1334 1336
1335 cnf = table->extra1; 1337 cnf = table->extra1;
1338 net = table->extra2;
1336 i = (int *)table->data - cnf->data; 1339 i = (int *)table->data - cnf->data;
1337 1340
1338 set_bit(i, cnf->state); 1341 set_bit(i, cnf->state);
1339 1342
1340 if (cnf == &ipv4_devconf_dflt) 1343 if (cnf == &ipv4_devconf_dflt)
1341 devinet_copy_dflt_conf(i); 1344 devinet_copy_dflt_conf(net, i);
1342 1345
1343 return 1; 1346 return 1;
1344} 1347}
@@ -1352,8 +1355,10 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
1352 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); 1355 int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
1353 1356
1354 if (write && *valp != val) { 1357 if (write && *valp != val) {
1358 struct net *net = ctl->extra2;
1359
1355 if (valp == &IPV4_DEVCONF_ALL(FORWARDING)) 1360 if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
1356 inet_forward_change(); 1361 inet_forward_change(net);
1357 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING)) 1362 else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
1358 rt_cache_flush(0); 1363 rt_cache_flush(0);
1359 } 1364 }
@@ -1477,6 +1482,7 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
1477 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { 1482 for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
1478 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; 1483 t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
1479 t->devinet_vars[i].extra1 = p; 1484 t->devinet_vars[i].extra1 = p;
1485 t->devinet_vars[i].extra2 = net;
1480 } 1486 }
1481 1487
1482 /* 1488 /*
@@ -1524,8 +1530,8 @@ static void devinet_sysctl_register(struct in_device *idev)
1524{ 1530{
1525 neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4, 1531 neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4,
1526 NET_IPV4_NEIGH, "ipv4", NULL, NULL); 1532 NET_IPV4_NEIGH, "ipv4", NULL, NULL);
1527 __devinet_sysctl_register(idev->dev->name, idev->dev->ifindex, 1533 __devinet_sysctl_register(idev->dev->nd_net, idev->dev->name,
1528 &idev->cnf); 1534 idev->dev->ifindex, &idev->cnf);
1529} 1535}
1530 1536
1531static void devinet_sysctl_unregister(struct in_device *idev) 1537static void devinet_sysctl_unregister(struct in_device *idev)
@@ -1546,6 +1552,7 @@ static struct ctl_table ctl_forward_entry[] = {
1546 .proc_handler = devinet_sysctl_forward, 1552 .proc_handler = devinet_sysctl_forward,
1547 .strategy = devinet_conf_sysctl, 1553 .strategy = devinet_conf_sysctl,
1548 .extra1 = &ipv4_devconf, 1554 .extra1 = &ipv4_devconf,
1555 .extra2 = &init_net,
1549 }, 1556 },
1550 { }, 1557 { },
1551}; 1558};
@@ -1565,9 +1572,9 @@ void __init devinet_init(void)
1565 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); 1572 rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
1566 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); 1573 rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
1567#ifdef CONFIG_SYSCTL 1574#ifdef CONFIG_SYSCTL
1568 __devinet_sysctl_register("all", NET_PROTO_CONF_ALL, 1575 __devinet_sysctl_register(&init_net, "all", NET_PROTO_CONF_ALL,
1569 &ipv4_devconf); 1576 &ipv4_devconf);
1570 __devinet_sysctl_register("default", NET_PROTO_CONF_DEFAULT, 1577 __devinet_sysctl_register(&init_net, "default", NET_PROTO_CONF_DEFAULT,
1571 &ipv4_devconf_dflt); 1578 &ipv4_devconf_dflt);
1572 register_sysctl_paths(net_ipv4_path, ctl_forward_entry); 1579 register_sysctl_paths(net_ipv4_path, ctl_forward_entry);
1573#endif 1580#endif