Skip to contentSkip to conversation

generalise per socket slab cache use

PATCH In review Arnaldo Carvalho de Melo 3 participants 4 messages Sep 11, 2004 – Sep 13, 2004

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 generalise per socket slab cache use

Hi,

Please see if it is acceptable, if it is, please pull from:

bk://kernel.bkbits.net/acme/net-2.6

I want to improve it a bit by not passing the slab cache name to
sk_alloc_slab, but create the name from the sk->sk_prot->name member, but unfortunately the kmem_cache_t struct stores a pointer to the slab cache name, which also creates problems for other improvements, like my __initstr patch, that moves the strings in __init and __exit functions to .text.init and .text.exit, perhaps I should send a patch to the slab code to have a char array to store the slab cache name.

Comments?

Best Regards,

- Arnaldo

You can import this changeset into BK by piping this whole message to:
'| bk receive [path to repository]' or apply the patch as usual.

===================================================================

[email protected], 2004-09-11 00:02:02-03:00, [email protected]
[NET] generalise per socket slab cache use

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 :
 include/linux/ipv6.h     |    4 +
 include/net/raw.h        |    1 
 include/net/sctp/sctp.h  |    1 
 include/net/sock.h       |    7 ++
 include/net/tcp.h        |    3 
 net/core/sock.c          |   21 ++++++
 net/ipv4/af_inet.c       |  103 ++++++++++++++------------------
 net/ipv4/raw.c           |    1 
 net/ipv4/tcp_ipv4.c      |    1 
 net/ipv4/tcp_minisocks.c |    2 
 net/ipv4/udp.c           |    1 
 net/ipv6/af_inet6.c      |  151 +++++++++++++++++++----------------------------
 net/ipv6/raw.c           |    6 +
 net/ipv6/tcp_ipv6.c      |    6 +
 net/ipv6/udp.c           |    6 +
 net/sctp/ipv6.c          |   24 +++++--
 net/sctp/protocol.c      |   26 +++++---
 net/sctp/socket.c        |   30 +++++++++
 18 files changed, 231 insertions(+), 163 deletions(-)
include/linux/ipv6.h +4 -0
diff -Nru a/include/linux/ipv6.h b/include/linux/ipv6.h
@@ -282,6 +282,10 @@
 	return &((struct raw6_sock *)__sk)->raw6;
 }
 
+struct ipv6_sk_offset {
+	int	offset;
+};
+
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 #define __ipv6_only_sock(sk)	(inet6_sk(sk)->ipv6only)
 #define ipv6_only_sock(sk)	((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk))
include/net/raw.h +0 -1
diff -Nru a/include/net/raw.h b/include/net/raw.h
@@ -17,7 +17,6 @@
 #ifndef _RAW_H
 #define _RAW_H
 
-
 extern struct proto raw_prot;
 
 
include/net/sctp/sctp.h +1 -0
diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
@@ -505,6 +505,7 @@
 /* External references. */
 
 extern struct proto sctp_prot;
+extern struct proto sctpv6_prot;
 extern struct proc_dir_entry *proc_net_sctp;
 void sctp_put_port(struct sock *sk);
 
include/net/sock.h +7 -0
diff -Nru a/include/net/sock.h b/include/net/sock.h
@@ -410,6 +410,9 @@
 	return test_bit(flag, &sk->sk_flags);
 }
 
+extern int sk_alloc_slab(struct proto *prot, char *name);
+extern void sk_free_slab(struct proto *prot);
+
 static inline void sk_acceptq_removed(struct sock *sk)
 {
 	sk->sk_ack_backlog--;
@@ -554,6 +557,10 @@
 	int			*sysctl_wmem;
 	int			*sysctl_rmem;
 	int			max_header;
+
+	kmem_cache_t		*slab;
+	int			slab_obj_size;
+	void			*af_specific;
 
 	char			name[32];
 
include/net/tcp.h +0 -3
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
@@ -153,9 +153,6 @@
 #define tcp_lhash_wait	(tcp_hashinfo.__tcp_lhash_wait)
 #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 struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
 						 unsigned short snum);
net/core/sock.c +21 -0
diff -Nru a/net/core/sock.c b/net/core/sock.c
@@ -1343,6 +1343,27 @@
 
 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(__release_sock);
 EXPORT_SYMBOL(sk_alloc);
net/ipv4/af_inet.c +47 -56

160 lines not on this page · raw message

net/ipv4/raw.c +1 -0
diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c
@@ -719,6 +719,7 @@
 	.backlog_rcv =	raw_rcv_skb,
 	.hash =		raw_v4_hash,
 	.unhash =	raw_v4_unhash,
+	.slab_obj_size = sizeof(struct raw_sock),
 };
 
 #ifdef CONFIG_PROC_FS
net/ipv4/tcp_ipv4.c +1 -0
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
@@ -2617,6 +2617,7 @@
 	.sysctl_wmem		= sysctl_tcp_wmem,
 	.sysctl_rmem		= sysctl_tcp_rmem,
 	.max_header		= MAX_TCP_HEADER,
+	.slab_obj_size		= sizeof(struct tcp_sock),
 };
 
 
net/ipv4/tcp_minisocks.c +1 -1
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
@@ -687,7 +687,7 @@
 	/* 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
 	 * 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) {
 		struct tcp_opt *newtp;
net/ipv4/udp.c +1 -0
diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c
@@ -1320,6 +1320,7 @@
 	.hash =		udp_v4_hash,
 	.unhash =	udp_v4_unhash,
 	.get_port =	udp_v4_get_port,
+	.slab_obj_size = sizeof(struct udp_sock),
 };
 
 /* ------------------------------------------------------------------------ */
net/ipv6/af_inet6.c +64 -87

229 lines not on this page · raw message

net/ipv6/raw.c +6 -0
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
@@ -973,6 +973,10 @@
 	return(0);
 }
 
+struct ipv6_sk_offset raw_sock_offset = {
+	.offset = offsetof(struct udp6_sock, inet6),
+};
+
 struct proto rawv6_prot = {
 	.name =		"RAW",
 	.close =	rawv6_close,
@@ -989,6 +993,8 @@
 	.backlog_rcv =	rawv6_rcv_skb,
 	.hash =		raw_v6_hash,
 	.unhash =	raw_v6_unhash,
+	.slab_obj_size = sizeof(struct raw6_sock),
+	.af_specific =	&raw_sock_offset,
 };
 
 #ifdef CONFIG_PROC_FS
net/ipv6/tcp_ipv6.c +6 -0
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
@@ -2119,6 +2119,10 @@
 }
 #endif
 
+struct ipv6_sk_offset tcp_sock_offset = {
+	.offset = offsetof(struct tcp6_sock, inet6),
+};
+
 struct proto tcpv6_prot = {
 	.name			= "TCPv6",
 	.close			= tcp_close,
@@ -2145,6 +2149,8 @@
 	.sysctl_wmem		= sysctl_tcp_wmem,
 	.sysctl_rmem		= sysctl_tcp_rmem,
 	.max_header		= MAX_TCP_HEADER,
+	.slab_obj_size		= sizeof(struct tcp6_sock),
+	.af_specific		= &tcp_sock_offset,
 };
 
 static struct inet6_protocol tcpv6_protocol = {
net/ipv6/udp.c +6 -0
diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c
@@ -1031,6 +1031,10 @@
 
 /* ------------------------------------------------------------------------ */
 
+struct ipv6_sk_offset udp_sock_offset = {
+	.offset = offsetof(struct udp6_sock, inet6),
+};
+
 struct proto udpv6_prot = {
 	.name =		"UDP",
 	.close =	udpv6_close,
@@ -1046,6 +1050,8 @@
 	.hash =		udp_v6_hash,
 	.unhash =	udp_v6_unhash,
 	.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;
net/sctp/ipv6.c +17 -7
diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c
@@ -583,8 +583,8 @@
 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
 	struct sctp6_sock *newsctp6sk;
 
-	newsk = sk_alloc(PF_INET6, GFP_KERNEL, sizeof(struct sctp6_sock),
-			 sk->sk_slab);
+	newsk = sk_alloc(PF_INET6, GFP_KERNEL, sk->sk_prot->slab_obj_size,
+			 sk->sk_prot->slab);
 	if (!newsk)
 		goto out;
 
@@ -892,7 +892,7 @@
 static struct inet_protosw sctpv6_seqpacket_protosw = {
 	.type          = SOCK_SEQPACKET,
 	.protocol      = IPPROTO_SCTP,
-	.prot 	       = &sctp_prot,
+	.prot 	       = &sctpv6_prot,
 	.ops           = &inet6_seqpacket_ops,
 	.capability    = -1,
 	.no_check      = 0,
@@ -901,7 +901,7 @@
 static struct inet_protosw sctpv6_stream_protosw = {
 	.type          = SOCK_STREAM,
 	.protocol      = IPPROTO_SCTP,
-	.prot 	       = &sctp_prot,
+	.prot 	       = &sctpv6_prot,
 	.ops           = &inet6_seqpacket_ops,
 	.capability    = -1,
 	.no_check      = 0,
@@ -963,9 +963,14 @@
 /* Initialize IPv6 support and register with inet6 stack.  */
 int sctp_v6_init(void)
 {
+	int rc = sk_alloc_slab(&sctpv6_prot, "sctpv6_sock");
+
+	if (rc)
+		goto out;
 	/* Register inet6 protocol. */
+	rc = -EAGAIN;
 	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. */
 	inet6_register_protosw(&sctpv6_seqpacket_protosw);
@@ -979,8 +984,12 @@
 
 	/* Register notifier for inet6 address additions/deletions. */
 	register_inet6addr_notifier(&sctp_inetaddr_notifier);
-
-	return 0;
+	rc = 0;
+out:
+	return rc;
+out_sctp_free_slab:
+	sk_free_slab(&sctpv6_prot);
+	goto out;
 }
 
 /* IPv6 specific exit support. */
@@ -991,4 +1000,5 @@
 	inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
 	inet6_unregister_protosw(&sctpv6_stream_protosw);
 	unregister_inet6addr_notifier(&sctp_inetaddr_notifier);
+	sk_free_slab(&sctpv6_prot);
 }
net/sctp/protocol.c +18 -8
diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c
@@ -554,8 +554,8 @@
 	struct inet_opt *inet = inet_sk(sk);
 	struct inet_opt *newinet;
 
-	newsk = sk_alloc(PF_INET, GFP_KERNEL, sizeof(struct sctp_sock),
-			 sk->sk_slab);
+	newsk = sk_alloc(PF_INET, GFP_KERNEL, sk->sk_prot->slab_obj_size,
+			 sk->sk_prot->slab);
 	if (!newsk)
 		goto out;
 
@@ -962,23 +962,29 @@
 __init int sctp_init(void)
 {
 	int i;
-	int status = 0;
+	int status = -EINVAL;
 	unsigned long goal;
 	int order;
 
 	/* SCTP_DEBUG 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.  */
+	status = -EAGAIN;
 	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.  */
 	inet_register_protosw(&sctp_seqpacket_protosw);
 	inet_register_protosw(&sctp_stream_protosw);
 
 	/* Allocate a cache pools. */
+	status = -ENOBUFS;
 	sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
 					       sizeof(struct sctp_bind_bucket),
 					       0, SLAB_HWCACHE_ALIGN,
@@ -1154,8 +1160,11 @@
 	sctp_get_local_addr_list();
 
 	__unsafe(THIS_MODULE);
-	return 0;
-
+	status = 0;
+out:
+	return status;
+err_add_protocol:
+	sk_free_slab(&sctp_prot);
 err_ctl_sock_init:
 	sctp_v6_exit();
 err_v6_init:
@@ -1183,7 +1192,7 @@
 	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 	inet_unregister_protosw(&sctp_seqpacket_protosw);
 	inet_unregister_protosw(&sctp_stream_protosw);
-	return status;
+	goto out;
 }
 
 /* Exit handler for the SCTP protocol.  */
@@ -1224,6 +1233,7 @@
 	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
 	inet_unregister_protosw(&sctp_seqpacket_protosw);
 	inet_unregister_protosw(&sctp_stream_protosw);
+	sk_free_slab(&sctp_prot);
 }
 
 module_init(sctp_init);
net/sctp/socket.c +30 -0
diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c
@@ -4622,4 +4622,34 @@
 	.hash        =	sctp_hash,
 	.unhash      =	sctp_unhash,
 	.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) */
#1 lore raw

Arnaldo,

looks good, but i have a few comments. It is great that SCTP now has its own slabcaches.

net/ipv6/raw.c line 978

Quoted 3 lines
net/ipv6/raw.c +3 -0
+struct ipv6_sk_offset raw_sock_offset = {
+     .offset = offsetof(struct udp6_sock, inet6),
+};

I think there is a typo here. udp6_sock should be raw6_sock

net/ipv6/af_inet6.c line 729

Quoted 2 lines
net/ipv6/af_inet6.c +0 -2
-                printk(KERN_CRIT "%s: Can't create protocol sock SLAB "
-                    "caches!\n", __FUNCTION__);

You have removed the above critical messages. Is this by intent or a mistake.

I am not clear on why we need this new structure ipv6_sk_offset.

include/linux/ipv6.h line 288

Quoted 4 lines
include/linux/ipv6.h +4 -0
+struct ipv6_sk_offset {
+     int     offset;
+};
+

Instead of adding the new field void *af_specific to struct proto, is it not sufficient to add

        int     pinet6_offset;

and assign it as follows for each v6 sock type
.pinet6_offset = offsetof(struct struct tcp6_sock, inet6)

In inet6_sk_generic(), you can directly use sk->sk_prot->pinet6_offset.

Thanks
Sridhar

#2 lore raw

Em Seg 13 Set 2004 18:17, Sridhar Samudrala escreveu:

Quoted 10 lines

Arnaldo,

looks good, but i have a few comments. It is great that SCTP now has its own slabcaches.

net/ipv6/raw.c line 978

Quoted 3 lines
net/ipv6/raw.c +3 -0
+struct ipv6_sk_offset raw_sock_offset = {
+     .offset = offsetof(struct udp6_sock, inet6),
+};

I think there is a typo here. udp6_sock should be raw6_sock

Good spotting! I'll fix this one

Quoted 5 lines

net/ipv6/af_inet6.c line 729

Quoted 2 lines
net/ipv6/af_inet6.c +0 -2
-                printk(KERN_CRIT "%s: Can't create protocol sock SLAB "
-                    "caches!\n", __FUNCTION__);

You have removed the above critical messages. Is this by intent or a mistake.

Humm, I'll put it on the sk_alloc_slab callers

Quoted 10 lines

I am not clear on why we need this new structure ipv6_sk_offset.

include/linux/ipv6.h line 288

Quoted 4 lines
include/linux/ipv6.h +4 -0
+struct ipv6_sk_offset {
+     int     offset;
+};
+

Instead of adding the new field void *af_specific to struct proto, is it not sufficient to add

Quoted 6 lines
        int     pinet6_offset;

and assign it as follows for each v6 sock type
.pinet6_offset = offsetof(struct struct tcp6_sock, inet6)

In inet6_sk_generic(), you can directly use sk->sk_prot->pinet6_offset.

I thought about it, but idea was to not introduce any family specific stuff in struct proto, I don't plan to have LLC over IPv6, for instance :)

Quoted 2 lines

Thanks
Sridhar

maintainer
#3 lore raw
Quoted 3 lines · On Mon, 13 Sep 2004 18:51:08 -0300 Arnaldo Carvalho de Melo…
Quoted 1 line

I think there is a typo here. udp6_sock should be raw6_sock

Good spotting! I'll fix this one

Let me know when the fixed version is available, thanks. :)