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