1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
5 * LTTng Process ID tracking.
7 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/err.h>
13 #include <linux/seq_file.h>
14 #include <linux/stringify.h>
15 #include <linux/hash.h>
16 #include <linux/rcupdate.h>
18 #include <wrapper/tracepoint.h>
19 #include <wrapper/rcu.h>
20 #include <wrapper/list.h>
21 #include <lttng/events.h>
22 #include <lttng/events-internal.h>
25 * Hash table is allocated and freed when there are no possible
26 * concurrent lookups (ensured by the alloc/free caller). However,
27 * there can be concurrent RCU lookups vs add/del operations.
29 * Concurrent updates of the PID hash table are forbidden: the caller
30 * must ensure mutual exclusion. This is currently done by holding the
31 * sessions_mutex across calls to create, destroy, add, and del
32 * functions of this API.
34 int lttng_id_tracker_get_node_id(const struct lttng_id_hash_node
*node
)
40 * Lookup performed from RCU read-side critical section (RCU sched),
41 * protected by preemption off at the tracepoint call site.
42 * Return true if found, false if not found.
44 bool lttng_id_tracker_lookup(struct lttng_kernel_id_tracker_rcu
*p
, int id
)
46 struct hlist_head
*head
;
47 struct lttng_id_hash_node
*e
;
48 uint32_t hash
= hash_32(id
, 32);
50 head
= &p
->id_hash
[hash
& (LTTNG_ID_TABLE_SIZE
- 1)];
51 lttng_hlist_for_each_entry_rcu(e
, head
, hlist
) {
53 return true; /* Found */
57 EXPORT_SYMBOL_GPL(lttng_id_tracker_lookup
);
59 static struct lttng_kernel_id_tracker_rcu
*lttng_id_tracker_rcu_create(void)
61 struct lttng_kernel_id_tracker_rcu
*tracker
;
63 tracker
= kzalloc(sizeof(struct lttng_kernel_id_tracker_rcu
), GFP_KERNEL
);
70 * Tracker add and del operations support concurrent RCU lookups.
72 int lttng_id_tracker_add(struct lttng_kernel_id_tracker
*lf
, int id
)
74 struct hlist_head
*head
;
75 struct lttng_id_hash_node
*e
;
76 struct lttng_kernel_id_tracker_rcu
*p
= lf
->p
;
77 uint32_t hash
= hash_32(id
, 32);
78 bool allocated
= false;
82 p
= lttng_id_tracker_rcu_create();
87 head
= &p
->id_hash
[hash
& (LTTNG_ID_TABLE_SIZE
- 1)];
88 lttng_hlist_for_each_entry(e
, head
, hlist
) {
94 e
= kmalloc(sizeof(struct lttng_id_hash_node
), GFP_KERNEL
);
100 hlist_add_head_rcu(&e
->hlist
, head
);
102 rcu_assign_pointer(lf
->p
, p
);
114 void id_tracker_del_node_rcu(struct lttng_id_hash_node
*e
)
116 hlist_del_rcu(&e
->hlist
);
118 * We choose to use a heavyweight synchronize on removal here,
119 * since removal of an ID from the tracker mask is a rare
120 * operation, and we don't want to use more cache lines than
121 * what we really need when doing the ID lookups, so we don't
122 * want to afford adding a rcu_head field to those pid hash
130 * This removal is only used on destroy, so it does not need to support
131 * concurrent RCU lookups.
134 void id_tracker_del_node(struct lttng_id_hash_node
*e
)
136 hlist_del(&e
->hlist
);
140 int lttng_id_tracker_del(struct lttng_kernel_id_tracker
*lf
, int id
)
142 struct hlist_head
*head
;
143 struct lttng_id_hash_node
*e
;
144 struct lttng_kernel_id_tracker_rcu
*p
= lf
->p
;
145 uint32_t hash
= hash_32(id
, 32);
149 head
= &p
->id_hash
[hash
& (LTTNG_ID_TABLE_SIZE
- 1)];
151 * No need of _safe iteration, because we stop traversal as soon
152 * as we remove the entry.
154 lttng_hlist_for_each_entry(e
, head
, hlist
) {
156 id_tracker_del_node_rcu(e
);
160 return -ENOENT
; /* Not found */
163 static void lttng_id_tracker_rcu_destroy(struct lttng_kernel_id_tracker_rcu
*p
)
169 for (i
= 0; i
< LTTNG_ID_TABLE_SIZE
; i
++) {
170 struct hlist_head
*head
= &p
->id_hash
[i
];
171 struct lttng_id_hash_node
*e
;
172 struct hlist_node
*tmp
;
174 lttng_hlist_for_each_entry_safe(e
, tmp
, head
, hlist
)
175 id_tracker_del_node(e
);
180 int lttng_id_tracker_empty_set(struct lttng_kernel_id_tracker
*lf
)
182 struct lttng_kernel_id_tracker_rcu
*p
, *oldp
;
184 p
= lttng_id_tracker_rcu_create();
188 rcu_assign_pointer(lf
->p
, p
);
190 lttng_id_tracker_rcu_destroy(oldp
);
194 int lttng_id_tracker_init(struct lttng_kernel_id_tracker
*lf
,
195 struct lttng_kernel_session
*session
,
196 enum tracker_type type
)
198 lf
->priv
= kzalloc(sizeof(*lf
->priv
), GFP_KERNEL
);
201 lf
->priv
->session
= session
;
202 lf
->priv
->tracker_type
= type
;
206 void lttng_id_tracker_destroy(struct lttng_kernel_id_tracker
*lf
, bool rcu
)
208 struct lttng_kernel_id_tracker_rcu
*p
= lf
->p
;
212 rcu_assign_pointer(lf
->p
, NULL
);
215 lttng_id_tracker_rcu_destroy(p
);
218 void lttng_id_tracker_fini(struct lttng_kernel_id_tracker
*lf
)
222 lttng_id_tracker_destroy(lf
, false);