xref: /spdk/module/blobfs/bdev/blobfs_bdev.c (revision 86ba16c39c091790f79e99a033db86b6fd502606)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2019 Intel Corporation.
33ce759a1SXiaodong Liu  *   All rights reserved.
43ce759a1SXiaodong Liu  */
53ce759a1SXiaodong Liu 
63ce759a1SXiaodong Liu #include "spdk/stdinc.h"
73ce759a1SXiaodong Liu #include "spdk/blobfs.h"
83ce759a1SXiaodong Liu #include "spdk/bdev.h"
96433c103SXiaodong Liu #include "spdk/bdev_module.h"
103ce759a1SXiaodong Liu #include "spdk/event.h"
113ce759a1SXiaodong Liu #include "spdk/blob_bdev.h"
123ce759a1SXiaodong Liu #include "spdk/blobfs_bdev.h"
133ce759a1SXiaodong Liu #include "spdk/log.h"
143ce759a1SXiaodong Liu #include "spdk/string.h"
153ce759a1SXiaodong Liu #include "spdk/rpc.h"
163ce759a1SXiaodong Liu #include "spdk/util.h"
173ce759a1SXiaodong Liu 
184c10e0bbSXiaodong Liu #include "blobfs_fuse.h"
194c10e0bbSXiaodong Liu 
206433c103SXiaodong Liu /* Dummy bdev module used to to claim bdevs. */
216433c103SXiaodong Liu static struct spdk_bdev_module blobfs_bdev_module = {
226433c103SXiaodong Liu 	.name	= "blobfs",
236433c103SXiaodong Liu };
246433c103SXiaodong Liu 
253ce759a1SXiaodong Liu static void
blobfs_bdev_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)263ce759a1SXiaodong Liu blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
273ce759a1SXiaodong Liu 		     void *event_ctx)
283ce759a1SXiaodong Liu {
293ce759a1SXiaodong Liu 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
303ce759a1SXiaodong Liu }
313ce759a1SXiaodong Liu 
323ce759a1SXiaodong Liu struct blobfs_bdev_operation_ctx {
333ce759a1SXiaodong Liu 	const char *bdev_name;
343ce759a1SXiaodong Liu 	struct spdk_filesystem *fs;
353ce759a1SXiaodong Liu 
364c10e0bbSXiaodong Liu 	/* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb.
374c10e0bbSXiaodong Liu 	 * cb_fn should be set NULL after its being called, in order to avoid repeated
384c10e0bbSXiaodong Liu 	 * calling in _blobfs_bdev_unload_cb.
394c10e0bbSXiaodong Liu 	 */
403ce759a1SXiaodong Liu 	spdk_blobfs_bdev_op_complete cb_fn;
413ce759a1SXiaodong Liu 	void *cb_arg;
424c10e0bbSXiaodong Liu 
434c10e0bbSXiaodong Liu 	/* Variables for mount operation */
444c10e0bbSXiaodong Liu 	const char *mountpoint;
454c10e0bbSXiaodong Liu 	struct spdk_thread *fs_loading_thread;
464c10e0bbSXiaodong Liu 
474c10e0bbSXiaodong Liu 	/* Used in bdev_event_cb to do some proper operations on blobfs_fuse for
484c10e0bbSXiaodong Liu 	 * asynchronous event of the backend bdev.
494c10e0bbSXiaodong Liu 	 */
504c10e0bbSXiaodong Liu 	struct spdk_blobfs_fuse *bfuse;
513ce759a1SXiaodong Liu };
523ce759a1SXiaodong Liu 
533ce759a1SXiaodong Liu static void
_blobfs_bdev_unload_cb(void * _ctx,int fserrno)543ce759a1SXiaodong Liu _blobfs_bdev_unload_cb(void *_ctx, int fserrno)
553ce759a1SXiaodong Liu {
563ce759a1SXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
573ce759a1SXiaodong Liu 
583ce759a1SXiaodong Liu 	if (fserrno) {
593ce759a1SXiaodong Liu 		SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
603ce759a1SXiaodong Liu 	}
613ce759a1SXiaodong Liu 
624c10e0bbSXiaodong Liu 	if (ctx->cb_fn) {
633ce759a1SXiaodong Liu 		ctx->cb_fn(ctx->cb_arg, fserrno);
644c10e0bbSXiaodong Liu 	}
654c10e0bbSXiaodong Liu 
663ce759a1SXiaodong Liu 	free(ctx);
673ce759a1SXiaodong Liu }
683ce759a1SXiaodong Liu 
693ce759a1SXiaodong Liu static void
blobfs_bdev_unload(void * _ctx)703ce759a1SXiaodong Liu blobfs_bdev_unload(void *_ctx)
713ce759a1SXiaodong Liu {
723ce759a1SXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
733ce759a1SXiaodong Liu 
743ce759a1SXiaodong Liu 	spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
753ce759a1SXiaodong Liu }
763ce759a1SXiaodong Liu 
773ce759a1SXiaodong Liu static void
blobfs_bdev_load_cb_to_unload(void * _ctx,struct spdk_filesystem * fs,int fserrno)783ce759a1SXiaodong Liu blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
793ce759a1SXiaodong Liu {
803ce759a1SXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
813ce759a1SXiaodong Liu 
823ce759a1SXiaodong Liu 	if (fserrno) {
833ce759a1SXiaodong Liu 		ctx->cb_fn(ctx->cb_arg, fserrno);
843ce759a1SXiaodong Liu 		free(ctx);
853ce759a1SXiaodong Liu 		return;
863ce759a1SXiaodong Liu 	}
873ce759a1SXiaodong Liu 
883ce759a1SXiaodong Liu 	ctx->fs = fs;
893ce759a1SXiaodong Liu 	spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
903ce759a1SXiaodong Liu }
913ce759a1SXiaodong Liu 
923ce759a1SXiaodong Liu void
spdk_blobfs_bdev_detect(const char * bdev_name,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)933ce759a1SXiaodong Liu spdk_blobfs_bdev_detect(const char *bdev_name,
943ce759a1SXiaodong Liu 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
953ce759a1SXiaodong Liu {
963ce759a1SXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx;
973ce759a1SXiaodong Liu 	struct spdk_bs_dev *bs_dev;
983ce759a1SXiaodong Liu 	int rc;
993ce759a1SXiaodong Liu 
1003ce759a1SXiaodong Liu 	ctx = calloc(1, sizeof(*ctx));
1013ce759a1SXiaodong Liu 	if (ctx == NULL) {
1023ce759a1SXiaodong Liu 		SPDK_ERRLOG("Failed to allocate ctx.\n");
1033ce759a1SXiaodong Liu 		cb_fn(cb_arg, -ENOMEM);
1043ce759a1SXiaodong Liu 
1053ce759a1SXiaodong Liu 		return;
1063ce759a1SXiaodong Liu 	}
1073ce759a1SXiaodong Liu 
1083ce759a1SXiaodong Liu 	ctx->bdev_name = bdev_name;
1093ce759a1SXiaodong Liu 	ctx->cb_fn = cb_fn;
1103ce759a1SXiaodong Liu 	ctx->cb_arg = cb_arg;
1113ce759a1SXiaodong Liu 
11228420560SShuhei Matsumoto 	rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
1133ce759a1SXiaodong Liu 	if (rc != 0) {
11428420560SShuhei Matsumoto 		SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
11528420560SShuhei Matsumoto 			     bdev_name);
1163ce759a1SXiaodong Liu 
1173ce759a1SXiaodong Liu 		goto invalid;
1183ce759a1SXiaodong Liu 	}
1193ce759a1SXiaodong Liu 
1203ce759a1SXiaodong Liu 	spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
1213ce759a1SXiaodong Liu 
1223ce759a1SXiaodong Liu 	return;
1233ce759a1SXiaodong Liu 
1243ce759a1SXiaodong Liu invalid:
1253ce759a1SXiaodong Liu 	free(ctx);
1263ce759a1SXiaodong Liu 
1273ce759a1SXiaodong Liu 	cb_fn(cb_arg, rc);
1283ce759a1SXiaodong Liu }
1296433c103SXiaodong Liu 
1306433c103SXiaodong Liu void
spdk_blobfs_bdev_create(const char * bdev_name,uint32_t cluster_sz,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)1316433c103SXiaodong Liu spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
1326433c103SXiaodong Liu 			spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
1336433c103SXiaodong Liu {
1346433c103SXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx;
1356433c103SXiaodong Liu 	struct spdk_blobfs_opts blobfs_opt;
1366433c103SXiaodong Liu 	struct spdk_bs_dev *bs_dev;
1376433c103SXiaodong Liu 	int rc;
1386433c103SXiaodong Liu 
1396433c103SXiaodong Liu 	ctx = calloc(1, sizeof(*ctx));
1406433c103SXiaodong Liu 	if (ctx == NULL) {
1416433c103SXiaodong Liu 		SPDK_ERRLOG("Failed to allocate ctx.\n");
1426433c103SXiaodong Liu 		cb_fn(cb_arg, -ENOMEM);
1436433c103SXiaodong Liu 
1446433c103SXiaodong Liu 		return;
1456433c103SXiaodong Liu 	}
1466433c103SXiaodong Liu 
1476433c103SXiaodong Liu 	ctx->bdev_name = bdev_name;
1486433c103SXiaodong Liu 	ctx->cb_fn = cb_fn;
1496433c103SXiaodong Liu 	ctx->cb_arg = cb_arg;
1506433c103SXiaodong Liu 
15128420560SShuhei Matsumoto 	rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
15228420560SShuhei Matsumoto 	if (rc) {
15328420560SShuhei Matsumoto 		SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)\n",
15428420560SShuhei Matsumoto 			     bdev_name);
1556433c103SXiaodong Liu 
1566433c103SXiaodong Liu 		goto invalid;
1576433c103SXiaodong Liu 	}
1586433c103SXiaodong Liu 
1596433c103SXiaodong Liu 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
1606433c103SXiaodong Liu 	if (rc) {
1612172c432STomasz Zawadzki 		SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
1626433c103SXiaodong Liu 		bs_dev->destroy(bs_dev);
1636433c103SXiaodong Liu 
1646433c103SXiaodong Liu 		goto invalid;
1656433c103SXiaodong Liu 	}
1666433c103SXiaodong Liu 
1676433c103SXiaodong Liu 	spdk_fs_opts_init(&blobfs_opt);
1686433c103SXiaodong Liu 	if (cluster_sz) {
1696433c103SXiaodong Liu 		blobfs_opt.cluster_sz = cluster_sz;
1706433c103SXiaodong Liu 	}
1716433c103SXiaodong Liu 
1726433c103SXiaodong Liu 	spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
1736433c103SXiaodong Liu 
1746433c103SXiaodong Liu 	return;
1756433c103SXiaodong Liu 
1766433c103SXiaodong Liu invalid:
1776433c103SXiaodong Liu 	free(ctx);
1786433c103SXiaodong Liu 
1796433c103SXiaodong Liu 	cb_fn(cb_arg, rc);
1806433c103SXiaodong Liu }
SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)1812172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)
1824c10e0bbSXiaodong Liu #ifdef SPDK_CONFIG_FUSE
1834c10e0bbSXiaodong Liu 
1844c10e0bbSXiaodong Liu static void
1854c10e0bbSXiaodong Liu blobfs_bdev_unmount(void *arg)
1864c10e0bbSXiaodong Liu {
1874c10e0bbSXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = arg;
1884c10e0bbSXiaodong Liu 
1894c10e0bbSXiaodong Liu 	/* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
1904c10e0bbSXiaodong Liu 	spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
1914c10e0bbSXiaodong Liu }
1924c10e0bbSXiaodong Liu 
1934c10e0bbSXiaodong Liu static void
_blobfs_bdev_mount_fuse_start(void * _ctx)1944c10e0bbSXiaodong Liu _blobfs_bdev_mount_fuse_start(void *_ctx)
1954c10e0bbSXiaodong Liu {
1964c10e0bbSXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
1974c10e0bbSXiaodong Liu 	spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn;
1984c10e0bbSXiaodong Liu 	int rc;
1994c10e0bbSXiaodong Liu 
2004c10e0bbSXiaodong Liu 	/* Since function of ctx->cb_fn will be called in this function, set
2014c10e0bbSXiaodong Liu 	 * ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb.
2024c10e0bbSXiaodong Liu 	 */
2034c10e0bbSXiaodong Liu 	ctx->cb_fn = NULL;
2044c10e0bbSXiaodong Liu 
20530e3f4d9SSeth Howell 	rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
2064c10e0bbSXiaodong Liu 			       blobfs_bdev_unmount, ctx, &ctx->bfuse);
2074c10e0bbSXiaodong Liu 	if (rc != 0) {
2084c10e0bbSXiaodong Liu 		SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
2094c10e0bbSXiaodong Liu 
2104c10e0bbSXiaodong Liu 		/* Return failure state back */
2114c10e0bbSXiaodong Liu 		cb_fn(ctx->cb_arg, rc);
2124c10e0bbSXiaodong Liu 
2134c10e0bbSXiaodong Liu 		blobfs_bdev_unmount(ctx);
2144c10e0bbSXiaodong Liu 
2154c10e0bbSXiaodong Liu 		return;
2164c10e0bbSXiaodong Liu 	}
2174c10e0bbSXiaodong Liu 
2184c10e0bbSXiaodong Liu 	cb_fn(ctx->cb_arg, 0);
2194c10e0bbSXiaodong Liu }
2204c10e0bbSXiaodong Liu 
2214c10e0bbSXiaodong Liu static void
_blobfs_bdev_mount_load_cb(void * _ctx,struct spdk_filesystem * fs,int fserrno)2224c10e0bbSXiaodong Liu _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
2234c10e0bbSXiaodong Liu {
2244c10e0bbSXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = _ctx;
2254c10e0bbSXiaodong Liu 
2264c10e0bbSXiaodong Liu 	if (fserrno) {
2274c10e0bbSXiaodong Liu 		SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
2284c10e0bbSXiaodong Liu 
2294c10e0bbSXiaodong Liu 		ctx->cb_fn(ctx->cb_arg, fserrno);
2304c10e0bbSXiaodong Liu 		free(ctx);
2314c10e0bbSXiaodong Liu 		return;
2324c10e0bbSXiaodong Liu 	}
2334c10e0bbSXiaodong Liu 
2344c10e0bbSXiaodong Liu 	ctx->fs = fs;
2354c10e0bbSXiaodong Liu 	ctx->fs_loading_thread = spdk_get_thread();
2364c10e0bbSXiaodong Liu 
2374c10e0bbSXiaodong Liu 	spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
2384c10e0bbSXiaodong Liu }
2394c10e0bbSXiaodong Liu 
2404c10e0bbSXiaodong Liu static void
blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)2414c10e0bbSXiaodong Liu blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
2424c10e0bbSXiaodong Liu 			  void *event_ctx)
2434c10e0bbSXiaodong Liu {
2444c10e0bbSXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx = event_ctx;
2454c10e0bbSXiaodong Liu 
2464c10e0bbSXiaodong Liu 	SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
2474c10e0bbSXiaodong Liu 
2484c10e0bbSXiaodong Liu 	if (type == SPDK_BDEV_EVENT_REMOVE) {
24930e3f4d9SSeth Howell 		blobfs_fuse_stop(ctx->bfuse);
2504c10e0bbSXiaodong Liu 	}
2514c10e0bbSXiaodong Liu }
2524c10e0bbSXiaodong Liu 
2534c10e0bbSXiaodong Liu void
spdk_blobfs_bdev_mount(const char * bdev_name,const char * mountpoint,spdk_blobfs_bdev_op_complete cb_fn,void * cb_arg)2544c10e0bbSXiaodong Liu spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
2554c10e0bbSXiaodong Liu 		       spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
2564c10e0bbSXiaodong Liu {
2574c10e0bbSXiaodong Liu 	struct blobfs_bdev_operation_ctx *ctx;
2584c10e0bbSXiaodong Liu 	struct spdk_bs_dev *bs_dev;
2594c10e0bbSXiaodong Liu 	int rc;
2604c10e0bbSXiaodong Liu 
2614c10e0bbSXiaodong Liu 	ctx = calloc(1, sizeof(*ctx));
2624c10e0bbSXiaodong Liu 	if (ctx == NULL) {
2634c10e0bbSXiaodong Liu 		SPDK_ERRLOG("Failed to allocate ctx.\n");
2644c10e0bbSXiaodong Liu 		cb_fn(cb_arg, -ENOMEM);
2654c10e0bbSXiaodong Liu 
2664c10e0bbSXiaodong Liu 		return;
2674c10e0bbSXiaodong Liu 	}
2684c10e0bbSXiaodong Liu 
2694c10e0bbSXiaodong Liu 	ctx->bdev_name = bdev_name;
2704c10e0bbSXiaodong Liu 	ctx->mountpoint = mountpoint;
2714c10e0bbSXiaodong Liu 	ctx->cb_fn = cb_fn;
2724c10e0bbSXiaodong Liu 	ctx->cb_arg = cb_arg;
2734c10e0bbSXiaodong Liu 
27428420560SShuhei Matsumoto 	rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_fuse_event_cb, ctx, &bs_dev);
2754c10e0bbSXiaodong Liu 	if (rc != 0) {
27628420560SShuhei Matsumoto 		SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
27728420560SShuhei Matsumoto 			     bdev_name);
2784c10e0bbSXiaodong Liu 
2794c10e0bbSXiaodong Liu 		goto invalid;
2804c10e0bbSXiaodong Liu 	}
2814c10e0bbSXiaodong Liu 
2824c10e0bbSXiaodong Liu 	rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
2834c10e0bbSXiaodong Liu 	if (rc != 0) {
2842172c432STomasz Zawadzki 		SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
2854c10e0bbSXiaodong Liu 		bs_dev->destroy(bs_dev);
2864c10e0bbSXiaodong Liu 
2874c10e0bbSXiaodong Liu 		goto invalid;
2884c10e0bbSXiaodong Liu 	}
2894c10e0bbSXiaodong Liu 
29030e3f4d9SSeth Howell 	spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
2914c10e0bbSXiaodong Liu 
2924c10e0bbSXiaodong Liu 	return;
2934c10e0bbSXiaodong Liu 
2944c10e0bbSXiaodong Liu invalid:
2954c10e0bbSXiaodong Liu 	free(ctx);
2964c10e0bbSXiaodong Liu 
2974c10e0bbSXiaodong Liu 	cb_fn(cb_arg, rc);
2984c10e0bbSXiaodong Liu }
2994c10e0bbSXiaodong Liu 
300*86ba16c3SKonrad Sztyber #else /* SPDK_CONFIG_FUSE */
301*86ba16c3SKonrad Sztyber 
302*86ba16c3SKonrad Sztyber void
303*86ba16c3SKonrad Sztyber spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
304*86ba16c3SKonrad Sztyber 		       spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
305*86ba16c3SKonrad Sztyber {
306*86ba16c3SKonrad Sztyber 	SPDK_ERRLOG("spdk_blobfs_bdev_mount() is unsupported\n");
307*86ba16c3SKonrad Sztyber 	cb_fn(cb_arg, -ENOTSUP);
308*86ba16c3SKonrad Sztyber }
309*86ba16c3SKonrad Sztyber 
3104c10e0bbSXiaodong Liu #endif
311