[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: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Родитель
efc36aa560
Коммит
eab7e2e647
|
@ -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)
|
||||||
} 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,
|
||||||
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
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
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 @@ out:
|
||||||
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,
|
||||||
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,
|
||||||
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 {
|
||||||
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)
|
||||||
{
|
{
|
||||||
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__ */
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче