xref: /spdk/module/blobfs/bdev/blobfs_bdev.c (revision 86ba16c39c091790f79e99a033db86b6fd502606)
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
blobfs_bdev_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)26 blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
27 		     void *event_ctx)
28 {
29 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
30 }
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
_blobfs_bdev_unload_cb(void * _ctx,int fserrno)54 _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
55 {
56 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
57 
58 	if (fserrno) {
59 		SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
60 	}
61 
62 	if (ctx->cb_fn) {
63 		ctx->cb_fn(ctx->cb_arg, fserrno);
64 	}
65 
66 	free(ctx);
67 }
68 
69 static void
blobfs_bdev_unload(void * _ctx)70 blobfs_bdev_unload(void *_ctx)
71 {
72 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
73 
74 	spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
75 }
76 
77 static void
blobfs_bdev_load_cb_to_unload(void * _ctx,struct spdk_filesystem * fs,int fserrno)78 blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
79 {
80 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
81 
82 	if (fserrno) {
83 		ctx->cb_fn(ctx->cb_arg, fserrno);
84 		free(ctx);
85 		return;
86 	}
87 
88 	ctx->fs = fs;
89 	spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
90 }
91 
92 void
spdk_blobfs_bdev_detect(const char * bdev_name,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)93 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 	struct spdk_bs_dev *bs_dev;
98 	int rc;
99 
100 	ctx = calloc(1, sizeof(*ctx));
101 	if (ctx == NULL) {
102 		SPDK_ERRLOG("Failed to allocate ctx.\n");
103 		cb_fn(cb_arg, -ENOMEM);
104 
105 		return;
106 	}
107 
108 	ctx->bdev_name = bdev_name;
109 	ctx->cb_fn = cb_fn;
110 	ctx->cb_arg = cb_arg;
111 
112 	rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
113 	if (rc != 0) {
114 		SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
115 			     bdev_name);
116 
117 		goto invalid;
118 	}
119 
120 	spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
121 
122 	return;
123 
124 invalid:
125 	free(ctx);
126 
127 	cb_fn(cb_arg, rc);
128 }
129 
130 void
spdk_blobfs_bdev_create(const char * bdev_name,uint32_t cluster_sz,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)131 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 	struct spdk_blobfs_opts blobfs_opt;
136 	struct spdk_bs_dev *bs_dev;
137 	int rc;
138 
139 	ctx = calloc(1, sizeof(*ctx));
140 	if (ctx == NULL) {
141 		SPDK_ERRLOG("Failed to allocate ctx.\n");
142 		cb_fn(cb_arg, -ENOMEM);
143 
144 		return;
145 	}
146 
147 	ctx->bdev_name = bdev_name;
148 	ctx->cb_fn = cb_fn;
149 	ctx->cb_arg = cb_arg;
150 
151 	rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
152 	if (rc) {
153 		SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)\n",
154 			     bdev_name);
155 
156 		goto invalid;
157 	}
158 
159 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
160 	if (rc) {
161 		SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
162 		bs_dev->destroy(bs_dev);
163 
164 		goto invalid;
165 	}
166 
167 	spdk_fs_opts_init(&blobfs_opt);
168 	if (cluster_sz) {
169 		blobfs_opt.cluster_sz = cluster_sz;
170 	}
171 
172 	spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
173 
174 	return;
175 
176 invalid:
177 	free(ctx);
178 
179 	cb_fn(cb_arg, rc);
180 }
SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)181 SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)
182 #ifdef SPDK_CONFIG_FUSE
183 
184 static void
185 blobfs_bdev_unmount(void *arg)
186 {
187 	struct blobfs_bdev_operation_ctx *ctx = arg;
188 
189 	/* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
190 	spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
191 }
192 
193 static void
_blobfs_bdev_mount_fuse_start(void * _ctx)194 _blobfs_bdev_mount_fuse_start(void *_ctx)
195 {
196 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
197 	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 	ctx->cb_fn = NULL;
204 
205 	rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
206 			       blobfs_bdev_unmount, ctx, &ctx->bfuse);
207 	if (rc != 0) {
208 		SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
209 
210 		/* Return failure state back */
211 		cb_fn(ctx->cb_arg, rc);
212 
213 		blobfs_bdev_unmount(ctx);
214 
215 		return;
216 	}
217 
218 	cb_fn(ctx->cb_arg, 0);
219 }
220 
221 static void
_blobfs_bdev_mount_load_cb(void * _ctx,struct spdk_filesystem * fs,int fserrno)222 _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
223 {
224 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
225 
226 	if (fserrno) {
227 		SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
228 
229 		ctx->cb_fn(ctx->cb_arg, fserrno);
230 		free(ctx);
231 		return;
232 	}
233 
234 	ctx->fs = fs;
235 	ctx->fs_loading_thread = spdk_get_thread();
236 
237 	spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
238 }
239 
240 static void
blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)241 blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
242 			  void *event_ctx)
243 {
244 	struct blobfs_bdev_operation_ctx *ctx = event_ctx;
245 
246 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
247 
248 	if (type == SPDK_BDEV_EVENT_REMOVE) {
249 		blobfs_fuse_stop(ctx->bfuse);
250 	}
251 }
252 
253 void
spdk_blobfs_bdev_mount(const char * bdev_name,const char * mountpoint,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)254 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 	struct spdk_bs_dev *bs_dev;
259 	int rc;
260 
261 	ctx = calloc(1, sizeof(*ctx));
262 	if (ctx == NULL) {
263 		SPDK_ERRLOG("Failed to allocate ctx.\n");
264 		cb_fn(cb_arg, -ENOMEM);
265 
266 		return;
267 	}
268 
269 	ctx->bdev_name = bdev_name;
270 	ctx->mountpoint = mountpoint;
271 	ctx->cb_fn = cb_fn;
272 	ctx->cb_arg = cb_arg;
273 
274 	rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_fuse_event_cb, ctx, &bs_dev);
275 	if (rc != 0) {
276 		SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
277 			     bdev_name);
278 
279 		goto invalid;
280 	}
281 
282 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
283 	if (rc != 0) {
284 		SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
285 		bs_dev->destroy(bs_dev);
286 
287 		goto invalid;
288 	}
289 
290 	spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
291 
292 	return;
293 
294 invalid:
295 	free(ctx);
296 
297 	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
311