diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 5a77a26c0..d238482f7 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -469,6 +469,7 @@ Example response: "bdev_ftl_unload", "bdev_ftl_create", "bdev_ftl_load", + "bdev_ftl_unmap", "bdev_lvol_get_lvstores", "bdev_lvol_delete", "bdev_lvol_resize", @@ -4912,6 +4913,46 @@ Example response: } ~~~ +### bdev_ftl_unmap {#rpc_bdev_ftl_unmap} + +Unmap range of LBAs. + +This RPC is subject to change. + +#### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Required | string | Bdev name +lba | Required | number | start lba, aligned to 1024 +num_blocks | Required | number | number of blocks, aligned to 1024 + +#### Example + +Example request: + +~~~json +{ + "params": { + "name": "ftl0" + "lba": "0" + "num_blocks": "1024" + }, + "jsonrpc": "2.0", + "method": "bdev_ftl_unmap", + "id": 1 +} +~~~ + +Example response: + +~~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ ### bdev_pmem_create_pool {#rpc_bdev_pmem_create_pool} Create a @ref bdev_config_pmem blk pool file. It is equivalent of following `pmempool create` command: diff --git a/lib/ftl/ftl_core.c b/lib/ftl/ftl_core.c index 508bbe2ac..6bbd1d3e4 100644 --- a/lib/ftl/ftl_core.c +++ b/lib/ftl/ftl_core.c @@ -474,6 +474,12 @@ spdk_ftl_unmap(struct spdk_ftl_dev *dev, struct ftl_io *io, struct spdk_io_chann } if (lba % aligment || lba_cnt % aligment) { + if (!io) { + /* This is management/RPC path, its parameters must be aligned to 1MiB. */ + return -EINVAL; + } + + /* Otherwise unaligned IO requests are NOPs */ rc = ftl_io_init(ch, io, lba, lba_cnt, NULL, 0, cb_fn, cb_arg, FTL_IO_UNMAP); if (rc) { return rc; @@ -484,7 +490,11 @@ spdk_ftl_unmap(struct spdk_ftl_dev *dev, struct ftl_io *io, struct spdk_io_chann return 0; } - rc = ftl_unmap(dev, io, ch, lba, lba_cnt, cb_fn, cb_arg); + if (io) { + rc = ftl_unmap(dev, io, ch, lba, lba_cnt, cb_fn, cb_arg); + } else { + rc = ftl_mngt_unmap(dev, lba, lba_cnt, cb_fn, cb_arg); + } return rc; } diff --git a/lib/ftl/mngt/ftl_mngt.h b/lib/ftl/mngt/ftl_mngt.h index 3484748b8..558a52d36 100644 --- a/lib/ftl/mngt/ftl_mngt.h +++ b/lib/ftl/mngt/ftl_mngt.h @@ -303,6 +303,23 @@ void ftl_mngt_call_process_rollback(struct ftl_mngt_process *mngt, */ int ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx); +/* + * The specific management functions + */ +/** + * @brief Issue unmap on FTL instance + * + * @param dev FTL device + * @param cb Caller callback + * @param cb_cntx Caller context + * + * @return Operation result + * @retval 0 The operation successful has started + * @retval Non-zero Startup failure + */ +int ftl_mngt_unmap(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb, + void *cb_cntx); + /** * @brief Shuts down a FTL instance * diff --git a/lib/ftl/mngt/ftl_mngt_startup.c b/lib/ftl/mngt/ftl_mngt_startup.c index 921ad5ff7..cea8ffcce 100644 --- a/lib/ftl/mngt/ftl_mngt_startup.c +++ b/lib/ftl/mngt/ftl_mngt_startup.c @@ -278,6 +278,87 @@ ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void return ftl_mngt_process_execute(dev, &desc_startup, cb, cb_cntx); } +struct ftl_unmap_ctx { + uint64_t lba; + uint64_t num_blocks; + spdk_ftl_fn cb_fn; + void *cb_arg; +}; + +static void +ftl_mngt_process_unmap_cb(void *ctx, int status) +{ + struct ftl_mngt_process *mngt = ctx; + + if (status) { + ftl_mngt_fail_step(ctx); + } else { + ftl_mngt_next_step(mngt); + } +} + +static void +ftl_mngt_process_unmap(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) +{ + struct ftl_io *io = ftl_mngt_get_process_ctx(mngt); + struct ftl_unmap_ctx *ctx = ftl_mngt_get_caller_ctx(mngt); + int rc; + + if (!dev->ioch) { + ftl_mngt_fail_step(mngt); + return; + } + + rc = spdk_ftl_unmap(dev, io, dev->ioch, ctx->lba, ctx->num_blocks, ftl_mngt_process_unmap_cb, mngt); + if (rc == -EAGAIN) { + ftl_mngt_continue_step(mngt); + } +} + +/* + * RPC unmap path. + */ +static const struct ftl_mngt_process_desc g_desc_unmap = { + .name = "FTL unmap", + .ctx_size = sizeof(struct ftl_io), + .steps = { + { + .name = "Process unmap", + .action = ftl_mngt_process_unmap, + }, + {} + } +}; + +static void +ftl_mngt_unmap_cb(struct spdk_ftl_dev *dev, void *_ctx, int status) +{ + struct ftl_unmap_ctx *ctx = _ctx; + + ctx->cb_fn(ctx->cb_arg, status); + + free(ctx); +} + +int +ftl_mngt_unmap(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb, + void *cb_cntx) +{ + struct ftl_unmap_ctx *ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + return -EAGAIN; + } + + ctx->lba = lba; + ctx->num_blocks = num_blocks; + ctx->cb_fn = cb; + ctx->cb_arg = cb_cntx; + + return ftl_mngt_process_execute(dev, &g_desc_unmap, ftl_mngt_unmap_cb, ctx); +} + void ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) { diff --git a/module/bdev/ftl/bdev_ftl.c b/module/bdev/ftl/bdev_ftl.c index 82411802d..0f62fe2a2 100644 --- a/module/bdev/ftl/bdev_ftl.c +++ b/module/bdev/ftl/bdev_ftl.c @@ -482,6 +482,72 @@ not_found: cb_fn(cb_arg, -ENODEV); } +struct ftl_unmap_ctx { + struct spdk_bdev_desc *bdev; + spdk_ftl_fn cb_fn; + void *cb_arg; +}; + +static void +bdev_ftl_unmap_cb(void *cb_arg, int status) +{ + struct ftl_unmap_ctx *ctx = cb_arg; + + spdk_bdev_close(ctx->bdev); + ctx->cb_fn(ctx->cb_arg, status); + free(ctx); +} + +void +bdev_ftl_unmap(const char *name, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb_fn, void *cb_arg) +{ + struct spdk_bdev_desc *ftl_bdev_desc; + struct spdk_bdev *bdev; + struct ftl_bdev *ftl; + struct ftl_unmap_ctx *ctx; + int rc; + + rc = spdk_bdev_open_ext(name, false, bdev_ftl_event_cb, NULL, &ftl_bdev_desc); + + if (rc) { + goto not_found; + } + + bdev = spdk_bdev_desc_get_bdev(ftl_bdev_desc); + + if (bdev->module != &g_ftl_if) { + rc = -ENODEV; + goto bdev_opened; + } + + ctx = calloc(1, sizeof(struct ftl_unmap_ctx)); + if (!ctx) { + rc = -ENOMEM; + goto bdev_opened; + } + + ctx->bdev = ftl_bdev_desc; + ctx->cb_arg = cb_arg; + ctx->cb_fn = cb_fn; + + ftl = bdev->ctxt; + assert(ftl); + /* It's ok to pass NULL as IO channel - FTL will detect this and use it's internal IO channel for management operations */ + rc = spdk_ftl_unmap(ftl->dev, NULL, NULL, lba, num_blocks, bdev_ftl_unmap_cb, ctx); + + if (rc) { + goto ctx_allocated; + } + + return; +ctx_allocated: + free(ctx); +bdev_opened: + spdk_bdev_close(ftl_bdev_desc); +not_found: + cb_fn(cb_arg, rc); +} + static void bdev_ftl_finish(void) { diff --git a/module/bdev/ftl/bdev_ftl.h b/module/bdev/ftl/bdev_ftl.h index 5f1529525..266bb2ca2 100644 --- a/module/bdev/ftl/bdev_ftl.h +++ b/module/bdev/ftl/bdev_ftl.h @@ -24,5 +24,7 @@ int bdev_ftl_create_bdev(const struct spdk_ftl_conf *conf, ftl_bdev_init_fn cb, void bdev_ftl_delete_bdev(const char *name, bool fast_shutdown, spdk_bdev_unregister_cb cb_fn, void *cb_arg); int bdev_ftl_defer_init(const struct spdk_ftl_conf *conf); +void bdev_ftl_unmap(const char *name, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb_fn, + void *cb_arg); #endif /* SPDK_BDEV_FTL_H */ diff --git a/module/bdev/ftl/bdev_ftl_rpc.c b/module/bdev/ftl/bdev_ftl_rpc.c index 782f9b7fd..3772543b6 100644 --- a/module/bdev/ftl/bdev_ftl_rpc.c +++ b/module/bdev/ftl/bdev_ftl_rpc.c @@ -172,3 +172,41 @@ rpc_bdev_ftl_unload(struct spdk_jsonrpc_request *request, rpc_bdev_ftl_delete(request, params); } SPDK_RPC_REGISTER("bdev_ftl_unload", rpc_bdev_ftl_unload, SPDK_RPC_RUNTIME) + +struct rpc_ftl_unmap { + char *name; + uint64_t lba; + uint64_t num_blocks; +}; + +static const struct spdk_json_object_decoder rpc_ftl_unmap_decoders[] = { + {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, + {"lba", offsetof(struct rpc_ftl_unmap, lba), spdk_json_decode_uint64, true}, + {"num_blocks", offsetof(struct rpc_ftl_unmap, num_blocks), spdk_json_decode_uint64, true}, +}; + +static void +rpc_bdev_ftl_unmap_cb(void *cb_arg, int bdeverrno) +{ + struct spdk_jsonrpc_request *request = cb_arg; + + spdk_jsonrpc_send_bool_response(request, bdeverrno == 0); +} + +static void +rpc_bdev_ftl_unmap(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) +{ + struct rpc_ftl_unmap attrs = {}; + + if (spdk_json_decode_object(params, rpc_ftl_unmap_decoders, SPDK_COUNTOF(rpc_ftl_unmap_decoders), + &attrs)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + goto invalid; + } + + bdev_ftl_unmap(attrs.name, attrs.lba, attrs.num_blocks, rpc_bdev_ftl_unmap_cb, request); +invalid: + free(attrs.name); +} + +SPDK_RPC_REGISTER("bdev_ftl_unmap", rpc_bdev_ftl_unmap, SPDK_RPC_RUNTIME) diff --git a/python/spdk/rpc/bdev.py b/python/spdk/rpc/bdev.py index 422ca94f8..92e2d08b3 100644 --- a/python/spdk/rpc/bdev.py +++ b/python/spdk/rpc/bdev.py @@ -1401,6 +1401,21 @@ def bdev_ftl_delete(client, name, fast_shutdown): return client.call('bdev_ftl_delete', params) +def bdev_ftl_unmap(client, name, lba, num_blocks): + """FTL unmap + + Args: + name: name of the bdev + lba: starting lba to be unmapped + num_blocks: number of blocks to unmap + """ + params = {'name': name, + 'lba': lba, + 'num_blocks': num_blocks} + + return client.call('bdev_ftl_unmap', params) + + def bdev_get_bdevs(client, name=None, timeout=None): """Get information about block devices. diff --git a/scripts/rpc.py b/scripts/rpc.py index 93641fc5d..778c5784f 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2072,6 +2072,17 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('-f', '--fast-shutdown', help="Fast shutdown", action='store_true') p.set_defaults(func=bdev_ftl_delete) + def bdev_ftl_unmap(args): + print_dict(rpc.bdev.bdev_ftl_unmap(args.client, name=args.name, + lba=args.lba, + num_blocks=args.num_blocks)) + + p = subparsers.add_parser('bdev_ftl_unmap', help='FTL unmap') + p.add_argument('-b', '--name', help="Name of the bdev", required=True) + p.add_argument('--lba', help='start LBA', required=True, type=int) + p.add_argument('--num-blocks', help='num blocks', required=True, type=int) + p.set_defaults(func=bdev_ftl_unmap) + # vmd def vmd_enable(args): print_dict(rpc.vmd.vmd_enable(args.client))