nfsd4: fix hang on fast-booting nfs servers

The last_close field of a cache_detail is initialized to zero, so the
condition

	detail->last_close < seconds_since_boot() - 30

may be false even for a cache that was never opened.

However, we want to immediately fail upcalls to caches that were never
opened: in the case of the auth_unix_gid cache, especially, which may
never be opened by mountd (if the --manage-gids option is not set), we
want to fail the upcall immediately.  Otherwise client requests will be
dropped unnecessarily on reboot.

Also document these conditions.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
J. Bruce Fields 2010-09-19 22:55:06 -04:00
parent c88739b373
commit 0649752458
1 changed files with 20 additions and 4 deletions

View File

@ -1091,6 +1091,23 @@ static void warn_no_listener(struct cache_detail *detail)
}
}
static bool cache_listeners_exist(struct cache_detail *detail)
{
if (atomic_read(&detail->readers))
return true;
if (detail->last_close == 0)
/* This cache was never opened */
return false;
if (detail->last_close < seconds_since_boot() - 30)
/*
* We allow for the possibility that someone might
* restart a userspace daemon without restarting the
* server; but after 30 seconds, we give up.
*/
return false;
return true;
}
/*
* register an upcall request to user-space and queue it up for read() by the
* upcall daemon.
@ -1109,10 +1126,9 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h,
char *bp;
int len;
if (atomic_read(&detail->readers) == 0 &&
detail->last_close < seconds_since_boot() - 30) {
warn_no_listener(detail);
return -EINVAL;
if (!cache_listeners_exist(detail)) {
warn_no_listener(detail);
return -EINVAL;
}
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);