ublk: add ublk to export block device
ublk could export a backend device as ublk block device (/dev/ublkb*). A rpc method is used to add ublk device and it should be done after creating ublk target. Corresponding, ublk_del_dev is used to delete the specified ublk device. Signed-off-by: Yifan Bian <yifan.bian@intel.com> Co-authored-by: Xiaodong Liu <xiaodong.liu@intel.com> Change-Id: I3a4ba8d8dc5f5ad241511ccbc9d3336b582a6dc5 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15976 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Xiaodong Liu <xiaodong.liu@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Paul Luse <paul.e.luse@intel.com>
This commit is contained in:
parent
a1944e0170
commit
e8a94a7122
@ -10749,6 +10749,88 @@ Example response:
|
||||
}
|
||||
~~~
|
||||
|
||||
### ublk_start_disk {#rpc_ublk_start_disk}
|
||||
|
||||
Start to export one SPDK bdev as a UBLK device
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
bdev_name | Required | string | Bdev name to export
|
||||
ublk_id | Required | int | Device id
|
||||
queue_depth | Optional | int | Device queue depth
|
||||
num_queues | Optional | int | Total number of device queues
|
||||
|
||||
#### Response
|
||||
|
||||
UBLK device ID
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"params": {
|
||||
"ublk_id": "1",
|
||||
"bdev_name": "Malloc1"
|
||||
},
|
||||
"jsonrpc": "2.0",
|
||||
"method": "ublk_start_disk",
|
||||
"id": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
### ublk_stop_disk {#rpc_ublk_stop_disk}
|
||||
|
||||
Delete a UBLK device
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
ublk_id | Required | int | Device id to delete
|
||||
|
||||
#### Response
|
||||
|
||||
True if UBLK device is deleted successfully; False if failed.
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"params": {
|
||||
"ublk_id": "1",
|
||||
},
|
||||
"jsonrpc": "2.0",
|
||||
"method": "ublk_stop_disk",
|
||||
"id": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": true
|
||||
}
|
||||
~~~
|
||||
|
||||
## 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
|
||||
|
1170
lib/ublk/ublk.c
1170
lib/ublk/ublk.c
File diff suppressed because it is too large
Load Diff
@ -10,12 +10,22 @@
|
||||
|
||||
#include "spdk/ublk.h"
|
||||
|
||||
#define UBLK_DEV_QUEUE_DEPTH 128
|
||||
#define UBLK_DEV_NUM_QUEUE 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*ublk_del_cb)(void *cb_arg);
|
||||
|
||||
int ublk_create_target(const char *cpumask_str);
|
||||
int ublk_destroy_target(spdk_ublk_fini_cb cb_fn, void *cb_arg);
|
||||
int ublk_start_disk(const char *bdev_name, uint32_t ublk_id,
|
||||
uint32_t num_queues, uint32_t queue_depth);
|
||||
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);
|
||||
const char *ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -75,3 +75,115 @@ rpc_ublk_destroy_target(struct spdk_jsonrpc_request *request, const struct spdk_
|
||||
}
|
||||
}
|
||||
SPDK_RPC_REGISTER("ublk_destroy_target", rpc_ublk_destroy_target, SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_ublk_start_disk {
|
||||
char *bdev_name;
|
||||
uint32_t ublk_id;
|
||||
uint32_t num_queues;
|
||||
uint32_t queue_depth;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_ublk_start_disk_decoders[] = {
|
||||
{"bdev_name", offsetof(struct rpc_ublk_start_disk, bdev_name), spdk_json_decode_string},
|
||||
{"ublk_id", offsetof(struct rpc_ublk_start_disk, ublk_id), spdk_json_decode_uint32},
|
||||
{"num_queues", offsetof(struct rpc_ublk_start_disk, num_queues), spdk_json_decode_uint32, true},
|
||||
{"queue_depth", offsetof(struct rpc_ublk_start_disk, queue_depth), spdk_json_decode_uint32, true},
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_ublk_start_disk(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct spdk_json_write_ctx *w;
|
||||
struct rpc_ublk_start_disk req = {};
|
||||
int rc;
|
||||
|
||||
req.queue_depth = UBLK_DEV_QUEUE_DEPTH;
|
||||
req.num_queues = UBLK_DEV_NUM_QUEUE;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_ublk_start_disk_decoders,
|
||||
SPDK_COUNTOF(rpc_ublk_start_disk_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");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = ublk_start_disk(req.bdev_name, req.ublk_id, req.num_queues, req.queue_depth);
|
||||
if (rc != 0) {
|
||||
spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(request);
|
||||
spdk_json_write_uint32(w, req.ublk_id);
|
||||
spdk_jsonrpc_end_result(request, w);
|
||||
goto out;
|
||||
|
||||
out:
|
||||
free(req.bdev_name);
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("ublk_start_disk", rpc_ublk_start_disk, SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_ublk_stop_disk {
|
||||
uint32_t ublk_id;
|
||||
struct spdk_jsonrpc_request *request;
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_ublk_stop_disk(struct rpc_ublk_stop_disk *req)
|
||||
{
|
||||
free(req);
|
||||
}
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_ublk_stop_disk_decoders[] = {
|
||||
{"ublk_id", offsetof(struct rpc_ublk_stop_disk, ublk_id), spdk_json_decode_uint32},
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_ublk_stop_disk_done(void *cb_arg)
|
||||
{
|
||||
struct rpc_ublk_stop_disk *req = cb_arg;
|
||||
|
||||
spdk_jsonrpc_send_bool_response(req->request, true);
|
||||
free_rpc_ublk_stop_disk(req);
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_ublk_stop_disk(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_ublk_stop_disk *req;
|
||||
int rc;
|
||||
|
||||
req = calloc(1, sizeof(*req));
|
||||
if (req == NULL) {
|
||||
SPDK_ERRLOG("could not allocate request.\n");
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
|
||||
return;
|
||||
}
|
||||
req->request = request;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_ublk_stop_disk_decoders,
|
||||
SPDK_COUNTOF(rpc_ublk_stop_disk_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");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rc = ublk_stop_disk(req->ublk_id, rpc_ublk_stop_disk_done, req);
|
||||
if (rc) {
|
||||
spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
|
||||
goto invalid;
|
||||
}
|
||||
return;
|
||||
|
||||
invalid:
|
||||
free_rpc_ublk_stop_disk(req);
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("ublk_stop_disk", rpc_ublk_stop_disk, SPDK_RPC_RUNTIME)
|
||||
|
@ -11,3 +11,20 @@ def ublk_create_target(client, cpumask=None):
|
||||
|
||||
def ublk_destroy_target(client):
|
||||
return client.call('ublk_destroy_target')
|
||||
|
||||
|
||||
def ublk_start_disk(client, bdev_name, ublk_id=1, num_queues=1, queue_depth=128):
|
||||
params = {
|
||||
'bdev_name': bdev_name,
|
||||
'ublk_id': ublk_id
|
||||
}
|
||||
if num_queues:
|
||||
params['num_queues'] = num_queues
|
||||
if queue_depth:
|
||||
params['queue_depth'] = queue_depth
|
||||
return client.call('ublk_start_disk', params)
|
||||
|
||||
|
||||
def ublk_stop_disk(client, ublk_id=1):
|
||||
params = {'ublk_id': ublk_id}
|
||||
return client.call('ublk_stop_disk', params)
|
||||
|
@ -2236,6 +2236,30 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
|
||||
help='Destroy spdk ublk target for ublk dev')
|
||||
p.set_defaults(func=ublk_destroy_target)
|
||||
|
||||
def ublk_start_disk(args):
|
||||
print(rpc.ublk.ublk_start_disk(args.client,
|
||||
bdev_name=args.bdev_name,
|
||||
ublk_id=args.ublk_id,
|
||||
num_queues=args.num_queues,
|
||||
queue_depth=args.queue_depth))
|
||||
|
||||
p = subparsers.add_parser('ublk_start_disk',
|
||||
help='Export a bdev as a ublk device')
|
||||
p.add_argument('bdev_name', help='Blockdev name to be exported. Example: Malloc0.')
|
||||
p.add_argument('ublk_id', help='ublk device id to be assigned. Example: 1.', type=int)
|
||||
p.add_argument('-q', '--num-queues', help="the total number of queues. Example: 1", type=int, required=False)
|
||||
p.add_argument('-d', '--queue-depth', help="queue depth. Example: 128", type=int, required=False)
|
||||
p.set_defaults(func=ublk_start_disk)
|
||||
|
||||
def ublk_stop_disk(args):
|
||||
rpc.ublk.ublk_stop_disk(args.client,
|
||||
ublk_id=args.ublk_id)
|
||||
|
||||
p = subparsers.add_parser('ublk_stop_disk',
|
||||
help='Stop a ublk device')
|
||||
p.add_argument('ublk_id', help='ublk device id to be deleted. Example: 1.', type=int)
|
||||
p.set_defaults(func=ublk_stop_disk)
|
||||
|
||||
# nbd
|
||||
def nbd_start_disk(args):
|
||||
print(rpc.nbd.nbd_start_disk(args.client,
|
||||
|
Loading…
Reference in New Issue
Block a user