Commit 90a6407d authored by Yifan Bian's avatar Yifan Bian Committed by Tomasz Zawadzki
Browse files

ublk: add an rpc method to get current ublk devices



Signed-off-by: default avatarYifan Bian <yifan.bian@intel.com>
Co-authored-by: default avatarXiaodong Liu <xiaodong.liu@intel.com>
Change-Id: I3fdf9795b90d7a30478ba81d8144bbf2f1cbdd2a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15987


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarXiaodong Liu <xiaodong.liu@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent e8a94a71
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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
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

### accel
+44 −0
Original line number Diff line number Diff line
@@ -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}

SPDK supports exporting bdevs through Linux nbd. These devices then appear as standard Linux kernel block devices
+28 −0
Original line number Diff line number Diff line
@@ -561,6 +561,34 @@ ublk_dev_find_by_id(uint32_t ublk_id)
	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 *
ublk_dev_get_bdev_name(struct spdk_ublk_dev *ublk)
{
+5 −0
Original line number Diff line number Diff line
@@ -25,7 +25,12 @@ 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);
uint32_t ublk_dev_get_id(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
}
+72 −0
Original line number Diff line number Diff line
@@ -187,3 +187,75 @@ invalid:
}

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)
Loading