xref: /illumos-gate/usr/src/uts/common/io/stream_test.c (revision 5016ae894be01e501342a67035ea848043662a45)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  * Copyright 2024 Ryan Zezeski
15  */
16 #include <sys/modctl.h>
17 #include <sys/strsun.h>
18 #include <sys/ktest.h>
19 
20 static mblk_t *
21 allocb_zeroed(size_t len, uint_t pri)
22 {
23 	mblk_t *mp = allocb(len, pri);
24 
25 	if (mp != NULL) {
26 		bzero(mp->b_wptr, len);
27 		mp->b_wptr += len;
28 	}
29 	return (mp);
30 }
31 
32 static size_t
33 msgsegs(const mblk_t *mp)
34 {
35 	size_t out = 0;
36 
37 	while (mp != NULL) {
38 		out++;
39 		mp = mp->b_cont;
40 	}
41 
42 	return (out);
43 }
44 
45 /*
46  * Initialises a chain of n_mps zeroed mblks, each containing
47  * mplen[i] bytes.
48  */
49 static mblk_t *
50 init_chain(const size_t *mp_len, const size_t n_mps)
51 {
52 	mblk_t *out = NULL;
53 	mblk_t **cont = &out;
54 
55 	for (int i = 0; i < n_mps; ++i) {
56 		mblk_t *new = allocb_zeroed(mp_len[i], BPRI_LO);
57 		if (new == NULL)
58 			goto bail;
59 		*cont = new;
60 		cont = &new->b_cont;
61 	}
62 
63 	return (out);
64 
65 bail:
66 	if (out != NULL)
67 		freemsg(out);
68 	return (NULL);
69 }
70 
71 /*
72  * Test the MBLKL macro.
73  */
74 void
75 mblkl_test(ktest_ctx_hdl_t *ctx)
76 {
77 	mblk_t *mp1 = allocb(64, 0);
78 
79 	KT_EASSERT3P(mp1, !=, NULL, ctx);
80 	KT_ASSERT3UG(MBLKL(mp1), ==, 0, ctx, cleanup);
81 	mp1->b_wptr += 14;
82 	KT_ASSERT3UG(MBLKL(mp1), ==, 14, ctx, cleanup);
83 	KT_PASS(ctx);
84 
85 cleanup:
86 	freeb(mp1);
87 }
88 
89 void
90 msgsize_test(ktest_ctx_hdl_t *ctx)
91 {
92 	mblk_t *mp1 = allocb(14, 0);
93 	mblk_t *mp2 = allocb(20, 0);
94 
95 	KT_EASSERT3P(mp1, !=, NULL, ctx);
96 	KT_EASSERT3PG(mp2, !=, NULL, ctx, cleanup);
97 	KT_ASSERT3UG(msgsize(mp1), ==, 0, ctx, cleanup);
98 	KT_ASSERT3UG(msgsize(mp2), ==, 0, ctx, cleanup);
99 	mp1->b_wptr += 14;
100 	mp2->b_wptr += 20;
101 	KT_ASSERT3UG(msgsize(mp1), ==, 14, ctx, cleanup);
102 	KT_ASSERT3UG(msgsize(mp2), ==, 20, ctx, cleanup);
103 	mp1->b_cont = mp2;
104 	KT_ASSERT3UG(msgsize(mp1), ==, 34, ctx, cleanup);
105 	KT_ASSERT3UG(msgsize(mp2), ==, 20, ctx, cleanup);
106 	KT_PASS(ctx);
107 
108 cleanup:
109 	freeb(mp1);
110 
111 	if (mp2 != NULL) {
112 		freeb(mp2);
113 	}
114 }
115 
116 void
117 msgpullup_test(ktest_ctx_hdl_t *ctx)
118 {
119 	const size_t test_1[] = {8, 8};
120 	const size_t test_2[] = {4, 8};
121 	const size_t test_3[] = {4, 4, 8};
122 	mblk_t *mp = NULL;
123 	mblk_t *pullmp = NULL;
124 
125 	/*
126 	 * Test 1 -> 8 + 8, pullup 4.
127 	 * Should copy first 4 bytes, then link into the existing mp.
128 	 */
129 	mp = init_chain(test_1, 2);
130 	KT_EASSERT3P(mp, !=, NULL, ctx);
131 	KT_ASSERT3UG(msgsegs(mp), ==, 2, ctx, cleanup);
132 	pullmp = msgpullup(mp, 4);
133 	KT_EASSERT3PG(pullmp, !=, NULL, ctx, cleanup);
134 
135 	KT_ASSERT3UG(MBLKL(pullmp), ==, 4, ctx, cleanup);
136 	KT_ASSERT3UG(msgsize(pullmp), ==, 16, ctx, cleanup);
137 	KT_ASSERT3UG(msgsegs(pullmp), ==, 3, ctx, cleanup);
138 	KT_ASSERT3PG(pullmp->b_cont, !=, NULL, ctx, cleanup);
139 	KT_ASSERT3PG(pullmp->b_cont->b_datap, ==, mp->b_datap, ctx, cleanup);
140 
141 	freemsg(mp);
142 	freemsg(pullmp);
143 
144 	/*
145 	 * Test 2 -> 4 + 8, pullup 5.
146 	 * Should be 5(copy) + 7(referencing the original tail).
147 	 */
148 	mp = init_chain(test_2, 2);
149 	KT_EASSERT3P(mp, !=, NULL, ctx);
150 	KT_ASSERT3UG(msgsegs(mp), ==, 2, ctx, cleanup);
151 	pullmp = msgpullup(mp, 5);
152 	KT_EASSERT3PG(pullmp, !=, NULL, ctx, cleanup);
153 
154 	KT_ASSERT3UG(MBLKL(pullmp), ==, 5, ctx, cleanup);
155 	KT_ASSERT3UG(msgsize(pullmp), ==, 12, ctx, cleanup);
156 	KT_ASSERT3UG(msgsegs(pullmp), ==, 2, ctx, cleanup);
157 	KT_ASSERT3PG(pullmp->b_cont, !=, NULL, ctx, cleanup);
158 	KT_ASSERT3PG(pullmp->b_cont->b_datap, ==, mp->b_cont->b_datap, ctx,
159 	    cleanup);
160 
161 	freemsg(mp);
162 	freemsg(pullmp);
163 
164 	/*
165 	 * Test 3 -> 4 + 4 + 8, pullup 12.
166 	 * Should be 12(copy) + 4(original tail).
167 	 */
168 	mp = init_chain(test_3, 3);
169 	KT_EASSERT3P(mp, !=, NULL, ctx);
170 	KT_ASSERT3UG(msgsegs(mp), ==, 3, ctx, cleanup);
171 	pullmp = msgpullup(mp, 12);
172 	KT_EASSERT3PG(pullmp, !=, NULL, ctx, cleanup);
173 
174 	KT_ASSERT3UG(MBLKL(pullmp), ==, 12, ctx, cleanup);
175 	KT_ASSERT3UG(msgsize(pullmp), ==, 16, ctx, cleanup);
176 	KT_ASSERT3UG(msgsegs(pullmp), ==, 2, ctx, cleanup);
177 	KT_ASSERT3PG(pullmp->b_cont, !=, NULL, ctx, cleanup);
178 	KT_ASSERT3PG(pullmp->b_cont->b_datap, ==, mp->b_cont->b_cont->b_datap,
179 	    ctx, cleanup);
180 
181 	KT_PASS(ctx);
182 
183 cleanup:
184 	if (mp != NULL)
185 		freemsg(mp);
186 	if (pullmp != NULL)
187 		freemsg(pullmp);
188 }
189 
190 static struct modlmisc stream_test_modlmisc = {
191 	.misc_modops = &mod_miscops,
192 	.misc_linkinfo = "stream ktest module"
193 };
194 
195 static struct modlinkage stream_test_modlinkage = {
196 	.ml_rev = MODREV_1,
197 	.ml_linkage = { &stream_test_modlmisc, NULL }
198 };
199 
200 int
201 _init()
202 {
203 	int ret;
204 	ktest_module_hdl_t *km = NULL;
205 	ktest_suite_hdl_t *ks = NULL;
206 
207 	VERIFY0(ktest_create_module("stream", &km));
208 	VERIFY0(ktest_add_suite(km, "mblk", &ks));
209 	VERIFY0(ktest_add_test(ks, "mblkl_test", mblkl_test, KTEST_FLAG_NONE));
210 	VERIFY0(ktest_add_test(ks, "msgsize_test", msgsize_test,
211 	    KTEST_FLAG_NONE));
212 	VERIFY0(ktest_add_test(ks, "msgpullup_test", msgpullup_test,
213 	    KTEST_FLAG_NONE));
214 
215 	if ((ret = ktest_register_module(km)) != 0) {
216 		ktest_free_module(km);
217 		return (ret);
218 	}
219 
220 	if ((ret = mod_install(&stream_test_modlinkage)) != 0) {
221 		ktest_unregister_module("stream");
222 		return (ret);
223 	}
224 
225 	return (0);
226 }
227 
228 int
229 _fini()
230 {
231 	ktest_unregister_module("stream");
232 	return (mod_remove(&stream_test_modlinkage));
233 }
234 
235 int
236 _info(struct modinfo *modinfop)
237 {
238 	return (mod_info(&stream_test_modlinkage, modinfop));
239 }
240