nfsd: export upcalls must not return ESTALE when mountd is down
authorTrond Myklebust <trondmy@gmail.com>
Sun, 1 Mar 2020 23:21:42 +0000 (18:21 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 16 Mar 2020 16:04:33 +0000 (12:04 -0400)
If the rpc.mountd daemon goes down, then that should not cause all
exports to start failing with ESTALE errors. Let's explicitly
distinguish between the cache upcall cases that need to time out,
and those that do not.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfs/dns_resolve.c
fs/nfsd/export.c
fs/nfsd/nfs4idmap.c
include/linux/sunrpc/cache.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/svcauth_unix.c

index 89bd5581f3172cfd0d226632578ec45c25a9b567..963800037609e089fb8747917adf7624b95968a4 100644 (file)
@@ -152,12 +152,13 @@ static int nfs_dns_upcall(struct cache_detail *cd,
                struct cache_head *ch)
 {
        struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h);
-       int ret;
 
-       ret = nfs_cache_upcall(cd, key->hostname);
-       if (ret)
-               ret = sunrpc_cache_pipe_upcall(cd, ch);
-       return ret;
+       if (test_and_set_bit(CACHE_PENDING, &ch->flags))
+               return 0;
+       if (!nfs_cache_upcall(cd, key->hostname))
+               return 0;
+       clear_bit(CACHE_PENDING, &ch->flags);
+       return sunrpc_cache_pipe_upcall_timeout(cd, ch);
 }
 
 static int nfs_dns_match(struct cache_head *ca,
index 6e6cbeb7ac2b51f41fccd86c8a8e0c08221015cd..cb777fe8298813e3a3d5196eb36ebe5da7ea8b57 100644 (file)
@@ -51,6 +51,11 @@ static void expkey_put(struct kref *ref)
        kfree_rcu(key, ek_rcu);
 }
 
+static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall(cd, h);
+}
+
 static void expkey_request(struct cache_detail *cd,
                           struct cache_head *h,
                           char **bpp, int *blen)
@@ -254,6 +259,7 @@ static const struct cache_detail svc_expkey_cache_template = {
        .hash_size      = EXPKEY_HASHMAX,
        .name           = "nfsd.fh",
        .cache_put      = expkey_put,
+       .cache_upcall   = expkey_upcall,
        .cache_request  = expkey_request,
        .cache_parse    = expkey_parse,
        .cache_show     = expkey_show,
@@ -335,6 +341,11 @@ static void svc_export_put(struct kref *ref)
        kfree_rcu(exp, ex_rcu);
 }
 
+static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall(cd, h);
+}
+
 static void svc_export_request(struct cache_detail *cd,
                               struct cache_head *h,
                               char **bpp, int *blen)
@@ -774,6 +785,7 @@ static const struct cache_detail svc_export_cache_template = {
        .hash_size      = EXPORT_HASHMAX,
        .name           = "nfsd.export",
        .cache_put      = svc_export_put,
+       .cache_upcall   = svc_export_upcall,
        .cache_request  = svc_export_request,
        .cache_parse    = svc_export_parse,
        .cache_show     = svc_export_show,
index d1f285245af802f0ca190c2e383f73931f1356d3..9460be8a83212e2ecb3cd9b775387be63ab93fa7 100644 (file)
@@ -122,6 +122,12 @@ idtoname_hash(struct ent *ent)
        return hash;
 }
 
+static int
+idtoname_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall_timeout(cd, h);
+}
+
 static void
 idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
     int *blen)
@@ -184,6 +190,7 @@ static const struct cache_detail idtoname_cache_template = {
        .hash_size      = ENT_HASHMAX,
        .name           = "nfs4.idtoname",
        .cache_put      = ent_put,
+       .cache_upcall   = idtoname_upcall,
        .cache_request  = idtoname_request,
        .cache_parse    = idtoname_parse,
        .cache_show     = idtoname_show,
@@ -295,6 +302,12 @@ nametoid_hash(struct ent *ent)
        return hash_str(ent->name, ENT_HASHBITS);
 }
 
+static int
+nametoid_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall_timeout(cd, h);
+}
+
 static void
 nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
     int *blen)
@@ -347,6 +360,7 @@ static const struct cache_detail nametoid_cache_template = {
        .hash_size      = ENT_HASHMAX,
        .name           = "nfs4.nametoid",
        .cache_put      = ent_put,
+       .cache_upcall   = nametoid_upcall,
        .cache_request  = nametoid_request,
        .cache_parse    = nametoid_parse,
        .cache_show     = nametoid_show,
index 0f64de7caa39e495bd23d3bf52d88e3e491196ef..656882a50991e06657d013254a6b384807b7f899 100644 (file)
@@ -179,6 +179,9 @@ sunrpc_cache_update(struct cache_detail *detail,
 
 extern int
 sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h);
+extern int
+sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
+                                struct cache_head *h);
 
 
 extern void cache_clean_deferred(void *owner);
index e93f06ec180d1ce350a2a18c683e0d70e49cbffd..54ae5be62f6a5d878878ffb396870a76ebff2d7a 100644 (file)
@@ -180,6 +180,11 @@ static struct cache_head *rsi_alloc(void)
                return NULL;
 }
 
+static int rsi_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall_timeout(cd, h);
+}
+
 static void rsi_request(struct cache_detail *cd,
                       struct cache_head *h,
                       char **bpp, int *blen)
@@ -278,6 +283,7 @@ static const struct cache_detail rsi_cache_template = {
        .hash_size      = RSI_HASHMAX,
        .name           = "auth.rpcsec.init",
        .cache_put      = rsi_put,
+       .cache_upcall   = rsi_upcall,
        .cache_request  = rsi_request,
        .cache_parse    = rsi_parse,
        .match          = rsi_match,
@@ -424,6 +430,11 @@ rsc_alloc(void)
                return NULL;
 }
 
+static int rsc_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return -EINVAL;
+}
+
 static int rsc_parse(struct cache_detail *cd,
                     char *mesg, int mlen)
 {
@@ -550,6 +561,7 @@ static const struct cache_detail rsc_cache_template = {
        .hash_size      = RSC_HASHMAX,
        .name           = "auth.rpcsec.context",
        .cache_put      = rsc_put,
+       .cache_upcall   = rsc_upcall,
        .cache_parse    = rsc_parse,
        .match          = rsc_match,
        .init           = rsc_init,
index 8a8e3528293c8fda47b6af4e748b7ea5270a1b44..7f2e5d818e05ee87b05d37a5da23a83cfdd54699 100644 (file)
@@ -38,7 +38,6 @@
 
 static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
 static void cache_revisit_request(struct cache_head *item);
-static bool cache_listeners_exist(struct cache_detail *detail);
 
 static void cache_init(struct cache_head *h, struct cache_detail *detail)
 {
@@ -225,13 +224,6 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
 }
 EXPORT_SYMBOL_GPL(sunrpc_cache_update);
 
-static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h)
-{
-       if (cd->cache_upcall)
-               return cd->cache_upcall(cd, h);
-       return sunrpc_cache_pipe_upcall(cd, h);
-}
-
 static inline int cache_is_valid(struct cache_head *h)
 {
        if (!test_bit(CACHE_VALID, &h->flags))
@@ -304,17 +296,14 @@ int cache_check(struct cache_detail *detail,
                   (h->expiry_time != 0 && age > refresh_age/2)) {
                dprintk("RPC:       Want update, refage=%lld, age=%lld\n",
                                refresh_age, age);
-               if (!test_and_set_bit(CACHE_PENDING, &h->flags)) {
-                       switch (cache_make_upcall(detail, h)) {
-                       case -EINVAL:
-                               rv = try_to_negate_entry(detail, h);
-                               break;
-                       case -EAGAIN:
-                               cache_fresh_unlocked(h, detail);
-                               break;
-                       }
-               } else if (!cache_listeners_exist(detail))
+               switch (detail->cache_upcall(detail, h)) {
+               case -EINVAL:
                        rv = try_to_negate_entry(detail, h);
+                       break;
+               case -EAGAIN:
+                       cache_fresh_unlocked(h, detail);
+                       break;
+               }
        }
 
        if (rv == -EAGAIN) {
@@ -1196,20 +1185,12 @@ static bool cache_listeners_exist(struct cache_detail *detail)
  *
  * Each request is at most one page long.
  */
-int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
+static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
 {
-
        char *buf;
        struct cache_request *crq;
        int ret = 0;
 
-       if (!detail->cache_request)
-               return -EINVAL;
-
-       if (!cache_listeners_exist(detail)) {
-               warn_no_listener(detail);
-               return -EINVAL;
-       }
        if (test_bit(CACHE_CLEANED, &h->flags))
                /* Too late to make an upcall */
                return -EAGAIN;
@@ -1243,8 +1224,26 @@ int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
        }
        return ret;
 }
+
+int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
+{
+       if (test_and_set_bit(CACHE_PENDING, &h->flags))
+               return 0;
+       return cache_pipe_upcall(detail, h);
+}
 EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
 
+int sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
+                                    struct cache_head *h)
+{
+       if (!cache_listeners_exist(detail)) {
+               warn_no_listener(detail);
+               return -EINVAL;
+       }
+       return sunrpc_cache_pipe_upcall(detail, h);
+}
+EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall_timeout);
+
 /*
  * parse a message from user-space and pass it
  * to an appropriate cache
index 04aa80a2d7523502a1ef4a4e0676946609801114..6c8f802c42612b6169d273db9c7196ad6bfb99c3 100644 (file)
@@ -148,6 +148,11 @@ static struct cache_head *ip_map_alloc(void)
                return NULL;
 }
 
+static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall(cd, h);
+}
+
 static void ip_map_request(struct cache_detail *cd,
                                  struct cache_head *h,
                                  char **bpp, int *blen)
@@ -467,6 +472,11 @@ static struct cache_head *unix_gid_alloc(void)
                return NULL;
 }
 
+static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h)
+{
+       return sunrpc_cache_pipe_upcall_timeout(cd, h);
+}
+
 static void unix_gid_request(struct cache_detail *cd,
                             struct cache_head *h,
                             char **bpp, int *blen)
@@ -584,6 +594,7 @@ static const struct cache_detail unix_gid_cache_template = {
        .hash_size      = GID_HASHMAX,
        .name           = "auth.unix.gid",
        .cache_put      = unix_gid_put,
+       .cache_upcall   = unix_gid_upcall,
        .cache_request  = unix_gid_request,
        .cache_parse    = unix_gid_parse,
        .cache_show     = unix_gid_show,
@@ -881,6 +892,7 @@ static const struct cache_detail ip_map_cache_template = {
        .hash_size      = IP_HASHMAX,
        .name           = "auth.unix.ip",
        .cache_put      = ip_map_put,
+       .cache_upcall   = ip_map_upcall,
        .cache_request  = ip_map_request,
        .cache_parse    = ip_map_parse,
        .cache_show     = ip_map_show,