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/rpc.h" 35 #include "spdk/util.h" 36 #include "spdk/bdev_module.h" 37 #include "spdk/string.h" 38 #include "spdk_internal/log.h" 39 40 #include "bdev_ftl.h" 41 42 struct rpc_bdev_ftl_create { 43 char *name; 44 char *base_bdev; 45 char *uuid; 46 char *cache_bdev; 47 struct spdk_ftl_conf ftl_conf; 48 }; 49 50 static void 51 free_rpc_bdev_ftl_create(struct rpc_bdev_ftl_create *req) 52 { 53 free(req->name); 54 free(req->base_bdev); 55 free(req->uuid); 56 free(req->cache_bdev); 57 } 58 59 static const struct spdk_json_object_decoder rpc_bdev_ftl_create_decoders[] = { 60 {"name", offsetof(struct rpc_bdev_ftl_create, name), spdk_json_decode_string}, 61 {"base_bdev", offsetof(struct rpc_bdev_ftl_create, base_bdev), spdk_json_decode_string}, 62 {"uuid", offsetof(struct rpc_bdev_ftl_create, uuid), spdk_json_decode_string, true}, 63 {"cache", offsetof(struct rpc_bdev_ftl_create, cache_bdev), spdk_json_decode_string, true}, 64 { 65 "allow_open_bands", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 66 offsetof(struct spdk_ftl_conf, allow_open_bands), spdk_json_decode_bool, true 67 }, 68 { 69 "overprovisioning", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 70 offsetof(struct spdk_ftl_conf, lba_rsvd), spdk_json_decode_uint64, true 71 }, 72 { 73 "use_append", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 74 offsetof(struct spdk_ftl_conf, use_append), spdk_json_decode_bool, true 75 }, 76 { 77 "limit_crit", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 78 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_CRIT]) + 79 offsetof(struct spdk_ftl_limit, limit), 80 spdk_json_decode_uint64, true 81 }, 82 { 83 "limit_crit_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 84 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_CRIT]) + 85 offsetof(struct spdk_ftl_limit, thld), 86 spdk_json_decode_uint64, true 87 }, 88 { 89 "limit_high", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 90 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_HIGH]) + 91 offsetof(struct spdk_ftl_limit, limit), 92 spdk_json_decode_uint64, true 93 }, 94 { 95 "limit_high_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 96 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_HIGH]) + 97 offsetof(struct spdk_ftl_limit, thld), 98 spdk_json_decode_uint64, true 99 }, 100 { 101 "limit_low", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 102 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_LOW]) + 103 offsetof(struct spdk_ftl_limit, limit), 104 spdk_json_decode_uint64, true 105 }, 106 { 107 "limit_low_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 108 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_LOW]) + 109 offsetof(struct spdk_ftl_limit, thld), 110 spdk_json_decode_uint64, true 111 }, 112 { 113 "limit_start", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 114 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_START]) + 115 offsetof(struct spdk_ftl_limit, limit), 116 spdk_json_decode_uint64, true 117 }, 118 { 119 "limit_start_threshold", offsetof(struct rpc_bdev_ftl_create, ftl_conf) + 120 offsetof(struct spdk_ftl_conf, limits[SPDK_FTL_LIMIT_START]) + 121 offsetof(struct spdk_ftl_limit, thld), 122 spdk_json_decode_uint64, true 123 }, 124 }; 125 126 static void 127 _spdk_rpc_bdev_ftl_create_cb(const struct ftl_bdev_info *bdev_info, void *ctx, int status) 128 { 129 struct spdk_jsonrpc_request *request = ctx; 130 char bdev_uuid[SPDK_UUID_STRING_LEN]; 131 struct spdk_json_write_ctx *w; 132 133 if (status) { 134 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 135 "Failed to create FTL bdev: %s", 136 spdk_strerror(-status)); 137 return; 138 } 139 140 w = spdk_jsonrpc_begin_result(request); 141 spdk_uuid_fmt_lower(bdev_uuid, sizeof(bdev_uuid), &bdev_info->uuid); 142 spdk_json_write_object_begin(w); 143 spdk_json_write_named_string(w, "name", bdev_info->name); 144 spdk_json_write_named_string(w, "uuid", bdev_uuid); 145 spdk_json_write_object_end(w); 146 spdk_jsonrpc_end_result(request, w); 147 } 148 149 static void 150 spdk_rpc_bdev_ftl_create(struct spdk_jsonrpc_request *request, 151 const struct spdk_json_val *params) 152 { 153 struct rpc_bdev_ftl_create req = {}; 154 struct ftl_bdev_init_opts opts = {}; 155 struct spdk_json_write_ctx *w; 156 int rc; 157 158 spdk_ftl_conf_init_defaults(&req.ftl_conf); 159 160 if (spdk_json_decode_object(params, rpc_bdev_ftl_create_decoders, 161 SPDK_COUNTOF(rpc_bdev_ftl_create_decoders), 162 &req)) { 163 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 164 "Invalid parameters"); 165 goto invalid; 166 } 167 168 if (req.cache_bdev && !spdk_bdev_get_by_name(req.cache_bdev)) { 169 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 170 "No such bdev: %s", req.cache_bdev); 171 goto invalid; 172 } 173 174 opts.name = req.name; 175 opts.mode = SPDK_FTL_MODE_CREATE; 176 opts.base_bdev = req.base_bdev; 177 opts.cache_bdev = req.cache_bdev; 178 opts.ftl_conf = req.ftl_conf; 179 180 if (req.uuid) { 181 if (spdk_uuid_parse(&opts.uuid, req.uuid) < 0) { 182 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 183 "Failed to parse uuid: %s", 184 req.uuid); 185 goto invalid; 186 } 187 188 if (!spdk_mem_all_zero(&opts.uuid, sizeof(opts.uuid))) { 189 opts.mode &= ~SPDK_FTL_MODE_CREATE; 190 } 191 } 192 193 rc = bdev_ftl_create_bdev(&opts, _spdk_rpc_bdev_ftl_create_cb, request); 194 if (rc) { 195 if (rc == -ENODEV) { 196 w = spdk_jsonrpc_begin_result(request); 197 spdk_json_write_string_fmt(w, "FTL bdev: %s creation deferred", req.name); 198 spdk_jsonrpc_end_result(request, w); 199 } else { 200 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 201 "Failed to create FTL bdev: %s", 202 spdk_strerror(-rc)); 203 } 204 goto invalid; 205 } 206 207 invalid: 208 free_rpc_bdev_ftl_create(&req); 209 } 210 211 SPDK_RPC_REGISTER("bdev_ftl_create", spdk_rpc_bdev_ftl_create, SPDK_RPC_RUNTIME) 212 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_ftl_create, construct_ftl_bdev) 213 214 struct rpc_delete_ftl { 215 char *name; 216 }; 217 218 static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = { 219 {"name", offsetof(struct rpc_bdev_ftl_create, name), spdk_json_decode_string}, 220 }; 221 222 static void 223 _spdk_rpc_bdev_ftl_delete_cb(void *cb_arg, int bdeverrno) 224 { 225 struct spdk_jsonrpc_request *request = cb_arg; 226 struct spdk_json_write_ctx *w = spdk_jsonrpc_begin_result(request); 227 228 spdk_json_write_bool(w, bdeverrno == 0); 229 spdk_jsonrpc_end_result(request, w); 230 } 231 232 static void 233 spdk_rpc_bdev_ftl_delete(struct spdk_jsonrpc_request *request, 234 const struct spdk_json_val *params) 235 { 236 struct rpc_delete_ftl attrs = {}; 237 238 if (spdk_json_decode_object(params, rpc_delete_ftl_decoders, 239 SPDK_COUNTOF(rpc_delete_ftl_decoders), 240 &attrs)) { 241 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 242 "Invalid parameters"); 243 goto invalid; 244 } 245 246 bdev_ftl_delete_bdev(attrs.name, _spdk_rpc_bdev_ftl_delete_cb, request); 247 invalid: 248 free(attrs.name); 249 } 250 251 SPDK_RPC_REGISTER("bdev_ftl_delete", spdk_rpc_bdev_ftl_delete, SPDK_RPC_RUNTIME) 252 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_ftl_delete, delete_ftl_bdev) 253