Skip to content

Commit 5215639

Browse files
authored
Merge pull request #127 from garlick/lock_tests
testsuite: improve locking tests
2 parents bfc9826 + adc86ad commit 5215639

File tree

18 files changed

+390
-1015
lines changed

18 files changed

+390
-1015
lines changed

src/libdiod/Makefile.am

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ test_ldadd = \
4747

4848
TESTS = \
4949
test_configfile.t \
50-
test_threadwrlock.t \
5150
test_read.t \
5251
test_directory.t \
52+
test_lock.t \
5353
test_multiuser.t
5454

5555
check_PROGRAMS = $(TESTS)
@@ -60,14 +60,14 @@ T_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
6060
test_configfile_t_SOURCES = test/configfile.c
6161
test_configfile_t_LDADD = $(test_ldadd)
6262

63-
test_threadwrlock_t_SOURCES = test/threadwrlock.c
64-
test_threadwrlock_t_LDADD = $(test_ldadd)
65-
6663
test_read_t_SOURCES = test/read.c
6764
test_read_t_LDADD = $(test_ldadd)
6865

6966
test_directory_t_SOURCES = test/directory.c
7067
test_directory_t_LDADD = $(test_ldadd)
7168

69+
test_lock_t_SOURCES = test/lock.c
70+
test_lock_t_LDADD = $(test_ldadd)
71+
7272
test_multiuser_t_SOURCES = test/multiuser.c
7373
test_multiuser_t_LDADD = $(test_ldadd)

src/libdiod/test/lock.c

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
/************************************************************\
2+
* Copyright 2025 Lawrence Livermore National Security, LLC
3+
* (c.f. AUTHORS, NOTICE.LLNS, COPYING)
4+
*
5+
* This file is part of the diod 9P server project.
6+
* For details, see https://github.com/chaos/diod.
7+
*
8+
* SPDX-License-Identifier: GPL-2.0-or-later
9+
\************************************************************/
10+
11+
/* test lock/getlock */
12+
13+
#if HAVE_CONFIG_H
14+
#include "config.h"
15+
#endif
16+
#include <sys/types.h>
17+
#include <sys/stat.h>
18+
#include <fcntl.h>
19+
#include <dirent.h>
20+
#include <stdlib.h>
21+
#include <string.h>
22+
#include <errno.h>
23+
24+
#include "src/libtest/server.h"
25+
#include "src/libnpclient/npclient.h"
26+
#include "src/libtap/tap.h"
27+
28+
#include "src/liblsd/list.h"
29+
#include "diod_conf.h"
30+
31+
#define TEST_MSIZE 8192
32+
#define TEST_FILE_SIZE 16384
33+
34+
static const char *statstr[] = { "Lsuccess", "Lblocked", "Lerror", "Lgrace" };
35+
static const char *typestr[] = { "Lrdlck", "Lwrlck", "Lunlck" };
36+
37+
const char *rerrstr (void)
38+
{
39+
return strerror (np_rerror ());
40+
}
41+
42+
static void make_test_file (Npcfid *root, char *name, size_t size)
43+
{
44+
Npcfid *fid;
45+
char *buf;
46+
int n;
47+
48+
if (!(buf = malloc (size)))
49+
BAIL_OUT ("out of memory");
50+
memset (buf, 'a', size);
51+
buf[size - 1] = '\0';
52+
53+
if (!(fid = npc_create_bypath (root, name, 0, 0644, getgid ())))
54+
BAIL_OUT ("npc_create_bypath %s: %s", name, rerrstr ());
55+
if (npc_clunk (fid) < 0)
56+
BAIL_OUT ("npc_clunk failed: %s", rerrstr ());
57+
if ((n = npc_put (root, name, buf, size)) != size)
58+
BAIL_OUT ("npc_put failed: %s", n < 0 ? rerrstr () : "short write");
59+
free (buf);
60+
}
61+
62+
static void check_lock_range (Npcfid *fid, u8 type, int hi, int lo, u8 xstatus)
63+
{
64+
Npclockinfo info = {
65+
.type = type,
66+
.start = lo,
67+
.length = hi - lo + 1,
68+
.proc_id = fid->fid,
69+
.client_id = "locktest",
70+
};
71+
u8 status;
72+
int rc;
73+
74+
if ((rc = npc_lock (fid, 0, &info, &status)) < 0)
75+
diag ("npc_lock failed: %s", rerrstr ());
76+
if (rc == 0 && status != xstatus)
77+
diag ("npc_lock status is %s", statstr[status % 4]);
78+
ok (rc == 0 && status == xstatus,
79+
"fid %d %s [%d:%d] => %s",
80+
fid->fid, typestr[type % 3], hi, lo, statstr[xstatus % 4]);
81+
}
82+
83+
static void check_lock (Npcfid *fid, u8 type, u8 xstatus)
84+
{
85+
return check_lock_range (fid, type, 0, -1, xstatus);
86+
}
87+
88+
static void check_getlock (Npcfid *fid, u8 type, u8 xtype)
89+
{
90+
Npclockinfo in = {
91+
.type = type,
92+
.start = 0,
93+
.length = 0,
94+
.proc_id = fid->fid,
95+
.client_id = "locktest",
96+
};
97+
Npclockinfo out;
98+
int rc;
99+
100+
memset (&out, 0, sizeof (out));
101+
if ((rc = npc_getlock (fid, &in, &out)) < 0)
102+
diag ("npc_lock failed: %s", rerrstr ());
103+
if (rc == 0 && out.type != xtype)
104+
diag ("npc_lock status is %s", typestr[out.type % 3]);
105+
ok (rc == 0 && out.type == xtype,
106+
"fid %d try %s => %s",
107+
fid->fid, typestr[type % 3], typestr[xtype % 3]);
108+
}
109+
110+
static void test_unlock (Npcfid *root, char *path)
111+
{
112+
Npcfid *fid1, *fid2;
113+
114+
diag ("Lwrlcks contend and Lunlck works");
115+
116+
ok ((fid1 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
117+
ok ((fid2 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
118+
119+
check_lock (fid1, Lwrlck, Lsuccess);
120+
check_lock (fid2, Lwrlck, Lblocked);
121+
check_lock (fid1, Lunlck, Lsuccess);
122+
check_lock (fid2, Lwrlck, Lsuccess);
123+
124+
ok (npc_clunk (fid2) == 0, "clunked fid");
125+
ok (npc_clunk (fid1) == 0, "clunked fid");
126+
}
127+
128+
static void test_clunk (Npcfid *root, char *path)
129+
{
130+
Npcfid *fid1, *fid2;
131+
132+
diag ("Clunk == Lunlck");
133+
134+
ok ((fid1 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
135+
ok ((fid2 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
136+
137+
check_lock (fid1, Lwrlck, Lsuccess);
138+
check_lock (fid2, Lwrlck, Lblocked);
139+
int fidno = fid1->fid;
140+
ok (npc_clunk (fid1) == 0, "clunked fid %d", fidno);
141+
check_lock (fid2, Lwrlck, Lsuccess);
142+
143+
ok (npc_clunk (fid2) == 0, "clunked fid");
144+
}
145+
146+
static void test_readwrite (Npcfid *root, char *path)
147+
{
148+
Npcfid *fid1, *fid2, *fid3;
149+
150+
diag ("reader/writer semantics work");
151+
152+
ok ((fid1 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
153+
ok ((fid2 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
154+
ok ((fid3 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
155+
156+
check_lock (fid1, Lrdlck, Lsuccess);
157+
check_lock (fid2, Lrdlck, Lsuccess);
158+
check_lock (fid3, Lwrlck, Lblocked);
159+
check_lock (fid2, Lunlck, Lsuccess);
160+
check_lock (fid1, Lunlck, Lsuccess);
161+
check_lock (fid3, Lwrlck, Lsuccess);
162+
check_lock (fid1, Lrdlck, Lblocked);
163+
check_lock (fid1, Lwrlck, Lblocked);
164+
165+
ok (npc_clunk (fid3) == 0, "clunked fid");
166+
ok (npc_clunk (fid2) == 0, "clunked fid");
167+
ok (npc_clunk (fid1) == 0, "clunked fid");
168+
}
169+
170+
static void test_ranges (Npcfid *root, char *path)
171+
{
172+
Npcfid *fid1, *fid2;
173+
174+
diag ("posix record locking is not implemented");
175+
176+
ok ((fid1 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
177+
ok ((fid2 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
178+
179+
check_lock_range (fid1, Lwrlck, 0, 31, Lsuccess);
180+
check_lock_range (fid2, Lwrlck, 32, 63, Lblock);
181+
182+
ok (npc_clunk (fid2) == 0, "clunked fid");
183+
ok (npc_clunk (fid1) == 0, "clunked fid");
184+
}
185+
186+
static void test_getlock (Npcfid *root, char *path)
187+
{
188+
Npcfid *fid1, *fid2;
189+
190+
diag ("check getlock");
191+
192+
ok ((fid1 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
193+
ok ((fid2 = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
194+
195+
check_getlock (fid1, Lrdlck, Lunlck);
196+
check_getlock (fid1, Lwrlck, Lunlck);
197+
check_lock (fid2, Lrdlck, Lsuccess);
198+
check_getlock (fid1, Lrdlck, Lunlck);
199+
check_getlock (fid1, Lwrlck, Lwrlck);
200+
201+
ok (npc_clunk (fid2) == 0, "clunked fid");
202+
ok (npc_clunk (fid1) == 0, "clunked fid");
203+
}
204+
205+
static void test_badparam (Npcfid *root, char *path)
206+
{
207+
Npclockinfo info = {
208+
.proc_id = 42,
209+
.client_id = "locktest",
210+
};
211+
Npcfid *fid;
212+
u8 status;
213+
214+
diag ("Confirm that the server handles some error cases");
215+
216+
ok ((fid = npc_open_bypath (root, path, Ordwr)) != NULL, "opened fid");
217+
218+
info.type = Lwrlck;
219+
info.start = info.length = 0;
220+
ok (npc_lock (fid, 42, &info, &status) < 0 && np_rerror () == EINVAL,
221+
"npc_lock with illegal flags value fails with EINVAL");
222+
223+
info.type = 42;
224+
info.start = info.length = 0;
225+
ok (npc_lock (fid, 0, &info, &status) < 0 && np_rerror () == EINVAL,
226+
"npc_lock with illegal type value fails with EINVAL");
227+
228+
ok (npc_clunk (fid) == 0, "clunked fid");
229+
230+
ok ((fid = npc_walk (root, path)) != NULL, "walked to fid");
231+
info.type = Lwrlck;
232+
info.start = info.length = 0;
233+
ok (npc_lock (fid, 0, &info, &status) < 0 && np_rerror () == EBADF,
234+
"npc_lock with on fid that has not been opened type value fails with EBADF");
235+
236+
ok (npc_clunk (fid) == 0, "clunked fid");
237+
}
238+
239+
int main (int argc, char *argv[])
240+
{
241+
Npsrv *srv;
242+
int client_fd;
243+
int flags = 0;//SRV_FLAGS_DEBUG_9PTRACE;
244+
char tmpdir[] = "/tmp/test-lock.XXXXXX";
245+
Npcfid *root;
246+
247+
plan (NO_PLAN);
248+
249+
if (!mkdtemp (tmpdir))
250+
BAIL_OUT ("mkdtemp: %s", strerror (errno));
251+
srv = test_server_create (tmpdir, flags, &client_fd);
252+
253+
root = npc_mount (client_fd, client_fd, TEST_MSIZE, tmpdir, NULL);
254+
if (!root)
255+
BAIL_OUT ("npc_mount: %s", strerror (np_rerror ()));
256+
257+
make_test_file (root, "foo", TEST_FILE_SIZE);
258+
259+
test_unlock (root, "foo");
260+
test_clunk (root, "foo");
261+
test_readwrite (root, "foo");
262+
test_ranges (root, "foo");
263+
test_getlock (root, "foo");
264+
test_badparam (root, "foo");
265+
266+
if (npc_remove_bypath (root, "foo") < 0)
267+
BAIL_OUT ("npc_remove_bypath: %s", strerror (np_rerror ()));
268+
269+
npc_umount (root);
270+
271+
test_server_destroy (srv);
272+
273+
rmdir (tmpdir);
274+
275+
done_testing ();
276+
277+
exit (0);
278+
}
279+
280+
/*
281+
* vi:tabstop=4 shiftwidth=4 expandtab
282+
*/

0 commit comments

Comments
 (0)