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