diff options
author | NeilBrown <neilb@suse.de> | 2006-03-27 04:15:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-27 11:44:41 -0500 |
commit | eab7e2e647c348b418e8715ecaca0177e1b473c7 (patch) | |
tree | 91aa453d6313eee89c8b19eea48699b1143264aa | |
parent | efc36aa5608f5717338747e152c23f2cfdb14697 (diff) |
[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>
-rw-r--r-- | fs/nfsd/export.c | 60 | ||||
-rw-r--r-- | include/linux/nfsd/export.h | 20 |
2 files changed, 44 insertions, 36 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index ac0997731fce..587829ed651c 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -73,8 +73,10 @@ void expkey_put(struct cache_head *item, struct cache_detail *cd) | |||
73 | if (cache_put(item, cd)) { | 73 | if (cache_put(item, cd)) { |
74 | struct svc_expkey *key = container_of(item, struct svc_expkey, h); | 74 | struct svc_expkey *key = container_of(item, struct svc_expkey, h); |
75 | if (test_bit(CACHE_VALID, &item->flags) && | 75 | if (test_bit(CACHE_VALID, &item->flags) && |
76 | !test_bit(CACHE_NEGATIVE, &item->flags)) | 76 | !test_bit(CACHE_NEGATIVE, &item->flags)) { |
77 | exp_put(key->ek_export); | 77 | dput(key->ek_dentry); |
78 | mntput(key->ek_mnt); | ||
79 | } | ||
78 | auth_domain_put(key->ek_client); | 80 | auth_domain_put(key->ek_client); |
79 | kfree(key); | 81 | kfree(key); |
80 | } | 82 | } |
@@ -164,26 +166,18 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
164 | } else { | 166 | } else { |
165 | struct nameidata nd; | 167 | struct nameidata nd; |
166 | struct svc_expkey *ek; | 168 | struct svc_expkey *ek; |
167 | struct svc_export *exp; | ||
168 | err = path_lookup(buf, 0, &nd); | 169 | err = path_lookup(buf, 0, &nd); |
169 | if (err) | 170 | if (err) |
170 | goto out; | 171 | goto out; |
171 | 172 | ||
172 | dprintk("Found the path %s\n", buf); | 173 | dprintk("Found the path %s\n", buf); |
173 | exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); | 174 | key.ek_mnt = nd.mnt; |
174 | 175 | key.ek_dentry = nd.dentry; | |
175 | err = -ENOENT; | ||
176 | if (!exp) | ||
177 | goto out_nd; | ||
178 | key.ek_export = exp; | ||
179 | dprintk("And found export\n"); | ||
180 | 176 | ||
181 | ek = svc_expkey_lookup(&key, 1); | 177 | ek = svc_expkey_lookup(&key, 1); |
182 | if (ek) | 178 | if (ek) |
183 | expkey_put(&ek->h, &svc_expkey_cache); | 179 | expkey_put(&ek->h, &svc_expkey_cache); |
184 | exp_put(exp); | ||
185 | err = 0; | 180 | err = 0; |
186 | out_nd: | ||
187 | path_release(&nd); | 181 | path_release(&nd); |
188 | } | 182 | } |
189 | cache_flush(); | 183 | cache_flush(); |
@@ -214,7 +208,7 @@ static int expkey_show(struct seq_file *m, | |||
214 | if (test_bit(CACHE_VALID, &h->flags) && | 208 | if (test_bit(CACHE_VALID, &h->flags) && |
215 | !test_bit(CACHE_NEGATIVE, &h->flags)) { | 209 | !test_bit(CACHE_NEGATIVE, &h->flags)) { |
216 | seq_printf(m, " "); | 210 | seq_printf(m, " "); |
217 | seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n"); | 211 | seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n"); |
218 | } | 212 | } |
219 | seq_printf(m, "\n"); | 213 | seq_printf(m, "\n"); |
220 | return 0; | 214 | return 0; |
@@ -252,8 +246,8 @@ static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *it | |||
252 | 246 | ||
253 | static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) | 247 | static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) |
254 | { | 248 | { |
255 | cache_get(&item->ek_export->h); | 249 | new->ek_mnt = mntget(item->ek_mnt); |
256 | new->ek_export = item->ek_export; | 250 | new->ek_dentry = dget(item->ek_dentry); |
257 | } | 251 | } |
258 | 252 | ||
259 | static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */ | 253 | 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 | key.ek_client = clp; | 513 | key.ek_client = clp; |
520 | key.ek_fsidtype = fsid_type; | 514 | key.ek_fsidtype = fsid_type; |
521 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | 515 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); |
522 | key.ek_export = exp; | 516 | key.ek_mnt = exp->ex_mnt; |
517 | key.ek_dentry = exp->ex_dentry; | ||
523 | key.h.expiry_time = NEVER; | 518 | key.h.expiry_time = NEVER; |
524 | key.h.flags = 0; | 519 | key.h.flags = 0; |
525 | 520 | ||
@@ -741,8 +736,8 @@ exp_export(struct nfsctl_export *nxp) | |||
741 | if ((nxp->ex_flags & NFSEXP_FSID) && | 736 | if ((nxp->ex_flags & NFSEXP_FSID) && |
742 | (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && | 737 | (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && |
743 | !IS_ERR(fsid_key) && | 738 | !IS_ERR(fsid_key) && |
744 | fsid_key->ek_export && | 739 | fsid_key->ek_mnt && |
745 | fsid_key->ek_export != exp) | 740 | (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) |
746 | goto finish; | 741 | goto finish; |
747 | 742 | ||
748 | if (exp) { | 743 | if (exp) { |
@@ -912,6 +907,24 @@ out: | |||
912 | return err; | 907 | return err; |
913 | } | 908 | } |
914 | 909 | ||
910 | struct svc_export * | ||
911 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | ||
912 | struct cache_req *reqp) | ||
913 | { | ||
914 | struct svc_export *exp; | ||
915 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | ||
916 | if (!ek || IS_ERR(ek)) | ||
917 | return ERR_PTR(PTR_ERR(ek)); | ||
918 | |||
919 | exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); | ||
920 | expkey_put(&ek->h, &svc_expkey_cache); | ||
921 | |||
922 | if (!exp || IS_ERR(exp)) | ||
923 | return ERR_PTR(PTR_ERR(exp)); | ||
924 | return exp; | ||
925 | } | ||
926 | |||
927 | |||
915 | /* | 928 | /* |
916 | * Called when we need the filehandle for the root of the pseudofs, | 929 | * Called when we need the filehandle for the root of the pseudofs, |
917 | * for a given NFSv4 client. The root is defined to be the | 930 | * 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 | struct cache_req *creq) | 935 | struct cache_req *creq) |
923 | { | 936 | { |
924 | struct svc_expkey *fsid_key; | 937 | struct svc_expkey *fsid_key; |
938 | struct svc_export *exp; | ||
925 | int rv; | 939 | int rv; |
926 | u32 fsidv[2]; | 940 | u32 fsidv[2]; |
927 | 941 | ||
@@ -933,8 +947,14 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |||
933 | if (!fsid_key || IS_ERR(fsid_key)) | 947 | if (!fsid_key || IS_ERR(fsid_key)) |
934 | return nfserr_perm; | 948 | return nfserr_perm; |
935 | 949 | ||
936 | rv = fh_compose(fhp, fsid_key->ek_export, | 950 | exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq); |
937 | fsid_key->ek_export->ex_dentry, NULL); | 951 | if (exp == NULL) |
952 | rv = nfserr_perm; | ||
953 | else if (IS_ERR(exp)) | ||
954 | rv = nfserrno(PTR_ERR(exp)); | ||
955 | else | ||
956 | rv = fh_compose(fhp, exp, | ||
957 | fsid_key->ek_dentry, NULL); | ||
938 | expkey_put(&fsid_key->h, &svc_expkey_cache); | 958 | expkey_put(&fsid_key->h, &svc_expkey_cache); |
939 | return rv; | 959 | return rv; |
940 | } | 960 | } |
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 6bad4766d3d9..d52e0b7ad37b 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h | |||
@@ -67,7 +67,8 @@ struct svc_expkey { | |||
67 | int ek_fsidtype; | 67 | int ek_fsidtype; |
68 | u32 ek_fsid[3]; | 68 | u32 ek_fsid[3]; |
69 | 69 | ||
70 | struct svc_export * ek_export; | 70 | struct vfsmount * ek_mnt; |
71 | struct dentry * ek_dentry; | ||
71 | }; | 72 | }; |
72 | 73 | ||
73 | #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) | 74 | #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) |
@@ -114,22 +115,9 @@ static inline void exp_get(struct svc_export *exp) | |||
114 | { | 115 | { |
115 | cache_get(&exp->h); | 116 | cache_get(&exp->h); |
116 | } | 117 | } |
117 | static inline struct svc_export * | 118 | extern struct svc_export * |
118 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | 119 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, |
119 | struct cache_req *reqp) | 120 | struct cache_req *reqp); |
120 | { | ||
121 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | ||
122 | if (ek && !IS_ERR(ek)) { | ||
123 | struct svc_export *exp = ek->ek_export; | ||
124 | int err; | ||
125 | exp_get(exp); | ||
126 | expkey_put(&ek->h, &svc_expkey_cache); | ||
127 | if ((err = cache_check(&svc_export_cache, &exp->h, reqp))) | ||
128 | exp = ERR_PTR(err); | ||
129 | return exp; | ||
130 | } else | ||
131 | return ERR_PTR(PTR_ERR(ek)); | ||
132 | } | ||
133 | 121 | ||
134 | #endif /* __KERNEL__ */ | 122 | #endif /* __KERNEL__ */ |
135 | 123 | ||