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