summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2010-09-19 22:55:06 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-09-19 23:49:30 -0400
commit06497524589f2a7717da33969d541674e0a27da6 (patch)
tree3d7d21b9dd325c36e11a923f186059f587d7724d
parentc88739b373e4930ed082a607cb78bf82616fd076 (diff)
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.c24
1 files changed, 20 insertions, 4 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index da872f9fe1e0..ca7c621cd975 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);