Commit eab7e2e6 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] knfsd: Break the hard linkage from svc_expkey to svc_export

Current svc_expkey holds a pointer to the svc_export structure, so updates to
that structure have to be in-place, which is a wart on the whole cache
infrastruct.  So we break that linkage and just do a second lookup.

If this became a performance issue, it would be possible to put a direct link
back in which was only used conditionally.  i.e.  when an object is replaced
in the cache, we set a flag in the old object.  When dereferencing the link
from svc_expkey, if the flag is set, we drop the reference and do a fresh
lookup.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent efc36aa5
...@@ -73,8 +73,10 @@ void expkey_put(struct cache_head *item, struct cache_detail *cd) ...@@ -73,8 +73,10 @@ void expkey_put(struct cache_head *item, struct cache_detail *cd)
if (cache_put(item, cd)) { if (cache_put(item, cd)) {
struct svc_expkey *key = container_of(item, struct svc_expkey, h); struct svc_expkey *key = container_of(item, struct svc_expkey, h);
if (test_bit(CACHE_VALID, &item->flags) && if (test_bit(CACHE_VALID, &item->flags) &&
!test_bit(CACHE_NEGATIVE, &item->flags)) !test_bit(CACHE_NEGATIVE, &item->flags)) {
exp_put(key->ek_export); dput(key->ek_dentry);
mntput(key->ek_mnt);
}
auth_domain_put(key->ek_client); auth_domain_put(key->ek_client);
kfree(key); kfree(key);
} }
...@@ -164,26 +166,18 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) ...@@ -164,26 +166,18 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
} else { } else {
struct nameidata nd; struct nameidata nd;
struct svc_expkey *ek; struct svc_expkey *ek;
struct svc_export *exp;
err = path_lookup(buf, 0, &nd); err = path_lookup(buf, 0, &nd);
if (err) if (err)
goto out; goto out;
dprintk("Found the path %s\n", buf); dprintk("Found the path %s\n", buf);
exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); key.ek_mnt = nd.mnt;
key.ek_dentry = nd.dentry;
err = -ENOENT;
if (!exp)
goto out_nd;
key.ek_export = exp;
dprintk("And found export\n");
ek = svc_expkey_lookup(&key, 1); ek = svc_expkey_lookup(&key, 1);
if (ek) if (ek)
expkey_put(&ek->h, &svc_expkey_cache); expkey_put(&ek->h, &svc_expkey_cache);
exp_put(exp);
err = 0; err = 0;
out_nd:
path_release(&nd); path_release(&nd);
} }
cache_flush(); cache_flush();
...@@ -214,7 +208,7 @@ static int expkey_show(struct seq_file *m, ...@@ -214,7 +208,7 @@ static int expkey_show(struct seq_file *m,
if (test_bit(CACHE_VALID, &h->flags) && if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags)) { !test_bit(CACHE_NEGATIVE, &h->flags)) {
seq_printf(m, " "); seq_printf(m, " ");
seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n"); seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n");
} }
seq_printf(m, "\n"); seq_printf(m, "\n");
return 0; return 0;
...@@ -252,8 +246,8 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it ...@@ -252,8 +246,8 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it
static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item)
{ {
cache_get(&item->ek_export->h); new->ek_mnt = mntget(item->ek_mnt);
new->ek_export = item->ek_export; new->ek_dentry = dget(item->ek_dentry);
} }
static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */ static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
...@@ -519,7 +513,8 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, ...@@ -519,7 +513,8 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
key.ek_client = clp; key.ek_client = clp;
key.ek_fsidtype = fsid_type; key.ek_fsidtype = fsid_type;
memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
key.ek_export = exp; key.ek_mnt = exp->ex_mnt;
key.ek_dentry = exp->ex_dentry;
key.h.expiry_time = NEVER; key.h.expiry_time = NEVER;
key.h.flags = 0; key.h.flags = 0;
...@@ -741,8 +736,8 @@ exp_export(struct nfsctl_export *nxp) ...@@ -741,8 +736,8 @@ exp_export(struct nfsctl_export *nxp)
if ((nxp->ex_flags & NFSEXP_FSID) && if ((nxp->ex_flags & NFSEXP_FSID) &&
(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
!IS_ERR(fsid_key) && !IS_ERR(fsid_key) &&
fsid_key->ek_export && fsid_key->ek_mnt &&
fsid_key->ek_export != exp) (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
goto finish; goto finish;
if (exp) { if (exp) {
...@@ -912,6 +907,24 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) ...@@ -912,6 +907,24 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
return err; return err;
} }
struct svc_export *
exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
struct cache_req *reqp)
{
struct svc_export *exp;
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
if (!ek || IS_ERR(ek))
return ERR_PTR(PTR_ERR(ek));
exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
expkey_put(&ek->h, &svc_expkey_cache);
if (!exp || IS_ERR(exp))
return ERR_PTR(PTR_ERR(exp));
return exp;
}
/* /*
* Called when we need the filehandle for the root of the pseudofs, * Called when we need the filehandle for the root of the pseudofs,
* for a given NFSv4 client. The root is defined to be the * for a given NFSv4 client. The root is defined to be the
...@@ -922,6 +935,7 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, ...@@ -922,6 +935,7 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
struct cache_req *creq) struct cache_req *creq)
{ {
struct svc_expkey *fsid_key; struct svc_expkey *fsid_key;
struct svc_export *exp;
int rv; int rv;
u32 fsidv[2]; u32 fsidv[2];
...@@ -933,8 +947,14 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, ...@@ -933,8 +947,14 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
if (!fsid_key || IS_ERR(fsid_key)) if (!fsid_key || IS_ERR(fsid_key))
return nfserr_perm; return nfserr_perm;
rv = fh_compose(fhp, fsid_key->ek_export, exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
fsid_key->ek_export->ex_dentry, NULL); if (exp == NULL)
rv = nfserr_perm;
else if (IS_ERR(exp))
rv = nfserrno(PTR_ERR(exp));
else
rv = fh_compose(fhp, exp,
fsid_key->ek_dentry, NULL);
expkey_put(&fsid_key->h, &svc_expkey_cache); expkey_put(&fsid_key->h, &svc_expkey_cache);
return rv; return rv;
} }
......
...@@ -67,7 +67,8 @@ struct svc_expkey { ...@@ -67,7 +67,8 @@ struct svc_expkey {
int ek_fsidtype; int ek_fsidtype;
u32 ek_fsid[3]; u32 ek_fsid[3];
struct svc_export * ek_export; struct vfsmount * ek_mnt;
struct dentry * ek_dentry;
}; };
#define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
...@@ -114,22 +115,9 @@ static inline void exp_get(struct svc_export *exp) ...@@ -114,22 +115,9 @@ static inline void exp_get(struct svc_export *exp)
{ {
cache_get(&exp->h); cache_get(&exp->h);
} }
static inline struct svc_export * extern struct svc_export *
exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
struct cache_req *reqp) struct cache_req *reqp);
{
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
if (ek && !IS_ERR(ek)) {
struct svc_export *exp = ek->ek_export;
int err;
exp_get(exp);
expkey_put(&ek->h, &svc_expkey_cache);
if ((err = cache_check(&svc_export_cache, &exp->h, reqp)))
exp = ERR_PTR(err);
return exp;
} else
return ERR_PTR(PTR_ERR(ek));
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment