Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

af_unix: Remove CONFIG_UNIX_SCM.

Originally, the code related to garbage collection was all in garbage.c.

Commit f4e65870e5ce ("net: split out functions related to registering
inflight socket files") moved some functions to scm.c for io_uring and
added CONFIG_UNIX_SCM just in case AF_UNIX was built as module.

However, since commit 97154bcf4d1b ("af_unix: Kconfig: make CONFIG_UNIX
bool"), AF_UNIX is no longer built separately. Also, io_uring does not
support SCM_RIGHTS now.

Let's move the functions back to garbage.c

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Acked-by: Jens Axboe <axboe@kernel.dk>
Link: https://lore.kernel.org/r/20240129190435.57228-4-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
99a7a5b9 11498715

+137 -175
+4 -3
include/net/af_unix.h
··· 17 17 } 18 18 #endif 19 19 20 + extern spinlock_t unix_gc_lock; 21 + extern unsigned int unix_tot_inflight; 22 + 20 23 void unix_inflight(struct user_struct *user, struct file *fp); 21 24 void unix_notinflight(struct user_struct *user, struct file *fp); 22 - void unix_destruct_scm(struct sk_buff *skb); 23 25 void unix_gc(void); 24 26 void wait_for_unix_gc(struct scm_fp_list *fpl); 27 + 25 28 struct sock *unix_peer_get(struct sock *sk); 26 29 27 30 #define UNIX_HASH_MOD (256 - 1) 28 31 #define UNIX_HASH_SIZE (256 * 2) 29 32 #define UNIX_HASH_BITS 8 30 - 31 - extern unsigned int unix_tot_inflight; 32 33 33 34 struct unix_address { 34 35 refcount_t refcnt;
+1 -1
net/Makefile
··· 17 17 obj-$(CONFIG_INET) += ipv4/ 18 18 obj-$(CONFIG_TLS) += tls/ 19 19 obj-$(CONFIG_XFRM) += xfrm/ 20 - obj-$(CONFIG_UNIX_SCM) += unix/ 20 + obj-$(CONFIG_UNIX) += unix/ 21 21 obj-y += ipv6/ 22 22 obj-$(CONFIG_PACKET) += packet/ 23 23 obj-$(CONFIG_NET_KEY) += key/
-5
net/unix/Kconfig
··· 16 16 17 17 Say Y unless you know what you are doing. 18 18 19 - config UNIX_SCM 20 - bool 21 - depends on UNIX 22 - default y 23 - 24 19 config AF_UNIX_OOB 25 20 bool 26 21 depends on UNIX
-2
net/unix/Makefile
··· 11 11 12 12 obj-$(CONFIG_UNIX_DIAG) += unix_diag.o 13 13 unix_diag-y := diag.o 14 - 15 - obj-$(CONFIG_UNIX_SCM) += scm.o
+61 -2
net/unix/af_unix.c
··· 118 118 #include <linux/btf_ids.h> 119 119 #include <linux/bpf-cgroup.h> 120 120 121 - #include "scm.h" 122 - 123 121 static atomic_long_t unix_nr_socks; 124 122 static struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2]; 125 123 static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2]; ··· 1788 1790 return err; 1789 1791 } 1790 1792 1793 + /* The "user->unix_inflight" variable is protected by the garbage 1794 + * collection lock, and we just read it locklessly here. If you go 1795 + * over the limit, there might be a tiny race in actually noticing 1796 + * it across threads. Tough. 1797 + */ 1798 + static inline bool too_many_unix_fds(struct task_struct *p) 1799 + { 1800 + struct user_struct *user = current_user(); 1801 + 1802 + if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) 1803 + return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); 1804 + return false; 1805 + } 1806 + 1807 + static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) 1808 + { 1809 + int i; 1810 + 1811 + if (too_many_unix_fds(current)) 1812 + return -ETOOMANYREFS; 1813 + 1814 + /* Need to duplicate file references for the sake of garbage 1815 + * collection. Otherwise a socket in the fps might become a 1816 + * candidate for GC while the skb is not yet queued. 1817 + */ 1818 + UNIXCB(skb).fp = scm_fp_dup(scm->fp); 1819 + if (!UNIXCB(skb).fp) 1820 + return -ENOMEM; 1821 + 1822 + for (i = scm->fp->count - 1; i >= 0; i--) 1823 + unix_inflight(scm->fp->user, scm->fp->fp[i]); 1824 + 1825 + return 0; 1826 + } 1827 + 1828 + static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) 1829 + { 1830 + int i; 1831 + 1832 + scm->fp = UNIXCB(skb).fp; 1833 + UNIXCB(skb).fp = NULL; 1834 + 1835 + for (i = scm->fp->count - 1; i >= 0; i--) 1836 + unix_notinflight(scm->fp->user, scm->fp->fp[i]); 1837 + } 1838 + 1791 1839 static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb) 1792 1840 { 1793 1841 scm->fp = scm_fp_dup(UNIXCB(skb).fp); ··· 1879 1835 */ 1880 1836 spin_lock(&unix_gc_lock); 1881 1837 spin_unlock(&unix_gc_lock); 1838 + } 1839 + 1840 + static void unix_destruct_scm(struct sk_buff *skb) 1841 + { 1842 + struct scm_cookie scm; 1843 + 1844 + memset(&scm, 0, sizeof(scm)); 1845 + scm.pid = UNIXCB(skb).pid; 1846 + if (UNIXCB(skb).fp) 1847 + unix_detach_fds(&scm, skb); 1848 + 1849 + /* Alas, it calls VFS */ 1850 + /* So fscking what? fput() had been SMP-safe since the last Summer */ 1851 + scm_destroy(&scm); 1852 + sock_wfree(skb); 1882 1853 } 1883 1854 1884 1855 static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
+71 -2
net/unix/garbage.c
··· 81 81 #include <net/scm.h> 82 82 #include <net/tcp_states.h> 83 83 84 - #include "scm.h" 84 + struct unix_sock *unix_get_socket(struct file *filp) 85 + { 86 + struct inode *inode = file_inode(filp); 85 87 86 - /* Internal data structures and random procedures: */ 88 + /* Socket ? */ 89 + if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { 90 + struct socket *sock = SOCKET_I(inode); 91 + const struct proto_ops *ops; 92 + struct sock *sk = sock->sk; 87 93 94 + ops = READ_ONCE(sock->ops); 95 + 96 + /* PF_UNIX ? */ 97 + if (sk && ops && ops->family == PF_UNIX) 98 + return unix_sk(sk); 99 + } 100 + 101 + return NULL; 102 + } 103 + 104 + DEFINE_SPINLOCK(unix_gc_lock); 105 + unsigned int unix_tot_inflight; 88 106 static LIST_HEAD(gc_candidates); 107 + static LIST_HEAD(gc_inflight_list); 108 + 109 + /* Keep the number of times in flight count for the file 110 + * descriptor if it is for an AF_UNIX socket. 111 + */ 112 + void unix_inflight(struct user_struct *user, struct file *filp) 113 + { 114 + struct unix_sock *u = unix_get_socket(filp); 115 + 116 + spin_lock(&unix_gc_lock); 117 + 118 + if (u) { 119 + if (!u->inflight) { 120 + WARN_ON_ONCE(!list_empty(&u->link)); 121 + list_add_tail(&u->link, &gc_inflight_list); 122 + } else { 123 + WARN_ON_ONCE(list_empty(&u->link)); 124 + } 125 + u->inflight++; 126 + 127 + /* Paired with READ_ONCE() in wait_for_unix_gc() */ 128 + WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); 129 + } 130 + 131 + WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1); 132 + 133 + spin_unlock(&unix_gc_lock); 134 + } 135 + 136 + void unix_notinflight(struct user_struct *user, struct file *filp) 137 + { 138 + struct unix_sock *u = unix_get_socket(filp); 139 + 140 + spin_lock(&unix_gc_lock); 141 + 142 + if (u) { 143 + WARN_ON_ONCE(!u->inflight); 144 + WARN_ON_ONCE(list_empty(&u->link)); 145 + 146 + u->inflight--; 147 + if (!u->inflight) 148 + list_del_init(&u->link); 149 + 150 + /* Paired with READ_ONCE() in wait_for_unix_gc() */ 151 + WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); 152 + } 153 + 154 + WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1); 155 + 156 + spin_unlock(&unix_gc_lock); 157 + } 89 158 90 159 static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *), 91 160 struct sk_buff_head *hitlist)
-150
net/unix/scm.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - #include <linux/module.h> 3 - #include <linux/kernel.h> 4 - #include <linux/string.h> 5 - #include <linux/socket.h> 6 - #include <linux/net.h> 7 - #include <linux/fs.h> 8 - #include <net/af_unix.h> 9 - #include <net/scm.h> 10 - #include <linux/init.h> 11 - #include <linux/io_uring.h> 12 - 13 - #include "scm.h" 14 - 15 - unsigned int unix_tot_inflight; 16 - EXPORT_SYMBOL(unix_tot_inflight); 17 - 18 - LIST_HEAD(gc_inflight_list); 19 - EXPORT_SYMBOL(gc_inflight_list); 20 - 21 - DEFINE_SPINLOCK(unix_gc_lock); 22 - EXPORT_SYMBOL(unix_gc_lock); 23 - 24 - struct unix_sock *unix_get_socket(struct file *filp) 25 - { 26 - struct inode *inode = file_inode(filp); 27 - 28 - /* Socket ? */ 29 - if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) { 30 - struct socket *sock = SOCKET_I(inode); 31 - const struct proto_ops *ops = READ_ONCE(sock->ops); 32 - struct sock *s = sock->sk; 33 - 34 - /* PF_UNIX ? */ 35 - if (s && ops && ops->family == PF_UNIX) 36 - return unix_sk(s); 37 - } 38 - 39 - return NULL; 40 - } 41 - EXPORT_SYMBOL(unix_get_socket); 42 - 43 - /* Keep the number of times in flight count for the file 44 - * descriptor if it is for an AF_UNIX socket. 45 - */ 46 - void unix_inflight(struct user_struct *user, struct file *fp) 47 - { 48 - struct unix_sock *u = unix_get_socket(fp); 49 - 50 - spin_lock(&unix_gc_lock); 51 - 52 - if (u) { 53 - if (!u->inflight) { 54 - WARN_ON_ONCE(!list_empty(&u->link)); 55 - list_add_tail(&u->link, &gc_inflight_list); 56 - } else { 57 - WARN_ON_ONCE(list_empty(&u->link)); 58 - } 59 - u->inflight++; 60 - /* Paired with READ_ONCE() in wait_for_unix_gc() */ 61 - WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1); 62 - } 63 - WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1); 64 - spin_unlock(&unix_gc_lock); 65 - } 66 - 67 - void unix_notinflight(struct user_struct *user, struct file *fp) 68 - { 69 - struct unix_sock *u = unix_get_socket(fp); 70 - 71 - spin_lock(&unix_gc_lock); 72 - 73 - if (u) { 74 - WARN_ON_ONCE(!u->inflight); 75 - WARN_ON_ONCE(list_empty(&u->link)); 76 - 77 - u->inflight--; 78 - if (!u->inflight) 79 - list_del_init(&u->link); 80 - /* Paired with READ_ONCE() in wait_for_unix_gc() */ 81 - WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1); 82 - } 83 - WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1); 84 - spin_unlock(&unix_gc_lock); 85 - } 86 - 87 - /* 88 - * The "user->unix_inflight" variable is protected by the garbage 89 - * collection lock, and we just read it locklessly here. If you go 90 - * over the limit, there might be a tiny race in actually noticing 91 - * it across threads. Tough. 92 - */ 93 - static inline bool too_many_unix_fds(struct task_struct *p) 94 - { 95 - struct user_struct *user = current_user(); 96 - 97 - if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE))) 98 - return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN); 99 - return false; 100 - } 101 - 102 - int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) 103 - { 104 - int i; 105 - 106 - if (too_many_unix_fds(current)) 107 - return -ETOOMANYREFS; 108 - 109 - /* 110 - * Need to duplicate file references for the sake of garbage 111 - * collection. Otherwise a socket in the fps might become a 112 - * candidate for GC while the skb is not yet queued. 113 - */ 114 - UNIXCB(skb).fp = scm_fp_dup(scm->fp); 115 - if (!UNIXCB(skb).fp) 116 - return -ENOMEM; 117 - 118 - for (i = scm->fp->count - 1; i >= 0; i--) 119 - unix_inflight(scm->fp->user, scm->fp->fp[i]); 120 - return 0; 121 - } 122 - EXPORT_SYMBOL(unix_attach_fds); 123 - 124 - void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) 125 - { 126 - int i; 127 - 128 - scm->fp = UNIXCB(skb).fp; 129 - UNIXCB(skb).fp = NULL; 130 - 131 - for (i = scm->fp->count-1; i >= 0; i--) 132 - unix_notinflight(scm->fp->user, scm->fp->fp[i]); 133 - } 134 - EXPORT_SYMBOL(unix_detach_fds); 135 - 136 - void unix_destruct_scm(struct sk_buff *skb) 137 - { 138 - struct scm_cookie scm; 139 - 140 - memset(&scm, 0, sizeof(scm)); 141 - scm.pid = UNIXCB(skb).pid; 142 - if (UNIXCB(skb).fp) 143 - unix_detach_fds(&scm, skb); 144 - 145 - /* Alas, it calls VFS */ 146 - /* So fscking what? fput() had been SMP-safe since the last Summer */ 147 - scm_destroy(&scm); 148 - sock_wfree(skb); 149 - } 150 - EXPORT_SYMBOL(unix_destruct_scm);
-10
net/unix/scm.h
··· 1 - #ifndef NET_UNIX_SCM_H 2 - #define NET_UNIX_SCM_H 3 - 4 - extern struct list_head gc_inflight_list; 5 - extern spinlock_t unix_gc_lock; 6 - 7 - int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb); 8 - void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb); 9 - 10 - #endif