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