diff options
Diffstat (limited to 'net/sunrpc/auth.c')
-rw-r--r-- | net/sunrpc/auth.c | 370 |
1 files changed, 256 insertions, 114 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 9527f2bb1744..aa55d0a03e6f 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -13,17 +13,22 @@ | |||
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/sunrpc/clnt.h> | 14 | #include <linux/sunrpc/clnt.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/smp_lock.h> | ||
16 | 17 | ||
17 | #ifdef RPC_DEBUG | 18 | #ifdef RPC_DEBUG |
18 | # define RPCDBG_FACILITY RPCDBG_AUTH | 19 | # define RPCDBG_FACILITY RPCDBG_AUTH |
19 | #endif | 20 | #endif |
20 | 21 | ||
21 | static struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = { | 22 | static DEFINE_SPINLOCK(rpc_authflavor_lock); |
23 | static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | ||
22 | &authnull_ops, /* AUTH_NULL */ | 24 | &authnull_ops, /* AUTH_NULL */ |
23 | &authunix_ops, /* AUTH_UNIX */ | 25 | &authunix_ops, /* AUTH_UNIX */ |
24 | NULL, /* others can be loadable modules */ | 26 | NULL, /* others can be loadable modules */ |
25 | }; | 27 | }; |
26 | 28 | ||
29 | static LIST_HEAD(cred_unused); | ||
30 | static unsigned long number_cred_unused; | ||
31 | |||
27 | static u32 | 32 | static u32 |
28 | pseudoflavor_to_flavor(u32 flavor) { | 33 | pseudoflavor_to_flavor(u32 flavor) { |
29 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 34 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
@@ -32,55 +37,67 @@ pseudoflavor_to_flavor(u32 flavor) { | |||
32 | } | 37 | } |
33 | 38 | ||
34 | int | 39 | int |
35 | rpcauth_register(struct rpc_authops *ops) | 40 | rpcauth_register(const struct rpc_authops *ops) |
36 | { | 41 | { |
37 | rpc_authflavor_t flavor; | 42 | rpc_authflavor_t flavor; |
43 | int ret = -EPERM; | ||
38 | 44 | ||
39 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | 45 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) |
40 | return -EINVAL; | 46 | return -EINVAL; |
41 | if (auth_flavors[flavor] != NULL) | 47 | spin_lock(&rpc_authflavor_lock); |
42 | return -EPERM; /* what else? */ | 48 | if (auth_flavors[flavor] == NULL) { |
43 | auth_flavors[flavor] = ops; | 49 | auth_flavors[flavor] = ops; |
44 | return 0; | 50 | ret = 0; |
51 | } | ||
52 | spin_unlock(&rpc_authflavor_lock); | ||
53 | return ret; | ||
45 | } | 54 | } |
46 | 55 | ||
47 | int | 56 | int |
48 | rpcauth_unregister(struct rpc_authops *ops) | 57 | rpcauth_unregister(const struct rpc_authops *ops) |
49 | { | 58 | { |
50 | rpc_authflavor_t flavor; | 59 | rpc_authflavor_t flavor; |
60 | int ret = -EPERM; | ||
51 | 61 | ||
52 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | 62 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) |
53 | return -EINVAL; | 63 | return -EINVAL; |
54 | if (auth_flavors[flavor] != ops) | 64 | spin_lock(&rpc_authflavor_lock); |
55 | return -EPERM; /* what else? */ | 65 | if (auth_flavors[flavor] == ops) { |
56 | auth_flavors[flavor] = NULL; | 66 | auth_flavors[flavor] = NULL; |
57 | return 0; | 67 | ret = 0; |
68 | } | ||
69 | spin_unlock(&rpc_authflavor_lock); | ||
70 | return ret; | ||
58 | } | 71 | } |
59 | 72 | ||
60 | struct rpc_auth * | 73 | struct rpc_auth * |
61 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | 74 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) |
62 | { | 75 | { |
63 | struct rpc_auth *auth; | 76 | struct rpc_auth *auth; |
64 | struct rpc_authops *ops; | 77 | const struct rpc_authops *ops; |
65 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | 78 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); |
66 | 79 | ||
67 | auth = ERR_PTR(-EINVAL); | 80 | auth = ERR_PTR(-EINVAL); |
68 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 81 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
69 | goto out; | 82 | goto out; |
70 | 83 | ||
71 | /* FIXME - auth_flavors[] really needs an rw lock, | ||
72 | * and module refcounting. */ | ||
73 | #ifdef CONFIG_KMOD | 84 | #ifdef CONFIG_KMOD |
74 | if ((ops = auth_flavors[flavor]) == NULL) | 85 | if ((ops = auth_flavors[flavor]) == NULL) |
75 | request_module("rpc-auth-%u", flavor); | 86 | request_module("rpc-auth-%u", flavor); |
76 | #endif | 87 | #endif |
77 | if ((ops = auth_flavors[flavor]) == NULL) | 88 | spin_lock(&rpc_authflavor_lock); |
89 | ops = auth_flavors[flavor]; | ||
90 | if (ops == NULL || !try_module_get(ops->owner)) { | ||
91 | spin_unlock(&rpc_authflavor_lock); | ||
78 | goto out; | 92 | goto out; |
93 | } | ||
94 | spin_unlock(&rpc_authflavor_lock); | ||
79 | auth = ops->create(clnt, pseudoflavor); | 95 | auth = ops->create(clnt, pseudoflavor); |
96 | module_put(ops->owner); | ||
80 | if (IS_ERR(auth)) | 97 | if (IS_ERR(auth)) |
81 | return auth; | 98 | return auth; |
82 | if (clnt->cl_auth) | 99 | if (clnt->cl_auth) |
83 | rpcauth_destroy(clnt->cl_auth); | 100 | rpcauth_release(clnt->cl_auth); |
84 | clnt->cl_auth = auth; | 101 | clnt->cl_auth = auth; |
85 | 102 | ||
86 | out: | 103 | out: |
@@ -88,7 +105,7 @@ out: | |||
88 | } | 105 | } |
89 | 106 | ||
90 | void | 107 | void |
91 | rpcauth_destroy(struct rpc_auth *auth) | 108 | rpcauth_release(struct rpc_auth *auth) |
92 | { | 109 | { |
93 | if (!atomic_dec_and_test(&auth->au_count)) | 110 | if (!atomic_dec_and_test(&auth->au_count)) |
94 | return; | 111 | return; |
@@ -97,11 +114,31 @@ rpcauth_destroy(struct rpc_auth *auth) | |||
97 | 114 | ||
98 | static DEFINE_SPINLOCK(rpc_credcache_lock); | 115 | static DEFINE_SPINLOCK(rpc_credcache_lock); |
99 | 116 | ||
117 | static void | ||
118 | rpcauth_unhash_cred_locked(struct rpc_cred *cred) | ||
119 | { | ||
120 | hlist_del_rcu(&cred->cr_hash); | ||
121 | smp_mb__before_clear_bit(); | ||
122 | clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | rpcauth_unhash_cred(struct rpc_cred *cred) | ||
127 | { | ||
128 | spinlock_t *cache_lock; | ||
129 | |||
130 | cache_lock = &cred->cr_auth->au_credcache->lock; | ||
131 | spin_lock(cache_lock); | ||
132 | if (atomic_read(&cred->cr_count) == 0) | ||
133 | rpcauth_unhash_cred_locked(cred); | ||
134 | spin_unlock(cache_lock); | ||
135 | } | ||
136 | |||
100 | /* | 137 | /* |
101 | * Initialize RPC credential cache | 138 | * Initialize RPC credential cache |
102 | */ | 139 | */ |
103 | int | 140 | int |
104 | rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | 141 | rpcauth_init_credcache(struct rpc_auth *auth) |
105 | { | 142 | { |
106 | struct rpc_cred_cache *new; | 143 | struct rpc_cred_cache *new; |
107 | int i; | 144 | int i; |
@@ -111,8 +148,7 @@ rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | |||
111 | return -ENOMEM; | 148 | return -ENOMEM; |
112 | for (i = 0; i < RPC_CREDCACHE_NR; i++) | 149 | for (i = 0; i < RPC_CREDCACHE_NR; i++) |
113 | INIT_HLIST_HEAD(&new->hashtable[i]); | 150 | INIT_HLIST_HEAD(&new->hashtable[i]); |
114 | new->expire = expire; | 151 | spin_lock_init(&new->lock); |
115 | new->nextgc = jiffies + (expire >> 1); | ||
116 | auth->au_credcache = new; | 152 | auth->au_credcache = new; |
117 | return 0; | 153 | return 0; |
118 | } | 154 | } |
@@ -121,13 +157,13 @@ rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | |||
121 | * Destroy a list of credentials | 157 | * Destroy a list of credentials |
122 | */ | 158 | */ |
123 | static inline | 159 | static inline |
124 | void rpcauth_destroy_credlist(struct hlist_head *head) | 160 | void rpcauth_destroy_credlist(struct list_head *head) |
125 | { | 161 | { |
126 | struct rpc_cred *cred; | 162 | struct rpc_cred *cred; |
127 | 163 | ||
128 | while (!hlist_empty(head)) { | 164 | while (!list_empty(head)) { |
129 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | 165 | cred = list_entry(head->next, struct rpc_cred, cr_lru); |
130 | hlist_del_init(&cred->cr_hash); | 166 | list_del_init(&cred->cr_lru); |
131 | put_rpccred(cred); | 167 | put_rpccred(cred); |
132 | } | 168 | } |
133 | } | 169 | } |
@@ -137,58 +173,95 @@ void rpcauth_destroy_credlist(struct hlist_head *head) | |||
137 | * that are not referenced. | 173 | * that are not referenced. |
138 | */ | 174 | */ |
139 | void | 175 | void |
140 | rpcauth_free_credcache(struct rpc_auth *auth) | 176 | rpcauth_clear_credcache(struct rpc_cred_cache *cache) |
141 | { | 177 | { |
142 | struct rpc_cred_cache *cache = auth->au_credcache; | 178 | LIST_HEAD(free); |
143 | HLIST_HEAD(free); | 179 | struct hlist_head *head; |
144 | struct hlist_node *pos, *next; | ||
145 | struct rpc_cred *cred; | 180 | struct rpc_cred *cred; |
146 | int i; | 181 | int i; |
147 | 182 | ||
148 | spin_lock(&rpc_credcache_lock); | 183 | spin_lock(&rpc_credcache_lock); |
184 | spin_lock(&cache->lock); | ||
149 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | 185 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { |
150 | hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | 186 | head = &cache->hashtable[i]; |
151 | cred = hlist_entry(pos, struct rpc_cred, cr_hash); | 187 | while (!hlist_empty(head)) { |
152 | __hlist_del(&cred->cr_hash); | 188 | cred = hlist_entry(head->first, struct rpc_cred, cr_hash); |
153 | hlist_add_head(&cred->cr_hash, &free); | 189 | get_rpccred(cred); |
190 | if (!list_empty(&cred->cr_lru)) { | ||
191 | list_del(&cred->cr_lru); | ||
192 | number_cred_unused--; | ||
193 | } | ||
194 | list_add_tail(&cred->cr_lru, &free); | ||
195 | rpcauth_unhash_cred_locked(cred); | ||
154 | } | 196 | } |
155 | } | 197 | } |
198 | spin_unlock(&cache->lock); | ||
156 | spin_unlock(&rpc_credcache_lock); | 199 | spin_unlock(&rpc_credcache_lock); |
157 | rpcauth_destroy_credlist(&free); | 200 | rpcauth_destroy_credlist(&free); |
158 | } | 201 | } |
159 | 202 | ||
160 | static void | 203 | /* |
161 | rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free) | 204 | * Destroy the RPC credential cache |
205 | */ | ||
206 | void | ||
207 | rpcauth_destroy_credcache(struct rpc_auth *auth) | ||
162 | { | 208 | { |
163 | if (atomic_read(&cred->cr_count) != 1) | 209 | struct rpc_cred_cache *cache = auth->au_credcache; |
164 | return; | 210 | |
165 | if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire)) | 211 | if (cache) { |
166 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 212 | auth->au_credcache = NULL; |
167 | if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) { | 213 | rpcauth_clear_credcache(cache); |
168 | __hlist_del(&cred->cr_hash); | 214 | kfree(cache); |
169 | hlist_add_head(&cred->cr_hash, free); | ||
170 | } | 215 | } |
171 | } | 216 | } |
172 | 217 | ||
173 | /* | 218 | /* |
174 | * Remove stale credentials. Avoid sleeping inside the loop. | 219 | * Remove stale credentials. Avoid sleeping inside the loop. |
175 | */ | 220 | */ |
176 | static void | 221 | static int |
177 | rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) | 222 | rpcauth_prune_expired(struct list_head *free, int nr_to_scan) |
178 | { | 223 | { |
179 | struct rpc_cred_cache *cache = auth->au_credcache; | 224 | spinlock_t *cache_lock; |
180 | struct hlist_node *pos, *next; | 225 | struct rpc_cred *cred; |
181 | struct rpc_cred *cred; | ||
182 | int i; | ||
183 | 226 | ||
184 | dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); | 227 | while (!list_empty(&cred_unused)) { |
185 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | 228 | cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); |
186 | hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | 229 | list_del_init(&cred->cr_lru); |
187 | cred = hlist_entry(pos, struct rpc_cred, cr_hash); | 230 | number_cred_unused--; |
188 | rpcauth_prune_expired(auth, cred, free); | 231 | if (atomic_read(&cred->cr_count) != 0) |
232 | continue; | ||
233 | cache_lock = &cred->cr_auth->au_credcache->lock; | ||
234 | spin_lock(cache_lock); | ||
235 | if (atomic_read(&cred->cr_count) == 0) { | ||
236 | get_rpccred(cred); | ||
237 | list_add_tail(&cred->cr_lru, free); | ||
238 | rpcauth_unhash_cred_locked(cred); | ||
239 | nr_to_scan--; | ||
189 | } | 240 | } |
241 | spin_unlock(cache_lock); | ||
242 | if (nr_to_scan == 0) | ||
243 | break; | ||
190 | } | 244 | } |
191 | cache->nextgc = jiffies + cache->expire; | 245 | return nr_to_scan; |
246 | } | ||
247 | |||
248 | /* | ||
249 | * Run memory cache shrinker. | ||
250 | */ | ||
251 | static int | ||
252 | rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | ||
253 | { | ||
254 | LIST_HEAD(free); | ||
255 | int res; | ||
256 | |||
257 | if (list_empty(&cred_unused)) | ||
258 | return 0; | ||
259 | spin_lock(&rpc_credcache_lock); | ||
260 | nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan); | ||
261 | res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure; | ||
262 | spin_unlock(&rpc_credcache_lock); | ||
263 | rpcauth_destroy_credlist(&free); | ||
264 | return res; | ||
192 | } | 265 | } |
193 | 266 | ||
194 | /* | 267 | /* |
@@ -198,53 +271,56 @@ struct rpc_cred * | |||
198 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | 271 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, |
199 | int flags) | 272 | int flags) |
200 | { | 273 | { |
274 | LIST_HEAD(free); | ||
201 | struct rpc_cred_cache *cache = auth->au_credcache; | 275 | struct rpc_cred_cache *cache = auth->au_credcache; |
202 | HLIST_HEAD(free); | 276 | struct hlist_node *pos; |
203 | struct hlist_node *pos, *next; | 277 | struct rpc_cred *cred = NULL, |
204 | struct rpc_cred *new = NULL, | 278 | *entry, *new; |
205 | *cred = NULL; | ||
206 | int nr = 0; | 279 | int nr = 0; |
207 | 280 | ||
208 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) | 281 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) |
209 | nr = acred->uid & RPC_CREDCACHE_MASK; | 282 | nr = acred->uid & RPC_CREDCACHE_MASK; |
210 | retry: | 283 | |
211 | spin_lock(&rpc_credcache_lock); | 284 | rcu_read_lock(); |
212 | if (time_before(cache->nextgc, jiffies)) | 285 | hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { |
213 | rpcauth_gc_credcache(auth, &free); | 286 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
214 | hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { | 287 | continue; |
215 | struct rpc_cred *entry; | 288 | spin_lock(&cache->lock); |
216 | entry = hlist_entry(pos, struct rpc_cred, cr_hash); | 289 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { |
217 | if (entry->cr_ops->crmatch(acred, entry, flags)) { | 290 | spin_unlock(&cache->lock); |
218 | hlist_del(&entry->cr_hash); | 291 | continue; |
219 | cred = entry; | ||
220 | break; | ||
221 | } | 292 | } |
222 | rpcauth_prune_expired(auth, entry, &free); | 293 | cred = get_rpccred(entry); |
294 | spin_unlock(&cache->lock); | ||
295 | break; | ||
223 | } | 296 | } |
224 | if (new) { | 297 | rcu_read_unlock(); |
225 | if (cred) | ||
226 | hlist_add_head(&new->cr_hash, &free); | ||
227 | else | ||
228 | cred = new; | ||
229 | } | ||
230 | if (cred) { | ||
231 | hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); | ||
232 | get_rpccred(cred); | ||
233 | } | ||
234 | spin_unlock(&rpc_credcache_lock); | ||
235 | 298 | ||
236 | rpcauth_destroy_credlist(&free); | 299 | if (cred != NULL) |
300 | goto found; | ||
237 | 301 | ||
238 | if (!cred) { | 302 | new = auth->au_ops->crcreate(auth, acred, flags); |
239 | new = auth->au_ops->crcreate(auth, acred, flags); | 303 | if (IS_ERR(new)) { |
240 | if (!IS_ERR(new)) { | 304 | cred = new; |
241 | #ifdef RPC_DEBUG | 305 | goto out; |
242 | new->cr_magic = RPCAUTH_CRED_MAGIC; | 306 | } |
243 | #endif | 307 | |
244 | goto retry; | 308 | spin_lock(&cache->lock); |
245 | } else | 309 | hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { |
246 | cred = new; | 310 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
247 | } else if ((cred->cr_flags & RPCAUTH_CRED_NEW) | 311 | continue; |
312 | cred = get_rpccred(entry); | ||
313 | break; | ||
314 | } | ||
315 | if (cred == NULL) { | ||
316 | cred = new; | ||
317 | set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); | ||
318 | hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); | ||
319 | } else | ||
320 | list_add_tail(&new->cr_lru, &free); | ||
321 | spin_unlock(&cache->lock); | ||
322 | found: | ||
323 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) | ||
248 | && cred->cr_ops->cr_init != NULL | 324 | && cred->cr_ops->cr_init != NULL |
249 | && !(flags & RPCAUTH_LOOKUP_NEW)) { | 325 | && !(flags & RPCAUTH_LOOKUP_NEW)) { |
250 | int res = cred->cr_ops->cr_init(auth, cred); | 326 | int res = cred->cr_ops->cr_init(auth, cred); |
@@ -253,8 +329,9 @@ retry: | |||
253 | cred = ERR_PTR(res); | 329 | cred = ERR_PTR(res); |
254 | } | 330 | } |
255 | } | 331 | } |
256 | 332 | rpcauth_destroy_credlist(&free); | |
257 | return (struct rpc_cred *) cred; | 333 | out: |
334 | return cred; | ||
258 | } | 335 | } |
259 | 336 | ||
260 | struct rpc_cred * | 337 | struct rpc_cred * |
@@ -275,10 +352,27 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |||
275 | return ret; | 352 | return ret; |
276 | } | 353 | } |
277 | 354 | ||
355 | void | ||
356 | rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | ||
357 | struct rpc_auth *auth, const struct rpc_credops *ops) | ||
358 | { | ||
359 | INIT_HLIST_NODE(&cred->cr_hash); | ||
360 | INIT_LIST_HEAD(&cred->cr_lru); | ||
361 | atomic_set(&cred->cr_count, 1); | ||
362 | cred->cr_auth = auth; | ||
363 | cred->cr_ops = ops; | ||
364 | cred->cr_expire = jiffies; | ||
365 | #ifdef RPC_DEBUG | ||
366 | cred->cr_magic = RPCAUTH_CRED_MAGIC; | ||
367 | #endif | ||
368 | cred->cr_uid = acred->uid; | ||
369 | } | ||
370 | EXPORT_SYMBOL(rpcauth_init_cred); | ||
371 | |||
278 | struct rpc_cred * | 372 | struct rpc_cred * |
279 | rpcauth_bindcred(struct rpc_task *task) | 373 | rpcauth_bindcred(struct rpc_task *task) |
280 | { | 374 | { |
281 | struct rpc_auth *auth = task->tk_auth; | 375 | struct rpc_auth *auth = task->tk_client->cl_auth; |
282 | struct auth_cred acred = { | 376 | struct auth_cred acred = { |
283 | .uid = current->fsuid, | 377 | .uid = current->fsuid, |
284 | .gid = current->fsgid, | 378 | .gid = current->fsgid, |
@@ -288,7 +382,7 @@ rpcauth_bindcred(struct rpc_task *task) | |||
288 | int flags = 0; | 382 | int flags = 0; |
289 | 383 | ||
290 | dprintk("RPC: %5u looking up %s cred\n", | 384 | dprintk("RPC: %5u looking up %s cred\n", |
291 | task->tk_pid, task->tk_auth->au_ops->au_name); | 385 | task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); |
292 | get_group_info(acred.group_info); | 386 | get_group_info(acred.group_info); |
293 | if (task->tk_flags & RPC_TASK_ROOTCREDS) | 387 | if (task->tk_flags & RPC_TASK_ROOTCREDS) |
294 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; | 388 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; |
@@ -304,19 +398,42 @@ rpcauth_bindcred(struct rpc_task *task) | |||
304 | void | 398 | void |
305 | rpcauth_holdcred(struct rpc_task *task) | 399 | rpcauth_holdcred(struct rpc_task *task) |
306 | { | 400 | { |
307 | dprintk("RPC: %5u holding %s cred %p\n", | 401 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
308 | task->tk_pid, task->tk_auth->au_ops->au_name, | 402 | if (cred != NULL) { |
309 | task->tk_msg.rpc_cred); | 403 | get_rpccred(cred); |
310 | if (task->tk_msg.rpc_cred) | 404 | dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, |
311 | get_rpccred(task->tk_msg.rpc_cred); | 405 | cred->cr_auth->au_ops->au_name, cred); |
406 | } | ||
312 | } | 407 | } |
313 | 408 | ||
314 | void | 409 | void |
315 | put_rpccred(struct rpc_cred *cred) | 410 | put_rpccred(struct rpc_cred *cred) |
316 | { | 411 | { |
317 | cred->cr_expire = jiffies; | 412 | /* Fast path for unhashed credentials */ |
413 | if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) | ||
414 | goto need_lock; | ||
415 | |||
318 | if (!atomic_dec_and_test(&cred->cr_count)) | 416 | if (!atomic_dec_and_test(&cred->cr_count)) |
319 | return; | 417 | return; |
418 | goto out_destroy; | ||
419 | need_lock: | ||
420 | if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) | ||
421 | return; | ||
422 | if (!list_empty(&cred->cr_lru)) { | ||
423 | number_cred_unused--; | ||
424 | list_del_init(&cred->cr_lru); | ||
425 | } | ||
426 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | ||
427 | rpcauth_unhash_cred(cred); | ||
428 | else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { | ||
429 | cred->cr_expire = jiffies; | ||
430 | list_add_tail(&cred->cr_lru, &cred_unused); | ||
431 | number_cred_unused++; | ||
432 | spin_unlock(&rpc_credcache_lock); | ||
433 | return; | ||
434 | } | ||
435 | spin_unlock(&rpc_credcache_lock); | ||
436 | out_destroy: | ||
320 | cred->cr_ops->crdestroy(cred); | 437 | cred->cr_ops->crdestroy(cred); |
321 | } | 438 | } |
322 | 439 | ||
@@ -326,7 +443,7 @@ rpcauth_unbindcred(struct rpc_task *task) | |||
326 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 443 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
327 | 444 | ||
328 | dprintk("RPC: %5u releasing %s cred %p\n", | 445 | dprintk("RPC: %5u releasing %s cred %p\n", |
329 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 446 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
330 | 447 | ||
331 | put_rpccred(cred); | 448 | put_rpccred(cred); |
332 | task->tk_msg.rpc_cred = NULL; | 449 | task->tk_msg.rpc_cred = NULL; |
@@ -338,7 +455,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p) | |||
338 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 455 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
339 | 456 | ||
340 | dprintk("RPC: %5u marshaling %s cred %p\n", | 457 | dprintk("RPC: %5u marshaling %s cred %p\n", |
341 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 458 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
342 | 459 | ||
343 | return cred->cr_ops->crmarshal(task, p); | 460 | return cred->cr_ops->crmarshal(task, p); |
344 | } | 461 | } |
@@ -349,7 +466,7 @@ rpcauth_checkverf(struct rpc_task *task, __be32 *p) | |||
349 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 466 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
350 | 467 | ||
351 | dprintk("RPC: %5u validating %s cred %p\n", | 468 | dprintk("RPC: %5u validating %s cred %p\n", |
352 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 469 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
353 | 470 | ||
354 | return cred->cr_ops->crvalidate(task, p); | 471 | return cred->cr_ops->crvalidate(task, p); |
355 | } | 472 | } |
@@ -359,13 +476,17 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, | |||
359 | __be32 *data, void *obj) | 476 | __be32 *data, void *obj) |
360 | { | 477 | { |
361 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 478 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
479 | int ret; | ||
362 | 480 | ||
363 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", | 481 | dprintk("RPC: %5u using %s cred %p to wrap rpc data\n", |
364 | task->tk_pid, cred->cr_ops->cr_name, cred); | 482 | task->tk_pid, cred->cr_ops->cr_name, cred); |
365 | if (cred->cr_ops->crwrap_req) | 483 | if (cred->cr_ops->crwrap_req) |
366 | return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); | 484 | return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj); |
367 | /* By default, we encode the arguments normally. */ | 485 | /* By default, we encode the arguments normally. */ |
368 | return encode(rqstp, data, obj); | 486 | lock_kernel(); |
487 | ret = encode(rqstp, data, obj); | ||
488 | unlock_kernel(); | ||
489 | return ret; | ||
369 | } | 490 | } |
370 | 491 | ||
371 | int | 492 | int |
@@ -373,6 +494,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | |||
373 | __be32 *data, void *obj) | 494 | __be32 *data, void *obj) |
374 | { | 495 | { |
375 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 496 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
497 | int ret; | ||
376 | 498 | ||
377 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", | 499 | dprintk("RPC: %5u using %s cred %p to unwrap rpc data\n", |
378 | task->tk_pid, cred->cr_ops->cr_name, cred); | 500 | task->tk_pid, cred->cr_ops->cr_name, cred); |
@@ -380,7 +502,10 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | |||
380 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, | 502 | return cred->cr_ops->crunwrap_resp(task, decode, rqstp, |
381 | data, obj); | 503 | data, obj); |
382 | /* By default, we decode the arguments normally. */ | 504 | /* By default, we decode the arguments normally. */ |
383 | return decode(rqstp, data, obj); | 505 | lock_kernel(); |
506 | ret = decode(rqstp, data, obj); | ||
507 | unlock_kernel(); | ||
508 | return ret; | ||
384 | } | 509 | } |
385 | 510 | ||
386 | int | 511 | int |
@@ -390,7 +515,7 @@ rpcauth_refreshcred(struct rpc_task *task) | |||
390 | int err; | 515 | int err; |
391 | 516 | ||
392 | dprintk("RPC: %5u refreshing %s cred %p\n", | 517 | dprintk("RPC: %5u refreshing %s cred %p\n", |
393 | task->tk_pid, task->tk_auth->au_ops->au_name, cred); | 518 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
394 | 519 | ||
395 | err = cred->cr_ops->crrefresh(task); | 520 | err = cred->cr_ops->crrefresh(task); |
396 | if (err < 0) | 521 | if (err < 0) |
@@ -401,17 +526,34 @@ rpcauth_refreshcred(struct rpc_task *task) | |||
401 | void | 526 | void |
402 | rpcauth_invalcred(struct rpc_task *task) | 527 | rpcauth_invalcred(struct rpc_task *task) |
403 | { | 528 | { |
529 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | ||
530 | |||
404 | dprintk("RPC: %5u invalidating %s cred %p\n", | 531 | dprintk("RPC: %5u invalidating %s cred %p\n", |
405 | task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred); | 532 | task->tk_pid, cred->cr_auth->au_ops->au_name, cred); |
406 | spin_lock(&rpc_credcache_lock); | 533 | if (cred) |
407 | if (task->tk_msg.rpc_cred) | 534 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
408 | task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | ||
409 | spin_unlock(&rpc_credcache_lock); | ||
410 | } | 535 | } |
411 | 536 | ||
412 | int | 537 | int |
413 | rpcauth_uptodatecred(struct rpc_task *task) | 538 | rpcauth_uptodatecred(struct rpc_task *task) |
414 | { | 539 | { |
415 | return !(task->tk_msg.rpc_cred) || | 540 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
416 | (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE); | 541 | |
542 | return cred == NULL || | ||
543 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; | ||
544 | } | ||
545 | |||
546 | |||
547 | static struct shrinker *rpc_cred_shrinker; | ||
548 | |||
549 | void __init rpcauth_init_module(void) | ||
550 | { | ||
551 | rpc_init_authunix(); | ||
552 | rpc_cred_shrinker = set_shrinker(DEFAULT_SEEKS, rpcauth_cache_shrinker); | ||
553 | } | ||
554 | |||
555 | void __exit rpcauth_remove_module(void) | ||
556 | { | ||
557 | if (rpc_cred_shrinker != NULL) | ||
558 | remove_shrinker(rpc_cred_shrinker); | ||
417 | } | 559 | } |