relayd: unlink stream files through the fd-tracker
[lttng-tools.git] / src / bin / lttng-relayd / stream-fd.c
CommitLineData
7591bab1
MD
1/*
2 * Copyright (C) 2015 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
bdafebb5 3 * 2018 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
7591bab1
MD
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
7591bab1 19#define _LGPL_SOURCE
bdafebb5
JG
20
21#include <urcu/ref.h>
22#include <sys/stat.h>
23#include <fcntl.h>
7591bab1 24#include <common/common.h>
bdafebb5
JG
25#include <common/fd-tracker/fd-tracker.h>
26#include <common/fd-tracker/utils.h>
27#include <common/utils.h>
7591bab1
MD
28
29#include "stream-fd.h"
bdafebb5
JG
30#include "lttng-relayd.h"
31
32struct stream_fd {
c78608f0 33 struct fs_handle *handle;
bdafebb5
JG
34 struct urcu_ref ref;
35};
7591bab1 36
bdafebb5 37static struct stream_fd *_stream_fd_alloc(void)
7591bab1
MD
38{
39 struct stream_fd *sf;
40
41 sf = zmalloc(sizeof(*sf));
42 if (!sf) {
43 goto end;
44 }
45 urcu_ref_init(&sf->ref);
7591bab1
MD
46end:
47 return sf;
48}
49
bdafebb5
JG
50static struct stream_fd *stream_fd_suspendable_create(struct fs_handle *handle)
51{
52 struct stream_fd *stream_fd = _stream_fd_alloc();
53
54 if (!stream_fd) {
55 goto end;
56 }
57
c78608f0 58 stream_fd->handle = handle;
bdafebb5
JG
59end:
60 return stream_fd;
61}
62
bdafebb5
JG
63struct stream_fd *stream_fd_open(const char *path)
64{
bdafebb5 65 struct stream_fd *stream_fd = NULL;
c78608f0
JG
66 int flags = O_RDONLY;
67 struct fs_handle *handle;
bdafebb5 68
c78608f0
JG
69 handle = fd_tracker_open_fs_handle(the_fd_tracker, path,
70 flags, NULL);
71 if (!handle) {
bdafebb5
JG
72 goto end;
73 }
74
c78608f0 75 stream_fd = stream_fd_suspendable_create(handle);
bdafebb5 76 if (!stream_fd) {
c78608f0
JG
77 int close_ret;
78
79 close_ret = fs_handle_close(handle);
80 if (close_ret) {
81 ERR("Failed to close filesystem handle of stream at %s", path);
82 }
bdafebb5
JG
83 }
84end:
85 return stream_fd;
86}
87
88static
c78608f0 89struct fs_handle *create_write_fs_handle(const char *path)
bdafebb5
JG
90{
91 struct fs_handle *handle;
92 /*
93 * With the session rotation feature on the relay, we might need to seek
94 * and truncate a tracefile, so we need read and write access.
95 */
96 int flags = O_RDWR | O_CREAT | O_TRUNC;
97 /* Open with 660 mode */
98 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
99
c78608f0 100 handle = fd_tracker_open_fs_handle(the_fd_tracker, path, flags, &mode);
bdafebb5
JG
101 if (!handle) {
102 ERR("Failed to open fs handle to %s", path);
103 }
104
105 return handle;
106}
107
108/*
109 * Stream file are created by on the consumerd/data-reception end. Those
110 * stream fds can be suspended as there is no expectation that the files
111 * will be unlinked and then need to be appended-to.
112 *
113 * Hence, the file descriptors are created as suspendable to allow the
114 * fd-tracker to reduce the number of active fds..
115 */
116struct stream_fd *stream_fd_create(const char *path_name, const char *file_name,
117 uint64_t size, uint64_t count, const char *suffix)
118{
119 struct stream_fd *stream_fd = NULL;
120 struct fs_handle *handle;
121 int ret;
122 char path[PATH_MAX];
123
124 ret = utils_stream_file_name(path, path_name, file_name,
125 size, count, suffix);
126 if (ret < 0) {
127 goto end;
128 }
129
c78608f0 130 handle = create_write_fs_handle(path);
bdafebb5
JG
131 if (!handle) {
132 goto end;
133 }
134
135 stream_fd = stream_fd_suspendable_create(handle);
136 if (!stream_fd) {
c78608f0
JG
137 int close_ret;
138
139 close_ret = fs_handle_close(handle);
140 if (close_ret) {
141 ERR("Failed to close filesystem handle of stream at %s", path);
142 }
bdafebb5
JG
143 }
144
145end:
146 return stream_fd;
147}
148
c78608f0
JG
149/*
150 * This unlink wrapper allows the fd_tracker to check if any other
151 * fs_handle references the stream before unlinking it. If the relay holds
152 * this file open, it is essential to unlink it through an fs_handle as this
153 * will delay the actual unlink() until all handles have released this file.
154 *
155 * The file is renamed and unlinked once the last handle to its inode has been
156 * released.
157 */
158static
159int unlink_through_handle(const char *path)
160{
161 int ret = 0, close_ret;
162 struct fs_handle *handle;
163 /*
164 * Since this operation is only performed to perform the unlink
165 * through the fs_handle and fd-tracker system, the flag is opened
166 * without the O_CREAT. There is no need to perform the unlink if
167 * the file doesn't already exist.
168 */
169 int flags = O_RDONLY;
170
171 DBG("Unlinking stream at %s through a filesystem handle", path);
172 handle = fd_tracker_open_fs_handle(the_fd_tracker, path, flags, NULL);
173 if (!handle) {
174 /* There is nothing to do. */
175 DBG("File %s does not exist, ignoring unlink", path);
176 goto end;
177 }
178
179 ret = fs_handle_unlink(handle);
180 close_ret = fs_handle_close(handle);
181 if (close_ret) {
182 ERR("Failed to close handle after performing an unlink operation on a filesystem handle");
183 }
184end:
185 if (ret) {
186 DBG("Unlinking stream at %s failed with error code %i", path, ret);
187 }
188 return ret;
189}
190
bdafebb5
JG
191int stream_fd_rotate(struct stream_fd *stream_fd, const char *path_name,
192 const char *file_name, uint64_t size,
193 uint64_t count, uint64_t *new_count)
194{
195 int ret;
196 bool should_unlink;
197 char path[PATH_MAX];
198
199 assert(stream_fd);
bdafebb5
JG
200
201 utils_stream_file_rotation_get_new_count(count, new_count,
202 &should_unlink);
203
204 ret = utils_stream_file_name(path, path_name, file_name,
205 size, count, NULL);
206 if (ret < 0) {
207 goto error;
208 }
209
c78608f0
JG
210 ret = fs_handle_close(stream_fd->handle);
211 stream_fd->handle = NULL;
bdafebb5
JG
212 if (ret < 0) {
213 PERROR("Closing stream tracefile handle");
214 goto error;
215 }
c78608f0 216
bdafebb5 217 if (should_unlink) {
c78608f0
JG
218 ret = unlink_through_handle(path);
219 if (ret < 0) {
bdafebb5
JG
220 goto error;
221 }
222 }
223
224 ret = utils_stream_file_name(path, path_name, file_name,
225 size, new_count ? *new_count : 0, NULL);
226 if (ret < 0) {
227 goto error;
228 }
229
c78608f0
JG
230 stream_fd->handle = create_write_fs_handle(path);
231 if (!stream_fd->handle) {
bdafebb5
JG
232 ret = -1;
233 goto error;
234 }
235
236 ret = 0;
237
238error:
239 return ret;
240}
241
7591bab1
MD
242void stream_fd_get(struct stream_fd *sf)
243{
244 urcu_ref_get(&sf->ref);
245}
246
247static void stream_fd_release(struct urcu_ref *ref)
248{
249 struct stream_fd *sf = caa_container_of(ref, struct stream_fd, ref);
250 int ret;
251
c78608f0 252 ret = fs_handle_close(sf->handle);
7591bab1 253 if (ret) {
bdafebb5 254 PERROR("Error closing stream handle");
7591bab1
MD
255 }
256 free(sf);
257}
258
259void stream_fd_put(struct stream_fd *sf)
260{
261 urcu_ref_put(&sf->ref, stream_fd_release);
262}
bdafebb5
JG
263
264int stream_fd_get_fd(struct stream_fd *sf)
265{
c78608f0 266 return fs_handle_get_fd(sf->handle);
bdafebb5
JG
267}
268
269void stream_fd_put_fd(struct stream_fd *sf)
270{
c78608f0 271 fs_handle_put_fd(sf->handle);
bdafebb5 272}
This page took 0.046506 seconds and 5 git commands to generate.