]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/blobfs/fuse/fuse.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / blobfs / fuse / fuse.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "spdk/stdinc.h"
35
36 #define FUSE_USE_VERSION 30
37 #include "fuse3/fuse.h"
38 #include "fuse3/fuse_lowlevel.h"
39
40 #include "spdk/blobfs.h"
41 #include "spdk/bdev.h"
42 #include "spdk/event.h"
43 #include "spdk/thread.h"
44 #include "spdk/blob_bdev.h"
45 #include "spdk/log.h"
46
47 struct fuse *g_fuse;
48 char *g_bdev_name;
49 char *g_mountpoint;
50 pthread_t g_fuse_thread;
51
52 struct spdk_bs_dev *g_bs_dev;
53 struct spdk_filesystem *g_fs;
54 struct spdk_fs_thread_ctx *g_channel;
55 struct spdk_file *g_file;
56 int g_fserrno;
57 int g_fuse_argc = 0;
58 char **g_fuse_argv = NULL;
59
60 static void
61 __call_fn(void *arg1, void *arg2)
62 {
63 fs_request_fn fn;
64
65 fn = (fs_request_fn)arg1;
66 fn(arg2);
67 }
68
69 static void
70 __send_request(fs_request_fn fn, void *arg)
71 {
72 struct spdk_event *event;
73
74 event = spdk_event_allocate(0, __call_fn, (void *)fn, arg);
75 spdk_event_call(event);
76 }
77
78 static int
79 spdk_fuse_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
80 {
81 struct spdk_file_stat stat;
82 int rc;
83
84 if (!strcmp(path, "/")) {
85 stbuf->st_mode = S_IFDIR | 0755;
86 stbuf->st_nlink = 2;
87 return 0;
88 }
89
90 rc = spdk_fs_file_stat(g_fs, g_channel, path, &stat);
91 if (rc == 0) {
92 stbuf->st_mode = S_IFREG | 0644;
93 stbuf->st_nlink = 1;
94 stbuf->st_size = stat.size;
95 }
96
97 return rc;
98 }
99
100 static int
101 spdk_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
102 off_t offset, struct fuse_file_info *fi,
103 enum fuse_readdir_flags flags)
104 {
105 struct spdk_file *file;
106 const char *filename;
107 spdk_fs_iter iter;
108
109 filler(buf, ".", NULL, 0, 0);
110 filler(buf, "..", NULL, 0, 0);
111
112 iter = spdk_fs_iter_first(g_fs);
113 while (iter != NULL) {
114 file = spdk_fs_iter_get_file(iter);
115 iter = spdk_fs_iter_next(iter);
116 filename = spdk_file_get_name(file);
117 filler(buf, &filename[1], NULL, 0, 0);
118 }
119
120 return 0;
121 }
122
123 static int
124 spdk_fuse_mknod(const char *path, mode_t mode, dev_t rdev)
125 {
126 return spdk_fs_create_file(g_fs, g_channel, path);
127 }
128
129 static int
130 spdk_fuse_unlink(const char *path)
131 {
132 return spdk_fs_delete_file(g_fs, g_channel, path);
133 }
134
135 static int
136 spdk_fuse_truncate(const char *path, off_t size, struct fuse_file_info *fi)
137 {
138 struct spdk_file *file;
139 int rc;
140
141 rc = spdk_fs_open_file(g_fs, g_channel, path, 0, &file);
142 if (rc != 0) {
143 return -rc;
144 }
145
146 rc = spdk_file_truncate(file, g_channel, size);
147 if (rc != 0) {
148 return -rc;
149 }
150
151 spdk_file_close(file, g_channel);
152
153 return 0;
154 }
155
156 static int
157 spdk_fuse_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi)
158 {
159 return 0;
160 }
161
162 static int
163 spdk_fuse_open(const char *path, struct fuse_file_info *info)
164 {
165 struct spdk_file *file;
166 int rc;
167
168 rc = spdk_fs_open_file(g_fs, g_channel, path, 0, &file);
169 if (rc != 0) {
170 return -rc;
171 }
172
173 info->fh = (uintptr_t)file;
174 return 0;
175 }
176
177 static int
178 spdk_fuse_release(const char *path, struct fuse_file_info *info)
179 {
180 struct spdk_file *file = (struct spdk_file *)info->fh;
181
182 return spdk_file_close(file, g_channel);
183 }
184
185 static int
186 spdk_fuse_read(const char *path, char *buf, size_t len, off_t offset, struct fuse_file_info *info)
187 {
188 struct spdk_file *file = (struct spdk_file *)info->fh;
189
190 return spdk_file_read(file, g_channel, buf, offset, len);
191 }
192
193 static int
194 spdk_fuse_write(const char *path, const char *buf, size_t len, off_t offset,
195 struct fuse_file_info *info)
196 {
197 struct spdk_file *file = (struct spdk_file *)info->fh;
198 int rc;
199
200 rc = spdk_file_write(file, g_channel, (void *)buf, offset, len);
201 if (rc == 0) {
202 return len;
203 } else {
204 return rc;
205 }
206 }
207
208 static int
209 spdk_fuse_flush(const char *path, struct fuse_file_info *info)
210 {
211 return 0;
212 }
213
214 static int
215 spdk_fuse_fsync(const char *path, int datasync, struct fuse_file_info *info)
216 {
217 return 0;
218 }
219
220 static int
221 spdk_fuse_rename(const char *old_path, const char *new_path, unsigned int flags)
222 {
223 return spdk_fs_rename_file(g_fs, g_channel, old_path, new_path);
224 }
225
226 static struct fuse_operations spdk_fuse_oper = {
227 .getattr = spdk_fuse_getattr,
228 .readdir = spdk_fuse_readdir,
229 .mknod = spdk_fuse_mknod,
230 .unlink = spdk_fuse_unlink,
231 .truncate = spdk_fuse_truncate,
232 .utimens = spdk_fuse_utimens,
233 .open = spdk_fuse_open,
234 .release = spdk_fuse_release,
235 .read = spdk_fuse_read,
236 .write = spdk_fuse_write,
237 .flush = spdk_fuse_flush,
238 .fsync = spdk_fuse_fsync,
239 .rename = spdk_fuse_rename,
240 };
241
242 static void
243 construct_targets(void)
244 {
245 struct spdk_bdev *bdev;
246
247 bdev = spdk_bdev_get_by_name(g_bdev_name);
248 if (bdev == NULL) {
249 SPDK_ERRLOG("bdev %s not found\n", g_bdev_name);
250 exit(1);
251 }
252
253 g_bs_dev = spdk_bdev_create_bs_dev(bdev, NULL, NULL);
254
255 printf("Mounting BlobFS on bdev %s\n", spdk_bdev_get_name(bdev));
256 }
257
258 static void
259 start_fuse_fn(void *arg1, void *arg2)
260 {
261 struct fuse_args args = FUSE_ARGS_INIT(g_fuse_argc, g_fuse_argv);
262 int rc;
263 struct fuse_cmdline_opts opts = {};
264
265 g_fuse_thread = pthread_self();
266 rc = fuse_parse_cmdline(&args, &opts);
267 if (rc != 0) {
268 spdk_app_stop(-1);
269 fuse_opt_free_args(&args);
270 return;
271 }
272 g_fuse = fuse_new(&args, &spdk_fuse_oper, sizeof(spdk_fuse_oper), NULL);
273 fuse_opt_free_args(&args);
274
275 rc = fuse_mount(g_fuse, g_mountpoint);
276 if (rc != 0) {
277 spdk_app_stop(-1);
278 return;
279 }
280
281 fuse_daemonize(true /* true = run in foreground */);
282
283 fuse_loop(g_fuse);
284
285 fuse_unmount(g_fuse);
286 fuse_destroy(g_fuse);
287 }
288
289 static void
290 init_cb(void *ctx, struct spdk_filesystem *fs, int fserrno)
291 {
292 struct spdk_event *event;
293
294 g_fs = fs;
295 g_channel = spdk_fs_alloc_thread_ctx(g_fs);
296 event = spdk_event_allocate(1, start_fuse_fn, NULL, NULL);
297 spdk_event_call(event);
298 }
299
300 static void
301 spdk_fuse_run(void *arg1)
302 {
303 construct_targets();
304 spdk_fs_load(g_bs_dev, __send_request, init_cb, NULL);
305 }
306
307 static void
308 shutdown_cb(void *ctx, int fserrno)
309 {
310 fuse_session_exit(fuse_get_session(g_fuse));
311 pthread_kill(g_fuse_thread, SIGINT);
312 spdk_fs_free_thread_ctx(g_channel);
313 spdk_app_stop(0);
314 }
315
316 static void
317 spdk_fuse_shutdown(void)
318 {
319 spdk_fs_unload(g_fs, shutdown_cb, NULL);
320 }
321
322 int main(int argc, char **argv)
323 {
324 struct spdk_app_opts opts = {};
325 int rc = 0;
326
327 if (argc < 4) {
328 fprintf(stderr, "usage: %s <conffile> <bdev name> <mountpoint>\n", argv[0]);
329 exit(1);
330 }
331
332 spdk_app_opts_init(&opts);
333 opts.name = "spdk_fuse";
334 opts.config_file = argv[1];
335 opts.reactor_mask = "0x3";
336 opts.shutdown_cb = spdk_fuse_shutdown;
337
338 g_bdev_name = argv[2];
339 g_mountpoint = argv[3];
340 g_fuse_argc = argc - 2;
341 g_fuse_argv = &argv[2];
342
343 rc = spdk_app_start(&opts, spdk_fuse_run, NULL);
344 spdk_app_fini();
345
346 return rc;
347 }