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/bdev.h" 36 #include "spdk/util.h" 37 #include "vbdev_lvol.h" 38 #include "spdk/string.h" 39 #include "spdk_internal/log.h" 40 41 SPDK_LOG_REGISTER_COMPONENT("lvolrpc", SPDK_LOG_LVOL_RPC) 42 43 struct rpc_bdev_lvol_create_lvstore { 44 char *lvs_name; 45 char *bdev_name; 46 uint32_t cluster_sz; 47 char *clear_method; 48 }; 49 50 static int 51 vbdev_get_lvol_store_by_uuid_xor_name(const char *uuid, const char *lvs_name, 52 struct spdk_lvol_store **lvs) 53 { 54 if ((uuid == NULL && lvs_name == NULL)) { 55 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "lvs UUID nor lvs name specified\n"); 56 return -EINVAL; 57 } else if ((uuid && lvs_name)) { 58 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "both lvs UUID '%s' and lvs name '%s' specified\n", uuid, 59 lvs_name); 60 return -EINVAL; 61 } else if (uuid) { 62 *lvs = vbdev_get_lvol_store_by_uuid(uuid); 63 64 if (*lvs == NULL) { 65 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "blobstore with UUID '%s' not found\n", uuid); 66 return -ENODEV; 67 } 68 } else if (lvs_name) { 69 70 *lvs = vbdev_get_lvol_store_by_name(lvs_name); 71 72 if (*lvs == NULL) { 73 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "blobstore with name '%s' not found\n", lvs_name); 74 return -ENODEV; 75 } 76 } 77 return 0; 78 } 79 80 static void 81 free_rpc_bdev_lvol_create_lvstore(struct rpc_bdev_lvol_create_lvstore *req) 82 { 83 free(req->bdev_name); 84 free(req->lvs_name); 85 free(req->clear_method); 86 } 87 88 static const struct spdk_json_object_decoder rpc_bdev_lvol_create_lvstore_decoders[] = { 89 {"bdev_name", offsetof(struct rpc_bdev_lvol_create_lvstore, bdev_name), spdk_json_decode_string}, 90 {"cluster_sz", offsetof(struct rpc_bdev_lvol_create_lvstore, cluster_sz), spdk_json_decode_uint32, true}, 91 {"lvs_name", offsetof(struct rpc_bdev_lvol_create_lvstore, lvs_name), spdk_json_decode_string}, 92 {"clear_method", offsetof(struct rpc_bdev_lvol_create_lvstore, clear_method), spdk_json_decode_string, true}, 93 }; 94 95 static void 96 rpc_lvol_store_construct_cb(void *cb_arg, struct spdk_lvol_store *lvol_store, int lvserrno) 97 { 98 struct spdk_json_write_ctx *w; 99 char lvol_store_uuid[SPDK_UUID_STRING_LEN]; 100 struct spdk_jsonrpc_request *request = cb_arg; 101 102 if (lvserrno != 0) { 103 goto invalid; 104 } 105 106 spdk_uuid_fmt_lower(lvol_store_uuid, sizeof(lvol_store_uuid), &lvol_store->uuid); 107 108 w = spdk_jsonrpc_begin_result(request); 109 spdk_json_write_string(w, lvol_store_uuid); 110 spdk_jsonrpc_end_result(request, w); 111 return; 112 113 invalid: 114 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 115 spdk_strerror(-lvserrno)); 116 } 117 118 static void 119 rpc_bdev_lvol_create_lvstore(struct spdk_jsonrpc_request *request, 120 const struct spdk_json_val *params) 121 { 122 struct rpc_bdev_lvol_create_lvstore req = {}; 123 struct spdk_bdev *bdev; 124 int rc = 0; 125 enum lvs_clear_method clear_method; 126 127 if (spdk_json_decode_object(params, rpc_bdev_lvol_create_lvstore_decoders, 128 SPDK_COUNTOF(rpc_bdev_lvol_create_lvstore_decoders), 129 &req)) { 130 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 131 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 132 "spdk_json_decode_object failed"); 133 goto cleanup; 134 } 135 136 bdev = spdk_bdev_get_by_name(req.bdev_name); 137 if (bdev == NULL) { 138 SPDK_ERRLOG("bdev '%s' does not exist\n", req.bdev_name); 139 spdk_jsonrpc_send_error_response_fmt(request, -ENODEV, "Bdev %s not found", req.bdev_name); 140 goto cleanup; 141 } 142 143 if (req.clear_method != NULL) { 144 if (!strcasecmp(req.clear_method, "none")) { 145 clear_method = LVS_CLEAR_WITH_NONE; 146 } else if (!strcasecmp(req.clear_method, "unmap")) { 147 clear_method = LVS_CLEAR_WITH_UNMAP; 148 } else if (!strcasecmp(req.clear_method, "write_zeroes")) { 149 clear_method = LVS_CLEAR_WITH_WRITE_ZEROES; 150 } else { 151 spdk_jsonrpc_send_error_response(request, -EINVAL, "Invalid clear_method parameter"); 152 goto cleanup; 153 } 154 } else { 155 clear_method = LVS_CLEAR_WITH_UNMAP; 156 } 157 158 rc = vbdev_lvs_create(bdev, req.lvs_name, req.cluster_sz, clear_method, 159 rpc_lvol_store_construct_cb, request); 160 if (rc < 0) { 161 spdk_jsonrpc_send_error_response(request, -rc, spdk_strerror(rc)); 162 goto cleanup; 163 } 164 free_rpc_bdev_lvol_create_lvstore(&req); 165 166 return; 167 168 cleanup: 169 free_rpc_bdev_lvol_create_lvstore(&req); 170 } 171 SPDK_RPC_REGISTER("bdev_lvol_create_lvstore", rpc_bdev_lvol_create_lvstore, SPDK_RPC_RUNTIME) 172 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_create_lvstore, construct_lvol_store) 173 174 struct rpc_bdev_lvol_rename_lvstore { 175 char *old_name; 176 char *new_name; 177 }; 178 179 static void 180 free_rpc_bdev_lvol_rename_lvstore(struct rpc_bdev_lvol_rename_lvstore *req) 181 { 182 free(req->old_name); 183 free(req->new_name); 184 } 185 186 static const struct spdk_json_object_decoder rpc_bdev_lvol_rename_lvstore_decoders[] = { 187 {"old_name", offsetof(struct rpc_bdev_lvol_rename_lvstore, old_name), spdk_json_decode_string}, 188 {"new_name", offsetof(struct rpc_bdev_lvol_rename_lvstore, new_name), spdk_json_decode_string}, 189 }; 190 191 static void 192 rpc_bdev_lvol_rename_lvstore_cb(void *cb_arg, int lvserrno) 193 { 194 struct spdk_json_write_ctx *w; 195 struct spdk_jsonrpc_request *request = cb_arg; 196 197 if (lvserrno != 0) { 198 goto invalid; 199 } 200 201 w = spdk_jsonrpc_begin_result(request); 202 spdk_json_write_bool(w, true); 203 spdk_jsonrpc_end_result(request, w); 204 return; 205 206 invalid: 207 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 208 spdk_strerror(-lvserrno)); 209 } 210 211 static void 212 rpc_bdev_lvol_rename_lvstore(struct spdk_jsonrpc_request *request, 213 const struct spdk_json_val *params) 214 { 215 struct rpc_bdev_lvol_rename_lvstore req = {}; 216 struct spdk_lvol_store *lvs; 217 218 if (spdk_json_decode_object(params, rpc_bdev_lvol_rename_lvstore_decoders, 219 SPDK_COUNTOF(rpc_bdev_lvol_rename_lvstore_decoders), 220 &req)) { 221 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 222 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 223 "spdk_json_decode_object failed"); 224 goto cleanup; 225 } 226 227 lvs = vbdev_get_lvol_store_by_name(req.old_name); 228 if (lvs == NULL) { 229 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "no lvs existing for given name\n"); 230 spdk_jsonrpc_send_error_response_fmt(request, -ENOENT, "Lvol store %s not found", req.old_name); 231 goto cleanup; 232 } 233 234 vbdev_lvs_rename(lvs, req.new_name, rpc_bdev_lvol_rename_lvstore_cb, request); 235 236 cleanup: 237 free_rpc_bdev_lvol_rename_lvstore(&req); 238 } 239 SPDK_RPC_REGISTER("bdev_lvol_rename_lvstore", rpc_bdev_lvol_rename_lvstore, SPDK_RPC_RUNTIME) 240 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_rename_lvstore, rename_lvol_store) 241 242 struct rpc_bdev_lvol_delete_lvstore { 243 char *uuid; 244 char *lvs_name; 245 }; 246 247 static void 248 free_rpc_bdev_lvol_delete_lvstore(struct rpc_bdev_lvol_delete_lvstore *req) 249 { 250 free(req->uuid); 251 free(req->lvs_name); 252 } 253 254 static const struct spdk_json_object_decoder rpc_bdev_lvol_delete_lvstore_decoders[] = { 255 {"uuid", offsetof(struct rpc_bdev_lvol_delete_lvstore, uuid), spdk_json_decode_string, true}, 256 {"lvs_name", offsetof(struct rpc_bdev_lvol_delete_lvstore, lvs_name), spdk_json_decode_string, true}, 257 }; 258 259 static void 260 rpc_lvol_store_destroy_cb(void *cb_arg, int lvserrno) 261 { 262 struct spdk_json_write_ctx *w; 263 struct spdk_jsonrpc_request *request = cb_arg; 264 265 if (lvserrno != 0) { 266 goto invalid; 267 } 268 269 w = spdk_jsonrpc_begin_result(request); 270 spdk_json_write_bool(w, true); 271 spdk_jsonrpc_end_result(request, w); 272 return; 273 274 invalid: 275 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 276 spdk_strerror(-lvserrno)); 277 } 278 279 static void 280 rpc_bdev_lvol_delete_lvstore(struct spdk_jsonrpc_request *request, 281 const struct spdk_json_val *params) 282 { 283 struct rpc_bdev_lvol_delete_lvstore req = {}; 284 struct spdk_lvol_store *lvs = NULL; 285 int rc; 286 287 if (spdk_json_decode_object(params, rpc_bdev_lvol_delete_lvstore_decoders, 288 SPDK_COUNTOF(rpc_bdev_lvol_delete_lvstore_decoders), 289 &req)) { 290 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 291 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 292 "spdk_json_decode_object failed"); 293 goto cleanup; 294 } 295 296 rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs); 297 if (rc != 0) { 298 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 299 goto cleanup; 300 } 301 302 vbdev_lvs_destruct(lvs, rpc_lvol_store_destroy_cb, request); 303 304 cleanup: 305 free_rpc_bdev_lvol_delete_lvstore(&req); 306 } 307 SPDK_RPC_REGISTER("bdev_lvol_delete_lvstore", rpc_bdev_lvol_delete_lvstore, SPDK_RPC_RUNTIME) 308 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_delete_lvstore, destroy_lvol_store) 309 310 struct rpc_bdev_lvol_create { 311 char *uuid; 312 char *lvs_name; 313 char *lvol_name; 314 uint64_t size; 315 bool thin_provision; 316 char *clear_method; 317 }; 318 319 static void 320 free_rpc_bdev_lvol_create(struct rpc_bdev_lvol_create *req) 321 { 322 free(req->uuid); 323 free(req->lvs_name); 324 free(req->lvol_name); 325 free(req->clear_method); 326 } 327 328 static const struct spdk_json_object_decoder rpc_bdev_lvol_create_decoders[] = { 329 {"uuid", offsetof(struct rpc_bdev_lvol_create, uuid), spdk_json_decode_string, true}, 330 {"lvs_name", offsetof(struct rpc_bdev_lvol_create, lvs_name), spdk_json_decode_string, true}, 331 {"lvol_name", offsetof(struct rpc_bdev_lvol_create, lvol_name), spdk_json_decode_string}, 332 {"size", offsetof(struct rpc_bdev_lvol_create, size), spdk_json_decode_uint64}, 333 {"thin_provision", offsetof(struct rpc_bdev_lvol_create, thin_provision), spdk_json_decode_bool, true}, 334 {"clear_method", offsetof(struct rpc_bdev_lvol_create, clear_method), spdk_json_decode_string, true}, 335 }; 336 337 static void 338 rpc_bdev_lvol_create_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) 339 { 340 struct spdk_json_write_ctx *w; 341 struct spdk_jsonrpc_request *request = cb_arg; 342 343 if (lvolerrno != 0) { 344 goto invalid; 345 } 346 347 w = spdk_jsonrpc_begin_result(request); 348 spdk_json_write_string(w, lvol->unique_id); 349 spdk_jsonrpc_end_result(request, w); 350 return; 351 352 invalid: 353 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 354 spdk_strerror(-lvolerrno)); 355 } 356 357 static void 358 rpc_bdev_lvol_create(struct spdk_jsonrpc_request *request, 359 const struct spdk_json_val *params) 360 { 361 struct rpc_bdev_lvol_create req = {}; 362 enum lvol_clear_method clear_method; 363 int rc = 0; 364 struct spdk_lvol_store *lvs = NULL; 365 366 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Creating blob\n"); 367 368 if (spdk_json_decode_object(params, rpc_bdev_lvol_create_decoders, 369 SPDK_COUNTOF(rpc_bdev_lvol_create_decoders), 370 &req)) { 371 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 372 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 373 "spdk_json_decode_object failed"); 374 goto cleanup; 375 } 376 377 rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs); 378 if (rc != 0) { 379 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 380 goto cleanup; 381 } 382 383 if (req.clear_method != NULL) { 384 if (!strcasecmp(req.clear_method, "none")) { 385 clear_method = LVOL_CLEAR_WITH_NONE; 386 } else if (!strcasecmp(req.clear_method, "unmap")) { 387 clear_method = LVOL_CLEAR_WITH_UNMAP; 388 } else if (!strcasecmp(req.clear_method, "write_zeroes")) { 389 clear_method = LVOL_CLEAR_WITH_WRITE_ZEROES; 390 } else { 391 spdk_jsonrpc_send_error_response(request, -EINVAL, "Invalid clean_method option"); 392 goto cleanup; 393 } 394 } else { 395 clear_method = LVOL_CLEAR_WITH_DEFAULT; 396 } 397 398 rc = vbdev_lvol_create(lvs, req.lvol_name, req.size, req.thin_provision, 399 clear_method, rpc_bdev_lvol_create_cb, request); 400 if (rc < 0) { 401 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 402 goto cleanup; 403 } 404 405 cleanup: 406 free_rpc_bdev_lvol_create(&req); 407 } 408 409 SPDK_RPC_REGISTER("bdev_lvol_create", rpc_bdev_lvol_create, SPDK_RPC_RUNTIME) 410 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_create, construct_lvol_bdev) 411 412 struct rpc_bdev_lvol_snapshot { 413 char *lvol_name; 414 char *snapshot_name; 415 }; 416 417 static void 418 free_rpc_bdev_lvol_snapshot(struct rpc_bdev_lvol_snapshot *req) 419 { 420 free(req->lvol_name); 421 free(req->snapshot_name); 422 } 423 424 static const struct spdk_json_object_decoder rpc_bdev_lvol_snapshot_decoders[] = { 425 {"lvol_name", offsetof(struct rpc_bdev_lvol_snapshot, lvol_name), spdk_json_decode_string}, 426 {"snapshot_name", offsetof(struct rpc_bdev_lvol_snapshot, snapshot_name), spdk_json_decode_string}, 427 }; 428 429 static void 430 rpc_bdev_lvol_snapshot_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) 431 { 432 struct spdk_json_write_ctx *w; 433 struct spdk_jsonrpc_request *request = cb_arg; 434 435 if (lvolerrno != 0) { 436 goto invalid; 437 } 438 439 w = spdk_jsonrpc_begin_result(request); 440 spdk_json_write_string(w, lvol->unique_id); 441 spdk_jsonrpc_end_result(request, w); 442 return; 443 444 invalid: 445 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 446 spdk_strerror(-lvolerrno)); 447 } 448 449 static void 450 rpc_bdev_lvol_snapshot(struct spdk_jsonrpc_request *request, 451 const struct spdk_json_val *params) 452 { 453 struct rpc_bdev_lvol_snapshot req = {}; 454 struct spdk_bdev *bdev; 455 struct spdk_lvol *lvol; 456 457 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Snapshotting blob\n"); 458 459 if (spdk_json_decode_object(params, rpc_bdev_lvol_snapshot_decoders, 460 SPDK_COUNTOF(rpc_bdev_lvol_snapshot_decoders), 461 &req)) { 462 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 463 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 464 "spdk_json_decode_object failed"); 465 goto cleanup; 466 } 467 468 bdev = spdk_bdev_get_by_name(req.lvol_name); 469 if (bdev == NULL) { 470 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "bdev '%s' does not exist\n", req.lvol_name); 471 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 472 goto cleanup; 473 } 474 475 lvol = vbdev_lvol_get_from_bdev(bdev); 476 if (lvol == NULL) { 477 SPDK_ERRLOG("lvol does not exist\n"); 478 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 479 goto cleanup; 480 } 481 482 vbdev_lvol_create_snapshot(lvol, req.snapshot_name, rpc_bdev_lvol_snapshot_cb, request); 483 484 cleanup: 485 free_rpc_bdev_lvol_snapshot(&req); 486 } 487 488 SPDK_RPC_REGISTER("bdev_lvol_snapshot", rpc_bdev_lvol_snapshot, SPDK_RPC_RUNTIME) 489 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_snapshot, snapshot_lvol_bdev) 490 491 struct rpc_bdev_lvol_clone { 492 char *snapshot_name; 493 char *clone_name; 494 }; 495 496 static void 497 free_rpc_bdev_lvol_clone(struct rpc_bdev_lvol_clone *req) 498 { 499 free(req->snapshot_name); 500 free(req->clone_name); 501 } 502 503 static const struct spdk_json_object_decoder rpc_bdev_lvol_clone_decoders[] = { 504 {"snapshot_name", offsetof(struct rpc_bdev_lvol_clone, snapshot_name), spdk_json_decode_string}, 505 {"clone_name", offsetof(struct rpc_bdev_lvol_clone, clone_name), spdk_json_decode_string, true}, 506 }; 507 508 static void 509 rpc_bdev_lvol_clone_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) 510 { 511 struct spdk_json_write_ctx *w; 512 struct spdk_jsonrpc_request *request = cb_arg; 513 514 if (lvolerrno != 0) { 515 goto invalid; 516 } 517 518 w = spdk_jsonrpc_begin_result(request); 519 spdk_json_write_string(w, lvol->unique_id); 520 spdk_jsonrpc_end_result(request, w); 521 return; 522 523 invalid: 524 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 525 spdk_strerror(-lvolerrno)); 526 } 527 528 static void 529 rpc_bdev_lvol_clone(struct spdk_jsonrpc_request *request, 530 const struct spdk_json_val *params) 531 { 532 struct rpc_bdev_lvol_clone req = {}; 533 struct spdk_bdev *bdev; 534 struct spdk_lvol *lvol; 535 536 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Cloning blob\n"); 537 538 if (spdk_json_decode_object(params, rpc_bdev_lvol_clone_decoders, 539 SPDK_COUNTOF(rpc_bdev_lvol_clone_decoders), 540 &req)) { 541 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 542 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 543 "spdk_json_decode_object failed"); 544 goto cleanup; 545 } 546 547 bdev = spdk_bdev_get_by_name(req.snapshot_name); 548 if (bdev == NULL) { 549 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "bdev '%s' does not exist\n", req.snapshot_name); 550 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 551 goto cleanup; 552 } 553 554 lvol = vbdev_lvol_get_from_bdev(bdev); 555 if (lvol == NULL) { 556 SPDK_ERRLOG("lvol does not exist\n"); 557 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 558 goto cleanup; 559 } 560 561 vbdev_lvol_create_clone(lvol, req.clone_name, rpc_bdev_lvol_clone_cb, request); 562 563 cleanup: 564 free_rpc_bdev_lvol_clone(&req); 565 } 566 567 SPDK_RPC_REGISTER("bdev_lvol_clone", rpc_bdev_lvol_clone, SPDK_RPC_RUNTIME) 568 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_clone, clone_lvol_bdev) 569 570 struct rpc_bdev_lvol_rename { 571 char *old_name; 572 char *new_name; 573 }; 574 575 static void 576 free_rpc_bdev_lvol_rename(struct rpc_bdev_lvol_rename *req) 577 { 578 free(req->old_name); 579 free(req->new_name); 580 } 581 582 static const struct spdk_json_object_decoder rpc_bdev_lvol_rename_decoders[] = { 583 {"old_name", offsetof(struct rpc_bdev_lvol_rename, old_name), spdk_json_decode_string}, 584 {"new_name", offsetof(struct rpc_bdev_lvol_rename, new_name), spdk_json_decode_string}, 585 }; 586 587 static void 588 rpc_bdev_lvol_rename_cb(void *cb_arg, int lvolerrno) 589 { 590 struct spdk_json_write_ctx *w; 591 struct spdk_jsonrpc_request *request = cb_arg; 592 593 if (lvolerrno != 0) { 594 goto invalid; 595 } 596 597 w = spdk_jsonrpc_begin_result(request); 598 spdk_json_write_bool(w, true); 599 spdk_jsonrpc_end_result(request, w); 600 return; 601 602 invalid: 603 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 604 spdk_strerror(-lvolerrno)); 605 } 606 607 static void 608 rpc_bdev_lvol_rename(struct spdk_jsonrpc_request *request, 609 const struct spdk_json_val *params) 610 { 611 struct rpc_bdev_lvol_rename req = {}; 612 struct spdk_bdev *bdev; 613 struct spdk_lvol *lvol; 614 615 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Renaming lvol\n"); 616 617 if (spdk_json_decode_object(params, rpc_bdev_lvol_rename_decoders, 618 SPDK_COUNTOF(rpc_bdev_lvol_rename_decoders), 619 &req)) { 620 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 621 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 622 "spdk_json_decode_object failed"); 623 goto cleanup; 624 } 625 626 bdev = spdk_bdev_get_by_name(req.old_name); 627 if (bdev == NULL) { 628 SPDK_ERRLOG("bdev '%s' does not exist\n", req.old_name); 629 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 630 goto cleanup; 631 } 632 633 lvol = vbdev_lvol_get_from_bdev(bdev); 634 if (lvol == NULL) { 635 SPDK_ERRLOG("lvol does not exist\n"); 636 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 637 goto cleanup; 638 } 639 640 vbdev_lvol_rename(lvol, req.new_name, rpc_bdev_lvol_rename_cb, request); 641 642 cleanup: 643 free_rpc_bdev_lvol_rename(&req); 644 } 645 646 SPDK_RPC_REGISTER("bdev_lvol_rename", rpc_bdev_lvol_rename, SPDK_RPC_RUNTIME) 647 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_rename, rename_lvol_bdev) 648 649 struct rpc_bdev_lvol_inflate { 650 char *name; 651 }; 652 653 static void 654 free_rpc_bdev_lvol_inflate(struct rpc_bdev_lvol_inflate *req) 655 { 656 free(req->name); 657 } 658 659 static const struct spdk_json_object_decoder rpc_bdev_lvol_inflate_decoders[] = { 660 {"name", offsetof(struct rpc_bdev_lvol_inflate, name), spdk_json_decode_string}, 661 }; 662 663 static void 664 rpc_bdev_lvol_inflate_cb(void *cb_arg, int lvolerrno) 665 { 666 struct spdk_json_write_ctx *w; 667 struct spdk_jsonrpc_request *request = cb_arg; 668 669 if (lvolerrno != 0) { 670 goto invalid; 671 } 672 673 w = spdk_jsonrpc_begin_result(request); 674 spdk_json_write_bool(w, true); 675 spdk_jsonrpc_end_result(request, w); 676 return; 677 678 invalid: 679 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 680 spdk_strerror(-lvolerrno)); 681 } 682 683 static void 684 rpc_bdev_lvol_inflate(struct spdk_jsonrpc_request *request, 685 const struct spdk_json_val *params) 686 { 687 struct rpc_bdev_lvol_inflate req = {}; 688 struct spdk_bdev *bdev; 689 struct spdk_lvol *lvol; 690 691 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Inflating lvol\n"); 692 693 if (spdk_json_decode_object(params, rpc_bdev_lvol_inflate_decoders, 694 SPDK_COUNTOF(rpc_bdev_lvol_inflate_decoders), 695 &req)) { 696 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 697 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 698 "spdk_json_decode_object failed"); 699 goto cleanup; 700 } 701 702 bdev = spdk_bdev_get_by_name(req.name); 703 if (bdev == NULL) { 704 SPDK_ERRLOG("bdev '%s' does not exist\n", req.name); 705 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 706 goto cleanup; 707 } 708 709 lvol = vbdev_lvol_get_from_bdev(bdev); 710 if (lvol == NULL) { 711 SPDK_ERRLOG("lvol does not exist\n"); 712 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 713 goto cleanup; 714 } 715 716 spdk_lvol_inflate(lvol, rpc_bdev_lvol_inflate_cb, request); 717 718 cleanup: 719 free_rpc_bdev_lvol_inflate(&req); 720 } 721 722 SPDK_RPC_REGISTER("bdev_lvol_inflate", rpc_bdev_lvol_inflate, SPDK_RPC_RUNTIME) 723 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_inflate, inflate_lvol_bdev) 724 725 static void 726 rpc_bdev_lvol_decouple_parent(struct spdk_jsonrpc_request *request, 727 const struct spdk_json_val *params) 728 { 729 struct rpc_bdev_lvol_inflate req = {}; 730 struct spdk_bdev *bdev; 731 struct spdk_lvol *lvol; 732 733 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Decoupling parent of lvol\n"); 734 735 if (spdk_json_decode_object(params, rpc_bdev_lvol_inflate_decoders, 736 SPDK_COUNTOF(rpc_bdev_lvol_inflate_decoders), 737 &req)) { 738 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 739 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 740 "spdk_json_decode_object failed"); 741 goto cleanup; 742 } 743 744 bdev = spdk_bdev_get_by_name(req.name); 745 if (bdev == NULL) { 746 SPDK_ERRLOG("bdev '%s' does not exist\n", req.name); 747 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 748 goto cleanup; 749 } 750 751 lvol = vbdev_lvol_get_from_bdev(bdev); 752 if (lvol == NULL) { 753 SPDK_ERRLOG("lvol does not exist\n"); 754 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 755 goto cleanup; 756 } 757 758 spdk_lvol_decouple_parent(lvol, rpc_bdev_lvol_inflate_cb, request); 759 760 cleanup: 761 free_rpc_bdev_lvol_inflate(&req); 762 } 763 764 SPDK_RPC_REGISTER("bdev_lvol_decouple_parent", rpc_bdev_lvol_decouple_parent, SPDK_RPC_RUNTIME) 765 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_decouple_parent, decouple_parent_lvol_bdev) 766 767 struct rpc_bdev_lvol_resize { 768 char *name; 769 uint64_t size; 770 }; 771 772 static void 773 free_rpc_bdev_lvol_resize(struct rpc_bdev_lvol_resize *req) 774 { 775 free(req->name); 776 } 777 778 static const struct spdk_json_object_decoder rpc_bdev_lvol_resize_decoders[] = { 779 {"name", offsetof(struct rpc_bdev_lvol_resize, name), spdk_json_decode_string}, 780 {"size", offsetof(struct rpc_bdev_lvol_resize, size), spdk_json_decode_uint64}, 781 }; 782 783 static void 784 rpc_bdev_lvol_resize_cb(void *cb_arg, int lvolerrno) 785 { 786 struct spdk_json_write_ctx *w; 787 struct spdk_jsonrpc_request *request = cb_arg; 788 789 if (lvolerrno != 0) { 790 goto invalid; 791 } 792 793 w = spdk_jsonrpc_begin_result(request); 794 spdk_json_write_bool(w, true); 795 spdk_jsonrpc_end_result(request, w); 796 return; 797 798 invalid: 799 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 800 spdk_strerror(-lvolerrno)); 801 } 802 803 static void 804 rpc_bdev_lvol_resize(struct spdk_jsonrpc_request *request, 805 const struct spdk_json_val *params) 806 { 807 struct rpc_bdev_lvol_resize req = {}; 808 struct spdk_bdev *bdev; 809 struct spdk_lvol *lvol; 810 811 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Resizing lvol\n"); 812 813 if (spdk_json_decode_object(params, rpc_bdev_lvol_resize_decoders, 814 SPDK_COUNTOF(rpc_bdev_lvol_resize_decoders), 815 &req)) { 816 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 817 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 818 "spdk_json_decode_object failed"); 819 goto cleanup; 820 } 821 822 bdev = spdk_bdev_get_by_name(req.name); 823 if (bdev == NULL) { 824 SPDK_ERRLOG("no bdev for provided name %s\n", req.name); 825 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 826 goto cleanup; 827 } 828 829 lvol = vbdev_lvol_get_from_bdev(bdev); 830 if (lvol == NULL) { 831 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 832 goto cleanup; 833 } 834 835 vbdev_lvol_resize(lvol, req.size, rpc_bdev_lvol_resize_cb, request); 836 837 cleanup: 838 free_rpc_bdev_lvol_resize(&req); 839 } 840 841 SPDK_RPC_REGISTER("bdev_lvol_resize", rpc_bdev_lvol_resize, SPDK_RPC_RUNTIME) 842 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_resize, resize_lvol_bdev) 843 844 struct rpc_set_ro_lvol_bdev { 845 char *name; 846 }; 847 848 static void 849 free_rpc_set_ro_lvol_bdev(struct rpc_set_ro_lvol_bdev *req) 850 { 851 free(req->name); 852 } 853 854 static const struct spdk_json_object_decoder rpc_set_ro_lvol_bdev_decoders[] = { 855 {"name", offsetof(struct rpc_set_ro_lvol_bdev, name), spdk_json_decode_string}, 856 }; 857 858 static void 859 rpc_set_ro_lvol_bdev_cb(void *cb_arg, int lvolerrno) 860 { 861 struct spdk_json_write_ctx *w; 862 struct spdk_jsonrpc_request *request = cb_arg; 863 864 if (lvolerrno != 0) { 865 goto invalid; 866 } 867 868 w = spdk_jsonrpc_begin_result(request); 869 spdk_json_write_bool(w, true); 870 spdk_jsonrpc_end_result(request, w); 871 return; 872 873 invalid: 874 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 875 spdk_strerror(-lvolerrno)); 876 } 877 878 static void 879 rpc_bdev_lvol_set_read_only(struct spdk_jsonrpc_request *request, 880 const struct spdk_json_val *params) 881 { 882 struct rpc_set_ro_lvol_bdev req = {}; 883 struct spdk_bdev *bdev; 884 struct spdk_lvol *lvol; 885 886 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Setting lvol as read only\n"); 887 888 if (spdk_json_decode_object(params, rpc_set_ro_lvol_bdev_decoders, 889 SPDK_COUNTOF(rpc_set_ro_lvol_bdev_decoders), 890 &req)) { 891 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 892 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 893 "spdk_json_decode_object failed"); 894 goto cleanup; 895 } 896 897 if (req.name == NULL) { 898 SPDK_ERRLOG("missing name param\n"); 899 spdk_jsonrpc_send_error_response(request, -EINVAL, "Missing name parameter"); 900 goto cleanup; 901 } 902 903 bdev = spdk_bdev_get_by_name(req.name); 904 if (bdev == NULL) { 905 SPDK_ERRLOG("no bdev for provided name %s\n", req.name); 906 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 907 goto cleanup; 908 } 909 910 lvol = vbdev_lvol_get_from_bdev(bdev); 911 if (lvol == NULL) { 912 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 913 goto cleanup; 914 } 915 916 vbdev_lvol_set_read_only(lvol, rpc_set_ro_lvol_bdev_cb, request); 917 918 cleanup: 919 free_rpc_set_ro_lvol_bdev(&req); 920 } 921 922 SPDK_RPC_REGISTER("bdev_lvol_set_read_only", rpc_bdev_lvol_set_read_only, SPDK_RPC_RUNTIME) 923 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_set_read_only, set_read_only_lvol_bdev) 924 925 struct rpc_bdev_lvol_delete { 926 char *name; 927 }; 928 929 static void 930 free_rpc_bdev_lvol_delete(struct rpc_bdev_lvol_delete *req) 931 { 932 free(req->name); 933 } 934 935 static const struct spdk_json_object_decoder rpc_bdev_lvol_delete_decoders[] = { 936 {"name", offsetof(struct rpc_bdev_lvol_delete, name), spdk_json_decode_string}, 937 }; 938 939 static void 940 rpc_bdev_lvol_delete_cb(void *cb_arg, int lvolerrno) 941 { 942 struct spdk_json_write_ctx *w; 943 struct spdk_jsonrpc_request *request = cb_arg; 944 945 if (lvolerrno != 0) { 946 goto invalid; 947 } 948 949 w = spdk_jsonrpc_begin_result(request); 950 spdk_json_write_bool(w, true); 951 spdk_jsonrpc_end_result(request, w); 952 return; 953 954 invalid: 955 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 956 spdk_strerror(-lvolerrno)); 957 } 958 959 static void 960 rpc_bdev_lvol_delete(struct spdk_jsonrpc_request *request, 961 const struct spdk_json_val *params) 962 { 963 struct rpc_bdev_lvol_delete req = {}; 964 struct spdk_bdev *bdev; 965 struct spdk_lvol *lvol; 966 967 if (spdk_json_decode_object(params, rpc_bdev_lvol_delete_decoders, 968 SPDK_COUNTOF(rpc_bdev_lvol_delete_decoders), 969 &req)) { 970 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 971 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 972 "spdk_json_decode_object failed"); 973 goto cleanup; 974 } 975 976 bdev = spdk_bdev_get_by_name(req.name); 977 if (bdev == NULL) { 978 SPDK_ERRLOG("no bdev for provided name %s\n", req.name); 979 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 980 goto cleanup; 981 } 982 983 lvol = vbdev_lvol_get_from_bdev(bdev); 984 if (lvol == NULL) { 985 spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); 986 goto cleanup; 987 } 988 989 vbdev_lvol_destroy(lvol, rpc_bdev_lvol_delete_cb, request); 990 991 cleanup: 992 free_rpc_bdev_lvol_delete(&req); 993 } 994 995 SPDK_RPC_REGISTER("bdev_lvol_delete", rpc_bdev_lvol_delete, SPDK_RPC_RUNTIME) 996 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_delete, destroy_lvol_bdev) 997 998 struct rpc_bdev_lvol_get_lvstores { 999 char *uuid; 1000 char *lvs_name; 1001 }; 1002 1003 static void 1004 free_rpc_bdev_lvol_get_lvstores(struct rpc_bdev_lvol_get_lvstores *req) 1005 { 1006 free(req->uuid); 1007 free(req->lvs_name); 1008 } 1009 1010 static const struct spdk_json_object_decoder rpc_bdev_lvol_get_lvstores_decoders[] = { 1011 {"uuid", offsetof(struct rpc_bdev_lvol_get_lvstores, uuid), spdk_json_decode_string, true}, 1012 {"lvs_name", offsetof(struct rpc_bdev_lvol_get_lvstores, lvs_name), spdk_json_decode_string, true}, 1013 }; 1014 1015 static void 1016 rpc_dump_lvol_store_info(struct spdk_json_write_ctx *w, struct lvol_store_bdev *lvs_bdev) 1017 { 1018 struct spdk_blob_store *bs; 1019 uint64_t cluster_size, block_size; 1020 char uuid[SPDK_UUID_STRING_LEN]; 1021 1022 bs = lvs_bdev->lvs->blobstore; 1023 cluster_size = spdk_bs_get_cluster_size(bs); 1024 /* Block size of lvols is always size of blob store page */ 1025 block_size = spdk_bs_get_page_size(bs); 1026 1027 spdk_json_write_object_begin(w); 1028 1029 spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs_bdev->lvs->uuid); 1030 spdk_json_write_named_string(w, "uuid", uuid); 1031 1032 spdk_json_write_named_string(w, "name", lvs_bdev->lvs->name); 1033 1034 spdk_json_write_named_string(w, "base_bdev", spdk_bdev_get_name(lvs_bdev->bdev)); 1035 1036 spdk_json_write_named_uint64(w, "total_data_clusters", spdk_bs_total_data_cluster_count(bs)); 1037 1038 spdk_json_write_named_uint64(w, "free_clusters", spdk_bs_free_cluster_count(bs)); 1039 1040 spdk_json_write_named_uint64(w, "block_size", block_size); 1041 1042 spdk_json_write_named_uint64(w, "cluster_size", cluster_size); 1043 1044 spdk_json_write_object_end(w); 1045 } 1046 1047 static void 1048 rpc_bdev_lvol_get_lvstores(struct spdk_jsonrpc_request *request, 1049 const struct spdk_json_val *params) 1050 { 1051 struct rpc_bdev_lvol_get_lvstores req = {}; 1052 struct spdk_json_write_ctx *w; 1053 struct lvol_store_bdev *lvs_bdev = NULL; 1054 struct spdk_lvol_store *lvs = NULL; 1055 int rc; 1056 1057 if (params != NULL) { 1058 if (spdk_json_decode_object(params, rpc_bdev_lvol_get_lvstores_decoders, 1059 SPDK_COUNTOF(rpc_bdev_lvol_get_lvstores_decoders), 1060 &req)) { 1061 SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n"); 1062 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1063 "spdk_json_decode_object failed"); 1064 goto cleanup; 1065 } 1066 1067 rc = vbdev_get_lvol_store_by_uuid_xor_name(req.uuid, req.lvs_name, &lvs); 1068 if (rc != 0) { 1069 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 1070 goto cleanup; 1071 } 1072 1073 lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvs); 1074 if (lvs_bdev == NULL) { 1075 spdk_jsonrpc_send_error_response(request, ENODEV, spdk_strerror(-ENODEV)); 1076 goto cleanup; 1077 } 1078 } 1079 1080 w = spdk_jsonrpc_begin_result(request); 1081 spdk_json_write_array_begin(w); 1082 1083 if (lvs_bdev != NULL) { 1084 rpc_dump_lvol_store_info(w, lvs_bdev); 1085 } else { 1086 for (lvs_bdev = vbdev_lvol_store_first(); lvs_bdev != NULL; 1087 lvs_bdev = vbdev_lvol_store_next(lvs_bdev)) { 1088 rpc_dump_lvol_store_info(w, lvs_bdev); 1089 } 1090 } 1091 spdk_json_write_array_end(w); 1092 1093 spdk_jsonrpc_end_result(request, w); 1094 1095 cleanup: 1096 free_rpc_bdev_lvol_get_lvstores(&req); 1097 } 1098 1099 SPDK_RPC_REGISTER("bdev_lvol_get_lvstores", rpc_bdev_lvol_get_lvstores, SPDK_RPC_RUNTIME) 1100 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_get_lvstores, get_lvol_stores) 1101