af_unix: Do not use atomic ops for unix_sk(sk)->inflight.
[ Upstream commit 97af84a6bba2ab2b9c704c08e67de3b5ea551bb2 ] When touching unix_sk(sk)->inflight, we are always under spin_lock(&unix_gc_lock). Let's convert unix_sk(sk)->inflight to the normal unsigned long. Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://lore.kernel.org/r/20240123170856.41348-3-kuniyu@amazon.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: 47d8ac011fe1 ("af_unix: Fix garbage collector racing against connect()") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
19643bf8c9
commit
fb6d14e23d
@ -54,7 +54,7 @@ struct unix_sock {
|
|||||||
struct mutex iolock, bindlock;
|
struct mutex iolock, bindlock;
|
||||||
struct sock *peer;
|
struct sock *peer;
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
atomic_long_t inflight;
|
unsigned long inflight;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
unsigned long gc_flags;
|
unsigned long gc_flags;
|
||||||
#define UNIX_GC_CANDIDATE 0
|
#define UNIX_GC_CANDIDATE 0
|
||||||
|
@ -968,11 +968,11 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,
|
|||||||
sk->sk_write_space = unix_write_space;
|
sk->sk_write_space = unix_write_space;
|
||||||
sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen;
|
sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen;
|
||||||
sk->sk_destruct = unix_sock_destructor;
|
sk->sk_destruct = unix_sock_destructor;
|
||||||
u = unix_sk(sk);
|
u = unix_sk(sk);
|
||||||
|
u->inflight = 0;
|
||||||
u->path.dentry = NULL;
|
u->path.dentry = NULL;
|
||||||
u->path.mnt = NULL;
|
u->path.mnt = NULL;
|
||||||
spin_lock_init(&u->lock);
|
spin_lock_init(&u->lock);
|
||||||
atomic_long_set(&u->inflight, 0);
|
|
||||||
INIT_LIST_HEAD(&u->link);
|
INIT_LIST_HEAD(&u->link);
|
||||||
mutex_init(&u->iolock); /* single task reading lock */
|
mutex_init(&u->iolock); /* single task reading lock */
|
||||||
mutex_init(&u->bindlock); /* single task binding lock */
|
mutex_init(&u->bindlock); /* single task binding lock */
|
||||||
|
@ -166,17 +166,18 @@ static void scan_children(struct sock *x, void (*func)(struct unix_sock *),
|
|||||||
|
|
||||||
static void dec_inflight(struct unix_sock *usk)
|
static void dec_inflight(struct unix_sock *usk)
|
||||||
{
|
{
|
||||||
atomic_long_dec(&usk->inflight);
|
usk->inflight--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inc_inflight(struct unix_sock *usk)
|
static void inc_inflight(struct unix_sock *usk)
|
||||||
{
|
{
|
||||||
atomic_long_inc(&usk->inflight);
|
usk->inflight++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inc_inflight_move_tail(struct unix_sock *u)
|
static void inc_inflight_move_tail(struct unix_sock *u)
|
||||||
{
|
{
|
||||||
atomic_long_inc(&u->inflight);
|
u->inflight++;
|
||||||
|
|
||||||
/* If this still might be part of a cycle, move it to the end
|
/* If this still might be part of a cycle, move it to the end
|
||||||
* of the list, so that it's checked even if it was already
|
* of the list, so that it's checked even if it was already
|
||||||
* passed over
|
* passed over
|
||||||
@ -237,14 +238,12 @@ void unix_gc(void)
|
|||||||
*/
|
*/
|
||||||
list_for_each_entry_safe(u, next, &gc_inflight_list, link) {
|
list_for_each_entry_safe(u, next, &gc_inflight_list, link) {
|
||||||
long total_refs;
|
long total_refs;
|
||||||
long inflight_refs;
|
|
||||||
|
|
||||||
total_refs = file_count(u->sk.sk_socket->file);
|
total_refs = file_count(u->sk.sk_socket->file);
|
||||||
inflight_refs = atomic_long_read(&u->inflight);
|
|
||||||
|
|
||||||
BUG_ON(inflight_refs < 1);
|
BUG_ON(!u->inflight);
|
||||||
BUG_ON(total_refs < inflight_refs);
|
BUG_ON(total_refs < u->inflight);
|
||||||
if (total_refs == inflight_refs) {
|
if (total_refs == u->inflight) {
|
||||||
list_move_tail(&u->link, &gc_candidates);
|
list_move_tail(&u->link, &gc_candidates);
|
||||||
__set_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
|
__set_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
|
||||||
__set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
|
__set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
|
||||||
@ -271,7 +270,7 @@ void unix_gc(void)
|
|||||||
/* Move cursor to after the current position. */
|
/* Move cursor to after the current position. */
|
||||||
list_move(&cursor, &u->link);
|
list_move(&cursor, &u->link);
|
||||||
|
|
||||||
if (atomic_long_read(&u->inflight) > 0) {
|
if (u->inflight) {
|
||||||
list_move_tail(&u->link, ¬_cycle_list);
|
list_move_tail(&u->link, ¬_cycle_list);
|
||||||
__clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
|
__clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
|
||||||
scan_children(&u->sk, inc_inflight_move_tail, NULL);
|
scan_children(&u->sk, inc_inflight_move_tail, NULL);
|
||||||
|
@ -52,12 +52,13 @@ void unix_inflight(struct user_struct *user, struct file *fp)
|
|||||||
if (s) {
|
if (s) {
|
||||||
struct unix_sock *u = unix_sk(s);
|
struct unix_sock *u = unix_sk(s);
|
||||||
|
|
||||||
if (atomic_long_inc_return(&u->inflight) == 1) {
|
if (!u->inflight) {
|
||||||
BUG_ON(!list_empty(&u->link));
|
BUG_ON(!list_empty(&u->link));
|
||||||
list_add_tail(&u->link, &gc_inflight_list);
|
list_add_tail(&u->link, &gc_inflight_list);
|
||||||
} else {
|
} else {
|
||||||
BUG_ON(list_empty(&u->link));
|
BUG_ON(list_empty(&u->link));
|
||||||
}
|
}
|
||||||
|
u->inflight++;
|
||||||
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
||||||
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1);
|
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1);
|
||||||
}
|
}
|
||||||
@ -74,10 +75,11 @@ void unix_notinflight(struct user_struct *user, struct file *fp)
|
|||||||
if (s) {
|
if (s) {
|
||||||
struct unix_sock *u = unix_sk(s);
|
struct unix_sock *u = unix_sk(s);
|
||||||
|
|
||||||
BUG_ON(!atomic_long_read(&u->inflight));
|
BUG_ON(!u->inflight);
|
||||||
BUG_ON(list_empty(&u->link));
|
BUG_ON(list_empty(&u->link));
|
||||||
|
|
||||||
if (atomic_long_dec_and_test(&u->inflight))
|
u->inflight--;
|
||||||
|
if (!u->inflight)
|
||||||
list_del_init(&u->link);
|
list_del_init(&u->link);
|
||||||
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
/* Paired with READ_ONCE() in wait_for_unix_gc() */
|
||||||
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1);
|
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user