Patch "af_unix: Try to run GC async." has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    af_unix: Try to run GC async.

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     af_unix-try-to-run-gc-async.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 6f82fb6e3831ba0424dd146e087553b9bfbe294b
Author: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx>
Date:   Tue Jan 23 09:08:56 2024 -0800

    af_unix: Try to run GC async.
    
    [ Upstream commit d9f21b3613337b55cc9d4a6ead484dca68475143 ]
    
    If more than 16000 inflight AF_UNIX sockets exist and the garbage
    collector is not running, unix_(dgram|stream)_sendmsg() call unix_gc().
    Also, they wait for unix_gc() to complete.
    
    In unix_gc(), all inflight AF_UNIX sockets are traversed at least once,
    and more if they are the GC candidate.  Thus, sendmsg() significantly
    slows down with too many inflight AF_UNIX sockets.
    
    However, if a process sends data with no AF_UNIX FD, the sendmsg() call
    does not need to wait for GC.  After this change, only the process that
    meets the condition below will be blocked under such a situation.
    
      1) cmsg contains AF_UNIX socket
      2) more than 32 AF_UNIX sent by the same user are still inflight
    
    Note that even a sendmsg() call that does not meet the condition but has
    AF_UNIX FD will be blocked later in unix_scm_to_skb() by the spinlock,
    but we allow that as a bonus for sane users.
    
    The results below are the time spent in unix_dgram_sendmsg() sending 1
    byte of data with no FD 4096 times on a host where 32K inflight AF_UNIX
    sockets exist.
    
    Without series: the sane sendmsg() needs to wait gc unreasonably.
    
      $ sudo /usr/share/bcc/tools/funclatency -p 11165 unix_dgram_sendmsg
      Tracing 1 functions for "unix_dgram_sendmsg"... Hit Ctrl-C to end.
      ^C
           nsecs               : count     distribution
      [...]
          524288 -> 1048575    : 0        |                                        |
         1048576 -> 2097151    : 3881     |****************************************|
         2097152 -> 4194303    : 214      |**                                      |
         4194304 -> 8388607    : 1        |                                        |
    
      avg = 1825567 nsecs, total: 7477526027 nsecs, count: 4096
    
    With series: the sane sendmsg() can finish much faster.
    
      $ sudo /usr/share/bcc/tools/funclatency -p 8702  unix_dgram_sendmsg
      Tracing 1 functions for "unix_dgram_sendmsg"... Hit Ctrl-C to end.
      ^C
           nsecs               : count     distribution
      [...]
             128 -> 255        : 0        |                                        |
             256 -> 511        : 4092     |****************************************|
             512 -> 1023       : 2        |                                        |
            1024 -> 2047       : 0        |                                        |
            2048 -> 4095       : 0        |                                        |
            4096 -> 8191       : 1        |                                        |
            8192 -> 16383      : 1        |                                        |
    
      avg = 410 nsecs, total: 1680510 nsecs, count: 4096
    
    Signed-off-by: Kuniyuki Iwashima <kuniyu@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20240123170856.41348-6-kuniyu@xxxxxxxxxx
    Signed-off-by: Jakub Kicinski <kuba@xxxxxxxxxx>
    Stable-dep-of: 1b536948e805 ("af_unix: Annotate data-race of sk->sk_state in unix_accept().")
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 7a00d7ed527b6..865e2f7bd67cf 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -8,13 +8,21 @@
 #include <linux/refcount.h>
 #include <net/sock.h>
 
+#if IS_ENABLED(CONFIG_UNIX)
+struct unix_sock *unix_get_socket(struct file *filp);
+#else
+static inline struct unix_sock *unix_get_socket(struct file *filp)
+{
+	return NULL;
+}
+#endif
+
 void unix_inflight(struct user_struct *user, struct file *fp);
 void unix_notinflight(struct user_struct *user, struct file *fp);
 void unix_destruct_scm(struct sk_buff *skb);
 void io_uring_destruct_scm(struct sk_buff *skb);
 void unix_gc(void);
-void wait_for_unix_gc(void);
-struct unix_sock *unix_get_socket(struct file *filp);
+void wait_for_unix_gc(struct scm_fp_list *fpl);
 struct sock *unix_peer_get(struct sock *sk);
 
 #define UNIX_HASH_MOD	(256 - 1)
diff --git a/include/net/scm.h b/include/net/scm.h
index e8c76b4be2fe7..1ff6a28550644 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -24,6 +24,7 @@ struct scm_creds {
 
 struct scm_fp_list {
 	short			count;
+	short			count_unix;
 	short			max;
 	struct user_struct	*user;
 	struct file		*fp[SCM_MAX_FD];
diff --git a/net/core/scm.c b/net/core/scm.c
index 737917c7ac627..574607b1c2d96 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -36,6 +36,7 @@
 #include <net/compat.h>
 #include <net/scm.h>
 #include <net/cls_cgroup.h>
+#include <net/af_unix.h>
 
 
 /*
@@ -85,6 +86,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 			return -ENOMEM;
 		*fplp = fpl;
 		fpl->count = 0;
+		fpl->count_unix = 0;
 		fpl->max = SCM_MAX_FD;
 		fpl->user = NULL;
 	}
@@ -109,6 +111,9 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
 			fput(file);
 			return -EINVAL;
 		}
+		if (unix_get_socket(file))
+			fpl->count_unix++;
+
 		*fpp++ = file;
 		fpl->count++;
 	}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e6395647558af..868f5332566c7 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1908,11 +1908,12 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
 	long timeo;
 	int err;
 
-	wait_for_unix_gc();
 	err = scm_send(sock, msg, &scm, false);
 	if (err < 0)
 		return err;
 
+	wait_for_unix_gc(scm.fp);
+
 	err = -EOPNOTSUPP;
 	if (msg->msg_flags&MSG_OOB)
 		goto out;
@@ -2180,11 +2181,12 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
 	bool fds_sent = false;
 	int data_len;
 
-	wait_for_unix_gc();
 	err = scm_send(sock, msg, &scm, false);
 	if (err < 0)
 		return err;
 
+	wait_for_unix_gc(scm.fp);
+
 	err = -EOPNOTSUPP;
 	if (msg->msg_flags & MSG_OOB) {
 #if IS_ENABLED(CONFIG_AF_UNIX_OOB)
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index a2a8543613a52..96cc6b7674333 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -335,8 +335,9 @@ void unix_gc(void)
 }
 
 #define UNIX_INFLIGHT_TRIGGER_GC 16000
+#define UNIX_INFLIGHT_SANE_USER (SCM_MAX_FD * 8)
 
-void wait_for_unix_gc(void)
+void wait_for_unix_gc(struct scm_fp_list *fpl)
 {
 	/* If number of inflight sockets is insane,
 	 * force a garbage collect right now.
@@ -348,6 +349,13 @@ void wait_for_unix_gc(void)
 	    !READ_ONCE(gc_in_progress))
 		unix_gc();
 
+	/* Penalise users who want to send AF_UNIX sockets
+	 * but whose sockets have not been received yet.
+	 */
+	if (!fpl || !fpl->count_unix ||
+	    READ_ONCE(fpl->user->unix_inflight) < UNIX_INFLIGHT_SANE_USER)
+		return;
+
 	if (READ_ONCE(gc_in_progress))
 		flush_work(&unix_gc_work);
 }




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux