Branch data Line data Source code
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
26 : 0 : blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
27 : : void *event_ctx)
28 : : {
29 : 0 : SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
30 : 0 : }
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
54 : 19 : _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
55 : : {
56 : 19 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
57 : :
58 [ + + ]: 19 : if (fserrno) {
59 : 6 : SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
60 : : }
61 : :
62 [ + + ]: 19 : if (ctx->cb_fn) {
63 : 17 : ctx->cb_fn(ctx->cb_arg, fserrno);
64 : : }
65 : :
66 : 19 : free(ctx);
67 : 19 : }
68 : :
69 : : static void
70 : 19 : blobfs_bdev_unload(void *_ctx)
71 : : {
72 : 19 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
73 : :
74 : 19 : spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
75 : 19 : }
76 : :
77 : : static void
78 : 24 : blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
79 : : {
80 : 24 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
81 : :
82 [ + + ]: 24 : if (fserrno) {
83 : 7 : ctx->cb_fn(ctx->cb_arg, fserrno);
84 : 7 : free(ctx);
85 : 7 : return;
86 : : }
87 : :
88 : 17 : ctx->fs = fs;
89 : 17 : spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
90 : : }
91 : :
92 : : void
93 : 15 : 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 : 15 : struct spdk_bs_dev *bs_dev;
98 : : int rc;
99 : :
100 : 15 : ctx = calloc(1, sizeof(*ctx));
101 [ - + ]: 15 : if (ctx == NULL) {
102 : 0 : SPDK_ERRLOG("Failed to allocate ctx.\n");
103 : 0 : cb_fn(cb_arg, -ENOMEM);
104 : :
105 : 0 : return;
106 : : }
107 : :
108 : 15 : ctx->bdev_name = bdev_name;
109 : 15 : ctx->cb_fn = cb_fn;
110 : 15 : ctx->cb_arg = cb_arg;
111 : :
112 : 15 : rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
113 [ + + ]: 15 : if (rc != 0) {
114 [ - + - + ]: 3 : SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
115 : : bdev_name);
116 : :
117 : 3 : goto invalid;
118 : : }
119 : :
120 : 12 : spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
121 : :
122 : 12 : return;
123 : :
124 : 3 : invalid:
125 : 3 : free(ctx);
126 : :
127 : 3 : cb_fn(cb_arg, rc);
128 : : }
129 : :
130 : : void
131 : 18 : 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 : 18 : struct spdk_blobfs_opts blobfs_opt;
136 : 18 : struct spdk_bs_dev *bs_dev;
137 : : int rc;
138 : :
139 : 18 : ctx = calloc(1, sizeof(*ctx));
140 [ - + ]: 18 : if (ctx == NULL) {
141 : 0 : SPDK_ERRLOG("Failed to allocate ctx.\n");
142 : 0 : cb_fn(cb_arg, -ENOMEM);
143 : :
144 : 0 : return;
145 : : }
146 : :
147 : 18 : ctx->bdev_name = bdev_name;
148 : 18 : ctx->cb_fn = cb_fn;
149 : 18 : ctx->cb_arg = cb_arg;
150 : :
151 : 18 : rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
152 [ + + ]: 18 : if (rc) {
153 [ - + - + ]: 3 : SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)\n",
154 : : bdev_name);
155 : :
156 : 3 : goto invalid;
157 : : }
158 : :
159 : 15 : rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
160 [ + + ]: 15 : if (rc) {
161 [ - + - + ]: 3 : SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
162 : 3 : bs_dev->destroy(bs_dev);
163 : :
164 : 3 : goto invalid;
165 : : }
166 : :
167 : 12 : spdk_fs_opts_init(&blobfs_opt);
168 [ + + ]: 12 : if (cluster_sz) {
169 : 9 : blobfs_opt.cluster_sz = cluster_sz;
170 : : }
171 : :
172 : 12 : spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
173 : :
174 : 12 : return;
175 : :
176 : 6 : invalid:
177 : 6 : free(ctx);
178 : :
179 : 6 : cb_fn(cb_arg, rc);
180 : : }
181 : 2354 : SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)
182 : : #ifdef SPDK_CONFIG_FUSE
183 : :
184 : : static void
185 : 2 : blobfs_bdev_unmount(void *arg)
186 : : {
187 : 2 : struct blobfs_bdev_operation_ctx *ctx = arg;
188 : :
189 : : /* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
190 : 2 : spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
191 : 2 : }
192 : :
193 : : static void
194 : 2 : _blobfs_bdev_mount_fuse_start(void *_ctx)
195 : : {
196 : 2 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
197 : 2 : 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 : 2 : ctx->cb_fn = NULL;
204 : :
205 : 2 : rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
206 : : blobfs_bdev_unmount, ctx, &ctx->bfuse);
207 [ - + ]: 2 : if (rc != 0) {
208 : 0 : SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
209 : :
210 : : /* Return failure state back */
211 : 0 : cb_fn(ctx->cb_arg, rc);
212 : :
213 : 0 : blobfs_bdev_unmount(ctx);
214 : :
215 : 0 : return;
216 : : }
217 : :
218 : 2 : cb_fn(ctx->cb_arg, 0);
219 : : }
220 : :
221 : : static void
222 : 2 : _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
223 : : {
224 : 2 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
225 : :
226 [ - + ]: 2 : if (fserrno) {
227 : 0 : SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
228 : :
229 : 0 : ctx->cb_fn(ctx->cb_arg, fserrno);
230 : 0 : free(ctx);
231 : 0 : return;
232 : : }
233 : :
234 : 2 : ctx->fs = fs;
235 : 2 : ctx->fs_loading_thread = spdk_get_thread();
236 : :
237 : 2 : spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
238 : : }
239 : :
240 : : static void
241 : 0 : blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
242 : : void *event_ctx)
243 : : {
244 : 0 : struct blobfs_bdev_operation_ctx *ctx = event_ctx;
245 : :
246 : 0 : SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
247 : :
248 [ # # ]: 0 : if (type == SPDK_BDEV_EVENT_REMOVE) {
249 : 0 : blobfs_fuse_stop(ctx->bfuse);
250 : : }
251 : 0 : }
252 : :
253 : : void
254 : 2 : 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 : 2 : struct spdk_bs_dev *bs_dev;
259 : : int rc;
260 : :
261 : 2 : ctx = calloc(1, sizeof(*ctx));
262 [ - + ]: 2 : if (ctx == NULL) {
263 : 0 : SPDK_ERRLOG("Failed to allocate ctx.\n");
264 : 0 : cb_fn(cb_arg, -ENOMEM);
265 : :
266 : 0 : return;
267 : : }
268 : :
269 : 2 : ctx->bdev_name = bdev_name;
270 : 2 : ctx->mountpoint = mountpoint;
271 : 2 : ctx->cb_fn = cb_fn;
272 : 2 : ctx->cb_arg = cb_arg;
273 : :
274 : 2 : rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_fuse_event_cb, ctx, &bs_dev);
275 [ - + ]: 2 : if (rc != 0) {
276 [ # # # # ]: 0 : SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
277 : : bdev_name);
278 : :
279 : 0 : goto invalid;
280 : : }
281 : :
282 : 2 : rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
283 [ - + ]: 2 : if (rc != 0) {
284 [ # # # # ]: 0 : SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
285 : 0 : bs_dev->destroy(bs_dev);
286 : :
287 : 0 : goto invalid;
288 : : }
289 : :
290 : 2 : spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
291 : :
292 : 2 : return;
293 : :
294 : 0 : invalid:
295 : 0 : free(ctx);
296 : :
297 : 0 : cb_fn(cb_arg, rc);
298 : : }
299 : :
300 : : #else /* SPDK_CONFIG_FUSE */
301 : :
302 : : void
303 : 0 : spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
304 : : spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
305 : : {
306 : 0 : SPDK_ERRLOG("spdk_blobfs_bdev_mount() is unsupported\n");
307 : 0 : cb_fn(cb_arg, -ENOTSUP);
308 : 0 : }
309 : :
310 : : #endif
|