af_unix: Remove CONFIG_UNIX_SCM.
Originally, the code related to garbage collection was all in garbage.c. Commitf4e65870e5
("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 commit97154bcf4d
("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>
This commit is contained in:
parent
11498715f2
commit
99a7a5b994
|
@ -17,19 +17,20 @@ static inline struct unix_sock *unix_get_socket(struct file *filp)
|
|||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t unix_gc_lock;
|
||||
extern unsigned int unix_tot_inflight;
|
||||
|
||||
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 unix_gc(void);
|
||||
void wait_for_unix_gc(struct scm_fp_list *fpl);
|
||||
|
||||
struct sock *unix_peer_get(struct sock *sk);
|
||||
|
||||
#define UNIX_HASH_MOD (256 - 1)
|
||||
#define UNIX_HASH_SIZE (256 * 2)
|
||||
#define UNIX_HASH_BITS 8
|
||||
|
||||
extern unsigned int unix_tot_inflight;
|
||||
|
||||
struct unix_address {
|
||||
refcount_t refcnt;
|
||||
int len;
|
||||
|
|
|
@ -17,7 +17,7 @@ obj-$(CONFIG_NETFILTER) += netfilter/
|
|||
obj-$(CONFIG_INET) += ipv4/
|
||||
obj-$(CONFIG_TLS) += tls/
|
||||
obj-$(CONFIG_XFRM) += xfrm/
|
||||
obj-$(CONFIG_UNIX_SCM) += unix/
|
||||
obj-$(CONFIG_UNIX) += unix/
|
||||
obj-y += ipv6/
|
||||
obj-$(CONFIG_PACKET) += packet/
|
||||
obj-$(CONFIG_NET_KEY) += key/
|
||||
|
|
|
@ -16,11 +16,6 @@ config UNIX
|
|||
|
||||
Say Y unless you know what you are doing.
|
||||
|
||||
config UNIX_SCM
|
||||
bool
|
||||
depends on UNIX
|
||||
default y
|
||||
|
||||
config AF_UNIX_OOB
|
||||
bool
|
||||
depends on UNIX
|
||||
|
|
|
@ -11,5 +11,3 @@ unix-$(CONFIG_BPF_SYSCALL) += unix_bpf.o
|
|||
|
||||
obj-$(CONFIG_UNIX_DIAG) += unix_diag.o
|
||||
unix_diag-y := diag.o
|
||||
|
||||
obj-$(CONFIG_UNIX_SCM) += scm.o
|
||||
|
|
|
@ -118,8 +118,6 @@
|
|||
#include <linux/btf_ids.h>
|
||||
#include <linux/bpf-cgroup.h>
|
||||
|
||||
#include "scm.h"
|
||||
|
||||
static atomic_long_t unix_nr_socks;
|
||||
static struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2];
|
||||
static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2];
|
||||
|
@ -1790,6 +1788,52 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
/* The "user->unix_inflight" variable is protected by the garbage
|
||||
* collection lock, and we just read it locklessly here. If you go
|
||||
* over the limit, there might be a tiny race in actually noticing
|
||||
* it across threads. Tough.
|
||||
*/
|
||||
static inline bool too_many_unix_fds(struct task_struct *p)
|
||||
{
|
||||
struct user_struct *user = current_user();
|
||||
|
||||
if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE)))
|
||||
return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (too_many_unix_fds(current))
|
||||
return -ETOOMANYREFS;
|
||||
|
||||
/* Need to duplicate file references for the sake of garbage
|
||||
* collection. Otherwise a socket in the fps might become a
|
||||
* candidate for GC while the skb is not yet queued.
|
||||
*/
|
||||
UNIXCB(skb).fp = scm_fp_dup(scm->fp);
|
||||
if (!UNIXCB(skb).fp)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = scm->fp->count - 1; i >= 0; i--)
|
||||
unix_inflight(scm->fp->user, scm->fp->fp[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
|
||||
scm->fp = UNIXCB(skb).fp;
|
||||
UNIXCB(skb).fp = NULL;
|
||||
|
||||
for (i = scm->fp->count - 1; i >= 0; i--)
|
||||
unix_notinflight(scm->fp->user, scm->fp->fp[i]);
|
||||
}
|
||||
|
||||
static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
{
|
||||
scm->fp = scm_fp_dup(UNIXCB(skb).fp);
|
||||
|
@ -1837,6 +1881,21 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
|||
spin_unlock(&unix_gc_lock);
|
||||
}
|
||||
|
||||
static void unix_destruct_scm(struct sk_buff *skb)
|
||||
{
|
||||
struct scm_cookie scm;
|
||||
|
||||
memset(&scm, 0, sizeof(scm));
|
||||
scm.pid = UNIXCB(skb).pid;
|
||||
if (UNIXCB(skb).fp)
|
||||
unix_detach_fds(&scm, skb);
|
||||
|
||||
/* Alas, it calls VFS */
|
||||
/* So fscking what? fput() had been SMP-safe since the last Summer */
|
||||
scm_destroy(&scm);
|
||||
sock_wfree(skb);
|
||||
}
|
||||
|
||||
static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
|
||||
{
|
||||
int err = 0;
|
||||
|
|
|
@ -81,11 +81,80 @@
|
|||
#include <net/scm.h>
|
||||
#include <net/tcp_states.h>
|
||||
|
||||
#include "scm.h"
|
||||
struct unix_sock *unix_get_socket(struct file *filp)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
|
||||
/* Internal data structures and random procedures: */
|
||||
/* Socket ? */
|
||||
if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
|
||||
struct socket *sock = SOCKET_I(inode);
|
||||
const struct proto_ops *ops;
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
ops = READ_ONCE(sock->ops);
|
||||
|
||||
/* PF_UNIX ? */
|
||||
if (sk && ops && ops->family == PF_UNIX)
|
||||
return unix_sk(sk);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_SPINLOCK(unix_gc_lock);
|
||||
unsigned int unix_tot_inflight;
|
||||
static LIST_HEAD(gc_candidates);
|
||||
static LIST_HEAD(gc_inflight_list);
|
||||
|
||||
/* Keep the number of times in flight count for the file
|
||||
* descriptor if it is for an AF_UNIX socket.
|
||||
*/
|
||||
void unix_inflight(struct user_struct *user, struct file *filp)
|
||||
{
|
||||
struct unix_sock *u = unix_get_socket(filp);
|
||||
|
||||
spin_lock(&unix_gc_lock);
|
||||
|
||||
if (u) {
|
||||
if (!u->inflight) {
|
||||
WARN_ON_ONCE(!list_empty(&u->link));
|
||||
list_add_tail(&u->link, &gc_inflight_list);
|
||||
} else {
|
||||
WARN_ON_ONCE(list_empty(&u->link));
|
||||
}
|
||||
u->inflight++;
|
||||
|
||||
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
||||
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1);
|
||||
}
|
||||
|
||||
WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1);
|
||||
|
||||
spin_unlock(&unix_gc_lock);
|
||||
}
|
||||
|
||||
void unix_notinflight(struct user_struct *user, struct file *filp)
|
||||
{
|
||||
struct unix_sock *u = unix_get_socket(filp);
|
||||
|
||||
spin_lock(&unix_gc_lock);
|
||||
|
||||
if (u) {
|
||||
WARN_ON_ONCE(!u->inflight);
|
||||
WARN_ON_ONCE(list_empty(&u->link));
|
||||
|
||||
u->inflight--;
|
||||
if (!u->inflight)
|
||||
list_del_init(&u->link);
|
||||
|
||||
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
||||
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1);
|
||||
}
|
||||
|
||||
WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1);
|
||||
|
||||
spin_unlock(&unix_gc_lock);
|
||||
}
|
||||
|
||||
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
|
||||
struct sk_buff_head *hitlist)
|
||||
|
|
150
net/unix/scm.c
150
net/unix/scm.c
|
@ -1,150 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/fs.h>
|
||||
#include <net/af_unix.h>
|
||||
#include <net/scm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io_uring.h>
|
||||
|
||||
#include "scm.h"
|
||||
|
||||
unsigned int unix_tot_inflight;
|
||||
EXPORT_SYMBOL(unix_tot_inflight);
|
||||
|
||||
LIST_HEAD(gc_inflight_list);
|
||||
EXPORT_SYMBOL(gc_inflight_list);
|
||||
|
||||
DEFINE_SPINLOCK(unix_gc_lock);
|
||||
EXPORT_SYMBOL(unix_gc_lock);
|
||||
|
||||
struct unix_sock *unix_get_socket(struct file *filp)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
|
||||
/* Socket ? */
|
||||
if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
|
||||
struct socket *sock = SOCKET_I(inode);
|
||||
const struct proto_ops *ops = READ_ONCE(sock->ops);
|
||||
struct sock *s = sock->sk;
|
||||
|
||||
/* PF_UNIX ? */
|
||||
if (s && ops && ops->family == PF_UNIX)
|
||||
return unix_sk(s);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(unix_get_socket);
|
||||
|
||||
/* Keep the number of times in flight count for the file
|
||||
* descriptor if it is for an AF_UNIX socket.
|
||||
*/
|
||||
void unix_inflight(struct user_struct *user, struct file *fp)
|
||||
{
|
||||
struct unix_sock *u = unix_get_socket(fp);
|
||||
|
||||
spin_lock(&unix_gc_lock);
|
||||
|
||||
if (u) {
|
||||
if (!u->inflight) {
|
||||
WARN_ON_ONCE(!list_empty(&u->link));
|
||||
list_add_tail(&u->link, &gc_inflight_list);
|
||||
} else {
|
||||
WARN_ON_ONCE(list_empty(&u->link));
|
||||
}
|
||||
u->inflight++;
|
||||
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
||||
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1);
|
||||
}
|
||||
WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1);
|
||||
spin_unlock(&unix_gc_lock);
|
||||
}
|
||||
|
||||
void unix_notinflight(struct user_struct *user, struct file *fp)
|
||||
{
|
||||
struct unix_sock *u = unix_get_socket(fp);
|
||||
|
||||
spin_lock(&unix_gc_lock);
|
||||
|
||||
if (u) {
|
||||
WARN_ON_ONCE(!u->inflight);
|
||||
WARN_ON_ONCE(list_empty(&u->link));
|
||||
|
||||
u->inflight--;
|
||||
if (!u->inflight)
|
||||
list_del_init(&u->link);
|
||||
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
||||
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1);
|
||||
}
|
||||
WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1);
|
||||
spin_unlock(&unix_gc_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* The "user->unix_inflight" variable is protected by the garbage
|
||||
* collection lock, and we just read it locklessly here. If you go
|
||||
* over the limit, there might be a tiny race in actually noticing
|
||||
* it across threads. Tough.
|
||||
*/
|
||||
static inline bool too_many_unix_fds(struct task_struct *p)
|
||||
{
|
||||
struct user_struct *user = current_user();
|
||||
|
||||
if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE)))
|
||||
return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
|
||||
return false;
|
||||
}
|
||||
|
||||
int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (too_many_unix_fds(current))
|
||||
return -ETOOMANYREFS;
|
||||
|
||||
/*
|
||||
* Need to duplicate file references for the sake of garbage
|
||||
* collection. Otherwise a socket in the fps might become a
|
||||
* candidate for GC while the skb is not yet queued.
|
||||
*/
|
||||
UNIXCB(skb).fp = scm_fp_dup(scm->fp);
|
||||
if (!UNIXCB(skb).fp)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = scm->fp->count - 1; i >= 0; i--)
|
||||
unix_inflight(scm->fp->user, scm->fp->fp[i]);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(unix_attach_fds);
|
||||
|
||||
void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
|
||||
scm->fp = UNIXCB(skb).fp;
|
||||
UNIXCB(skb).fp = NULL;
|
||||
|
||||
for (i = scm->fp->count-1; i >= 0; i--)
|
||||
unix_notinflight(scm->fp->user, scm->fp->fp[i]);
|
||||
}
|
||||
EXPORT_SYMBOL(unix_detach_fds);
|
||||
|
||||
void unix_destruct_scm(struct sk_buff *skb)
|
||||
{
|
||||
struct scm_cookie scm;
|
||||
|
||||
memset(&scm, 0, sizeof(scm));
|
||||
scm.pid = UNIXCB(skb).pid;
|
||||
if (UNIXCB(skb).fp)
|
||||
unix_detach_fds(&scm, skb);
|
||||
|
||||
/* Alas, it calls VFS */
|
||||
/* So fscking what? fput() had been SMP-safe since the last Summer */
|
||||
scm_destroy(&scm);
|
||||
sock_wfree(skb);
|
||||
}
|
||||
EXPORT_SYMBOL(unix_destruct_scm);
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef NET_UNIX_SCM_H
|
||||
#define NET_UNIX_SCM_H
|
||||
|
||||
extern struct list_head gc_inflight_list;
|
||||
extern spinlock_t unix_gc_lock;
|
||||
|
||||
int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb);
|
||||
void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue