Skip to content

Commit 1002e86

Browse files
q2vengregkh
authored andcommitted
af_unix: Allocate struct unix_vertex for each inflight AF_UNIX fd.
commit 1fbfdfaa590248c1d86407f578e40e5c65136330 upstream. We will replace the garbage collection algorithm for AF_UNIX, where we will consider each inflight AF_UNIX socket as a vertex and its file descriptor as an edge in a directed graph. This patch introduces a new struct unix_vertex representing a vertex in the graph and adds its pointer to struct unix_sock. When we send a fd using the SCM_RIGHTS message, we allocate struct scm_fp_list to struct scm_cookie in scm_fp_copy(). Then, we bump each refcount of the inflight fds' struct file and save them in scm_fp_list.fp. After that, unix_attach_fds() inexplicably clones scm_fp_list of scm_cookie and sets it to skb. (We will remove this part after replacing GC.) Here, we add a new function call in unix_attach_fds() to preallocate struct unix_vertex per inflight AF_UNIX fd and link each vertex to skb's scm_fp_list.vertices. When sendmsg() succeeds later, if the socket of the inflight fd is still not inflight yet, we will set the preallocated vertex to struct unix_sock.vertex and link it to a global list unix_unvisited_vertices under spin_lock(&unix_gc_lock). If the socket is already inflight, we free the preallocated vertex. This is to avoid taking the lock unnecessarily when sendmsg() could fail later. In the following patch, we will similarly allocate another struct per edge, which will finally be linked to the inflight socket's unix_vertex.edges. And then, we will count the number of edges as unix_vertex.out_degree. Signed-off-by: Kuniyuki Iwashima <[email protected]> Acked-by: Paolo Abeni <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Lee Jones <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 44aebf5 commit 1002e86

File tree

5 files changed

+63
-0
lines changed

5 files changed

+63
-0
lines changed

include/net/af_unix.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@ extern unsigned int unix_tot_inflight;
2222

2323
void unix_inflight(struct user_struct *user, struct file *fp);
2424
void unix_notinflight(struct user_struct *user, struct file *fp);
25+
int unix_prepare_fpl(struct scm_fp_list *fpl);
26+
void unix_destroy_fpl(struct scm_fp_list *fpl);
2527
void unix_gc(void);
2628
void wait_for_unix_gc(struct scm_fp_list *fpl);
2729

30+
struct unix_vertex {
31+
struct list_head edges;
32+
struct list_head entry;
33+
unsigned long out_degree;
34+
};
35+
2836
struct sock *unix_peer_get(struct sock *sk);
2937

3038
#define UNIX_HASH_MOD (256 - 1)
@@ -62,6 +70,7 @@ struct unix_sock {
6270
struct path path;
6371
struct mutex iolock, bindlock;
6472
struct sock *peer;
73+
struct unix_vertex *vertex;
6574
struct list_head link;
6675
unsigned long inflight;
6776
spinlock_t lock;

include/net/scm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ struct scm_fp_list {
2525
short count;
2626
short count_unix;
2727
short max;
28+
#ifdef CONFIG_UNIX
29+
struct list_head vertices;
30+
#endif
2831
struct user_struct *user;
2932
struct file *fp[SCM_MAX_FD];
3033
};

net/core/scm.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
8989
fpl->count_unix = 0;
9090
fpl->max = SCM_MAX_FD;
9191
fpl->user = NULL;
92+
#if IS_ENABLED(CONFIG_UNIX)
93+
INIT_LIST_HEAD(&fpl->vertices);
94+
#endif
9295
}
9396
fpp = &fpl->fp[fpl->count];
9497

@@ -372,8 +375,12 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
372375
if (new_fpl) {
373376
for (i = 0; i < fpl->count; i++)
374377
get_file(fpl->fp[i]);
378+
375379
new_fpl->max = new_fpl->count;
376380
new_fpl->user = get_uid(fpl->user);
381+
#if IS_ENABLED(CONFIG_UNIX)
382+
INIT_LIST_HEAD(&new_fpl->vertices);
383+
#endif
377384
}
378385
return new_fpl;
379386
}

net/unix/af_unix.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,
955955
sk->sk_destruct = unix_sock_destructor;
956956
u = unix_sk(sk);
957957
u->inflight = 0;
958+
u->vertex = NULL;
958959
u->path.dentry = NULL;
959960
u->path.mnt = NULL;
960961
spin_lock_init(&u->lock);
@@ -1756,6 +1757,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
17561757
for (i = scm->fp->count - 1; i >= 0; i--)
17571758
unix_inflight(scm->fp->user, scm->fp->fp[i]);
17581759

1760+
if (unix_prepare_fpl(UNIXCB(skb).fp))
1761+
return -ENOMEM;
1762+
17591763
return 0;
17601764
}
17611765

@@ -1766,6 +1770,8 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
17661770
scm->fp = UNIXCB(skb).fp;
17671771
UNIXCB(skb).fp = NULL;
17681772

1773+
unix_destroy_fpl(scm->fp);
1774+
17691775
for (i = scm->fp->count - 1; i >= 0; i--)
17701776
unix_notinflight(scm->fp->user, scm->fp->fp[i]);
17711777
}

net/unix/garbage.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,44 @@ struct unix_sock *unix_get_socket(struct file *filp)
101101
return NULL;
102102
}
103103

104+
static void unix_free_vertices(struct scm_fp_list *fpl)
105+
{
106+
struct unix_vertex *vertex, *next_vertex;
107+
108+
list_for_each_entry_safe(vertex, next_vertex, &fpl->vertices, entry) {
109+
list_del(&vertex->entry);
110+
kfree(vertex);
111+
}
112+
}
113+
114+
int unix_prepare_fpl(struct scm_fp_list *fpl)
115+
{
116+
struct unix_vertex *vertex;
117+
int i;
118+
119+
if (!fpl->count_unix)
120+
return 0;
121+
122+
for (i = 0; i < fpl->count_unix; i++) {
123+
vertex = kmalloc(sizeof(*vertex), GFP_KERNEL);
124+
if (!vertex)
125+
goto err;
126+
127+
list_add(&vertex->entry, &fpl->vertices);
128+
}
129+
130+
return 0;
131+
132+
err:
133+
unix_free_vertices(fpl);
134+
return -ENOMEM;
135+
}
136+
137+
void unix_destroy_fpl(struct scm_fp_list *fpl)
138+
{
139+
unix_free_vertices(fpl);
140+
}
141+
104142
DEFINE_SPINLOCK(unix_gc_lock);
105143
unsigned int unix_tot_inflight;
106144
static LIST_HEAD(gc_candidates);

0 commit comments

Comments
 (0)