xref: /spdk/module/blobfs/bdev/blobfs_bdev.c (revision 03e3fc4f5835983a4e6602b4e770922e798ce263)
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_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
146 			     spdk_strerror(rc));
147 
148 		goto invalid;
149 	}
150 
151 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
152 	if (bs_dev == NULL) {
153 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV,  "Failed to create a blobstore block device from bdev desc");
154 		rc = -ENOMEM;
155 		spdk_bdev_close(desc);
156 
157 		goto invalid;
158 	}
159 
160 	spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
161 
162 	return;
163 
164 invalid:
165 	free(ctx);
166 
167 	cb_fn(cb_arg, rc);
168 }
169 
170 void
171 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
172 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
173 {
174 	struct blobfs_bdev_operation_ctx *ctx;
175 	struct spdk_blobfs_opts blobfs_opt;
176 	struct spdk_bs_dev *bs_dev;
177 	struct spdk_bdev_desc *desc;
178 	int rc;
179 
180 	ctx = calloc(1, sizeof(*ctx));
181 	if (ctx == NULL) {
182 		SPDK_ERRLOG("Failed to allocate ctx.\n");
183 		cb_fn(cb_arg, -ENOMEM);
184 
185 		return;
186 	}
187 
188 	ctx->bdev_name = bdev_name;
189 	ctx->cb_fn = cb_fn;
190 	ctx->cb_arg = cb_arg;
191 
192 	/* Creation requires WRITE operation */
193 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
194 	if (rc != 0) {
195 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
196 			     spdk_strerror(rc));
197 
198 		goto invalid;
199 	}
200 
201 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
202 	if (bs_dev == NULL) {
203 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV,  "Failed to create a blobstore block device from bdev desc\n");
204 		rc = -ENOMEM;
205 		spdk_bdev_close(desc);
206 
207 		goto invalid;
208 	}
209 
210 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
211 	if (rc) {
212 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Blobfs base bdev already claimed by another bdev\n");
213 		bs_dev->destroy(bs_dev);
214 
215 		goto invalid;
216 	}
217 
218 	spdk_fs_opts_init(&blobfs_opt);
219 	if (cluster_sz) {
220 		blobfs_opt.cluster_sz = cluster_sz;
221 	}
222 
223 	spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
224 
225 	return;
226 
227 invalid:
228 	free(ctx);
229 
230 	cb_fn(cb_arg, rc);
231 }
232 SPDK_LOG_REGISTER_COMPONENT("blobfs_bdev", SPDK_LOG_BLOBFS_BDEV)
233 #ifdef SPDK_CONFIG_FUSE
234 
235 static void
236 blobfs_bdev_unmount(void *arg)
237 {
238 	struct blobfs_bdev_operation_ctx *ctx = arg;
239 
240 	/* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
241 	spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
242 }
243 
244 static void
245 _blobfs_bdev_mount_fuse_start(void *_ctx)
246 {
247 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
248 	spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn;
249 	int rc;
250 
251 	/* Since function of ctx->cb_fn will be called in this function, set
252 	 * ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb.
253 	 */
254 	ctx->cb_fn = NULL;
255 
256 	rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
257 			       blobfs_bdev_unmount, ctx, &ctx->bfuse);
258 	if (rc != 0) {
259 		SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
260 
261 		/* Return failure state back */
262 		cb_fn(ctx->cb_arg, rc);
263 
264 		blobfs_bdev_unmount(ctx);
265 
266 		return;
267 	}
268 
269 	cb_fn(ctx->cb_arg, 0);
270 }
271 
272 static void
273 _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
274 {
275 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
276 
277 	if (fserrno) {
278 		SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
279 
280 		ctx->cb_fn(ctx->cb_arg, fserrno);
281 		free(ctx);
282 		return;
283 	}
284 
285 	ctx->fs = fs;
286 	ctx->fs_loading_thread = spdk_get_thread();
287 
288 	spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
289 }
290 
291 static void
292 blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
293 			  void *event_ctx)
294 {
295 	struct blobfs_bdev_operation_ctx *ctx = event_ctx;
296 
297 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
298 
299 	if (type == SPDK_BDEV_EVENT_REMOVE) {
300 		blobfs_fuse_stop(ctx->bfuse);
301 	}
302 }
303 
304 void
305 spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
306 		       spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
307 {
308 	struct blobfs_bdev_operation_ctx *ctx;
309 	struct spdk_bs_dev *bs_dev;
310 	struct spdk_bdev_desc *desc;
311 	int rc;
312 
313 	ctx = calloc(1, sizeof(*ctx));
314 	if (ctx == NULL) {
315 		SPDK_ERRLOG("Failed to allocate ctx.\n");
316 		cb_fn(cb_arg, -ENOMEM);
317 
318 		return;
319 	}
320 
321 	ctx->bdev_name = bdev_name;
322 	ctx->mountpoint = mountpoint;
323 	ctx->cb_fn = cb_fn;
324 	ctx->cb_arg = cb_arg;
325 
326 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_fuse_event_cb, ctx, &desc);
327 	if (rc != 0) {
328 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
329 			     spdk_strerror(rc));
330 
331 		goto invalid;
332 	}
333 
334 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
335 	if (bs_dev == NULL) {
336 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV,  "Failed to create a blobstore block device from bdev desc");
337 		rc = -ENOMEM;
338 		spdk_bdev_close(desc);
339 
340 		goto invalid;
341 	}
342 
343 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
344 	if (rc != 0) {
345 		SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Blobfs base bdev already claimed by another bdev\n");
346 		bs_dev->destroy(bs_dev);
347 
348 		goto invalid;
349 	}
350 
351 	spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
352 
353 	return;
354 
355 invalid:
356 	free(ctx);
357 
358 	cb_fn(cb_arg, rc);
359 }
360 
361 #endif
362