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, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc)); 146 147 goto invalid; 148 } 149 150 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 151 if (bs_dev == NULL) { 152 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to create a blobstore block device from bdev desc"); 153 rc = -ENOMEM; 154 spdk_bdev_close(desc); 155 156 goto invalid; 157 } 158 159 spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx); 160 161 return; 162 163 invalid: 164 free(ctx); 165 166 cb_fn(cb_arg, rc); 167 } 168 169 void 170 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz, 171 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg) 172 { 173 struct blobfs_bdev_operation_ctx *ctx; 174 struct spdk_blobfs_opts blobfs_opt; 175 struct spdk_bs_dev *bs_dev; 176 struct spdk_bdev_desc *desc; 177 int rc; 178 179 ctx = calloc(1, sizeof(*ctx)); 180 if (ctx == NULL) { 181 SPDK_ERRLOG("Failed to allocate ctx.\n"); 182 cb_fn(cb_arg, -ENOMEM); 183 184 return; 185 } 186 187 ctx->bdev_name = bdev_name; 188 ctx->cb_fn = cb_fn; 189 ctx->cb_arg = cb_arg; 190 191 /* Creation requires WRITE operation */ 192 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc); 193 if (rc != 0) { 194 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc)); 195 196 goto invalid; 197 } 198 199 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 200 if (bs_dev == NULL) { 201 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to create a blobstore block device from bdev desc\n"); 202 rc = -ENOMEM; 203 spdk_bdev_close(desc); 204 205 goto invalid; 206 } 207 208 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module); 209 if (rc) { 210 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Blobfs base bdev already claimed by another bdev\n"); 211 bs_dev->destroy(bs_dev); 212 213 goto invalid; 214 } 215 216 spdk_fs_opts_init(&blobfs_opt); 217 if (cluster_sz) { 218 blobfs_opt.cluster_sz = cluster_sz; 219 } 220 221 spdk_fs_init(bs_dev, &blobfs_opt, NULL, blobfs_bdev_load_cb_to_unload, ctx); 222 223 return; 224 225 invalid: 226 free(ctx); 227 228 cb_fn(cb_arg, rc); 229 } 230 231 #ifdef SPDK_CONFIG_FUSE 232 233 static void 234 blobfs_bdev_unmount(void *arg) 235 { 236 struct blobfs_bdev_operation_ctx *ctx = arg; 237 238 /* Keep blobfs unloaded in a same spdk thread with spdk_fs_load */ 239 spdk_thread_send_msg(ctx->fs_loading_thread, blobfs_bdev_unload, ctx); 240 } 241 242 static void 243 _blobfs_bdev_mount_fuse_start(void *_ctx) 244 { 245 struct blobfs_bdev_operation_ctx *ctx = _ctx; 246 spdk_blobfs_bdev_op_complete cb_fn = ctx->cb_fn; 247 int rc; 248 249 /* Since function of ctx->cb_fn will be called in this function, set 250 * ctx->cb_fn to be NULL, in order to avoid repeated calling in unload_cb. 251 */ 252 ctx->cb_fn = NULL; 253 254 rc = spdk_blobfs_fuse_start(ctx->bdev_name, ctx->mountpoint, ctx->fs, 255 blobfs_bdev_unmount, ctx, &ctx->bfuse); 256 if (rc != 0) { 257 SPDK_ERRLOG("Failed to mount blobfs on bdev %s to %s\n", ctx->bdev_name, ctx->mountpoint); 258 259 /* Return failure state back */ 260 cb_fn(ctx->cb_arg, rc); 261 262 blobfs_bdev_unmount(ctx); 263 264 return; 265 } 266 267 cb_fn(ctx->cb_arg, 0); 268 } 269 270 static void 271 _blobfs_bdev_mount_load_cb(void *_ctx, struct spdk_filesystem *fs, int fserrno) 272 { 273 struct blobfs_bdev_operation_ctx *ctx = _ctx; 274 275 if (fserrno) { 276 SPDK_ERRLOG("Failed to load blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno); 277 278 ctx->cb_fn(ctx->cb_arg, fserrno); 279 free(ctx); 280 return; 281 } 282 283 ctx->fs = fs; 284 ctx->fs_loading_thread = spdk_get_thread(); 285 286 spdk_thread_send_msg(spdk_get_thread(), _blobfs_bdev_mount_fuse_start, ctx); 287 } 288 289 static void 290 blobfs_bdev_fuse_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 291 void *event_ctx) 292 { 293 struct blobfs_bdev_operation_ctx *ctx = event_ctx; 294 295 SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev)); 296 297 if (type == SPDK_BDEV_EVENT_REMOVE) { 298 spdk_blobfs_fuse_stop(ctx->bfuse); 299 } 300 } 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 struct blobfs_bdev_operation_ctx *ctx; 307 struct spdk_bs_dev *bs_dev; 308 struct spdk_bdev_desc *desc; 309 int rc; 310 311 ctx = calloc(1, sizeof(*ctx)); 312 if (ctx == NULL) { 313 SPDK_ERRLOG("Failed to allocate ctx.\n"); 314 cb_fn(cb_arg, -ENOMEM); 315 316 return; 317 } 318 319 ctx->bdev_name = bdev_name; 320 ctx->mountpoint = mountpoint; 321 ctx->cb_fn = cb_fn; 322 ctx->cb_arg = cb_arg; 323 324 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_fuse_event_cb, ctx, &desc); 325 if (rc != 0) { 326 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to open bdev(%s): %s\n", ctx->bdev_name, spdk_strerror(rc)); 327 328 goto invalid; 329 } 330 331 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 332 if (bs_dev == NULL) { 333 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Failed to create a blobstore block device from bdev desc"); 334 rc = -ENOMEM; 335 spdk_bdev_close(desc); 336 337 goto invalid; 338 } 339 340 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module); 341 if (rc != 0) { 342 SPDK_INFOLOG(SPDK_LOG_BLOBFS, "Blobfs base bdev already claimed by another bdev\n"); 343 bs_dev->destroy(bs_dev); 344 345 goto invalid; 346 } 347 348 spdk_fs_load(bs_dev, spdk_blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx); 349 350 return; 351 352 invalid: 353 free(ctx); 354 355 cb_fn(cb_arg, rc); 356 } 357 358 #endif 359