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