Module Name: src Committed By: pooka Date: Mon Jan 31 10:01:26 UTC 2011
Modified Files: src/tests/fs/vfs: t_vnops.c Log Message: Add test case for F_GETLK pid-oddness from PR kern/44494. I found the test case a little difficult to understand (because of many indices), so I added a few more comments after I think I figured out what was going on. To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/tests/fs/vfs/t_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/fs/vfs/t_vnops.c diff -u src/tests/fs/vfs/t_vnops.c:1.12 src/tests/fs/vfs/t_vnops.c:1.13 --- src/tests/fs/vfs/t_vnops.c:1.12 Tue Jan 11 14:03:38 2011 +++ src/tests/fs/vfs/t_vnops.c Mon Jan 31 10:01:26 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: t_vnops.c,v 1.12 2011/01/11 14:03:38 kefren Exp $ */ +/* $NetBSD: t_vnops.c,v 1.13 2011/01/31 10:01:26 pooka Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -29,10 +29,12 @@ #include <sys/stat.h> #include <sys/statvfs.h> +#include <assert.h> #include <atf-c.h> #include <fcntl.h> #include <libgen.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <rump/rump_syscalls.h> @@ -567,6 +569,122 @@ FSTEST_EXIT(); } +static int +flock_compare(const void *p, const void *q) +{ + int a = ((const struct flock *)p)->l_start; + int b = ((const struct flock *)q)->l_start; + return a < b ? -1 : (a > b ? 1 : 0); +} + +static void +fcntl_getlock_pids(const atf_tc_t *tc, const char *mp) +{ + /* test non-overlaping ranges */ + struct flock expect[4]; + const struct flock lock[4] = { + { 0, 2, 0, F_WRLCK, SEEK_SET }, + { 2, 1, 0, F_WRLCK, SEEK_SET }, + { 7, 5, 0, F_WRLCK, SEEK_SET }, + { 4, 3, 0, F_WRLCK, SEEK_SET }, + }; + + int fd[4]; + struct lwp *lwp[4]; + pid_t prevpid = 0; + + unsigned int i, j; + const off_t sz = 8192; + int omode = 0755; + int oflags = O_RDWR | O_CREAT; + + memcpy(expect, lock, sizeof(lock)); + qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare); + + FSTEST_ENTER(); + + /* + * First, we create 4 processes and let each lock a range of the + * file. Note that the third and fourth processes lock in + * "reverse" order, i.e. the greater pid locks a range before + * the lesser pid. + */ + for(i = 0; i < __arraycount(lwp); i++) { + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + + lwp[i] = rump_pub_lwproc_curlwp(); + assert(rump_sys_getpid() > prevpid); + prevpid = rump_sys_getpid(); + + RL(fd[i] = rump_sys_open(TESTFILE, oflags, omode)); + oflags = O_RDWR; + omode = 0; + + RL(rump_sys_ftruncate(fd[i], sz)); + RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i])); + } + + atf_tc_expect_fail("PR kern/44494"); + /* + * In the context of each pid , do GETLK for a readlock from + * i = [0,__arraycount(locks)]. If we try to lock from the same + * start offset as the lock our current process holds, check + * that we fail on the offset of the next lock ("else if" branch). + * Otherwise, expect to get a lock for the current offset + * ("if" branch). The "else" branch is purely for the last + * process where we expect no blocking locks. + */ + for(i = 0; i < __arraycount(lwp); i++) { + rump_pub_lwproc_switch(lwp[i]); + + for(j = 0; j < __arraycount(lwp); j++) { + struct flock l; + l = expect[j]; + l.l_len = sz; + l.l_type = F_RDLCK; + + RL(rump_sys_fcntl(fd[i], F_GETLK, &l)); + + if(expect[j].l_start != lock[i].l_start) { + /* + * lock set by another process + */ + ATF_CHECK(l.l_type != F_UNLCK); + ATF_CHECK_EQ(l.l_start, expect[j].l_start); + ATF_CHECK_EQ(l.l_len, expect[j].l_len); + } else if (j != __arraycount(lwp) - 1) { + /* + * lock set by the current process + */ + ATF_CHECK(l.l_type != F_UNLCK); + ATF_CHECK_EQ(l.l_start, expect[j+1].l_start); + ATF_CHECK_EQ(l.l_len, expect[j+1].l_len); + } else { + /* + * there are no other locks after the + * current process lock + */ + ATF_CHECK_EQ(l.l_type, F_UNLCK); + ATF_CHECK_EQ(l.l_start, expect[j].l_start); + ATF_CHECK_EQ(l.l_len, sz); + ATF_CHECK_EQ(l.l_pid, expect[j].l_pid); + ATF_CHECK_EQ(l.l_whence, expect[j].l_whence); + } + } + } + + /* + * Release processes. This also releases the fds and locks + * making fs unmount possible + */ + for(i = 0; i < __arraycount(lwp); i++) { + rump_pub_lwproc_switch(lwp[i]); + rump_pub_lwproc_releaselwp(); + } + + FSTEST_EXIT(); +} + ATF_TC_FSAPPLY(lookup_simple, "simple lookup (./.. on root)"); ATF_TC_FSAPPLY(lookup_complex, "lookup of non-dot entries"); ATF_TC_FSAPPLY(dir_simple, "mkdir/rmdir"); @@ -579,6 +697,7 @@ ATF_TC_FSAPPLY(symlink_zerolen, "symlink with 0-len target"); ATF_TC_FSAPPLY(attrs, "check setting attributes works"); ATF_TC_FSAPPLY(fcntl_lock, "check fcntl F_SETLK"); +ATF_TC_FSAPPLY(fcntl_getlock_pids,"fcntl F_GETLK w/ many procs, PR kern/44494"); ATF_TP_ADD_TCS(tp) { @@ -595,6 +714,7 @@ ATF_TP_FSAPPLY(symlink_zerolen); ATF_TP_FSAPPLY(attrs); ATF_TP_FSAPPLY(fcntl_lock); + ATF_TP_FSAPPLY(fcntl_getlock_pids); return atf_no_error(); }