aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-03-27 04:14:59 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-27 11:44:41 -0500
commitefc36aa5608f5717338747e152c23f2cfdb14697 (patch)
treeab444f6e6c88ed07a8d5a034777c10de50e663fd
parent3e7b19198003fc25b11838e709f17d4fa173b2d7 (diff)
[PATCH] knfsd: Change the store of auth_domains to not be a 'cache'
The 'auth_domain's are simply handles on internal data structures. They do not cache information from user-space, and forcing them into the mold of a 'cache' misrepresents their true nature and causes confusion. 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.c5
-rw-r--r--include/linux/sunrpc/svcauth.h12
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c14
-rw-r--r--net/sunrpc/sunrpc_syms.c4
-rw-r--r--net/sunrpc/svcauth.c122
-rw-r--r--net/sunrpc/svcauth_unix.c69
6 files changed, 81 insertions, 145 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 417ec02df44f..ac0997731fce 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -242,7 +242,7 @@ static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b)
242 242
243static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item) 243static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item)
244{ 244{
245 cache_get(&item->ek_client->h); 245 kref_get(&item->ek_client->ref);
246 new->ek_client = item->ek_client; 246 new->ek_client = item->ek_client;
247 new->ek_fsidtype = item->ek_fsidtype; 247 new->ek_fsidtype = item->ek_fsidtype;
248 new->ek_fsid[0] = item->ek_fsid[0]; 248 new->ek_fsid[0] = item->ek_fsid[0];
@@ -474,7 +474,7 @@ static inline int svc_export_match(struct svc_export *a, struct svc_export *b)
474} 474}
475static inline void svc_export_init(struct svc_export *new, struct svc_export *item) 475static inline void svc_export_init(struct svc_export *new, struct svc_export *item)
476{ 476{
477 cache_get(&item->ex_client->h); 477 kref_get(&item->ex_client->ref);
478 new->ex_client = item->ex_client; 478 new->ex_client = item->ex_client;
479 new->ex_dentry = dget(item->ex_dentry); 479 new->ex_dentry = dget(item->ex_dentry);
480 new->ex_mnt = mntget(item->ex_mnt); 480 new->ex_mnt = mntget(item->ex_mnt);
@@ -1129,7 +1129,6 @@ exp_delclient(struct nfsctl_client *ncp)
1129 */ 1129 */
1130 if (dom) { 1130 if (dom) {
1131 err = auth_unix_forget_old(dom); 1131 err = auth_unix_forget_old(dom);
1132 dom->h.expiry_time = get_seconds();
1133 auth_domain_put(dom); 1132 auth_domain_put(dom);
1134 } 1133 }
1135 1134
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index c119ce7cbd22..2fe2087edd66 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -45,9 +45,10 @@ struct svc_rqst; /* forward decl */
45 * of ip addresses to the given client. 45 * of ip addresses to the given client.
46 */ 46 */
47struct auth_domain { 47struct auth_domain {
48 struct cache_head h; 48 struct kref ref;
49 struct hlist_node hash;
49 char *name; 50 char *name;
50 int flavour; 51 struct auth_ops *flavour;
51}; 52};
52 53
53/* 54/*
@@ -86,6 +87,9 @@ struct auth_domain {
86 * 87 *
87 * domain_release() 88 * domain_release()
88 * This call releases a domain. 89 * This call releases a domain.
90 * set_client()
91 * Givens a pending request (struct svc_rqst), finds and assigns
92 * an appropriate 'auth_domain' as the client.
89 */ 93 */
90struct auth_ops { 94struct auth_ops {
91 char * name; 95 char * name;
@@ -117,7 +121,7 @@ extern void svc_auth_unregister(rpc_authflavor_t flavor);
117extern struct auth_domain *unix_domain_find(char *name); 121extern struct auth_domain *unix_domain_find(char *name);
118extern void auth_domain_put(struct auth_domain *item); 122extern void auth_domain_put(struct auth_domain *item);
119extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom); 123extern int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom);
120extern struct auth_domain *auth_domain_lookup(struct auth_domain *item, int set); 124extern struct auth_domain *auth_domain_lookup(char *name, struct auth_domain *new);
121extern struct auth_domain *auth_domain_find(char *name); 125extern struct auth_domain *auth_domain_find(char *name);
122extern struct auth_domain *auth_unix_lookup(struct in_addr addr); 126extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
123extern int auth_unix_forget_old(struct auth_domain *dom); 127extern int auth_unix_forget_old(struct auth_domain *dom);
@@ -160,8 +164,6 @@ static inline unsigned long hash_mem(char *buf, int length, int bits)
160 return hash >> (BITS_PER_LONG - bits); 164 return hash >> (BITS_PER_LONG - bits);
161} 165}
162 166
163extern struct cache_detail auth_domain_cache, ip_map_cache;
164
165#endif /* __KERNEL__ */ 167#endif /* __KERNEL__ */
166 168
167#endif /* _LINUX_SUNRPC_SVCAUTH_H_ */ 169#endif /* _LINUX_SUNRPC_SVCAUTH_H_ */
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 23632d84d8d7..6b073c2e6930 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -645,6 +645,8 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
645 return auth_domain_find(name); 645 return auth_domain_find(name);
646} 646}
647 647
648static struct auth_ops svcauthops_gss;
649
648int 650int
649svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) 651svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
650{ 652{
@@ -655,20 +657,18 @@ svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
655 new = kmalloc(sizeof(*new), GFP_KERNEL); 657 new = kmalloc(sizeof(*new), GFP_KERNEL);
656 if (!new) 658 if (!new)
657 goto out; 659 goto out;
658 cache_init(&new->h.h); 660 kref_init(&new->h.ref);
659 new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL); 661 new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL);
660 if (!new->h.name) 662 if (!new->h.name)
661 goto out_free_dom; 663 goto out_free_dom;
662 strcpy(new->h.name, name); 664 strcpy(new->h.name, name);
663 new->h.flavour = RPC_AUTH_GSS; 665 new->h.flavour = &svcauthops_gss;
664 new->pseudoflavor = pseudoflavor; 666 new->pseudoflavor = pseudoflavor;
665 new->h.h.expiry_time = NEVER;
666 667
667 test = auth_domain_lookup(&new->h, 1); 668 test = auth_domain_lookup(name, &new->h);
668 if (test == &new->h) { 669 if (test != &new->h) { /* XXX Duplicate registration? */
669 BUG_ON(atomic_dec_and_test(&new->h.h.refcnt));
670 } else { /* XXX Duplicate registration? */
671 auth_domain_put(&new->h); 670 auth_domain_put(&new->h);
671 /* dangling ref-count... */
672 goto out; 672 goto out;
673 } 673 }
674 return 0; 674 return 0;
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 9f7373203592..40401196e7de 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -142,6 +142,7 @@ EXPORT_SYMBOL(nlm_debug);
142 142
143extern int register_rpc_pipefs(void); 143extern int register_rpc_pipefs(void);
144extern void unregister_rpc_pipefs(void); 144extern void unregister_rpc_pipefs(void);
145extern struct cache_detail ip_map_cache;
145 146
146static int __init 147static int __init
147init_sunrpc(void) 148init_sunrpc(void)
@@ -158,7 +159,6 @@ init_sunrpc(void)
158#ifdef CONFIG_PROC_FS 159#ifdef CONFIG_PROC_FS
159 rpc_proc_init(); 160 rpc_proc_init();
160#endif 161#endif
161 cache_register(&auth_domain_cache);
162 cache_register(&ip_map_cache); 162 cache_register(&ip_map_cache);
163out: 163out:
164 return err; 164 return err;
@@ -169,8 +169,6 @@ cleanup_sunrpc(void)
169{ 169{
170 unregister_rpc_pipefs(); 170 unregister_rpc_pipefs();
171 rpc_destroy_mempool(); 171 rpc_destroy_mempool();
172 if (cache_unregister(&auth_domain_cache))
173 printk(KERN_ERR "sunrpc: failed to unregister auth_domain cache\n");
174 if (cache_unregister(&ip_map_cache)) 172 if (cache_unregister(&ip_map_cache))
175 printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n"); 173 printk(KERN_ERR "sunrpc: failed to unregister ip_map cache\n");
176#ifdef RPC_DEBUG 174#ifdef RPC_DEBUG
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index dda4f0c63511..5b28c6176806 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -106,112 +106,56 @@ svc_auth_unregister(rpc_authflavor_t flavor)
106EXPORT_SYMBOL(svc_auth_unregister); 106EXPORT_SYMBOL(svc_auth_unregister);
107 107
108/************************************************** 108/**************************************************
109 * cache for domain name to auth_domain 109 * 'auth_domains' are stored in a hash table indexed by name.
110 * Entries are only added by flavours which will normally 110 * When the last reference to an 'auth_domain' is dropped,
111 * have a structure that 'inherits' from auth_domain. 111 * the object is unhashed and freed.
112 * e.g. when an IP -> domainname is given to auth_unix, 112 * If auth_domain_lookup fails to find an entry, it will return
113 * and the domain name doesn't exist, it will create a 113 * it's second argument 'new'. If this is non-null, it will
114 * auth_unix_domain and add it to this hash table. 114 * have been atomically linked into the table.
115 * If it finds the name does exist, but isn't AUTH_UNIX,
116 * it will complain.
117 */ 115 */
118 116
119/*
120 * Auth auth_domain cache is somewhat different to other caches,
121 * largely because the entries are possibly of different types:
122 * each auth flavour has it's own type.
123 * One consequence of this that DefineCacheLookup cannot
124 * allocate a new structure as it cannot know the size.
125 * Notice that the "INIT" code fragment is quite different
126 * from other caches. When auth_domain_lookup might be
127 * creating a new domain, the new domain is passed in
128 * complete and it is used as-is rather than being copied into
129 * another structure.
130 */
131#define DN_HASHBITS 6 117#define DN_HASHBITS 6
132#define DN_HASHMAX (1<<DN_HASHBITS) 118#define DN_HASHMAX (1<<DN_HASHBITS)
133#define DN_HASHMASK (DN_HASHMAX-1) 119#define DN_HASHMASK (DN_HASHMAX-1)
134 120
135static struct cache_head *auth_domain_table[DN_HASHMAX]; 121static struct hlist_head auth_domain_table[DN_HASHMAX];
136 122static spinlock_t auth_domain_lock = SPIN_LOCK_UNLOCKED;
137static void auth_domain_drop(struct cache_head *item, struct cache_detail *cd)
138{
139 struct auth_domain *dom = container_of(item, struct auth_domain, h);
140 if (cache_put(item,cd))
141 authtab[dom->flavour]->domain_release(dom);
142}
143
144
145struct cache_detail auth_domain_cache = {
146 .owner = THIS_MODULE,
147 .hash_size = DN_HASHMAX,
148 .hash_table = auth_domain_table,
149 .name = "auth.domain",
150 .cache_put = auth_domain_drop,
151};
152 123
153void auth_domain_put(struct auth_domain *dom) 124void auth_domain_put(struct auth_domain *dom)
154{ 125{
155 auth_domain_drop(&dom->h, &auth_domain_cache); 126 if (atomic_dec_and_lock(&dom->ref.refcount, &auth_domain_lock)) {
156} 127 hlist_del(&dom->hash);
157 128 dom->flavour->domain_release(dom);
158static inline int auth_domain_hash(struct auth_domain *item) 129 }
159{
160 return hash_str(item->name, DN_HASHBITS);
161}
162static inline int auth_domain_match(struct auth_domain *tmp, struct auth_domain *item)
163{
164 return strcmp(tmp->name, item->name) == 0;
165} 130}
166 131
167struct auth_domain * 132struct auth_domain *
168auth_domain_lookup(struct auth_domain *item, int set) 133auth_domain_lookup(char *name, struct auth_domain *new)
169{ 134{
170 struct auth_domain *tmp = NULL; 135 struct auth_domain *hp;
171 struct cache_head **hp, **head; 136 struct hlist_head *head;
172 head = &auth_domain_cache.hash_table[auth_domain_hash(item)]; 137 struct hlist_node *np;
173 138
174 if (set) 139 head = &auth_domain_table[hash_str(name, DN_HASHBITS)];
175 write_lock(&auth_domain_cache.hash_lock); 140
176 else 141 spin_lock(&auth_domain_lock);
177 read_lock(&auth_domain_cache.hash_lock); 142
178 for (hp=head; *hp != NULL; hp = &tmp->h.next) { 143 hlist_for_each_entry(hp, np, head, hash) {
179 tmp = container_of(*hp, struct auth_domain, h); 144 if (strcmp(hp->name, name)==0) {
180 if (!auth_domain_match(tmp, item)) 145 kref_get(&hp->ref);
181 continue; 146 spin_unlock(&auth_domain_lock);
182 if (!set) { 147 return hp;
183 cache_get(&tmp->h);
184 goto out_noset;
185 } 148 }
186 *hp = tmp->h.next;
187 tmp->h.next = NULL;
188 auth_domain_drop(&tmp->h, &auth_domain_cache);
189 goto out_set;
190 } 149 }
191 /* Didn't find anything */ 150 if (new) {
192 if (!set) 151 hlist_add_head(&new->hash, head);
193 goto out_nada; 152 kref_get(&new->ref);
194 auth_domain_cache.entries++; 153 }
195out_set: 154 spin_unlock(&auth_domain_lock);
196 item->h.next = *head; 155 return new;
197 *head = &item->h;
198 cache_get(&item->h);
199 write_unlock(&auth_domain_cache.hash_lock);
200 cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time);
201 cache_get(&item->h);
202 return item;
203out_nada:
204 tmp = NULL;
205out_noset:
206 read_unlock(&auth_domain_cache.hash_lock);
207 return tmp;
208} 156}
209 157
210struct auth_domain *auth_domain_find(char *name) 158struct auth_domain *auth_domain_find(char *name)
211{ 159{
212 struct auth_domain *rv, ad; 160 return auth_domain_lookup(name, NULL);
213
214 ad.name = name;
215 rv = auth_domain_lookup(&ad, 0);
216 return rv;
217} 161}
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 3e6c694bbad1..17e8b2a3130c 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -27,41 +27,35 @@ struct unix_domain {
27 /* other stuff later */ 27 /* other stuff later */
28}; 28};
29 29
30extern struct auth_ops svcauth_unix;
31
30struct auth_domain *unix_domain_find(char *name) 32struct auth_domain *unix_domain_find(char *name)
31{ 33{
32 struct auth_domain *rv, ud; 34 struct auth_domain *rv;
33 struct unix_domain *new; 35 struct unix_domain *new = NULL;
34 36
35 ud.name = name; 37 rv = auth_domain_lookup(name, NULL);
36 38 while(1) {
37 rv = auth_domain_lookup(&ud, 0); 39 if (rv != &new->h) {
38 40 if (new) auth_domain_put(&new->h);
39 foundit: 41 return rv;
40 if (rv && rv->flavour != RPC_AUTH_UNIX) { 42 }
41 auth_domain_put(rv); 43 if (rv && rv->flavour != &svcauth_unix) {
42 return NULL; 44 auth_domain_put(rv);
43 } 45 return NULL;
44 if (rv) 46 }
45 return rv; 47 if (rv)
46 48 return rv;
47 new = kmalloc(sizeof(*new), GFP_KERNEL); 49
48 if (new == NULL) 50 new = kmalloc(sizeof(*new), GFP_KERNEL);
49 return NULL; 51 if (new == NULL)
50 cache_init(&new->h.h); 52 return NULL;
51 new->h.name = kstrdup(name, GFP_KERNEL); 53 kref_init(&new->h.ref);
52 new->h.flavour = RPC_AUTH_UNIX; 54 new->h.name = kstrdup(name, GFP_KERNEL);
53 new->addr_changes = 0; 55 new->h.flavour = &svcauth_unix;
54 new->h.h.expiry_time = NEVER; 56 new->addr_changes = 0;
55 57 rv = auth_domain_lookup(name, &new->h);
56 rv = auth_domain_lookup(&new->h, 2);
57 if (rv == &new->h) {
58 if (atomic_dec_and_test(&new->h.h.refcnt)) BUG();
59 } else {
60 auth_domain_put(&new->h);
61 goto foundit;
62 } 58 }
63
64 return rv;
65} 59}
66 60
67static void svcauth_unix_domain_release(struct auth_domain *dom) 61static void svcauth_unix_domain_release(struct auth_domain *dom)
@@ -130,7 +124,7 @@ static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
130} 124}
131static inline void ip_map_update(struct ip_map *new, struct ip_map *item) 125static inline void ip_map_update(struct ip_map *new, struct ip_map *item)
132{ 126{
133 cache_get(&item->m_client->h.h); 127 kref_get(&item->m_client->h.ref);
134 new->m_client = item->m_client; 128 new->m_client = item->m_client;
135 new->m_add_change = item->m_add_change; 129 new->m_add_change = item->m_add_change;
136} 130}
@@ -272,7 +266,7 @@ int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
272 struct unix_domain *udom; 266 struct unix_domain *udom;
273 struct ip_map ip, *ipmp; 267 struct ip_map ip, *ipmp;
274 268
275 if (dom->flavour != RPC_AUTH_UNIX) 269 if (dom->flavour != &svcauth_unix)
276 return -EINVAL; 270 return -EINVAL;
277 udom = container_of(dom, struct unix_domain, h); 271 udom = container_of(dom, struct unix_domain, h);
278 strcpy(ip.m_class, "nfsd"); 272 strcpy(ip.m_class, "nfsd");
@@ -295,7 +289,7 @@ int auth_unix_forget_old(struct auth_domain *dom)
295{ 289{
296 struct unix_domain *udom; 290 struct unix_domain *udom;
297 291
298 if (dom->flavour != RPC_AUTH_UNIX) 292 if (dom->flavour != &svcauth_unix)
299 return -EINVAL; 293 return -EINVAL;
300 udom = container_of(dom, struct unix_domain, h); 294 udom = container_of(dom, struct unix_domain, h);
301 udom->addr_changes++; 295 udom->addr_changes++;
@@ -323,7 +317,7 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr)
323 rv = NULL; 317 rv = NULL;
324 } else { 318 } else {
325 rv = &ipm->m_client->h; 319 rv = &ipm->m_client->h;
326 cache_get(&rv->h); 320 kref_get(&rv->ref);
327 } 321 }
328 ip_map_put(&ipm->h, &ip_map_cache); 322 ip_map_put(&ipm->h, &ip_map_cache);
329 return rv; 323 return rv;
@@ -332,7 +326,6 @@ struct auth_domain *auth_unix_lookup(struct in_addr addr)
332void svcauth_unix_purge(void) 326void svcauth_unix_purge(void)
333{ 327{
334 cache_purge(&ip_map_cache); 328 cache_purge(&ip_map_cache);
335 cache_purge(&auth_domain_cache);
336} 329}
337 330
338static int 331static int
@@ -361,7 +354,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
361 return SVC_DENIED; 354 return SVC_DENIED;
362 case 0: 355 case 0:
363 rqstp->rq_client = &ipm->m_client->h; 356 rqstp->rq_client = &ipm->m_client->h;
364 cache_get(&rqstp->rq_client->h); 357 kref_get(&rqstp->rq_client->ref);
365 ip_map_put(&ipm->h, &ip_map_cache); 358 ip_map_put(&ipm->h, &ip_map_cache);
366 break; 359 break;
367 } 360 }