diff options
author | J. Bruce Fields <bfields@redhat.com> | 2010-09-19 22:55:06 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-09-19 23:49:30 -0400 |
commit | 06497524589f2a7717da33969d541674e0a27da6 (patch) | |
tree | 3d7d21b9dd325c36e11a923f186059f587d7724d | |
parent | c88739b373e4930ed082a607cb78bf82616fd076 (diff) | |
download | op-kernel-dev-06497524589f2a7717da33969d541674e0a27da6.zip op-kernel-dev-06497524589f2a7717da33969d541674e0a27da6.tar.gz |
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>
-rw-r--r-- | net/sunrpc/cache.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index da872f9..ca7c621 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -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); |