Commit 8000cedb authored by Rafal Stefanowski's avatar Rafal Stefanowski Committed by Tomasz Zawadzki
Browse files

bdev/ocf: Add runtime cache bdev flush support



Introduce two RPC calls for starting flush and getting flush
status of OCF cache bdev:
- bdev_ocf_flush_start
- bdev_ocf_flush_status

Signed-off-by: default avatarRobert Baldyga <robert.baldyga@intel.com>
Signed-off-by: default avatarRafal Stefanowski <rafal.stefanowski@intel.com>
Change-Id: I1d659da6fc51396e0d070af35372ee130c40ae8b
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/8961


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
parent 6ee39210
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
@@ -2859,6 +2859,101 @@ Example response:
}
~~~

### bdev_ocf_flush_start {#rpc_bdev_ocf_flush_start}

Start flushing OCF cache device.

Automatic flushes of dirty data are managed by OCF cleaning policy settings.
In addition to that, all dirty data is flushed to core device when there is
an attempt to stop caching.
On the other hand, this RPC call gives a possibility to flush dirty data manually
when there is a need for it, e.g. to speed up the shutdown process when data
hasn't been flushed for a long time.
This RPC returns immediately, and flush is then being performed in the
background. To see the status of flushing operation use bdev_ocf_flush_status.

#### Parameters

Name                    | Optional | Type        | Description
----------------------- | -------- | ----------- | -----------
name                    | Required | string      | Bdev name

#### Example

Example request:

~~~json
{
  "params": {
    "name": "ocf0"
  },
  "jsonrpc": "2.0",
  "method": "bdev_ocf_flush_start",
  "id": 1
}
~~~

Example response:

~~~json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": true
}
~~~

### bdev_ocf_flush_status {#rpc_bdev_ocf_flush_status}

Get flush status of OCF cache device.

Automatic flushes of dirty data are managed by OCF cleaning policy settings.
In addition to that, all dirty data is flushed to core device when there is
an attempt to stop caching.
On the other hand, there is a possibility to flush dirty data manually
when there is a need for it, e.g. to speed up the shutdown process when data
hasn't been flushed for a long time.
This RPC reports if such manual flush is still in progress and if the operation
was successful. To start manual flush use bdev_ocf_flush_start.

#### Parameters

Name                    | Optional | Type        | Description
----------------------- | -------- | ----------- | -----------
name                    | Required | string      | Bdev name

#### Response

Status of OCF cache device flush.

#### Example

Example request:

~~~json
{
  "params": {
    "name": "ocf0"
  },
  "jsonrpc": "2.0",
  "method": "bdev_ocf_flush_status",
  "id": 1
}
~~~

Example response:

~~~json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "in_progress": false,
    "status": 0
  }
}
~~~

### bdev_malloc_create {#rpc_bdev_malloc_create}

Construct @ref bdev_config_malloc
+8 −1
Original line number Diff line number Diff line
@@ -141,9 +141,16 @@ struct vbdev_ocf {

	/* Management context */
	struct vbdev_ocf_mngt_ctx    mngt_ctx;
	/* Cache conext */

	/* Cache context */
	struct vbdev_ocf_cache_ctx  *cache_ctx;

	/* Status of flushing operation */
	struct {
		bool in_progress;
		int status;
	} flush;

	/* Exposed SPDK bdev. Registered in bdev layer */
	struct spdk_bdev             exp_bdev;

+126 −0
Original line number Diff line number Diff line
@@ -438,3 +438,129 @@ end:
	free_rpc_bdev_ocf_set_seqcutoff(&req);
}
SPDK_RPC_REGISTER("bdev_ocf_set_seqcutoff", rpc_bdev_ocf_set_seqcutoff, SPDK_RPC_RUNTIME)

struct get_ocf_flush_start_ctx {
	struct spdk_jsonrpc_request *request;
	struct vbdev_ocf *vbdev;
};

static void
rpc_bdev_ocf_flush_start_cmpl(ocf_cache_t cache, void *priv, int error)
{
	struct get_ocf_flush_start_ctx *ctx = priv;

	ctx->vbdev->flush.in_progress = false;
	ctx->vbdev->flush.status = error;

	ocf_mngt_cache_read_unlock(cache);

	free(ctx);
}

static void
rpc_bdev_ocf_flush_start_lock_cmpl(ocf_cache_t cache, void *priv, int error)
{
	struct get_ocf_flush_start_ctx *ctx = priv;

	if (error) {
		spdk_jsonrpc_send_error_response_fmt(ctx->request,
						     SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
						     "Could not lock cache: %d", error);
		free(ctx);
		return;
	}

	ctx->vbdev->flush.in_progress = true;
	ocf_mngt_cache_flush(cache, rpc_bdev_ocf_flush_start_cmpl, ctx);

	spdk_jsonrpc_send_bool_response(ctx->request, true);
}

static void
rpc_bdev_ocf_flush_start(struct spdk_jsonrpc_request *request,
			 const struct spdk_json_val *params)
{
	struct rpc_bdev_ocf_name req = {NULL};
	struct get_ocf_flush_start_ctx *ctx;
	int status;

	ctx = calloc(1, sizeof(*ctx));
	if (!ctx) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 "Not enough memory to process request");
		goto end;
	}

	status = spdk_json_decode_object(params, rpc_bdev_ocf_name_decoders,
					 SPDK_COUNTOF(rpc_bdev_ocf_name_decoders),
					 &req);
	if (status) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 "Invalid parameters");
		free(ctx);
		goto end;
	}

	ctx->vbdev = vbdev_ocf_get_by_name(req.name);
	if (ctx->vbdev == NULL) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 spdk_strerror(ENODEV));
		free(ctx);
		goto end;
	}

	if (!ctx->vbdev->ocf_cache) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 "Couldn't flush cache: device not attached");
		free(ctx);
		goto end;
	}

	ctx->request = request;
	ocf_mngt_cache_read_lock(ctx->vbdev->ocf_cache, rpc_bdev_ocf_flush_start_lock_cmpl, ctx);

end:
	free_rpc_bdev_ocf_name(&req);
}
SPDK_RPC_REGISTER("bdev_ocf_flush_start", rpc_bdev_ocf_flush_start, SPDK_RPC_RUNTIME)

static void
rpc_bdev_ocf_flush_status(struct spdk_jsonrpc_request *request,
			  const struct spdk_json_val *params)
{
	struct rpc_bdev_ocf_name req = {NULL};
	struct spdk_json_write_ctx *w;
	struct vbdev_ocf *vbdev;
	int status;

	status = spdk_json_decode_object(params, rpc_bdev_ocf_name_decoders,
					 SPDK_COUNTOF(rpc_bdev_ocf_name_decoders),
					 &req);
	if (status) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 "Invalid parameters");
		goto end;
	}

	vbdev = vbdev_ocf_get_by_name(req.name);
	if (vbdev == NULL) {
		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
						 spdk_strerror(ENODEV));
		goto end;
	}

	w = spdk_jsonrpc_begin_result(request);

	spdk_json_write_object_begin(w);
	spdk_json_write_named_bool(w, "in_progress", vbdev->flush.in_progress);
	if (!vbdev->flush.in_progress) {
		spdk_json_write_named_int32(w, "status", vbdev->flush.status);
	}
	spdk_json_write_object_end(w);

	spdk_jsonrpc_end_result(request, w);

end:
	free_rpc_bdev_ocf_name(&req);
}
SPDK_RPC_REGISTER("bdev_ocf_flush_status", rpc_bdev_ocf_flush_status, SPDK_RPC_RUNTIME)
+29 −0
Original line number Diff line number Diff line
@@ -234,6 +234,35 @@ def bdev_ocf_set_seqcutoff(client, name, policy, threshold, promotion_count):
    return client.call('bdev_ocf_set_seqcutoff', params)


def bdev_ocf_flush_start(client, name):
    """Start flushing OCF cache device

    Args:
        name: name of OCF bdev
    """
    params = {
        'name': name,
    }

    return client.call('bdev_ocf_flush_start', params)


def bdev_ocf_flush_status(client, name):
    """Get flush status of OCF cache device

    Args:
        name: name of OCF bdev

    Returns:
        Flush status
    """
    params = {
        'name': name,
    }

    return client.call('bdev_ocf_flush_status', params)


def bdev_malloc_create(client, num_blocks, block_size, name=None, uuid=None, optimal_io_boundary=None,
                       md_size=None, md_interleave=None, dif_type=None, dif_is_head_of_md=None):
    """Construct a malloc block device.
+14 −0
Original line number Diff line number Diff line
@@ -364,6 +364,20 @@ if __name__ == "__main__":
                   help='Sequential cutoff policy')
    p.set_defaults(func=bdev_ocf_set_seqcutoff)

    def bdev_ocf_flush_start(args):
        rpc.bdev.bdev_ocf_flush_start(args.client, name=args.name)
    p = subparsers.add_parser('bdev_ocf_flush_start',
                              help='Start flushing OCF cache device')
    p.add_argument('name', help='Name of OCF bdev')
    p.set_defaults(func=bdev_ocf_flush_start)

    def bdev_ocf_flush_status(args):
        print_json(rpc.bdev.bdev_ocf_flush_status(args.client, name=args.name))
    p = subparsers.add_parser('bdev_ocf_flush_status',
                              help='Get flush status of OCF cache device')
    p.add_argument('name', help='Name of OCF bdev')
    p.set_defaults(func=bdev_ocf_flush_status)

    def bdev_malloc_create(args):
        num_blocks = (args.total_size * 1024 * 1024) // args.block_size
        print_json(rpc.bdev.bdev_malloc_create(args.client,
Loading