]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/test/blobfs/fuse/fuse.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / blobfs / fuse / fuse.c
CommitLineData
7c673cae
FG
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 */
7c673cae 33
11fdf7f2
TL
34#include "spdk/stdinc.h"
35
36#define FUSE_USE_VERSION 30
7c673cae
FG
37#include "fuse3/fuse.h"
38#include "fuse3/fuse_lowlevel.h"
39
7c673cae
FG
40#include "spdk/blobfs.h"
41#include "spdk/bdev.h"
42#include "spdk/event.h"
11fdf7f2 43#include "spdk/thread.h"
7c673cae
FG
44#include "spdk/blob_bdev.h"
45#include "spdk/log.h"
46
47struct fuse *g_fuse;
48char *g_bdev_name;
49char *g_mountpoint;
50pthread_t g_fuse_thread;
51
52struct spdk_bs_dev *g_bs_dev;
53struct spdk_filesystem *g_fs;
9f95a23c 54struct spdk_fs_thread_ctx *g_channel;
7c673cae
FG
55struct spdk_file *g_file;
56int g_fserrno;
57int g_fuse_argc = 0;
58char **g_fuse_argv = NULL;
59
60static 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
69static 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
78static int
79spdk_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
11fdf7f2 90 rc = spdk_fs_file_stat(g_fs, g_channel, path, &stat);
7c673cae
FG
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
100static int
101spdk_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);
11fdf7f2 117 filler(buf, &filename[1], NULL, 0, 0);
7c673cae
FG
118 }
119
120 return 0;
121}
122
123static int
124spdk_fuse_mknod(const char *path, mode_t mode, dev_t rdev)
125{
11fdf7f2 126 return spdk_fs_create_file(g_fs, g_channel, path);
7c673cae
FG
127}
128
129static int
130spdk_fuse_unlink(const char *path)
131{
11fdf7f2 132 return spdk_fs_delete_file(g_fs, g_channel, path);
7c673cae
FG
133}
134
135static int
136spdk_fuse_truncate(const char *path, off_t size, struct fuse_file_info *fi)
137{
138 struct spdk_file *file;
139 int rc;
140
11fdf7f2
TL
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);
7c673cae
FG
147 if (rc != 0) {
148 return -rc;
149 }
150
7c673cae
FG
151 spdk_file_close(file, g_channel);
152
153 return 0;
154}
155
156static int
157spdk_fuse_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi)
158{
159 return 0;
160}
161
162static int
163spdk_fuse_open(const char *path, struct fuse_file_info *info)
164{
165 struct spdk_file *file;
166 int rc;
167
11fdf7f2 168 rc = spdk_fs_open_file(g_fs, g_channel, path, 0, &file);
7c673cae
FG
169 if (rc != 0) {
170 return -rc;
171 }
172
173 info->fh = (uintptr_t)file;
174 return 0;
175}
176
177static int
178spdk_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
185static int
186spdk_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
193static int
194spdk_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
208static int
209spdk_fuse_flush(const char *path, struct fuse_file_info *info)
210{
211 return 0;
212}
213
214static int
215spdk_fuse_fsync(const char *path, int datasync, struct fuse_file_info *info)
216{
217 return 0;
218}
219
220static int
221spdk_fuse_rename(const char *old_path, const char *new_path, unsigned int flags)
222{
11fdf7f2 223 return spdk_fs_rename_file(g_fs, g_channel, old_path, new_path);
7c673cae
FG
224}
225
226static 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
242static void
243construct_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
11fdf7f2 253 g_bs_dev = spdk_bdev_create_bs_dev(bdev, NULL, NULL);
7c673cae 254
11fdf7f2 255 printf("Mounting BlobFS on bdev %s\n", spdk_bdev_get_name(bdev));
7c673cae
FG
256}
257
258static void
259start_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
289static void
290init_cb(void *ctx, struct spdk_filesystem *fs, int fserrno)
291{
292 struct spdk_event *event;
293
294 g_fs = fs;
9f95a23c 295 g_channel = spdk_fs_alloc_thread_ctx(g_fs);
7c673cae
FG
296 event = spdk_event_allocate(1, start_fuse_fn, NULL, NULL);
297 spdk_event_call(event);
298}
299
300static void
9f95a23c 301spdk_fuse_run(void *arg1)
7c673cae
FG
302{
303 construct_targets();
304 spdk_fs_load(g_bs_dev, __send_request, init_cb, NULL);
305}
306
307static void
308shutdown_cb(void *ctx, int fserrno)
309{
310 fuse_session_exit(fuse_get_session(g_fuse));
311 pthread_kill(g_fuse_thread, SIGINT);
9f95a23c 312 spdk_fs_free_thread_ctx(g_channel);
7c673cae
FG
313 spdk_app_stop(0);
314}
315
316static void
317spdk_fuse_shutdown(void)
318{
319 spdk_fs_unload(g_fs, shutdown_cb, NULL);
320}
321
322int main(int argc, char **argv)
323{
324 struct spdk_app_opts opts = {};
11fdf7f2 325 int rc = 0;
7c673cae
FG
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";
7c673cae 336 opts.shutdown_cb = spdk_fuse_shutdown;
7c673cae
FG
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
9f95a23c 343 rc = spdk_app_start(&opts, spdk_fuse_run, NULL);
7c673cae
FG
344 spdk_app_fini();
345
11fdf7f2 346 return rc;
7c673cae 347}