ublk: add an rpc method to get current ublk devices

Signed-off-by: Yifan Bian <yifan.bian@intel.com>
Co-authored-by: Xiaodong Liu <xiaodong.liu@intel.com>
Change-Id: I3fdf9795b90d7a30478ba81d8144bbf2f1cbdd2a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15987
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Xiaodong Liu <xiaodong.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Yifan Bian 2022-12-16 08:40:11 +00:00 committed by Tomasz Zawadzki
parent e8a94a7122
commit 90a6407df6
7 changed files with 174 additions and 0 deletions

View File

@ -176,6 +176,15 @@ For the active-active policy of the multipath mode, in addition to the default r
selector, the minimum queue depth path selector was added. The minimum queue depth path selector selector, the minimum queue depth path selector was added. The minimum queue depth path selector
selects an I/O path according to the number of outstanding requests of each nvme qpair. selects an I/O path according to the number of outstanding requests of each nvme qpair.
### ublk device
The ublk application supports the ublk kernel driver. It's implemented as a ublk backend
in spdk_tgt and could be started with specifying configuration. See the
[ublk](https://www.kernel.org/doc/html/latest/block/ublk.html) documentation for more details.
ublk bdev could export a block device via Linux ublk. It will move this backend device into userspace
as `/dev/ublkb*`. Before to adding ublk device, need to create ublk target by rpc methond.
## v22.09 ## v22.09
### accel ### accel

View File

@ -10831,6 +10831,50 @@ Example response:
} }
~~~ ~~~
### ublk_get_disks {#rpc_ublk_get_disks}
Display full or specified ublk device list
#### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
ublk_id | Optional | int | ublk device id to display
#### Response
Display ublk device list
#### Example
Example request:
~~~json
{
"jsonrpc": "2.0",
"method": "ublk_get_disks",
"id": 1
}
~~~
Example response:
~~~json
{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"ublk_device": "/dev/ublkb1",
"id": 1,
"queue_depth": 512,
"num_queues": 1,
"bdev_name": "Malloc1"
}
]
}
~~~
## Linux Network Block Device (NBD) {#jsonrpc_components_nbd} ## Linux Network Block Device (NBD) {#jsonrpc_components_nbd}
SPDK supports exporting bdevs through Linux nbd. These devices then appear as standard Linux kernel block devices SPDK supports exporting bdevs through Linux nbd. These devices then appear as standard Linux kernel block devices

View File

@ -561,6 +561,34 @@ ublk_dev_find_by_id(uint32_t ublk_id)
return NULL; return NULL;
} }
uint32_t
ublk_dev_get_id(struct spdk_ublk_dev *ublk)
{
return ublk->ublk_id;
}
struct spdk_ublk_dev *ublk_dev_first(void)
{
return TAILQ_FIRST(&g_ublk_bdevs);
}
struct spdk_ublk_dev *ublk_dev_next(struct spdk_ublk_dev *prev)
{
return TAILQ_NEXT(prev, tailq);
}
uint32_t
ublk_dev_get_queue_depth(struct spdk_ublk_dev *ublk)
{
return ublk->queue_depth;
}
uint32_t
ublk_dev_get_num_queues(struct spdk_ublk_dev *ublk)
{
return ublk->num_queues;
}
const char * const char *
ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk) ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk)
{ {

View File

@ -25,7 +25,12 @@ int ublk_start_disk(const char *bdev_name, uint32_t ublk_id,
uint32_t num_queues, uint32_t queue_depth); uint32_t num_queues, uint32_t queue_depth);
int ublk_stop_disk(uint32_t ublk_id, ublk_del_cb del_cb, void *cb_arg); int ublk_stop_disk(uint32_t ublk_id, ublk_del_cb del_cb, void *cb_arg);
struct spdk_ublk_dev *ublk_dev_find_by_id(uint32_t ublk_id); struct spdk_ublk_dev *ublk_dev_find_by_id(uint32_t ublk_id);
uint32_t ublk_dev_get_id(struct spdk_ublk_dev *ublk);
const char *ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk); const char *ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk);
struct spdk_ublk_dev *ublk_dev_first(void);
struct spdk_ublk_dev *ublk_dev_next(struct spdk_ublk_dev *prev);
uint32_t ublk_dev_get_queue_depth(struct spdk_ublk_dev *ublk);
uint32_t ublk_dev_get_num_queues(struct spdk_ublk_dev *ublk);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -187,3 +187,75 @@ invalid:
} }
SPDK_RPC_REGISTER("ublk_stop_disk", rpc_ublk_stop_disk, SPDK_RPC_RUNTIME) SPDK_RPC_REGISTER("ublk_stop_disk", rpc_ublk_stop_disk, SPDK_RPC_RUNTIME)
static void
rpc_dump_ublk_info(struct spdk_json_write_ctx *w,
struct spdk_ublk_dev *ublk)
{
char ublk_path[32];
snprintf(ublk_path, 32, "%s%u", "/dev/ublkb", ublk_dev_get_id(ublk));
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "ublk_device", ublk_path);
spdk_json_write_named_uint32(w, "id", ublk_dev_get_id(ublk));
spdk_json_write_named_uint32(w, "queue_depth", ublk_dev_get_queue_depth(ublk));
spdk_json_write_named_uint32(w, "num_queues", ublk_dev_get_num_queues(ublk));
spdk_json_write_named_string(w, "bdev_name", ublk_dev_get_bdev_name(ublk));
spdk_json_write_object_end(w);
}
struct rpc_ublk_get_disks {
uint32_t ublk_id;
};
static const struct spdk_json_object_decoder rpc_ublk_get_disks_decoders[] = {
{"ublk_id", offsetof(struct rpc_ublk_get_disks, ublk_id), spdk_json_decode_uint32, true},
};
static void
rpc_ublk_get_disks(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_ublk_get_disks req = {};
struct spdk_json_write_ctx *w;
struct spdk_ublk_dev *ublk = NULL;
if (params != NULL) {
if (spdk_json_decode_object(params, rpc_ublk_get_disks_decoders,
SPDK_COUNTOF(rpc_ublk_get_disks_decoders),
&req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"spdk_json_decode_object failed");
return;
}
if (req.ublk_id) {
ublk = ublk_dev_find_by_id(req.ublk_id);
if (ublk == NULL) {
SPDK_ERRLOG("ublk device '%d' does not exist\n", req.ublk_id);
spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
return;
}
}
}
w = spdk_jsonrpc_begin_result(request);
spdk_json_write_array_begin(w);
if (ublk != NULL) {
rpc_dump_ublk_info(w, ublk);
} else {
for (ublk = ublk_dev_first(); ublk != NULL; ublk = ublk_dev_next(ublk)) {
rpc_dump_ublk_info(w, ublk);
}
}
spdk_json_write_array_end(w);
spdk_jsonrpc_end_result(request, w);
return;
}
SPDK_RPC_REGISTER("ublk_get_disks", rpc_ublk_get_disks, SPDK_RPC_RUNTIME)

View File

@ -28,3 +28,10 @@ def ublk_start_disk(client, bdev_name, ublk_id=1, num_queues=1, queue_depth=128)
def ublk_stop_disk(client, ublk_id=1): def ublk_stop_disk(client, ublk_id=1):
params = {'ublk_id': ublk_id} params = {'ublk_id': ublk_id}
return client.call('ublk_stop_disk', params) return client.call('ublk_stop_disk', params)
def ublk_get_disks(client, ublk_id=1):
params = {}
if ublk_id:
params['ublk_id'] = ublk_id
return client.call('ublk_get_disks', params)

View File

@ -2260,6 +2260,15 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.add_argument('ublk_id', help='ublk device id to be deleted. Example: 1.', type=int) p.add_argument('ublk_id', help='ublk device id to be deleted. Example: 1.', type=int)
p.set_defaults(func=ublk_stop_disk) p.set_defaults(func=ublk_stop_disk)
def ublk_get_disks(args):
print_dict(rpc.ublk.ublk_get_disks(args.client,
ublk_id=args.ublk_id))
p = subparsers.add_parser('ublk_get_disks',
help='Display full or specified ublk device list')
p.add_argument('-n', '--ublk-id', help="ublk device id. Example: 1", type=int, required=False)
p.set_defaults(func=ublk_get_disks)
# nbd # nbd
def nbd_start_disk(args): def nbd_start_disk(args):
print(rpc.nbd.nbd_start_disk(args.client, print(rpc.nbd.nbd_start_disk(args.client,