1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk/blobfs.h" 36 #include "spdk/bdev.h" 37 #include "spdk/bdev_module.h" 38 #include "spdk/event.h" 39 #include "spdk/blob_bdev.h" 40 #include "spdk/blobfs_bdev.h" 41 #include "spdk/log.h" 42 #include "spdk/string.h" 43 #include "spdk/rpc.h" 44 #include "spdk/util.h" 45 46 #include "spdk_internal/log.h" 47 48 #include "blobfs_fuse.h" 49 50 /* Dummy bdev module used to to claim bdevs. */ 51 static struct spdk_bdev_module blobfs_bdev_module = { 52 .name = "blobfs", 53 }; 54 55 static void 56 blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 57 void *event_ctx) 58 { 59 SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev)); 60 } 61 62 struct blobfs_bdev_operation_ctx { 63 const char *bdev_name; 64 struct spdk_filesystem *fs; 65 66 /* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb. 67 * cb_fn should be set NULL after its being called, in order to avoid repeated 68 * calling in _blobfs_bdev_unload_cb. 69 */ 70 spdk_blobfs_bdev_op_complete cb_fn; 71 void *cb_arg; 72 73 /* Variables for mount operation */ 74 const char *mountpoint; 75 struct spdk_thread *fs_loading_thread; 76 77 /* Used in bdev_event_cb to do some proper operations on blobfs_fuse for 78 * asynchronous event of the backend bdev. 79 */ 80 struct spdk_blobfs_fuse *bfuse; 81 }; 82 83 static void 84 _blobfs_bdev_unload_cb(void *_ctx, int fserrno) 85 { 86 struct blobfs_bdev_operation_ctx *ctx = _ctx; 87 88 if (fserrno) { 89 SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno); 90 } 91 92 if (ctx->cb_fn) { 93 ctx->cb_fn(ctx->cb_arg, fserrno); 94 } 95 96 free(ctx); 97 } 98 99 static void 100 blobfs_bdev_unload(void *_ctx) 101 { 102 struct blobfs_bdev_operation_ctx *ctx = _ctx; 103 104 spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx); 105 } 106 107 static void 108 blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno) 109 { 110 struct blobfs_bdev_operation_ctx *ctx = _ctx; 111 112 if (fserrno) { 113 ctx->cb_fn(ctx->cb_arg, fserrno); 114 free(ctx); 115 return; 116 } 117 118 ctx->fs = fs; 119 spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx); 120 } 121 122 void 123 spdk_blobfs_bdev_detect(const char *bdev_name, 124 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg) 125 { 126 struct blobfs_bdev_operation_ctx *ctx; 127 struct spdk_bs_dev *bs_dev; 128 struct spdk_bdev_desc *desc; 129 int rc; 130 131 ctx = calloc(1, sizeof(*ctx)); 132 if (ctx == NULL) { 133 SPDK_ERRLOG("Failed to allocate ctx.\n"); 134 cb_fn(cb_arg, -ENOMEM); 135 136 return; 137 } 138 139 ctx->bdev_name = bdev_name; 140 ctx->cb_fn = cb_fn; 141 ctx->cb_arg = cb_arg; 142 143 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc); 144 if (rc != 0) { 145 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name, 146 spdk_strerror(rc)); 147 148 goto invalid; 149 } 150 151 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 152 if (bs_dev == NULL) { 153 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to create a blobstore block device from bdev desc"); 154 rc = -ENOMEM; 155 spdk_bdev_close(desc); 156 157 goto invalid; 158 } 159 160 spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx); 161 162 return; 163 164 invalid: 165 free(ctx); 166 167 cb_fn(cb_arg, rc); 168 } 169 170 void 171 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz, 172 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg) 173 { 174 struct blobfs_bdev_operation_ctx *ctx; 175 struct spdk_blobfs_opts blobfs_opt; 176 struct spdk_bs_dev *bs_dev; 177 struct spdk_bdev_desc *desc; 178 int rc; 179 180 ctx = calloc(1, sizeof(*ctx)); 181 if (ctx == NULL) { 182 SPDK_ERRLOG("Failed to allocate ctx.\n"); 183 cb_fn(cb_arg, -ENOMEM); 184 185 return; 186 } 187 188 ctx->bdev_name = bdev_name; 189 ctx->cb_fn = cb_fn; 190 ctx->cb_arg = cb_arg; 191 192 /* Creation requires WRITE operation */ 193 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc); 194 if (rc != 0) { 195 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name, 196 spdk_strerror(rc)); 197 198 goto invalid; 199 } 200 201 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 202 if (bs_dev == NULL) { 203 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to create a blobstore block device from bdev desc\n"); 204 rc = -ENOMEM; 205 spdk_bdev_close(desc); 206 207 goto invalid; 208 } 209 210 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module); 211 if (rc) { 212 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Blobfs base bdev already claimed by another bdev\n"); 213 bs_dev->destroy(bs_dev); 214 215 goto invalid; 216 } 217 218 spdk_fs_opts_init(&blobfs_opt); 219 if (cluster_sz) { 220 blobfs_opt.cluster_sz = cluster_sz; 221 } 222 223 spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx); 224 225 return; 226 227 invalid: 228 free(ctx); 229 230 cb_fn(cb_arg, rc); 231 } 232 SPDK_LOG_REGISTER_COMPONENT("blobfs_bdev", SPDK_LOG_BLOBFS_BDEV) 233 #ifdef SPDK_CONFIG_FUSE 234 235 static void 236 blobfs_bdev_unmount(void *arg) 237 { 238 struct blobfs_bdev_operation_ctx *ctx = arg; 239 240 /* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */ 241 spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx); 242 } 243 244 static void 245 _blobfs_bdev_mount_fuse_start(void *_ctx) 246 { 247 struct blobfs_bdev_operation_ctx *ctx = _ctx; 248 spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn; 249 int rc; 250 251 /* Since function of ctx->cb_fn will be called in this function, set 252 * ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb. 253 */ 254 ctx->cb_fn = NULL; 255 256 rc = blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs, 257 blobfs_bdev_unmount, ctx, &ctx->bfuse); 258 if (rc != 0) { 259 SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint); 260 261 /* Return failure state back */ 262 cb_fn(ctx->cb_arg, rc); 263 264 blobfs_bdev_unmount(ctx); 265 266 return; 267 } 268 269 cb_fn(ctx->cb_arg, 0); 270 } 271 272 static void 273 _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno) 274 { 275 struct blobfs_bdev_operation_ctx *ctx = _ctx; 276 277 if (fserrno) { 278 SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno); 279 280 ctx->cb_fn(ctx->cb_arg, fserrno); 281 free(ctx); 282 return; 283 } 284 285 ctx->fs = fs; 286 ctx->fs_loading_thread = spdk_get_thread(); 287 288 spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx); 289 } 290 291 static void 292 blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 293 void *event_ctx) 294 { 295 struct blobfs_bdev_operation_ctx *ctx = event_ctx; 296 297 SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev)); 298 299 if (type == SPDK_BDEV_EVENT_REMOVE) { 300 blobfs_fuse_stop(ctx->bfuse); 301 } 302 } 303 304 void 305 spdk_blobfs_bdev_mount(const char *bdev_name, const char *mountpoint, 306 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg) 307 { 308 struct blobfs_bdev_operation_ctx *ctx; 309 struct spdk_bs_dev *bs_dev; 310 struct spdk_bdev_desc *desc; 311 int rc; 312 313 ctx = calloc(1, sizeof(*ctx)); 314 if (ctx == NULL) { 315 SPDK_ERRLOG("Failed to allocate ctx.\n"); 316 cb_fn(cb_arg, -ENOMEM); 317 318 return; 319 } 320 321 ctx->bdev_name = bdev_name; 322 ctx->mountpoint = mountpoint; 323 ctx->cb_fn = cb_fn; 324 ctx->cb_arg = cb_arg; 325 326 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_fuse_event_cb, ctx, &desc); 327 if (rc != 0) { 328 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to open bdev(%s): %s\n", ctx->bdev_name, 329 spdk_strerror(rc)); 330 331 goto invalid; 332 } 333 334 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 335 if (bs_dev == NULL) { 336 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Failed to create a blobstore block device from bdev desc"); 337 rc = -ENOMEM; 338 spdk_bdev_close(desc); 339 340 goto invalid; 341 } 342 343 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module); 344 if (rc != 0) { 345 SPDK_INFOLOG(SPDK_LOG_BLOBFS_BDEV, "Blobfs base bdev already claimed by another bdev\n"); 346 bs_dev->destroy(bs_dev); 347 348 goto invalid; 349 } 350 351 spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx); 352 353 return; 354 355 invalid: 356 free(ctx); 357 358 cb_fn(cb_arg, rc); 359 } 360 361 #endif 362