Line data Source code
1 : #include "../common/tdb_private.h"
2 : #include "lock-tracking.h"
3 :
4 : static ssize_t pwrite_check(int fd, const void *buf, size_t count, off_t offset);
5 : static ssize_t write_check(int fd, const void *buf, size_t count);
6 : static int ftruncate_check(int fd, off_t length);
7 :
8 : #define pwrite pwrite_check
9 : #define write write_check
10 : #define fcntl fcntl_with_lockcheck
11 : #define ftruncate ftruncate_check
12 :
13 : #include "../common/io.c"
14 : #include "../common/tdb.c"
15 : #include "../common/lock.c"
16 : #include "../common/freelist.c"
17 : #include "../common/traverse.c"
18 : #include "../common/transaction.c"
19 : #include "../common/error.c"
20 : #include "../common/open.c"
21 : #include "../common/check.c"
22 : #include "../common/hash.c"
23 : #include "../common/mutex.c"
24 : #include "tap-interface.h"
25 : #include <stdlib.h>
26 : #include <stdbool.h>
27 : #include <stdarg.h>
28 : #include "external-agent.h"
29 : #include "logging.h"
30 :
31 : static struct agent *agent;
32 : static bool opened;
33 : static int errors = 0;
34 : static bool clear_if_first;
35 : #define TEST_DBNAME "run-open-during-transaction.tdb"
36 :
37 : #undef write
38 : #undef pwrite
39 : #undef fcntl
40 : #undef ftruncate
41 :
42 24 : static bool is_same(const char *snapshot, const char *latest, off_t len)
43 : {
44 : unsigned i;
45 :
46 19955736 : for (i = 0; i < len; i++) {
47 19955712 : if (snapshot[i] != latest[i])
48 0 : return false;
49 : }
50 24 : return true;
51 : }
52 :
53 24 : static bool compare_file(int fd, const char *snapshot, off_t snapshot_len)
54 : {
55 : char *contents;
56 : bool same;
57 :
58 : /* over-length read serves as length check. */
59 24 : contents = malloc(snapshot_len+1);
60 24 : same = pread(fd, contents, snapshot_len+1, 0) == snapshot_len
61 24 : && is_same(snapshot, contents, snapshot_len);
62 24 : free(contents);
63 24 : return same;
64 : }
65 :
66 24 : static void check_file_intact(int fd)
67 : {
68 : enum agent_return ret;
69 : struct stat st;
70 : char *contents;
71 :
72 24 : fstat(fd, &st);
73 24 : contents = malloc(st.st_size);
74 24 : if (pread(fd, contents, st.st_size, 0) != st.st_size) {
75 0 : diag("Read fail");
76 0 : errors++;
77 0 : free(contents);
78 0 : return;
79 : }
80 :
81 : /* Ask agent to open file. */
82 24 : ret = external_agent_operation(agent, clear_if_first ?
83 : OPEN_WITH_CLEAR_IF_FIRST :
84 : OPEN,
85 : TEST_DBNAME);
86 :
87 : /* It's OK to open it, but it must not have changed! */
88 24 : if (!compare_file(fd, contents, st.st_size)) {
89 0 : diag("Agent changed file after opening %s",
90 : agent_return_name(ret));
91 0 : errors++;
92 : }
93 :
94 24 : if (ret == SUCCESS) {
95 4 : ret = external_agent_operation(agent, CLOSE, NULL);
96 4 : if (ret != SUCCESS) {
97 0 : diag("Agent failed to close tdb: %s",
98 : agent_return_name(ret));
99 0 : errors++;
100 : }
101 20 : } else if (ret != WOULD_HAVE_BLOCKED) {
102 0 : diag("Agent opening file gave %s",
103 : agent_return_name(ret));
104 0 : errors++;
105 : }
106 :
107 24 : free(contents);
108 : }
109 :
110 20 : static void after_unlock(int fd)
111 : {
112 20 : if (opened)
113 12 : check_file_intact(fd);
114 20 : }
115 :
116 12 : static ssize_t pwrite_check(int fd,
117 : const void *buf, size_t count, off_t offset)
118 : {
119 12 : if (opened)
120 12 : check_file_intact(fd);
121 :
122 12 : return pwrite(fd, buf, count, offset);
123 : }
124 :
125 4 : static ssize_t write_check(int fd, const void *buf, size_t count)
126 : {
127 4 : if (opened)
128 0 : check_file_intact(fd);
129 :
130 4 : return write(fd, buf, count);
131 : }
132 :
133 4 : static int ftruncate_check(int fd, off_t length)
134 : {
135 4 : if (opened)
136 0 : check_file_intact(fd);
137 :
138 4 : return ftruncate(fd, length);
139 :
140 : }
141 :
142 1 : int main(int argc, char *argv[])
143 : {
144 1 : const int flags[] = { TDB_DEFAULT,
145 : TDB_CLEAR_IF_FIRST,
146 : TDB_NOMMAP,
147 : TDB_CLEAR_IF_FIRST | TDB_NOMMAP };
148 : int i;
149 : struct tdb_context *tdb;
150 : TDB_DATA key, data;
151 :
152 : plan_tests(20);
153 1 : agent = prepare_external_agent();
154 :
155 1 : unlock_callback = after_unlock;
156 5 : for (i = 0; i < sizeof(flags)/sizeof(flags[0]); i++) {
157 4 : clear_if_first = (flags[i] & TDB_CLEAR_IF_FIRST);
158 4 : diag("Test with %s and %s",
159 : clear_if_first ? "CLEAR" : "DEFAULT",
160 : (flags[i] & TDB_NOMMAP) ? "no mmap" : "mmap");
161 4 : unlink(TEST_DBNAME);
162 4 : tdb = tdb_open_ex(TEST_DBNAME, 1024, flags[i],
163 : O_CREAT|O_TRUNC|O_RDWR, 0600,
164 : &taplogctx, NULL);
165 4 : ok1(tdb);
166 :
167 4 : opened = true;
168 4 : ok1(tdb_transaction_start(tdb) == 0);
169 4 : key.dsize = strlen("hi");
170 4 : key.dptr = discard_const_p(uint8_t, "hi");
171 4 : data.dptr = discard_const_p(uint8_t, "world");
172 4 : data.dsize = strlen("world");
173 :
174 4 : ok1(tdb_store(tdb, key, data, TDB_INSERT) == 0);
175 4 : ok1(tdb_transaction_commit(tdb) == 0);
176 4 : ok(!errors, "We had %u open errors", errors);
177 :
178 4 : opened = false;
179 4 : tdb_close(tdb);
180 : }
181 :
182 1 : return exit_status();
183 : }
|