Skip to content

Commit ba31b4a

Browse files
q2venkuba-moo
authored andcommitted
af_unix: Save O(n) setup of Tarjan's algo.
Before starting Tarjan's algorithm, we need to mark all vertices as unvisited. We can save this O(n) setup by reserving two special indices (0, 1) and using two variables. The first time we link a vertex to unix_unvisited_vertices, we set unix_vertex_unvisited_index to index. During DFS, we can see that the index of unvisited vertices is the same as unix_vertex_unvisited_index. When we finalise SCC later, we set unix_vertex_grouped_index to each vertex's index. Then, we can know (i) that the vertex is on the stack if the index of a visited vertex is >= 2 and (ii) that it is not on the stack and belongs to a different SCC if the index is unix_vertex_grouped_index. After the whole algorithm, all indices of vertices are set as unix_vertex_grouped_index. Next time we start DFS, we know that all unvisited vertices have unix_vertex_grouped_index, and we can use unix_vertex_unvisited_index as the not-on-stack marker. To use the same variable in __unix_walk_scc(), we can swap unix_vertex_(grouped|unvisited)_index at the end of Tarjan's algorithm. 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]>
1 parent dcf70df commit ba31b4a

File tree

2 files changed

+15
-12
lines changed

2 files changed

+15
-12
lines changed

include/net/af_unix.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ struct unix_vertex {
3737
unsigned long out_degree;
3838
unsigned long index;
3939
unsigned long lowlink;
40-
bool on_stack;
4140
};
4241

4342
struct unix_edge {

net/unix/garbage.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,20 @@ static struct unix_vertex *unix_edge_successor(struct unix_edge *edge)
115115
static LIST_HEAD(unix_unvisited_vertices);
116116

117117
enum unix_vertex_index {
118-
UNIX_VERTEX_INDEX_UNVISITED,
118+
UNIX_VERTEX_INDEX_MARK1,
119+
UNIX_VERTEX_INDEX_MARK2,
119120
UNIX_VERTEX_INDEX_START,
120121
};
121122

123+
static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1;
124+
122125
static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
123126
{
124127
struct unix_vertex *vertex = edge->predecessor->vertex;
125128

126129
if (!vertex) {
127130
vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry);
131+
vertex->index = unix_vertex_unvisited_index;
128132
vertex->out_degree = 0;
129133
INIT_LIST_HEAD(&vertex->edges);
130134

@@ -265,6 +269,7 @@ void unix_destroy_fpl(struct scm_fp_list *fpl)
265269
}
266270

267271
static LIST_HEAD(unix_visited_vertices);
272+
static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2;
268273

269274
static void __unix_walk_scc(struct unix_vertex *vertex)
270275
{
@@ -274,10 +279,10 @@ static void __unix_walk_scc(struct unix_vertex *vertex)
274279
LIST_HEAD(edge_stack);
275280

276281
next_vertex:
277-
/* Push vertex to vertex_stack.
282+
/* Push vertex to vertex_stack and mark it as on-stack
283+
* (index >= UNIX_VERTEX_INDEX_START).
278284
* The vertex will be popped when finalising SCC later.
279285
*/
280-
vertex->on_stack = true;
281286
list_add(&vertex->scc_entry, &vertex_stack);
282287

283288
vertex->index = index;
@@ -291,7 +296,7 @@ static void __unix_walk_scc(struct unix_vertex *vertex)
291296
if (!next_vertex)
292297
continue;
293298

294-
if (next_vertex->index == UNIX_VERTEX_INDEX_UNVISITED) {
299+
if (next_vertex->index == unix_vertex_unvisited_index) {
295300
/* Iterative deepening depth first search
296301
*
297302
* 1. Push a forward edge to edge_stack and set
@@ -317,7 +322,7 @@ static void __unix_walk_scc(struct unix_vertex *vertex)
317322
* to skip SCC finalisation.
318323
*/
319324
vertex->lowlink = min(vertex->lowlink, next_vertex->lowlink);
320-
} else if (next_vertex->on_stack) {
325+
} else if (next_vertex->index != unix_vertex_grouped_index) {
321326
/* Loop detected by a back/cross edge.
322327
*
323328
* The successor is on vertex_stack, so two vertices are
@@ -344,7 +349,8 @@ static void __unix_walk_scc(struct unix_vertex *vertex)
344349
/* Don't restart DFS from this vertex in unix_walk_scc(). */
345350
list_move_tail(&vertex->entry, &unix_visited_vertices);
346351

347-
vertex->on_stack = false;
352+
/* Mark vertex as off-stack. */
353+
vertex->index = unix_vertex_grouped_index;
348354
}
349355

350356
list_del(&scc);
@@ -357,20 +363,18 @@ static void __unix_walk_scc(struct unix_vertex *vertex)
357363

358364
static void unix_walk_scc(void)
359365
{
360-
struct unix_vertex *vertex;
361-
362-
list_for_each_entry(vertex, &unix_unvisited_vertices, entry)
363-
vertex->index = UNIX_VERTEX_INDEX_UNVISITED;
364-
365366
/* Visit every vertex exactly once.
366367
* __unix_walk_scc() moves visited vertices to unix_visited_vertices.
367368
*/
368369
while (!list_empty(&unix_unvisited_vertices)) {
370+
struct unix_vertex *vertex;
371+
369372
vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry);
370373
__unix_walk_scc(vertex);
371374
}
372375

373376
list_replace_init(&unix_visited_vertices, &unix_unvisited_vertices);
377+
swap(unix_vertex_unvisited_index, unix_vertex_grouped_index);
374378
}
375379

376380
static LIST_HEAD(gc_candidates);

0 commit comments

Comments
 (0)