2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
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.
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
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.
19 #include <lttng/trigger/trigger.h>
20 #include <common/error.h>
21 #include <common/config/session-config.h>
22 #include <common/defaults.h>
23 #include <common/utils.h>
24 #include <common/futex.h>
25 #include <common/align.h>
26 #include <common/time.h>
27 #include <common/hashtable/utils.h>
28 #include <sys/eventfd.h>
34 #include <common/kernel-ctl/kernel-ctl.h>
35 #include "rotation-thread.h"
36 #include "lttng-sessiond.h"
37 #include "health-sessiond.h"
41 #include <urcu/list.h>
42 #include <urcu/rculfhash.h>
44 struct cds_lfht
*channel_pending_rotate_ht
;
47 unsigned long hash_channel_key(struct rotation_channel_key
*key
)
49 return hash_key_u64(&key
->key
, lttng_ht_seed
) ^ hash_key_ulong(
50 (void *) (unsigned long) key
->domain
, lttng_ht_seed
);
54 void channel_rotation_info_destroy(struct rotation_channel_info
*channel_info
)
60 int rotate_add_channel_pending(uint64_t key
, enum lttng_domain_type domain
,
61 struct ltt_session
*session
)
64 struct rotation_channel_info
*new_info
;
65 struct rotation_channel_key channel_key
= { .key
= key
,
68 new_info
= zmalloc(sizeof(struct rotation_channel_info
));
73 new_info
->channel_key
.key
= key
;
74 new_info
->channel_key
.domain
= domain
;
75 new_info
->session
= session
;
76 cds_lfht_node_init(&new_info
->rotate_channels_ht_node
);
78 session
->nr_chan_rotate_pending
++;
79 cds_lfht_add(channel_pending_rotate_ht
,
80 hash_channel_key(&channel_key
),
81 &new_info
->rotate_channels_ht_node
);
93 int match_channel_info(struct cds_lfht_node
*node
, const void *key
)
95 struct rotation_channel_key
*channel_key
= (struct rotation_channel_key
*) key
;
96 struct rotation_channel_info
*channel_info
;
98 channel_info
= caa_container_of(node
, struct rotation_channel_info
,
99 rotate_channels_ht_node
);
101 return !!((channel_key
->key
== channel_info
->channel_key
.key
) &&
102 (channel_key
->domain
== channel_info
->channel_key
.domain
));
106 struct rotation_channel_info
*lookup_channel_pending(uint64_t key
,
107 enum lttng_domain_type domain
)
109 struct cds_lfht_iter iter
;
110 struct cds_lfht_node
*node
;
111 struct rotation_channel_info
*channel_info
= NULL
;
112 struct rotation_channel_key channel_key
= { .key
= key
,
115 cds_lfht_lookup(channel_pending_rotate_ht
,
116 hash_channel_key(&channel_key
),
118 &channel_key
, &iter
);
119 node
= cds_lfht_iter_get_node(&iter
);
124 channel_info
= caa_container_of(node
, struct rotation_channel_info
,
125 rotate_channels_ht_node
);
126 cds_lfht_del(channel_pending_rotate_ht
, node
);
132 * Destroy the thread data previously created by the init function.
134 void rotation_thread_handle_destroy(
135 struct rotation_thread_handle
*handle
)
143 if (handle
->ust32_consumer
>= 0) {
144 ret
= close(handle
->ust32_consumer
);
146 PERROR("close 32-bit consumer channel rotation pipe");
149 if (handle
->ust64_consumer
>= 0) {
150 ret
= close(handle
->ust64_consumer
);
152 PERROR("close 64-bit consumer channel rotation pipe");
155 if (handle
->kernel_consumer
>= 0) {
156 ret
= close(handle
->kernel_consumer
);
158 PERROR("close kernel consumer channel rotation pipe");
166 struct rotation_thread_handle
*rotation_thread_handle_create(
167 struct lttng_pipe
*ust32_channel_rotate_pipe
,
168 struct lttng_pipe
*ust64_channel_rotate_pipe
,
169 struct lttng_pipe
*kernel_channel_rotate_pipe
,
170 int thread_quit_pipe
)
172 struct rotation_thread_handle
*handle
;
174 handle
= zmalloc(sizeof(*handle
));
179 if (ust32_channel_rotate_pipe
) {
180 handle
->ust32_consumer
=
181 lttng_pipe_release_readfd(
182 ust32_channel_rotate_pipe
);
183 if (handle
->ust32_consumer
< 0) {
187 handle
->ust32_consumer
= -1;
189 if (ust64_channel_rotate_pipe
) {
190 handle
->ust64_consumer
=
191 lttng_pipe_release_readfd(
192 ust64_channel_rotate_pipe
);
193 if (handle
->ust64_consumer
< 0) {
197 handle
->ust64_consumer
= -1;
199 if (kernel_channel_rotate_pipe
) {
200 handle
->kernel_consumer
=
201 lttng_pipe_release_readfd(
202 kernel_channel_rotate_pipe
);
203 if (handle
->kernel_consumer
< 0) {
207 handle
->kernel_consumer
= -1;
209 handle
->thread_quit_pipe
= thread_quit_pipe
;
214 rotation_thread_handle_destroy(handle
);
219 int init_poll_set(struct lttng_poll_event
*poll_set
,
220 struct rotation_thread_handle
*handle
)
225 * Create pollset with size 4:
226 * - sessiond quit pipe
227 * - consumerd (32-bit user space) channel rotate pipe,
228 * - consumerd (64-bit user space) channel rotate pipe,
229 * - consumerd (kernel) channel rotate pipe.
231 ret
= lttng_poll_create(poll_set
, 4, LTTNG_CLOEXEC
);
236 ret
= lttng_poll_add(poll_set
, handle
->thread_quit_pipe
,
239 ERR("[rotation-thread] Failed to add thread_quit_pipe fd to pollset");
242 ret
= lttng_poll_add(poll_set
, handle
->ust32_consumer
,
245 ERR("[rotation-thread] Failed to add ust-32 channel rotation pipe fd to pollset");
248 ret
= lttng_poll_add(poll_set
, handle
->ust64_consumer
,
251 ERR("[rotation-thread] Failed to add ust-64 channel rotation pipe fd to pollset");
254 if (handle
->kernel_consumer
< 0) {
257 ret
= lttng_poll_add(poll_set
, handle
->kernel_consumer
,
260 ERR("[rotation-thread] Failed to add kernel channel rotation pipe fd to pollset");
267 lttng_poll_clean(poll_set
);
272 void fini_thread_state(struct rotation_thread_state
*state
)
274 lttng_poll_clean(&state
->events
);
278 int init_thread_state(struct rotation_thread_handle
*handle
,
279 struct rotation_thread_state
*state
)
283 memset(state
, 0, sizeof(*state
));
284 lttng_poll_init(&state
->events
);
286 ret
= init_poll_set(&state
->events
, handle
);
291 channel_pending_rotate_ht
= cds_lfht_new(DEFAULT_HT_SIZE
,
292 1, 0, CDS_LFHT_AUTO_RESIZE
| CDS_LFHT_ACCOUNTING
, NULL
);
293 if (!channel_pending_rotate_ht
) {
301 int rename_complete_chunk(struct ltt_session
*session
, time_t ts
)
305 char *tmppath
= NULL
;
308 timeinfo
= localtime(&ts
);
309 strftime(datetime
, sizeof(datetime
), "%Y%m%d-%H%M%S", timeinfo
);
311 tmppath
= zmalloc(PATH_MAX
* sizeof(char));
313 ERR("Alloc tmppath");
318 snprintf(tmppath
, PATH_MAX
, "%s%s-%" PRIu64
,
319 session
->rotation_chunk
.current_rotate_path
,
320 datetime
, session
->rotate_count
);
322 fprintf(stderr
, "rename %s to %s\n", session
->rotation_chunk
.current_rotate_path
,
324 ret
= rename(session
->rotation_chunk
.current_rotate_path
,
327 PERROR("Rename completed rotation chunk");
331 * Store the path where the readable chunk is. This path is valid
332 * and can be queried by the client with rotate_pending until the next
333 * rotation is started.
335 snprintf(session
->rotation_chunk
.current_rotate_path
, PATH_MAX
,
337 session
->rotate_pending
= 0;
345 int handle_channel_rotation_pipe(int fd
, uint32_t revents
,
346 struct rotation_thread_handle
*handle
,
347 struct rotation_thread_state
*state
)
350 enum lttng_domain_type domain
;
351 struct rotation_channel_info
*channel_info
;
354 if (fd
== handle
->ust32_consumer
||
355 fd
== handle
->ust64_consumer
) {
356 domain
= LTTNG_DOMAIN_UST
;
357 } else if (fd
== handle
->kernel_consumer
) {
358 domain
= LTTNG_DOMAIN_KERNEL
;
363 if (revents
& (LPOLLERR
| LPOLLHUP
| LPOLLRDHUP
)) {
364 ret
= lttng_poll_del(&state
->events
, fd
);
366 ERR("[rotation-thread] Failed to remove consumer rotation pipe from poll set");
372 ret
= read(fd
, &key
, sizeof(key
));
373 } while (ret
== -1 && errno
== EINTR
);
374 if (ret
!= sizeof(key
)) {
375 ERR("[rotation-thread] Failed to read from pipe (fd = %i)",
381 DBG("[rotation-thread] Received notification for chan %" PRIu64
382 ", domain %d\n", key
, domain
);
384 channel_info
= lookup_channel_pending(key
, domain
);
386 ERR("[rotation-thread] Failed to find channel_info (key = %"
392 if (--channel_info
->session
->nr_chan_rotate_pending
== 0) {
393 time_t now
= time(NULL
);
395 if (now
== (time_t) -1) {
396 ret
= LTTNG_ERR_ROTATE_NOT_AVAILABLE
;
400 ret
= rename_complete_chunk(channel_info
->session
, now
);
402 ERR("Failed to rename completed rotation chunk");
407 channel_rotation_info_destroy(channel_info
);
415 void *thread_rotation(void *data
)
418 struct rotation_thread_handle
*handle
= data
;
419 struct rotation_thread_state state
;
421 DBG("[rotation-thread] Started rotation thread");
424 ERR("[rotation-thread] Invalid thread context provided");
428 rcu_register_thread();
431 health_register(health_sessiond
, HEALTH_SESSIOND_TYPE_ROTATION
);
432 health_code_update();
434 ret
= init_thread_state(handle
, &state
);
439 /* Ready to handle client connections. */
440 sessiond_notify_ready();
446 DBG("[rotation-thread] Entering poll wait");
447 ret
= lttng_poll_wait(&state
.events
, -1);
448 DBG("[rotation-thread] Poll wait returned (%i)", ret
);
452 * Restart interrupted system call.
454 if (errno
== EINTR
) {
457 ERR("[rotation-thread] Error encountered during lttng_poll_wait (%i)", ret
);
462 for (i
= 0; i
< fd_count
; i
++) {
463 int fd
= LTTNG_POLL_GETFD(&state
.events
, i
);
464 uint32_t revents
= LTTNG_POLL_GETEV(&state
.events
, i
);
466 DBG("[rotation-thread] Handling fd (%i) activity (%u)",
469 if (fd
== handle
->thread_quit_pipe
) {
470 DBG("[rotation-thread] Quit pipe activity");
472 } else if (fd
== handle
->ust32_consumer
||
473 fd
== handle
->ust64_consumer
||
474 fd
== handle
->kernel_consumer
) {
475 ret
= handle_channel_rotation_pipe(fd
,
476 revents
, handle
, &state
);
478 ERR("[rotation-thread] Exit main loop");
486 fini_thread_state(&state
);
487 health_unregister(health_sessiond
);
488 rcu_thread_offline();
489 rcu_unregister_thread();