xref: /spdk/test/unit/lib/blob/blob.c/esnap_dev.c (revision 80b22cf31405a515dce9d470ff11989ff1fdb56e)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  */
4 #include "spdk/stdinc.h"
5 
6 #include "spdk_cunit.h"
7 #include "spdk/blob.h"
8 
9 /*
10  * This creates a bs_dev that does not depend on a bdev. Typical use without assertions looks like:
11  *
12  *	struct spdk_bs_dev	*dev;
13  *	struct spdk_bs_opts	bs_opts;
14  *	struct spdk_blob_opts	blob_opts;
15  *	struct ut_snap_opts	esnap_opts;
16  *
17  *   Create the blobstore with external snapshot support.
18  *	dev = init_dev();
19  *	memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
20  *	spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
21  *	bs_opts.esnap_bs_dev_create = ut_esnap_create;
22  *
23  *   Create an esnap clone blob.
24  *	ut_spdk_blob_opts_init(&blob_opts);
25  *	ut_esnap_opts_init(512, 2048, "name", &esnap_opts);
26  *	blob_opts.esnap_id = &esnap_opts;
27  *	blob_opts.esnap_id_len = sizeof(esnap_opts);
28  *	opts.num_clusters = 4;
29  *	blob = ut_blob_create_and_open(bs, &opts);
30  *
31  * At this point the blob can be used like any other blob.
32  */
33 
34 #define UT_ESNAP_OPTS_MAGIC	0xbadf1ea5
35 struct ut_esnap_opts {
36 	/*
37 	 * This structure gets stored in an xattr. The magic number is used to give some assurance
38 	 * that we got the right thing before trying to use the other fields.
39 	 */
40 	uint32_t	magic;
41 	uint32_t	block_size;
42 	uint64_t	num_blocks;
43 	char		name[32];
44 };
45 
46 struct ut_esnap_dev {
47 	struct spdk_bs_dev	bs_dev;
48 	struct ut_esnap_opts	ut_opts;
49 	spdk_blob_id		blob_id;
50 	uint32_t		num_channels;
51 };
52 
53 static void
54 ut_esnap_opts_init(uint32_t block_size, uint32_t num_blocks, const char *name,
55 		   struct ut_esnap_opts *opts)
56 {
57 	memset(opts, 0, sizeof(*opts));
58 	opts->magic = UT_ESNAP_OPTS_MAGIC;
59 	opts->block_size = block_size;
60 	opts->num_blocks = num_blocks;
61 	spdk_strcpy_pad(opts->name, name, sizeof(opts->name) - 1, '\0');
62 }
63 
64 static void
65 ut_esnap_destroy(struct spdk_bs_dev *bs_dev)
66 {
67 	free(bs_dev);
68 }
69 
70 static struct spdk_bs_dev *
71 ut_esnap_dev_alloc(const struct ut_esnap_opts *opts)
72 {
73 	struct ut_esnap_dev	*ut_dev;
74 	struct spdk_bs_dev	*bs_dev;
75 
76 	assert(opts->magic == UT_ESNAP_OPTS_MAGIC);
77 
78 	ut_dev = calloc(1, sizeof(*ut_dev));
79 	if (ut_dev == NULL) {
80 		return NULL;
81 	}
82 
83 	ut_dev->ut_opts = *opts;
84 	bs_dev = &ut_dev->bs_dev;
85 
86 	bs_dev->blocklen = opts->block_size;
87 	bs_dev->blockcnt = opts->num_blocks;
88 
89 	bs_dev->destroy = ut_esnap_destroy;
90 
91 	return bs_dev;
92 }
93 
94 static int
95 ut_esnap_create(void *bs_ctx, struct spdk_blob *blob, const void *id, uint32_t id_len,
96 		struct spdk_bs_dev **bs_devp)
97 {
98 	struct spdk_bs_dev	*bs_dev = NULL;
99 
100 	/* With any blobstore that will use bs_ctx, wrap this function and pass NULL as bs_ctx. */
101 	CU_ASSERT(bs_ctx == NULL);
102 
103 	SPDK_CU_ASSERT_FATAL(id != NULL);
104 	SPDK_CU_ASSERT_FATAL(sizeof(struct ut_esnap_opts) == id_len);
105 
106 	bs_dev = ut_esnap_dev_alloc(id);
107 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
108 
109 	*bs_devp = bs_dev;
110 	return 0;
111 }
112 
113 static int
114 ut_esnap_create_with_count(void *bs_ctx, struct spdk_blob *blob,
115 			   const void *id, uint32_t id_len, struct spdk_bs_dev **bs_devp)
116 {
117 	uint32_t *bs_ctx_count = bs_ctx;
118 
119 	SPDK_CU_ASSERT_FATAL(bs_ctx != NULL);
120 
121 	(*bs_ctx_count)++;
122 	return ut_esnap_create(NULL, blob, id, id_len, bs_devp);
123 }
124