2020-03-01 23:25:42

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 2/8] nfsd: Add tracing to nfsd_set_fh_dentry()

Add tracing to allow us to figure out where any stale filehandle issues
may be originating from.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfsd/nfsfh.c | 13 ++++++++++---
fs/nfsd/trace.h | 30 ++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index b319080288c3..37bc8f5f4514 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -14,6 +14,7 @@
#include "nfsd.h"
#include "vfs.h"
#include "auth.h"
+#include "trace.h"

#define NFSDDBG_FACILITY NFSDDBG_FH

@@ -209,11 +210,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
}

error = nfserr_stale;
- if (PTR_ERR(exp) == -ENOENT)
- return error;
+ if (IS_ERR(exp)) {
+ trace_nfsd_set_fh_dentry_badexport(rqstp, fhp, PTR_ERR(exp));
+
+ if (PTR_ERR(exp) == -ENOENT)
+ return error;

- if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));
+ }

if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
/* Elevate privileges so that the lack of 'r' or 'x'
@@ -267,6 +271,9 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
data_left, fileid_type,
nfsd_acceptable, exp);
+ if (IS_ERR_OR_NULL(dentry))
+ trace_nfsd_set_fh_dentry_badhandle(rqstp, fhp,
+ dentry ? PTR_ERR(dentry) : -ESTALE);
}
if (dentry == NULL)
goto out;
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 06dd0d337049..9abd1591a841 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -50,6 +50,36 @@ TRACE_EVENT(nfsd_compound_status,
__get_str(name), __entry->status)
)

+DECLARE_EVENT_CLASS(nfsd_fh_err_class,
+ TP_PROTO(struct svc_rqst *rqstp,
+ struct svc_fh *fhp,
+ int status),
+ TP_ARGS(rqstp, fhp, status),
+ TP_STRUCT__entry(
+ __field(u32, xid)
+ __field(u32, fh_hash)
+ __field(int, status)
+ ),
+ TP_fast_assign(
+ __entry->xid = be32_to_cpu(rqstp->rq_xid);
+ __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
+ __entry->status = status;
+ ),
+ TP_printk("xid=0x%08x fh_hash=0x%08x status=%d",
+ __entry->xid, __entry->fh_hash,
+ __entry->status)
+)
+
+#define DEFINE_NFSD_FH_ERR_EVENT(name) \
+DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \
+ TP_PROTO(struct svc_rqst *rqstp, \
+ struct svc_fh *fhp, \
+ int status), \
+ TP_ARGS(rqstp, fhp, status))
+
+DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport);
+DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle);
+
DECLARE_EVENT_CLASS(nfsd_io_class,
TP_PROTO(struct svc_rqst *rqstp,
struct svc_fh *fhp,
--
2.24.1


2020-03-01 23:25:41

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 3/8] nfsd: Add tracepoints for exp_find_key() and exp_get_by_name()

Add tracepoints for upcalls.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfsd/export.c | 9 +++++++--
fs/nfsd/trace.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 15422c951fd1..e867db0bb380 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -23,6 +23,7 @@
#include "netns.h"
#include "pnfs.h"
#include "filecache.h"
+#include "trace.h"

#define NFSDDBG_FACILITY NFSDDBG_EXPORT

@@ -832,8 +833,10 @@ exp_find_key(struct cache_detail *cd, struct auth_domain *clp, int fsid_type,
if (ek == NULL)
return ERR_PTR(-ENOMEM);
err = cache_check(cd, &ek->h, reqp);
- if (err)
+ if (err) {
+ trace_nfsd_exp_find_key(&key, err);
return ERR_PTR(err);
+ }
return ek;
}

@@ -855,8 +858,10 @@ exp_get_by_name(struct cache_detail *cd, struct auth_domain *clp,
if (exp == NULL)
return ERR_PTR(-ENOMEM);
err = cache_check(cd, &exp->h, reqp);
- if (err)
+ if (err) {
+ trace_nfsd_exp_get_by_name(&key, err);
return ERR_PTR(err);
+ }
return exp;
}

diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 9abd1591a841..3b9277d7b5f2 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -9,6 +9,7 @@
#define _NFSD_TRACE_H

#include <linux/tracepoint.h>
+#include "export.h"
#include "nfsfh.h"

TRACE_EVENT(nfsd_compound,
@@ -80,6 +81,51 @@ DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \
DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport);
DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle);

+TRACE_EVENT(nfsd_exp_find_key,
+ TP_PROTO(const struct svc_expkey *key,
+ int status),
+ TP_ARGS(key, status),
+ TP_STRUCT__entry(
+ __field(int, fsidtype)
+ __array(u32, fsid, 6)
+ __string(auth_domain, key->ek_client->name)
+ __field(int, status)
+ ),
+ TP_fast_assign(
+ __entry->fsidtype = key->ek_fsidtype;
+ memcpy(__entry->fsid, key->ek_fsid, 4*6);
+ __assign_str(auth_domain, key->ek_client->name);
+ __entry->status = status;
+ ),
+ TP_printk("fsid=%x::%s domain=%s status=%d",
+ __entry->fsidtype,
+ __print_array(__entry->fsid, 6, 4),
+ __get_str(auth_domain),
+ __entry->status
+ )
+);
+
+TRACE_EVENT(nfsd_exp_get_by_name,
+ TP_PROTO(const struct svc_export *key,
+ int status),
+ TP_ARGS(key, status),
+ TP_STRUCT__entry(
+ __string(path, key->ex_path.dentry->d_name.name)
+ __string(auth_domain, key->ex_client->name)
+ __field(int, status)
+ ),
+ TP_fast_assign(
+ __assign_str(path, key->ex_path.dentry->d_name.name);
+ __assign_str(auth_domain, key->ex_client->name);
+ __entry->status = status;
+ ),
+ TP_printk("path=%s domain=%s status=%d",
+ __get_str(path),
+ __get_str(auth_domain),
+ __entry->status
+ )
+);
+
DECLARE_EVENT_CLASS(nfsd_io_class,
TP_PROTO(struct svc_rqst *rqstp,
struct svc_fh *fhp,
--
2.24.1

2020-03-01 23:25:41

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 4/8] nfsd: Add tracepoints for update of the expkey and export cache entries

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfsd/export.c | 24 +++++++++++++++---------
fs/nfsd/trace.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index e867db0bb380..6e6cbeb7ac2b 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -141,7 +141,9 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
if (len == 0) {
set_bit(CACHE_NEGATIVE, &key.h.flags);
ek = svc_expkey_update(cd, &key, ek);
- if (!ek)
+ if (ek)
+ trace_nfsd_expkey_update(ek, NULL);
+ else
err = -ENOMEM;
} else {
err = kern_path(buf, 0, &key.ek_path);
@@ -151,7 +153,9 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
dprintk("Found the path %s\n", buf);

ek = svc_expkey_update(cd, &key, ek);
- if (!ek)
+ if (ek)
+ trace_nfsd_expkey_update(ek, buf);
+ else
err = -ENOMEM;
path_put(&key.ek_path);
}
@@ -644,15 +648,17 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
}

expp = svc_export_lookup(&exp);
- if (expp)
- expp = svc_export_update(&exp, expp);
- else
- err = -ENOMEM;
- cache_flush();
- if (expp == NULL)
+ if (!expp) {
err = -ENOMEM;
- else
+ goto out4;
+ }
+ expp = svc_export_update(&exp, expp);
+ if (expp) {
+ trace_nfsd_export_update(expp);
+ cache_flush();
exp_put(expp);
+ } else
+ err = -ENOMEM;
out4:
nfsd4_fslocs_free(&exp.ex_fslocs);
kfree(exp.ex_uuid);
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index 3b9277d7b5f2..78c574251c60 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -105,6 +105,32 @@ TRACE_EVENT(nfsd_exp_find_key,
)
);

+TRACE_EVENT(nfsd_expkey_update,
+ TP_PROTO(const struct svc_expkey *key, const char *exp_path),
+ TP_ARGS(key, exp_path),
+ TP_STRUCT__entry(
+ __field(int, fsidtype)
+ __array(u32, fsid, 6)
+ __string(auth_domain, key->ek_client->name)
+ __string(path, exp_path)
+ __field(bool, cache)
+ ),
+ TP_fast_assign(
+ __entry->fsidtype = key->ek_fsidtype;
+ memcpy(__entry->fsid, key->ek_fsid, 4*6);
+ __assign_str(auth_domain, key->ek_client->name);
+ __assign_str(path, exp_path);
+ __entry->cache = !test_bit(CACHE_NEGATIVE, &key->h.flags);
+ ),
+ TP_printk("fsid=%x::%s domain=%s path=%s cache=%s",
+ __entry->fsidtype,
+ __print_array(__entry->fsid, 6, 4),
+ __get_str(auth_domain),
+ __get_str(path),
+ __entry->cache ? "pos" : "neg"
+ )
+);
+
TRACE_EVENT(nfsd_exp_get_by_name,
TP_PROTO(const struct svc_export *key,
int status),
@@ -126,6 +152,26 @@ TRACE_EVENT(nfsd_exp_get_by_name,
)
);

+TRACE_EVENT(nfsd_export_update,
+ TP_PROTO(const struct svc_export *key),
+ TP_ARGS(key),
+ TP_STRUCT__entry(
+ __string(path, key->ex_path.dentry->d_name.name)
+ __string(auth_domain, key->ex_client->name)
+ __field(bool, cache)
+ ),
+ TP_fast_assign(
+ __assign_str(path, key->ex_path.dentry->d_name.name);
+ __assign_str(auth_domain, key->ex_client->name);
+ __entry->cache = !test_bit(CACHE_NEGATIVE, &key->h.flags);
+ ),
+ TP_printk("path=%s domain=%s cache=%s",
+ __get_str(path),
+ __get_str(auth_domain),
+ __entry->cache ? "pos" : "neg"
+ )
+);
+
DECLARE_EVENT_CLASS(nfsd_io_class,
TP_PROTO(struct svc_rqst *rqstp,
struct svc_fh *fhp,
--
2.24.1

2020-03-01 23:25:42

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 5/8] nfsd: export upcalls must not return ESTALE when mountd is down

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 <[email protected]>
---
fs/nfs/dns_resolve.c | 11 ++++---
fs/nfsd/export.c | 12 +++++++
fs/nfsd/nfs4idmap.c | 14 ++++++++
include/linux/sunrpc/cache.h | 3 ++
net/sunrpc/auth_gss/svcauth_gss.c | 12 +++++++
net/sunrpc/cache.c | 53 +++++++++++++++----------------
net/sunrpc/svcauth_unix.c | 12 +++++++
7 files changed, 85 insertions(+), 32 deletions(-)

diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c
index 89bd5581f317..963800037609 100644
--- a/fs/nfs/dns_resolve.c
+++ b/fs/nfs/dns_resolve.c
@@ -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,
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 6e6cbeb7ac2b..cb777fe82988 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -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,
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index d1f285245af8..9460be8a8321 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -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,
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 0f64de7caa39..656882a50991 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -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);
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 65b67b257302..6d698bf1c16e 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -184,6 +184,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)
@@ -282,6 +287,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,
@@ -428,6 +434,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)
{
@@ -554,6 +565,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,
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index bd843a81afa0..5e14513603cb 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -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)
{
@@ -224,13 +223,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))
@@ -303,17 +295,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) {
@@ -1195,20 +1184,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;
@@ -1242,8 +1223,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
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 04aa80a2d752..6c8f802c4261 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -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,
--
2.24.1

2020-03-01 23:26:33

by Trond Myklebust

[permalink] [raw]
Subject: [PATCH 6/8] SUNRPC/cache: Allow garbage collection of invalid cache entries

If the cache entry never gets initialised, we want the garbage
collector to be able to evict it. Otherwise if the upcall daemon
fails to initialise the entry, we end up never expiring it.

Signed-off-by: Trond Myklebust <[email protected]>
---
include/linux/sunrpc/cache.h | 3 ---
net/sunrpc/cache.c | 36 +++++++++++++++++++-----------------
2 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 656882a50991..532cdbda43da 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -209,9 +209,6 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd)

static inline bool cache_is_expired(struct cache_detail *detail, struct cache_head *h)
{
- if (!test_bit(CACHE_VALID, &h->flags))
- return false;
-
return (h->expiry_time < seconds_since_boot()) ||
(detail->flush_time >= h->last_refresh);
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 5e14513603cb..b7ddb2affb7e 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -64,13 +64,14 @@ static struct cache_head *sunrpc_cache_find_rcu(struct cache_detail *detail,

rcu_read_lock();
hlist_for_each_entry_rcu(tmp, head, cache_list) {
- if (detail->match(tmp, key)) {
- if (cache_is_expired(detail, tmp))
- continue;
- tmp = cache_get_rcu(tmp);
- rcu_read_unlock();
- return tmp;
- }
+ if (!detail->match(tmp, key))
+ continue;
+ if (test_bit(CACHE_VALID, &tmp->flags) &&
+ cache_is_expired(detail, tmp))
+ continue;
+ tmp = cache_get_rcu(tmp);
+ rcu_read_unlock();
+ return tmp;
}
rcu_read_unlock();
return NULL;
@@ -113,17 +114,18 @@ static struct cache_head *sunrpc_cache_add_entry(struct cache_detail *detail,

/* check if entry appeared while we slept */
hlist_for_each_entry_rcu(tmp, head, cache_list) {
- if (detail->match(tmp, key)) {
- if (cache_is_expired(detail, tmp)) {
- sunrpc_begin_cache_remove_entry(tmp, detail);
- freeme = tmp;
- break;
- }
- cache_get(tmp);
- spin_unlock(&detail->hash_lock);
- cache_put(new, detail);
- return tmp;
+ if (!detail->match(tmp, key))
+ continue;
+ if (test_bit(CACHE_VALID, &tmp->flags) &&
+ cache_is_expired(detail, tmp)) {
+ sunrpc_begin_cache_remove_entry(tmp, detail);
+ freeme = tmp;
+ break;
}
+ cache_get(tmp);
+ spin_unlock(&detail->hash_lock);
+ cache_put(new, detail);
+ return tmp;
}

hlist_add_head_rcu(&new->cache_list, head);
--
2.24.1

2020-03-03 00:23:20

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH 2/8] nfsd: Add tracing to nfsd_set_fh_dentry()



> On Mar 1, 2020, at 6:21 PM, Trond Myklebust <[email protected]> wrote:
>
> Add tracing to allow us to figure out where any stale filehandle issues
> may be originating from.
>
> Signed-off-by: Trond Myklebust <[email protected]>
> ---
> fs/nfsd/nfsfh.c | 13 ++++++++++---
> fs/nfsd/trace.h | 30 ++++++++++++++++++++++++++++++
> 2 files changed, 40 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> index b319080288c3..37bc8f5f4514 100644
> --- a/fs/nfsd/nfsfh.c
> +++ b/fs/nfsd/nfsfh.c
> @@ -14,6 +14,7 @@
> #include "nfsd.h"
> #include "vfs.h"
> #include "auth.h"
> +#include "trace.h"
>
> #define NFSDDBG_FACILITY NFSDDBG_FH
>
> @@ -209,11 +210,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
> }
>
> error = nfserr_stale;
> - if (PTR_ERR(exp) == -ENOENT)
> - return error;
> + if (IS_ERR(exp)) {
> + trace_nfsd_set_fh_dentry_badexport(rqstp, fhp, PTR_ERR(exp));
> +
> + if (PTR_ERR(exp) == -ENOENT)
> + return error;
>
> - if (IS_ERR(exp))
> return nfserrno(PTR_ERR(exp));
> + }
>
> if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
> /* Elevate privileges so that the lack of 'r' or 'x'
> @@ -267,6 +271,9 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
> dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
> data_left, fileid_type,
> nfsd_acceptable, exp);
> + if (IS_ERR_OR_NULL(dentry))
> + trace_nfsd_set_fh_dentry_badhandle(rqstp, fhp,
> + dentry ? PTR_ERR(dentry) : -ESTALE);

If you'll be respinning this series, a handful of nits:

- the line above has a double space
- the trace point names here are a little long, will result in
hard-to-read formatting in the trace log
- checkpatch.pl complains about a couple of the later patches,
where one arm of an "if" statement has braces but the other
does not


> }
> if (dentry == NULL)
> goto out;
> diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
> index 06dd0d337049..9abd1591a841 100644
> --- a/fs/nfsd/trace.h
> +++ b/fs/nfsd/trace.h
> @@ -50,6 +50,36 @@ TRACE_EVENT(nfsd_compound_status,
> __get_str(name), __entry->status)
> )
>
> +DECLARE_EVENT_CLASS(nfsd_fh_err_class,
> + TP_PROTO(struct svc_rqst *rqstp,
> + struct svc_fh *fhp,
> + int status),
> + TP_ARGS(rqstp, fhp, status),
> + TP_STRUCT__entry(
> + __field(u32, xid)
> + __field(u32, fh_hash)
> + __field(int, status)
> + ),
> + TP_fast_assign(
> + __entry->xid = be32_to_cpu(rqstp->rq_xid);
> + __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
> + __entry->status = status;
> + ),
> + TP_printk("xid=0x%08x fh_hash=0x%08x status=%d",
> + __entry->xid, __entry->fh_hash,
> + __entry->status)
> +)
> +
> +#define DEFINE_NFSD_FH_ERR_EVENT(name) \
> +DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \
> + TP_PROTO(struct svc_rqst *rqstp, \
> + struct svc_fh *fhp, \
> + int status), \
> + TP_ARGS(rqstp, fhp, status))
> +
> +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport);
> +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle);
> +
> DECLARE_EVENT_CLASS(nfsd_io_class,
> TP_PROTO(struct svc_rqst *rqstp,
> struct svc_fh *fhp,
> --
> 2.24.1
>

--
Chuck Lever
[email protected]



2020-03-03 05:59:37

by Trond Myklebust

[permalink] [raw]
Subject: Re: [PATCH 2/8] nfsd: Add tracing to nfsd_set_fh_dentry()

On Mon, 2020-03-02 at 19:22 -0500, Chuck Lever wrote:
> > On Mar 1, 2020, at 6:21 PM, Trond Myklebust <[email protected]>
> > wrote:
> >
> > Add tracing to allow us to figure out where any stale filehandle
> > issues
> > may be originating from.
> >
> > Signed-off-by: Trond Myklebust <[email protected]>
> > ---
> > fs/nfsd/nfsfh.c | 13 ++++++++++---
> > fs/nfsd/trace.h | 30 ++++++++++++++++++++++++++++++
> > 2 files changed, 40 insertions(+), 3 deletions(-)
> >
> > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
> > index b319080288c3..37bc8f5f4514 100644
> > --- a/fs/nfsd/nfsfh.c
> > +++ b/fs/nfsd/nfsfh.c
> > @@ -14,6 +14,7 @@
> > #include "nfsd.h"
> > #include "vfs.h"
> > #include "auth.h"
> > +#include "trace.h"
> >
> > #define NFSDDBG_FACILITY NFSDDBG_FH
> >
> > @@ -209,11 +210,14 @@ static __be32 nfsd_set_fh_dentry(struct
> > svc_rqst *rqstp, struct svc_fh *fhp)
> > }
> >
> > error = nfserr_stale;
> > - if (PTR_ERR(exp) == -ENOENT)
> > - return error;
> > + if (IS_ERR(exp)) {
> > + trace_nfsd_set_fh_dentry_badexport(rqstp, fhp,
> > PTR_ERR(exp));
> > +
> > + if (PTR_ERR(exp) == -ENOENT)
> > + return error;
> >
> > - if (IS_ERR(exp))
> > return nfserrno(PTR_ERR(exp));
> > + }
> >
> > if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
> > /* Elevate privileges so that the lack of 'r' or 'x'
> > @@ -267,6 +271,9 @@ static __be32 nfsd_set_fh_dentry(struct
> > svc_rqst *rqstp, struct svc_fh *fhp)
> > dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
> > data_left, fileid_type,
> > nfsd_acceptable, exp);
> > + if (IS_ERR_OR_NULL(dentry))
> > + trace_nfsd_set_fh_dentry_badhandle(rqstp, fhp,
> > + dentry ? PTR_ERR(dentry) :
> > -ESTALE);
>
> If you'll be respinning this series, a handful of nits:
>

I see no need to respin the entire series. Just the last patch.

> - the line above has a double space
> - the trace point names here are a little long, will result in
> hard-to-read formatting in the trace log
> - checkpatch.pl complains about a couple of the later patches,
> where one arm of an "if" statement has braces but the other
> does not
>
> > }
> > if (dentry == NULL)
> > goto out;
> > diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
> > index 06dd0d337049..9abd1591a841 100644
> > --- a/fs/nfsd/trace.h
> > +++ b/fs/nfsd/trace.h
> > @@ -50,6 +50,36 @@ TRACE_EVENT(nfsd_compound_status,
> > __get_str(name), __entry->status)
> > )
> >
> > +DECLARE_EVENT_CLASS(nfsd_fh_err_class,
> > + TP_PROTO(struct svc_rqst *rqstp,
> > + struct svc_fh *fhp,
> > + int status),
> > + TP_ARGS(rqstp, fhp, status),
> > + TP_STRUCT__entry(
> > + __field(u32, xid)
> > + __field(u32, fh_hash)
> > + __field(int, status)
> > + ),
> > + TP_fast_assign(
> > + __entry->xid = be32_to_cpu(rqstp->rq_xid);
> > + __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
> > + __entry->status = status;
> > + ),
> > + TP_printk("xid=0x%08x fh_hash=0x%08x status=%d",
> > + __entry->xid, __entry->fh_hash,
> > + __entry->status)
> > +)
> > +
> > +#define DEFINE_NFSD_FH_ERR_EVENT(name) \
> > +DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \
> > + TP_PROTO(struct svc_rqst *rqstp, \
> > + struct svc_fh *fhp, \
> > + int status), \
> > + TP_ARGS(rqstp, fhp, status))
> > +
> > +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport);
> > +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle);
> > +
> > DECLARE_EVENT_CLASS(nfsd_io_class,
> > TP_PROTO(struct svc_rqst *rqstp,
> > struct svc_fh *fhp,
> > --
> > 2.24.1
> >
>
> --
> Chuck Lever
> [email protected]
>
>
>
--
Trond Myklebust
Linux NFS client maintainer, Hammerspace
[email protected]


2020-03-03 13:39:42

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH 2/8] nfsd: Add tracing to nfsd_set_fh_dentry()


> On Mar 3, 2020, at 12:59 AM, Trond Myklebust <[email protected]> wrote:
>
> On Mon, 2020-03-02 at 19:22 -0500, Chuck Lever wrote:
>>> On Mar 1, 2020, at 6:21 PM, Trond Myklebust <[email protected]>
>>> wrote:
>>>
>>> Add tracing to allow us to figure out where any stale filehandle
>>> issues
>>> may be originating from.
>>>
>>> Signed-off-by: Trond Myklebust <[email protected]>
>>> ---
>>> fs/nfsd/nfsfh.c | 13 ++++++++++---
>>> fs/nfsd/trace.h | 30 ++++++++++++++++++++++++++++++
>>> 2 files changed, 40 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
>>> index b319080288c3..37bc8f5f4514 100644
>>> --- a/fs/nfsd/nfsfh.c
>>> +++ b/fs/nfsd/nfsfh.c
>>> @@ -14,6 +14,7 @@
>>> #include "nfsd.h"
>>> #include "vfs.h"
>>> #include "auth.h"
>>> +#include "trace.h"
>>>
>>> #define NFSDDBG_FACILITY NFSDDBG_FH
>>>
>>> @@ -209,11 +210,14 @@ static __be32 nfsd_set_fh_dentry(struct
>>> svc_rqst *rqstp, struct svc_fh *fhp)
>>> }
>>>
>>> error = nfserr_stale;
>>> - if (PTR_ERR(exp) == -ENOENT)
>>> - return error;
>>> + if (IS_ERR(exp)) {
>>> + trace_nfsd_set_fh_dentry_badexport(rqstp, fhp,
>>> PTR_ERR(exp));
>>> +
>>> + if (PTR_ERR(exp) == -ENOENT)
>>> + return error;
>>>
>>> - if (IS_ERR(exp))
>>> return nfserrno(PTR_ERR(exp));
>>> + }
>>>
>>> if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) {
>>> /* Elevate privileges so that the lack of 'r' or 'x'
>>> @@ -267,6 +271,9 @@ static __be32 nfsd_set_fh_dentry(struct
>>> svc_rqst *rqstp, struct svc_fh *fhp)
>>> dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
>>> data_left, fileid_type,
>>> nfsd_acceptable, exp);
>>> + if (IS_ERR_OR_NULL(dentry))
>>> + trace_nfsd_set_fh_dentry_badhandle(rqstp, fhp,
>>> + dentry ? PTR_ERR(dentry) :
>>> -ESTALE);
>>
>> If you'll be respinning this series, a handful of nits:
>>
>
> I see no need to respin the entire series. Just the last patch.

Fair enough.


>> - the line above has a double space
>> - the trace point names here are a little long, will result in
>> hard-to-read formatting in the trace log
>> - checkpatch.pl complains about a couple of the later patches,
>> where one arm of an "if" statement has braces but the other
>> does not
>>
>>> }
>>> if (dentry == NULL)
>>> goto out;
>>> diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
>>> index 06dd0d337049..9abd1591a841 100644
>>> --- a/fs/nfsd/trace.h
>>> +++ b/fs/nfsd/trace.h
>>> @@ -50,6 +50,36 @@ TRACE_EVENT(nfsd_compound_status,
>>> __get_str(name), __entry->status)
>>> )
>>>
>>> +DECLARE_EVENT_CLASS(nfsd_fh_err_class,
>>> + TP_PROTO(struct svc_rqst *rqstp,
>>> + struct svc_fh *fhp,
>>> + int status),
>>> + TP_ARGS(rqstp, fhp, status),
>>> + TP_STRUCT__entry(
>>> + __field(u32, xid)
>>> + __field(u32, fh_hash)
>>> + __field(int, status)
>>> + ),
>>> + TP_fast_assign(
>>> + __entry->xid = be32_to_cpu(rqstp->rq_xid);
>>> + __entry->fh_hash = knfsd_fh_hash(&fhp->fh_handle);
>>> + __entry->status = status;
>>> + ),
>>> + TP_printk("xid=0x%08x fh_hash=0x%08x status=%d",
>>> + __entry->xid, __entry->fh_hash,
>>> + __entry->status)
>>> +)
>>> +
>>> +#define DEFINE_NFSD_FH_ERR_EVENT(name) \
>>> +DEFINE_EVENT(nfsd_fh_err_class, nfsd_##name, \
>>> + TP_PROTO(struct svc_rqst *rqstp, \
>>> + struct svc_fh *fhp, \
>>> + int status), \
>>> + TP_ARGS(rqstp, fhp, status))
>>> +
>>> +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport);
>>> +DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle);
>>> +
>>> DECLARE_EVENT_CLASS(nfsd_io_class,
>>> TP_PROTO(struct svc_rqst *rqstp,
>>> struct svc_fh *fhp,
>>> --
>>> 2.24.1
>>>
>>
>> --
>> Chuck Lever
>> [email protected]
>>
>>
>>
> --
> Trond Myklebust
> Linux NFS client maintainer, Hammerspace
> [email protected]
>
>