Line data Source code
1 : #include "../common/io.c"
2 : #include "../common/tdb.c"
3 : #include "../common/lock.c"
4 : #include "../common/freelist.c"
5 : #include "../common/traverse.c"
6 : #include "../common/transaction.c"
7 : #include "../common/error.c"
8 : #include "../common/open.c"
9 : #include "../common/check.c"
10 : #include "../common/hash.c"
11 : #include "../common/mutex.c"
12 : #include "tap-interface.h"
13 : #include <stdlib.h>
14 : #include <sys/types.h>
15 : #include <sys/wait.h>
16 : #include <stdarg.h>
17 : #include "logging.h"
18 :
19 : static TDB_DATA key, data;
20 :
21 1 : static void do_chainlock(const char *name, int tdb_flags, int up, int down)
22 : {
23 : struct tdb_context *tdb;
24 : int ret;
25 : ssize_t nread, nwritten;
26 1 : char c = 0;
27 :
28 1 : tdb = tdb_open_ex(name, 3, tdb_flags,
29 : O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
30 1 : ok(tdb, "tdb_open_ex should succeed");
31 :
32 1 : ret = tdb_chainlock_read(tdb, key);
33 1 : ok(ret == 0, "tdb_chainlock_read should succeed");
34 :
35 1 : nwritten = write(up, &c, sizeof(c));
36 1 : ok(nwritten == sizeof(c), "write should succeed");
37 :
38 1 : nread = read(down, &c, sizeof(c));
39 1 : ok(nread == 0, "read should succeed");
40 :
41 1 : exit(0);
42 : }
43 :
44 1 : static void do_trylock(const char *name, int tdb_flags, int up, int down)
45 : {
46 : struct tdb_context *tdb;
47 : int ret;
48 : ssize_t nread, nwritten;
49 1 : char c = 0;
50 :
51 1 : tdb = tdb_open_ex(name, 3, tdb_flags,
52 : O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
53 1 : ok(tdb, "tdb_open_ex should succeed");
54 :
55 : /*
56 : * tdb used to have a bug where with fcntl locks an upgrade
57 : * from a readlock to writelock did not check for the
58 : * underlying fcntl lock. Mutexes don't distinguish between
59 : * readlocks and writelocks, so that bug does not apply here.
60 : */
61 :
62 1 : ret = tdb_chainlock_read(tdb, key);
63 1 : ok(ret == 0, "tdb_chainlock_read should succeed");
64 :
65 1 : ret = tdb_chainlock_nonblock(tdb, key);
66 1 : ok(ret == -1, "tdb_chainlock_nonblock should fail");
67 :
68 1 : nwritten = write(up, &c, sizeof(c));
69 1 : ok(nwritten == sizeof(c), "write should succeed");
70 :
71 1 : nread = read(down, &c, sizeof(c));
72 1 : ok(nread == 0, "read should succeed");
73 :
74 1 : exit(0);
75 : }
76 :
77 1 : static int do_tests(const char *name, int tdb_flags)
78 : {
79 : int ret;
80 : pid_t chainlock_child, store_child;
81 : int chainlock_down[2];
82 : int chainlock_up[2];
83 : int store_down[2];
84 : int store_up[2];
85 : char c;
86 : ssize_t nread;
87 :
88 1 : key.dsize = strlen("hi");
89 1 : key.dptr = discard_const_p(uint8_t, "hi");
90 1 : data.dsize = strlen("world");
91 1 : data.dptr = discard_const_p(uint8_t, "world");
92 :
93 1 : ret = pipe(chainlock_down);
94 1 : ok(ret == 0, "pipe should succeed");
95 :
96 1 : ret = pipe(chainlock_up);
97 1 : ok(ret == 0, "pipe should succeed");
98 :
99 1 : ret = pipe(store_down);
100 1 : ok(ret == 0, "pipe should succeed");
101 :
102 1 : ret = pipe(store_up);
103 1 : ok(ret == 0, "pipe should succeed");
104 :
105 1 : chainlock_child = fork();
106 2 : ok(chainlock_child != -1, "fork should succeed");
107 :
108 2 : if (chainlock_child == 0) {
109 1 : close(chainlock_up[0]);
110 1 : close(chainlock_down[1]);
111 1 : close(store_up[0]);
112 1 : close(store_up[1]);
113 1 : close(store_down[0]);
114 1 : close(store_down[1]);
115 1 : do_chainlock(name, tdb_flags,
116 : chainlock_up[1], chainlock_down[0]);
117 0 : exit(0);
118 : }
119 1 : close(chainlock_up[1]);
120 1 : close(chainlock_down[0]);
121 :
122 1 : nread = read(chainlock_up[0], &c, sizeof(c));
123 1 : ok(nread == sizeof(c), "read should succeed");
124 :
125 : /*
126 : * Now we have a process holding a chain read lock. Start
127 : * another process trying to write lock. This should fail.
128 : */
129 :
130 1 : store_child = fork();
131 2 : ok(store_child != -1, "fork should succeed");
132 :
133 2 : if (store_child == 0) {
134 1 : close(chainlock_up[0]);
135 1 : close(chainlock_down[1]);
136 1 : close(store_up[0]);
137 1 : close(store_down[1]);
138 1 : do_trylock(name, tdb_flags,
139 : store_up[1], store_down[0]);
140 0 : exit(0);
141 : }
142 1 : close(store_up[1]);
143 1 : close(store_down[0]);
144 :
145 1 : nread = read(store_up[0], &c, sizeof(c));
146 1 : ok(nread == sizeof(c), "read should succeed");
147 :
148 1 : close(chainlock_up[0]);
149 1 : close(chainlock_down[1]);
150 1 : close(store_up[0]);
151 1 : close(store_down[1]);
152 1 : diag("%s tests done", name);
153 1 : return exit_status();
154 : }
155 :
156 1 : int main(int argc, char *argv[])
157 : {
158 : int ret;
159 :
160 1 : ret = do_tests("rdlock-upgrade.tdb",
161 : TDB_CLEAR_IF_FIRST |
162 : TDB_INCOMPATIBLE_HASH);
163 1 : ok(ret == 0, "rdlock-upgrade.tdb tests should succeed");
164 :
165 1 : return exit_status();
166 : }
|