2022-06-03 19:15:11 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
2022-11-01 20:26:26 +00:00
|
|
|
* Copyright (C) 2019 Intel Corporation.
|
2019-08-28 08:06:50 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk/blobfs.h"
|
|
|
|
#include "spdk/bdev.h"
|
2019-08-28 08:06:50 +00:00
|
|
|
#include "spdk/bdev_module.h"
|
2019-08-28 08:06:50 +00:00
|
|
|
#include "spdk/event.h"
|
|
|
|
#include "spdk/blob_bdev.h"
|
|
|
|
#include "spdk/blobfs_bdev.h"
|
|
|
|
#include "spdk/log.h"
|
|
|
|
#include "spdk/string.h"
|
|
|
|
#include "spdk/rpc.h"
|
|
|
|
#include "spdk/util.h"
|
|
|
|
|
2019-09-25 08:47:02 +00:00
|
|
|
#include "blobfs_fuse.h"
|
|
|
|
|
2019-08-28 08:06:50 +00:00
|
|
|
/* Dummy bdev module used to to claim bdevs. */
|
|
|
|
static struct spdk_bdev_module blobfs_bdev_module = {
|
|
|
|
.name = "blobfs",
|
|
|
|
};
|
|
|
|
|
2019-08-28 08:06:50 +00:00
|
|
|
static void
|
|
|
|
blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
|
|
|
|
void *event_ctx)
|
|
|
|
{
|
|
|
|
SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct blobfs_bdev_operation_ctx {
|
|
|
|
const char *bdev_name;
|
|
|
|
struct spdk_filesystem *fs;
|
|
|
|
|
2019-09-25 08:47:02 +00:00
|
|
|
/* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb.
|
|
|
|
* cb_fn should be set NULL after its being called, in order to avoid repeated
|
|
|
|
* calling in _blobfs_bdev_unload_cb.
|
|
|
|
*/
|
2019-08-28 08:06:50 +00:00
|
|
|
spdk_blobfs_bdev_op_complete cb_fn;
|
|
|
|
void *cb_arg;
|
2019-09-25 08:47:02 +00:00
|
|
|
|
|
|
|
/* Variables for mount operation */
|
|
|
|
const char *mountpoint;
|
|
|
|
struct spdk_thread *fs_loading_thread;
|
|
|
|
|
|
|
|
/* Used in bdev_event_cb to do some proper operations on blobfs_fuse for
|
|
|
|
* asynchronous event of the backend bdev.
|
|
|
|
*/
|
|
|
|
struct spdk_blobfs_fuse *bfuse;
|
2019-08-28 08:06:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
_blobfs_bdev_unload_cb(void *_ctx, int fserrno)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = _ctx;
|
|
|
|
|
|
|
|
if (fserrno) {
|
|
|
|
SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
|
|
|
|
}
|
|
|
|
|
2019-09-25 08:47:02 +00:00
|
|
|
if (ctx->cb_fn) {
|
|
|
|
ctx->cb_fn(ctx->cb_arg, fserrno);
|
|
|
|
}
|
|
|
|
|
2019-08-28 08:06:50 +00:00
|
|
|
free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
blobfs_bdev_unload(void *_ctx)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = _ctx;
|
|
|
|
|
|
|
|
spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = _ctx;
|
|
|
|
|
|
|
|
if (fserrno) {
|
|
|
|
ctx->cb_fn(ctx->cb_arg, fserrno);
|
|
|
|
free(ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->fs = fs;
|
|
|
|
spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
spdk_blobfs_bdev_detect(const char *bdev_name,
|
|
|
|
spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx;
|
|
|
|
struct spdk_bs_dev *bs_dev;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate ctx.\n");
|
|
|
|
cb_fn(cb_arg, -ENOMEM);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->bdev_name = bdev_name;
|
|
|
|
ctx->cb_fn = cb_fn;
|
|
|
|
ctx->cb_arg = cb_arg;
|
|
|
|
|
2020-10-14 22:37:34 +00:00
|
|
|
rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
|
2019-08-28 08:06:50 +00:00
|
|
|
if (rc != 0) {
|
2020-10-14 22:37:34 +00:00
|
|
|
SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
|
|
|
|
bdev_name);
|
2019-08-28 08:06:50 +00:00
|
|
|
|
|
|
|
goto invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
invalid:
|
|
|
|
free(ctx);
|
|
|
|
|
|
|
|
cb_fn(cb_arg, rc);
|
|
|
|
}
|
2019-08-28 08:06:50 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz,
|
|
|
|
spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx;
|
|
|
|
struct spdk_blobfs_opts blobfs_opt;
|
|
|
|
struct spdk_bs_dev *bs_dev;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate ctx.\n");
|
|
|
|
cb_fn(cb_arg, -ENOMEM);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->bdev_name = bdev_name;
|
|
|
|
ctx->cb_fn = cb_fn;
|
|
|
|
ctx->cb_arg = cb_arg;
|
|
|
|
|
2020-10-14 22:37:34 +00:00
|
|
|
rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_event_cb, NULL, &bs_dev);
|
|
|
|
if (rc) {
|
|
|
|
SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)\n",
|
|
|
|
bdev_name);
|
2019-08-28 08:06:50 +00:00
|
|
|
|
|
|
|
goto invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
|
|
|
|
if (rc) {
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
|
2019-08-28 08:06:50 +00:00
|
|
|
bs_dev->destroy(bs_dev);
|
|
|
|
|
|
|
|
goto invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_fs_opts_init(&blobfs_opt);
|
|
|
|
if (cluster_sz) {
|
|
|
|
blobfs_opt.cluster_sz = cluster_sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
invalid:
|
|
|
|
free(ctx);
|
|
|
|
|
|
|
|
cb_fn(cb_arg, rc);
|
|
|
|
}
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev)
|
2019-09-25 08:47:02 +00:00
|
|
|
#ifdef SPDK_CONFIG_FUSE
|
|
|
|
|
|
|
|
static void
|
|
|
|
blobfs_bdev_unmount(void *arg)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = arg;
|
|
|
|
|
|
|
|
/* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */
|
|
|
|
spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_blobfs_bdev_mount_fuse_start(void *_ctx)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = _ctx;
|
|
|
|
spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Since function of ctx->cb_fn will be called in this function, set
|
|
|
|
* ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb.
|
|
|
|
*/
|
|
|
|
ctx->cb_fn = NULL;
|
|
|
|
|
2020-05-10 18:49:31 +00:00
|
|
|
rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
|
|
|
|
blobfs_bdev_unmount, ctx, &ctx->bfuse);
|
2019-09-25 08:47:02 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint);
|
|
|
|
|
|
|
|
/* Return failure state back */
|
|
|
|
cb_fn(ctx->cb_arg, rc);
|
|
|
|
|
|
|
|
blobfs_bdev_unmount(ctx);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cb_fn(ctx->cb_arg, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = _ctx;
|
|
|
|
|
|
|
|
if (fserrno) {
|
|
|
|
SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno);
|
|
|
|
|
|
|
|
ctx->cb_fn(ctx->cb_arg, fserrno);
|
|
|
|
free(ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->fs = fs;
|
|
|
|
ctx->fs_loading_thread = spdk_get_thread();
|
|
|
|
|
|
|
|
spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
|
|
|
|
void *event_ctx)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx = event_ctx;
|
|
|
|
|
|
|
|
SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev));
|
|
|
|
|
|
|
|
if (type == SPDK_BDEV_EVENT_REMOVE) {
|
2020-05-10 18:49:31 +00:00
|
|
|
blobfs_fuse_stop(ctx->bfuse);
|
2019-09-25 08:47:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
|
|
|
|
spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct blobfs_bdev_operation_ctx *ctx;
|
|
|
|
struct spdk_bs_dev *bs_dev;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(*ctx));
|
|
|
|
if (ctx == NULL) {
|
|
|
|
SPDK_ERRLOG("Failed to allocate ctx.\n");
|
|
|
|
cb_fn(cb_arg, -ENOMEM);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx->bdev_name = bdev_name;
|
|
|
|
ctx->mountpoint = mountpoint;
|
|
|
|
ctx->cb_fn = cb_fn;
|
|
|
|
ctx->cb_arg = cb_arg;
|
|
|
|
|
2020-10-14 22:37:34 +00:00
|
|
|
rc = spdk_bdev_create_bs_dev_ext(bdev_name, blobfs_bdev_fuse_event_cb, ctx, &bs_dev);
|
2019-09-25 08:47:02 +00:00
|
|
|
if (rc != 0) {
|
2020-10-14 22:37:34 +00:00
|
|
|
SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev (%s)",
|
|
|
|
bdev_name);
|
2019-09-25 08:47:02 +00:00
|
|
|
|
|
|
|
goto invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
|
|
|
|
if (rc != 0) {
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n");
|
2019-09-25 08:47:02 +00:00
|
|
|
bs_dev->destroy(bs_dev);
|
|
|
|
|
|
|
|
goto invalid;
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:49:31 +00:00
|
|
|
spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
|
2019-09-25 08:47:02 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
invalid:
|
|
|
|
free(ctx);
|
|
|
|
|
|
|
|
cb_fn(cb_arg, rc);
|
|
|
|
}
|
|
|
|
|
2022-11-10 15:32:42 +00:00
|
|
|
#else /* SPDK_CONFIG_FUSE */
|
|
|
|
|
|
|
|
void
|
|
|
|
spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint,
|
|
|
|
spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
SPDK_ERRLOG("spdk_blobfs_bdev_mount() is unsupported\n");
|
|
|
|
cb_fn(cb_arg, -ENOTSUP);
|
|
|
|
}
|
|
|
|
|
2019-09-25 08:47:02 +00:00
|
|
|
#endif
|