diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-27 14:16:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-27 14:16:27 -0400 |
commit | 10799db60cbc4f990dd69eb49883477095c66af7 (patch) | |
tree | b87ac6acaa48f4f59f5d6a0b11490105876952e1 /net | |
parent | aaab184276a6e20834f63735d433f94ef52a0497 (diff) | |
parent | c5c177b4aca83338781e72be2e6dd1601c560cb3 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6:
net: Kill ratelimit.h dependency in linux/net.h
net: Add linux/sysctl.h includes where needed.
net: Kill ether_table[] declaration.
inetpeer: fix race in unused_list manipulations
atm: expose ATM device index in sysfs
IPVS: bug in ip_vs_ftp, same list heaad used in all netns.
bug.h: Move ratelimit warn interfaces to ratelimit.h
bonding: cleanup module option descriptions
net:8021q:vlan.c Fix pr_info to just give the vlan fullname and version.
net: davinci_emac: fix dev_err use at probe
can: convert to %pK for kptr_restrict support
net: fix ETHTOOL_SFEATURES compatibility with old ethtool_ops.set_flags
netfilter: Fix several warnings in compat_mtw_from_user().
netfilter: ipset: fix ip_set_flush return code
netfilter: ipset: remove unused variable from type_pf_tdel()
netfilter: ipset: Use proper timeout value to jiffies conversion
Diffstat (limited to 'net')
-rw-r--r-- | net/8021q/vlan.c | 5 | ||||
-rw-r--r-- | net/atm/atm_sysfs.c | 10 | ||||
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 6 | ||||
-rw-r--r-- | net/can/proc.c | 7 | ||||
-rw-r--r-- | net/core/ethtool.c | 25 | ||||
-rw-r--r-- | net/core/filter.c | 1 | ||||
-rw-r--r-- | net/core/sysctl_net_core.c | 1 | ||||
-rw-r--r-- | net/core/utils.c | 1 | ||||
-rw-r--r-- | net/ipv4/inetpeer.c | 42 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ftp.c | 27 |
11 files changed, 92 insertions, 35 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index b2274d1fd605..c7a581a96894 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -46,8 +46,6 @@ int vlan_net_id __read_mostly; | |||
46 | 46 | ||
47 | const char vlan_fullname[] = "802.1Q VLAN Support"; | 47 | const char vlan_fullname[] = "802.1Q VLAN Support"; |
48 | const char vlan_version[] = DRV_VERSION; | 48 | const char vlan_version[] = DRV_VERSION; |
49 | static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>"; | ||
50 | static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>"; | ||
51 | 49 | ||
52 | /* End of global variables definitions. */ | 50 | /* End of global variables definitions. */ |
53 | 51 | ||
@@ -673,8 +671,7 @@ static int __init vlan_proto_init(void) | |||
673 | { | 671 | { |
674 | int err; | 672 | int err; |
675 | 673 | ||
676 | pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); | 674 | pr_info("%s v%s\n", vlan_fullname, vlan_version); |
677 | pr_info("All bugs added by %s\n", vlan_buggyright); | ||
678 | 675 | ||
679 | err = register_pernet_subsys(&vlan_net_ops); | 676 | err = register_pernet_subsys(&vlan_net_ops); |
680 | if (err < 0) | 677 | if (err < 0) |
diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index f7fa67c78766..f49da5814bc3 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c | |||
@@ -59,6 +59,14 @@ static ssize_t show_atmaddress(struct device *cdev, | |||
59 | return pos - buf; | 59 | return pos - buf; |
60 | } | 60 | } |
61 | 61 | ||
62 | static ssize_t show_atmindex(struct device *cdev, | ||
63 | struct device_attribute *attr, char *buf) | ||
64 | { | ||
65 | struct atm_dev *adev = to_atm_dev(cdev); | ||
66 | |||
67 | return sprintf(buf, "%d\n", adev->number); | ||
68 | } | ||
69 | |||
62 | static ssize_t show_carrier(struct device *cdev, | 70 | static ssize_t show_carrier(struct device *cdev, |
63 | struct device_attribute *attr, char *buf) | 71 | struct device_attribute *attr, char *buf) |
64 | { | 72 | { |
@@ -99,6 +107,7 @@ static ssize_t show_link_rate(struct device *cdev, | |||
99 | 107 | ||
100 | static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); | 108 | static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); |
101 | static DEVICE_ATTR(atmaddress, S_IRUGO, show_atmaddress, NULL); | 109 | static DEVICE_ATTR(atmaddress, S_IRUGO, show_atmaddress, NULL); |
110 | static DEVICE_ATTR(atmindex, S_IRUGO, show_atmindex, NULL); | ||
102 | static DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL); | 111 | static DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL); |
103 | static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); | 112 | static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); |
104 | static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL); | 113 | static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL); |
@@ -106,6 +115,7 @@ static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL); | |||
106 | static struct device_attribute *atm_attrs[] = { | 115 | static struct device_attribute *atm_attrs[] = { |
107 | &dev_attr_atmaddress, | 116 | &dev_attr_atmaddress, |
108 | &dev_attr_address, | 117 | &dev_attr_address, |
118 | &dev_attr_atmindex, | ||
109 | &dev_attr_carrier, | 119 | &dev_attr_carrier, |
110 | &dev_attr_type, | 120 | &dev_attr_type, |
111 | &dev_attr_link_rate, | 121 | &dev_attr_link_rate, |
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 1a92b369c820..2b5ca1a0054d 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -1883,14 +1883,13 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, | |||
1883 | struct xt_target *wt; | 1883 | struct xt_target *wt; |
1884 | void *dst = NULL; | 1884 | void *dst = NULL; |
1885 | int off, pad = 0; | 1885 | int off, pad = 0; |
1886 | unsigned int size_kern, entry_offset, match_size = mwt->match_size; | 1886 | unsigned int size_kern, match_size = mwt->match_size; |
1887 | 1887 | ||
1888 | strlcpy(name, mwt->u.name, sizeof(name)); | 1888 | strlcpy(name, mwt->u.name, sizeof(name)); |
1889 | 1889 | ||
1890 | if (state->buf_kern_start) | 1890 | if (state->buf_kern_start) |
1891 | dst = state->buf_kern_start + state->buf_kern_offset; | 1891 | dst = state->buf_kern_start + state->buf_kern_offset; |
1892 | 1892 | ||
1893 | entry_offset = (unsigned char *) mwt - base; | ||
1894 | switch (compat_mwt) { | 1893 | switch (compat_mwt) { |
1895 | case EBT_COMPAT_MATCH: | 1894 | case EBT_COMPAT_MATCH: |
1896 | match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE, | 1895 | match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE, |
@@ -1933,6 +1932,9 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, | |||
1933 | size_kern = wt->targetsize; | 1932 | size_kern = wt->targetsize; |
1934 | module_put(wt->me); | 1933 | module_put(wt->me); |
1935 | break; | 1934 | break; |
1935 | |||
1936 | default: | ||
1937 | return -EINVAL; | ||
1936 | } | 1938 | } |
1937 | 1939 | ||
1938 | state->buf_kern_offset += match_size + off; | 1940 | state->buf_kern_offset += match_size + off; |
diff --git a/net/can/proc.c b/net/can/proc.c index f4265cc9c3fb..0016f7339699 100644 --- a/net/can/proc.c +++ b/net/can/proc.c | |||
@@ -204,12 +204,11 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, | |||
204 | 204 | ||
205 | hlist_for_each_entry_rcu(r, n, rx_list, list) { | 205 | hlist_for_each_entry_rcu(r, n, rx_list, list) { |
206 | char *fmt = (r->can_id & CAN_EFF_FLAG)? | 206 | char *fmt = (r->can_id & CAN_EFF_FLAG)? |
207 | " %-5s %08X %08x %08x %08x %8ld %s\n" : | 207 | " %-5s %08x %08x %pK %pK %8ld %s\n" : |
208 | " %-5s %03X %08x %08lx %08lx %8ld %s\n"; | 208 | " %-5s %03x %08x %pK %pK %8ld %s\n"; |
209 | 209 | ||
210 | seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask, | 210 | seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask, |
211 | (unsigned long)r->func, (unsigned long)r->data, | 211 | r->func, r->data, r->matches, r->ident); |
212 | r->matches, r->ident); | ||
213 | } | 212 | } |
214 | } | 213 | } |
215 | 214 | ||
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 84e7304532e6..fd14116ad7f0 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -233,6 +233,29 @@ static int ethtool_set_feature_compat(struct net_device *dev, | |||
233 | return 1; | 233 | return 1; |
234 | } | 234 | } |
235 | 235 | ||
236 | static int ethtool_set_flags_compat(struct net_device *dev, | ||
237 | int (*legacy_set)(struct net_device *, u32), | ||
238 | struct ethtool_set_features_block *features, u32 mask) | ||
239 | { | ||
240 | u32 value; | ||
241 | |||
242 | if (!legacy_set) | ||
243 | return 0; | ||
244 | |||
245 | if (!(features[0].valid & mask)) | ||
246 | return 0; | ||
247 | |||
248 | value = dev->features & ~features[0].valid; | ||
249 | value |= features[0].requested; | ||
250 | |||
251 | features[0].valid &= ~mask; | ||
252 | |||
253 | if (legacy_set(dev, value & mask) < 0) | ||
254 | netdev_info(dev, "Legacy flags change failed\n"); | ||
255 | |||
256 | return 1; | ||
257 | } | ||
258 | |||
236 | static int ethtool_set_features_compat(struct net_device *dev, | 259 | static int ethtool_set_features_compat(struct net_device *dev, |
237 | struct ethtool_set_features_block *features) | 260 | struct ethtool_set_features_block *features) |
238 | { | 261 | { |
@@ -249,7 +272,7 @@ static int ethtool_set_features_compat(struct net_device *dev, | |||
249 | features, NETIF_F_ALL_TSO); | 272 | features, NETIF_F_ALL_TSO); |
250 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum, | 273 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum, |
251 | features, NETIF_F_RXCSUM); | 274 | features, NETIF_F_RXCSUM); |
252 | compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags, | 275 | compat |= ethtool_set_flags_compat(dev, dev->ethtool_ops->set_flags, |
253 | features, flags_dup_features); | 276 | features, flags_dup_features); |
254 | 277 | ||
255 | return compat; | 278 | return compat; |
diff --git a/net/core/filter.c b/net/core/filter.c index 0e3622f1dcb1..36f975fa87cb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <asm/unaligned.h> | 38 | #include <asm/unaligned.h> |
39 | #include <linux/filter.h> | 39 | #include <linux/filter.h> |
40 | #include <linux/reciprocal_div.h> | 40 | #include <linux/reciprocal_div.h> |
41 | #include <linux/ratelimit.h> | ||
41 | 42 | ||
42 | /* No hurry in this branch */ | 43 | /* No hurry in this branch */ |
43 | static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size) | 44 | static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size) |
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index a829e3f60aeb..77a65f031488 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <net/ip.h> | 18 | #include <net/ip.h> |
19 | #include <net/sock.h> | 19 | #include <net/sock.h> |
20 | #include <net/net_ratelimit.h> | ||
20 | 21 | ||
21 | #ifdef CONFIG_RPS | 22 | #ifdef CONFIG_RPS |
22 | static int rps_sock_flow_sysctl(ctl_table *table, int write, | 23 | static int rps_sock_flow_sysctl(ctl_table *table, int write, |
diff --git a/net/core/utils.c b/net/core/utils.c index 2012bc797f9c..386e263f6066 100644 --- a/net/core/utils.c +++ b/net/core/utils.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/ratelimit.h> | 27 | #include <linux/ratelimit.h> |
28 | 28 | ||
29 | #include <net/sock.h> | 29 | #include <net/sock.h> |
30 | #include <net/net_ratelimit.h> | ||
30 | 31 | ||
31 | #include <asm/byteorder.h> | 32 | #include <asm/byteorder.h> |
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 9df4e635fb5f..ce616d92cc54 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
@@ -154,11 +154,9 @@ void __init inet_initpeers(void) | |||
154 | /* Called with or without local BH being disabled. */ | 154 | /* Called with or without local BH being disabled. */ |
155 | static void unlink_from_unused(struct inet_peer *p) | 155 | static void unlink_from_unused(struct inet_peer *p) |
156 | { | 156 | { |
157 | if (!list_empty(&p->unused)) { | 157 | spin_lock_bh(&unused_peers.lock); |
158 | spin_lock_bh(&unused_peers.lock); | 158 | list_del_init(&p->unused); |
159 | list_del_init(&p->unused); | 159 | spin_unlock_bh(&unused_peers.lock); |
160 | spin_unlock_bh(&unused_peers.lock); | ||
161 | } | ||
162 | } | 160 | } |
163 | 161 | ||
164 | static int addr_compare(const struct inetpeer_addr *a, | 162 | static int addr_compare(const struct inetpeer_addr *a, |
@@ -205,6 +203,20 @@ static int addr_compare(const struct inetpeer_addr *a, | |||
205 | u; \ | 203 | u; \ |
206 | }) | 204 | }) |
207 | 205 | ||
206 | static bool atomic_add_unless_return(atomic_t *ptr, int a, int u, int *newv) | ||
207 | { | ||
208 | int cur, old = atomic_read(ptr); | ||
209 | |||
210 | while (old != u) { | ||
211 | *newv = old + a; | ||
212 | cur = atomic_cmpxchg(ptr, old, *newv); | ||
213 | if (cur == old) | ||
214 | return true; | ||
215 | old = cur; | ||
216 | } | ||
217 | return false; | ||
218 | } | ||
219 | |||
208 | /* | 220 | /* |
209 | * Called with rcu_read_lock() | 221 | * Called with rcu_read_lock() |
210 | * Because we hold no lock against a writer, its quite possible we fall | 222 | * Because we hold no lock against a writer, its quite possible we fall |
@@ -213,7 +225,8 @@ static int addr_compare(const struct inetpeer_addr *a, | |||
213 | * We exit from this function if number of links exceeds PEER_MAXDEPTH | 225 | * We exit from this function if number of links exceeds PEER_MAXDEPTH |
214 | */ | 226 | */ |
215 | static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr, | 227 | static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr, |
216 | struct inet_peer_base *base) | 228 | struct inet_peer_base *base, |
229 | int *newrefcnt) | ||
217 | { | 230 | { |
218 | struct inet_peer *u = rcu_dereference(base->root); | 231 | struct inet_peer *u = rcu_dereference(base->root); |
219 | int count = 0; | 232 | int count = 0; |
@@ -226,7 +239,7 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr, | |||
226 | * distinction between an unused entry (refcnt=0) and | 239 | * distinction between an unused entry (refcnt=0) and |
227 | * a freed one. | 240 | * a freed one. |
228 | */ | 241 | */ |
229 | if (unlikely(!atomic_add_unless(&u->refcnt, 1, -1))) | 242 | if (!atomic_add_unless_return(&u->refcnt, 1, -1, newrefcnt)) |
230 | u = NULL; | 243 | u = NULL; |
231 | return u; | 244 | return u; |
232 | } | 245 | } |
@@ -465,22 +478,23 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create) | |||
465 | struct inet_peer_base *base = family_to_base(daddr->family); | 478 | struct inet_peer_base *base = family_to_base(daddr->family); |
466 | struct inet_peer *p; | 479 | struct inet_peer *p; |
467 | unsigned int sequence; | 480 | unsigned int sequence; |
468 | int invalidated; | 481 | int invalidated, newrefcnt = 0; |
469 | 482 | ||
470 | /* Look up for the address quickly, lockless. | 483 | /* Look up for the address quickly, lockless. |
471 | * Because of a concurrent writer, we might not find an existing entry. | 484 | * Because of a concurrent writer, we might not find an existing entry. |
472 | */ | 485 | */ |
473 | rcu_read_lock(); | 486 | rcu_read_lock(); |
474 | sequence = read_seqbegin(&base->lock); | 487 | sequence = read_seqbegin(&base->lock); |
475 | p = lookup_rcu(daddr, base); | 488 | p = lookup_rcu(daddr, base, &newrefcnt); |
476 | invalidated = read_seqretry(&base->lock, sequence); | 489 | invalidated = read_seqretry(&base->lock, sequence); |
477 | rcu_read_unlock(); | 490 | rcu_read_unlock(); |
478 | 491 | ||
479 | if (p) { | 492 | if (p) { |
480 | /* The existing node has been found. | 493 | found: /* The existing node has been found. |
481 | * Remove the entry from unused list if it was there. | 494 | * Remove the entry from unused list if it was there. |
482 | */ | 495 | */ |
483 | unlink_from_unused(p); | 496 | if (newrefcnt == 1) |
497 | unlink_from_unused(p); | ||
484 | return p; | 498 | return p; |
485 | } | 499 | } |
486 | 500 | ||
@@ -494,11 +508,9 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create) | |||
494 | write_seqlock_bh(&base->lock); | 508 | write_seqlock_bh(&base->lock); |
495 | p = lookup(daddr, stack, base); | 509 | p = lookup(daddr, stack, base); |
496 | if (p != peer_avl_empty) { | 510 | if (p != peer_avl_empty) { |
497 | atomic_inc(&p->refcnt); | 511 | newrefcnt = atomic_inc_return(&p->refcnt); |
498 | write_sequnlock_bh(&base->lock); | 512 | write_sequnlock_bh(&base->lock); |
499 | /* Remove the entry from unused list if it was there. */ | 513 | goto found; |
500 | unlink_from_unused(p); | ||
501 | return p; | ||
502 | } | 514 | } |
503 | p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL; | 515 | p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL; |
504 | if (p) { | 516 | if (p) { |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 72d1ac611fdc..8041befc6555 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -815,7 +815,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb, | |||
815 | ip_set_id_t i; | 815 | ip_set_id_t i; |
816 | 816 | ||
817 | if (unlikely(protocol_failed(attr))) | 817 | if (unlikely(protocol_failed(attr))) |
818 | return -EPROTO; | 818 | return -IPSET_ERR_PROTOCOL; |
819 | 819 | ||
820 | if (!attr[IPSET_ATTR_SETNAME]) { | 820 | if (!attr[IPSET_ATTR_SETNAME]) { |
821 | for (i = 0; i < ip_set_max; i++) | 821 | for (i = 0; i < ip_set_max; i++) |
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 6b5dd6ddaae9..af63553fa332 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c | |||
@@ -411,25 +411,35 @@ static struct ip_vs_app ip_vs_ftp = { | |||
411 | static int __net_init __ip_vs_ftp_init(struct net *net) | 411 | static int __net_init __ip_vs_ftp_init(struct net *net) |
412 | { | 412 | { |
413 | int i, ret; | 413 | int i, ret; |
414 | struct ip_vs_app *app = &ip_vs_ftp; | 414 | struct ip_vs_app *app; |
415 | struct netns_ipvs *ipvs = net_ipvs(net); | ||
416 | |||
417 | app = kmemdup(&ip_vs_ftp, sizeof(struct ip_vs_app), GFP_KERNEL); | ||
418 | if (!app) | ||
419 | return -ENOMEM; | ||
420 | INIT_LIST_HEAD(&app->a_list); | ||
421 | INIT_LIST_HEAD(&app->incs_list); | ||
422 | ipvs->ftp_app = app; | ||
415 | 423 | ||
416 | ret = register_ip_vs_app(net, app); | 424 | ret = register_ip_vs_app(net, app); |
417 | if (ret) | 425 | if (ret) |
418 | return ret; | 426 | goto err_exit; |
419 | 427 | ||
420 | for (i=0; i<IP_VS_APP_MAX_PORTS; i++) { | 428 | for (i=0; i<IP_VS_APP_MAX_PORTS; i++) { |
421 | if (!ports[i]) | 429 | if (!ports[i]) |
422 | continue; | 430 | continue; |
423 | ret = register_ip_vs_app_inc(net, app, app->protocol, ports[i]); | 431 | ret = register_ip_vs_app_inc(net, app, app->protocol, ports[i]); |
424 | if (ret) | 432 | if (ret) |
425 | break; | 433 | goto err_unreg; |
426 | pr_info("%s: loaded support on port[%d] = %d\n", | 434 | pr_info("%s: loaded support on port[%d] = %d\n", |
427 | app->name, i, ports[i]); | 435 | app->name, i, ports[i]); |
428 | } | 436 | } |
437 | return 0; | ||
429 | 438 | ||
430 | if (ret) | 439 | err_unreg: |
431 | unregister_ip_vs_app(net, app); | 440 | unregister_ip_vs_app(net, app); |
432 | 441 | err_exit: | |
442 | kfree(ipvs->ftp_app); | ||
433 | return ret; | 443 | return ret; |
434 | } | 444 | } |
435 | /* | 445 | /* |
@@ -437,9 +447,10 @@ static int __net_init __ip_vs_ftp_init(struct net *net) | |||
437 | */ | 447 | */ |
438 | static void __ip_vs_ftp_exit(struct net *net) | 448 | static void __ip_vs_ftp_exit(struct net *net) |
439 | { | 449 | { |
440 | struct ip_vs_app *app = &ip_vs_ftp; | 450 | struct netns_ipvs *ipvs = net_ipvs(net); |
441 | 451 | ||
442 | unregister_ip_vs_app(net, app); | 452 | unregister_ip_vs_app(net, ipvs->ftp_app); |
453 | kfree(ipvs->ftp_app); | ||
443 | } | 454 | } |
444 | 455 | ||
445 | static struct pernet_operations ip_vs_ftp_ops = { | 456 | static struct pernet_operations ip_vs_ftp_ops = { |