relayd: unlink index files through the fd-tracker
[lttng-tools.git] / src / bin / lttng-relayd / index-file.c
CommitLineData
f465e978
JG
1/*
2 * Copyright (C) 2018 - Jérémie Galarneau <jeremie.galarneau@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#include "index-file.h"
19#include "lttng-relayd.h"
20
21#include <common/defaults.h>
22#include <common/error.h>
23#include <common/utils.h>
24#include <common/readwrite.h>
25#include <common/fd-tracker/fd-tracker.h>
26#include <common/fd-tracker/utils.h>
27#include <lttng/constant.h>
28
29#include <inttypes.h>
30#include <stdbool.h>
31#include <urcu/ref.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34
35struct relay_index_file {
0b124aaa 36 struct fs_handle *handle;
f465e978
JG
37 uint32_t major;
38 uint32_t minor;
39 uint32_t element_len;
40 struct urcu_ref ref;
41};
42
0b124aaa
JG
43/*
44 * This unlink wrapper allows the fd_tracker to check if any other
45 * fs_handle references the index before unlinking it. If the relay holds
46 * this file open, it is essential to unlink it through an fs_handle as this
47 * will delay the actual unlink() until all handles have released this file.
48 *
49 * The file is renamed and unlinked once the last handle to its inode has been
50 * released.
51 */
52static
53int unlink_through_handle(const char *path)
54{
55 int ret = 0, close_ret;
56 struct fs_handle *handle;
57 /*
58 * Since this operation is only performed to perform the unlink
59 * through the fs_handle and fd-tracker system, the flag is opened
60 * without the O_CREAT. There is no need to perform the unlink if
61 * the file doesn't already exist.
62 */
63 int flags = O_RDONLY;
64
65 DBG("Unlinking index at %s through a filesystem handle", path);
66 handle = fd_tracker_open_fs_handle(the_fd_tracker, path, flags, NULL);
67 if (!handle) {
68 /* There is nothing to do. */
69 DBG("File %s does not exist, ignoring unlink", path);
70 goto end;
71 }
72
73 ret = fs_handle_unlink(handle);
74 close_ret = fs_handle_close(handle);
75 if (close_ret) {
76 ERR("Failed to close handle after performing an unlink operation on a filesystem handle");
77 }
78end:
79 if (ret) {
80 DBG("Unlinking index at %s failed with error code %i", path, ret);
81 }
82 return ret;
83}
84
f465e978
JG
85/*
86 * Create the index file associated with a trace file.
87 *
88 * Return allocated struct lttng_index_file, NULL on error.
89 */
90struct relay_index_file *relay_index_file_create(const char *path_name,
91 const char *stream_name, uint64_t size, uint64_t count,
92 uint32_t idx_major, uint32_t idx_minor)
93{
94 struct relay_index_file *index_file;
95 struct fs_handle *fs_handle = NULL;
96 int ret, fd = -1;
97 ssize_t size_ret;
98 struct ctf_packet_index_file_hdr hdr;
99 char idx_dir_path[LTTNG_PATH_MAX];
100 char idx_file_path[LTTNG_PATH_MAX];
101 /*
102 * With the session rotation feature on the relay, we might need to seek
103 * and truncate a tracefile, so we need read and write access.
104 */
105 int flags = O_RDWR | O_CREAT | O_TRUNC;
106 /* Open with 660 mode */
107 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
108
109 index_file = zmalloc(sizeof(*index_file));
110 if (!index_file) {
111 PERROR("allocating relay_index_file");
112 goto error;
113 }
114
f465e978
JG
115 ret = snprintf(idx_dir_path, sizeof(idx_dir_path), "%s/" DEFAULT_INDEX_DIR,
116 path_name);
117 if (ret < 0) {
118 PERROR("snprintf index path");
119 goto error;
120 }
121
122 /* Create index directory if necessary. */
123 ret = utils_mkdir(idx_dir_path, S_IRWXU | S_IRWXG, -1, -1);
124 if (ret < 0) {
125 if (errno != EEXIST) {
126 PERROR("Index trace directory creation error");
127 goto error;
128 }
129 }
130
131 ret = utils_stream_file_name(idx_file_path, idx_dir_path, stream_name,
132 size, count, DEFAULT_INDEX_FILE_SUFFIX);
133 if (ret < 0) {
134 ERR("Could not build path of index file");
135 goto error;
136 }
137
138 /*
139 * For tracefile rotation. We need to unlink the old
140 * file if present to synchronize with the tail of the
141 * live viewer which could be working on this same file.
142 * By doing so, any reference to the old index file
143 * stays valid even if we re-create a new file with the
144 * same name afterwards.
145 */
0b124aaa
JG
146 ret = unlink_through_handle(idx_file_path);
147 if (ret < 0) {
f465e978
JG
148 goto error;
149 }
150
151 fs_handle = fd_tracker_open_fs_handle(the_fd_tracker, idx_file_path,
152 flags, &mode);
153 if (!fs_handle) {
154 goto error;
155 }
0b124aaa 156 index_file->handle = fs_handle;
f465e978
JG
157
158 fd = fs_handle_get_fd(fs_handle);
159 if (fd < 0) {
160 goto error;
161 }
162
163 ctf_packet_index_file_hdr_init(&hdr, idx_major, idx_minor);
164 size_ret = lttng_write(fd, &hdr, sizeof(hdr));
165 if (size_ret < sizeof(hdr)) {
166 PERROR("write index header");
167 goto error;
168 }
169
170 index_file->major = idx_major;
171 index_file->minor = idx_minor;
172 index_file->element_len = ctf_packet_index_len(idx_major, idx_minor);
173 urcu_ref_init(&index_file->ref);
174
175 fs_handle_put_fd(fs_handle);
176
177 return index_file;
178
179error:
180 if (fd >= 0) {
181 fs_handle_put_fd(fs_handle);
182 }
183 if (fs_handle) {
184 int close_ret;
185
186 close_ret = fs_handle_close(fs_handle);
187 if (close_ret < 0) {
188 PERROR("Failed to close index filesystem handle");
189 }
190 }
191 free(index_file);
192 return NULL;
193}
194
f465e978
JG
195struct relay_index_file *relay_index_file_open(const char *path_name,
196 const char *channel_name, uint64_t tracefile_count,
197 uint64_t tracefile_count_current)
198{
199 struct relay_index_file *index_file;
0b124aaa 200 int ret, fd = -1;
f465e978
JG
201 ssize_t read_len;
202 char fullpath[PATH_MAX];
f465e978
JG
203 struct ctf_packet_index_file_hdr hdr;
204 uint32_t major, minor, element_len;
0b124aaa
JG
205 int flags = O_RDONLY;
206 struct fs_handle *handle = NULL;
f465e978
JG
207
208 assert(path_name);
209 assert(channel_name);
210
211 index_file = zmalloc(sizeof(*index_file));
212 if (!index_file) {
213 PERROR("Failed to allocate relay_index_file");
214 goto error;
215 }
216
f465e978
JG
217 if (tracefile_count > 0) {
218 ret = snprintf(fullpath, sizeof(fullpath), "%s/" DEFAULT_INDEX_DIR "/%s_%"
219 PRIu64 DEFAULT_INDEX_FILE_SUFFIX, path_name,
220 channel_name, tracefile_count_current);
221 } else {
222 ret = snprintf(fullpath, sizeof(fullpath), "%s/" DEFAULT_INDEX_DIR "/%s"
223 DEFAULT_INDEX_FILE_SUFFIX, path_name, channel_name);
224 }
225 if (ret < 0) {
226 PERROR("Failed to build index path");
227 goto error;
228 }
229
0b124aaa
JG
230 DBG("Index opening file %s in read only mode", fullpath);
231 handle = fd_tracker_open_fs_handle(the_fd_tracker, fullpath, flags,
232 NULL);
233 if (!handle) {
f465e978
JG
234 PERROR("Failed to open index file at %s", fullpath);
235 goto error;
236 }
237
0b124aaa
JG
238 fd = fs_handle_get_fd(handle);
239 if (fd < 0) {
240 PERROR("Failed to get fd of index file at %s", fullpath);
241 goto error;
242 }
243
f465e978
JG
244 read_len = lttng_read(fd, &hdr, sizeof(hdr));
245 if (read_len < 0) {
246 PERROR("Failed to read index header");
247 goto error_close;
248 }
249
250 if (be32toh(hdr.magic) != CTF_INDEX_MAGIC) {
251 ERR("Invalid header magic %#010x, expected %#010x",
252 be32toh(hdr.magic), CTF_INDEX_MAGIC);
253 goto error_close;
254 }
255 major = be32toh(hdr.index_major);
256 minor = be32toh(hdr.index_minor);
257 element_len = be32toh(hdr.packet_index_len);
258
259 if (major != CTF_INDEX_MAJOR) {
260 ERR("Invalid header version, major = %" PRIu32 ", expected %i",
261 major, CTF_INDEX_MAJOR);
262 goto error_close;
263 }
264 if (element_len > sizeof(struct ctf_packet_index)) {
265 ERR("Index element length too long (%" PRIu32 " bytes)",
266 element_len);
267 goto error_close;
268 }
269
0b124aaa
JG
270 fs_handle_put_fd(handle);
271 index_file->handle = handle;
f465e978
JG
272 index_file->major = major;
273 index_file->minor = minor;
274 index_file->element_len = element_len;
275 urcu_ref_init(&index_file->ref);
276
277 return index_file;
278
279error_close:
0b124aaa
JG
280 if (fd >= 0) {
281 fs_handle_put_fd(handle);
282 }
283 ret = fs_handle_close(handle);
f465e978 284 if (ret < 0) {
0b124aaa
JG
285 PERROR("Failed to close index filesystem handle to %s",
286 fullpath);
f465e978
JG
287 }
288
289error:
290 free(index_file);
291 return NULL;
292}
293
294int relay_index_file_write(const struct relay_index_file *index_file,
295 const struct ctf_packet_index *element)
296{
297 int fd, ret;
298 ssize_t write_ret;
299
300 assert(index_file);
301 assert(element);
302
0b124aaa 303 fd = fs_handle_get_fd(index_file->handle);
f465e978
JG
304 if (fd < 0) {
305 ret = fd;
306 goto end;
307 }
308
309 write_ret = lttng_write(fd, element, index_file->element_len);
310 if (write_ret < index_file->element_len) {
311 PERROR("Failed to write packet index to index file");
312 ret = -1;
313 }
314 ret = 0;
315
0b124aaa 316 fs_handle_put_fd(index_file->handle);
f465e978
JG
317end:
318 return ret;
319}
320
321int relay_index_file_read(const struct relay_index_file *index_file,
322 struct ctf_packet_index *element)
323{
324 int fd, ret;
325 ssize_t read_ret;
326
327 assert(index_file);
328 assert(element);
329
0b124aaa 330 fd = fs_handle_get_fd(index_file->handle);
f465e978
JG
331 if (fd < 0) {
332 ret = fd;
333 goto end;
334 }
335
336 read_ret = lttng_read(fd, element, index_file->element_len);
337 if (read_ret < index_file->element_len) {
338 PERROR("Failed to read packet index from file");
339 ret = -1;
340 }
341 ret = 0;
342
0b124aaa 343 fs_handle_put_fd(index_file->handle);
f465e978
JG
344end:
345 return ret;
346}
347
348int relay_index_file_seek_end(struct relay_index_file *index_file)
349{
350 int fd, ret = 0;
351 off_t lseek_ret;
352
0b124aaa 353 fd = fs_handle_get_fd(index_file->handle);
f465e978
JG
354 if (fd < 0) {
355 ret = fd;
356 goto end;
357 }
358
359 lseek_ret = lseek(fd, 0, SEEK_END);
360 if (lseek_ret < 0) {
361 ret = lseek_ret;
362 }
363
0b124aaa 364 fs_handle_put_fd(index_file->handle);
f465e978
JG
365end:
366 return ret;
367}
368
369void relay_index_file_get(struct relay_index_file *index_file)
370{
371 urcu_ref_get(&index_file->ref);
372}
373
374static
375void relay_index_file_release(struct urcu_ref *ref)
376{
377 int ret;
378 struct relay_index_file *index_file = caa_container_of(ref,
379 struct relay_index_file, ref);
380
0b124aaa 381 ret = fs_handle_close(index_file->handle);
f465e978
JG
382 if (ret < 0) {
383 PERROR("Failed to close index file");
384 }
385 free(index_file);
386}
387
388void relay_index_file_put(struct relay_index_file *index_file)
389{
390 urcu_ref_put(&index_file->ref, relay_index_file_release);
391}
This page took 0.03969 seconds and 5 git commands to generate.