net/unix/garbage.c

Source file repositories/reference/linux-study-clean/net/unix/garbage.c

File Facts

System
Linux kernel
Corpus path
net/unix/garbage.c
Extension
.c
Size
16807 bytes
Lines
660
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

const struct proto_ops *ops;
		struct sock *sk = sock->sk;

		ops = READ_ONCE(sock->ops);

		/* PF_UNIX ? */
		if (sk && ops && ops->family == PF_UNIX)
			return unix_sk(sk);
	}

	return NULL;
}

static struct unix_vertex *unix_edge_successor(struct unix_edge *edge)
{
	/* If an embryo socket has a fd,
	 * the listener indirectly holds the fd's refcnt.
	 */
	if (edge->successor->listener)
		return unix_sk(edge->successor->listener)->vertex;

	return edge->successor->vertex;
}

enum {
	UNIX_GRAPH_NOT_CYCLIC,
	UNIX_GRAPH_MAYBE_CYCLIC,
	UNIX_GRAPH_CYCLIC,
};

static unsigned char unix_graph_state;

static void unix_update_graph(struct unix_vertex *vertex)
{
	/* If the receiver socket is not inflight, no cyclic
	 * reference could be formed.
	 */
	if (!vertex)
		return;

	WRITE_ONCE(unix_graph_state, UNIX_GRAPH_MAYBE_CYCLIC);
}

static LIST_HEAD(unix_unvisited_vertices);

enum unix_vertex_index {
	UNIX_VERTEX_INDEX_MARK1,
	UNIX_VERTEX_INDEX_MARK2,
	UNIX_VERTEX_INDEX_START,
};

static unsigned long unix_vertex_unvisited_index = UNIX_VERTEX_INDEX_MARK1;
static unsigned long unix_vertex_max_scc_index = UNIX_VERTEX_INDEX_START;

static void unix_add_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
{
	struct unix_vertex *vertex = edge->predecessor->vertex;

	if (!vertex) {
		vertex = list_first_entry(&fpl->vertices, typeof(*vertex), entry);
		vertex->index = unix_vertex_unvisited_index;
		vertex->scc_index = ++unix_vertex_max_scc_index;
		vertex->out_degree = 0;
		INIT_LIST_HEAD(&vertex->edges);
		INIT_LIST_HEAD(&vertex->scc_entry);

		list_move_tail(&vertex->entry, &unix_unvisited_vertices);
		edge->predecessor->vertex = vertex;
	}

	vertex->out_degree++;
	list_add_tail(&edge->vertex_entry, &vertex->edges);

	unix_update_graph(unix_edge_successor(edge));
}

static void unix_del_edge(struct scm_fp_list *fpl, struct unix_edge *edge)
{
	struct unix_vertex *vertex = edge->predecessor->vertex;

	if (!fpl->dead)
		unix_update_graph(unix_edge_successor(edge));

	list_del(&edge->vertex_entry);
	vertex->out_degree--;

	if (!vertex->out_degree) {
		edge->predecessor->vertex = NULL;
		list_move_tail(&vertex->entry, &fpl->vertices);
	}

Annotation

Implementation Notes