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 6 : _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
55 : {
56 6 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
57 :
58 6 : if (fserrno) {
59 2 : SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
60 : }
61 :
62 6 : if (ctx->cb_fn) {
63 4 : ctx->cb_fn(ctx->cb_arg, fserrno);
64 : }
65 :
66 6 : free(ctx);
67 6 : }
68 :
69 : static void
70 6 : blobfs_bdev_unload(void *_ctx)
71 : {
72 6 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
73 :
74 6 : spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
75 6 : }
76 :
77 : static void
78 6 : blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
79 : {
80 6 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
81 :
82 6 : if (fserrno) {
83 2 : ctx->cb_fn(ctx->cb_arg, fserrno);
84 2 : free(ctx);
85 2 : return;
86 : }
87 :
88 4 : ctx->fs = fs;
89 4 : spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
90 : }
91 :
92 : void
93 4 : 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 4 : struct spdk_bs_dev *bs_dev;
98 : int rc;
99 :
100 4 : ctx = calloc(1, sizeof(*ctx));
101 4 : 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 4 : ctx->bdev_name = bdev_name;
109 4 : ctx->cb_fn = cb_fn;
110 4 : ctx->cb_arg = cb_arg;
111 :
112 4 : rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
113 4 : if (rc != 0) {
114 1 : SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
115 : bdev_name);
116 :
117 1 : goto invalid;
118 : }
119 :
120 3 : spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
121 :
122 3 : return;
123 :
124 1 : invalid:
125 1 : free(ctx);
126 :
127 1 : cb_fn(cb_arg, rc);
128 : }
129 :
130 : void
131 5 : 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 5 : struct spdk_blobfs_opts blobfs_opt;
136 5 : struct spdk_bs_dev *bs_dev;
137 : int rc;
138 :
139 5 : ctx = calloc(1, sizeof(*ctx));
140 5 : 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 5 : ctx->bdev_name = bdev_name;
148 5 : ctx->cb_fn = cb_fn;
149 5 : ctx->cb_arg = cb_arg;
150 :
151 5 : rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
152 5 : if (rc) {
153 1 : SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)\n",
154 : bdev_name);
155 :
156 1 : goto invalid;
157 : }
158 :
159 4 : rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
160 4 : if (rc) {
161 1 : SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
162 1 : bs_dev->destroy(bs_dev);
163 :
164 1 : goto invalid;
165 : }
166 :
167 3 : spdk_fs_opts_init(&blobfs_opt);
168 3 : if (cluster_sz) {
169 3 : blobfs_opt.cluster_sz = cluster_sz;
170 : }
171 :
172 3 : spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
173 :
174 3 : return;
175 :
176 2 : invalid:
177 2 : free(ctx);
178 :
179 2 : cb_fn(cb_arg, rc);
180 : }
181 1 : 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 1 : SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
209 :
210 : /* Return failure state back */
211 1 : cb_fn(ctx->cb_arg, rc);
212 :
213 1 : blobfs_bdev_unmount(ctx);
214 :
215 1 : return;
216 : }
217 :
218 1 : cb_fn(ctx->cb_arg, 0);
219 : }
220 :
221 : static void
222 3 : _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
223 : {
224 3 : struct blobfs_bdev_operation_ctx *ctx = _ctx;
225 :
226 3 : if (fserrno) {
227 1 : SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
228 :
229 1 : ctx->cb_fn(ctx->cb_arg, fserrno);
230 1 : free(ctx);
231 1 : 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 5 : 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 5 : struct spdk_bs_dev *bs_dev;
259 : int rc;
260 :
261 5 : ctx = calloc(1, sizeof(*ctx));
262 5 : 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 5 : ctx->bdev_name = bdev_name;
270 5 : ctx->mountpoint = mountpoint;
271 5 : ctx->cb_fn = cb_fn;
272 5 : ctx->cb_arg = cb_arg;
273 :
274 5 : rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_fuse_event_cb, ctx, &bs_dev);
275 5 : if (rc != 0) {
276 1 : SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
277 : bdev_name);
278 :
279 1 : goto invalid;
280 : }
281 :
282 4 : rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
283 4 : if (rc != 0) {
284 1 : SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
285 1 : bs_dev->destroy(bs_dev);
286 :
287 1 : goto invalid;
288 : }
289 :
290 3 : spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
291 :
292 3 : return;
293 :
294 2 : invalid:
295 2 : free(ctx);
296 :
297 2 : 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
|