Commit c0ce9fb3 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by David S. Miller

[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: default avatarPavel Emelyanov <xemul@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 32e569b7
...@@ -1236,12 +1236,12 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, ...@@ -1236,12 +1236,12 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static void devinet_copy_dflt_conf(int i) static void devinet_copy_dflt_conf(struct net *net, int i)
{ {
struct net_device *dev; struct net_device *dev;
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for_each_netdev(&init_net, dev) { for_each_netdev(net, dev) {
struct in_device *in_dev; struct in_device *in_dev;
rcu_read_lock(); rcu_read_lock();
in_dev = __in_dev_get_rcu(dev); in_dev = __in_dev_get_rcu(dev);
...@@ -1252,7 +1252,7 @@ static void devinet_copy_dflt_conf(int i) ...@@ -1252,7 +1252,7 @@ static void devinet_copy_dflt_conf(int i)
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
} }
static void inet_forward_change(void) static void inet_forward_change(struct net *net)
{ {
struct net_device *dev; struct net_device *dev;
int on = IPV4_DEVCONF_ALL(FORWARDING); int on = IPV4_DEVCONF_ALL(FORWARDING);
...@@ -1261,7 +1261,7 @@ static void inet_forward_change(void) ...@@ -1261,7 +1261,7 @@ static void inet_forward_change(void)
IPV4_DEVCONF_DFLT(FORWARDING) = on; IPV4_DEVCONF_DFLT(FORWARDING) = on;
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for_each_netdev(&init_net, dev) { for_each_netdev(net, dev) {
struct in_device *in_dev; struct in_device *in_dev;
rcu_read_lock(); rcu_read_lock();
in_dev = __in_dev_get_rcu(dev); in_dev = __in_dev_get_rcu(dev);
...@@ -1282,12 +1282,13 @@ static int devinet_conf_proc(ctl_table *ctl, int write, ...@@ -1282,12 +1282,13 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
if (write) { if (write) {
struct ipv4_devconf *cnf = ctl->extra1; struct ipv4_devconf *cnf = ctl->extra1;
struct net *net = ctl->extra2;
int i = (int *)ctl->data - cnf->data; int i = (int *)ctl->data - cnf->data;
set_bit(i, cnf->state); set_bit(i, cnf->state);
if (cnf == &ipv4_devconf_dflt) if (cnf == &ipv4_devconf_dflt)
devinet_copy_dflt_conf(i); devinet_copy_dflt_conf(net, i);
} }
return ret; return ret;
...@@ -1298,6 +1299,7 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen, ...@@ -1298,6 +1299,7 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
void __user *newval, size_t newlen) void __user *newval, size_t newlen)
{ {
struct ipv4_devconf *cnf; struct ipv4_devconf *cnf;
struct net *net;
int *valp = table->data; int *valp = table->data;
int new; int new;
int i; int i;
...@@ -1333,12 +1335,13 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen, ...@@ -1333,12 +1335,13 @@ static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
*valp = new; *valp = new;
cnf = table->extra1; cnf = table->extra1;
net = table->extra2;
i = (int *)table->data - cnf->data; i = (int *)table->data - cnf->data;
set_bit(i, cnf->state); set_bit(i, cnf->state);
if (cnf == &ipv4_devconf_dflt) if (cnf == &ipv4_devconf_dflt)
devinet_copy_dflt_conf(i); devinet_copy_dflt_conf(net, i);
return 1; return 1;
} }
...@@ -1352,8 +1355,10 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, ...@@ -1352,8 +1355,10 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
if (write && *valp != val) { if (write && *valp != val) {
struct net *net = ctl->extra2;
if (valp == &IPV4_DEVCONF_ALL(FORWARDING)) if (valp == &IPV4_DEVCONF_ALL(FORWARDING))
inet_forward_change(); inet_forward_change(net);
else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING)) else if (valp != &IPV4_DEVCONF_DFLT(FORWARDING))
rt_cache_flush(0); rt_cache_flush(0);
} }
...@@ -1477,6 +1482,7 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name, ...@@ -1477,6 +1482,7 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name,
for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
t->devinet_vars[i].extra1 = p; t->devinet_vars[i].extra1 = p;
t->devinet_vars[i].extra2 = net;
} }
/* /*
...@@ -1524,8 +1530,8 @@ static void devinet_sysctl_register(struct in_device *idev) ...@@ -1524,8 +1530,8 @@ static void devinet_sysctl_register(struct in_device *idev)
{ {
neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4, neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4", NULL, NULL); NET_IPV4_NEIGH, "ipv4", NULL, NULL);
__devinet_sysctl_register(idev->dev->name, idev->dev->ifindex, __devinet_sysctl_register(idev->dev->nd_net, idev->dev->name,
&idev->cnf); idev->dev->ifindex, &idev->cnf);
} }
static void devinet_sysctl_unregister(struct in_device *idev) static void devinet_sysctl_unregister(struct in_device *idev)
...@@ -1546,6 +1552,7 @@ static struct ctl_table ctl_forward_entry[] = { ...@@ -1546,6 +1552,7 @@ static struct ctl_table ctl_forward_entry[] = {
.proc_handler = devinet_sysctl_forward, .proc_handler = devinet_sysctl_forward,
.strategy = devinet_conf_sysctl, .strategy = devinet_conf_sysctl,
.extra1 = &ipv4_devconf, .extra1 = &ipv4_devconf,
.extra2 = &init_net,
}, },
{ }, { },
}; };
...@@ -1565,9 +1572,9 @@ void __init devinet_init(void) ...@@ -1565,9 +1572,9 @@ void __init devinet_init(void)
rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL); rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL);
rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr); rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
__devinet_sysctl_register("all", NET_PROTO_CONF_ALL, __devinet_sysctl_register(&init_net, "all", NET_PROTO_CONF_ALL,
&ipv4_devconf); &ipv4_devconf);
__devinet_sysctl_register("default", NET_PROTO_CONF_DEFAULT, __devinet_sysctl_register(&init_net, "default", NET_PROTO_CONF_DEFAULT,
&ipv4_devconf_dflt); &ipv4_devconf_dflt);
register_sysctl_paths(net_ipv4_path, ctl_forward_entry); register_sysctl_paths(net_ipv4_path, ctl_forward_entry);
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment