summaryrefslogtreecommitdiffstats
path: root/src/spdk/module/blobfs/bdev/blobfs_bdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/module/blobfs/bdev/blobfs_bdev.c')
-rw-r--r--src/spdk/module/blobfs/bdev/blobfs_bdev.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/spdk/module/blobfs/bdev/blobfs_bdev.c b/src/spdk/module/blobfs/bdev/blobfs_bdev.c
new file mode 100644
index 000000000..501bbea18
--- /dev/null
+++ b/src/spdk/module/blobfs/bdev/blobfs_bdev.c
@@ -0,0 +1,361 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright (c) Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "spdk/stdinc.h"
+#include "spdk/blobfs.h"
+#include "spdk/bdev.h"
+#include "spdk/bdev_module.h"
+#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"
+
+#include "spdk_internal/log.h"
+
+#include "blobfs_fuse.h"
+
+/* Dummy bdev module used to to claim bdevs. */
+static struct spdk_bdev_module blobfs_bdev_module = {
+ .name = "blobfs",
+};
+
+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;
+
+ /* 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.
+ */
+ spdk_blobfs_bdev_op_complete cb_fn;
+ void *cb_arg;
+
+ /* 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;
+};
+
+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);
+ }
+
+ if (ctx->cb_fn) {
+ ctx->cb_fn(ctx->cb_arg, fserrno);
+ }
+
+ 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;
+ struct spdk_bdev_desc *desc;
+ 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;
+
+ rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
+ if (rc != 0) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
+ spdk_strerror(rc));
+
+ goto invalid;
+ }
+
+ bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
+ if (bs_dev == NULL) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to create a blobstore block device from bdev desc");
+ rc = -ENOMEM;
+ spdk_bdev_close(desc);
+
+ goto invalid;
+ }
+
+ spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx);
+
+ return;
+
+invalid:
+ free(ctx);
+
+ cb_fn(cb_arg, rc);
+}
+
+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;
+ struct spdk_bdev_desc *desc;
+ 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;
+
+ /* Creation requires WRITE operation */
+ rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc);
+ if (rc != 0) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
+ spdk_strerror(rc));
+
+ goto invalid;
+ }
+
+ bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
+ if (bs_dev == NULL) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to create a blobstore block device from bdev desc\n");
+ rc = -ENOMEM;
+ spdk_bdev_close(desc);
+
+ goto invalid;
+ }
+
+ rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
+ if (rc) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Blobfs base bdev already claimed by another bdev\n");
+ 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);
+}
+SPDK_LOG_REGISTER_COMPONENT("blobfs_bdev", SPDK_LOG_BLOBFS_BDEV)
+#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;
+
+ rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs,
+ blobfs_bdev_unmount, ctx, &ctx->bfuse);
+ 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) {
+ blobfs_fuse_stop(ctx->bfuse);
+ }
+}
+
+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;
+ struct spdk_bdev_desc *desc;
+ 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;
+
+ rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_fuse_event_cb, ctx, &desc);
+ if (rc != 0) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name,
+ spdk_strerror(rc));
+
+ goto invalid;
+ }
+
+ bs_dev = spdk_bdev_create_bs_dev_from_desc(desc);
+ if (bs_dev == NULL) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to create a blobstore block device from bdev desc");
+ rc = -ENOMEM;
+ spdk_bdev_close(desc);
+
+ goto invalid;
+ }
+
+ rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module);
+ if (rc != 0) {
+ SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Blobfs base bdev already claimed by another bdev\n");
+ bs_dev->destroy(bs_dev);
+
+ goto invalid;
+ }
+
+ spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx);
+
+ return;
+
+invalid:
+ free(ctx);
+
+ cb_fn(cb_arg, rc);
+}
+
+#endif