LCOV - code coverage report
Current view: top level - module/blobfs/bdev - blobfs_bdev.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 109 127 85.8 %
Date: 2024-11-05 10:06:02 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.15