提交 827bf122 编写于 作者: S Sridhar Samudrala 提交者: David S. Miller

[SCTP]: Re-order SCTP initializations to avoid race with sctp_rcv()

Signed-off-by: NSridhar Samudrala <sri@us.ibm.com>
Signed-off-by: NVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 ce5325c1
...@@ -378,11 +378,15 @@ static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int ...@@ -378,11 +378,15 @@ static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int
int sctp_v6_init(void); int sctp_v6_init(void);
void sctp_v6_exit(void); void sctp_v6_exit(void);
int sctp_v6_add_protocol(void);
void sctp_v6_del_protocol(void);
#else /* #ifdef defined(CONFIG_IPV6) */ #else /* #ifdef defined(CONFIG_IPV6) */
static inline int sctp_v6_init(void) { return 0; } static inline int sctp_v6_init(void) { return 0; }
static inline void sctp_v6_exit(void) { return; } static inline void sctp_v6_exit(void) { return; }
static inline int sctp_v6_add_protocol(void) { return 0; }
static inline void sctp_v6_del_protocol(void) { return; }
#endif /* #if defined(CONFIG_IPV6) */ #endif /* #if defined(CONFIG_IPV6) */
......
...@@ -992,45 +992,52 @@ static struct sctp_pf sctp_pf_inet6_specific = { ...@@ -992,45 +992,52 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.af = &sctp_ipv6_specific, .af = &sctp_ipv6_specific,
}; };
/* Initialize IPv6 support and register with inet6 stack. */ /* Initialize IPv6 support and register with socket layer. */
int sctp_v6_init(void) int sctp_v6_init(void)
{ {
int rc = proto_register(&sctpv6_prot, 1); int rc;
/* Register the SCTP specific PF_INET6 functions. */
sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
/* Register the SCTP specific AF_INET6 functions. */
sctp_register_af(&sctp_ipv6_specific);
rc = proto_register(&sctpv6_prot, 1);
if (rc) if (rc)
goto out; return rc;
/* Register inet6 protocol. */
rc = -EAGAIN;
if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
goto out_unregister_sctp_proto;
/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */ /* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_seqpacket_protosw); inet6_register_protosw(&sctpv6_seqpacket_protosw);
inet6_register_protosw(&sctpv6_stream_protosw); inet6_register_protosw(&sctpv6_stream_protosw);
/* Register the SCTP specific PF_INET6 functions. */ return 0;
sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6); }
/* Register the SCTP specific AF_INET6 functions. */
sctp_register_af(&sctp_ipv6_specific);
/* Register with inet6 layer. */
int sctp_v6_add_protocol(void)
{
/* Register notifier for inet6 address additions/deletions. */ /* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier(&sctp_inet6addr_notifier); register_inet6addr_notifier(&sctp_inet6addr_notifier);
rc = 0;
out: if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
return rc; return -EAGAIN;
out_unregister_sctp_proto:
proto_unregister(&sctpv6_prot); return 0;
goto out;
} }
/* IPv6 specific exit support. */ /* IPv6 specific exit support. */
void sctp_v6_exit(void) void sctp_v6_exit(void)
{ {
list_del(&sctp_ipv6_specific.list);
inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
inet6_unregister_protosw(&sctpv6_seqpacket_protosw); inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
inet6_unregister_protosw(&sctpv6_stream_protosw); inet6_unregister_protosw(&sctpv6_stream_protosw);
unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
proto_unregister(&sctpv6_prot); proto_unregister(&sctpv6_prot);
list_del(&sctp_ipv6_specific.list);
}
/* Unregister with inet6 layer. */
void sctp_v6_del_protocol(void)
{
inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
} }
...@@ -975,28 +975,14 @@ SCTP_STATIC __init int sctp_init(void) ...@@ -975,28 +975,14 @@ SCTP_STATIC __init int sctp_init(void)
if (!sctp_sanity_check()) if (!sctp_sanity_check())
goto out; goto out;
status = proto_register(&sctp_prot, 1); /* Allocate bind_bucket and chunk caches. */
if (status)
goto out;
/* Add SCTP to inet_protos hash table. */
status = -EAGAIN;
if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
goto err_add_protocol;
/* Add SCTP(TCP and UDP style) to inetsw linked list. */
inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw);
/* Allocate a cache pools. */
status = -ENOBUFS; status = -ENOBUFS;
sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket", sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
sizeof(struct sctp_bind_bucket), sizeof(struct sctp_bind_bucket),
0, SLAB_HWCACHE_ALIGN, 0, SLAB_HWCACHE_ALIGN,
NULL, NULL); NULL, NULL);
if (!sctp_bucket_cachep) if (!sctp_bucket_cachep)
goto err_bucket_cachep; goto out;
sctp_chunk_cachep = kmem_cache_create("sctp_chunk", sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
sizeof(struct sctp_chunk), sizeof(struct sctp_chunk),
...@@ -1153,6 +1139,14 @@ SCTP_STATIC __init int sctp_init(void) ...@@ -1153,6 +1139,14 @@ SCTP_STATIC __init int sctp_init(void)
INIT_LIST_HEAD(&sctp_address_families); INIT_LIST_HEAD(&sctp_address_families);
sctp_register_af(&sctp_ipv4_specific); sctp_register_af(&sctp_ipv4_specific);
status = proto_register(&sctp_prot, 1);
if (status)
goto err_proto_register;
/* Register SCTP(UDP and TCP style) with socket layer. */
inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw);
status = sctp_v6_init(); status = sctp_v6_init();
if (status) if (status)
goto err_v6_init; goto err_v6_init;
...@@ -1166,19 +1160,39 @@ SCTP_STATIC __init int sctp_init(void) ...@@ -1166,19 +1160,39 @@ SCTP_STATIC __init int sctp_init(void)
/* Initialize the local address list. */ /* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list); INIT_LIST_HEAD(&sctp_local_addr_list);
sctp_get_local_addr_list(); sctp_get_local_addr_list();
/* Register notifier for inet address additions/deletions. */ /* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier(&sctp_inetaddr_notifier); register_inetaddr_notifier(&sctp_inetaddr_notifier);
/* Register SCTP with inet layer. */
if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) {
status = -EAGAIN;
goto err_add_protocol;
}
/* Register SCTP with inet6 layer. */
status = sctp_v6_add_protocol();
if (status)
goto err_v6_add_protocol;
__unsafe(THIS_MODULE); __unsafe(THIS_MODULE);
status = 0; status = 0;
out: out:
return status; return status;
err_v6_add_protocol:
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
err_add_protocol:
sctp_free_local_addr_list();
sock_release(sctp_ctl_socket);
err_ctl_sock_init: err_ctl_sock_init:
sctp_v6_exit(); sctp_v6_exit();
err_v6_init: err_v6_init:
inet_unregister_protosw(&sctp_stream_protosw);
inet_unregister_protosw(&sctp_seqpacket_protosw);
proto_unregister(&sctp_prot);
err_proto_register:
sctp_sysctl_unregister(); sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list); list_del(&sctp_ipv4_specific.list);
free_pages((unsigned long)sctp_port_hashtable, free_pages((unsigned long)sctp_port_hashtable,
...@@ -1192,19 +1206,13 @@ SCTP_STATIC __init int sctp_init(void) ...@@ -1192,19 +1206,13 @@ SCTP_STATIC __init int sctp_init(void)
sizeof(struct sctp_hashbucket))); sizeof(struct sctp_hashbucket)));
err_ahash_alloc: err_ahash_alloc:
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
err_init_proc:
sctp_proc_exit(); sctp_proc_exit();
err_init_proc:
cleanup_sctp_mibs(); cleanup_sctp_mibs();
err_init_mibs: err_init_mibs:
kmem_cache_destroy(sctp_chunk_cachep); kmem_cache_destroy(sctp_chunk_cachep);
err_chunk_cachep: err_chunk_cachep:
kmem_cache_destroy(sctp_bucket_cachep); kmem_cache_destroy(sctp_bucket_cachep);
err_bucket_cachep:
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw);
err_add_protocol:
proto_unregister(&sctp_prot);
goto out; goto out;
} }
...@@ -1215,8 +1223,9 @@ SCTP_STATIC __exit void sctp_exit(void) ...@@ -1215,8 +1223,9 @@ SCTP_STATIC __exit void sctp_exit(void)
* up all the remaining associations and all that memory. * up all the remaining associations and all that memory.
*/ */
/* Unregister notifier for inet address additions/deletions. */ /* Unregister with inet6/inet layers. */
unregister_inetaddr_notifier(&sctp_inetaddr_notifier); sctp_v6_del_protocol();
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
/* Free the local address list. */ /* Free the local address list. */
sctp_free_local_addr_list(); sctp_free_local_addr_list();
...@@ -1224,7 +1233,16 @@ SCTP_STATIC __exit void sctp_exit(void) ...@@ -1224,7 +1233,16 @@ SCTP_STATIC __exit void sctp_exit(void)
/* Free the control endpoint. */ /* Free the control endpoint. */
sock_release(sctp_ctl_socket); sock_release(sctp_ctl_socket);
/* Cleanup v6 initializations. */
sctp_v6_exit(); sctp_v6_exit();
/* Unregister with socket layer. */
inet_unregister_protosw(&sctp_stream_protosw);
inet_unregister_protosw(&sctp_seqpacket_protosw);
/* Unregister notifier for inet address additions/deletions. */
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
sctp_sysctl_unregister(); sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list); list_del(&sctp_ipv4_specific.list);
...@@ -1236,16 +1254,13 @@ SCTP_STATIC __exit void sctp_exit(void) ...@@ -1236,16 +1254,13 @@ SCTP_STATIC __exit void sctp_exit(void)
get_order(sctp_port_hashsize * get_order(sctp_port_hashsize *
sizeof(struct sctp_bind_hashbucket))); sizeof(struct sctp_bind_hashbucket)));
kmem_cache_destroy(sctp_chunk_cachep);
kmem_cache_destroy(sctp_bucket_cachep);
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
sctp_proc_exit(); sctp_proc_exit();
cleanup_sctp_mibs(); cleanup_sctp_mibs();
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); kmem_cache_destroy(sctp_chunk_cachep);
inet_unregister_protosw(&sctp_seqpacket_protosw); kmem_cache_destroy(sctp_bucket_cachep);
inet_unregister_protosw(&sctp_stream_protosw);
proto_unregister(&sctp_prot); proto_unregister(&sctp_prot);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册