features/locks: fcntl(3) on F_GETLK must return first conflicting lock

- Added test program, getlk_owner.c to capture the bug when regressed.

Change-Id: Ic2a0f6fa8d094c0f2e9f4a6febd278d4a2948223
BUG: 869724
Signed-off-by: Krishnan Parthasarathi <kparthas@redhat.com>
Reviewed-on: http://review.gluster.org/4164
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
Krishnan Parthasarathi 2012-11-07 12:55:08 +05:30 committed by Vijay Bellur
parent 0f87154a4b
commit cfe51eb7ff
3 changed files with 204 additions and 1 deletions

61
tests/bugs/bug-869724.t Normal file
View File

@ -0,0 +1,61 @@
#!/bin/bash
. $(dirname $0)/../include.rc
cleanup;
## Start and create a volume
TEST glusterd
TEST pidof glusterd
TEST $CLI volume create $V0 $H0:$B0/${V0}1;
function volinfo_field()
{
local vol=$1;
local field=$2;
$CLI volume info $vol | grep "^$field: " | sed 's/.*: //';
}
## Verify volume is is created
EXPECT "$V0" volinfo_field $V0 'Volume Name';
EXPECT 'Created' volinfo_field $V0 'Status';
## Start volume and verify
TEST $CLI volume start $V0;
EXPECT 'Started' volinfo_field $V0 'Status';
## Make volume tightly consistent for metdata
TEST $CLI volume set $V0 performance.stat-prefetch off;
## Mount FUSE with caching disabled
TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0;
function cleanup_tester ()
{
local exe=$1
rm -f $exe
}
function build_tester ()
{
local cfile=$1
local fname=$(basename "$cfile")
local ext="${fname##*.}"
local execname="${fname%.*}"
gcc -g -o $(dirname $cfile)/$execname $cfile
}
touch $M0/test;
build_tester $(dirname $0)/getlk_owner.c
TEST $(dirname $0)/getlk_owner $M0/test;
rm -f $(dirname $0)/getlk_owner
cleanup;

120
tests/bugs/getlk_owner.c Normal file
View File

@ -0,0 +1,120 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define GETLK_OWNER_CHECK(f, cp, label) \
do { \
switch (f.l_type) { \
case F_RDLCK: \
case F_WRLCK: \
ret = 1; \
goto label; \
case F_UNLCK: \
if (!are_flocks_sane (&f, &cp)) { \
ret = 1; \
goto label; \
} \
break; \
} \
} while (0)
void
flock_init (struct flock *f, short int type, off_t start, off_t len)
{
f->l_type = type;
f->l_start = start;
f->l_len = len;
}
int
flock_cp (struct flock *dst, struct flock *src)
{
memcpy ((void *) dst, (void *) src, sizeof (struct flock));
}
int
are_flocks_sane (struct flock *src, struct flock *cpy)
{
return ((src->l_whence == cpy->l_whence) &&
(src->l_start == cpy->l_start) &&
(src->l_len == cpy->l_len));
}
/*
* Test description:
* SETLK (0,3), F_WRLCK
* SETLK (3,3), F_WRLCK
*
* the following GETLK requests must return flock struct unmodified
* except for l_type to F_UNLCK
* GETLK (3,3), F_WRLCK
* GETLK (3,3), F_RDLCK
*
* */
int main (int argc, char **argv)
{
int fd = -1;
int ret = 1;
char *fname = NULL;
struct flock f = {0,};
struct flock cp = {0,};
if (argc < 2)
goto out;
fname = argv[1];
fd = open (fname, O_RDWR);
if (fd == -1) {
perror ("open");
goto out;
}
flock_init (&f, F_WRLCK, 0, 3);
flock_cp (&cp, &f);
ret = fcntl (fd, F_SETLK, &f);
if (ret) {
perror ("fcntl");
goto out;
}
if (!are_flocks_sane (&f, &cp)) {
ret = 1;
goto out;
}
flock_init (&f, F_WRLCK, 3, 3);
flock_cp (&cp, &f);
ret = fcntl (fd, F_SETLK, &f);
if (ret) {
perror ("fcntl");
goto out;
}
if (!are_flocks_sane (&f, &cp)) {
ret = 1;
goto out;
}
flock_init (&f, F_WRLCK, 3, 3);
flock_cp (&cp, &f);
ret = fcntl (fd, F_GETLK, &f);
if (ret) {
perror ("fcntl");
return 1;
}
GETLK_OWNER_CHECK (f, cp, out);
flock_init (&f, F_RDLCK, 3, 3);
flock_cp (&cp, &f);
ret = fcntl (fd, F_GETLK, &f);
if (ret) {
perror ("fcntl");
return 1;
}
GETLK_OWNER_CHECK (f, cp, out);
out:
if (fd != -1)
close (fd);
return ret;
}

View File

@ -714,6 +714,28 @@ done:
return v;
}
static posix_lock_t *
first_conflicting_overlap (pl_inode_t *pl_inode, posix_lock_t *lock)
{
posix_lock_t *l = NULL;
list_for_each_entry (l, &pl_inode->ext_list, list) {
if (l->blocked)
continue;
if (locks_overlap (l, lock)) {
if (same_owner (l, lock))
continue;
if ((l->fl_type == F_WRLCK) ||
(lock->fl_type == F_WRLCK))
return l;
}
}
return NULL;
}
/*
Start searching from {begin}, and return the first lock that
conflicts, NULL if no conflict
@ -1058,7 +1080,7 @@ pl_getlk (pl_inode_t *pl_inode, posix_lock_t *lock)
{
posix_lock_t *conf = NULL;
conf = first_overlap (pl_inode, lock);
conf = first_conflicting_overlap (pl_inode, lock);
if (conf == NULL) {
lock->fl_type = F_UNLCK;