aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-02-19 08:22:59 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-19 18:40:50 -0500
commit88af182e389097997c5e2a0b42285b3522796759 (patch)
treeb2df5a8589aaee30073665da46523a3908e8870a /net
parentb0483e78e5c4c9871fc5541875b3bc006846d46b (diff)
net: Fix sysctl restarts...
Yuck. It turns out that when we restart sysctls we were restarting with the values already changed. Which unfortunately meant that the second time through we thought there was no change and skipped all kinds of work, despite the fact that there was indeed a change. I have fixed this the simplest way possible by restoring the changed values when we restart the sysctl write. One of my coworkers spotted this bug when after disabling forwarding on an interface pings were still forwarded. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/devinet.c7
-rw-r--r--net/ipv6/addrconf.c16
2 files changed, 20 insertions, 3 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 040c4f05b653..26dec2be9615 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1317,14 +1317,19 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
1317{ 1317{
1318 int *valp = ctl->data; 1318 int *valp = ctl->data;
1319 int val = *valp; 1319 int val = *valp;
1320 loff_t pos = *ppos;
1320 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 1321 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
1321 1322
1322 if (write && *valp != val) { 1323 if (write && *valp != val) {
1323 struct net *net = ctl->extra2; 1324 struct net *net = ctl->extra2;
1324 1325
1325 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) { 1326 if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
1326 if (!rtnl_trylock()) 1327 if (!rtnl_trylock()) {
1328 /* Restore the original values before restarting */
1329 *valp = val;
1330 *ppos = pos;
1327 return restart_syscall(); 1331 return restart_syscall();
1332 }
1328 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { 1333 if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
1329 inet_forward_change(net); 1334 inet_forward_change(net);
1330 } else if (*valp) { 1335 } else if (*valp) {
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index de7a194a64ab..143791da062c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -502,8 +502,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
502 if (p == &net->ipv6.devconf_dflt->forwarding) 502 if (p == &net->ipv6.devconf_dflt->forwarding)
503 return 0; 503 return 0;
504 504
505 if (!rtnl_trylock()) 505 if (!rtnl_trylock()) {
506 /* Restore the original values before restarting */
507 *p = old;
506 return restart_syscall(); 508 return restart_syscall();
509 }
507 510
508 if (p == &net->ipv6.devconf_all->forwarding) { 511 if (p == &net->ipv6.devconf_all->forwarding) {
509 __s32 newf = net->ipv6.devconf_all->forwarding; 512 __s32 newf = net->ipv6.devconf_all->forwarding;
@@ -4028,12 +4031,15 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write,
4028{ 4031{
4029 int *valp = ctl->data; 4032 int *valp = ctl->data;
4030 int val = *valp; 4033 int val = *valp;
4034 loff_t pos = *ppos;
4031 int ret; 4035 int ret;
4032 4036
4033 ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 4037 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
4034 4038
4035 if (write) 4039 if (write)
4036 ret = addrconf_fixup_forwarding(ctl, valp, val); 4040 ret = addrconf_fixup_forwarding(ctl, valp, val);
4041 if (ret)
4042 *ppos = pos;
4037 return ret; 4043 return ret;
4038} 4044}
4039 4045
@@ -4075,8 +4081,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
4075 if (p == &net->ipv6.devconf_dflt->disable_ipv6) 4081 if (p == &net->ipv6.devconf_dflt->disable_ipv6)
4076 return 0; 4082 return 0;
4077 4083
4078 if (!rtnl_trylock()) 4084 if (!rtnl_trylock()) {
4085 /* Restore the original values before restarting */
4086 *p = old;
4079 return restart_syscall(); 4087 return restart_syscall();
4088 }
4080 4089
4081 if (p == &net->ipv6.devconf_all->disable_ipv6) { 4090 if (p == &net->ipv6.devconf_all->disable_ipv6) {
4082 __s32 newf = net->ipv6.devconf_all->disable_ipv6; 4091 __s32 newf = net->ipv6.devconf_all->disable_ipv6;
@@ -4095,12 +4104,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write,
4095{ 4104{
4096 int *valp = ctl->data; 4105 int *valp = ctl->data;
4097 int val = *valp; 4106 int val = *valp;
4107 loff_t pos = *ppos;
4098 int ret; 4108 int ret;
4099 4109
4100 ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 4110 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
4101 4111
4102 if (write) 4112 if (write)
4103 ret = addrconf_disable_ipv6(ctl, valp, val); 4113 ret = addrconf_disable_ipv6(ctl, valp, val);
4114 if (ret)
4115 *ppos = pos;
4104 return ret; 4116 return ret;
4105} 4117}
4106 4118