kern/116679: lockd replies with DENIED for blocking lock if held by underlying FS

Zach Loafman zachary.loafman at isilon.com
Wed Sep 26 15:20:02 PDT 2007


>Number:         116679
>Category:       kern
>Synopsis:       lockd replies with DENIED for blocking lock if held by underlying FS
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 26 22:20:02 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Zach Loafman
>Release:        6.1-RELEASE
>Organization:
Isilon Systems
>Environment:
FreeBSD you.dont.care 6.1-RELEASE FreeBSD 6.1-RELEASE #0: Sun May  7 04:32:43 UTC 2006     root at opus.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
If lockd gets a request to an NLM request to lock a file but the non-blocking lockf() call on the exported file system fails, lockd will reply with NLM4_DENIED. In this situation, lockd needs to return NLM4_BLOCKED and actually set up some sort of structure to deal with it (however, there exists no way for the FS to notify lockd that the lock could be acquired).

The result of this is that an NFS client may try for a blocking lock, but still get EAGAIN ("Resource temporarily unavailable"), which is counter-intuitive. 
>How-To-Repeat:
# cat > locker_two_path.c <<EOF
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

static void
do_lock(int fd, int exclusive, int waitok)
{
	int rc;
	time_t start_time;
	struct flock flock;

	start_time = time(0);

	flock.l_start = 0;
	flock.l_len = 0;
	flock.l_type = exclusive ? F_WRLCK : F_RDLCK;
	flock.l_whence = SEEK_SET;
	rc = fcntl(fd, waitok ? F_SETLKW : F_SETLK,
	    &flock);
	if (rc < 0) {
		perror("fcntl lock");
		exit(1);
	}

	printf("%d: waited %d seconds for lock\n",
	    getpid(), time(0) - start_time);
}

int
main(int argc, char *argv[])
{
	int local_fd, nfs_fd;

	if (argc != 3) {
		printf("usage: %s <local path> <nfs path>", argv[0]);
		exit(1);
	}

	local_fd = open(argv[1], O_RDWR|O_CREAT, 0666);
	if (local_fd < 0) {
		perror("open");
		exit(1);
	}

	nfs_fd = open(argv[2], O_RDWR|O_CREAT, 0666);
	if (nfs_fd < 0) {
		perror("open");
		exit(1);
	}

	do_lock(local_fd, 1, 1);
	do_lock(nfs_fd, 1, 1);
	
	return 0;
}
EOF

# cc -Wall -o locker_two_path locker_two_path.c
# mount -otcp,intr localhost:/local /mnt/test
# ./locker_two_path /local/foobar /mnt/test/foobar
99086: waited 0 seconds for lock
fcntl lock: Resource temporarily unavailable

>Fix:
Serious work.

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list