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 "blobfs_fuse.h" 47 48 /* Dummy bdev module used to to claim bdevs. */ 49 static struct spdk_bdev_module blobfs_bdev_module = { 50 .name = "blobfs", 51 }; 52 53 static void 54 blobfs_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, 55 void *event_ctx) 56 { 57 SPDK_WARNLOG("Async event(%d) is triggered in bdev %s\n", type, spdk_bdev_get_name(bdev)); 58 } 59 60 struct blobfs_bdev_operation_ctx { 61 const char *bdev_name; 62 struct spdk_filesystem *fs; 63 64 /* If cb_fn is already called in other function, not _blobfs_bdev_unload_cb. 65 * cb_fn should be set NULL after its being called, in order to avoid repeated 66 * calling in _blobfs_bdev_unload_cb. 67 */ 68 spdk_blobfs_bdev_op_complete cb_fn; 69 void *cb_arg; 70 71 /* Variables for mount operation */ 72 const char *mountpoint; 73 struct spdk_thread *fs_loading_thread; 74 75 /* Used in bdev_event_cb to do some proper operations on blobfs_fuse for 76 * asynchronous event of the backend bdev. 77 */ 78 struct spdk_blobfs_fuse *bfuse; 79 }; 80 81 static void 82 _blobfs_bdev_unload_cb(void *_ctx, int fserrno) 83 { 84 struct blobfs_bdev_operation_ctx *ctx = _ctx; 85 86 if (fserrno) { 87 SPDK_ERRLOG("Failed to unload blobfs on bdev %s: errno %d\n", ctx->bdev_name, fserrno); 88 } 89 90 if (ctx->cb_fn) { 91 ctx->cb_fn(ctx->cb_arg, fserrno); 92 } 93 94 free(ctx); 95 } 96 97 static void 98 blobfs_bdev_unload(void *_ctx) 99 { 100 struct blobfs_bdev_operation_ctx *ctx = _ctx; 101 102 spdk_fs_unload(ctx->fs, _blobfs_bdev_unload_cb, ctx); 103 } 104 105 static void 106 blobfs_bdev_load_cb_to_unload(void *_ctx, struct spdk_filesystem *fs, int fserrno) 107 { 108 struct blobfs_bdev_operation_ctx *ctx = _ctx; 109 110 if (fserrno) { 111 ctx->cb_fn(ctx->cb_arg, fserrno); 112 free(ctx); 113 return; 114 } 115 116 ctx->fs = fs; 117 spdk_thread_send_msg(spdk_get_thread(), blobfs_bdev_unload, ctx); 118 } 119 120 void 121 spdk_blobfs_bdev_detect(const char *bdev_name, 122 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg) 123 { 124 struct blobfs_bdev_operation_ctx *ctx; 125 struct spdk_bs_dev *bs_dev; 126 struct spdk_bdev_desc *desc; 127 int rc; 128 129 ctx = calloc(1, sizeof(*ctx)); 130 if (ctx == NULL) { 131 SPDK_ERRLOG("Failed to allocate ctx.\n"); 132 cb_fn(cb_arg, -ENOMEM); 133 134 return; 135 } 136 137 ctx->bdev_name = bdev_name; 138 ctx->cb_fn = cb_fn; 139 ctx->cb_arg = cb_arg; 140 141 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc); 142 if (rc != 0) { 143 SPDK_INFOLOG(blobfs_bdev, "Failed to open bdev(%s): %s\n", ctx->bdev_name, 144 spdk_strerror(rc)); 145 146 goto invalid; 147 } 148 149 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 150 if (bs_dev == NULL) { 151 SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev desc"); 152 rc = -ENOMEM; 153 spdk_bdev_close(desc); 154 155 goto invalid; 156 } 157 158 spdk_fs_load(bs_dev, NULL, blobfs_bdev_load_cb_to_unload, ctx); 159 160 return; 161 162 invalid: 163 free(ctx); 164 165 cb_fn(cb_arg, rc); 166 } 167 168 void 169 spdk_blobfs_bdev_create(const char *bdev_name, uint32_t cluster_sz, 170 spdk_blobfs_bdev_op_complete cb_fn, void *cb_arg) 171 { 172 struct blobfs_bdev_operation_ctx *ctx; 173 struct spdk_blobfs_opts blobfs_opt; 174 struct spdk_bs_dev *bs_dev; 175 struct spdk_bdev_desc *desc; 176 int rc; 177 178 ctx = calloc(1, sizeof(*ctx)); 179 if (ctx == NULL) { 180 SPDK_ERRLOG("Failed to allocate ctx.\n"); 181 cb_fn(cb_arg, -ENOMEM); 182 183 return; 184 } 185 186 ctx->bdev_name = bdev_name; 187 ctx->cb_fn = cb_fn; 188 ctx->cb_arg = cb_arg; 189 190 /* Creation requires WRITE operation */ 191 rc = spdk_bdev_open_ext(bdev_name, true, blobfs_bdev_event_cb, NULL, &desc); 192 if (rc != 0) { 193 SPDK_INFOLOG(blobfs_bdev, "Failed to open bdev(%s): %s\n", ctx->bdev_name, 194 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(blobfs_bdev, "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(blobfs_bdev, "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 SPDK_LOG_REGISTER_COMPONENT(blobfs_bdev) 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 = 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 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(blobfs_bdev, "Failed to open bdev(%s): %s\n", ctx->bdev_name, 327 spdk_strerror(rc)); 328 329 goto invalid; 330 } 331 332 bs_dev = spdk_bdev_create_bs_dev_from_desc(desc); 333 if (bs_dev == NULL) { 334 SPDK_INFOLOG(blobfs_bdev, "Failed to create a blobstore block device from bdev desc"); 335 rc = -ENOMEM; 336 spdk_bdev_close(desc); 337 338 goto invalid; 339 } 340 341 rc = spdk_bs_bdev_claim(bs_dev, &blobfs_bdev_module); 342 if (rc != 0) { 343 SPDK_INFOLOG(blobfs_bdev, "Blobfs base bdev already claimed by another bdev\n"); 344 bs_dev->destroy(bs_dev); 345 346 goto invalid; 347 } 348 349 spdk_fs_load(bs_dev, blobfs_fuse_send_request, _blobfs_bdev_mount_load_cb, ctx); 350 351 return; 352 353 invalid: 354 free(ctx); 355 356 cb_fn(cb_arg, rc); 357 } 358 359 #endif 360