[NET] generalise per protocol slab cache handling

With this patch we get two new slabcaches, for sctp socks, that previously
were being allocated on the default, that was tcp[6]_sock, i.e. wasting 288
bytes per sock in the IPv4 case and 256 bytes for the IPv6 version, this is in
preparation for DCCP (or any other new protocol :) ).

With this in place another nice side effect that is easier to achieve is to
get rid of struct sock sk->sk_slab, and instead use sk->sk_prot->slab, saving
sizeof(void *) on every struct sock instance, but this unfortunatly has to
wait for the conversion of all protocols that use per socket slabcaches to
use sk->sk_prot, AF_UNIX is the only one AFAIK, so I'll try to convert it to
use sk->sk_prot and then get rid of sk->sk_slab.

As for the protocols that don't use per socket slabcaches its just a matter
of defaulting to sk_cachep at sk_free time if sk->sk_prot is NULL.

[root@qemu ~]# modprobe sctp
[root@qemu ~]# grep _sock /proc/slabinfo
sctpv6_sock            9      9    864    9    2 : tunables   54   27    0 :
sctp_sock              0      0    736    5    1 : tunables   54   27    0 :
rawv6_sock             3      6    640    6    1 : tunables   54   27    0 :
udpv6_sock             0      0    608    6    1 : tunables   54   27    0 :
tcpv6_sock             1      7   1120    7    2 : tunables   24   12    0 :
unix_sock              6     10    384   10    1 : tunables   54   27    0 :
raw_sock               2      8    480    8    1 : tunables   54   27    0 :
udp_sock               0      0    512    7    1 : tunables   54   27    0 :
tcp_sock               0      0   1024    4    1 : tunables   54   27    0 :
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@conectiva.com.br>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent 664d4fca
...@@ -282,6 +282,10 @@ static inline struct raw6_opt * raw6_sk(const struct sock *__sk) ...@@ -282,6 +282,10 @@ static inline struct raw6_opt * raw6_sk(const struct sock *__sk)
return &((struct raw6_sock *)__sk)->raw6; return &((struct raw6_sock *)__sk)->raw6;
} }
struct ipv6_sk_offset {
int offset;
};
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only) #define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only)
#define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk)) #define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk))
......
...@@ -505,6 +505,7 @@ for (pos = chunk->subh.fwdtsn_hdr->skip;\ ...@@ -505,6 +505,7 @@ for (pos = chunk->subh.fwdtsn_hdr->skip;\
/* External references. */ /* External references. */
extern struct proto sctp_prot; extern struct proto sctp_prot;
extern struct proto sctpv6_prot;
extern struct proc_dir_entry *proc_net_sctp; extern struct proc_dir_entry *proc_net_sctp;
void sctp_put_port(struct sock *sk); void sctp_put_port(struct sock *sk);
......
...@@ -555,6 +555,10 @@ struct proto { ...@@ -555,6 +555,10 @@ struct proto {
int *sysctl_rmem; int *sysctl_rmem;
int max_header; int max_header;
kmem_cache_t *slab;
int slab_obj_size;
void *af_specific;
char name[32]; char name[32];
struct { struct {
...@@ -563,6 +567,14 @@ struct proto { ...@@ -563,6 +567,14 @@ struct proto {
} stats[NR_CPUS]; } stats[NR_CPUS];
}; };
extern int sk_alloc_slab(struct proto *prot, char *name);
extern void sk_free_slab(struct proto *prot);
static inline void sk_alloc_slab_error(struct proto *proto)
{
printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", proto->name);
}
static __inline__ void sk_set_owner(struct sock *sk, struct module *owner) static __inline__ void sk_set_owner(struct sock *sk, struct module *owner)
{ {
/* /*
......
...@@ -153,9 +153,6 @@ extern struct tcp_hashinfo { ...@@ -153,9 +153,6 @@ extern struct tcp_hashinfo {
#define tcp_lhash_wait (tcp_hashinfo.__tcp_lhash_wait) #define tcp_lhash_wait (tcp_hashinfo.__tcp_lhash_wait)
#define tcp_portalloc_lock (tcp_hashinfo.__tcp_portalloc_lock) #define tcp_portalloc_lock (tcp_hashinfo.__tcp_portalloc_lock)
/* SLAB cache for TCP socks */
extern kmem_cache_t *tcp_sk_cachep;
extern kmem_cache_t *tcp_bucket_cachep; extern kmem_cache_t *tcp_bucket_cachep;
extern struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head, extern struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
unsigned short snum); unsigned short snum);
......
...@@ -1343,6 +1343,27 @@ void sk_common_release(struct sock *sk) ...@@ -1343,6 +1343,27 @@ void sk_common_release(struct sock *sk)
EXPORT_SYMBOL(sk_common_release); EXPORT_SYMBOL(sk_common_release);
int sk_alloc_slab(struct proto *prot, char *name)
{
prot->slab = kmem_cache_create(name,
prot->slab_obj_size, 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
return prot->slab != NULL ? 0 : -ENOBUFS;
}
EXPORT_SYMBOL(sk_alloc_slab);
void sk_free_slab(struct proto *prot)
{
if (prot->slab != NULL) {
kmem_cache_destroy(prot->slab);
prot->slab = NULL;
}
}
EXPORT_SYMBOL(sk_free_slab);
EXPORT_SYMBOL(__lock_sock); EXPORT_SYMBOL(__lock_sock);
EXPORT_SYMBOL(__release_sock); EXPORT_SYMBOL(__release_sock);
EXPORT_SYMBOL(sk_alloc); EXPORT_SYMBOL(sk_alloc);
......
...@@ -121,11 +121,6 @@ atomic_t inet_sock_nr; ...@@ -121,11 +121,6 @@ atomic_t inet_sock_nr;
extern void ip_mc_drop_socket(struct sock *sk); extern void ip_mc_drop_socket(struct sock *sk);
/* Per protocol sock slabcache */
kmem_cache_t *tcp_sk_cachep;
static kmem_cache_t *udp_sk_cachep;
static kmem_cache_t *raw4_sk_cachep;
/* The inetsw table contains everything that inet_create needs to /* The inetsw table contains everything that inet_create needs to
* build a new socket. * build a new socket.
*/ */
...@@ -228,28 +223,6 @@ int inet_listen(struct socket *sock, int backlog) ...@@ -228,28 +223,6 @@ int inet_listen(struct socket *sock, int backlog)
return err; return err;
} }
static __inline__ kmem_cache_t *inet_sk_slab(int protocol)
{
kmem_cache_t* rc = tcp_sk_cachep;
if (protocol == IPPROTO_UDP)
rc = udp_sk_cachep;
else if (protocol == IPPROTO_RAW)
rc = raw4_sk_cachep;
return rc;
}
static __inline__ int inet_sk_size(int protocol)
{
int rc = sizeof(struct tcp_sock);
if (protocol == IPPROTO_UDP)
rc = sizeof(struct udp_sock);
else if (protocol == IPPROTO_RAW)
rc = sizeof(struct raw_sock);
return rc;
}
/* /*
* Create an inet socket. * Create an inet socket.
*/ */
...@@ -260,13 +233,12 @@ static int inet_create(struct socket *sock, int protocol) ...@@ -260,13 +233,12 @@ static int inet_create(struct socket *sock, int protocol)
struct list_head *p; struct list_head *p;
struct inet_protosw *answer; struct inet_protosw *answer;
struct inet_opt *inet; struct inet_opt *inet;
int err = -ENOBUFS; struct proto *answer_prot;
unsigned char answer_flags;
char answer_no_check;
int err;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
inet_sk_slab(protocol));
if (!sk)
goto out;
/* Look for the requested type/protocol pair. */ /* Look for the requested type/protocol pair. */
answer = NULL; answer = NULL;
...@@ -292,21 +264,35 @@ static int inet_create(struct socket *sock, int protocol) ...@@ -292,21 +264,35 @@ static int inet_create(struct socket *sock, int protocol)
err = -ESOCKTNOSUPPORT; err = -ESOCKTNOSUPPORT;
if (!answer) if (!answer)
goto out_sk_free; goto out_rcu_unlock;
err = -EPERM; err = -EPERM;
if (answer->capability > 0 && !capable(answer->capability)) if (answer->capability > 0 && !capable(answer->capability))
goto out_sk_free; goto out_rcu_unlock;
err = -EPROTONOSUPPORT; err = -EPROTONOSUPPORT;
if (!protocol) if (!protocol)
goto out_sk_free; goto out_rcu_unlock;
err = 0;
sock->ops = answer->ops; sock->ops = answer->ops;
sk->sk_prot = answer->prot; answer_prot = answer->prot;
sk->sk_no_check = answer->no_check; answer_no_check = answer->no_check;
if (INET_PROTOSW_REUSE & answer->flags) answer_flags = answer->flags;
sk->sk_reuse = 1;
rcu_read_unlock(); rcu_read_unlock();
BUG_TRAP(answer_prot->slab != NULL);
err = -ENOBUFS;
sk = sk_alloc(PF_INET, GFP_KERNEL,
answer_prot->slab_obj_size,
answer_prot->slab);
if (sk == NULL)
goto out;
err = 0;
sk->sk_prot = answer_prot;
sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = 1;
inet = inet_sk(sk); inet = inet_sk(sk);
if (SOCK_RAW == sock->type) { if (SOCK_RAW == sock->type) {
...@@ -359,9 +345,8 @@ static int inet_create(struct socket *sock, int protocol) ...@@ -359,9 +345,8 @@ static int inet_create(struct socket *sock, int protocol)
} }
out: out:
return err; return err;
out_sk_free: out_rcu_unlock:
rcu_read_unlock(); rcu_read_unlock();
sk_free(sk);
goto out; goto out;
} }
...@@ -1010,24 +995,29 @@ static int __init inet_init(void) ...@@ -1010,24 +995,29 @@ static int __init inet_init(void)
struct sk_buff *dummy_skb; struct sk_buff *dummy_skb;
struct inet_protosw *q; struct inet_protosw *q;
struct list_head *r; struct list_head *r;
int rc = -EINVAL;
if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) { if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
printk(KERN_CRIT "%s: panic\n", __FUNCTION__); printk(KERN_CRIT "%s: panic\n", __FUNCTION__);
return -EINVAL; goto out;
}
rc = sk_alloc_slab(&tcp_prot, "tcp_sock");
if (rc) {
sk_alloc_slab_error(&tcp_prot);
goto out;
}
rc = sk_alloc_slab(&udp_prot, "udp_sock");
if (rc) {
sk_alloc_slab_error(&udp_prot);
goto out_tcp_free_slab;
}
rc = sk_alloc_slab(&raw_prot, "raw_sock");
if (rc) {
sk_alloc_slab_error(&raw_prot);
goto out_udp_free_slab;
} }
tcp_sk_cachep = kmem_cache_create("tcp_sock",
sizeof(struct tcp_sock), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
udp_sk_cachep = kmem_cache_create("udp_sock",
sizeof(struct udp_sock), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
raw4_sk_cachep = kmem_cache_create("raw4_sock",
sizeof(struct raw_sock), 0,
SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!tcp_sk_cachep || !udp_sk_cachep || !raw4_sk_cachep)
printk(KERN_CRIT
"inet_init: Can't create protocol sock SLAB caches!\n");
/* /*
* Tell SOCKET that we are alive... * Tell SOCKET that we are alive...
*/ */
...@@ -1097,7 +1087,14 @@ static int __init inet_init(void) ...@@ -1097,7 +1087,14 @@ static int __init inet_init(void)
ipfrag_init(); ipfrag_init();
return 0; rc = 0;
out:
return rc;
out_tcp_free_slab:
sk_free_slab(&tcp_prot);
out_udp_free_slab:
sk_free_slab(&udp_prot);
goto out;
} }
module_init(inet_init); module_init(inet_init);
......
...@@ -719,6 +719,7 @@ struct proto raw_prot = { ...@@ -719,6 +719,7 @@ struct proto raw_prot = {
.backlog_rcv = raw_rcv_skb, .backlog_rcv = raw_rcv_skb,
.hash = raw_v4_hash, .hash = raw_v4_hash,
.unhash = raw_v4_unhash, .unhash = raw_v4_unhash,
.slab_obj_size = sizeof(struct raw_sock),
}; };
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -2617,6 +2617,7 @@ struct proto tcp_prot = { ...@@ -2617,6 +2617,7 @@ struct proto tcp_prot = {
.sysctl_wmem = sysctl_tcp_wmem, .sysctl_wmem = sysctl_tcp_wmem,
.sysctl_rmem = sysctl_tcp_rmem, .sysctl_rmem = sysctl_tcp_rmem,
.max_header = MAX_TCP_HEADER, .max_header = MAX_TCP_HEADER,
.slab_obj_size = sizeof(struct tcp_sock),
}; };
......
...@@ -687,7 +687,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req, ...@@ -687,7 +687,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
/* allocate the newsk from the same slab of the master sock, /* allocate the newsk from the same slab of the master sock,
* if not, at sk_free time we'll try to free it from the wrong * if not, at sk_free time we'll try to free it from the wrong
* slabcache (i.e. is it TCPv4 or v6?) -acme */ * slabcache (i.e. is it TCPv4 or v6?) -acme */
struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0, sk->sk_slab); struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0, sk->sk_prot->slab);
if(newsk != NULL) { if(newsk != NULL) {
struct tcp_opt *newtp; struct tcp_opt *newtp;
......
...@@ -1320,6 +1320,7 @@ struct proto udp_prot = { ...@@ -1320,6 +1320,7 @@ struct proto udp_prot = {
.hash = udp_v4_hash, .hash = udp_v4_hash,
.unhash = udp_v4_unhash, .unhash = udp_v4_unhash,
.get_port = udp_v4_get_port, .get_port = udp_v4_get_port,
.slab_obj_size = sizeof(struct udp_sock),
}; };
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
......
...@@ -90,11 +90,6 @@ int sysctl_ipv6_bindv6only; ...@@ -90,11 +90,6 @@ int sysctl_ipv6_bindv6only;
atomic_t inet6_sock_nr; atomic_t inet6_sock_nr;
#endif #endif
/* Per protocol sock slabcache */
kmem_cache_t *tcp6_sk_cachep;
kmem_cache_t *udp6_sk_cachep;
kmem_cache_t *raw6_sk_cachep;
/* The inetsw table contains everything that inet_create needs to /* The inetsw table contains everything that inet_create needs to
* build a new socket. * build a new socket.
*/ */
...@@ -110,37 +105,11 @@ static void inet6_sock_destruct(struct sock *sk) ...@@ -110,37 +105,11 @@ static void inet6_sock_destruct(struct sock *sk)
#endif #endif
} }
static __inline__ kmem_cache_t *inet6_sk_slab(int protocol)
{
kmem_cache_t* rc = tcp6_sk_cachep;
if (protocol == IPPROTO_UDP)
rc = udp6_sk_cachep;
else if (protocol == IPPROTO_RAW)
rc = raw6_sk_cachep;
return rc;
}
static __inline__ int inet6_sk_size(int protocol)
{
int rc = sizeof(struct tcp6_sock);
if (protocol == IPPROTO_UDP)
rc = sizeof(struct udp6_sock);
else if (protocol == IPPROTO_RAW)
rc = sizeof(struct raw6_sock);
return rc;
}
static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
{ {
struct ipv6_pinfo *rc = (&((struct tcp6_sock *)sk)->inet6); const struct ipv6_sk_offset *offset = sk->sk_prot->af_specific;
if (sk->sk_protocol == IPPROTO_UDP) return (struct ipv6_pinfo *)(((u8 *)sk) + offset->offset);
rc = (&((struct udp6_sock *)sk)->inet6);
else if (sk->sk_protocol == IPPROTO_RAW)
rc = (&((struct raw6_sock *)sk)->inet6);
return rc;
} }
static int inet6_create(struct socket *sock, int protocol) static int inet6_create(struct socket *sock, int protocol)
...@@ -151,11 +120,10 @@ static int inet6_create(struct socket *sock, int protocol) ...@@ -151,11 +120,10 @@ static int inet6_create(struct socket *sock, int protocol)
struct tcp6_sock* tcp6sk; struct tcp6_sock* tcp6sk;
struct list_head *p; struct list_head *p;
struct inet_protosw *answer; struct inet_protosw *answer;
struct proto *answer_prot;
sk = sk_alloc(PF_INET6, GFP_KERNEL, inet6_sk_size(protocol), unsigned char answer_flags;
inet6_sk_slab(protocol)); char answer_no_check;
if (sk == NULL) int rc;
goto do_oom;
/* Look for the requested type/protocol pair. */ /* Look for the requested type/protocol pair. */
answer = NULL; answer = NULL;
...@@ -179,22 +147,40 @@ static int inet6_create(struct socket *sock, int protocol) ...@@ -179,22 +147,40 @@ static int inet6_create(struct socket *sock, int protocol)
answer = NULL; answer = NULL;
} }
rc = -ESOCKTNOSUPPORT;
if (!answer) if (!answer)
goto free_and_badtype; goto out_rcu_unlock;
rc = -EPERM;
if (answer->capability > 0 && !capable(answer->capability)) if (answer->capability > 0 && !capable(answer->capability))
goto free_and_badperm; goto out_rcu_unlock;
rc = -EPROTONOSUPPORT;
if (!protocol) if (!protocol)
goto free_and_noproto; goto out_rcu_unlock;
sock->ops = answer->ops; sock->ops = answer->ops;
answer_prot = answer->prot;
answer_no_check = answer->no_check;
answer_flags = answer->flags;
rcu_read_unlock();
BUG_TRAP(answer_prot->slab != NULL);
rc = -ENOBUFS;
sk = sk_alloc(PF_INET6, GFP_KERNEL,
answer_prot->slab_obj_size,
answer_prot->slab);
if (sk == NULL)
goto out;
sock_init_data(sock, sk); sock_init_data(sock, sk);
sk_set_owner(sk, THIS_MODULE); sk_set_owner(sk, THIS_MODULE);
sk->sk_prot = answer->prot; rc = 0;
sk->sk_no_check = answer->no_check; sk->sk_prot = answer_prot;
if (INET_PROTOSW_REUSE & answer->flags) sk->sk_no_check = answer_no_check;
if (INET_PROTOSW_REUSE & answer_flags)
sk->sk_reuse = 1; sk->sk_reuse = 1;
rcu_read_unlock();
inet = inet_sk(sk); inet = inet_sk(sk);
...@@ -248,28 +234,17 @@ static int inet6_create(struct socket *sock, int protocol) ...@@ -248,28 +234,17 @@ static int inet6_create(struct socket *sock, int protocol)
sk->sk_prot->hash(sk); sk->sk_prot->hash(sk);
} }
if (sk->sk_prot->init) { if (sk->sk_prot->init) {
int err = sk->sk_prot->init(sk); rc = sk->sk_prot->init(sk);
if (err != 0) { if (rc) {
sk_common_release(sk); sk_common_release(sk);
return err; goto out;
} }
} }
return 0; out:
return rc;
free_and_badtype: out_rcu_unlock:
rcu_read_unlock();
sk_free(sk);
return -ESOCKTNOSUPPORT;
free_and_badperm:
rcu_read_unlock();
sk_free(sk);
return -EPERM;
free_and_noproto:
rcu_read_unlock(); rcu_read_unlock();
sk_free(sk); goto out;
return -EPROTONOSUPPORT;
do_oom:
return -ENOBUFS;
} }
...@@ -709,24 +684,26 @@ static int __init inet6_init(void) ...@@ -709,24 +684,26 @@ static int __init inet6_init(void)
#endif #endif
#endif #endif
if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)) if (sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)) {
{
printk(KERN_CRIT "inet6_proto_init: size fault\n"); printk(KERN_CRIT "inet6_proto_init: size fault\n");
return -EINVAL; return -EINVAL;
} }
/* allocate our sock slab caches */
tcp6_sk_cachep = kmem_cache_create("tcp6_sock", err = sk_alloc_slab(&tcpv6_prot, "tcpv6_sock");
sizeof(struct tcp6_sock), 0, if (err) {
SLAB_HWCACHE_ALIGN, NULL, NULL); sk_alloc_slab_error(&tcpv6_prot);
udp6_sk_cachep = kmem_cache_create("udp6_sock", goto out;
sizeof(struct udp6_sock), 0, }
SLAB_HWCACHE_ALIGN, NULL, NULL); err = sk_alloc_slab(&udpv6_prot, "udpv6_sock");
raw6_sk_cachep = kmem_cache_create("raw6_sock", if (err) {
sizeof(struct raw6_sock), 0, sk_alloc_slab_error(&udpv6_prot);
SLAB_HWCACHE_ALIGN, NULL, NULL); goto out_tcp_free_slab;
if (!tcp6_sk_cachep || !udp6_sk_cachep || !raw6_sk_cachep) }
printk(KERN_CRIT "%s: Can't create protocol sock SLAB " err = sk_alloc_slab(&rawv6_prot, "rawv6_sock");
"caches!\n", __FUNCTION__); if (err) {
sk_alloc_slab_error(&rawv6_prot);
goto out_udp_free_slab;
}
/* Register the socket-side information for inet6_create. */ /* Register the socket-side information for inet6_create. */
for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
...@@ -745,7 +722,7 @@ static int __init inet6_init(void) ...@@ -745,7 +722,7 @@ static int __init inet6_init(void)
/* Initialise ipv6 mibs */ /* Initialise ipv6 mibs */
err = init_ipv6_mibs(); err = init_ipv6_mibs();
if (err) if (err)
goto init_mib_fail; goto out_raw_free_slab;
/* /*
* ipngwg API draft makes clear that the correct semantics * ipngwg API draft makes clear that the correct semantics
...@@ -798,8 +775,9 @@ static int __init inet6_init(void) ...@@ -798,8 +775,9 @@ static int __init inet6_init(void)
/* Init v6 transport protocols. */ /* Init v6 transport protocols. */
udpv6_init(); udpv6_init();
tcpv6_init(); tcpv6_init();
err = 0;
return 0; out:
return err;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_if6_fail: proc_if6_fail:
...@@ -824,8 +802,13 @@ static int __init inet6_init(void) ...@@ -824,8 +802,13 @@ static int __init inet6_init(void)
ipv6_sysctl_unregister(); ipv6_sysctl_unregister();
#endif #endif
cleanup_ipv6_mibs(); cleanup_ipv6_mibs();
init_mib_fail: out_raw_free_slab:
return err; sk_free_slab(&rawv6_prot);
out_udp_free_slab:
sk_free_slab(&udpv6_prot);
out_tcp_free_slab:
sk_free_slab(&tcpv6_prot);
goto out;
} }
module_init(inet6_init); module_init(inet6_init);
...@@ -854,9 +837,9 @@ static void __exit inet6_exit(void) ...@@ -854,9 +837,9 @@ static void __exit inet6_exit(void)
ipv6_sysctl_unregister(); ipv6_sysctl_unregister();
#endif #endif
cleanup_ipv6_mibs(); cleanup_ipv6_mibs();
kmem_cache_destroy(tcp6_sk_cachep); sk_free_slab(&rawv6_prot);
kmem_cache_destroy(udp6_sk_cachep); sk_free_slab(&udpv6_prot);
kmem_cache_destroy(raw6_sk_cachep); sk_free_slab(&tcpv6_prot);
} }
module_exit(inet6_exit); module_exit(inet6_exit);
......
...@@ -973,6 +973,10 @@ static int rawv6_init_sk(struct sock *sk) ...@@ -973,6 +973,10 @@ static int rawv6_init_sk(struct sock *sk)
return(0); return(0);
} }
struct ipv6_sk_offset raw_sock_offset = {
.offset = offsetof(struct raw6_sock, inet6),
};
struct proto rawv6_prot = { struct proto rawv6_prot = {
.name = "RAW", .name = "RAW",
.close = rawv6_close, .close = rawv6_close,
...@@ -989,6 +993,8 @@ struct proto rawv6_prot = { ...@@ -989,6 +993,8 @@ struct proto rawv6_prot = {
.backlog_rcv = rawv6_rcv_skb, .backlog_rcv = rawv6_rcv_skb,
.hash = raw_v6_hash, .hash = raw_v6_hash,
.unhash = raw_v6_unhash, .unhash = raw_v6_unhash,
.slab_obj_size = sizeof(struct raw6_sock),
.af_specific = &raw_sock_offset,
}; };
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -2119,6 +2119,10 @@ void tcp6_proc_exit(void) ...@@ -2119,6 +2119,10 @@ void tcp6_proc_exit(void)
} }
#endif #endif
struct ipv6_sk_offset tcp_sock_offset = {
.offset = offsetof(struct tcp6_sock, inet6),
};
struct proto tcpv6_prot = { struct proto tcpv6_prot = {
.name = "TCPv6", .name = "TCPv6",
.close = tcp_close, .close = tcp_close,
...@@ -2145,6 +2149,8 @@ struct proto tcpv6_prot = { ...@@ -2145,6 +2149,8 @@ struct proto tcpv6_prot = {
.sysctl_wmem = sysctl_tcp_wmem, .sysctl_wmem = sysctl_tcp_wmem,
.sysctl_rmem = sysctl_tcp_rmem, .sysctl_rmem = sysctl_tcp_rmem,
.max_header = MAX_TCP_HEADER, .max_header = MAX_TCP_HEADER,
.slab_obj_size = sizeof(struct tcp6_sock),
.af_specific = &tcp_sock_offset,
}; };
static struct inet6_protocol tcpv6_protocol = { static struct inet6_protocol tcpv6_protocol = {
......
...@@ -1031,6 +1031,10 @@ void udp6_proc_exit(void) { ...@@ -1031,6 +1031,10 @@ void udp6_proc_exit(void) {
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
struct ipv6_sk_offset udp_sock_offset = {
.offset = offsetof(struct udp6_sock, inet6),
};
struct proto udpv6_prot = { struct proto udpv6_prot = {
.name = "UDP", .name = "UDP",
.close = udpv6_close, .close = udpv6_close,
...@@ -1046,6 +1050,8 @@ struct proto udpv6_prot = { ...@@ -1046,6 +1050,8 @@ struct proto udpv6_prot = {
.hash = udp_v6_hash, .hash = udp_v6_hash,
.unhash = udp_v6_unhash, .unhash = udp_v6_unhash,
.get_port = udp_v6_get_port, .get_port = udp_v6_get_port,
.slab_obj_size = sizeof(struct udp6_sock),
.af_specific = &udp_sock_offset,
}; };
extern struct proto_ops inet6_dgram_ops; extern struct proto_ops inet6_dgram_ops;
......
...@@ -583,8 +583,8 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk, ...@@ -583,8 +583,8 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk,
struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct sctp6_sock *newsctp6sk; struct sctp6_sock *newsctp6sk;
newsk = sk_alloc(PF_INET6, GFP_KERNEL, sizeof(struct sctp6_sock), newsk = sk_alloc(PF_INET6, GFP_KERNEL, sk->sk_prot->slab_obj_size,
sk->sk_slab); sk->sk_prot->slab);
if (!newsk) if (!newsk)
goto out; goto out;
...@@ -892,7 +892,7 @@ static struct proto_ops inet6_seqpacket_ops = { ...@@ -892,7 +892,7 @@ static struct proto_ops inet6_seqpacket_ops = {
static struct inet_protosw sctpv6_seqpacket_protosw = { static struct inet_protosw sctpv6_seqpacket_protosw = {
.type = SOCK_SEQPACKET, .type = SOCK_SEQPACKET,
.protocol = IPPROTO_SCTP, .protocol = IPPROTO_SCTP,
.prot = &sctp_prot, .prot = &sctpv6_prot,
.ops = &inet6_seqpacket_ops, .ops = &inet6_seqpacket_ops,
.capability = -1, .capability = -1,
.no_check = 0, .no_check = 0,
...@@ -901,7 +901,7 @@ static struct inet_protosw sctpv6_seqpacket_protosw = { ...@@ -901,7 +901,7 @@ static struct inet_protosw sctpv6_seqpacket_protosw = {
static struct inet_protosw sctpv6_stream_protosw = { static struct inet_protosw sctpv6_stream_protosw = {
.type = SOCK_STREAM, .type = SOCK_STREAM,
.protocol = IPPROTO_SCTP, .protocol = IPPROTO_SCTP,
.prot = &sctp_prot, .prot = &sctpv6_prot,
.ops = &inet6_seqpacket_ops, .ops = &inet6_seqpacket_ops,
.capability = -1, .capability = -1,
.no_check = 0, .no_check = 0,
...@@ -963,9 +963,14 @@ static struct sctp_pf sctp_pf_inet6_specific = { ...@@ -963,9 +963,14 @@ static struct sctp_pf sctp_pf_inet6_specific = {
/* Initialize IPv6 support and register with inet6 stack. */ /* Initialize IPv6 support and register with inet6 stack. */
int sctp_v6_init(void) int sctp_v6_init(void)
{ {
int rc = sk_alloc_slab(&sctpv6_prot, "sctpv6_sock");
if (rc)
goto out;
/* Register inet6 protocol. */ /* Register inet6 protocol. */
rc = -EAGAIN;
if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0) if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN; goto out_sctp_free_slab;
/* 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);
...@@ -979,8 +984,12 @@ int sctp_v6_init(void) ...@@ -979,8 +984,12 @@ int sctp_v6_init(void)
/* Register notifier for inet6 address additions/deletions. */ /* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier(&sctp_inetaddr_notifier); register_inet6addr_notifier(&sctp_inetaddr_notifier);
rc = 0;
return 0; out:
return rc;
out_sctp_free_slab:
sk_free_slab(&sctpv6_prot);
goto out;
} }
/* IPv6 specific exit support. */ /* IPv6 specific exit support. */
...@@ -991,4 +1000,5 @@ void sctp_v6_exit(void) ...@@ -991,4 +1000,5 @@ void sctp_v6_exit(void)
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_inetaddr_notifier); unregister_inet6addr_notifier(&sctp_inetaddr_notifier);
sk_free_slab(&sctpv6_prot);
} }
...@@ -554,8 +554,8 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk, ...@@ -554,8 +554,8 @@ struct sock *sctp_v4_create_accept_sk(struct sock *sk,
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
struct inet_opt *newinet; struct inet_opt *newinet;
newsk = sk_alloc(PF_INET, GFP_KERNEL, sizeof(struct sctp_sock), newsk = sk_alloc(PF_INET, GFP_KERNEL, sk->sk_prot->slab_obj_size,
sk->sk_slab); sk->sk_prot->slab);
if (!newsk) if (!newsk)
goto out; goto out;
...@@ -962,23 +962,29 @@ static void cleanup_sctp_mibs(void) ...@@ -962,23 +962,29 @@ static void cleanup_sctp_mibs(void)
__init int sctp_init(void) __init int sctp_init(void)
{ {
int i; int i;
int status = 0; int status = -EINVAL;
unsigned long goal; unsigned long goal;
int order; int order;
/* SCTP_DEBUG sanity check. */ /* SCTP_DEBUG sanity check. */
if (!sctp_sanity_check()) if (!sctp_sanity_check())
return -EINVAL; goto out;
status = sk_alloc_slab(&sctp_prot, "sctp_sock");
if (status)
goto out;
/* Add SCTP to inet_protos hash table. */ /* Add SCTP to inet_protos hash table. */
status = -EAGAIN;
if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN; goto err_add_protocol;
/* Add SCTP(TCP and UDP style) to inetsw linked list. */ /* Add SCTP(TCP and UDP style) to inetsw linked list. */
inet_register_protosw(&sctp_seqpacket_protosw); inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw); inet_register_protosw(&sctp_stream_protosw);
/* Allocate a cache pools. */ /* Allocate a cache pools. */
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,
...@@ -1154,8 +1160,11 @@ __init int sctp_init(void) ...@@ -1154,8 +1160,11 @@ __init int sctp_init(void)
sctp_get_local_addr_list(); sctp_get_local_addr_list();
__unsafe(THIS_MODULE); __unsafe(THIS_MODULE);
return 0; status = 0;
out:
return status;
err_add_protocol:
sk_free_slab(&sctp_prot);
err_ctl_sock_init: err_ctl_sock_init:
sctp_v6_exit(); sctp_v6_exit();
err_v6_init: err_v6_init:
...@@ -1183,7 +1192,7 @@ __init int sctp_init(void) ...@@ -1183,7 +1192,7 @@ __init int sctp_init(void)
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_seqpacket_protosw); inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw); inet_unregister_protosw(&sctp_stream_protosw);
return status; goto out;
} }
/* Exit handler for the SCTP protocol. */ /* Exit handler for the SCTP protocol. */
...@@ -1224,6 +1233,7 @@ __exit void sctp_exit(void) ...@@ -1224,6 +1233,7 @@ __exit void sctp_exit(void)
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_seqpacket_protosw); inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw); inet_unregister_protosw(&sctp_stream_protosw);
sk_free_slab(&sctp_prot);
} }
module_init(sctp_init); module_init(sctp_init);
......
...@@ -4622,4 +4622,34 @@ struct proto sctp_prot = { ...@@ -4622,4 +4622,34 @@ struct proto sctp_prot = {
.hash = sctp_hash, .hash = sctp_hash,
.unhash = sctp_unhash, .unhash = sctp_unhash,
.get_port = sctp_get_port, .get_port = sctp_get_port,
.slab_obj_size = sizeof(struct sctp_sock),
}; };
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct ipv6_sk_offset sctp_sock_offset = {
.offset = offsetof(struct sctp6_sock, inet6),
};
struct proto sctpv6_prot = {
.name = "SCTPv6",
.close = sctp_close,
.connect = sctp_connect,
.disconnect = sctp_disconnect,
.accept = sctp_accept,
.ioctl = sctp_ioctl,
.init = sctp_init_sock,
.destroy = sctp_destroy_sock,
.shutdown = sctp_shutdown,
.setsockopt = sctp_setsockopt,
.getsockopt = sctp_getsockopt,
.sendmsg = sctp_sendmsg,
.recvmsg = sctp_recvmsg,
.bind = sctp_bind,
.backlog_rcv = sctp_backlog_rcv,
.hash = sctp_hash,
.unhash = sctp_unhash,
.get_port = sctp_get_port,
.slab_obj_size = sizeof(struct sctp6_sock),
.af_specific = &sctp_sock_offset,
};
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
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