Commit f3c14b8d authored by Mike Gerdts's avatar Mike Gerdts Committed by Jim Harris
Browse files

vbdev_lvol: add bdev_lvol_get_lvols RPC



This provides information about logical volumes without providing
information about the bdevs. It is useful for listing the lvols
associated with specific lvol stores and for listing lvols that are
degraded and have no associated bdev.

Signed-off-by: default avatarMike Gerdts <mgerdts@nvidia.com>
Change-Id: I795161ac88d9707831d9fcd2079635c7e46ecc42
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/17547


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent a67e0eb3
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@ New API `spdk_lvol_iter_immediate_clones` was added to iterate the clones of an
New APIs `spdk_lvol_get_by_uuid` and `spdk_lvol_get_by_names` to get lvols by the lvol's UUID or
lvstore and lvol names.

New `bdev_lvol_get_lvols` RPC to list logical volumes. This provides information about logical
volumes without providing information about the bdevs. It is useful for listing the lvols
associated with specific lvol stores and for listing lvols that are degraded and have no
associated bdev.

### nvmf

New `spdk_nvmf_request_copy_to/from_buf()` APIs have been added, which support
+52 −0
Original line number Diff line number Diff line
@@ -9903,6 +9903,58 @@ Example response:
}
~~~

### bdev_lvol_get_lvols {#rpc_bdev_lvol_get_lvols}

Get a list of logical volumes. This list can be limited by lvol store and will display volumes even if
they are degraded. Degraded lvols do not have an associated bdev, thus this RPC call may return lvols
not returned by `bdev_get_bdevs`.

#### Parameters

Name                    | Optional | Type        | Description
----------------------- | -------- | ----------- | -----------
lvs_uuid                | Optional | string      | Only show volumes in the logical volume store with this UUID
lvs_name                | Optional | string      | Only show volumes in the logical volume store with this name

Either lvs_uuid or lvs_name may be specified, but not both.
If both lvs_uuid and lvs_name are omitted, information about lvols in all logical volume stores is returned.

#### Example

Example request:

~~~json
{
  "jsonrpc": "2.0",
  "method": "bdev_lvol_get_lvols",
  "id": 1,
  "params": {
    "lvs_name": "lvs_test"
  }
}
~~~

Example response:

~~~json
[
  {
    "alias": "lvs_test/lvol1",
    "uuid": "b335c368-851d-4099-81e0-018cc494fdf6",
    "name": "lvol1",
    "is_thin_provisioned": false,
    "is_snapshot": false,
    "is_clone": false,
    "is_esnap_clone": false,
    "is_degraded": false,
    "lvs": {
      "name": "lvs_test",
      "uuid": "a1c8d950-5715-4558-936d-ab9e6eca0794"
    }
  }
]
~~~

## RAID

### bdev_raid_get_bdevs {#rpc_bdev_raid_get_bdevs}
+6 −0
Original line number Diff line number Diff line
@@ -150,6 +150,12 @@ bdev_lvol_create [-h] [-u UUID] [-l LVS_NAME] [-t] [-c CLEAR_METHOD] lvol_name s
    optional arguments:
    -h, --help  show help
    -c, --clear-method specify data clusters clear method "none", "unmap" (default), "write_zeroes"
bdev_lvol_get_lvols [-h] [-u LVS_UUID] [-l LVS_NAME]
    Display logical volume list, including those that do not have associated bdevs.
    optional arguments:
    -h, --help  show help
    -u LVS_UUID, --lvs_uuid UUID  show volumes only in the specified lvol store
    -l LVS_NAME, --lvs_name LVS_NAME  show volumes only in the specified lvol store
bdev_get_bdevs [-h] [-b NAME]
    User can view created bdevs using this call including those created on top of lvols.
    optional arguments:
+107 −0
Original line number Diff line number Diff line
@@ -1149,6 +1149,113 @@ cleanup:
SPDK_RPC_REGISTER("bdev_lvol_get_lvstores", rpc_bdev_lvol_get_lvstores, SPDK_RPC_RUNTIME)
SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_lvol_get_lvstores, get_lvol_stores)

struct rpc_bdev_lvol_get_lvols {
	char *lvs_uuid;
	char *lvs_name;
};

static void
free_rpc_bdev_lvol_get_lvols(struct rpc_bdev_lvol_get_lvols *req)
{
	free(req->lvs_uuid);
	free(req->lvs_name);
}

static const struct spdk_json_object_decoder rpc_bdev_lvol_get_lvols_decoders[] = {
	{"lvs_uuid", offsetof(struct rpc_bdev_lvol_get_lvols, lvs_uuid), spdk_json_decode_string, true},
	{"lvs_name", offsetof(struct rpc_bdev_lvol_get_lvols, lvs_name), spdk_json_decode_string, true},
};

static void
rpc_dump_lvol(struct spdk_json_write_ctx *w, struct spdk_lvol *lvol)
{
	struct spdk_lvol_store *lvs = lvol->lvol_store;
	char uuid[SPDK_UUID_STRING_LEN];

	spdk_json_write_object_begin(w);

	spdk_json_write_named_string_fmt(w, "alias", "%s/%s", lvs->name, lvol->name);
	spdk_json_write_named_string(w, "uuid", lvol->uuid_str);
	spdk_json_write_named_string(w, "name", lvol->name);
	spdk_json_write_named_bool(w, "is_thin_provisioned", spdk_blob_is_thin_provisioned(lvol->blob));
	spdk_json_write_named_bool(w, "is_snapshot", spdk_blob_is_snapshot(lvol->blob));
	spdk_json_write_named_bool(w, "is_clone", spdk_blob_is_clone(lvol->blob));
	spdk_json_write_named_bool(w, "is_esnap_clone", spdk_blob_is_esnap_clone(lvol->blob));
	spdk_json_write_named_bool(w, "is_degraded", spdk_blob_is_degraded(lvol->blob));

	spdk_json_write_named_object_begin(w, "lvs");
	spdk_json_write_named_string(w, "name", lvs->name);
	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs->uuid);
	spdk_json_write_named_string(w, "uuid", uuid);
	spdk_json_write_object_end(w);

	spdk_json_write_object_end(w);
}

static void
rpc_dump_lvols(struct spdk_json_write_ctx *w, struct lvol_store_bdev *lvs_bdev)
{
	struct spdk_lvol_store *lvs = lvs_bdev->lvs;
	struct spdk_lvol *lvol;

	TAILQ_FOREACH(lvol, &lvs->lvols, link) {
		rpc_dump_lvol(w, lvol);
	}
}

static void
rpc_bdev_lvol_get_lvols(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
{
	struct rpc_bdev_lvol_get_lvols req = {};
	struct spdk_json_write_ctx *w;
	struct lvol_store_bdev *lvs_bdev = NULL;
	struct spdk_lvol_store *lvs = NULL;
	int rc;

	if (params != NULL) {
		if (spdk_json_decode_object(params, rpc_bdev_lvol_get_lvols_decoders,
					    SPDK_COUNTOF(rpc_bdev_lvol_get_lvols_decoders),
					    &req)) {
			SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
							 "spdk_json_decode_object failed");
			goto cleanup;
		}

		rc = vbdev_get_lvol_store_by_uuid_xor_name(req.lvs_uuid, req.lvs_name, &lvs);
		if (rc != 0) {
			spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
			goto cleanup;
		}

		lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvs);
		if (lvs_bdev == NULL) {
			spdk_jsonrpc_send_error_response(request, ENODEV, spdk_strerror(-ENODEV));
			goto cleanup;
		}
	}

	w = spdk_jsonrpc_begin_result(request);
	spdk_json_write_array_begin(w);

	if (lvs_bdev != NULL) {
		rpc_dump_lvols(w, lvs_bdev);
	} else {
		for (lvs_bdev = vbdev_lvol_store_first(); lvs_bdev != NULL;
		     lvs_bdev = vbdev_lvol_store_next(lvs_bdev)) {
			rpc_dump_lvols(w, lvs_bdev);
		}
	}
	spdk_json_write_array_end(w);

	spdk_jsonrpc_end_result(request, w);

cleanup:
	free_rpc_bdev_lvol_get_lvols(&req);
}

SPDK_RPC_REGISTER("bdev_lvol_get_lvols", rpc_bdev_lvol_get_lvols, SPDK_RPC_RUNTIME)

struct rpc_bdev_lvol_grow_lvstore {
	char *uuid;
	char *lvs_name;
+21 −0
Original line number Diff line number Diff line
@@ -261,3 +261,24 @@ def bdev_lvol_get_lvstores(client, uuid=None, lvs_name=None):
    if lvs_name:
        params['lvs_name'] = lvs_name
    return client.call('bdev_lvol_get_lvstores', params)


def bdev_lvol_get_lvols(client, lvs_uuid=None, lvs_name=None):
    """List logical volumes

    Args:
        lvs_uuid: Only show volumes in the logical volume store with this UUID (optional)
        lvs_name: Only show volumes in the logical volume store with this name (optional)

    Either lvs_uuid or lvs_name may be specified, but not both.
    If both lvs_uuid and lvs_name are omitted, information about volumes in all
    logical volume stores is returned.
    """
    if (lvs_uuid and lvs_name):
        raise ValueError("Exactly one of uuid or lvs_name may be specified")
    params = {}
    if lvs_uuid:
        params['lvs_uuid'] = lvs_uuid
    if lvs_name:
        params['lvs_name'] = lvs_name
    return client.call('bdev_lvol_get_lvols', params)
Loading