1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2019 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "spdk/stdinc.h"
7 #include "spdk/blobfs.h"
8 #include "spdk/bdev.h"
9 #include "spdk/bdev_module.h"
10 #include "spdk/event.h"
11 #include "spdk/blob_bdev.h"
12 #include "spdk/blobfs_bdev.h"
13 #include "spdk/log.h"
14 #include "spdk/string.h"
15 #include "spdk/rpc.h"
16 #include "spdk/util.h"
17
18 #include "blobfs_fuse.h"
19
20 /* Dummy bdev module used to to claim bdevs. */
21 static struct spdk_bdev_module blobfs_bdev_module = {
22 .name = "blobfs",
23 };
24
25 static void
blobfs_bdev_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)26 blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
27 void *event_ctx)
28 {
29 SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
30 }
31
32 struct blobfs_bdev_operation_ctx {
33 const char *bdev_name;
34 struct spdk_filesystem *fs;
35
36 /* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb.
37 * cb_fn should be set NULL after its being called, in order to avoid repeated
38 * calling in _blobfs_bdev_unload_cb.
39 */
40 spdk_blobfs_bdev_op_complete cb_fn;
41 void *cb_arg;
42
43 /* Variables for mount operation */
44 const char *mountpoint;
45 struct spdk_thread *fs_loading_thread;
46
47 /* Used in bdev_event_cb to do some proper operations on blobfs_fuse for
48 * asynchronous event of the backend bdev.
49 */
50 struct spdk_blobfs_fuse *bfuse;
51 };
52
53 static void
_blobfs_bdev_unload_cb(void * _ctx,int fserrno)54 _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
55 {
56 struct blobfs_bdev_operation_ctx *ctx = _ctx;
57
58 if (fserrno) {
59 SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
60 }
61
62 if (ctx->cb_fn) {
63 ctx->cb_fn(ctx->cb_arg, fserrno);
64 }
65
66 free(ctx);
67 }
68
69 static void
blobfs_bdev_unload(void * _ctx)70 blobfs_bdev_unload(void *_ctx)
71 {
72 struct blobfs_bdev_operation_ctx *ctx = _ctx;
73
74 spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
75 }
76
77 static void
blobfs_bdev_load_cb_to_unload(void * _ctx,struct spdk_filesystem * fs,int fserrno)78 blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
79 {
80 struct blobfs_bdev_operation_ctx *ctx = _ctx;
81
82 if (fserrno) {
83 ctx->cb_fn(ctx->cb_arg, fserrno);
84 free(ctx);
85 return;
86 }
87
88 ctx->fs = fs;
89 spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
90 }
91
92 void
spdk_blobfs_bdev_detect(const char * bdev_name,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)93 spdk_blobfs_bdev_detect(const char *bdev_name,
94 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
95 {
96 struct blobfs_bdev_operation_ctx *ctx;
97 struct spdk_bs_dev *bs_dev;
98 int rc;
99
100 ctx = calloc(1, sizeof(*ctx));
101 if (ctx == NULL) {
102 SPDK_ERRLOG("Failed to allocate ctx.\n");
103 cb_fn(cb_arg, -ENOMEM);
104
105 return;
106 }
107
108 ctx->bdev_name = bdev_name;
109 ctx->cb_fn = cb_fn;
110 ctx->cb_arg = cb_arg;
111
112 rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
113 if (rc != 0) {
114 SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
115 bdev_name);
116
117 goto invalid;
118 }
119
120 spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
121
122 return;
123
124 invalid:
125 free(ctx);
126
127 cb_fn(cb_arg, rc);
128 }
129
130 void
spdk_blobfs_bdev_create(const char * bdev_name,uint32_t cluster_sz,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)131 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
132 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
133 {
134 struct blobfs_bdev_operation_ctx *ctx;
135 struct spdk_blobfs_opts blobfs_opt;
136 struct spdk_bs_dev *bs_dev;
137 int rc;
138
139 ctx = calloc(1, sizeof(*ctx));
140 if (ctx == NULL) {
141 SPDK_ERRLOG("Failed to allocate ctx.\n");
142 cb_fn(cb_arg, -ENOMEM);
143
144 return;
145 }
146
147 ctx->bdev_name = bdev_name;
148 ctx->cb_fn = cb_fn;
149 ctx->cb_arg = cb_arg;
150
151 rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
152 if (rc) {
153 SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)\n",
154 bdev_name);
155
156 goto invalid;
157 }
158
159 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
160 if (rc) {
161 SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
162 bs_dev->destroy(bs_dev);
163
164 goto invalid;
165 }
166
167 spdk_fs_opts_init(&blobfs_opt);
168 if (cluster_sz) {
169 blobfs_opt.cluster_sz = cluster_sz;
170 }
171
172 spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
173
174 return;
175
176 invalid:
177 free(ctx);
178
179 cb_fn(cb_arg, rc);
180 }
SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)181 SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)
182 #ifdef SPDK_CONFIG_FUSE
183
184 static void
185 blobfs_bdev_unmount(void *arg)
186 {
187 struct blobfs_bdev_operation_ctx *ctx = arg;
188
189 /* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
190 spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
191 }
192
193 static void
_blobfs_bdev_mount_fuse_start(void * _ctx)194 _blobfs_bdev_mount_fuse_start(void *_ctx)
195 {
196 struct blobfs_bdev_operation_ctx *ctx = _ctx;
197 spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn;
198 int rc;
199
200 /* Since function of ctx->cb_fn will be called in this function, set
201 * ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb.
202 */
203 ctx->cb_fn = NULL;
204
205 rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
206 blobfs_bdev_unmount, ctx, &ctx->bfuse);
207 if (rc != 0) {
208 SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
209
210 /* Return failure state back */
211 cb_fn(ctx->cb_arg, rc);
212
213 blobfs_bdev_unmount(ctx);
214
215 return;
216 }
217
218 cb_fn(ctx->cb_arg, 0);
219 }
220
221 static void
_blobfs_bdev_mount_load_cb(void * _ctx,struct spdk_filesystem * fs,int fserrno)222 _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
223 {
224 struct blobfs_bdev_operation_ctx *ctx = _ctx;
225
226 if (fserrno) {
227 SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
228
229 ctx->cb_fn(ctx->cb_arg, fserrno);
230 free(ctx);
231 return;
232 }
233
234 ctx->fs = fs;
235 ctx->fs_loading_thread = spdk_get_thread();
236
237 spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
238 }
239
240 static void
blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)241 blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
242 void *event_ctx)
243 {
244 struct blobfs_bdev_operation_ctx *ctx = event_ctx;
245
246 SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
247
248 if (type == SPDK_BDEV_EVENT_REMOVE) {
249 blobfs_fuse_stop(ctx->bfuse);
250 }
251 }
252
253 void
spdk_blobfs_bdev_mount(const char * bdev_name,const char * mountpoint,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)254 spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
255 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
256 {
257 struct blobfs_bdev_operation_ctx *ctx;
258 struct spdk_bs_dev *bs_dev;
259 int rc;
260
261 ctx = calloc(1, sizeof(*ctx));
262 if (ctx == NULL) {
263 SPDK_ERRLOG("Failed to allocate ctx.\n");
264 cb_fn(cb_arg, -ENOMEM);
265
266 return;
267 }
268
269 ctx->bdev_name = bdev_name;
270 ctx->mountpoint = mountpoint;
271 ctx->cb_fn = cb_fn;
272 ctx->cb_arg = cb_arg;
273
274 rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_fuse_event_cb, ctx, &bs_dev);
275 if (rc != 0) {
276 SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
277 bdev_name);
278
279 goto invalid;
280 }
281
282 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
283 if (rc != 0) {
284 SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
285 bs_dev->destroy(bs_dev);
286
287 goto invalid;
288 }
289
290 spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
291
292 return;
293
294 invalid:
295 free(ctx);
296
297 cb_fn(cb_arg, rc);
298 }
299
300 #else /* SPDK_CONFIG_FUSE */
301
302 void
303 spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
304 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
305 {
306 SPDK_ERRLOG("spdk_blobfs_bdev_mount() is unsupported\n");
307 cb_fn(cb_arg, -ENOTSUP);
308 }
309
310 #endif
311