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