Module Name:    src
Committed By:   alnsn
Date:           Sat Jul 23 09:59:14 UTC 2011

Modified Files:
        src/tests/fs/vfs: t_vnops.c

Log Message:
Don't assume that "first lock that blocks" is a lock with the lowest
start offset and change the test to work when F_GETLK returns any
lock that blocks.


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 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.25 src/tests/fs/vfs/t_vnops.c:1.26
--- src/tests/fs/vfs/t_vnops.c:1.25	Wed Jul 20 11:52:00 2011
+++ src/tests/fs/vfs/t_vnops.c	Sat Jul 23 09:59:14 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_vnops.c,v 1.25 2011/07/20 11:52:00 hannken Exp $	*/
+/*	$NetBSD: t_vnops.c,v 1.26 2011/07/23 09:59:14 alnsn Exp $	*/
 
 /*-
  * Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -636,6 +636,57 @@
 	return a < b ? -1 : (a > b ? 1 : 0);
 }
 
+/*
+ * Find all locks set by fcntl_getlock_pids test
+ * using GETLK for a range [start, start+end], and,
+ * if there is a blocking lock, recursively find
+ * all locks to the left (toward the beginning of
+ * a file) and to the right of the lock.
+ * The function also understands "until end of file"
+ * convention when len==0.
+ */
+static unsigned int
+fcntl_getlocks(int fildes, off_t start, off_t len,
+    struct flock *lock, struct flock *end)
+{
+	unsigned int rv = 0;
+	const struct flock l = { start, len, 0, F_RDLCK, SEEK_SET };
+
+	if (lock == end)
+		return rv;
+
+	RL(rump_sys_fcntl(fildes, F_GETLK, &l));
+
+	if (l.l_type == F_UNLCK)
+		return rv;
+
+	*lock++ = l;
+	rv += 1;
+
+	ATF_REQUIRE(l.l_whence == SEEK_SET);
+
+	if (l.l_start > start) {
+		unsigned int n =
+		    fcntl_getlocks(fildes, start, l.l_start - start, lock, end);
+		rv += n;
+		lock += n;
+		if (lock == end)
+			return rv;
+	}
+
+	if (l.l_len == 0) /* does l spans until the end? */
+		return rv;
+
+	if (len == 0) /* are we looking for locks until the end? */ {
+		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
+	} else if (l.l_start + l.l_len < start + len) {
+		len -= l.l_start + l.l_len - start;
+		rv += fcntl_getlocks(fildes, l.l_start + l.l_len, len, lock, end);
+	}
+
+	return rv;
+}
+
 static void
 fcntl_getlock_pids(const atf_tc_t *tc, const char *mp)
 {
@@ -648,9 +699,13 @@
 		{ 4, 3, 0, F_WRLCK, SEEK_SET },
 	};
 
-	int fd[4];
-	struct lwp *lwp[4];
-	pid_t prevpid = 0;
+    /* Add extra element to make sure recursion does't stop at array end */
+	struct flock result[5];
+
+	/* Add 5th process */
+	int fd[5];
+	pid_t pid[5];
+	struct lwp *lwp[5];
 
 	unsigned int i, j;
 	const off_t sz = 8192;
@@ -658,7 +713,6 @@
 	int oflags = O_RDWR | O_CREAT;
 
 	memcpy(expect, lock, sizeof(lock));
-	qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
 
 	FSTEST_ENTER();
 
@@ -667,68 +721,60 @@
 	 * file.  Note that the third and fourth processes lock in
 	 * "reverse" order, i.e. the greater pid locks a range before
 	 * the lesser pid.
+	 * Then, we create 5th process which doesn't lock anything.
 	 */
-	for(i = 0; i < __arraycount(lwp); i++) {
+	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();
+		pid[i] = 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]));
+
+		if (i < __arraycount(lock)) {
+			RL(rump_sys_fcntl(fd[i], F_SETLK, &lock[i]));
+			expect[i].l_pid = pid[i];
+		}
 	}
 
-	atf_tc_expect_fail("PR kern/44494");
+	qsort(expect, __arraycount(expect), sizeof(expect[0]), &flock_compare);
+
 	/*
-	 * 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.
+	 * In the context of each process, recursively find all locks
+	 * that would block the current process. Processes 1-4 don't
+	 * see their own lock, we insert it to simplify checks.
+	 * Process 5 sees all 4 locks.
 	 */
-	for(i = 0; i < __arraycount(lwp); i++) {
+	for (i = 0; i < __arraycount(lwp); i++) {
+		unsigned int nlocks;
+
 		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);
-			}
+		memset(result, 0, sizeof(result));
+		nlocks = fcntl_getlocks(fd[i], 0, sz,
+		    result, result + __arraycount(result));
+
+		if (i < __arraycount(lock)) {
+			ATF_REQUIRE(nlocks < __arraycount(result));
+			result[nlocks] = lock[i];
+			result[nlocks].l_pid = pid[i];
+			nlocks++;
+		}
+
+		ATF_CHECK_EQ(nlocks, __arraycount(expect));
+
+		qsort(result, nlocks, sizeof(result[0]), &flock_compare);
+
+		for (j = 0; j < nlocks; j++) {
+			ATF_CHECK_EQ(result[j].l_start,  expect[j].l_start );
+			ATF_CHECK_EQ(result[j].l_len,    expect[j].l_len   );
+			ATF_CHECK_EQ(result[j].l_pid,    expect[j].l_pid   );
+			ATF_CHECK_EQ(result[j].l_type,   expect[j].l_type  );
+			ATF_CHECK_EQ(result[j].l_whence, expect[j].l_whence);
 		}
 	}
 
@@ -736,7 +782,7 @@
 	 * Release processes.  This also releases the fds and locks
 	 * making fs unmount possible
 	 */
-	for(i = 0; i < __arraycount(lwp); i++) {
+	for (i = 0; i < __arraycount(lwp); i++) {
 		rump_pub_lwproc_switch(lwp[i]);
 		rump_pub_lwproc_releaselwp();
 	}

Reply via email to