xref: /spdk/module/blobfs/bdev/blobfs_bdev.c (revision ceea3088870a3919d6bdfe61d7adba11b9733fb7)
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 "blobfs_fuse.h"
47 
48 /* Dummy bdev module used to to claim bdevs. */
49 static struct spdk_bdev_module blobfs_bdev_module = {
50 	.name	= "blobfs",
51 };
52 
53 static void
54 blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
55 		     void *event_ctx)
56 {
57 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
58 }
59 
60 struct blobfs_bdev_operation_ctx {
61 	const char *bdev_name;
62 	struct spdk_filesystem *fs;
63 
64 	/* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb.
65 	 * cb_fn should be set NULL after its being called, in order to avoid repeated
66 	 * calling in _blobfs_bdev_unload_cb.
67 	 */
68 	spdk_blobfs_bdev_op_complete cb_fn;
69 	void *cb_arg;
70 
71 	/* Variables for mount operation */
72 	const char *mountpoint;
73 	struct spdk_thread *fs_loading_thread;
74 
75 	/* Used in bdev_event_cb to do some proper operations on blobfs_fuse for
76 	 * asynchronous event of the backend bdev.
77 	 */
78 	struct spdk_blobfs_fuse *bfuse;
79 };
80 
81 static void
82 _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
83 {
84 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
85 
86 	if (fserrno) {
87 		SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
88 	}
89 
90 	if (ctx->cb_fn) {
91 		ctx->cb_fn(ctx->cb_arg, fserrno);
92 	}
93 
94 	free(ctx);
95 }
96 
97 static void
98 blobfs_bdev_unload(void *_ctx)
99 {
100 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
101 
102 	spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
103 }
104 
105 static void
106 blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
107 {
108 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
109 
110 	if (fserrno) {
111 		ctx->cb_fn(ctx->cb_arg, fserrno);
112 		free(ctx);
113 		return;
114 	}
115 
116 	ctx->fs = fs;
117 	spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
118 }
119 
120 void
121 spdk_blobfs_bdev_detect(const char *bdev_name,
122 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
123 {
124 	struct blobfs_bdev_operation_ctx *ctx;
125 	struct spdk_bs_dev *bs_dev;
126 	struct spdk_bdev_desc *desc;
127 	int rc;
128 
129 	ctx = calloc(1, sizeof(*ctx));
130 	if (ctx == NULL) {
131 		SPDK_ERRLOG("Failed to allocate ctx.\n");
132 		cb_fn(cb_arg, -ENOMEM);
133 
134 		return;
135 	}
136 
137 	ctx->bdev_name = bdev_name;
138 	ctx->cb_fn = cb_fn;
139 	ctx->cb_arg = cb_arg;
140 
141 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
142 	if (rc != 0) {
143 		SPDK_INFOLOG(blobfs_bdev, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
144 			     spdk_strerror(rc));
145 
146 		goto invalid;
147 	}
148 
149 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
150 	if (bs_dev == NULL) {
151 		SPDK_INFOLOG(blobfs_bdev,  "Failed to create a blobstore block device from bdev desc");
152 		rc = -ENOMEM;
153 		spdk_bdev_close(desc);
154 
155 		goto invalid;
156 	}
157 
158 	spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
159 
160 	return;
161 
162 invalid:
163 	free(ctx);
164 
165 	cb_fn(cb_arg, rc);
166 }
167 
168 void
169 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
170 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
171 {
172 	struct blobfs_bdev_operation_ctx *ctx;
173 	struct spdk_blobfs_opts blobfs_opt;
174 	struct spdk_bs_dev *bs_dev;
175 	struct spdk_bdev_desc *desc;
176 	int rc;
177 
178 	ctx = calloc(1, sizeof(*ctx));
179 	if (ctx == NULL) {
180 		SPDK_ERRLOG("Failed to allocate ctx.\n");
181 		cb_fn(cb_arg, -ENOMEM);
182 
183 		return;
184 	}
185 
186 	ctx->bdev_name = bdev_name;
187 	ctx->cb_fn = cb_fn;
188 	ctx->cb_arg = cb_arg;
189 
190 	/* Creation requires WRITE operation */
191 	rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
192 	if (rc != 0) {
193 		SPDK_INFOLOG(blobfs_bdev, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
194 			     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(blobfs_bdev,  "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(blobfs_bdev, "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 SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)
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 = 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 		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(blobfs_bdev, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
327 			     spdk_strerror(rc));
328 
329 		goto invalid;
330 	}
331 
332 	bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
333 	if (bs_dev == NULL) {
334 		SPDK_INFOLOG(blobfs_bdev,  "Failed to create a blobstore block device from bdev desc");
335 		rc = -ENOMEM;
336 		spdk_bdev_close(desc);
337 
338 		goto invalid;
339 	}
340 
341 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
342 	if (rc != 0) {
343 		SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
344 		bs_dev->destroy(bs_dev);
345 
346 		goto invalid;
347 	}
348 
349 	spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
350 
351 	return;
352 
353 invalid:
354 	free(ctx);
355 
356 	cb_fn(cb_arg, rc);
357 }
358 
359 #endif
360