diff --git a/lib/bdev/rbd/bdev_rbd.c b/lib/bdev/rbd/bdev_rbd.c index f0d077058c..a7d079e96a 100644 --- a/lib/bdev/rbd/bdev_rbd.c +++ b/lib/bdev/rbd/bdev_rbd.c @@ -656,6 +656,17 @@ spdk_bdev_rbd_create(const char *name, const char *pool_name, const char *rbd_na return &rbd->disk; } +void +spdk_bdev_rbd_delete(struct spdk_bdev *bdev, spdk_delete_rbd_complete cb_fn, void *cb_arg) +{ + if (!bdev || bdev->module != &rbd_if) { + cb_fn(cb_arg, -ENODEV); + return; + } + + spdk_bdev_unregister(bdev, cb_fn, cb_arg); +} + static int bdev_rbd_library_init(void) { diff --git a/lib/bdev/rbd/bdev_rbd.h b/lib/bdev/rbd/bdev_rbd.h index 9d1701d835..dd2448e120 100644 --- a/lib/bdev/rbd/bdev_rbd.h +++ b/lib/bdev/rbd/bdev_rbd.h @@ -38,7 +38,18 @@ #include "spdk/bdev.h" +typedef void (*spdk_delete_rbd_complete)(void *cb_arg, int bdeverrno); + struct spdk_bdev *spdk_bdev_rbd_create(const char *name, const char *pool_name, const char *rbd_name, uint32_t block_size); +/** + * Delete rbd bdev. + * + * \param bdev Pointer to rbd bdev. + * \param cb_fn Function to call after deletion. + * \param cb_arg Argument to pass to cb_fn. + */ +void spdk_bdev_rbd_delete(struct spdk_bdev *bdev, spdk_delete_rbd_complete cb_fn, + void *cb_arg); #endif // SPDK_BDEV_RBD_H diff --git a/lib/bdev/rbd/bdev_rbd_rpc.c b/lib/bdev/rbd/bdev_rbd_rpc.c index 655a766e4e..745a90ed4f 100644 --- a/lib/bdev/rbd/bdev_rbd_rpc.c +++ b/lib/bdev/rbd/bdev_rbd_rpc.c @@ -34,7 +34,7 @@ #include "bdev_rbd.h" #include "spdk/rpc.h" #include "spdk/util.h" - +#include "spdk/string.h" #include "spdk_internal/log.h" struct rpc_construct_rbd { @@ -95,3 +95,63 @@ invalid: free_rpc_construct_rbd(&req); } SPDK_RPC_REGISTER("construct_rbd_bdev", spdk_rpc_construct_rbd_bdev, SPDK_RPC_RUNTIME) + +struct rpc_delete_rbd { + char *name; +}; + +static void +free_rpc_delete_rbd(struct rpc_delete_rbd *req) +{ + free(req->name); +} + +static const struct spdk_json_object_decoder rpc_delete_rbd_decoders[] = { + {"name", offsetof(struct rpc_delete_rbd, name), spdk_json_decode_string}, +}; + +static void +_spdk_rpc_delete_rbd_bdev_cb(void *cb_arg, int bdeverrno) +{ + struct spdk_jsonrpc_request *request = cb_arg; + struct spdk_json_write_ctx *w; + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_bool(w, bdeverrno == 0); + spdk_jsonrpc_end_result(request, w); +} + +static void +spdk_rpc_delete_rbd_bdev(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_delete_rbd req = {NULL}; + struct spdk_bdev *bdev; + int rc; + + if (spdk_json_decode_object(params, rpc_delete_rbd_decoders, + SPDK_COUNTOF(rpc_delete_rbd_decoders), + &req)) { + rc = -EINVAL; + goto invalid; + } + + bdev = spdk_bdev_get_by_name(req.name); + if (bdev == NULL) { + rc = -ENODEV; + goto invalid; + } + + spdk_bdev_rbd_delete(bdev, _spdk_rpc_delete_rbd_bdev_cb, request); + free_rpc_delete_rbd(&req); + return; + +invalid: + free_rpc_delete_rbd(&req); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc)); +} +SPDK_RPC_REGISTER("delete_rbd_bdev", spdk_rpc_delete_rbd_bdev, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index c1c5969f21..33064a2d77 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -250,6 +250,15 @@ if __name__ == "__main__": p.add_argument('block_size', help='rbd block size', type=int) p.set_defaults(func=construct_rbd_bdev) + @call_cmd + def delete_rbd_bdev(args): + rpc.bdev.delete_rbd_bdev(args.client, + name=args.name) + + p = subparsers.add_parser('delete_rbd_bdev', help='Delete a rbd bdev') + p.add_argument('name', help='rbd bdev name') + p.set_defaults(func=delete_rbd_bdev) + @call_cmd def construct_error_bdev(args): print(rpc.bdev.construct_error_bdev(args.client, diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index ce85298adc..26306b0b68 100755 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -158,6 +158,16 @@ def construct_rbd_bdev(client, pool_name, rbd_name, block_size, name=None): return client.call('construct_rbd_bdev', params) +def delete_rbd_bdev(client, name): + """Remove rbd bdev from the system. + + Args: + name: name of rbd bdev to delete + """ + params = {'name': name} + return client.call('delete_rbd_bdev', params) + + def construct_error_bdev(client, base_name): """Construct an error injection block device. diff --git a/test/iscsi_tgt/rbd/rbd.sh b/test/iscsi_tgt/rbd/rbd.sh index 4abb73e765..53547e2a4a 100755 --- a/test/iscsi_tgt/rbd/rbd.sh +++ b/test/iscsi_tgt/rbd/rbd.sh @@ -34,7 +34,7 @@ timing_exit start_iscsi_tgt $rpc_py add_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT $rpc_py add_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK -$rpc_py construct_rbd_bdev $RBD_POOL $RBD_NAME 4096 +rbd_bdev="$($rpc_py construct_rbd_bdev $RBD_POOL $RBD_NAME 4096)" $rpc_py get_bdevs # "Ceph0:0" ==> use Ceph0 blockdev for LUN0 # "1:2" ==> map PortalGroup1 to InitiatorGroup2 @@ -57,6 +57,7 @@ rm -f ./local-job0-0-verify.state trap - SIGINT SIGTERM EXIT iscsicleanup +$rpc_py delete_rbd_bdev $rbd_bdev killprocess $pid rbd_cleanup diff --git a/test/json_config/clear_config.py b/test/json_config/clear_config.py index 775ef907c8..1ae8b89ccd 100755 --- a/test/json_config/clear_config.py +++ b/test/json_config/clear_config.py @@ -48,9 +48,9 @@ def delete_subbdevs(args, bdev, rpc_bdevs): def get_bdev_destroy_method(bdev): destroy_method_map = {'construct_nvme_bdev': "delete_bdev", 'construct_pmem_bdev': "delete_bdev", - 'construct_rbd_bdev': "delete_bdev", 'construct_malloc_bdev': "delete_malloc_bdev", 'construct_null_bdev': "delete_null_bdev", + 'construct_rbd_bdev': "delete_rbd_bdev", 'construct_aio_bdev': "delete_aio_bdev", 'construct_error_bdev': "delete_error_bdev", 'construct_split_vbdev': "destruct_split_vbdev",