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