bdev/opal: Add rpc for init, revert and get info

Add bdev_nvme_opal_init, bdev_nvme_opal_revert,
bdev_opal_get_info rpc commands.

Change-Id: Ib53492c02a1c18603834640d23f9fb2e7eb08657
Signed-off-by: Chunyang Hui <chunyang.hui@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/468917
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Chunyang Hui 2019-10-23 21:29:17 +08:00 committed by Jim Harris
parent 5f42a71745
commit 36c9ac2dde
9 changed files with 502 additions and 0 deletions

View File

@ -5468,6 +5468,80 @@ Example response:
# OPAL
## bdev_nvme_opal_init {#rpc_bdev_nvme_opal_init}
This is used to initialize OPAL of a given NVMe ctrlr, including taking ownership and activating.
### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nvme_ctrlr_name | Required | string | name of nvme ctrlr
password | Required | string | admin password of OPAL
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"method": "bdev_nvme_opal_init",
"id": 1,
"params": {
"nvme_ctrlr_name": "nvme0",
"password": "*****"
}
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
~~~
## bdev_nvme_opal_revert {#rpc_bdev_nvme_opal_revert}
This is used to revert OPAL to its factory settings. Erase all user configuration and data.
### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
nvme_ctrlr_name | Required | string | name of nvme ctrlr
password | Required | string | admin password of OPAL
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"method": "bdev_nvme_opal_revert",
"id": 1,
"params": {
"nvme_ctrlr_name": "nvme0",
"password": "*****"
}
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
~~~
## bdev_opal_create {#rpc_bdev_opal_create}
This is used to create an OPAL virtual bdev.
@ -5517,6 +5591,55 @@ Example response:
}
~~~
## bdev_opal_get_info {#rpc_bdev_opal_get_info}
This is used to get information of a given OPAL bdev.
### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
bdev_name | Required | string | name of OPAL vbdev
password | Required | string | admin password
### Response
The response is the locking info of OPAL virtual bdev.
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"method": "bdev_opal_get_info",
"id": 1,
"params": {
"bdev_name": "nvme0n1r1",
"password": "*****"
}
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"name": "nvme0n1r1",
"range_start": 0,
"range_length": 4096,
"read_lock_enabled": true,
"write_lock_enabled": true,
"read_locked": false,
"write_locked": false
}
}
~~~
## bdev_opal_delete {#rpc_bdev_opal_delete}
This is used to delete OPAL vbdev.

View File

@ -226,7 +226,13 @@ bdev_nvme_ctrlr_destruct(struct nvme_bdev_ctrlr *nvme_bdev_ctrlr)
{
assert(nvme_bdev_ctrlr->destruct);
if (nvme_bdev_ctrlr->opal_dev) {
if (nvme_bdev_ctrlr->opal_poller != NULL) {
spdk_poller_unregister(&nvme_bdev_ctrlr->opal_poller);
/* wait until we get the result */
while (spdk_opal_revert_poll(nvme_bdev_ctrlr->opal_dev) == -EAGAIN);
}
spdk_opal_close(nvme_bdev_ctrlr->opal_dev);
nvme_bdev_ctrlr->opal_dev = NULL;
}
pthread_mutex_lock(&g_bdev_nvme_mutex);
TAILQ_REMOVE(&g_nvme_bdev_ctrlrs, nvme_bdev_ctrlr, tailq);

View File

@ -66,6 +66,7 @@ struct nvme_bdev_ctrlr {
struct nvme_bdev *bdevs;
struct spdk_opal_dev *opal_dev;
struct spdk_poller *opal_poller;
struct spdk_poller *adminq_timer_poller;

View File

@ -228,6 +228,50 @@ vbdev_opal_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_
}
}
struct spdk_opal_locking_range_info *
spdk_vbdev_opal_get_info_from_bdev(const char *opal_bdev_name, const char *password)
{
struct opal_vbdev *vbdev;
struct nvme_bdev_ctrlr *nvme_ctrlr;
int locking_range_id;
int rc;
TAILQ_FOREACH(vbdev, &g_opal_vbdev, tailq) {
if (strcmp(vbdev->name, opal_bdev_name) == 0) {
break;
}
}
if (vbdev == NULL) {
SPDK_ERRLOG("%s not found\n", opal_bdev_name);
return NULL;
}
nvme_ctrlr = vbdev->nvme_ctrlr;
if (nvme_ctrlr == NULL) {
SPDK_ERRLOG("can't find nvme_ctrlr of %s\n", vbdev->name);
return NULL;
}
if (spdk_opal_get_max_locking_ranges(nvme_ctrlr->opal_dev) == 0) {
rc = spdk_opal_cmd_get_max_ranges(nvme_ctrlr->opal_dev, password);
if (rc) {
SPDK_ERRLOG("Get locking range number failure: %d\n", rc);
return NULL;
}
}
locking_range_id = vbdev->cfg.locking_range_id;
rc = spdk_opal_cmd_get_locking_range_info(nvme_ctrlr->opal_dev, password,
OPAL_ADMIN1, locking_range_id);
if (rc) {
SPDK_ERRLOG("Get locking range info error: %d\n", rc);
return NULL;
}
return spdk_opal_get_locking_range_info(nvme_ctrlr->opal_dev, locking_range_id);
}
static int
vbdev_opal_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
{
@ -514,6 +558,7 @@ spdk_vbdev_opal_destruct(const char *bdev_name, const char *password)
goto err;
}
spdk_opal_free_locking_range_info(opal_bdev->opal_dev, locking_range_id);
vbdev_opal_destruct_bdev(opal_bdev);
return 0;
@ -528,4 +573,36 @@ vbdev_opal_examine(struct spdk_bdev *bdev)
spdk_bdev_module_examine_done(&opal_if);
}
static int
vbdev_opal_recv_poll(void *arg)
{
struct nvme_bdev_ctrlr *nvme_ctrlr = arg;
int rc;
rc = spdk_opal_revert_poll(nvme_ctrlr->opal_dev);
if (rc == -EAGAIN) {
return -1;
}
/* receive end */
spdk_poller_unregister(&nvme_ctrlr->opal_poller);
nvme_ctrlr->opal_poller = NULL;
return 1;
}
int
spdk_vbdev_opal_revert_tper(struct nvme_bdev_ctrlr *nvme_ctrlr, const char *password,
spdk_opal_revert_cb cb_fn, void *cb_ctx)
{
int rc;
rc = spdk_opal_cmd_revert_tper_async(nvme_ctrlr->opal_dev, password, cb_fn, cb_ctx);
if (rc) {
SPDK_ERRLOG("%s revert tper failure: %d\n", nvme_ctrlr->name, rc);
return rc;
}
nvme_ctrlr->opal_poller = spdk_poller_register(vbdev_opal_recv_poll, nvme_ctrlr, 50);
return 0;
}
SPDK_LOG_REGISTER_COMPONENT("vbdev_opal", SPDK_LOG_VBDEV_OPAL)

View File

@ -40,6 +40,11 @@
int spdk_vbdev_opal_create(const char *nvme_ctrlr_name, uint32_t nsid, uint8_t locking_range_id,
uint64_t range_start, uint64_t range_length, const char *password);
struct spdk_opal_locking_range_info *spdk_vbdev_opal_get_info_from_bdev(const char *opal_bdev_name,
const char *password);
int spdk_vbdev_opal_destruct(const char *bdev_name, const char *password);
int spdk_vbdev_opal_revert_tper(struct nvme_bdev_ctrlr *nvme_ctrlr, const char *password,
spdk_opal_revert_cb cb_fn, void *cb_ctx);
#endif

View File

@ -38,6 +38,160 @@
#include "vbdev_opal.h"
struct rpc_bdev_nvme_opal_init {
char *nvme_ctrlr_name;
char *password;
};
static void
free_rpc_bdev_nvme_opal_init(struct rpc_bdev_nvme_opal_init *req)
{
free(req->nvme_ctrlr_name);
free(req->password);
}
static const struct spdk_json_object_decoder rpc_bdev_nvme_opal_init_decoders[] = {
{"nvme_ctrlr_name", offsetof(struct rpc_bdev_nvme_opal_init, nvme_ctrlr_name), spdk_json_decode_string},
{"password", offsetof(struct rpc_bdev_nvme_opal_init, password), spdk_json_decode_string},
};
static void
spdk_rpc_bdev_nvme_opal_init(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_bdev_nvme_opal_init req = {};
struct spdk_json_write_ctx *w;
struct nvme_bdev_ctrlr *nvme_ctrlr;
int rc;
if (spdk_json_decode_object(params, rpc_bdev_nvme_opal_init_decoders,
SPDK_COUNTOF(rpc_bdev_nvme_opal_init_decoders),
&req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
goto out;
}
/* check if opal supported */
nvme_ctrlr = nvme_bdev_ctrlr_get_by_name(req.nvme_ctrlr_name);
if (nvme_ctrlr == NULL || nvme_ctrlr->opal_dev == NULL ||
!spdk_opal_supported(nvme_ctrlr->opal_dev)) {
SPDK_ERRLOG("%s not support opal\n", req.nvme_ctrlr_name);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
goto out;
}
/* take ownership */
rc = spdk_opal_cmd_take_ownership(nvme_ctrlr->opal_dev, req.password);
if (rc) {
SPDK_ERRLOG("Take ownership failure: %d\n", rc);
switch (rc) {
case -EBUSY:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"SP Busy, try again later");
break;
case -EACCES:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"This drive is already enabled");
break;
default:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
}
goto out;
}
/* activate locking SP */
rc = spdk_opal_cmd_activate_locking_sp(nvme_ctrlr->opal_dev, req.password);
if (rc) {
SPDK_ERRLOG("Activate locking SP failure: %d\n", rc);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
goto out;
}
w = spdk_jsonrpc_begin_result(request);
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(request, w);
out:
free_rpc_bdev_nvme_opal_init(&req);
}
SPDK_RPC_REGISTER("bdev_nvme_opal_init", spdk_rpc_bdev_nvme_opal_init, SPDK_RPC_RUNTIME)
struct rpc_bdev_nvme_opal_revert {
char *nvme_ctrlr_name;
char *password;
};
static void
free_rpc_bdev_nvme_opal_revert(struct rpc_bdev_nvme_opal_revert *req)
{
free(req->nvme_ctrlr_name);
free(req->password);
}
static const struct spdk_json_object_decoder rpc_bdev_nvme_opal_revert_decoders[] = {
{"nvme_ctrlr_name", offsetof(struct rpc_bdev_nvme_opal_revert, nvme_ctrlr_name), spdk_json_decode_string},
{"password", offsetof(struct rpc_bdev_nvme_opal_revert, password), spdk_json_decode_string},
};
static void
revert_tper_done(struct spdk_opal_dev *dev, void *data, int rc)
{
struct nvme_bdev_ctrlr *ctrlr = data;
if (rc != 0) {
SPDK_ERRLOG("%s revert TPer failed\n", ctrlr->name);
return;
}
SPDK_NOTICELOG("%s revert TPer done\n", ctrlr->name);
}
static void
spdk_rpc_bdev_nvme_opal_revert(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_bdev_nvme_opal_revert req = {};
struct spdk_json_write_ctx *w;
struct nvme_bdev_ctrlr *nvme_ctrlr;
int rc;
if (spdk_json_decode_object(params, rpc_bdev_nvme_opal_revert_decoders,
SPDK_COUNTOF(rpc_bdev_nvme_opal_revert_decoders),
&req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
goto out;
}
/* check if opal supported */
nvme_ctrlr = nvme_bdev_ctrlr_get_by_name(req.nvme_ctrlr_name);
if (nvme_ctrlr == NULL || nvme_ctrlr->opal_dev == NULL ||
!spdk_opal_supported(nvme_ctrlr->opal_dev)) {
SPDK_ERRLOG("%s not support opal\n", req.nvme_ctrlr_name);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
goto out;
}
/* TODO: delete all opal vbdev before revert TPer */
rc = spdk_vbdev_opal_revert_tper(nvme_ctrlr, req.password, revert_tper_done,
nvme_ctrlr);
if (rc) {
SPDK_ERRLOG("Revert TPer failure: %d\n", rc);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
goto out;
}
w = spdk_jsonrpc_begin_result(request);
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(request, w);
out:
free_rpc_bdev_nvme_opal_revert(&req);
}
SPDK_RPC_REGISTER("bdev_nvme_opal_revert", spdk_rpc_bdev_nvme_opal_revert, SPDK_RPC_RUNTIME)
struct rpc_bdev_opal_create {
char *nvme_ctrlr_name;
uint32_t nsid;
@ -101,6 +255,65 @@ out:
}
SPDK_RPC_REGISTER("bdev_opal_create", spdk_rpc_bdev_opal_create, SPDK_RPC_RUNTIME)
struct rpc_bdev_opal_get_info {
char *bdev_name;
char *password;
};
static void
free_rpc_bdev_opal_get_info(struct rpc_bdev_opal_get_info *req)
{
free(req->bdev_name);
free(req->password);
}
static const struct spdk_json_object_decoder rpc_bdev_opal_get_info_decoders[] = {
{"bdev_name", offsetof(struct rpc_bdev_opal_get_info, bdev_name), spdk_json_decode_string},
{"password", offsetof(struct rpc_bdev_opal_get_info, password), spdk_json_decode_string},
};
static void
spdk_rpc_bdev_opal_get_info(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_bdev_opal_get_info req = {};
struct spdk_json_write_ctx *w;
struct spdk_opal_locking_range_info *info;
if (spdk_json_decode_object(params, rpc_bdev_opal_get_info_decoders,
SPDK_COUNTOF(rpc_bdev_opal_get_info_decoders),
&req)) {
SPDK_ERRLOG("spdk_json_decode_object failed\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
goto out;
}
info = spdk_vbdev_opal_get_info_from_bdev(req.bdev_name, req.password);
if (info == NULL) {
SPDK_ERRLOG("Get opal info failure\n");
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
goto out;
}
w = spdk_jsonrpc_begin_result(request);
spdk_json_write_object_begin(w);
spdk_json_write_named_string(w, "name", req.bdev_name);
spdk_json_write_named_uint64(w, "range_start", info->range_start);
spdk_json_write_named_uint64(w, "range_length", info->range_length);
spdk_json_write_named_bool(w, "read_lock_enabled", info->read_lock_enabled);
spdk_json_write_named_bool(w, "write_lock_enabled", info->write_lock_enabled);
spdk_json_write_named_bool(w, "read_locked", info->read_locked);
spdk_json_write_named_bool(w, "write_locked", info->write_locked);
spdk_json_write_object_end(w);
spdk_jsonrpc_end_result(request, w);
out:
free_rpc_bdev_opal_get_info(&req);
}
SPDK_RPC_REGISTER("bdev_opal_get_info", spdk_rpc_bdev_opal_get_info, SPDK_RPC_RUNTIME)
struct rpc_bdev_opal_delete {
char *bdev_name;
char *password;

View File

@ -2014,6 +2014,25 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.set_defaults(func=ioat_scan_copy_engine)
# opal
def bdev_nvme_opal_init(args):
rpc.nvme.bdev_nvme_opal_init(args.client,
nvme_ctrlr_name=args.nvme_ctrlr_name,
password=args.password)
p = subparsers.add_parser('bdev_nvme_opal_init', help='take ownership and activate')
p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
p.add_argument('-p', '--password', help='password for admin')
p.set_defaults(func=bdev_nvme_opal_init)
def bdev_nvme_opal_revert(args):
rpc.nvme.bdev_nvme_opal_revert(args.client,
nvme_ctrlr_name=args.nvme_ctrlr_name,
password=args.password)
p = subparsers.add_parser('bdev_nvme_opal_revert', help='Revert to default factory settings')
p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name')
p.add_argument('-p', '--password', help='password')
p.set_defaults(func=bdev_nvme_opal_revert)
def bdev_opal_create(args):
print_json(rpc.bdev.bdev_opal_create(args.client,
nvme_ctrlr_name=args.nvme_ctrlr_name,
@ -2032,6 +2051,16 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.add_argument('-p', '--password', help='admin password', required=True)
p.set_defaults(func=bdev_opal_create)
def bdev_opal_get_info(args):
print_dict(rpc.bdev.bdev_opal_get_info(args.client,
bdev_name=args.bdev_name,
password=args.password))
p = subparsers.add_parser('bdev_opal_get_info', help='get opal locking range info for this bdev')
p.add_argument('-b', '--bdev-name', help='opal bdev')
p.add_argument('-p', '--password', help='password')
p.set_defaults(func=bdev_opal_get_info)
def bdev_opal_delete(args):
rpc.bdev.bdev_opal_delete(args.client,
bdev_name=args.bdev_name,

View File

@ -689,6 +689,24 @@ def bdev_opal_create(client, nvme_ctrlr_name, nsid, locking_range_id, range_star
return client.call('bdev_opal_create', params)
def bdev_opal_get_info(client, bdev_name, password):
"""Get opal locking range info.
Args:
bdev_name: name of opal vbdev to get info
password: admin password
Returns:
Locking range info.
"""
params = {
'bdev_name': bdev_name,
'password': password,
}
return client.call('bdev_opal_get_info', params)
def bdev_opal_delete(client, bdev_name, password):
"""Delete opal virtual bdev from the system.

View File

@ -55,3 +55,33 @@ def bdev_nvme_get_controllers(client, name=None):
if name:
params['name'] = name
return client.call('bdev_nvme_get_controllers', params)
def bdev_nvme_opal_init(client, nvme_ctrlr_name, password):
"""Init nvme opal. Take ownership and activate
Args:
nvme_ctrlr_name: name of nvme ctrlr
password: password to init opal
"""
params = {
'nvme_ctrlr_name': nvme_ctrlr_name,
'password': password,
}
return client.call('bdev_nvme_opal_init', params)
def bdev_nvme_opal_revert(client, nvme_ctrlr_name, password):
"""Revert opal to default factory settings. Erase all data.
Args:
nvme_ctrlr_name: name of nvme ctrlr
password: password
"""
params = {
'nvme_ctrlr_name': nvme_ctrlr_name,
'password': password,
}
return client.call('bdev_nvme_opal_revert', params)