sessiond: Replace uses of session_trylock_list by a dedicated assert macro
[lttng-tools.git] / src / bin / lttng-sessiond / snapshot.cpp
1 /*
2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <inttypes.h>
10 #include <string.h>
11 #include <urcu/uatomic.h>
12
13 #include <common/defaults.hpp>
14
15 #include "snapshot.hpp"
16 #include "utils.hpp"
17
18 /*
19 * Return the atomically incremented value of next_output_id.
20 */
21 static inline unsigned long get_next_output_id(struct snapshot *snapshot)
22 {
23 return uatomic_add_return(&snapshot->next_output_id, 1);
24 }
25
26 /*
27 * Initialized snapshot output with the given values.
28 *
29 * Return 0 on success or else a negative value.
30 */
31 static int output_init(const struct ltt_session *session,
32 uint64_t max_size, const char *name,
33 struct lttng_uri *uris, size_t nb_uri,
34 struct consumer_output *consumer, struct snapshot_output *output,
35 struct snapshot *snapshot)
36 {
37 int ret = 0, i;
38
39 memset(output, 0, sizeof(struct snapshot_output));
40
41 /*
42 * max_size of -1ULL means unset. Set to default (unlimited).
43 */
44 if (max_size == (uint64_t) -1ULL) {
45 max_size = 0;
46 }
47 output->max_size = max_size;
48
49 if (snapshot) {
50 output->id = get_next_output_id(snapshot);
51 }
52 lttng_ht_node_init_ulong(&output->node, (unsigned long) output->id);
53
54 if (name && name[0] != '\0') {
55 if (lttng_strncpy(output->name, name, sizeof(output->name))) {
56 ret = -LTTNG_ERR_INVALID;
57 goto error;
58 }
59 } else {
60 /* Set default name. */
61 ret = snprintf(output->name, sizeof(output->name), "%s-%" PRIu32,
62 DEFAULT_SNAPSHOT_NAME, output->id);
63 if (ret < 0) {
64 ret = -ENOMEM;
65 goto error;
66 }
67 }
68
69 if (!consumer) {
70 goto end;
71 }
72
73 output->consumer = consumer_copy_output(consumer);
74 if (!output->consumer) {
75 ret = -ENOMEM;
76 goto error;
77 }
78 output->consumer->snapshot = 1;
79
80 /* No URL given. */
81 if (nb_uri == 0) {
82 ret = 0;
83 goto end;
84 }
85
86 if (uris[0].dtype == LTTNG_DST_PATH) {
87 memset(output->consumer->dst.session_root_path, 0,
88 sizeof(output->consumer->dst.session_root_path));
89 if (lttng_strncpy(output->consumer->dst.session_root_path,
90 uris[0].dst.path,
91 sizeof(output->consumer->dst.session_root_path))) {
92 ret = -LTTNG_ERR_INVALID;
93 goto error;
94 }
95 output->consumer->type = CONSUMER_DST_LOCAL;
96 ret = 0;
97 goto end;
98 }
99
100 if (nb_uri != 2) {
101 /* Absolutely needs two URIs for network. */
102 ret = -LTTNG_ERR_INVALID;
103 goto error;
104 }
105
106 for (i = 0; i < nb_uri; i ++) {
107 /* Network URIs */
108 ret = consumer_set_network_uri(session, output->consumer,
109 &uris[i]);
110 if (ret < 0) {
111 goto error;
112 }
113 }
114
115 error:
116 end:
117 return ret;
118 }
119
120 /*
121 * Initialize a snapshot output object using the given parameters and URI(s).
122 * The name value and uris can be NULL.
123 *
124 * Return 0 on success or else a negative value.
125 */
126 int snapshot_output_init_with_uri(const struct ltt_session *session,
127 uint64_t max_size, const char *name,
128 struct lttng_uri *uris, size_t nb_uri,
129 struct consumer_output *consumer, struct snapshot_output *output,
130 struct snapshot *snapshot)
131 {
132 return output_init(session, max_size, name, uris, nb_uri, consumer,
133 output, snapshot);
134 }
135
136 /*
137 * Initialize a snapshot output object using the given parameters. The name
138 * value and url can be NULL.
139 *
140 * Return 0 on success or else a negative value.
141 */
142 int snapshot_output_init(const struct ltt_session *session,
143 uint64_t max_size, const char *name,
144 const char *ctrl_url, const char *data_url,
145 struct consumer_output *consumer, struct snapshot_output *output,
146 struct snapshot *snapshot)
147 {
148 int ret = 0, nb_uri;
149 struct lttng_uri *uris = NULL;
150
151 /* Create an array of URIs from URLs. */
152 nb_uri = uri_parse_str_urls(ctrl_url, data_url, &uris);
153 if (nb_uri < 0) {
154 ret = nb_uri;
155 goto error;
156 }
157
158 ret = output_init(session, max_size, name, uris, nb_uri, consumer,
159 output, snapshot);
160
161 error:
162 free(uris);
163 return ret;
164 }
165
166 struct snapshot_output *snapshot_output_alloc(void)
167 {
168 return zmalloc<snapshot_output>();
169 }
170
171 /*
172 * Delete output from the snapshot object.
173 */
174 void snapshot_delete_output(struct snapshot *snapshot,
175 struct snapshot_output *output)
176 {
177 int ret;
178 struct lttng_ht_iter iter;
179
180 LTTNG_ASSERT(snapshot);
181 LTTNG_ASSERT(snapshot->output_ht);
182 LTTNG_ASSERT(output);
183
184 iter.iter.node = &output->node.node;
185 rcu_read_lock();
186 ret = lttng_ht_del(snapshot->output_ht, &iter);
187 rcu_read_unlock();
188 LTTNG_ASSERT(!ret);
189 /*
190 * This is safe because the ownership of a snapshot object is in a session
191 * for which the session lock need to be acquired to read and modify it.
192 */
193 snapshot->nb_output--;
194 }
195
196 /*
197 * Add output object to the snapshot.
198 */
199 void snapshot_add_output(struct snapshot *snapshot,
200 struct snapshot_output *output)
201 {
202 LTTNG_ASSERT(snapshot);
203 LTTNG_ASSERT(snapshot->output_ht);
204 LTTNG_ASSERT(output);
205
206 rcu_read_lock();
207 lttng_ht_add_unique_ulong(snapshot->output_ht, &output->node);
208 rcu_read_unlock();
209 /*
210 * This is safe because the ownership of a snapshot object is in a session
211 * for which the session lock need to be acquired to read and modify it.
212 */
213 snapshot->nb_output++;
214 }
215
216 /*
217 * Destroy and free a snapshot output object.
218 */
219 void snapshot_output_destroy(struct snapshot_output *obj)
220 {
221 LTTNG_ASSERT(obj);
222
223 if (obj->consumer) {
224 consumer_output_send_destroy_relayd(obj->consumer);
225 consumer_output_put(obj->consumer);
226 }
227 free(obj);
228 }
229
230 /*
231 * RCU read side lock MUST be acquired before calling this since the returned
232 * pointer is in a RCU hash table.
233 *
234 * Return the reference on success or else NULL.
235 */
236 struct snapshot_output *snapshot_find_output_by_name(const char *name,
237 struct snapshot *snapshot)
238 {
239 struct lttng_ht_iter iter;
240 struct snapshot_output *output = NULL;
241
242 LTTNG_ASSERT(snapshot);
243 LTTNG_ASSERT(name);
244 ASSERT_RCU_READ_LOCKED();
245
246 cds_lfht_for_each_entry(snapshot->output_ht->ht, &iter.iter, output,
247 node.node) {
248 if (!strncmp(output->name, name, strlen(name))) {
249 return output;
250 }
251 }
252
253 /* Not found */
254 return NULL;
255 }
256
257 /*
258 * RCU read side lock MUST be acquired before calling this since the returned
259 * pointer is in a RCU hash table.
260 *
261 * Return the reference on success or else NULL.
262 */
263 struct snapshot_output *snapshot_find_output_by_id(uint32_t id,
264 struct snapshot *snapshot)
265 {
266 struct lttng_ht_node_ulong *node;
267 struct lttng_ht_iter iter;
268 struct snapshot_output *output = NULL;
269
270 LTTNG_ASSERT(snapshot);
271 ASSERT_RCU_READ_LOCKED();
272
273 lttng_ht_lookup(snapshot->output_ht, (void *)((unsigned long) id), &iter);
274 node = lttng_ht_iter_get_node_ulong(&iter);
275 if (!node) {
276 DBG3("Snapshot output not found with id %" PRId32, id);
277 goto error;
278 }
279 output = caa_container_of(node, struct snapshot_output, node);
280
281 error:
282 return output;
283 }
284
285 /*
286 * Initialized a snapshot object that was already allocated.
287 *
288 * Return 0 on success or else a negative errno value.
289 */
290 int snapshot_init(struct snapshot *obj)
291 {
292 int ret;
293
294 LTTNG_ASSERT(obj);
295
296 memset(obj, 0, sizeof(struct snapshot));
297
298 obj->output_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
299 if (!obj->output_ht) {
300 ret = -ENOMEM;
301 goto error;
302 }
303
304 ret = 0;
305
306 error:
307 return ret;
308 }
309
310 /*
311 * Destroy snapshot object but the pointer is not freed so it's safe to pass a
312 * static reference.
313 */
314 void snapshot_destroy(struct snapshot *obj)
315 {
316 struct lttng_ht_iter iter;
317 struct snapshot_output *output;
318
319 if (!obj->output_ht) {
320 return;
321 }
322
323 rcu_read_lock();
324 cds_lfht_for_each_entry(obj->output_ht->ht, &iter.iter, output,
325 node.node) {
326 snapshot_delete_output(obj, output);
327 snapshot_output_destroy(output);
328 }
329 rcu_read_unlock();
330 lttng_ht_destroy(obj->output_ht);
331 }
This page took 0.035804 seconds and 4 git commands to generate.