diff --git a/include/spdk/lvol.h b/include/spdk/lvol.h index 85cd4d228..36de87010 100644 --- a/include/spdk/lvol.h +++ b/include/spdk/lvol.h @@ -143,12 +143,13 @@ int spdk_lvs_destroy(struct spdk_lvol_store *lvol_store, * \param lvs Handle to lvolstore * \param name Name of lvol * \param sz size of lvol in bytes + * \param thin_provisioned Enables thin provisioning * \param cb_fn Completion callback * \param cb_arg Completion callback custom arguments * \return error */ int spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz, - spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); + bool thin_provisioned, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); /** * \brief Closes lvol and removes information about lvol from its lvolstore. diff --git a/lib/bdev/lvol/vbdev_lvol.c b/lib/bdev/lvol/vbdev_lvol.c index 6b91d6932..02e46174c 100644 --- a/lib/bdev/lvol/vbdev_lvol.c +++ b/lib/bdev/lvol/vbdev_lvol.c @@ -725,7 +725,7 @@ end: int vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz, - spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) + bool thin_provision, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) { struct spdk_lvol_with_handle_req *req; int rc; @@ -737,7 +737,7 @@ vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz, req->cb_fn = cb_fn; req->cb_arg = cb_arg; - rc = spdk_lvol_create(lvs, name, sz, _vbdev_lvol_create_cb, req); + rc = spdk_lvol_create(lvs, name, sz, thin_provision, _vbdev_lvol_create_cb, req); if (rc != 0) { free(req); } diff --git a/lib/bdev/lvol/vbdev_lvol.h b/lib/bdev/lvol/vbdev_lvol.h index 2cf6aa798..c5bc04f3c 100644 --- a/lib/bdev/lvol/vbdev_lvol.h +++ b/lib/bdev/lvol/vbdev_lvol.h @@ -53,8 +53,7 @@ void vbdev_lvs_destruct(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void vbdev_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg); int vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz, - spdk_lvol_op_with_handle_complete cb_fn, - void *cb_arg); + bool thin_provisioned, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); int vbdev_lvol_resize(char *name, size_t sz, spdk_lvol_op_complete cb_fn, void *cb_arg); diff --git a/lib/bdev/lvol/vbdev_lvol_rpc.c b/lib/bdev/lvol/vbdev_lvol_rpc.c index 359cef6fe..7da858d32 100644 --- a/lib/bdev/lvol/vbdev_lvol_rpc.c +++ b/lib/bdev/lvol/vbdev_lvol_rpc.c @@ -248,6 +248,7 @@ struct rpc_construct_lvol_bdev { char *lvs_name; char *lvol_name; uint64_t size; + bool thin_provision; }; static void @@ -263,6 +264,7 @@ static const struct spdk_json_object_decoder rpc_construct_lvol_bdev_decoders[] {"lvs_name", offsetof(struct rpc_construct_lvol_bdev, lvs_name), spdk_json_decode_string, true}, {"lvol_name", offsetof(struct rpc_construct_lvol_bdev, lvol_name), spdk_json_decode_string, true}, {"size", offsetof(struct rpc_construct_lvol_bdev, size), spdk_json_decode_uint64}, + {"thin_provision", offsetof(struct rpc_construct_lvol_bdev, thin_provision), spdk_json_decode_bool, true}, }; static void @@ -323,7 +325,8 @@ spdk_rpc_construct_lvol_bdev(struct spdk_jsonrpc_request *request, sz = (size_t)req.size; - rc = vbdev_lvol_create(lvs, req.lvol_name, sz, _spdk_rpc_construct_lvol_bdev_cb, request); + rc = vbdev_lvol_create(lvs, req.lvol_name, sz, req.thin_provision, + _spdk_rpc_construct_lvol_bdev_cb, request); if (rc < 0) { goto invalid; } diff --git a/lib/lvol/lvol.c b/lib/lvol/lvol.c index eb62dd349..43e2c3bc6 100644 --- a/lib/lvol/lvol.c +++ b/lib/lvol/lvol.c @@ -936,11 +936,12 @@ _spdk_lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno) int spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz, - spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) + bool thin_provision, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) { struct spdk_lvol_with_handle_req *req; struct spdk_blob_store *bs; struct spdk_lvol *lvol, *tmp; + struct spdk_blob_opts opts; uint64_t num_clusters, free_clusters; if (lvs == NULL) { @@ -996,7 +997,10 @@ spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz, strncpy(lvol->name, name, SPDK_LVS_NAME_MAX); req->lvol = lvol; - spdk_bs_create_blob(lvs->blobstore, _spdk_lvol_create_cb, req); + spdk_blob_opts_init(&opts); + opts.thin_provision = thin_provision; + + spdk_bs_create_blob_ext(lvs->blobstore, &opts, _spdk_lvol_create_cb, req); return 0; } diff --git a/scripts/rpc.py b/scripts/rpc.py index c636c5c55..d715e66e8 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -258,6 +258,7 @@ if __name__ == "__main__": p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend') p.add_argument('-u', '--uuid', help='lvol store UUID', required=False) p.add_argument('-l', '--lvs_name', help='lvol store name', required=False) + p.add_argument('-t', '--thin-provision', action='store_true', help='create lvol bdev as thin provisioned') p.add_argument('lvol_name', help='name for this lvol') p.add_argument('size', help='size in MiB for this bdev', type=int) p.set_defaults(func=rpc.lvol.construct_lvol_bdev) diff --git a/scripts/rpc/lvol.py b/scripts/rpc/lvol.py index c655b4b90..ae3ccd1ed 100755 --- a/scripts/rpc/lvol.py +++ b/scripts/rpc/lvol.py @@ -11,6 +11,8 @@ def construct_lvol_store(args): def construct_lvol_bdev(args): num_bytes = (args.size * 1024 * 1024) params = {'lvol_name': args.lvol_name, 'size': num_bytes} + if args.thin_provision: + params['thin_provision'] = args.thin_provision if (args.uuid and args.lvs_name) or (not args.uuid and not args.lvs_name): print("You need to specify either uuid or name of lvolstore") else: diff --git a/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c b/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c index 1d657f080..31c1ba646 100644 --- a/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c +++ b/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c @@ -460,7 +460,7 @@ _lvol_create(struct spdk_lvol_store *lvs) int spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz, - spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) + bool thin_provision, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) { struct spdk_lvol *lvol; @@ -519,7 +519,7 @@ ut_lvs_destroy(void) /* Suuccessfully create lvol, which should be unloaded with lvs later */ g_lvolerrno = -1; - rc = vbdev_lvol_create(lvs, "lvol", sz, vbdev_lvol_create_complete, NULL); + rc = vbdev_lvol_create(lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvolerrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -553,7 +553,7 @@ ut_lvol_init(void) /* Successful lvol create */ g_lvolerrno = -1; - rc = vbdev_lvol_create(g_lvs, "lvol", sz, vbdev_lvol_create_complete, NULL); + rc = vbdev_lvol_create(g_lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL); SPDK_CU_ASSERT_FATAL(rc == 0); CU_ASSERT(g_lvol != NULL); CU_ASSERT(g_lvolerrno == 0); @@ -703,7 +703,7 @@ ut_lvol_resize(void) /* Successful lvol create */ g_lvolerrno = -1; - rc = vbdev_lvol_create(g_lvs, "lvol", sz, vbdev_lvol_create_complete, NULL); + rc = vbdev_lvol_create(g_lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvolerrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -761,7 +761,7 @@ ut_lvs_unload(void) /* Suuccessfully create lvol, which should be destroyed with lvs later */ g_lvolerrno = -1; - rc = vbdev_lvol_create(lvs, "lvol", sz, vbdev_lvol_create_complete, NULL); + rc = vbdev_lvol_create(lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvolerrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); diff --git a/test/unit/lib/lvol/lvol.c/lvol_ut.c b/test/unit/lib/lvol/lvol.c/lvol_ut.c index 15b47dae9..8deaea021 100644 --- a/test/unit/lib/lvol/lvol.c/lvol_ut.c +++ b/test/unit/lib/lvol/lvol.c/lvol_ut.c @@ -52,6 +52,8 @@ #define SPDK_BLOB_OPTS_MAX_MD_OPS 32 #define SPDK_BLOB_OPTS_MAX_CHANNEL_OPS 512 +#define SPDK_BLOB_THIN_PROV (1ULL << 0) + const char *uuid = "828d9766-ae50-11e7-bd8d-001e67edf350"; struct spdk_blob { @@ -63,6 +65,7 @@ struct spdk_blob { TAILQ_ENTRY(spdk_blob) link; char uuid[UUID_STRING_LEN]; char name[SPDK_LVS_NAME_MAX]; + bool thin_provisioned; }; int g_lvolerrno; @@ -352,9 +355,27 @@ spdk_bs_free_cluster_count(struct spdk_blob_store *bs) return BS_FREE_CLUSTERS; } +void +spdk_blob_opts_init(struct spdk_blob_opts *opts) +{ + opts->num_clusters = 0; + opts->thin_provision = false; + opts->xattr_count = 0; + opts->xattr_names = NULL; + opts->xattr_ctx = NULL; + opts->get_xattr_value = NULL; +} + void spdk_bs_create_blob(struct spdk_blob_store *bs, spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + spdk_bs_create_blob_ext(bs, NULL, cb_fn, cb_arg); +} + +void +spdk_bs_create_blob_ext(struct spdk_blob_store *bs, const struct spdk_blob_opts *opts, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) { struct spdk_blob *b; @@ -362,6 +383,9 @@ spdk_bs_create_blob(struct spdk_blob_store *bs, SPDK_CU_ASSERT_FATAL(b != NULL); b->id = g_blobid++; + if (opts != NULL && opts->thin_provision) { + b->thin_provisioned = true; + } TAILQ_INSERT_TAIL(&bs->blobs, b, link); cb_fn(cb_arg, b->id, 0); @@ -433,7 +457,7 @@ lvs_init_unload_success(void) SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); CU_ASSERT(!TAILQ_EMPTY(&g_lvol_stores)); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -481,7 +505,7 @@ lvs_init_destroy_success(void) CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -683,7 +707,7 @@ lvol_create_destroy_success(void) CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -728,11 +752,11 @@ lvol_create_fail(void) SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); g_lvol = NULL; - rc = spdk_lvol_create(NULL, "lvol", 10, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(NULL, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc != 0); CU_ASSERT(g_lvol == NULL); - rc = spdk_lvol_create(g_lvol_store, "lvol", DEV_BUFFER_SIZE + 1, + rc = spdk_lvol_create(g_lvol_store, "lvol", DEV_BUFFER_SIZE + 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc != 0); CU_ASSERT(g_lvol == NULL); @@ -767,7 +791,7 @@ lvol_destroy_fail(void) CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -806,7 +830,7 @@ lvol_close_fail(void) CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -844,7 +868,7 @@ lvol_close_success(void) CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -883,7 +907,7 @@ lvol_resize(void) CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -1271,28 +1295,28 @@ lvol_names(void) SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); lvs = g_lvol_store; - rc = spdk_lvol_create(lvs, NULL, 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, NULL, 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == -EINVAL); - rc = spdk_lvol_create(lvs, "", 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, "", 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == -EINVAL); memset(fullname, 'x', sizeof(fullname)); - rc = spdk_lvol_create(lvs, fullname, 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, fullname, 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == -EINVAL); g_lvserrno = -1; - rc = spdk_lvol_create(lvs, "lvol", 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); lvol = g_lvol; - rc = spdk_lvol_create(lvs, "lvol", 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == -EINVAL); g_lvserrno = -1; - rc = spdk_lvol_create(lvs, "lvol2", 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, "lvol2", 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -1303,7 +1327,7 @@ lvol_names(void) g_lvserrno = -1; g_lvol = NULL; - rc = spdk_lvol_create(lvs, "lvol", 1, lvol_op_with_handle_complete, NULL); + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -1342,7 +1366,7 @@ static void lvol_refcnt(void) SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); - spdk_lvol_create(g_lvol_store, "lvol", 10, lvol_op_with_handle_complete, NULL); + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); CU_ASSERT(g_lvserrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); @@ -1383,6 +1407,58 @@ static void lvol_refcnt(void) spdk_free_thread(); } +static void +lvol_create_thin_provisioned(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + strncpy(opts.name, "lvs", sizeof(opts.name)); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + CU_ASSERT(g_lvol->blob->thin_provisioned == false); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + CU_ASSERT(g_lvol->blob->thin_provisioned == true); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} int main(int argc, char **argv) { @@ -1418,7 +1494,8 @@ int main(int argc, char **argv) CU_add_test(suite, "lvs_load", lvols_load) == NULL || CU_add_test(suite, "lvol_open", lvol_open) == NULL || CU_add_test(suite, "lvol_refcnt", lvol_refcnt) == NULL || - CU_add_test(suite, "lvol_names", lvol_names) == NULL + CU_add_test(suite, "lvol_names", lvol_names) == NULL || + CU_add_test(suite, "lvol_create_thin_provisioned", lvol_create_thin_provisioned) == NULL ) { CU_cleanup_registry(); return CU_get_error();