xref: /netbsd-src/tests/fs/vfs/t_vnops.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: t_vnops.c,v 1.33 2012/03/20 18:20:49 njoly 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))				\
50 	atf_tc_skip("directories not supported by file system")
51 
52 #define USES_SYMLINKS					\
53     if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))		\
54 	atf_tc_skip("symlinks not supported by file system")
55 
56 static char *
57 md(char *buf, const char *base, const char *tail)
58 {
59 
60 	sprintf(buf, "%s/%s", base, tail);
61 	return buf;
62 }
63 
64 static void
65 lookup_simple(const atf_tc_t *tc, const char *mountpath)
66 {
67 	char pb[MAXPATHLEN], final[MAXPATHLEN];
68 	struct stat sb1, sb2;
69 
70 	strcpy(final, mountpath);
71 	sprintf(pb, "%s/../%s", mountpath, basename(final));
72 	if (rump_sys_stat(pb, &sb1) == -1)
73 		atf_tc_fail_errno("stat 1");
74 
75 	sprintf(pb, "%s/./../%s", mountpath, basename(final));
76 	if (rump_sys_stat(pb, &sb2) == -1)
77 		atf_tc_fail_errno("stat 2");
78 
79 	ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
80 }
81 
82 static void
83 lookup_complex(const atf_tc_t *tc, const char *mountpath)
84 {
85 	char pb[MAXPATHLEN];
86 	struct stat sb1, sb2;
87 
88 	USES_DIRS;
89 
90 	sprintf(pb, "%s/dir", mountpath);
91 	if (rump_sys_mkdir(pb, 0777) == -1)
92 		atf_tc_fail_errno("mkdir");
93 	if (rump_sys_stat(pb, &sb1) == -1)
94 		atf_tc_fail_errno("stat 1");
95 
96 	sprintf(pb, "%s/./dir/../././dir/.", mountpath);
97 	if (rump_sys_stat(pb, &sb2) == -1)
98 		atf_tc_fail_errno("stat 2");
99 
100 	ATF_REQUIRE(memcmp(&sb1, &sb2, sizeof(sb1)) == 0);
101 }
102 
103 static void
104 dir_simple(const atf_tc_t *tc, const char *mountpath)
105 {
106 	char pb[MAXPATHLEN];
107 	struct stat sb;
108 
109 	USES_DIRS;
110 
111 	/* check we can create directories */
112 	sprintf(pb, "%s/dir", mountpath);
113 	if (rump_sys_mkdir(pb, 0777) == -1)
114 		atf_tc_fail_errno("mkdir");
115 	if (rump_sys_stat(pb, &sb) == -1)
116 		atf_tc_fail_errno("stat new directory");
117 
118 	/* check we can remove then and that it makes them unreachable */
119 	if (rump_sys_rmdir(pb) == -1)
120 		atf_tc_fail_errno("rmdir");
121 	if (rump_sys_stat(pb, &sb) != -1 || errno != ENOENT)
122 		atf_tc_fail("ENOENT expected from stat");
123 }
124 
125 static void
126 dir_notempty(const atf_tc_t *tc, const char *mountpath)
127 {
128 	char pb[MAXPATHLEN], pb2[MAXPATHLEN];
129 	int fd, rv;
130 
131 	USES_DIRS;
132 
133 	/* check we can create directories */
134 	sprintf(pb, "%s/dir", mountpath);
135 	if (rump_sys_mkdir(pb, 0777) == -1)
136 		atf_tc_fail_errno("mkdir");
137 
138 	sprintf(pb2, "%s/dir/file", mountpath);
139 	fd = rump_sys_open(pb2, O_RDWR | O_CREAT, 0777);
140 	if (fd == -1)
141 		atf_tc_fail_errno("create file");
142 	rump_sys_close(fd);
143 
144 	rv = rump_sys_rmdir(pb);
145 	if (rv != -1 || errno != ENOTEMPTY)
146 		atf_tc_fail("non-empty directory removed succesfully");
147 
148 	if (rump_sys_unlink(pb2) == -1)
149 		atf_tc_fail_errno("cannot remove dir/file");
150 
151 	if (rump_sys_rmdir(pb) == -1)
152 		atf_tc_fail_errno("remove directory");
153 }
154 
155 static void
156 dir_rmdirdotdot(const atf_tc_t *tc, const char *mp)
157 {
158 	char pb[MAXPATHLEN];
159 	int xerrno;
160 
161 	USES_DIRS;
162 
163 	FSTEST_ENTER();
164 	RL(rump_sys_mkdir("test", 0777));
165 	RL(rump_sys_chdir("test"));
166 
167 	RL(rump_sys_mkdir("subtest", 0777));
168 	RL(rump_sys_chdir("subtest"));
169 
170 	md(pb, mp, "test/subtest");
171 	RL(rump_sys_rmdir(pb));
172 	md(pb, mp, "test");
173 	RL(rump_sys_rmdir(pb));
174 
175 	if (FSTYPE_NFS(tc))
176 		xerrno = ESTALE;
177 	else
178 		xerrno = ENOENT;
179 	ATF_REQUIRE_ERRNO(xerrno, rump_sys_chdir("..") == -1);
180 	FSTEST_EXIT();
181 }
182 
183 static void
184 checkfile(const char *path, struct stat *refp)
185 {
186 	char buf[MAXPATHLEN];
187 	struct stat sb;
188 	static int n = 1;
189 
190 	md(buf, path, "file");
191 	if (rump_sys_stat(buf, &sb) == -1)
192 		atf_tc_fail_errno("cannot stat file %d (%s)", n, buf);
193 	if (memcmp(&sb, refp, sizeof(sb)) != 0)
194 		atf_tc_fail("stat mismatch %d", n);
195 	n++;
196 }
197 
198 static void
199 rename_dir(const atf_tc_t *tc, const char *mp)
200 {
201 	char pb1[MAXPATHLEN], pb2[MAXPATHLEN], pb3[MAXPATHLEN];
202 	struct stat ref, sb;
203 
204 	if (FSTYPE_RUMPFS(tc))
205 		atf_tc_skip("rename not supported by file system");
206 
207 	USES_DIRS;
208 
209 	md(pb1, mp, "dir1");
210 	if (rump_sys_mkdir(pb1, 0777) == -1)
211 		atf_tc_fail_errno("mkdir 1");
212 
213 	md(pb2, mp, "dir2");
214 	if (rump_sys_mkdir(pb2, 0777) == -1)
215 		atf_tc_fail_errno("mkdir 2");
216 	md(pb2, mp, "dir2/subdir");
217 	if (rump_sys_mkdir(pb2, 0777) == -1)
218 		atf_tc_fail_errno("mkdir 3");
219 
220 	md(pb3, mp, "dir1/file");
221 	if (rump_sys_mknod(pb3, S_IFREG | 0777, -1) == -1)
222 		atf_tc_fail_errno("create file");
223 	if (rump_sys_stat(pb3, &ref) == -1)
224 		atf_tc_fail_errno("stat of file");
225 
226 	/*
227 	 * First try ops which should succeed.
228 	 */
229 
230 	/* rename within directory */
231 	md(pb3, mp, "dir3");
232 	if (rump_sys_rename(pb1, pb3) == -1)
233 		atf_tc_fail_errno("rename 1");
234 	checkfile(pb3, &ref);
235 
236 	/* rename directory onto itself (two ways, should fail) */
237 	md(pb1, mp, "dir3/.");
238 	if (rump_sys_rename(pb1, pb3) != -1 || errno != EINVAL)
239 		atf_tc_fail_errno("rename 2");
240 	if (rump_sys_rename(pb3, pb1) != -1 || errno != EISDIR)
241 		atf_tc_fail_errno("rename 3");
242 
243 	checkfile(pb3, &ref);
244 
245 	/* rename father of directory into directory */
246 	md(pb1, mp, "dir2/dir");
247 	md(pb2, mp, "dir2");
248 	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
249 		atf_tc_fail_errno("rename 4");
250 
251 	/* same for grandfather */
252 	md(pb1, mp, "dir2/subdir/dir2");
253 	if (rump_sys_rename(pb2, pb1) != -1 || errno != EINVAL)
254 		atf_tc_fail("rename 5");
255 
256 	checkfile(pb3, &ref);
257 
258 	/* rename directory over a non-empty directory */
259 	if (rump_sys_rename(pb2, pb3) != -1 || errno != ENOTEMPTY)
260 		atf_tc_fail("rename 6");
261 
262 	/* cross-directory rename */
263 	md(pb1, mp, "dir3");
264 	md(pb2, mp, "dir2/somedir");
265 	if (rump_sys_rename(pb1, pb2) == -1)
266 		atf_tc_fail_errno("rename 7");
267 	checkfile(pb2, &ref);
268 
269 	/* move to parent directory */
270 	md(pb1, mp, "dir2/somedir/../../dir3");
271 	if (rump_sys_rename(pb2, pb1) == -1)
272 		atf_tc_fail_errno("rename 8");
273 	md(pb1, mp, "dir2/../dir3");
274 	checkfile(pb1, &ref);
275 
276 	/* atomic cross-directory rename */
277 	md(pb3, mp, "dir2/subdir");
278 	if (rump_sys_rename(pb1, pb3) == -1)
279 		atf_tc_fail_errno("rename 9");
280 	checkfile(pb3, &ref);
281 
282 	/* rename directory over an empty directory */
283 	md(pb1, mp, "parent");
284 	md(pb2, mp, "parent/dir1");
285 	md(pb3, mp, "parent/dir2");
286 	RL(rump_sys_mkdir(pb1, 0777));
287 	RL(rump_sys_mkdir(pb2, 0777));
288 	RL(rump_sys_mkdir(pb3, 0777));
289 	RL(rump_sys_rename(pb2, pb3));
290 
291 	RL(rump_sys_stat(pb1, &sb));
292 	if (! FSTYPE_MSDOS(tc))
293 		ATF_CHECK_EQ(sb.st_nlink, 3);
294 	RL(rump_sys_rmdir(pb3));
295 	RL(rump_sys_rmdir(pb1));
296 }
297 
298 static void
299 rename_dotdot(const atf_tc_t *tc, const char *mp)
300 {
301 
302 	if (FSTYPE_RUMPFS(tc))
303 		atf_tc_skip("rename not supported by file system");
304 
305 	USES_DIRS;
306 
307 	if (rump_sys_chdir(mp) == -1)
308 		atf_tc_fail_errno("chdir mountpoint");
309 
310 	if (rump_sys_mkdir("dir1", 0777) == -1)
311 		atf_tc_fail_errno("mkdir 1");
312 	if (rump_sys_mkdir("dir2", 0777) == -1)
313 		atf_tc_fail_errno("mkdir 2");
314 
315 	if (rump_sys_rename("dir1", "dir1/..") != -1 || errno != EINVAL)
316 		atf_tc_fail_errno("self-dotdot to");
317 
318 	if (rump_sys_rename("dir1/..", "sometarget") != -1 || errno != EINVAL)
319 		atf_tc_fail_errno("self-dotdot from");
320 
321 	if (rump_sys_rename("dir1", "dir2/..") != -1 || errno != EINVAL)
322 		atf_tc_fail("other-dotdot");
323 
324 	rump_sys_chdir("/");
325 }
326 
327 static void
328 rename_reg_nodir(const atf_tc_t *tc, const char *mp)
329 {
330 	bool haslinks;
331 	struct stat sb;
332 	ino_t f1ino, f2ino;
333 
334 	if (FSTYPE_RUMPFS(tc))
335 		atf_tc_skip("rename not supported by file system");
336 
337 	if (rump_sys_chdir(mp) == -1)
338 		atf_tc_fail_errno("chdir mountpoint");
339 
340 	if (FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))
341 		haslinks = false;
342 	else
343 		haslinks = true;
344 
345 	if (rump_sys_mknod("file1", S_IFREG | 0777, -1) == -1)
346 		atf_tc_fail_errno("create file");
347 	if (rump_sys_mknod("file2", S_IFREG | 0777, -1) == -1)
348 		atf_tc_fail_errno("create file");
349 
350 	if (rump_sys_stat("file1", &sb) == -1)
351 		atf_tc_fail_errno("stat");
352 	f1ino = sb.st_ino;
353 
354 	if (haslinks) {
355 		if (rump_sys_link("file1", "file_link") == -1)
356 			atf_tc_fail_errno("link");
357 		if (rump_sys_stat("file_link", &sb) == -1)
358 			atf_tc_fail_errno("stat");
359 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
360 		ATF_REQUIRE_EQ(sb.st_nlink, 2);
361 	}
362 
363 	if (rump_sys_stat("file2", &sb) == -1)
364 		atf_tc_fail_errno("stat");
365 	f2ino = sb.st_ino;
366 
367 	if (rump_sys_rename("file1", "file3") == -1)
368 		atf_tc_fail_errno("rename 1");
369 	if (rump_sys_stat("file3", &sb) == -1)
370 		atf_tc_fail_errno("stat 1");
371 	if (haslinks) {
372 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
373 	}
374 	if (rump_sys_stat("file1", &sb) != -1 || errno != ENOENT)
375 		atf_tc_fail_errno("source 1");
376 
377 	if (rump_sys_rename("file3", "file2") == -1)
378 		atf_tc_fail_errno("rename 2");
379 	if (rump_sys_stat("file2", &sb) == -1)
380 		atf_tc_fail_errno("stat 2");
381 	if (haslinks) {
382 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
383 	}
384 
385 	if (rump_sys_stat("file3", &sb) != -1 || errno != ENOENT)
386 		atf_tc_fail_errno("source 2");
387 
388 	if (haslinks) {
389 		if (rump_sys_rename("file2", "file_link") == -1)
390 			atf_tc_fail_errno("rename hardlink");
391 		if (rump_sys_stat("file2", &sb) != -1 || errno != ENOENT)
392 			atf_tc_fail_errno("source 3");
393 		if (rump_sys_stat("file_link", &sb) == -1)
394 			atf_tc_fail_errno("stat 2");
395 		ATF_REQUIRE_EQ(sb.st_ino, f1ino);
396 		ATF_REQUIRE_EQ(sb.st_nlink, 1);
397 	}
398 
399 	rump_sys_chdir("/");
400 }
401 
402 static void
403 create_nametoolong(const atf_tc_t *tc, const char *mp)
404 {
405 	char *name;
406 	int fd;
407 	long val;
408 	size_t len;
409 
410 	if (rump_sys_chdir(mp) == -1)
411 		atf_tc_fail_errno("chdir mountpoint");
412 
413 	val = rump_sys_pathconf(".", _PC_NAME_MAX);
414 	if (val == -1)
415 		atf_tc_fail_errno("pathconf");
416 
417 	len = val + 1;
418 	name = malloc(len+1);
419 	if (name == NULL)
420 		atf_tc_fail_errno("malloc");
421 
422 	memset(name, 'a', len);
423 	*(name+len) = '\0';
424 
425 	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
426 	if (val == -1)
427 		atf_tc_fail_errno("pathconf");
428 
429 	fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666);
430 	if (val != 0 && (fd != -1 || errno != ENAMETOOLONG))
431 		atf_tc_fail_errno("open");
432 
433 	if (val == 0 && rump_sys_close(fd) == -1)
434 		atf_tc_fail_errno("close");
435 	if (val == 0 && rump_sys_unlink(name) == -1)
436 		atf_tc_fail_errno("unlink");
437 
438 	free(name);
439 
440 	rump_sys_chdir("/");
441 }
442 
443 static void
444 create_exist(const atf_tc_t *tc, const char *mp)
445 {
446 	const char *name = "hoge";
447 	int fd;
448 
449 	RL(rump_sys_chdir(mp));
450 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666));
451 	RL(rump_sys_close(fd));
452 	RL(rump_sys_unlink(name));
453 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
454 	RL(rump_sys_close(fd));
455 	RL(fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666));
456 	RL(rump_sys_close(fd));
457 	ATF_REQUIRE_ERRNO(EEXIST,
458 	    (fd = rump_sys_open(name, O_RDWR|O_CREAT|O_EXCL, 0666)));
459 	RL(rump_sys_unlink(name));
460 	RL(rump_sys_chdir("/"));
461 }
462 
463 static void
464 rename_nametoolong(const atf_tc_t *tc, const char *mp)
465 {
466 	char *name;
467 	int res, fd;
468 	long val;
469 	size_t len;
470 
471 	if (FSTYPE_RUMPFS(tc))
472 		atf_tc_skip("rename not supported by file system");
473 
474 	if (rump_sys_chdir(mp) == -1)
475 		atf_tc_fail_errno("chdir mountpoint");
476 
477 	val = rump_sys_pathconf(".", _PC_NAME_MAX);
478 	if (val == -1)
479 		atf_tc_fail_errno("pathconf");
480 
481 	len = val + 1;
482 	name = malloc(len+1);
483 	if (name == NULL)
484 		atf_tc_fail_errno("malloc");
485 
486 	memset(name, 'a', len);
487 	*(name+len) = '\0';
488 
489 	fd = rump_sys_open("dummy", O_RDWR|O_CREAT, 0666);
490 	if (fd == -1)
491 		atf_tc_fail_errno("open");
492 	if (rump_sys_close(fd) == -1)
493 		atf_tc_fail_errno("close");
494 
495 	val = rump_sys_pathconf(".", _PC_NO_TRUNC);
496 	if (val == -1)
497 		atf_tc_fail_errno("pathconf");
498 
499 	res = rump_sys_rename("dummy", name);
500 	if (val != 0 && (res != -1 || errno != ENAMETOOLONG))
501 		atf_tc_fail_errno("rename");
502 
503 	if (val == 0 && rump_sys_unlink(name) == -1)
504 		atf_tc_fail_errno("unlink");
505 
506 	free(name);
507 
508 	rump_sys_chdir("/");
509 }
510 
511 static void
512 symlink_zerolen(const atf_tc_t *tc, const char *mp)
513 {
514 
515 	USES_SYMLINKS;
516 
517 	RL(rump_sys_chdir(mp));
518 
519 	RL(rump_sys_symlink("", "afile"));
520 	RL(rump_sys_chdir("/"));
521 }
522 
523 static void
524 symlink_root(const atf_tc_t *tc, const char *mp)
525 {
526 
527 	USES_SYMLINKS;
528 
529 	RL(rump_sys_chdir(mp));
530 	RL(rump_sys_symlink("/", "foo"));
531 	RL(rump_sys_chdir("foo"));
532 }
533 
534 static void
535 attrs(const atf_tc_t *tc, const char *mp)
536 {
537 	struct stat sb, sb2;
538 	struct timeval tv[2];
539 	int fd;
540 
541 	FSTEST_ENTER();
542 	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
543 	RL(rump_sys_close(fd));
544 	RL(rump_sys_stat(TESTFILE, &sb));
545 	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
546 		RL(rump_sys_chown(TESTFILE, 1, 2));
547 		sb.st_uid = 1;
548 		sb.st_gid = 2;
549 		RL(rump_sys_chmod(TESTFILE, 0123));
550 		sb.st_mode = (sb.st_mode & ~ACCESSPERMS) | 0123;
551 	}
552 
553 	tv[0].tv_sec = 1000000000; /* need something >1980 for msdosfs */
554 	tv[0].tv_usec = 1;
555 	tv[1].tv_sec = 1000000002; /* need even seconds for msdosfs */
556 	tv[1].tv_usec = 3;
557 	RL(rump_sys_utimes(TESTFILE, tv));
558 	RL(rump_sys_utimes(TESTFILE, tv)); /* XXX: utimes & birthtime */
559 	sb.st_atimespec.tv_sec = 1000000000;
560 	sb.st_atimespec.tv_nsec = 1000;
561 	sb.st_mtimespec.tv_sec = 1000000002;
562 	sb.st_mtimespec.tv_nsec = 3000;
563 
564 	RL(rump_sys_stat(TESTFILE, &sb2));
565 #define CHECK(a) ATF_REQUIRE_EQ(sb.a, sb2.a)
566 	if (!(FSTYPE_MSDOS(tc) || FSTYPE_SYSVBFS(tc))) {
567 		CHECK(st_uid);
568 		CHECK(st_gid);
569 		CHECK(st_mode);
570 	}
571 	if (!FSTYPE_MSDOS(tc)) {
572 		/* msdosfs has only access date, not time */
573 		CHECK(st_atimespec.tv_sec);
574 	}
575 	CHECK(st_mtimespec.tv_sec);
576 	if (!(FSTYPE_EXT2FS(tc) || FSTYPE_MSDOS(tc) ||
577 	      FSTYPE_SYSVBFS(tc) || FSTYPE_V7FS(tc))) {
578 		CHECK(st_atimespec.tv_nsec);
579 		CHECK(st_mtimespec.tv_nsec);
580 	}
581 #undef  CHECK
582 
583 	FSTEST_EXIT();
584 }
585 
586 static void
587 fcntl_lock(const atf_tc_t *tc, const char *mp)
588 {
589 	int fd, fd2;
590 	struct flock l;
591 	struct lwp *lwp1, *lwp2;
592 
593 	FSTEST_ENTER();
594 	l.l_pid = 0;
595 	l.l_start = l.l_len = 1024;
596 	l.l_type = F_RDLCK | F_WRLCK;
597 	l.l_whence = SEEK_END;
598 
599 	lwp1 = rump_pub_lwproc_curlwp();
600 	RL(fd = rump_sys_open(TESTFILE, O_RDWR | O_CREAT, 0755));
601 	RL(rump_sys_ftruncate(fd, 8192));
602 
603 	/* PR kern/43321 */
604 	RL(rump_sys_fcntl(fd, F_SETLK, &l));
605 
606 	/* Next, we fork and try to lock the same area */
607 	RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
608 	lwp2 = rump_pub_lwproc_curlwp();
609 	RL(fd2 = rump_sys_open(TESTFILE, O_RDWR, 0));
610 	ATF_REQUIRE_ERRNO(EAGAIN, rump_sys_fcntl(fd2, F_SETLK, &l));
611 
612 	/* Switch back and unlock... */
613 	rump_pub_lwproc_switch(lwp1);
614 	l.l_type = F_UNLCK;
615 	RL(rump_sys_fcntl(fd, F_SETLK, &l));
616 
617 	/* ... and try to lock again */
618 	rump_pub_lwproc_switch(lwp2);
619 	l.l_type = F_RDLCK | F_WRLCK;
620 	RL(rump_sys_fcntl(fd2, F_SETLK, &l));
621 
622 	RL(rump_sys_close(fd2));
623 	rump_pub_lwproc_releaselwp();
624 
625 	RL(rump_sys_close(fd));
626 
627 	FSTEST_EXIT();
628 }
629 
630 static int
631 flock_compare(const void *p, const void *q)
632 {
633 	int a = ((const struct flock *)p)->l_start;
634 	int b = ((const struct flock *)q)->l_start;
635 	return a < b ? -1 : (a > b ? 1 : 0);
636 }
637 
638 /*
639  * Find all locks set by fcntl_getlock_pids test
640  * using GETLK for a range [start, start+end], and,
641  * if there is a blocking lock, recursively find
642  * all locks to the left (toward the beginning of
643  * a file) and to the right of the lock.
644  * The function also understands "until end of file"
645  * convention when len==0.
646  */
647 static unsigned int
648 fcntl_getlocks(int fildes, off_t start, off_t len,
649     struct flock *lock, struct flock *end)
650 {
651 	unsigned int rv = 0;
652 	const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET };
653 
654 	if (lock == end)
655 		return rv;
656 
657 	RL(rump_sys_fcntl(fildes, F_GETLK, &l));
658 
659 	if (l.l_type == F_UNLCK)
660 		return rv;
661 
662 	*lock++ = l;
663 	rv += 1;
664 
665 	ATF_REQUIRE(l.l_whence == SEEK_SET);
666 
667 	if (l.l_start > start) {
668 		unsigned int n =
669 		    fcntl_getlocks(fildes, start, l.l_start - start, lock, end);
670 		rv += n;
671 		lock += n;
672 		if (lock == end)
673 			return rv;
674 	}
675 
676 	if (l.l_len == 0) /* does l spans until the end? */
677 		return rv;
678 
679 	if (len == 0) /* are we looking for locks until the end? */ {
680 		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
681 	} else if (l.l_start + l.l_len < start + len) {
682 		len -= l.l_start + l.l_len - start;
683 		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
684 	}
685 
686 	return rv;
687 }
688 
689 static void
690 fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
691 {
692 	/* test non-overlaping ranges */
693 	struct flock expect[4];
694 	const struct flock lock[4] = {
695 		{ 0, 2, 0, F_WRLCK, SEEK_SET },
696 		{ 2, 1, 0, F_WRLCK, SEEK_SET },
697 		{ 7, 5, 0, F_WRLCK, SEEK_SET },
698 		{ 4, 3, 0, F_WRLCK, SEEK_SET },
699 	};
700 
701     /* Add extra element to make sure recursion does't stop at array end */
702 	struct flock result[5];
703 
704 	/* Add 5th process */
705 	int fd[5];
706 	pid_t pid[5];
707 	struct lwp *lwp[5];
708 
709 	unsigned int i, j;
710 	const off_t sz = 8192;
711 	int omode  = 0755;
712 	int oflags = O_RDWR | O_CREAT;
713 
714 	memcpy(expect, lock, sizeof(lock));
715 
716 	FSTEST_ENTER();
717 
718 	/*
719 	 * First, we create 4 processes and let each lock a range of the
720 	 * file.  Note that the third and fourth processes lock in
721 	 * "reverse" order, i.e. the greater pid locks a range before
722 	 * the lesser pid.
723 	 * Then, we create 5th process which doesn't lock anything.
724 	 */
725 	for (i = 0; i < __arraycount(lwp); i++) {
726 		RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
727 
728 		lwp[i] = rump_pub_lwproc_curlwp();
729 		pid[i] = rump_sys_getpid();
730 
731 		RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode));
732 		oflags = O_RDWR;
733 		omode  = 0;
734 
735 		RL(rump_sys_ftruncate(fd[i], sz));
736 
737 		if (i < __arraycount(lock)) {
738 			RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
739 			expect[i].l_pid = pid[i];
740 		}
741 	}
742 
743 	qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
744 
745 	/*
746 	 * In the context of each process, recursively find all locks
747 	 * that would block the current process. Processes 1-4 don't
748 	 * see their own lock, we insert it to simplify checks.
749 	 * Process 5 sees all 4 locks.
750 	 */
751 	for (i = 0; i < __arraycount(lwp); i++) {
752 		unsigned int nlocks;
753 
754 		rump_pub_lwproc_switch(lwp[i]);
755 
756 		memset(result, 0, sizeof(result));
757 		nlocks = fcntl_getlocks(fd[i], 0, sz,
758 		    result, result + __arraycount(result));
759 
760 		if (i < __arraycount(lock)) {
761 			ATF_REQUIRE(nlocks < __arraycount(result));
762 			result[nlocks] = lock[i];
763 			result[nlocks].l_pid = pid[i];
764 			nlocks++;
765 		}
766 
767 		ATF_CHECK_EQ(nlocks, __arraycount(expect));
768 
769 		qsort(result, nlocks, sizeof(result[0]), &flock_compare);
770 
771 		for (j = 0; j < nlocks; j++) {
772 			ATF_CHECK_EQ(result[j].l_start,  expect[j].l_start );
773 			ATF_CHECK_EQ(result[j].l_len,    expect[j].l_len   );
774 			ATF_CHECK_EQ(result[j].l_pid,    expect[j].l_pid   );
775 			ATF_CHECK_EQ(result[j].l_type,   expect[j].l_type  );
776 			ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence);
777 		}
778 	}
779 
780 	/*
781 	 * Release processes.  This also releases the fds and locks
782 	 * making fs unmount possible
783 	 */
784 	for (i = 0; i < __arraycount(lwp); i++) {
785 		rump_pub_lwproc_switch(lwp[i]);
786 		rump_pub_lwproc_releaselwp();
787 	}
788 
789 	FSTEST_EXIT();
790 }
791 
792 static void
793 access_simple(const atf_tc_t *tc, const char *mp)
794 {
795 	int fd;
796 	int tmode;
797 
798 	FSTEST_ENTER();
799 	RL(fd = rump_sys_open("tfile", O_CREAT | O_RDWR, 0777));
800 	RL(rump_sys_close(fd));
801 
802 #define ALLACC (F_OK | X_OK | W_OK | R_OK)
803 	if (FSTYPE_SYSVBFS(tc) || FSTYPE_MSDOS(tc))
804 		tmode = F_OK;
805 	else
806 		tmode = ALLACC;
807 
808 	RL(rump_sys_access("tfile", tmode));
809 
810 	/* PR kern/44648 */
811 	ATF_REQUIRE_ERRNO(EINVAL, rump_sys_access("tfile", ALLACC+1) == -1);
812 #undef ALLACC
813 	FSTEST_EXIT();
814 }
815 
816 static void
817 read_directory(const atf_tc_t *tc, const char *mp)
818 {
819 	char buf[1024];
820 	int fd, res;
821 	ssize_t size;
822 
823 	FSTEST_ENTER();
824 	fd = rump_sys_open(".", O_DIRECTORY | O_RDONLY, 0777);
825 	ATF_REQUIRE(fd != -1);
826 
827 	size = rump_sys_pread(fd, buf, sizeof(buf), 0);
828 	ATF_CHECK(size != -1 || errno == EISDIR);
829 	size = rump_sys_read(fd, buf, sizeof(buf));
830 	ATF_CHECK(size != -1 || errno == EISDIR);
831 
832 	res = rump_sys_close(fd);
833 	ATF_REQUIRE(res != -1);
834 	FSTEST_EXIT();
835 }
836 
837 ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)");
838 ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries");
839 ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir");
840 ATF_TC_FSAPPLY(dir_notempty, "non-empty directories cannot be removed");
841 ATF_TC_FSAPPLY(dir_rmdirdotdot, "remove .. and try to cd out (PR kern/44657)");
842 ATF_TC_FSAPPLY(rename_dir, "exercise various directory renaming ops "
843 "(PR kern/44288)");
844 ATF_TC_FSAPPLY(rename_dotdot, "rename dir .. (PR kern/43617)");
845 ATF_TC_FSAPPLY(rename_reg_nodir, "rename regular files, no subdirectories");
846 ATF_TC_FSAPPLY(create_nametoolong, "create file with name too long");
847 ATF_TC_FSAPPLY(create_exist, "create with O_EXCL");
848 ATF_TC_FSAPPLY(rename_nametoolong, "rename to file with name too long");
849 ATF_TC_FSAPPLY(symlink_zerolen, "symlink with 0-len target");
850 ATF_TC_FSAPPLY(symlink_root, "symlink to root directory");
851 ATF_TC_FSAPPLY(attrs, "check setting attributes works");
852 ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK");
853 ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494");
854 ATF_TC_FSAPPLY(access_simple, "access(2)");
855 ATF_TC_FSAPPLY(read_directory, "read(2) on directories");
856 
857 ATF_TP_ADD_TCS(tp)
858 {
859 
860 	ATF_TP_FSAPPLY(lookup_simple);
861 	ATF_TP_FSAPPLY(lookup_complex);
862 	ATF_TP_FSAPPLY(dir_simple);
863 	ATF_TP_FSAPPLY(dir_notempty);
864 	ATF_TP_FSAPPLY(dir_rmdirdotdot);
865 	ATF_TP_FSAPPLY(rename_dir);
866 	ATF_TP_FSAPPLY(rename_dotdot);
867 	ATF_TP_FSAPPLY(rename_reg_nodir);
868 	ATF_TP_FSAPPLY(create_nametoolong);
869 	ATF_TP_FSAPPLY(create_exist);
870 	ATF_TP_FSAPPLY(rename_nametoolong);
871 	ATF_TP_FSAPPLY(symlink_zerolen);
872 	ATF_TP_FSAPPLY(symlink_root);
873 	ATF_TP_FSAPPLY(attrs);
874 	ATF_TP_FSAPPLY(fcntl_lock);
875 	ATF_TP_FSAPPLY(fcntl_getlock_pids);
876 	ATF_TP_FSAPPLY(access_simple);
877 	ATF_TP_FSAPPLY(read_directory);
878 
879 	return atf_no_error();
880 }
881