diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-03-05 15:46:18 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-03-05 15:46:18 -0500 |
commit | 3fa04ecd72780da31ba8b329e148179bc24a9c7d (patch) | |
tree | f5d462fd4aee086952d18f159f737c450ab46b3b /net/ipv6/addrconf.c | |
parent | 180b62a3d837613fcac3ce89576526423926c3c3 (diff) | |
parent | 1cda707d52e51a6cafac0aef12d2bd7052d572e6 (diff) |
Merge branch 'writeback-for-2.6.34' into nfs-for-2.6.34
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 110 |
1 files changed, 67 insertions, 43 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index de7a194a64ab..88fd8c5877ee 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -278,31 +278,31 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
278 | 278 | ||
279 | static int snmp6_alloc_dev(struct inet6_dev *idev) | 279 | static int snmp6_alloc_dev(struct inet6_dev *idev) |
280 | { | 280 | { |
281 | if (snmp_mib_init((void **)idev->stats.ipv6, | 281 | if (snmp_mib_init((void __percpu **)idev->stats.ipv6, |
282 | sizeof(struct ipstats_mib)) < 0) | 282 | sizeof(struct ipstats_mib)) < 0) |
283 | goto err_ip; | 283 | goto err_ip; |
284 | if (snmp_mib_init((void **)idev->stats.icmpv6, | 284 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, |
285 | sizeof(struct icmpv6_mib)) < 0) | 285 | sizeof(struct icmpv6_mib)) < 0) |
286 | goto err_icmp; | 286 | goto err_icmp; |
287 | if (snmp_mib_init((void **)idev->stats.icmpv6msg, | 287 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, |
288 | sizeof(struct icmpv6msg_mib)) < 0) | 288 | sizeof(struct icmpv6msg_mib)) < 0) |
289 | goto err_icmpmsg; | 289 | goto err_icmpmsg; |
290 | 290 | ||
291 | return 0; | 291 | return 0; |
292 | 292 | ||
293 | err_icmpmsg: | 293 | err_icmpmsg: |
294 | snmp_mib_free((void **)idev->stats.icmpv6); | 294 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
295 | err_icmp: | 295 | err_icmp: |
296 | snmp_mib_free((void **)idev->stats.ipv6); | 296 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
297 | err_ip: | 297 | err_ip: |
298 | return -ENOMEM; | 298 | return -ENOMEM; |
299 | } | 299 | } |
300 | 300 | ||
301 | static void snmp6_free_dev(struct inet6_dev *idev) | 301 | static void snmp6_free_dev(struct inet6_dev *idev) |
302 | { | 302 | { |
303 | snmp_mib_free((void **)idev->stats.icmpv6msg); | 303 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); |
304 | snmp_mib_free((void **)idev->stats.icmpv6); | 304 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
305 | snmp_mib_free((void **)idev->stats.ipv6); | 305 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
306 | } | 306 | } |
307 | 307 | ||
308 | /* Nobody refers to this device, we may destroy it. */ | 308 | /* Nobody refers to this device, we may destroy it. */ |
@@ -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; |
@@ -989,8 +992,7 @@ struct ipv6_saddr_dst { | |||
989 | 992 | ||
990 | static inline int ipv6_saddr_preferred(int type) | 993 | static inline int ipv6_saddr_preferred(int type) |
991 | { | 994 | { |
992 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| | 995 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK)) |
993 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) | ||
994 | return 1; | 996 | return 1; |
995 | return 0; | 997 | return 0; |
996 | } | 998 | } |
@@ -2646,7 +2648,8 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2646 | 2648 | ||
2647 | write_lock_bh(&addrconf_hash_lock); | 2649 | write_lock_bh(&addrconf_hash_lock); |
2648 | while ((ifa = *bifa) != NULL) { | 2650 | while ((ifa = *bifa) != NULL) { |
2649 | if (ifa->idev == idev) { | 2651 | if (ifa->idev == idev && |
2652 | (how || !(ifa->flags&IFA_F_PERMANENT))) { | ||
2650 | *bifa = ifa->lst_next; | 2653 | *bifa = ifa->lst_next; |
2651 | ifa->lst_next = NULL; | 2654 | ifa->lst_next = NULL; |
2652 | addrconf_del_timer(ifa); | 2655 | addrconf_del_timer(ifa); |
@@ -2686,18 +2689,30 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2686 | write_lock_bh(&idev->lock); | 2689 | write_lock_bh(&idev->lock); |
2687 | } | 2690 | } |
2688 | #endif | 2691 | #endif |
2689 | while ((ifa = idev->addr_list) != NULL) { | 2692 | bifa = &idev->addr_list; |
2690 | idev->addr_list = ifa->if_next; | 2693 | while ((ifa = *bifa) != NULL) { |
2691 | ifa->if_next = NULL; | 2694 | if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) { |
2692 | ifa->dead = 1; | 2695 | /* Retain permanent address on admin down */ |
2693 | addrconf_del_timer(ifa); | 2696 | bifa = &ifa->if_next; |
2694 | write_unlock_bh(&idev->lock); | 2697 | |
2698 | /* Restart DAD if needed when link comes back up */ | ||
2699 | if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
2700 | idev->cnf.accept_dad <= 0 || | ||
2701 | (ifa->flags & IFA_F_NODAD))) | ||
2702 | ifa->flags |= IFA_F_TENTATIVE; | ||
2703 | } else { | ||
2704 | *bifa = ifa->if_next; | ||
2705 | ifa->if_next = NULL; | ||
2695 | 2706 | ||
2696 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2707 | ifa->dead = 1; |
2697 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | 2708 | write_unlock_bh(&idev->lock); |
2698 | in6_ifa_put(ifa); | ||
2699 | 2709 | ||
2700 | write_lock_bh(&idev->lock); | 2710 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
2711 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | ||
2712 | in6_ifa_put(ifa); | ||
2713 | |||
2714 | write_lock_bh(&idev->lock); | ||
2715 | } | ||
2701 | } | 2716 | } |
2702 | write_unlock_bh(&idev->lock); | 2717 | write_unlock_bh(&idev->lock); |
2703 | 2718 | ||
@@ -2789,14 +2804,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2789 | read_lock_bh(&idev->lock); | 2804 | read_lock_bh(&idev->lock); |
2790 | if (ifp->dead) | 2805 | if (ifp->dead) |
2791 | goto out; | 2806 | goto out; |
2792 | spin_lock_bh(&ifp->lock); | ||
2793 | 2807 | ||
2808 | spin_lock(&ifp->lock); | ||
2794 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2809 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2795 | idev->cnf.accept_dad < 1 || | 2810 | idev->cnf.accept_dad < 1 || |
2796 | !(ifp->flags&IFA_F_TENTATIVE) || | 2811 | !(ifp->flags&IFA_F_TENTATIVE) || |
2797 | ifp->flags & IFA_F_NODAD) { | 2812 | ifp->flags & IFA_F_NODAD) { |
2798 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2813 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2799 | spin_unlock_bh(&ifp->lock); | 2814 | spin_unlock(&ifp->lock); |
2800 | read_unlock_bh(&idev->lock); | 2815 | read_unlock_bh(&idev->lock); |
2801 | 2816 | ||
2802 | addrconf_dad_completed(ifp); | 2817 | addrconf_dad_completed(ifp); |
@@ -2804,7 +2819,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2804 | } | 2819 | } |
2805 | 2820 | ||
2806 | if (!(idev->if_flags & IF_READY)) { | 2821 | if (!(idev->if_flags & IF_READY)) { |
2807 | spin_unlock_bh(&ifp->lock); | 2822 | spin_unlock(&ifp->lock); |
2808 | read_unlock_bh(&idev->lock); | 2823 | read_unlock_bh(&idev->lock); |
2809 | /* | 2824 | /* |
2810 | * If the device is not ready: | 2825 | * If the device is not ready: |
@@ -2824,7 +2839,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2824 | ip6_ins_rt(ifp->rt); | 2839 | ip6_ins_rt(ifp->rt); |
2825 | 2840 | ||
2826 | addrconf_dad_kick(ifp); | 2841 | addrconf_dad_kick(ifp); |
2827 | spin_unlock_bh(&ifp->lock); | 2842 | spin_unlock(&ifp->lock); |
2828 | out: | 2843 | out: |
2829 | read_unlock_bh(&idev->lock); | 2844 | read_unlock_bh(&idev->lock); |
2830 | } | 2845 | } |
@@ -2840,14 +2855,15 @@ static void addrconf_dad_timer(unsigned long data) | |||
2840 | read_unlock_bh(&idev->lock); | 2855 | read_unlock_bh(&idev->lock); |
2841 | goto out; | 2856 | goto out; |
2842 | } | 2857 | } |
2843 | spin_lock_bh(&ifp->lock); | 2858 | |
2859 | spin_lock(&ifp->lock); | ||
2844 | if (ifp->probes == 0) { | 2860 | if (ifp->probes == 0) { |
2845 | /* | 2861 | /* |
2846 | * DAD was successful | 2862 | * DAD was successful |
2847 | */ | 2863 | */ |
2848 | 2864 | ||
2849 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2865 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2850 | spin_unlock_bh(&ifp->lock); | 2866 | spin_unlock(&ifp->lock); |
2851 | read_unlock_bh(&idev->lock); | 2867 | read_unlock_bh(&idev->lock); |
2852 | 2868 | ||
2853 | addrconf_dad_completed(ifp); | 2869 | addrconf_dad_completed(ifp); |
@@ -2857,7 +2873,7 @@ static void addrconf_dad_timer(unsigned long data) | |||
2857 | 2873 | ||
2858 | ifp->probes--; | 2874 | ifp->probes--; |
2859 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); | 2875 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); |
2860 | spin_unlock_bh(&ifp->lock); | 2876 | spin_unlock(&ifp->lock); |
2861 | read_unlock_bh(&idev->lock); | 2877 | read_unlock_bh(&idev->lock); |
2862 | 2878 | ||
2863 | /* send a neighbour solicitation for our addr */ | 2879 | /* send a neighbour solicitation for our addr */ |
@@ -2905,12 +2921,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) { | |||
2905 | 2921 | ||
2906 | read_lock_bh(&idev->lock); | 2922 | read_lock_bh(&idev->lock); |
2907 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | 2923 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { |
2908 | spin_lock_bh(&ifp->lock); | 2924 | spin_lock(&ifp->lock); |
2909 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | 2925 | if (!(ifp->flags & IFA_F_TENTATIVE)) { |
2910 | spin_unlock_bh(&ifp->lock); | 2926 | spin_unlock(&ifp->lock); |
2911 | continue; | 2927 | continue; |
2912 | } | 2928 | } |
2913 | spin_unlock_bh(&ifp->lock); | 2929 | spin_unlock(&ifp->lock); |
2914 | addrconf_dad_kick(ifp); | 2930 | addrconf_dad_kick(ifp); |
2915 | } | 2931 | } |
2916 | read_unlock_bh(&idev->lock); | 2932 | read_unlock_bh(&idev->lock); |
@@ -3027,14 +3043,14 @@ static const struct file_operations if6_fops = { | |||
3027 | .release = seq_release_net, | 3043 | .release = seq_release_net, |
3028 | }; | 3044 | }; |
3029 | 3045 | ||
3030 | static int if6_proc_net_init(struct net *net) | 3046 | static int __net_init if6_proc_net_init(struct net *net) |
3031 | { | 3047 | { |
3032 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) | 3048 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) |
3033 | return -ENOMEM; | 3049 | return -ENOMEM; |
3034 | return 0; | 3050 | return 0; |
3035 | } | 3051 | } |
3036 | 3052 | ||
3037 | static void if6_proc_net_exit(struct net *net) | 3053 | static void __net_exit if6_proc_net_exit(struct net *net) |
3038 | { | 3054 | { |
3039 | proc_net_remove(net, "if_inet6"); | 3055 | proc_net_remove(net, "if_inet6"); |
3040 | } | 3056 | } |
@@ -3752,8 +3768,8 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3752 | ); | 3768 | ); |
3753 | } | 3769 | } |
3754 | 3770 | ||
3755 | static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, | 3771 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, |
3756 | int bytes) | 3772 | int items, int bytes) |
3757 | { | 3773 | { |
3758 | int i; | 3774 | int i; |
3759 | int pad = bytes - sizeof(u64) * items; | 3775 | int pad = bytes - sizeof(u64) * items; |
@@ -3772,10 +3788,10 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3772 | { | 3788 | { |
3773 | switch(attrtype) { | 3789 | switch(attrtype) { |
3774 | case IFLA_INET6_STATS: | 3790 | case IFLA_INET6_STATS: |
3775 | __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); | 3791 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); |
3776 | break; | 3792 | break; |
3777 | case IFLA_INET6_ICMP6STATS: | 3793 | case IFLA_INET6_ICMP6STATS: |
3778 | __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3794 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); |
3779 | break; | 3795 | break; |
3780 | } | 3796 | } |
3781 | } | 3797 | } |
@@ -4028,12 +4044,15 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, | |||
4028 | { | 4044 | { |
4029 | int *valp = ctl->data; | 4045 | int *valp = ctl->data; |
4030 | int val = *valp; | 4046 | int val = *valp; |
4047 | loff_t pos = *ppos; | ||
4031 | int ret; | 4048 | int ret; |
4032 | 4049 | ||
4033 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4050 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
4034 | 4051 | ||
4035 | if (write) | 4052 | if (write) |
4036 | ret = addrconf_fixup_forwarding(ctl, valp, val); | 4053 | ret = addrconf_fixup_forwarding(ctl, valp, val); |
4054 | if (ret) | ||
4055 | *ppos = pos; | ||
4037 | return ret; | 4056 | return ret; |
4038 | } | 4057 | } |
4039 | 4058 | ||
@@ -4075,8 +4094,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) | |||
4075 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) | 4094 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) |
4076 | return 0; | 4095 | return 0; |
4077 | 4096 | ||
4078 | if (!rtnl_trylock()) | 4097 | if (!rtnl_trylock()) { |
4098 | /* Restore the original values before restarting */ | ||
4099 | *p = old; | ||
4079 | return restart_syscall(); | 4100 | return restart_syscall(); |
4101 | } | ||
4080 | 4102 | ||
4081 | if (p == &net->ipv6.devconf_all->disable_ipv6) { | 4103 | if (p == &net->ipv6.devconf_all->disable_ipv6) { |
4082 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; | 4104 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; |
@@ -4095,12 +4117,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write, | |||
4095 | { | 4117 | { |
4096 | int *valp = ctl->data; | 4118 | int *valp = ctl->data; |
4097 | int val = *valp; | 4119 | int val = *valp; |
4120 | loff_t pos = *ppos; | ||
4098 | int ret; | 4121 | int ret; |
4099 | 4122 | ||
4100 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4123 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
4101 | 4124 | ||
4102 | if (write) | 4125 | if (write) |
4103 | ret = addrconf_disable_ipv6(ctl, valp, val); | 4126 | ret = addrconf_disable_ipv6(ctl, valp, val); |
4127 | if (ret) | ||
4128 | *ppos = pos; | ||
4104 | return ret; | 4129 | return ret; |
4105 | } | 4130 | } |
4106 | 4131 | ||
@@ -4402,8 +4427,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
4402 | 4427 | ||
4403 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 4428 | static void addrconf_sysctl_register(struct inet6_dev *idev) |
4404 | { | 4429 | { |
4405 | neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, | 4430 | neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", |
4406 | NET_IPV6_NEIGH, "ipv6", | ||
4407 | &ndisc_ifinfo_sysctl_change); | 4431 | &ndisc_ifinfo_sysctl_change); |
4408 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 4432 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
4409 | idev, &idev->cnf); | 4433 | idev, &idev->cnf); |
@@ -4418,7 +4442,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
4418 | 4442 | ||
4419 | #endif | 4443 | #endif |
4420 | 4444 | ||
4421 | static int addrconf_init_net(struct net *net) | 4445 | static int __net_init addrconf_init_net(struct net *net) |
4422 | { | 4446 | { |
4423 | int err; | 4447 | int err; |
4424 | struct ipv6_devconf *all, *dflt; | 4448 | struct ipv6_devconf *all, *dflt; |
@@ -4467,7 +4491,7 @@ err_alloc_all: | |||
4467 | return err; | 4491 | return err; |
4468 | } | 4492 | } |
4469 | 4493 | ||
4470 | static void addrconf_exit_net(struct net *net) | 4494 | static void __net_exit addrconf_exit_net(struct net *net) |
4471 | { | 4495 | { |
4472 | #ifdef CONFIG_SYSCTL | 4496 | #ifdef CONFIG_SYSCTL |
4473 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); | 4497 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); |