Revert "vfs_aio_pthread: use event context and threadpool from user_vfs_evg"
[samba.git] / source3 / torture / test_cleanup.c
1 /*
2    Unix SMB/CIFS implementation.
3    Test cleanup behaviour
4    Copyright (C) Volker Lendecke 2011
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "locking/proto.h"
22 #include "torture/proto.h"
23 #include "system/filesys.h"
24 #include "system/select.h"
25 #include "libsmb/libsmb.h"
26 #include "libcli/smb/smbXcli_base.h"
27 #include "libcli/security/security.h"
28 #include "librpc/gen_ndr/open_files.h"
29
30 bool run_cleanup1(int dummy)
31 {
32         struct cli_state *cli;
33         const char *fname = "\\cleanup1";
34         uint16_t fnum;
35         NTSTATUS status;
36
37         printf("CLEANUP1: Checking that a conflicting share mode is cleaned "
38                "up\n");
39
40         if (!torture_open_connection(&cli, 0)) {
41                 return false;
42         }
43         status = cli_openx(cli, fname, O_RDWR|O_CREAT, DENY_ALL, &fnum);
44         if (!NT_STATUS_IS_OK(status)) {
45                 printf("open of %s failed (%s)\n", fname, nt_errstr(status));
46                 return false;
47         }
48         status = smbXcli_conn_samba_suicide(cli->conn, 1);
49         if (!NT_STATUS_IS_OK(status)) {
50                 printf("smbXcli_conn_samba_suicide failed: %s\n",
51                        nt_errstr(status));
52                 return false;
53         }
54
55         if (!torture_open_connection(&cli, 1)) {
56                 return false;
57         }
58         status = cli_ntcreate(
59                 cli, fname, 0,
60                 FILE_GENERIC_READ|FILE_GENERIC_WRITE|DELETE_ACCESS,
61                 FILE_ATTRIBUTE_NORMAL,
62                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
63                 FILE_OPEN, FILE_DELETE_ON_CLOSE, 0, &fnum, NULL);
64         if (!NT_STATUS_IS_OK(status)) {
65                 printf("2nd open of %s failed (%s)\n", fname,
66                        nt_errstr(status));
67                 return false;
68         }
69         cli_close(cli, fnum);
70
71         torture_close_connection(cli);
72         return NT_STATUS_IS_OK(status);
73 }
74
75 bool run_cleanup2(int dummy)
76 {
77         struct cli_state *cli1, *cli2, *cli3;
78         const char *fname = "\\cleanup2";
79         uint16_t fnum1, fnum2, fnum3;
80         NTSTATUS status;
81         char buf;
82
83         printf("CLEANUP2: Checking that a conflicting brlock is cleaned up\n");
84
85         if (!torture_open_connection(&cli1, 0)) {
86                 return false;
87         }
88         status = cli_ntcreate(
89                 cli1, fname, 0, FILE_GENERIC_READ|FILE_GENERIC_WRITE,
90                 FILE_ATTRIBUTE_NORMAL,
91                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
92                 FILE_OVERWRITE_IF, 0, 0, &fnum1, NULL);
93         if (!NT_STATUS_IS_OK(status)) {
94                 printf("open of %s failed (%s)\n", fname, nt_errstr(status));
95                 return false;
96         }
97         status = cli_lock32(cli1, fnum1, 0, 1, 0, WRITE_LOCK);
98         if (!NT_STATUS_IS_OK(status)) {
99                 printf("lock failed (%s)\n", nt_errstr(status));
100                 return false;
101         }
102
103         if (!torture_open_connection(&cli3, 1)) {
104                 return false;
105         }
106         status = cli_ntcreate(
107                 cli3, fname, 0, FILE_GENERIC_READ|FILE_GENERIC_WRITE,
108                 FILE_ATTRIBUTE_NORMAL,
109                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
110                 FILE_OVERWRITE_IF, 0, 0, &fnum3, NULL);
111         if (!NT_STATUS_IS_OK(status)) {
112                 printf("open of %s failed (%s)\n", fname, nt_errstr(status));
113                 return false;
114         }
115         status = cli_lock32(cli3, fnum3, 1, 1, 0, WRITE_LOCK);
116         if (!NT_STATUS_IS_OK(status)) {
117                 printf("lock failed (%s)\n", nt_errstr(status));
118                 return false;
119         }
120
121         status = cli_lock32(cli1, fnum1, 2, 1, 0, WRITE_LOCK);
122         if (!NT_STATUS_IS_OK(status)) {
123                 printf("lock failed (%s)\n", nt_errstr(status));
124                 return false;
125         }
126
127         /*
128          * Check the file is indeed locked
129          */
130         if (!torture_open_connection(&cli2, 1)) {
131                 return false;
132         }
133         status = cli_ntcreate(
134                 cli2, fname, 0, FILE_GENERIC_READ|FILE_GENERIC_WRITE,
135                 FILE_ATTRIBUTE_NORMAL,
136                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
137                 FILE_OPEN, 0, 0, &fnum2, NULL);
138         if (!NT_STATUS_IS_OK(status)) {
139                 printf("open of %s failed (%s)\n", fname, nt_errstr(status));
140                 return false;
141         }
142         buf = 'x';
143         status = cli_smbwrite(cli2, fnum2, &buf, 0, 1, NULL);
144         if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
145                 printf("write succeeded\n");
146                 return false;
147         }
148
149         /*
150          * Kill the lock holder
151          */
152         status = smbXcli_conn_samba_suicide(cli1->conn, 1);
153         if (!NT_STATUS_IS_OK(status)) {
154                 printf("smbXcli_conn_samba_suicide failed: %s\n",
155                        nt_errstr(status));
156                 return false;
157         }
158
159         /*
160          * Give the suicidal smbd a bit of time to really pass away
161          */
162         smb_msleep(1000);
163
164         status = cli_smbwrite(cli2, fnum2, &buf, 0, 1, NULL);
165         if (!NT_STATUS_IS_OK(status)) {
166                 printf("write failed: %s\n", nt_errstr(status));
167                 return false;
168         }
169         return true;
170 }
171
172 static bool create_stale_share_mode_entry(const char *fname,
173                                           struct file_id *p_id)
174 {
175         struct cli_state *cli;
176         uint16_t fnum;
177         NTSTATUS status;
178         SMB_STRUCT_STAT sbuf;
179         struct file_id id;
180
181         if (!torture_open_connection(&cli, 0)) {
182                 return false;
183         }
184
185         status = torture_setup_unix_extensions(cli);
186         if (!NT_STATUS_IS_OK(status)) {
187                 printf("torture_setup_unix_extensions failed: %s\n",
188                        nt_errstr(status));
189                 return false;
190         }
191         status = cli_openx(cli, fname, O_RDWR|O_CREAT, DENY_ALL, &fnum);
192         if (!NT_STATUS_IS_OK(status)) {
193                 printf("open of %s failed (%s)\n", fname, nt_errstr(status));
194                 return false;
195         }
196         status = cli_posix_stat(cli, fname, &sbuf);
197         if (!NT_STATUS_IS_OK(status)) {
198                 printf("cli_posix_stat failed: %s\n", nt_errstr(status));
199                 return false;
200         }
201         status = smbXcli_conn_samba_suicide(cli->conn, 1);
202         if (!NT_STATUS_IS_OK(status)) {
203                 printf("smbXcli_conn_samba_suicide failed: %s\n",
204                        nt_errstr(status));
205                 return false;
206         }
207
208         id.devid = sbuf.st_ex_rdev;
209         id.inode = sbuf.st_ex_ino;
210         id.extid = 0;
211
212         poll(NULL, 0, 1000);
213
214         *p_id = id;
215         return true;
216 }
217
218 static bool corrupt_dummy(struct share_mode_data *d)
219 {
220         return true;
221 }
222
223 static bool invalidate_sharemode(struct share_mode_data *d)
224 {
225         d->share_modes[0].op_type =
226                 OPLOCK_EXCLUSIVE|OPLOCK_BATCH|OPLOCK_LEVEL_II;
227         d->modified = true;
228         return true;
229 }
230
231 static bool duplicate_entry(struct share_mode_data *d, int i)
232 {
233         struct share_mode_entry *tmp;
234
235         if (i >= d->num_share_modes) {
236                 return false;
237         }
238
239         tmp = talloc_realloc(d, d->share_modes, struct share_mode_entry,
240                              d->num_share_modes + 1);
241         if (tmp == NULL) {
242                 return false;
243         }
244         d->share_modes = tmp;
245         d->num_share_modes += 1;
246         d->share_modes[d->num_share_modes-1] = d->share_modes[i];
247         d->modified = true;
248         return true;
249 }
250
251 static bool create_duplicate_batch(struct share_mode_data *d)
252 {
253         if (d->num_share_modes != 1) {
254                 return false;
255         }
256         d->share_modes[0].op_type = OPLOCK_BATCH;
257         if (!duplicate_entry(d, 0)) {
258                 return false;
259         }
260         return true;
261 }
262
263 struct corruption_fns {
264         bool (*fn)(struct share_mode_data *d);
265         const char *descr;
266 };
267
268 bool run_cleanup3(int dummy)
269 {
270         struct cli_state *cli;
271         const char *fname = "cleanup3";
272         uint16_t fnum;
273         NTSTATUS status;
274         struct share_mode_lock *lck;
275         struct file_id id;
276         size_t i;
277
278         struct corruption_fns fns[] = {
279                 { corrupt_dummy, "no corruption" },
280                 { invalidate_sharemode, "invalidate_sharemode" },
281                 { create_duplicate_batch, "create_duplicate_batch" },
282         };
283
284         printf("CLEANUP3: Checking that a share mode is cleaned up on "
285                "conflict\n");
286
287         for (i=0; i<ARRAY_SIZE(fns); i++) {
288
289                 printf("testing %s\n", fns[i].descr);
290
291                 if (!create_stale_share_mode_entry(fname, &id)) {
292                         printf("create_stale_entry failed\n");
293                         return false;
294                 }
295
296                 printf("%d %d %d\n", (int)id.devid, (int)id.inode,
297                        (int)id.extid);
298
299                 if (!locking_init()) {
300                         printf("locking_init failed\n");
301                         return false;
302                 }
303                 lck = get_existing_share_mode_lock(talloc_tos(), id);
304                 if (lck == NULL) {
305                         printf("get_existing_share_mode_lock failed\n");
306                         return false;
307                 }
308                 if (lck->data->num_share_modes != 1) {
309                         printf("get_existing_share_mode_lock did clean up\n");
310                         return false;
311                 }
312
313                 fns[i].fn(lck->data);
314
315                 TALLOC_FREE(lck);
316
317                 if (!torture_open_connection(&cli, 0)) {
318                         return false;
319                 }
320                 status = cli_openx(cli, fname, O_RDWR|O_CREAT, DENY_ALL,
321                                    &fnum);
322                 if (!NT_STATUS_IS_OK(status)) {
323                         printf("open of %s failed (%s)\n", fname,
324                                nt_errstr(status));
325                         return false;
326                 }
327                 lck = get_existing_share_mode_lock(talloc_tos(), id);
328                 if (lck == NULL) {
329                         printf("get_existing_share_mode_lock failed\n");
330                         return false;
331                 }
332                 if (lck->data->num_share_modes != 1) {
333                         printf("conflicting open did not clean up\n");
334                         return false;
335                 }
336                 TALLOC_FREE(lck);
337
338                 torture_close_connection(cli);
339         }
340
341         return true;
342 }
343
344 bool run_cleanup4(int dummy)
345 {
346         struct cli_state *cli1, *cli2;
347         const char *fname = "\\cleanup4";
348         uint16_t fnum1, fnum2;
349         NTSTATUS status;
350
351         printf("CLEANUP4: Checking that a conflicting share mode is cleaned "
352                "up\n");
353
354         if (!torture_open_connection(&cli1, 0)) {
355                 return false;
356         }
357         if (!torture_open_connection(&cli2, 0)) {
358                 return false;
359         }
360
361         status = cli_ntcreate(
362                 cli1, fname, 0,
363                 FILE_GENERIC_READ|DELETE_ACCESS,
364                 FILE_ATTRIBUTE_NORMAL,
365                 FILE_SHARE_READ|FILE_SHARE_DELETE,
366                 FILE_OVERWRITE_IF, 0, 0, &fnum1, NULL);
367         if (!NT_STATUS_IS_OK(status)) {
368                 printf("creating file failed: %s\n",
369                        nt_errstr(status));
370                 return false;
371         }
372
373         status = cli_ntcreate(
374                 cli2, fname, 0,
375                 FILE_GENERIC_READ|DELETE_ACCESS,
376                 FILE_ATTRIBUTE_NORMAL,
377                 FILE_SHARE_READ|FILE_SHARE_DELETE,
378                 FILE_OPEN, 0, 0, &fnum2, NULL);
379         if (!NT_STATUS_IS_OK(status)) {
380                 printf("opening file 1st time failed: %s\n",
381                        nt_errstr(status));
382                 return false;
383         }
384
385         status = smbXcli_conn_samba_suicide(cli1->conn, 1);
386         if (!NT_STATUS_IS_OK(status)) {
387                 printf("smbXcli_conn_samba_suicide failed: %s\n",
388                        nt_errstr(status));
389                 return false;
390         }
391
392         /*
393          * The next open will conflict with both opens above. The first open
394          * above will be correctly cleaned up. A bug in smbd iterating over
395          * the share mode array made it skip the share conflict check for the
396          * second open. Trigger this bug.
397          */
398
399         status = cli_ntcreate(
400                 cli2, fname, 0,
401                 FILE_GENERIC_WRITE|DELETE_ACCESS,
402                 FILE_ATTRIBUTE_NORMAL,
403                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
404                 FILE_OPEN, 0, 0, &fnum2, NULL);
405         if (!NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
406                 printf("opening file 2nd time returned: %s\n",
407                        nt_errstr(status));
408                 return false;
409         }
410
411         return true;
412 }