xref: /illumos-gate/usr/src/test/os-tests/tests/idmap/idmaptest.c (revision 24987e92ed84693f7d1351de150743664658894f)
1*24987e92SBill Sommerfeld /*
2*24987e92SBill Sommerfeld  * This file and its contents are supplied under the terms of the
3*24987e92SBill Sommerfeld  * Common Development and Distribution License ("CDDL"), version 1.0.
4*24987e92SBill Sommerfeld  * You may only use this file in accordance with the terms of version
5*24987e92SBill Sommerfeld  * 1.0 of the CDDL.
6*24987e92SBill Sommerfeld  *
7*24987e92SBill Sommerfeld  * A full copy of the text of the CDDL should have accompanied this
8*24987e92SBill Sommerfeld  * source.  A copy of the CDDL is also available via the Internet at
9*24987e92SBill Sommerfeld  * http://www.illumos.org/license/CDDL.
10*24987e92SBill Sommerfeld  */
11*24987e92SBill Sommerfeld 
12*24987e92SBill Sommerfeld /*
13*24987e92SBill Sommerfeld  * Copyright 2025 Bill Sommerfeld
14*24987e92SBill Sommerfeld  */
15*24987e92SBill Sommerfeld 
16*24987e92SBill Sommerfeld /*
17*24987e92SBill Sommerfeld  * Demonstration of idmap collisions due to missing locking and a
18*24987e92SBill Sommerfeld  * fencepost error in get_next_eph_uid.  On a 24-core Zen 4 system
19*24987e92SBill Sommerfeld  * (EPYC 8224P) with a batchsize of 1000 and 20 threads, I see a
20*24987e92SBill Sommerfeld  * couple dups per run.  Dups ending in 001 are from the fencepost error.
21*24987e92SBill Sommerfeld  *
22*24987e92SBill Sommerfeld  * Build with: gcc -O2 -o idmaptest idmaptest.c -lidmap
23*24987e92SBill Sommerfeld  */
24*24987e92SBill Sommerfeld #include <err.h>
25*24987e92SBill Sommerfeld #include <idmap.h>
26*24987e92SBill Sommerfeld #include <pthread.h>
27*24987e92SBill Sommerfeld #include <stdio.h>
28*24987e92SBill Sommerfeld #include <stdbool.h>
29*24987e92SBill Sommerfeld #include <time.h>
30*24987e92SBill Sommerfeld 
31*24987e92SBill Sommerfeld struct batch {
32*24987e92SBill Sommerfeld 	idmap_rid_t base;
33*24987e92SBill Sommerfeld 	int count;
34*24987e92SBill Sommerfeld 	uid_t *idbuf;
35*24987e92SBill Sommerfeld 	idmap_stat *statbuf;
36*24987e92SBill Sommerfeld 	idmap_stat *statbuf2;
37*24987e92SBill Sommerfeld };
38*24987e92SBill Sommerfeld 
39*24987e92SBill Sommerfeld static volatile int go;
40*24987e92SBill Sommerfeld static char sid[32];
41*24987e92SBill Sommerfeld 
42*24987e92SBill Sommerfeld static pthread_mutex_t m;
43*24987e92SBill Sommerfeld static int ready_count;
44*24987e92SBill Sommerfeld static bool test_gid;
45*24987e92SBill Sommerfeld 
46*24987e92SBill Sommerfeld void *
get_idmap_batch(void * arg)47*24987e92SBill Sommerfeld get_idmap_batch(void *arg)
48*24987e92SBill Sommerfeld {
49*24987e92SBill Sommerfeld 	idmap_rid_t rid;
50*24987e92SBill Sommerfeld 	int i;
51*24987e92SBill Sommerfeld 	struct batch *b = arg;
52*24987e92SBill Sommerfeld 
53*24987e92SBill Sommerfeld 	(void) pthread_mutex_lock(&m);
54*24987e92SBill Sommerfeld 	ready_count += 1;
55*24987e92SBill Sommerfeld 	(void) pthread_mutex_unlock(&m);
56*24987e92SBill Sommerfeld 
57*24987e92SBill Sommerfeld 	/* spinwait until all threads are created */
58*24987e92SBill Sommerfeld 	while (!go)
59*24987e92SBill Sommerfeld 		;
60*24987e92SBill Sommerfeld 
61*24987e92SBill Sommerfeld 	for (i = 0; i < b->count; i++) {
62*24987e92SBill Sommerfeld 		idmap_get_handle_t *h;
63*24987e92SBill Sommerfeld 		rid = b->base + i;
64*24987e92SBill Sommerfeld 		(void) idmap_get_create(&h);
65*24987e92SBill Sommerfeld 		if (test_gid) {
66*24987e92SBill Sommerfeld 			(void) idmap_get_gidbysid(h, sid, rid,
67*24987e92SBill Sommerfeld 			    IDMAP_REQ_FLG_USE_CACHE,
68*24987e92SBill Sommerfeld 			    &b->idbuf[i], &b->statbuf[i]);
69*24987e92SBill Sommerfeld 		} else {
70*24987e92SBill Sommerfeld 			(void) idmap_get_uidbysid(h, sid, rid,
71*24987e92SBill Sommerfeld 			    IDMAP_REQ_FLG_USE_CACHE,
72*24987e92SBill Sommerfeld 			    &b->idbuf[i], &b->statbuf[i]);
73*24987e92SBill Sommerfeld 		}
74*24987e92SBill Sommerfeld 		b->statbuf2[i] = idmap_get_mappings(h);
75*24987e92SBill Sommerfeld 		idmap_get_destroy(h);
76*24987e92SBill Sommerfeld 	}
77*24987e92SBill Sommerfeld 	return (NULL);
78*24987e92SBill Sommerfeld }
79*24987e92SBill Sommerfeld 
80*24987e92SBill Sommerfeld #define	NTHREAD 20
81*24987e92SBill Sommerfeld #define	BATCHSIZE 1000
82*24987e92SBill Sommerfeld #define	RIDBASE 2000
83*24987e92SBill Sommerfeld 
84*24987e92SBill Sommerfeld int
cmpugid(const void * a,const void * b)85*24987e92SBill Sommerfeld cmpugid(const void *a, const void *b)
86*24987e92SBill Sommerfeld {
87*24987e92SBill Sommerfeld 	uid_t x = *(const uid_t *)a;
88*24987e92SBill Sommerfeld 	uid_t y = *(const uid_t *)b;
89*24987e92SBill Sommerfeld 	if (x > y)
90*24987e92SBill Sommerfeld 		return (1);
91*24987e92SBill Sommerfeld 	if (x < y)
92*24987e92SBill Sommerfeld 		return (-1);
93*24987e92SBill Sommerfeld 	return (0);
94*24987e92SBill Sommerfeld }
95*24987e92SBill Sommerfeld 
96*24987e92SBill Sommerfeld static const struct timespec usec100 = { 0, 100000 };
97*24987e92SBill Sommerfeld 
98*24987e92SBill Sommerfeld bool
test_idmap()99*24987e92SBill Sommerfeld test_idmap()
100*24987e92SBill Sommerfeld {
101*24987e92SBill Sommerfeld 	int i, j, err;
102*24987e92SBill Sommerfeld 	time_t now;
103*24987e92SBill Sommerfeld 	bool fail = false;
104*24987e92SBill Sommerfeld 	const char *whatsit = test_gid ? "gid" : "uid";
105*24987e92SBill Sommerfeld 
106*24987e92SBill Sommerfeld 	pthread_t thread[NTHREAD];
107*24987e92SBill Sommerfeld 	struct batch b[NTHREAD];
108*24987e92SBill Sommerfeld 	uid_t idbuf[NTHREAD*BATCHSIZE];
109*24987e92SBill Sommerfeld 
110*24987e92SBill Sommerfeld 	go = 0;
111*24987e92SBill Sommerfeld 	ready_count = 0;
112*24987e92SBill Sommerfeld 
113*24987e92SBill Sommerfeld 	(void) time(&now);
114*24987e92SBill Sommerfeld 	(void) snprintf(sid, sizeof (sid), "S-1-5-21-44444444-%ld", now);
115*24987e92SBill Sommerfeld 
116*24987e92SBill Sommerfeld 	printf("testing for dup %s\n", whatsit);
117*24987e92SBill Sommerfeld 
118*24987e92SBill Sommerfeld 	printf("base sid: %s\n", sid);
119*24987e92SBill Sommerfeld 
120*24987e92SBill Sommerfeld 	for (i = 0; i < NTHREAD; i++) {
121*24987e92SBill Sommerfeld 		b[i].base = RIDBASE +  i * BATCHSIZE;
122*24987e92SBill Sommerfeld 		b[i].count = BATCHSIZE;
123*24987e92SBill Sommerfeld 		b[i].idbuf = &idbuf[i * BATCHSIZE];
124*24987e92SBill Sommerfeld 		b[i].statbuf = calloc(BATCHSIZE, sizeof (idmap_stat));
125*24987e92SBill Sommerfeld 		b[i].statbuf2 = calloc(BATCHSIZE, sizeof (idmap_stat));
126*24987e92SBill Sommerfeld 	}
127*24987e92SBill Sommerfeld 	for (i = 0; i < NTHREAD; i++) {
128*24987e92SBill Sommerfeld 		err = pthread_create(&thread[i], NULL, get_idmap_batch, &b[i]);
129*24987e92SBill Sommerfeld 		if (err) {
130*24987e92SBill Sommerfeld 			errc(EXIT_FAILURE, err,
131*24987e92SBill Sommerfeld 			    "Failed to create thread %d", i);
132*24987e92SBill Sommerfeld 		}
133*24987e92SBill Sommerfeld 	}
134*24987e92SBill Sommerfeld 
135*24987e92SBill Sommerfeld 	for (;;) {
136*24987e92SBill Sommerfeld 		int n;
137*24987e92SBill Sommerfeld 		(void) pthread_mutex_lock(&m);
138*24987e92SBill Sommerfeld 		n = ready_count;
139*24987e92SBill Sommerfeld 		(void) pthread_mutex_unlock(&m);
140*24987e92SBill Sommerfeld 		if (n == NTHREAD) {
141*24987e92SBill Sommerfeld 			go = 1;
142*24987e92SBill Sommerfeld 			break;
143*24987e92SBill Sommerfeld 		}
144*24987e92SBill Sommerfeld 		(void) nanosleep(&usec100, NULL);
145*24987e92SBill Sommerfeld 	}
146*24987e92SBill Sommerfeld 
147*24987e92SBill Sommerfeld 	go = 1;
148*24987e92SBill Sommerfeld 	for (i = 0; i < NTHREAD; i++) {
149*24987e92SBill Sommerfeld 		int err = pthread_join(thread[i], NULL);
150*24987e92SBill Sommerfeld 		if (err != 0) {
151*24987e92SBill Sommerfeld 			printf("thread %d error %d\n", i, err);
152*24987e92SBill Sommerfeld 			fail = true;
153*24987e92SBill Sommerfeld 		}
154*24987e92SBill Sommerfeld 	}
155*24987e92SBill Sommerfeld 	for (i = 0; i < NTHREAD; i++) {
156*24987e92SBill Sommerfeld 		for (j = 0; j < BATCHSIZE; j++) {
157*24987e92SBill Sommerfeld 			if (b[i].statbuf[j]) {
158*24987e92SBill Sommerfeld 				printf("fail 1: %d,%d => %d\n",
159*24987e92SBill Sommerfeld 				    i, j, b[i].statbuf[j]);
160*24987e92SBill Sommerfeld 				fail = true;
161*24987e92SBill Sommerfeld 			}
162*24987e92SBill Sommerfeld 			if (b[i].statbuf2[j]) {
163*24987e92SBill Sommerfeld 				printf("fail 2: %d,%d => %d\n",
164*24987e92SBill Sommerfeld 				    i, j, b[i].statbuf2[j]);
165*24987e92SBill Sommerfeld 				fail = true;
166*24987e92SBill Sommerfeld 			}
167*24987e92SBill Sommerfeld 		}
168*24987e92SBill Sommerfeld 	}
169*24987e92SBill Sommerfeld 	qsort(idbuf, NTHREAD*BATCHSIZE, sizeof (uid_t), cmpugid);
170*24987e92SBill Sommerfeld 	for (i = 1; i < NTHREAD*BATCHSIZE; i++) {
171*24987e92SBill Sommerfeld 		if (idbuf[i] == idbuf[i-1]) {
172*24987e92SBill Sommerfeld 			printf("dup %s %x\n", whatsit, idbuf[i]);
173*24987e92SBill Sommerfeld 			fail = true;
174*24987e92SBill Sommerfeld 		}
175*24987e92SBill Sommerfeld 	}
176*24987e92SBill Sommerfeld 	return (fail);
177*24987e92SBill Sommerfeld }
178*24987e92SBill Sommerfeld 
179*24987e92SBill Sommerfeld bool
idmapd_running()180*24987e92SBill Sommerfeld idmapd_running()
181*24987e92SBill Sommerfeld {
182*24987e92SBill Sommerfeld 	bool running = false;
183*24987e92SBill Sommerfeld 	idmap_get_handle_t *h;
184*24987e92SBill Sommerfeld 	idmap_stat status;
185*24987e92SBill Sommerfeld 	idmap_stat s = idmap_get_create(&h);
186*24987e92SBill Sommerfeld 	idmap_rid_t rid;
187*24987e92SBill Sommerfeld 	char *domain;
188*24987e92SBill Sommerfeld 
189*24987e92SBill Sommerfeld 	if (s != 0) {
190*24987e92SBill Sommerfeld 		fprintf(stderr, "Can't create idmap handle: %s\n",
191*24987e92SBill Sommerfeld 		    idmap_stat2string(s));
192*24987e92SBill Sommerfeld 		return (false);
193*24987e92SBill Sommerfeld 	}
194*24987e92SBill Sommerfeld 
195*24987e92SBill Sommerfeld 	s = idmap_get_sidbyuid(h, 0,
196*24987e92SBill Sommerfeld 	    IDMAP_REQ_FLG_USE_CACHE, &domain, &rid, &status);
197*24987e92SBill Sommerfeld 	if (s != IDMAP_SUCCESS) {
198*24987e92SBill Sommerfeld 		fprintf(stderr, "Can't create queue map request: %s\n",
199*24987e92SBill Sommerfeld 		    idmap_stat2string(s));
200*24987e92SBill Sommerfeld 	} else if ((s = idmap_get_mappings(h)) != 0) {
201*24987e92SBill Sommerfeld 		fprintf(stderr, "idmap_get_mappings failed: %s\n",
202*24987e92SBill Sommerfeld 		    idmap_stat2string(s));
203*24987e92SBill Sommerfeld 	} else if (status != IDMAP_SUCCESS) {
204*24987e92SBill Sommerfeld 		fprintf(stderr, "mapping of 0 failed: %s\n",
205*24987e92SBill Sommerfeld 		    idmap_stat2string(status));
206*24987e92SBill Sommerfeld 	} else {
207*24987e92SBill Sommerfeld 		running = true;
208*24987e92SBill Sommerfeld 	}
209*24987e92SBill Sommerfeld 	idmap_get_destroy(h);
210*24987e92SBill Sommerfeld 	return (running);
211*24987e92SBill Sommerfeld }
212*24987e92SBill Sommerfeld 
213*24987e92SBill Sommerfeld int
main(int argc,char ** argv)214*24987e92SBill Sommerfeld main(int argc, char **argv)
215*24987e92SBill Sommerfeld {
216*24987e92SBill Sommerfeld 	bool fail = false;
217*24987e92SBill Sommerfeld 
218*24987e92SBill Sommerfeld 	if (!idmapd_running()) {
219*24987e92SBill Sommerfeld 		fprintf(stderr, "Is idmapd running?\n");
220*24987e92SBill Sommerfeld 		exit(4);	/* signal a "SKIP" to the testing framework */
221*24987e92SBill Sommerfeld 	}
222*24987e92SBill Sommerfeld 	fprintf(stderr, "idmapd is running\n");
223*24987e92SBill Sommerfeld 
224*24987e92SBill Sommerfeld 	(void) pthread_mutex_init(&m, NULL);
225*24987e92SBill Sommerfeld 
226*24987e92SBill Sommerfeld 	test_gid = false;
227*24987e92SBill Sommerfeld 	if (test_idmap())
228*24987e92SBill Sommerfeld 		fail = true;
229*24987e92SBill Sommerfeld 
230*24987e92SBill Sommerfeld 	test_gid = true;
231*24987e92SBill Sommerfeld 	if (test_idmap())
232*24987e92SBill Sommerfeld 		fail = true;
233*24987e92SBill Sommerfeld 
234*24987e92SBill Sommerfeld 	if (fail) {
235*24987e92SBill Sommerfeld 		fprintf(stderr, "FAIL: test failed\n");
236*24987e92SBill Sommerfeld 		exit(EXIT_FAILURE);
237*24987e92SBill Sommerfeld 	}
238*24987e92SBill Sommerfeld 	fprintf(stderr, "PASS: duplicate ids not detected\n");
239*24987e92SBill Sommerfeld 	exit(EXIT_SUCCESS);
240*24987e92SBill Sommerfeld }
241