Fix: src.ctf.fs: Using uninitialized value
[babeltrace.git] / fd-cache / fd-cache.c
CommitLineData
1e638f98
FD
1/*
2 * fd-cache.c
3 *
4 * Babeltrace - File descriptor cache
5 *
6 * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
7 *
8 * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29#define BT_LOG_TAG "FD-CACHE"
30#include "logging.h"
31
32#include <fcntl.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <unistd.h>
36#include <glib.h>
37
38#include <babeltrace/assert-internal.h>
39#include <babeltrace/fd-cache-internal.h>
40
41struct file_key {
42 uint64_t dev;
43 uint64_t ino;
44};
45
46struct fd_handle_internal {
47 struct bt_fd_cache_handle fd_handle;
48 uint64_t ref_count;
49 struct file_key *key;
50};
51
52static
53void fd_cache_handle_internal_destroy(
54 struct fd_handle_internal *internal_fd)
55{
56 if (!internal_fd) {
57 goto end;
58 }
59
60 if (internal_fd->fd_handle.fd >= 0) {
61 close(internal_fd->fd_handle.fd);
62 internal_fd->fd_handle.fd = -1;
63 }
64
65end:
66 g_free(internal_fd);
67}
68
69/*
70 * Using simple hash algorithm found on stackoverflow:
71 * https://stackoverflow.com/questions/664014/
72 */
73static inline
74uint64_t hash_uint64_t(uint64_t x) {
75 x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
76 x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
77 x = x ^ (x >> 31);
78 return x;
79}
80
81static
82guint file_key_hash(gconstpointer v)
83{
84 const struct file_key *fk = v;
85 return hash_uint64_t(fk->dev) ^ hash_uint64_t(fk->ino);
86}
87
88static
89gboolean file_key_equal(gconstpointer v1, gconstpointer v2)
90{
91 const struct file_key *fk1 = v1;
92 const struct file_key *fk2 = v2;
93
94 return (fk1->dev == fk2->dev) && (fk1->ino == fk2->ino);
95}
96
97static
98void file_key_destroy(gpointer data)
99{
100 struct file_key *fk = data;
101 g_free(fk);
102}
103
104BT_HIDDEN
105int bt_fd_cache_init(struct bt_fd_cache *fdc)
106{
107 int ret = 0;
108
109 fdc->cache = g_hash_table_new_full(file_key_hash, file_key_equal,
110 file_key_destroy, (GDestroyNotify) fd_cache_handle_internal_destroy);
111 if (!fdc->cache) {
112 ret = -1;
113 }
114
115 return ret;
116}
117
118BT_HIDDEN
119void bt_fd_cache_fini(struct bt_fd_cache *fdc)
120{
121 BT_ASSERT(fdc->cache);
122 /*
123 * All handle should have been removed for the hashtable at this point.
124 */
125 BT_ASSERT(g_hash_table_size(fdc->cache) == 0);
126 g_hash_table_destroy(fdc->cache);
127
128 return;
129}
130
131BT_HIDDEN
132struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
133 const char *path)
134{
135 struct fd_handle_internal *fd_internal = NULL;
136 struct stat statbuf;
137 struct file_key fk;
2431859f 138 int ret, fd = -1;
1e638f98
FD
139
140 ret = stat(path, &statbuf);
141 if (ret < 0) {
142 BT_LOGE_ERRNO("Failed to stat file", ": path=%s", path);
143 goto end;
144 }
145
146 /*
147 * Use the device number and inode number to uniquely identify a file.
148 * Even if the file as the same path, it may have been replaced so we
149 * must open a new FD for it. This replacement of file is more likely
150 * to happen with a lttng-live source component.
151 */
152 fk.dev = statbuf.st_dev;
153 fk.ino = statbuf.st_ino;
154
155 fd_internal = g_hash_table_lookup(fdc->cache, &fk);
156 if (!fd_internal) {
1e638f98
FD
157 struct file_key *file_key;
158
2431859f 159 fd = open(path, O_RDONLY);
1e638f98
FD
160 if (fd < 0) {
161 BT_LOGE_ERRNO("Failed to open file", "path=%s", path);
162 goto error;
163 }
164
165 fd_internal = g_new0(struct fd_handle_internal, 1);
166 if (!fd_internal) {
167 BT_LOGE("Failed to allocate fd internal handle");
168 goto error;
169 }
170
171 file_key = g_new0(struct file_key, 1);
172 if (!fd_internal) {
173 BT_LOGE("Failed to allocate file key");
174 goto error;
175 }
176
177 *file_key = fk;
178
179 fd_internal->fd_handle.fd = fd;
180 fd_internal->ref_count = 0;
181 fd_internal->key = file_key;
182
183 /* Insert the newly created fd handle. */
95dc9c84 184 g_hash_table_insert(fdc->cache, fd_internal->key, fd_internal);
1e638f98
FD
185 }
186
187 BT_ASSERT(fd_internal->ref_count >= 0);
188
189 fd_internal->ref_count++;
190 goto end;
191
192error:
2431859f
FD
193 /*
194 * Close file descriptor if it was open() and we are currently on error
195 * path.
196 */
197 if (fd != -1) {
198 ret = close(fd);
199 if (ret) {
200 BT_LOGE_ERRNO("Failed to close file descriptor",
201 ": fd=%i, path=%s", fd, path);
202 }
203 }
204
1e638f98
FD
205 fd_cache_handle_internal_destroy(fd_internal);
206 fd_internal = NULL;
207end:
208 return (struct bt_fd_cache_handle *) fd_internal;
209}
210
211BT_HIDDEN
212void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
213 struct bt_fd_cache_handle *handle)
214{
215 struct fd_handle_internal *fd_internal;
216
217 if (!handle) {
218 goto end;
219 }
220
221 fd_internal = (struct fd_handle_internal *) handle;
222
223 BT_ASSERT(fd_internal->ref_count > 0);
224
225 if (fd_internal->ref_count > 1) {
226 fd_internal->ref_count--;
227 } else {
228 gboolean ret;
229 int close_ret;
230
231 close_ret = close(fd_internal->fd_handle.fd);
232 if (close_ret == -1) {
233 BT_LOGW_ERRNO("Failed to close file descriptor",
234 ": fd=%d", fd_internal->fd_handle.fd);
235 }
236 ret = g_hash_table_remove(fdc->cache, fd_internal->key);
237 BT_ASSERT(ret);
238 }
239
240end:
241 return;
242}
This page took 0.03103 seconds and 4 git commands to generate.