diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a4f79483..5d589df6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -153,6 +153,8 @@ A new RPC, `framework_get_reactors`, has been added to retrieve a list of all re `nvmf_set_config` now takes an argument to enable passthru of identify commands to base NVMe devices. Please see the nvmf section above for more details. +A new RPC, `bdev_rbd_resize` has been added to resize the Ceph RBD bdev. + ### scsi `spdk_scsi_lun_get_dif_ctx` now takes an additional argument of type `spdk_scsi_task`. diff --git a/doc/bdev.md b/doc/bdev.md index 2552d6f5b..1320011de 100644 --- a/doc/bdev.md +++ b/doc/bdev.md @@ -119,6 +119,12 @@ To remove a block device representation use the bdev_rbd_delete command. `rpc.py bdev_rbd_delete Rbd0` +To resize a bdev use the bdev_rbd_resize command. + +`rpc.py bdev_rbd_resize Rbd0 4096` + +This command will resize the Rbd0 bdev to 4096 MiB. + # Compression Virtual Bdev Module {#bdev_config_compress} The compression bdev module can be configured to provide compression/decompression diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index cee57a5eb..58484fa5a 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -1853,6 +1853,49 @@ Example response: } ~~~ +## bdev_rbd_resize {#rpc_bdev_rbd_resize} + +Resize @ref bdev_config_rbd bdev + +This method is available only if SPDK was build with Ceph RBD support. + +### Result + +`true` if bdev with provided name was resized or `false` otherwise. + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Required | string | Bdev name +new_size | Required | int | New bdev size for resize operation in MiB + +### Example + +Example request: + +~~~ +{ + "params": { + "name": "Rbd0" + "new_size": "4096" + }, + "jsonrpc": "2.0", + "method": "bdev_rbd_resize", + "id": 1 +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + ## bdev_delay_create {#rpc_bdev_delay_create} Create delay bdev. This bdev type redirects all IO to it's base bdev and inserts a delay on the completion diff --git a/module/bdev/rbd/bdev_rbd.c b/module/bdev/rbd/bdev_rbd.c index 01ef50edb..2cb78fa00 100644 --- a/module/bdev/rbd/bdev_rbd.c +++ b/module/bdev/rbd/bdev_rbd.c @@ -783,6 +783,44 @@ spdk_bdev_rbd_delete(struct spdk_bdev *bdev, spdk_delete_rbd_complete cb_fn, voi spdk_bdev_unregister(bdev, cb_fn, cb_arg); } +int +spdk_bdev_rbd_resize(struct spdk_bdev *bdev, const uint64_t new_size_in_mb) +{ + struct spdk_io_channel *ch; + struct bdev_rbd_io_channel *rbd_io_ch; + int rc; + uint64_t new_size_in_byte; + uint64_t current_size_in_mb; + + if (bdev->module != &rbd_if) { + return -EINVAL; + } + + current_size_in_mb = bdev->blocklen * bdev->blockcnt / (1024 * 1024); + if (current_size_in_mb > new_size_in_mb) { + SPDK_ERRLOG("The new bdev size must be lager than current bdev size.\n"); + return -EINVAL; + } + + ch = bdev_rbd_get_io_channel(bdev); + rbd_io_ch = spdk_io_channel_get_ctx(ch); + new_size_in_byte = new_size_in_mb * 1024 * 1024; + + rc = rbd_resize(rbd_io_ch->image, new_size_in_byte); + if (rc != 0) { + SPDK_ERRLOG("failed to resize the ceph bdev.\n"); + return rc; + } + + rc = spdk_bdev_notify_blockcnt_change(bdev, new_size_in_byte / bdev->blocklen); + if (rc != 0) { + SPDK_ERRLOG("failed to notify block cnt change.\n"); + return rc; + } + + return rc; +} + static int bdev_rbd_library_init(void) { diff --git a/module/bdev/rbd/bdev_rbd.h b/module/bdev/rbd/bdev_rbd.h index d62df027f..344bb85e3 100644 --- a/module/bdev/rbd/bdev_rbd.h +++ b/module/bdev/rbd/bdev_rbd.h @@ -57,4 +57,12 @@ int spdk_bdev_rbd_create(struct spdk_bdev **bdev, const char *name, const char * void spdk_bdev_rbd_delete(struct spdk_bdev *bdev, spdk_delete_rbd_complete cb_fn, void *cb_arg); +/** + * Resize rbd bdev. + * + * \param bdev Pointer to rbd bdev. + * \param new_size_in_mb The new size in MiB for this bdev. + */ +int spdk_bdev_rbd_resize(struct spdk_bdev *bdev, const uint64_t new_size_in_mb); + #endif /* SPDK_BDEV_RBD_H */ diff --git a/module/bdev/rbd/bdev_rbd_rpc.c b/module/bdev/rbd/bdev_rbd_rpc.c index ff9c7b6fd..55bafa2aa 100644 --- a/module/bdev/rbd/bdev_rbd_rpc.c +++ b/module/bdev/rbd/bdev_rbd_rpc.c @@ -197,3 +197,56 @@ cleanup: } SPDK_RPC_REGISTER("bdev_rbd_delete", spdk_rpc_bdev_rbd_delete, SPDK_RPC_RUNTIME) SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_rbd_delete, delete_rbd_bdev) + +struct rpc_bdev_rbd_resize { + char *name; + uint64_t new_size; +}; + +static const struct spdk_json_object_decoder rpc_bdev_rbd_resize_decoders[] = { + {"name", offsetof(struct rpc_bdev_rbd_resize, name), spdk_json_decode_string}, + {"new_size", offsetof(struct rpc_bdev_rbd_resize, new_size), spdk_json_decode_uint64} +}; + +static void +free_rpc_bdev_rbd_resize(struct rpc_bdev_rbd_resize *req) +{ + free(req->name); +} + +static void +spdk_rpc_bdev_rbd_resize(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_bdev_rbd_resize req = {}; + struct spdk_bdev *bdev; + struct spdk_json_write_ctx *w; + int rc; + + if (spdk_json_decode_object(params, rpc_bdev_rbd_resize_decoders, + SPDK_COUNTOF(rpc_bdev_rbd_resize_decoders), + &req)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "spdk_json_decode_object failed"); + goto cleanup; + } + + bdev = spdk_bdev_get_by_name(req.name); + if (bdev == NULL) { + spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); + goto cleanup; + } + + rc = spdk_bdev_rbd_resize(bdev, req.new_size); + if (rc) { + spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); + goto cleanup; + } + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +cleanup: + free_rpc_bdev_rbd_resize(&req); +} +SPDK_RPC_REGISTER("bdev_rbd_resize", spdk_rpc_bdev_rbd_resize, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index d6f58c19f..32b2bd5ea 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -541,6 +541,20 @@ if __name__ == "__main__": p.add_argument('name', help='rbd bdev name') p.set_defaults(func=bdev_rbd_delete) + def bdev_rbd_resize(args): + print_json(rpc.bdev.bdev_rbd_resize(args.client, + name=args.name, + new_size=int(args.new_size))) + rpc.bdev.bdev_rbd_resize(args.client, + name=args.name, + new_size=int(args.new_size)) + + p = subparsers.add_parser('bdev_rbd_resize', + help='Resize a rbd bdev') + p.add_argument('name', help='rbd bdev name') + p.add_argument('new_size', help='new bdev size for resize operation. The unit is MiB') + p.set_defaults(func=bdev_rbd_resize) + def bdev_delay_create(args): print_json(rpc.bdev.bdev_delay_create(args.client, base_bdev_name=args.base_bdev_name, diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index 301805ead..4ed51dc92 100644 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -585,6 +585,20 @@ def bdev_rbd_delete(client, name): return client.call('bdev_rbd_delete', params) +def bdev_rbd_resize(client, name, new_size): + """Resize rbd bdev in the system. + + Args: + name: name of rbd bdev to resize + new_size: new bdev size of resize operation. The unit is MiB + """ + params = { + 'name': name, + 'new_size': new_size, + } + return client.call('bdev_rbd_resize', params) + + @deprecated_alias('construct_error_bdev') def bdev_error_create(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 73f6dec5b..6369e8bad 100755 --- a/test/iscsi_tgt/rbd/rbd.sh +++ b/test/iscsi_tgt/rbd/rbd.sh @@ -40,6 +40,15 @@ $rpc_py iscsi_create_portal_group $PORTAL_TAG $TARGET_IP:$ISCSI_PORT $rpc_py iscsi_create_initiator_group $INITIATOR_TAG $INITIATOR_NAME $NETMASK rbd_bdev="$($rpc_py bdev_rbd_create $RBD_POOL $RBD_NAME 4096)" $rpc_py bdev_get_bdevs + +$rpc_py bdev_rbd_resize $rbd_bdev 2000 +num_block=$($rpc_py bdev_get_bdevs|grep num_blocks|sed 's/[^[:digit:]]//g') +# get the bdev size in MiB. +total_size=$(( num_block * 4096/ 1048576 )) +if [ $total_size != 2000 ];then + echo "resize failed." + exit 1 +fi # "Ceph0:0" ==> use Ceph0 blockdev for LUN0 # "1:2" ==> map PortalGroup1 to InitiatorGroup2 # "64" ==> iSCSI queue depth 64