diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index f504ffc6d..79a6a22d4 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -2572,6 +2572,48 @@ Example response: } ~~~ +### bdev_ocf_set_seqcutoff {#rpc_bdev_ocf_set_seqcutoff} + +Set sequential cutoff parameters on all cores for the given OCF cache device. +A brief description of this functionality can be found in [OpenCAS documentation](https://open-cas.github.io/guide_tool_details.html#seq-cutoff). + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Required | string | Bdev name +policy | Required | string | Sequential cutoff policy: always, full, never +threshold | Optional | int | Activation threshold in KiB +promotion_count | Optional | int | Promotion request count + +#### Example + +Example request: + +~~~json +{ + "params": { + "name": "ocf0", + "policy": "full", + "threshold": 4, + "promotion_count": 2 + }, + "jsonrpc": "2.0", + "method": "bdev_ocf_set_seqcutoff", + "id": 1 +} +~~~ + +Example response: + +~~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + ### bdev_malloc_create {#rpc_bdev_malloc_create} Construct @ref bdev_config_malloc diff --git a/module/bdev/ocf/utils.c b/module/bdev/ocf/utils.c index dacab10b7..751f13d8c 100644 --- a/module/bdev/ocf/utils.c +++ b/module/bdev/ocf/utils.c @@ -32,6 +32,7 @@ */ #include "spdk/stdinc.h" +#include "spdk/log.h" #include "utils.h" #include "vbdev_ocf.h" @@ -45,6 +46,12 @@ static char *cache_modes[ocf_cache_mode_max] = { [ocf_cache_mode_wo] = "wo", }; +static char *seqcutoff_policies[ocf_seq_cutoff_policy_max] = { + [ocf_seq_cutoff_policy_always] = "always", + [ocf_seq_cutoff_policy_full] = "full", + [ocf_seq_cutoff_policy_never] = "never", +}; + ocf_cache_mode_t ocf_get_cache_mode(const char *cache_mode) { @@ -75,6 +82,19 @@ ocf_get_cache_line_size(ocf_cache_t cache) return ocf_cache_get_line_size(cache) / KiB; } +ocf_seq_cutoff_policy +ocf_get_seqcutoff_policy(const char *policy_name) +{ + int policy; + + for (policy = 0; policy < ocf_seq_cutoff_policy_max; policy++) + if (!strcmp(policy_name, seqcutoff_policies[policy])) { + return policy; + } + + return ocf_seq_cutoff_policy_max; +} + int vbdev_ocf_mngt_start(struct vbdev_ocf *vbdev, vbdev_ocf_mngt_fn *path, vbdev_ocf_mngt_callback cb, void *cb_arg) diff --git a/module/bdev/ocf/utils.h b/module/bdev/ocf/utils.h index eb9f26d31..37255bcdf 100644 --- a/module/bdev/ocf/utils.h +++ b/module/bdev/ocf/utils.h @@ -43,6 +43,9 @@ const char *ocf_get_cache_modename(ocf_cache_mode_t mode); /* Get cache line size in KiB units */ int ocf_get_cache_line_size(ocf_cache_t cache); +/* Get sequential cutoff policy by name */ +ocf_seq_cutoff_policy ocf_get_seqcutoff_policy(const char *policy_name); + /* Initiate management operation * Receives NULL terminated array of functions (path) * and callback (cb) diff --git a/module/bdev/ocf/vbdev_ocf.c b/module/bdev/ocf/vbdev_ocf.c index 4c8ca71f4..9afa3c4b1 100644 --- a/module/bdev/ocf/vbdev_ocf.c +++ b/module/bdev/ocf/vbdev_ocf.c @@ -1518,6 +1518,52 @@ vbdev_ocf_set_cache_mode(struct vbdev_ocf *vbdev, cb(rc, vbdev, cb_arg); } +/* Set sequential cutoff parameters on OCF cache */ +void +vbdev_ocf_set_seqcutoff(struct vbdev_ocf *vbdev, const char *policy_name, uint32_t threshold, + uint32_t promotion_count, void (*cb)(int, void *), void *cb_arg) +{ + ocf_cache_t cache; + ocf_seq_cutoff_policy policy; + int rc; + + cache = vbdev->ocf_cache; + + policy = ocf_get_seqcutoff_policy(policy_name); + if (policy == ocf_seq_cutoff_policy_max) { + cb(OCF_ERR_INVAL, cb_arg); + return; + } + + rc = ocf_mngt_cache_trylock(cache); + if (rc) { + cb(rc, cb_arg); + return; + } + + rc = ocf_mngt_core_set_seq_cutoff_policy_all(cache, policy); + if (rc) { + goto end; + } + + if (threshold) { + threshold = threshold * KiB; + + rc = ocf_mngt_core_set_seq_cutoff_threshold_all(cache, threshold); + if (rc) { + goto end; + } + } + + if (promotion_count) { + rc = ocf_mngt_core_set_seq_cutoff_promotion_count_all(cache, promotion_count); + } + +end: + ocf_mngt_cache_unlock(cache); + cb(rc, cb_arg); +} + /* This called if new device is created in SPDK application * If that device named as one of base bdevs of OCF vbdev, * claim and open them */ diff --git a/module/bdev/ocf/vbdev_ocf.h b/module/bdev/ocf/vbdev_ocf.h index 5502dbfdb..447f6911c 100644 --- a/module/bdev/ocf/vbdev_ocf.h +++ b/module/bdev/ocf/vbdev_ocf.h @@ -210,6 +210,15 @@ void vbdev_ocf_set_cache_mode( void (*cb)(int, struct vbdev_ocf *, void *), void *cb_arg); +/* Set sequential cutoff parameters on OCF cache */ +void vbdev_ocf_set_seqcutoff( + struct vbdev_ocf *vbdev, + const char *policy_name, + uint32_t threshold, + uint32_t promotion_count, + void (*cb)(int, void *), + void *cb_arg); + typedef void (*vbdev_ocf_foreach_fn)(struct vbdev_ocf *, void *); /* Execute fn for each OCF device that is online or waits for base devices */ diff --git a/module/bdev/ocf/vbdev_ocf_rpc.c b/module/bdev/ocf/vbdev_ocf_rpc.c index 315f13138..01791f789 100644 --- a/module/bdev/ocf/vbdev_ocf_rpc.c +++ b/module/bdev/ocf/vbdev_ocf_rpc.c @@ -428,3 +428,70 @@ end: free_rpc_bdev_ocf_set_cache_mode(&req); } SPDK_RPC_REGISTER("bdev_ocf_set_cache_mode", rpc_bdev_ocf_set_cache_mode, SPDK_RPC_RUNTIME) + +static void +seqcutoff_cb(int status, void *cb_arg) +{ + struct spdk_jsonrpc_request *request = cb_arg; + + if (status) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "OCF could not set sequential cutoff parameters: %d", status); + } else { + spdk_jsonrpc_send_bool_response(request, true); + } +} + +/* Structure to hold the parameters for this RPC method. */ +struct rpc_bdev_ocf_set_seqcutoff { + char *name; /* main vbdev name */ + char *policy; + uint32_t threshold; + uint32_t promotion_count; +}; + +static void +free_rpc_bdev_ocf_set_seqcutoff(struct rpc_bdev_ocf_set_seqcutoff *r) +{ + free(r->name); + free(r->policy); +} + +/* Structure to decode the input parameters for this RPC method. */ +static const struct spdk_json_object_decoder rpc_bdev_ocf_set_seqcutoff_decoders[] = { + {"name", offsetof(struct rpc_bdev_ocf_set_seqcutoff, name), spdk_json_decode_string}, + {"policy", offsetof(struct rpc_bdev_ocf_set_seqcutoff, policy), spdk_json_decode_string}, + {"threshold", offsetof(struct rpc_bdev_ocf_set_seqcutoff, threshold), spdk_json_decode_uint32, true}, + {"promotion_count", offsetof(struct rpc_bdev_ocf_set_seqcutoff, promotion_count), spdk_json_decode_uint32, true}, +}; + +static void +rpc_bdev_ocf_set_seqcutoff(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_bdev_ocf_set_seqcutoff req = {NULL}; + struct vbdev_ocf *vbdev; + int ret; + + ret = spdk_json_decode_object(params, rpc_bdev_ocf_set_seqcutoff_decoders, + SPDK_COUNTOF(rpc_bdev_ocf_set_seqcutoff_decoders), &req); + if (ret) { + 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; + } + + vbdev_ocf_set_seqcutoff(vbdev, req.policy, req.threshold, req.promotion_count, seqcutoff_cb, + request); + +end: + free_rpc_bdev_ocf_set_seqcutoff(&req); +} +SPDK_RPC_REGISTER("bdev_ocf_set_seqcutoff", rpc_bdev_ocf_set_seqcutoff, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index c3b579bfd..9d09c5f18 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -341,6 +341,23 @@ if __name__ == "__main__": p.add_argument('mode', help='OCF cache mode', choices=['wb', 'wt', 'pt', 'wa', 'wi', 'wo']) p.set_defaults(func=bdev_ocf_set_cache_mode) + def bdev_ocf_set_seqcutoff(args): + rpc.bdev.bdev_ocf_set_seqcutoff(args.client, + name=args.name, + policy=args.policy, + threshold=args.threshold, + promotion_count=args.promotion_count) + p = subparsers.add_parser('bdev_ocf_set_seqcutoff', + help='Set sequential cutoff parameters on all cores for the given OCF cache device') + p.add_argument('name', help='Name of OCF cache bdev') + p.add_argument('-t', '--threshold', type=int, + help='Activation threshold [KiB]') + p.add_argument('-c', '--promotion-count', type=int, + help='Promotion request count') + p.add_argument('-p', '--policy', choices=['always', 'full', 'never'], required=True, + help='Sequential cutoff policy') + p.set_defaults(func=bdev_ocf_set_seqcutoff) + def bdev_malloc_create(args): num_blocks = (args.total_size * 1024 * 1024) // args.block_size print_json(rpc.bdev.bdev_malloc_create(args.client, diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index 88c6a9f98..7f600cc96 100644 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -222,6 +222,27 @@ def bdev_ocf_set_cache_mode(client, name, mode): return client.call('bdev_ocf_set_cache_mode', params) +def bdev_ocf_set_seqcutoff(client, name, policy, threshold, promotion_count): + """Set sequential cutoff parameters on all cores for the given OCF cache device + + Args: + name: Name of OCF cache bdev + policy: Sequential cutoff policy + threshold: Activation threshold [KiB] (optional) + promotion_count: Promotion request count (optional) + """ + params = { + 'name': name, + 'policy': policy, + } + if threshold: + params['threshold'] = threshold + if promotion_count: + params['promotion_count'] = promotion_count + + return client.call('bdev_ocf_set_seqcutoff', params) + + @deprecated_alias('construct_malloc_bdev') def bdev_malloc_create(client, num_blocks, block_size, name=None, uuid=None, optimal_io_boundary=None): """Construct a malloc block device. diff --git a/test/ocf/management/configuration-change.sh b/test/ocf/management/configuration-change.sh index faccebc9d..b8ac8b5bf 100755 --- a/test/ocf/management/configuration-change.sh +++ b/test/ocf/management/configuration-change.sh @@ -52,5 +52,9 @@ for cache_mode in "${cache_modes[@]}"; do ".config | .[] | select(.method == \"bdev_ocf_create\") | .params.mode == \"$cache_mode\"" done +# Change sequential cutoff +$rpc_py bdev_ocf_set_seqcutoff Cache0 -p always -t 64 +$rpc_py bdev_ocf_set_seqcutoff Cache0 -p never -t 16 + trap - SIGINT SIGTERM EXIT killprocess $spdk_pid