Skip to content

Commit 1fd05ba

Browse files
Miklos Szeredidavem330
authored andcommitted
[AF_UNIX]: Rewrite garbage collector, fixes race.
Throw out the old mark & sweep garbage collector and put in a refcounting cycle detecting one. The old one had a race with recvmsg, that resulted in false positives and hence data loss. The old algorithm operated on all unix sockets in the system, so any additional locking would have meant performance problems for all users of these. The new algorithm instead only operates on "in flight" sockets, which are very rare, and the additional locking for these doesn't negatively impact the vast majority of users. In fact it's probable, that there weren't *any* heavy senders of sockets over sockets, otherwise the above race would have been discovered long ago. The patch works OK with the app that exposed the race with the old code. The garbage collection has also been verified to work in a few simple cases. Signed-off-by: Miklos Szeredi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 99d24ed commit 1fd05ba

File tree

3 files changed

+190
-144
lines changed

3 files changed

+190
-144
lines changed

include/net/af_unix.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ struct unix_sock {
7979
struct mutex readlock;
8080
struct sock *peer;
8181
struct sock *other;
82-
struct sock *gc_tree;
82+
struct list_head link;
8383
atomic_t inflight;
8484
spinlock_t lock;
85+
unsigned int gc_candidate : 1;
8586
wait_queue_head_t peer_wait;
8687
};
8788
#define unix_sk(__sk) ((struct unix_sock *)__sk)

net/unix/af_unix.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,8 @@ static struct sock * unix_create1(struct socket *sock)
592592
u->dentry = NULL;
593593
u->mnt = NULL;
594594
spin_lock_init(&u->lock);
595-
atomic_set(&u->inflight, sock ? 0 : -1);
595+
atomic_set(&u->inflight, 0);
596+
INIT_LIST_HEAD(&u->link);
596597
mutex_init(&u->readlock); /* single task reading lock */
597598
init_waitqueue_head(&u->peer_wait);
598599
unix_insert_socket(unix_sockets_unbound, sk);
@@ -1134,9 +1135,6 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
11341135
/* take ten and and send info to listening sock */
11351136
spin_lock(&other->sk_receive_queue.lock);
11361137
__skb_queue_tail(&other->sk_receive_queue, skb);
1137-
/* Undo artificially decreased inflight after embrion
1138-
* is installed to listening socket. */
1139-
atomic_inc(&newu->inflight);
11401138
spin_unlock(&other->sk_receive_queue.lock);
11411139
unix_state_unlock(other);
11421140
other->sk_data_ready(other, 0);

0 commit comments

Comments
 (0)