NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/44494: F_GETLCK doesn't see some locks



>Number:         44494
>Category:       kern
>Synopsis:       F_GETLCK doesn't see some locks
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Jan 31 00:40:00 +0000 2011
>Originator:     Alexander Nasonov
>Release:        NetBSD 5.99.44 amd64
>Organization:
home sweet home
>Environment:
NetBSD nebeda.localdomain 5.99.44 NetBSD 5.99.44 (GENERIC) #0: Tue Jan 25 
21:26:14 GMT 2011  
root%nebeda.localdomain@localhost:/home/alnsn/src/netbsd-current/src/sys/arch/amd64/compile/obj/GENERIC
 amd64

>Description:
When you start processes one by one and each process locks one byte at getpid() 
offset for writing in a shared file (on tmpfs in case it matters) and then some 
process walks through the file trying to enumerate all processes it misses 
some. Everything is fine when pids are increasing but if a pid of some process 
is lower than a pid of the preceding process, the lower pid will not be 
enumerated.
>How-To-Repeat:
I wrote a rump test:
                          
Index: t_vnops.c
===================================================================
RCS file: /cvsroot/src/tests/fs/vfs/t_vnops.c,v
retrieving revision 1.12
diff -u -u -r1.12 t_vnops.c
--- t_vnops.c   11 Jan 2011 14:03:38 -0000      1.12
+++ t_vnops.c   31 Jan 2011 00:21:33 -0000
@@ -33,6 +33,7 @@
 #include <fcntl.h>
 #include <libgen.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 #include <rump/rump_syscalls.h>
@@ -567,6 +568,99 @@
        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(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];
+
+       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();
+
+       for(i = 0; i < __arraycount(lwp); i++) {
+               if(i != 0)
+                       RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG));
+
+               lwp[i] = rump_pub_lwproc_curlwp();
+
+               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]));
+       }
+
+       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) {
+                               /* skip the 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);
+                       }
+               }
+       }
+
+       rump_pub_lwproc_switch(lwp[0]);
+       for(i = __arraycount(lwp); i > 0; i--) {
+               rump_pub_lwproc_switch(lwp[i-1]);
+               RL(rump_sys_close(fd[i-1]));
+       }
+
+       for(i = __arraycount(lwp); i > 1; i--) {
+               rump_pub_lwproc_switch(lwp[i-1]);
+               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 +673,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, "check fcntl F_GETLK");
 
 ATF_TP_ADD_TCS(tp)
 {
@@ -595,6 +690,7 @@
        ATF_TP_FSAPPLY(symlink_zerolen);
        ATF_TP_FSAPPLY(attrs);
        ATF_TP_FSAPPLY(fcntl_lock);
+       ATF_TP_FSAPPLY(fcntl_getlock);
 
        return atf_no_error();
 }
>Fix:



Home | Main Index | Thread Index | Old Index