[PATCH net-next] af_unix: dont send SCM_CREDENTIALS by default
flat view
STALE5501d
From: Eric Dumazet <hidden>
Date: 2011-09-09 05:06:26
Subsystem:
networking [general], networking [sockets], networking [unix sockets], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Kuniyuki Iwashima, Willem de Bruijn, Linus Torvalds
Le jeudi 08 septembre 2011 à 02:24 -0700, Tim Chen a écrit :
Looking forward to the patch. This should improve the scalability of af_unix.
Here it is, based on top on previous one [af_unix: Fix use-after-free
crashes]
Thanks
[PATCH net-next] af_unix: dont send SCM_CREDENTIALS by default
Since commit 7361c36c5224 (af_unix: Allow credentials to work across
user and pid namespaces) af_unix performance dropped a lot.
This is because we now take a reference on pid and cred in each write(),
and release them in read(), usually done from another process,
eventually from another cpu. This triggers false sharing.
# Events: 154K cycles
#
# Overhead Command Shared Object Symbol
# ........ ....... .................. ...................................
#
10.40% hackbench [kernel.kallsyms] [k] put_pid
8.60% hackbench [kernel.kallsyms] [k] unix_stream_recvmsg
7.87% hackbench [kernel.kallsyms] [k] unix_stream_sendmsg
6.11% hackbench [kernel.kallsyms] [k] do_raw_spin_lock
4.95% hackbench [kernel.kallsyms] [k] unix_scm_to_skb
4.87% hackbench [kernel.kallsyms] [k] pid_nr_ns
4.34% hackbench [kernel.kallsyms] [k] cred_to_ucred
2.39% hackbench [kernel.kallsyms] [k] unix_destruct_scm
2.24% hackbench [kernel.kallsyms] [k] sub_preempt_count
1.75% hackbench [kernel.kallsyms] [k] fget_light
1.51% hackbench [kernel.kallsyms] [k] __mutex_lock_interruptible_slowpath
1.42% hackbench [kernel.kallsyms] [k] sock_alloc_send_pskb
This patch includes SCM_CREDENTIALS information in a af_unix message/skb
only if requested by the sender, [man 7 unix for details how to include
ancillary data using sendmsg() system call]
Note: This might break buggy applications that expected SCM_CREDENTIAL
from an unaware write() system call.
Performance boost in hackbench : more than 50% gain on a 16 thread
machine (2 quad-core cpus, 2 threads per core)
hackbench 20 thread 2000
4.224 sec instead of 9.102 sec
Signed-off-by: Eric Dumazet <redacted>
---
include/net/scm.h | 11 +----------
net/core/scm.c | 10 ++++++----
net/netlink/af_netlink.c | 5 ++---
net/unix/af_unix.c | 9 +++++----
4 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/include/net/scm.h b/include/net/scm.h
index 2a5b42f..74c8fdc 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h@@ -45,14 +45,6 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co { } #endif /* CONFIG_SECURITY_NETWORK */ -static __inline__ void scm_set_cred(struct scm_cookie *scm, - struct pid *pid, const struct cred *cred) -{ - scm->pid = get_pid(pid); - scm->cred = get_cred(cred); - cred_to_ucred(pid, cred, &scm->creds); -} - static __inline__ void scm_set_cred_noref(struct scm_cookie *scm, struct pid *pid, const struct cred *cred) {
@@ -81,8 +73,7 @@ static __inline__ void scm_destroy(struct scm_cookie *scm) static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) { - scm_set_cred(scm, task_tgid(current), current_cred()); - scm->fp = NULL; + memset(scm, 0, sizeof(*scm)); unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) return 0;
diff --git a/net/core/scm.c b/net/core/scm.c
index 811b53f..ff52ad0 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c@@ -173,7 +173,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) if (err) goto error; - if (pid_vnr(p->pid) != p->creds.pid) { + if (!p->pid || pid_vnr(p->pid) != p->creds.pid) { struct pid *pid; err = -ESRCH; pid = find_get_pid(p->creds.pid);
@@ -183,8 +183,9 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) p->pid = pid; } - if ((p->cred->euid != p->creds.uid) || - (p->cred->egid != p->creds.gid)) { + if (!p->cred || + (p->cred->euid != p->creds.uid) || + (p->cred->egid != p->creds.gid)) { struct cred *cred; err = -ENOMEM; cred = prepare_creds();
@@ -193,7 +194,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) cred->uid = cred->euid = p->creds.uid; cred->gid = cred->egid = p->creds.gid; - put_cred(p->cred); + if (p->cred) + put_cred(p->cred); p->cred = cred; } break;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 4330db9..1201b6d 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c@@ -1324,10 +1324,9 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, if (msg->msg_flags&MSG_OOB) return -EOPNOTSUPP; - if (NULL == siocb->scm) { + if (NULL == siocb->scm) siocb->scm = &scm; - memset(&scm, 0, sizeof(scm)); - } + err = scm_send(sock, msg, siocb->scm); if (err < 0) return err;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c8a08ba..4c77385 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c@@ -1383,12 +1383,13 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, { int err = 0; + UNIXCB(skb).pid = scm->pid; + UNIXCB(skb).cred = scm->cred; if (!steal_refs) { - UNIXCB(skb).pid = get_pid(scm->pid); - UNIXCB(skb).cred = get_cred(scm->cred); + get_pid(scm->pid); + if (scm->cred) + get_cred(scm->cred); } else { - UNIXCB(skb).pid = scm->pid; - UNIXCB(skb).cred = scm->cred; scm->pid = NULL; scm->cred = NULL; }