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