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