t_vnops.c revision 1.14 1 /* $NetBSD: t_vnops.c,v 1.14 2011/02/22 21:23:19 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/stat.h>
30 #include <sys/statvfs.h>
31
32 #include <assert.h>
33 #include <atf-c.h>
34 #include <fcntl.h>
35 #include <libgen.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include <rump/rump_syscalls.h>
41 #include <rump/rump.h>
42
43 #include "../common/h_fsmacros.h"
44 #include "../../h_macros.h"
45
46 #define TESTFILE "afile"
47
48 #define USES_DIRS \
49 if (FSTYPE_SYSVBFS(tc)) atf_tc_skip("dirs not supported by file system")
50
51 #define USES_SYMLINKS \
52 if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc)) \
53 atf_tc_skip("symlinks not supported by file system")
54
55 static char *
56 md(char *buf, const char *base, const char *tail)
57 {
58
59 sprintf(buf, "%s/%s", base, tail);
60 return buf;
61 }
62
63 static void
64 lookup_simple(const atf_tc_t *tc, const char *mountpath)
65 {
66 char pb[MAXPATHLEN], final[MAXPATHLEN];
67 struct stat sb1, sb2;
68
69 strcpy(final, mountpath);
70 sprintf(pb, "%s/../%s", mountpath, basename(final));
71 if (rump_sys_stat(pb, &sb1) == -1)
72 atf_tc_fail_errno("stat 1");
73
74 sprintf(pb, "%s/./../%s", mountpath, basename(final));
75 if (rump_sys_stat(pb, &sb2) == -1)
76 atf_tc_fail_errno("stat 2");
77
78 ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
79 }
80
81 static void
82 lookup_complex(const atf_tc_t *tc, const char *mountpath)
83 {
84 char pb[MAXPATHLEN];
85 struct stat sb1, sb2;
86
87 USES_DIRS;
88
89 sprintf(pb, "%s/dir", mountpath);
90 if (rump_sys_mkdir(pb, 0777) == -1)
91 atf_tc_fail_errno("mkdir");
92 if (rump_sys_stat(pb, &sb1) == -1)
93 atf_tc_fail_errno("stat 1");
94
95 sprintf(pb, "%s/./dir/../././dir/.", mountpath);
96 if (rump_sys_stat(pb, &sb2) == -1)
97 atf_tc_fail_errno("stat 2");
98
99 ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
100 }
101
102 static void
103 dir_simple(const atf_tc_t *tc, const char *mountpath)
104 {
105 char pb[MAXPATHLEN];
106 struct stat sb;
107
108 USES_DIRS;
109
110 /* check we can create directories */
111 sprintf(pb, "%s/dir", mountpath);
112 if (rump_sys_mkdir(pb, 0777) == -1)
113 atf_tc_fail_errno("mkdir");
114 if (rump_sys_stat(pb, &sb) == -1)
115 atf_tc_fail_errno("stat new directory");
116
117 /* check we can remove then and that it makes them unreachable */
118 if (rump_sys_rmdir(pb) == -1)
119 atf_tc_fail_errno("rmdir");
120 if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT)
121 atf_tc_fail("ENOENT expected from stat");
122 }
123
124 static void
125 dir_notempty(const atf_tc_t *tc, const char *mountpath)
126 {
127 char pb[MAXPATHLEN], pb2[MAXPATHLEN];
128 int fd, rv;
129
130 USES_DIRS;
131
132 /* check we can create directories */
133 sprintf(pb, "%s/dir", mountpath);
134 if (rump_sys_mkdir(pb, 0777) == -1)
135 atf_tc_fail_errno("mkdir");
136
137 sprintf(pb2, "%s/dir/file", mountpath);
138 fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777);
139 if (fd == -1)
140 atf_tc_fail_errno("create file");
141 rump_sys_close(fd);
142
143 rv = rump_sys_rmdir(pb);
144 if (rv != -1 || errno != ENOTEMPTY)
145 atf_tc_fail("non-empty directory removed succesfully");
146
147 if (rump_sys_unlink(pb2) == -1)
148 atf_tc_fail_errno("cannot remove dir/file");
149
150 if (rump_sys_rmdir(pb) == -1)
151 atf_tc_fail_errno("remove directory");
152 }
153
154 static void
155 checkfile(const char *path, struct stat *refp)
156 {
157 char buf[MAXPATHLEN];
158 struct stat sb;
159 static int n = 1;
160
161 md(buf, path, "file");
162 if (rump_sys_stat(buf, &sb) == -1)
163 atf_tc_fail_errno("cannot stat file %d (%s)", n, buf);
164 if (memcmp(&sb, refp, sizeof(sb)) != 0)
165 atf_tc_fail("stat mismatch %d", n);
166 n++;
167 }
168
169 static void
170 rename_dir(const atf_tc_t *tc, const char *mp)
171 {
172 char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN];
173 struct stat ref;
174
175 if (FSTYPE_MSDOS(tc))
176 atf_tc_skip("test fails in some setups, reason unknown");
177
178 if (FSTYPE_RUMPFS(tc))
179 atf_tc_skip("rename not supported by fs");
180
181 USES_DIRS;
182
183 md(pb1, mp, "dir1");
184 if (rump_sys_mkdir(pb1, 0777) == -1)
185 atf_tc_fail_errno("mkdir 1");
186
187 md(pb2, mp, "dir2");
188 if (rump_sys_mkdir(pb2, 0777) == -1)
189 atf_tc_fail_errno("mkdir 2");
190 md(pb2, mp, "dir2/subdir");
191 if (rump_sys_mkdir(pb2, 0777) == -1)
192 atf_tc_fail_errno("mkdir 3");
193
194 md(pb3, mp, "dir1/file");
195 if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1)
196 atf_tc_fail_errno("create file");
197 if (rump_sys_stat(pb3, &ref) == -1)
198 atf_tc_fail_errno("stat of file");
199
200 /*
201 * First try ops which should succeed.
202 */
203
204 /* rename within directory */
205 md(pb3, mp, "dir3");
206 if (rump_sys_rename(pb1, pb3) == -1)
207 atf_tc_fail_errno("rename 1");
208 checkfile(pb3, &ref);
209
210 /* rename directory onto itself (two ways, should fail) */
211 md(pb1, mp, "dir3/.");
212 if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL)
213 atf_tc_fail_errno("rename 2");
214 if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR)
215 atf_tc_fail_errno("rename 3");
216
217 checkfile(pb3, &ref);
218
219 /* rename father of directory into directory */
220 md(pb1, mp, "dir2/dir");
221 md(pb2, mp, "dir2");
222 if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
223 atf_tc_fail_errno("rename 4");
224
225 /* same for grandfather */
226 md(pb1, mp, "dir2/subdir/dir2");
227 if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
228 atf_tc_fail("rename 5");
229
230 checkfile(pb3, &ref);
231
232 /* rename directory over a non-empty directory */
233 if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY)
234 atf_tc_fail("rename 6");
235
236 /* cross-directory rename */
237 md(pb1, mp, "dir3");
238 md(pb2, mp, "dir2/somedir");
239 if (rump_sys_rename(pb1, pb2) == -1)
240 atf_tc_fail_errno("rename 7");
241 checkfile(pb2, &ref);
242
243 /* move to parent directory */
244 md(pb1, mp, "dir2/somedir/../../dir3");
245 if (rump_sys_rename(pb2, pb1) == -1)
246 atf_tc_fail_errno("rename 8");
247 md(pb1, mp, "dir2/../dir3");
248 checkfile(pb1, &ref);
249
250 /* finally, atomic cross-directory rename */
251 md(pb3, mp, "dir2/subdir");
252 if (rump_sys_rename(pb1, pb3) == -1)
253 atf_tc_fail_errno("rename 9");
254 checkfile(pb3, &ref);
255 }
256
257 static void
258 rename_dotdot(const atf_tc_t *tc, const char *mp)
259 {
260
261 if (FSTYPE_RUMPFS(tc))
262 atf_tc_skip("rename not supported by fs");
263
264 USES_DIRS;
265
266 if (rump_sys_chdir(mp) == -1)
267 atf_tc_fail_errno("chdir mountpoint");
268
269 if (rump_sys_mkdir("dir1", 0777) == -1)
270 atf_tc_fail_errno("mkdir 1");
271 if (rump_sys_mkdir("dir2", 0777) == -1)
272 atf_tc_fail_errno("mkdir 2");
273
274 if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL)
275 atf_tc_fail_errno("self-dotdot to");
276
277 if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL)
278 atf_tc_fail_errno("self-dotdot from");
279 atf_tc_expect_pass();
280
281 if (FSTYPE_TMPFS(tc)) {
282 atf_tc_expect_fail("PR kern/43617");
283 }
284 if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL)
285 atf_tc_fail("other-dotdot");
286
287 rump_sys_chdir("/");
288 }
289
290 static void
291 rename_reg_nodir(const atf_tc_t *tc, const char *mp)
292 {
293 bool haslinks;
294 struct stat sb;
295 ino_t f1ino, f2ino;
296
297 if (FSTYPE_RUMPFS(tc))
298 atf_tc_skip("rename not supported by fs");
299
300 if (FSTYPE_MSDOS(tc))
301 atf_tc_skip("test fails in some setups, reason unknown");
302
303 if (rump_sys_chdir(mp) == -1)
304 atf_tc_fail_errno("chdir mountpoint");
305
306 if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))
307 haslinks = false;
308 else
309 haslinks = true;
310
311 if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1)
312 atf_tc_fail_errno("create file");
313 if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1)
314 atf_tc_fail_errno("create file");
315
316 if (rump_sys_stat("file1", &sb) == -1)
317 atf_tc_fail_errno("stat");
318 f1ino = sb.st_ino;
319
320 if (haslinks) {
321 if (rump_sys_link("file1", "file_link") == -1)
322 atf_tc_fail_errno("link");
323 if (rump_sys_stat("file_link", &sb) == -1)
324 atf_tc_fail_errno("stat");
325 ATF_REQUIRE_EQ(sb.st_ino, f1ino);
326 ATF_REQUIRE_EQ(sb.st_nlink, 2);
327 }
328
329 if (rump_sys_stat("file2", &sb) == -1)
330 atf_tc_fail_errno("stat");
331 f2ino = sb.st_ino;
332
333 if (rump_sys_rename("file1", "file3") == -1)
334 atf_tc_fail_errno("rename 1");
335 if (rump_sys_stat("file3", &sb) == -1)
336 atf_tc_fail_errno("stat 1");
337 if (haslinks) {
338 ATF_REQUIRE_EQ(sb.st_ino, f1ino);
339 }
340 if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT)
341 atf_tc_fail_errno("source 1");
342
343 if (rump_sys_rename("file3", "file2") == -1)
344 atf_tc_fail_errno("rename 2");
345 if (rump_sys_stat("file2", &sb) == -1)
346 atf_tc_fail_errno("stat 2");
347 if (haslinks) {
348 ATF_REQUIRE_EQ(sb.st_ino, f1ino);
349 }
350
351 if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT)
352 atf_tc_fail_errno("source 2");
353
354 if (haslinks) {
355 if (rump_sys_rename("file2", "file_link") == -1)
356 atf_tc_fail_errno("rename hardlink");
357 if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT)
358 atf_tc_fail_errno("source 3");
359 if (rump_sys_stat("file_link", &sb) == -1)
360 atf_tc_fail_errno("stat 2");
361 ATF_REQUIRE_EQ(sb.st_ino, f1ino);
362 ATF_REQUIRE_EQ(sb.st_nlink, 1);
363 }
364
365 rump_sys_chdir("/");
366 }
367
368 static void
369 create_nametoolong(const atf_tc_t *tc, const char *mp)
370 {
371 char *name;
372 int fd;
373 long val;
374 size_t len;
375
376 if (rump_sys_chdir(mp) == -1)
377 atf_tc_fail_errno("chdir mountpoint");
378
379 val = rump_sys_pathconf(".", _PC_NAME_MAX);
380 if (val == -1)
381 atf_tc_fail_errno("pathconf");
382
383 len = val + 1;
384 name = malloc(len+1);
385 if (name == NULL)
386 atf_tc_fail_errno("malloc");
387
388 memset(name, 'a', len);
389 *(name+len) = '\0';
390
391 val = rump_sys_pathconf(".", _PC_NO_TRUNC);
392 if (val == -1)
393 atf_tc_fail_errno("pathconf");
394
395 if (FSTYPE_MSDOS(tc))
396 atf_tc_expect_fail("PR kern/43670");
397 fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666);
398 if (val != 0 && (fd != -1 || errno != ENAMETOOLONG))
399 atf_tc_fail_errno("open");
400
401 if (val == 0 && rump_sys_close(fd) == -1)
402 atf_tc_fail_errno("close");
403 if (val == 0 && rump_sys_unlink(name) == -1)
404 atf_tc_fail_errno("unlink");
405
406 free(name);
407
408 rump_sys_chdir("/");
409 }
410
411 static void
412 create_exist(const atf_tc_t *tc, const char *mp)
413 {
414 const char *name = "hoge";
415 int fd;
416
417 RL(rump_sys_chdir(mp));
418 RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666));
419 RL(rump_sys_close(fd));
420 RL(rump_sys_unlink(name));
421 RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
422 RL(rump_sys_close(fd));
423 RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
424 RL(rump_sys_close(fd));
425 ATF_REQUIRE_ERRNO(EEXIST,
426 (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)));
427 RL(rump_sys_unlink(name));
428 RL(rump_sys_chdir("/"));
429 }
430
431 static void
432 rename_nametoolong(const atf_tc_t *tc, const char *mp)
433 {
434 char *name;
435 int res, fd;
436 long val;
437 size_t len;
438
439 if (FSTYPE_RUMPFS(tc))
440 atf_tc_skip("rename not supported by fs");
441
442 if (rump_sys_chdir(mp) == -1)
443 atf_tc_fail_errno("chdir mountpoint");
444
445 val = rump_sys_pathconf(".", _PC_NAME_MAX);
446 if (val == -1)
447 atf_tc_fail_errno("pathconf");
448
449 len = val + 1;
450 name = malloc(len+1);
451 if (name == NULL)
452 atf_tc_fail_errno("malloc");
453
454 memset(name, 'a', len);
455 *(name+len) = '\0';
456
457 fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666);
458 if (fd == -1)
459 atf_tc_fail_errno("open");
460 if (rump_sys_close(fd) == -1)
461 atf_tc_fail_errno("close");
462
463 val = rump_sys_pathconf(".", _PC_NO_TRUNC);
464 if (val == -1)
465 atf_tc_fail_errno("pathconf");
466
467 if (FSTYPE_MSDOS(tc))
468 atf_tc_expect_fail("PR kern/43670");
469 res = rump_sys_rename("dummy", name);
470 if (val != 0 && (res != -1 || errno != ENAMETOOLONG))
471 atf_tc_fail_errno("rename");
472
473 if (val == 0 && rump_sys_unlink(name) == -1)
474 atf_tc_fail_errno("unlink");
475
476 free(name);
477
478 rump_sys_chdir("/");
479 }
480
481 static void
482 symlink_zerolen(const atf_tc_t *tc, const char *mp)
483 {
484
485 USES_SYMLINKS;
486
487 RL(rump_sys_chdir(mp));
488
489 if (FSTYPE_TMPFS(tc)) {
490 atf_tc_expect_signal(SIGABRT, "PR kern/43843");
491 }
492
493 RL(rump_sys_symlink("", "afile"));
494 RL(rump_sys_chdir("/"));
495 }
496
497 static void
498 attrs(const atf_tc_t *tc, const char *mp)
499 {
500 struct stat sb, sb2;
501 struct timeval tv[2];
502 int fd;
503
504 FSTEST_ENTER();
505 RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
506 RL(rump_sys_close(fd));
507 RL(rump_sys_stat(TESTFILE, &sb));
508 if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
509 RL(rump_sys_chown(TESTFILE, 1, 2));
510 sb.st_uid = 1;
511 sb.st_gid = 2;
512 RL(rump_sys_chmod(TESTFILE, 0123));
513 sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123;
514 }
515
516 tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */
517 tv[0].tv_usec = 1;
518 tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */
519 tv[1].tv_usec = 3;
520 RL(rump_sys_utimes(TESTFILE, tv));
521 RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */
522 sb.st_atimespec.tv_sec = 1000000000;
523 sb.st_atimespec.tv_nsec = 1000;
524 sb.st_mtimespec.tv_sec = 1000000002;
525 sb.st_mtimespec.tv_nsec = 3000;
526
527 RL(rump_sys_stat(TESTFILE, &sb2));
528 #define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a)
529 if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
530 CHECK(st_uid);
531 CHECK(st_gid);
532 CHECK(st_mode);
533 }
534 if (!FSTYPE_MSDOS(tc)) {
535 /* msdosfs has only access date, not time */
536 CHECK(st_atimespec.tv_sec);
537 }
538 CHECK(st_mtimespec.tv_sec);
539 if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
540 CHECK(st_atimespec.tv_nsec);
541 CHECK(st_mtimespec.tv_nsec);
542 }
543 #undef CHECK
544
545 FSTEST_EXIT();
546 }
547
548 static void
549 fcntl_lock(const atf_tc_t *tc, const char *mp)
550 {
551 int fd, fd2;
552 struct flock l;
553 struct lwp *lwp1, *lwp2;
554
555 FSTEST_ENTER();
556 l.l_pid = 0;
557 l.l_start = l.l_len = 1024;
558 l.l_type = F_RDLCK | F_WRLCK;
559 l.l_whence = SEEK_END;
560
561 lwp1 = rump_pub_lwproc_curlwp();
562 RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
563 RL(rump_sys_ftruncate(fd, 8192));
564
565 /* PR kern/43321 */
566 RL(rump_sys_fcntl(fd, F_SETLK, &l));
567
568 /* Next, we fork and try to lock the same area */
569 RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
570 lwp2 = rump_pub_lwproc_curlwp();
571 RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0));
572 ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l));
573
574 /* Switch back and unlock... */
575 rump_pub_lwproc_switch(lwp1);
576 l.l_type = F_UNLCK;
577 RL(rump_sys_fcntl(fd, F_SETLK, &l));
578
579 /* ... and try to lock again */
580 rump_pub_lwproc_switch(lwp2);
581 l.l_type = F_RDLCK | F_WRLCK;
582 RL(rump_sys_fcntl(fd2, F_SETLK, &l));
583
584 RL(rump_sys_close(fd2));
585 rump_pub_lwproc_releaselwp();
586
587 RL(rump_sys_close(fd));
588
589 FSTEST_EXIT();
590 }
591
592 static int
593 flock_compare(const void *p, const void *q)
594 {
595 int a = ((const struct flock *)p)->l_start;
596 int b = ((const struct flock *)q)->l_start;
597 return a < b ? -1 : (a > b ? 1 : 0);
598 }
599
600 static void
601 fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
602 {
603 /* test non-overlaping ranges */
604 struct flock expect[4];
605 const struct flock lock[4] = {
606 { 0, 2, 0, F_WRLCK, SEEK_SET },
607 { 2, 1, 0, F_WRLCK, SEEK_SET },
608 { 7, 5, 0, F_WRLCK, SEEK_SET },
609 { 4, 3, 0, F_WRLCK, SEEK_SET },
610 };
611
612 int fd[4];
613 struct lwp *lwp[4];
614 pid_t prevpid = 0;
615
616 unsigned int i, j;
617 const off_t sz = 8192;
618 int omode = 0755;
619 int oflags = O_RDWR | O_CREAT;
620
621 memcpy(expect, lock, sizeof(lock));
622 qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
623
624 FSTEST_ENTER();
625
626 /*
627 * First, we create 4 processes and let each lock a range of the
628 * file. Note that the third and fourth processes lock in
629 * "reverse" order, i.e. the greater pid locks a range before
630 * the lesser pid.
631 */
632 for(i = 0; i < __arraycount(lwp); i++) {
633 RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
634
635 lwp[i] = rump_pub_lwproc_curlwp();
636 assert(rump_sys_getpid() > prevpid);
637 prevpid = rump_sys_getpid();
638
639 RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode));
640 oflags = O_RDWR;
641 omode = 0;
642
643 RL(rump_sys_ftruncate(fd[i], sz));
644 RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
645 }
646
647 atf_tc_expect_fail("PR kern/44494");
648 /*
649 * In the context of each pid , do GETLK for a readlock from
650 * i = [0,__arraycount(locks)]. If we try to lock from the same
651 * start offset as the lock our current process holds, check
652 * that we fail on the offset of the next lock ("else if" branch).
653 * Otherwise, expect to get a lock for the current offset
654 * ("if" branch). The "else" branch is purely for the last
655 * process where we expect no blocking locks.
656 */
657 for(i = 0; i < __arraycount(lwp); i++) {
658 rump_pub_lwproc_switch(lwp[i]);
659
660 for(j = 0; j < __arraycount(lwp); j++) {
661 struct flock l;
662 l = expect[j];
663 l.l_len = sz;
664 l.l_type = F_RDLCK;
665
666 RL(rump_sys_fcntl(fd[i], F_GETLK, &l));
667
668 if(expect[j].l_start != lock[i].l_start) {
669 /*
670 * lock set by another process
671 */
672 ATF_CHECK(l.l_type != F_UNLCK);
673 ATF_CHECK_EQ(l.l_start, expect[j].l_start);
674 ATF_CHECK_EQ(l.l_len, expect[j].l_len);
675 } else if (j != __arraycount(lwp) - 1) {
676 /*
677 * lock set by the current process
678 */
679 ATF_CHECK(l.l_type != F_UNLCK);
680 ATF_CHECK_EQ(l.l_start, expect[j+1].l_start);
681 ATF_CHECK_EQ(l.l_len, expect[j+1].l_len);
682 } else {
683 /*
684 * there are no other locks after the
685 * current process lock
686 */
687 ATF_CHECK_EQ(l.l_type, F_UNLCK);
688 ATF_CHECK_EQ(l.l_start, expect[j].l_start);
689 ATF_CHECK_EQ(l.l_len, sz);
690 ATF_CHECK_EQ(l.l_pid, expect[j].l_pid);
691 ATF_CHECK_EQ(l.l_whence, expect[j].l_whence);
692 }
693 }
694 }
695
696 /*
697 * Release processes. This also releases the fds and locks
698 * making fs unmount possible
699 */
700 for(i = 0; i < __arraycount(lwp); i++) {
701 rump_pub_lwproc_switch(lwp[i]);
702 rump_pub_lwproc_releaselwp();
703 }
704
705 FSTEST_EXIT();
706 }
707
708 ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)");
709 ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries");
710 ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir");
711 ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed");
712 ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops");
713 ATF_TC_FSAPPLY(rename_dotdot, "rename dir ..");
714 ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories");
715 ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long");
716 ATF_TC_FSAPPLY(create_exist, "create with O_EXCL");
717 ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long");
718 ATF_TC_FSAPPLY(symlink_zerolen, "symlink with 0-len target");
719 ATF_TC_FSAPPLY(attrs, "check setting attributes works");
720 ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK");
721 ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494");
722
723 ATF_TP_ADD_TCS(tp)
724 {
725
726 ATF_TP_FSAPPLY(lookup_simple);
727 ATF_TP_FSAPPLY(lookup_complex);
728 ATF_TP_FSAPPLY(dir_simple);
729 ATF_TP_FSAPPLY(dir_notempty);
730 ATF_TP_FSAPPLY(rename_dir);
731 ATF_TP_FSAPPLY(rename_dotdot);
732 ATF_TP_FSAPPLY(rename_reg_nodir);
733 ATF_TP_FSAPPLY(create_nametoolong);
734 ATF_TP_FSAPPLY(create_exist);
735 ATF_TP_FSAPPLY(rename_nametoolong);
736 ATF_TP_FSAPPLY(symlink_zerolen);
737 ATF_TP_FSAPPLY(attrs);
738 ATF_TP_FSAPPLY(fcntl_lock);
739 ATF_TP_FSAPPLY(fcntl_getlock_pids);
740
741 return atf_no_error();
742 }
743