Skip to content

Commit fd86344

Browse files
q2venPaolo Abeni
authored andcommitted
af_unix: Try not to hold unix_gc_lock during accept().
Commit dcf70df ("af_unix: Fix up unix_edge.successor for embryo socket.") added spin_lock(&unix_gc_lock) in accept() path, and it caused regression in a stress test as reported by kernel test robot. If the embryo socket is not part of the inflight graph, we need not hold the lock. To decide that in O(1) time and avoid the regression in the normal use case, 1. add a new stat unix_sk(sk)->scm_stat.nr_unix_fds 2. count the number of inflight AF_UNIX sockets in the receive queue under unix_state_lock() 3. move unix_update_edges() call under unix_state_lock() 4. avoid locking if nr_unix_fds is 0 in unix_update_edges() Reported-by: kernel test robot <[email protected]> Closes: https://lore.kernel.org/oe-lkp/[email protected] Signed-off-by: Kuniyuki Iwashima <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent e918c7b commit fd86344

File tree

3 files changed

+18
-5
lines changed

3 files changed

+18
-5
lines changed

include/net/af_unix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct unix_skb_parms {
6767

6868
struct scm_stat {
6969
atomic_t nr_fds;
70+
unsigned long nr_unix_fds;
7071
};
7172

7273
#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))

net/unix/af_unix.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1719,12 +1719,12 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags,
17191719
}
17201720

17211721
tsk = skb->sk;
1722-
unix_update_edges(unix_sk(tsk));
17231722
skb_free_datagram(sk, skb);
17241723
wake_up_interruptible(&unix_sk(sk)->peer_wait);
17251724

17261725
/* attach accepted sock to socket */
17271726
unix_state_lock(tsk);
1727+
unix_update_edges(unix_sk(tsk));
17281728
newsock->state = SS_CONNECTED;
17291729
unix_sock_inherit_flags(sock, newsock);
17301730
sock_graft(tsk, newsock);

net/unix/garbage.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ void unix_add_edges(struct scm_fp_list *fpl, struct unix_sock *receiver)
209209
unix_add_edge(fpl, edge);
210210
} while (i < fpl->count_unix);
211211

212+
receiver->scm_stat.nr_unix_fds += fpl->count_unix;
212213
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + fpl->count_unix);
213214
out:
214215
WRITE_ONCE(fpl->user->unix_inflight, fpl->user->unix_inflight + fpl->count);
@@ -222,6 +223,7 @@ void unix_add_edges(struct scm_fp_list *fpl, struct unix_sock *receiver)
222223

223224
void unix_del_edges(struct scm_fp_list *fpl)
224225
{
226+
struct unix_sock *receiver;
225227
int i = 0;
226228

227229
spin_lock(&unix_gc_lock);
@@ -235,6 +237,8 @@ void unix_del_edges(struct scm_fp_list *fpl)
235237
unix_del_edge(fpl, edge);
236238
} while (i < fpl->count_unix);
237239

240+
receiver = fpl->edges[0].successor;
241+
receiver->scm_stat.nr_unix_fds -= fpl->count_unix;
238242
WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - fpl->count_unix);
239243
out:
240244
WRITE_ONCE(fpl->user->unix_inflight, fpl->user->unix_inflight - fpl->count);
@@ -246,10 +250,18 @@ void unix_del_edges(struct scm_fp_list *fpl)
246250

247251
void unix_update_edges(struct unix_sock *receiver)
248252
{
249-
spin_lock(&unix_gc_lock);
250-
unix_update_graph(unix_sk(receiver->listener)->vertex);
251-
receiver->listener = NULL;
252-
spin_unlock(&unix_gc_lock);
253+
/* nr_unix_fds is only updated under unix_state_lock().
254+
* If it's 0 here, the embryo socket is not part of the
255+
* inflight graph, and GC will not see it, so no lock needed.
256+
*/
257+
if (!receiver->scm_stat.nr_unix_fds) {
258+
receiver->listener = NULL;
259+
} else {
260+
spin_lock(&unix_gc_lock);
261+
unix_update_graph(unix_sk(receiver->listener)->vertex);
262+
receiver->listener = NULL;
263+
spin_unlock(&unix_gc_lock);
264+
}
253265
}
254266

255267
int unix_prepare_fpl(struct scm_fp_list *fpl)

0 commit comments

Comments
 (0)