xref: /spdk/module/blobfs/bdev/blobfs_bdev.c (revision 94a84ae98590bea46939eb1dcd7a9876bd393b54)
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 #include "spdk/blobfs.h"
36 #include "spdk/bdev.h"
37 #include "spdk/bdev_module.h"
38 #include "spdk/event.h"
39 #include "spdk/blob_bdev.h"
40 #include "spdk/blobfs_bdev.h"
41 #include "spdk/log.h"
42 #include "spdk/string.h"
43 #include "spdk/rpc.h"
44 #include "spdk/util.h"
45 
46 #include "spdk_internal/log.h"
47 
48 #include "blobfs_fuse.h"
49 
50 /* Dummy bdev module used to to claim bdevs. */
51 static struct spdk_bdev_module blobfs_bdev_module = {
52 	.name	= "blobfs",
53 };
54 
55 static void
56 blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
57 		     void *event_ctx)
58 {
59 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
60 }
61 
62 struct blobfs_bdev_operation_ctx {
63 	const char *bdev_name;
64 	struct spdk_filesystem *fs;
65 
66 	/* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb.
67 	 * cb_fn should be set NULL after its being called, in order to avoid repeated
68 	 * calling in _blobfs_bdev_unload_cb.
69 	 */
70 	spdk_blobfs_bdev_op_complete cb_fn;
71 	void *cb_arg;
72 
73 	/* Variables for mount operation */
74 	const char *mountpoint;
75 	struct spdk_thread *fs_loading_thread;
76 
77 	/* Used in bdev_event_cb to do some proper operations on blobfs_fuse for
78 	 * asynchronous event of the backend bdev.
79 	 */
80 	struct spdk_blobfs_fuse *bfuse;
81 };
82 
83 static void
84 _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
85 {
86 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
87 
88 	if (fserrno) {
89 		SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
90 	}
91 
92 	if (ctx->cb_fn) {
93 		ctx->cb_fn(ctx->cb_arg, fserrno);
94 	}
95 
96 	free(ctx);
97 }
98 
99 static void
100 blobfs_bdev_unload(void *_ctx)
101 {
102 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
103 
104 	spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
105 }
106 
107 static void
108 blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
109 {
110 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
111 
112 	if (fserrno) {
113 		ctx->cb_fn(ctx->cb_arg, fserrno);
114 		free(ctx);
115 		return;
116 	}
117 
118 	ctx->fs = fs;
119 	spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
120 }
121 
122 void
123 spdk_blobfs_bdev_detect(const char *bdev_name,
124 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
125 {
126 	struct blobfs_bdev_operation_ctx *ctx;
127 	struct spdk_bs_dev *bs_dev;
128 	struct spdk_bdev_desc *desc;
129 	int rc;
130 
131 	ctx = calloc(1, sizeof(*ctx));
132 	if (ctx == NULL) {
133 		SPDK_ERRLOG("Failed to allocate ctx.\n");
134 		cb_fn(cb_arg, -ENOMEM);
135 
136 		return;
137 	}
138 
139 	ctx->bdev_name = bdev_name;
140 	ctx->cb_fn = cb_fn;
141 	ctx->cb_arg = cb_arg;
142 
143 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
144 	if (rc != 0) {
145 		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc));
146 
147 		goto invalid;
148 	}
149 
150 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
151 	if (bs_dev == NULL) {
152 		SPDK_INFOLOG(SPDK_LOG_BLOBFS,  "Failed to create a blobstore block device from bdev desc");
153 		rc = -ENOMEM;
154 		spdk_bdev_close(desc);
155 
156 		goto invalid;
157 	}
158 
159 	spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
160 
161 	return;
162 
163 invalid:
164 	free(ctx);
165 
166 	cb_fn(cb_arg, rc);
167 }
168 
169 void
170 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
171 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
172 {
173 	struct blobfs_bdev_operation_ctx *ctx;
174 	struct spdk_blobfs_opts blobfs_opt;
175 	struct spdk_bs_dev *bs_dev;
176 	struct spdk_bdev_desc *desc;
177 	int rc;
178 
179 	ctx = calloc(1, sizeof(*ctx));
180 	if (ctx == NULL) {
181 		SPDK_ERRLOG("Failed to allocate ctx.\n");
182 		cb_fn(cb_arg, -ENOMEM);
183 
184 		return;
185 	}
186 
187 	ctx->bdev_name = bdev_name;
188 	ctx->cb_fn = cb_fn;
189 	ctx->cb_arg = cb_arg;
190 
191 	/* Creation requires WRITE operation */
192 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
193 	if (rc != 0) {
194 		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc));
195 
196 		goto invalid;
197 	}
198 
199 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
200 	if (bs_dev == NULL) {
201 		SPDK_INFOLOG(SPDK_LOG_BLOBFS,  "Failed to create a blobstore block device from bdev desc\n");
202 		rc = -ENOMEM;
203 		spdk_bdev_close(desc);
204 
205 		goto invalid;
206 	}
207 
208 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
209 	if (rc) {
210 		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Blobfs base bdev already claimed by another bdev\n");
211 		bs_dev->destroy(bs_dev);
212 
213 		goto invalid;
214 	}
215 
216 	spdk_fs_opts_init(&blobfs_opt);
217 	if (cluster_sz) {
218 		blobfs_opt.cluster_sz = cluster_sz;
219 	}
220 
221 	spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
222 
223 	return;
224 
225 invalid:
226 	free(ctx);
227 
228 	cb_fn(cb_arg, rc);
229 }
230 
231 #ifdef SPDK_CONFIG_FUSE
232 
233 static void
234 blobfs_bdev_unmount(void *arg)
235 {
236 	struct blobfs_bdev_operation_ctx *ctx = arg;
237 
238 	/* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
239 	spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
240 }
241 
242 static void
243 _blobfs_bdev_mount_fuse_start(void *_ctx)
244 {
245 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
246 	spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn;
247 	int rc;
248 
249 	/* Since function of ctx->cb_fn will be called in this function, set
250 	 * ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb.
251 	 */
252 	ctx->cb_fn = NULL;
253 
254 	rc = spdk_blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
255 				    blobfs_bdev_unmount, ctx, &ctx->bfuse);
256 	if (rc != 0) {
257 		SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
258 
259 		/* Return failure state back */
260 		cb_fn(ctx->cb_arg, rc);
261 
262 		blobfs_bdev_unmount(ctx);
263 
264 		return;
265 	}
266 
267 	cb_fn(ctx->cb_arg, 0);
268 }
269 
270 static void
271 _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
272 {
273 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
274 
275 	if (fserrno) {
276 		SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
277 
278 		ctx->cb_fn(ctx->cb_arg, fserrno);
279 		free(ctx);
280 		return;
281 	}
282 
283 	ctx->fs = fs;
284 	ctx->fs_loading_thread = spdk_get_thread();
285 
286 	spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
287 }
288 
289 static void
290 blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
291 			  void *event_ctx)
292 {
293 	struct blobfs_bdev_operation_ctx *ctx = event_ctx;
294 
295 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
296 
297 	if (type == SPDK_BDEV_EVENT_REMOVE) {
298 		spdk_blobfs_fuse_stop(ctx->bfuse);
299 	}
300 }
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 	struct blobfs_bdev_operation_ctx *ctx;
307 	struct spdk_bs_dev *bs_dev;
308 	struct spdk_bdev_desc *desc;
309 	int rc;
310 
311 	ctx = calloc(1, sizeof(*ctx));
312 	if (ctx == NULL) {
313 		SPDK_ERRLOG("Failed to allocate ctx.\n");
314 		cb_fn(cb_arg, -ENOMEM);
315 
316 		return;
317 	}
318 
319 	ctx->bdev_name = bdev_name;
320 	ctx->mountpoint = mountpoint;
321 	ctx->cb_fn = cb_fn;
322 	ctx->cb_arg = cb_arg;
323 
324 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_fuse_event_cb, ctx, &desc);
325 	if (rc != 0) {
326 		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc));
327 
328 		goto invalid;
329 	}
330 
331 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
332 	if (bs_dev == NULL) {
333 		SPDK_INFOLOG(SPDK_LOG_BLOBFS,  "Failed to create a blobstore block device from bdev desc");
334 		rc = -ENOMEM;
335 		spdk_bdev_close(desc);
336 
337 		goto invalid;
338 	}
339 
340 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
341 	if (rc != 0) {
342 		SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Blobfs base bdev already claimed by another bdev\n");
343 		bs_dev->destroy(bs_dev);
344 
345 		goto invalid;
346 	}
347 
348 	spdk_fs_load(bs_dev, spdk_blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
349 
350 	return;
351 
352 invalid:
353 	free(ctx);
354 
355 	cb_fn(cb_arg, rc);
356 }
357 
358 #endif
359