This patch addresses two problems. fs/locks.c: When a program locked the entire file, and then did an unlock of just the first byte in the file, the kernel would not modify the existing lock because of an overflow/signedness problem. fs/lockd/*.c: Consider the following scenario: client A locks a file client B requests a conflicting lock, and asks for "blocking" mode. lockd creates a "struct block" and attaches it to the existing lock client A unlocks the file This causes a call to nlmsvc_notify_blocked, which puts the blocked lock onto a list of locks which sould be retried, setting the b_when field to 0. The next time lockd comes around to inspecting this list, it should notice that the lock can now be granted, and send a NLM_GRANTED message to client B. However, due to a signedness problem, the lock is appended to the *end* of the list, where it's never picked up. Olaf Kirch -okir@suse.de --- linux/fs/lockd/svclock.c.locks Mon Jun 17 13:32:21 2002 +++ linux/fs/lockd/svclock.c Mon Jun 17 13:37:36 2002 @@ -62,8 +62,8 @@ nlmsvc_remove_block(block); bp = &nlm_blocked; if (when != NLM_NEVER) { - if ((when += jiffies) == NLM_NEVER) - when ++; + if ((when += jiffies) > NLM_NEVER) + when = NLM_NEVER; while ((b = *bp) && time_before_eq(b->b_when,when)) bp = &b->b_next; } else --- linux/fs/locks.c.locks Thu Oct 11 16:52:18 2001 +++ linux/fs/locks.c Mon Jun 17 13:32:35 2002 @@ -926,8 +926,11 @@ goto next_lock; /* If the next lock in the list has entirely bigger * addresses than the new one, insert the lock here. + * + * be careful if fl_end == OFFSET_MAX --okir */ - if (fl->fl_start > caller->fl_end + 1) + if (fl->fl_start > caller->fl_end + 1 + && caller->fl_end != OFFSET_MAX) break; /* If we come here, the new and old lock are of the --- linux/include/linux/lockd/lockd.h.locks Thu Nov 22 20:47:20 2001 +++ linux/include/linux/lockd/lockd.h Mon Jun 17 13:38:51 2002 @@ -89,8 +89,11 @@ /* * This is a server block (i.e. a lock requested by some client which * couldn't be granted because of a conflicting lock). + * + * XXX: Beware of signedness errors. b_when is passed as a signed long + * into time_before_eq et al. --okir */ -#define NLM_NEVER (~(unsigned long) 0) +#define NLM_NEVER (0x7FFFFFF) struct nlm_block { struct nlm_block * b_next; /* linked list (all blocks) */ struct nlm_block * b_fnext; /* linked list (per file) */