Blame view
net/sunrpc/cache.c
43.4 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/* * net/sunrpc/cache.c * * Generic code for various authentication-related caches * used by sunrpc clients and servers. * * Copyright (C) 2002 Neil Brown <neilb@cse.unsw.edu.au> * * Released under terms in GPL version 2. See COPYING. * */ #include <linux/types.h> #include <linux/fs.h> #include <linux/file.h> #include <linux/slab.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/kmod.h> #include <linux/list.h> #include <linux/module.h> #include <linux/ctype.h> #include <asm/uaccess.h> #include <linux/poll.h> #include <linux/seq_file.h> #include <linux/proc_fs.h> #include <linux/net.h> #include <linux/workqueue.h> |
4a3e2f711 [NET] sem2mutex: ... |
29 |
#include <linux/mutex.h> |
da77005f0 SUNRPC: Remove th... |
30 |
#include <linux/pagemap.h> |
1da177e4c Linux-2.6.12-rc2 |
31 32 33 34 |
#include <asm/ioctls.h> #include <linux/sunrpc/types.h> #include <linux/sunrpc/cache.h> #include <linux/sunrpc/stats.h> |
8854e82d9 SUNRPC: Add an rp... |
35 |
#include <linux/sunrpc/rpc_pipe_fs.h> |
4f42d0d53 sunrpc: Make the ... |
36 |
#include "netns.h" |
1da177e4c Linux-2.6.12-rc2 |
37 38 |
#define RPCDBG_FACILITY RPCDBG_CACHE |
d76d1815f svcrpc: avoid dou... |
39 |
static bool cache_defer_req(struct cache_req *req, struct cache_head *item); |
1da177e4c Linux-2.6.12-rc2 |
40 |
static void cache_revisit_request(struct cache_head *item); |
74cae61ab [PATCH] fs/nfsd/e... |
41 |
static void cache_init(struct cache_head *h) |
1da177e4c Linux-2.6.12-rc2 |
42 |
{ |
c5b29f885 sunrpc: use secon... |
43 |
time_t now = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
44 45 |
h->next = NULL; h->flags = 0; |
baab935ff [PATCH] knfsd: Co... |
46 |
kref_init(&h->ref); |
1da177e4c Linux-2.6.12-rc2 |
47 48 49 |
h->expiry_time = now + CACHE_NEW_EXPIRY; h->last_refresh = now; } |
2f50d8b63 sunrpc/cache: fac... |
50 51 |
static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h) { |
c5b29f885 sunrpc: use secon... |
52 |
return (h->expiry_time < seconds_since_boot()) || |
2f50d8b63 sunrpc/cache: fac... |
53 54 |
(detail->flush_time > h->last_refresh); } |
15a5f6bd2 [PATCH] knfsd: Cr... |
55 56 57 58 |
struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail, struct cache_head *key, int hash) { struct cache_head **head, **hp; |
d202cce89 sunrpc: never ret... |
59 |
struct cache_head *new = NULL, *freeme = NULL; |
15a5f6bd2 [PATCH] knfsd: Cr... |
60 61 62 63 64 65 66 67 |
head = &detail->hash_table[hash]; read_lock(&detail->hash_lock); for (hp=head; *hp != NULL ; hp = &(*hp)->next) { struct cache_head *tmp = *hp; if (detail->match(tmp, key)) { |
d202cce89 sunrpc: never ret... |
68 69 70 |
if (cache_is_expired(detail, tmp)) /* This entry is expired, we will discard it. */ break; |
15a5f6bd2 [PATCH] knfsd: Cr... |
71 72 73 74 75 76 77 78 79 80 81 |
cache_get(tmp); read_unlock(&detail->hash_lock); return tmp; } } read_unlock(&detail->hash_lock); /* Didn't find anything, insert an empty entry */ new = detail->alloc(); if (!new) return NULL; |
2f34931fd [PATCH] knfsd: fi... |
82 83 84 85 |
/* must fully initialise 'new', else * we might get lose if we need to * cache_put it soon. */ |
15a5f6bd2 [PATCH] knfsd: Cr... |
86 |
cache_init(new); |
2f34931fd [PATCH] knfsd: fi... |
87 |
detail->init(new, key); |
15a5f6bd2 [PATCH] knfsd: Cr... |
88 89 90 91 92 93 94 |
write_lock(&detail->hash_lock); /* check if entry appeared while we slept */ for (hp=head; *hp != NULL ; hp = &(*hp)->next) { struct cache_head *tmp = *hp; if (detail->match(tmp, key)) { |
d202cce89 sunrpc: never ret... |
95 96 97 98 99 100 101 |
if (cache_is_expired(detail, tmp)) { *hp = tmp->next; tmp->next = NULL; detail->entries --; freeme = tmp; break; } |
15a5f6bd2 [PATCH] knfsd: Cr... |
102 103 |
cache_get(tmp); write_unlock(&detail->hash_lock); |
baab935ff [PATCH] knfsd: Co... |
104 |
cache_put(new, detail); |
15a5f6bd2 [PATCH] knfsd: Cr... |
105 106 107 |
return tmp; } } |
15a5f6bd2 [PATCH] knfsd: Cr... |
108 109 110 111 112 |
new->next = *head; *head = new; detail->entries++; cache_get(new); write_unlock(&detail->hash_lock); |
d202cce89 sunrpc: never ret... |
113 114 |
if (freeme) cache_put(freeme, detail); |
15a5f6bd2 [PATCH] knfsd: Cr... |
115 116 |
return new; } |
24c3767e4 SUNRPC: The sunrp... |
117 |
EXPORT_SYMBOL_GPL(sunrpc_cache_lookup); |
15a5f6bd2 [PATCH] knfsd: Cr... |
118 |
|
ebd0cb1af [PATCH] knfsd: Un... |
119 |
|
f866a8194 sunrpc/cache: ren... |
120 |
static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch); |
ebd0cb1af [PATCH] knfsd: Un... |
121 |
|
908329f2c sunrpc/cache: sim... |
122 |
static void cache_fresh_locked(struct cache_head *head, time_t expiry) |
ebd0cb1af [PATCH] knfsd: Un... |
123 124 |
{ head->expiry_time = expiry; |
c5b29f885 sunrpc: use secon... |
125 |
head->last_refresh = seconds_since_boot(); |
fdef7aa5d svcrpc: ensure ca... |
126 |
smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */ |
908329f2c sunrpc/cache: sim... |
127 |
set_bit(CACHE_VALID, &head->flags); |
ebd0cb1af [PATCH] knfsd: Un... |
128 129 130 |
} static void cache_fresh_unlocked(struct cache_head *head, |
908329f2c sunrpc/cache: sim... |
131 |
struct cache_detail *detail) |
ebd0cb1af [PATCH] knfsd: Un... |
132 |
{ |
ebd0cb1af [PATCH] knfsd: Un... |
133 134 |
if (test_and_clear_bit(CACHE_PENDING, &head->flags)) { cache_revisit_request(head); |
f866a8194 sunrpc/cache: ren... |
135 |
cache_dequeue(detail, head); |
ebd0cb1af [PATCH] knfsd: Un... |
136 137 |
} } |
15a5f6bd2 [PATCH] knfsd: Cr... |
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
struct cache_head *sunrpc_cache_update(struct cache_detail *detail, struct cache_head *new, struct cache_head *old, int hash) { /* The 'old' entry is to be replaced by 'new'. * If 'old' is not VALID, we update it directly, * otherwise we need to replace it */ struct cache_head **head; struct cache_head *tmp; if (!test_bit(CACHE_VALID, &old->flags)) { write_lock(&detail->hash_lock); if (!test_bit(CACHE_VALID, &old->flags)) { if (test_bit(CACHE_NEGATIVE, &new->flags)) set_bit(CACHE_NEGATIVE, &old->flags); else detail->update(old, new); |
908329f2c sunrpc/cache: sim... |
155 |
cache_fresh_locked(old, new->expiry_time); |
15a5f6bd2 [PATCH] knfsd: Cr... |
156 |
write_unlock(&detail->hash_lock); |
908329f2c sunrpc/cache: sim... |
157 |
cache_fresh_unlocked(old, detail); |
15a5f6bd2 [PATCH] knfsd: Cr... |
158 159 160 161 162 163 164 |
return old; } write_unlock(&detail->hash_lock); } /* We need to insert a new entry */ tmp = detail->alloc(); if (!tmp) { |
baab935ff [PATCH] knfsd: Co... |
165 |
cache_put(old, detail); |
15a5f6bd2 [PATCH] knfsd: Cr... |
166 167 168 169 170 171 172 173 174 175 176 177 178 |
return NULL; } cache_init(tmp); detail->init(tmp, old); head = &detail->hash_table[hash]; write_lock(&detail->hash_lock); if (test_bit(CACHE_NEGATIVE, &new->flags)) set_bit(CACHE_NEGATIVE, &tmp->flags); else detail->update(tmp, new); tmp->next = *head; *head = tmp; |
f2d395865 [PATCH] knfsd: Fi... |
179 |
detail->entries++; |
15a5f6bd2 [PATCH] knfsd: Cr... |
180 |
cache_get(tmp); |
908329f2c sunrpc/cache: sim... |
181 |
cache_fresh_locked(tmp, new->expiry_time); |
ebd0cb1af [PATCH] knfsd: Un... |
182 |
cache_fresh_locked(old, 0); |
15a5f6bd2 [PATCH] knfsd: Cr... |
183 |
write_unlock(&detail->hash_lock); |
908329f2c sunrpc/cache: sim... |
184 185 |
cache_fresh_unlocked(tmp, detail); cache_fresh_unlocked(old, detail); |
baab935ff [PATCH] knfsd: Co... |
186 |
cache_put(old, detail); |
15a5f6bd2 [PATCH] knfsd: Cr... |
187 188 |
return tmp; } |
24c3767e4 SUNRPC: The sunrp... |
189 |
EXPORT_SYMBOL_GPL(sunrpc_cache_update); |
1da177e4c Linux-2.6.12-rc2 |
190 |
|
bc74b4f5e SUNRPC: Allow the... |
191 192 |
static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) { |
2d4383383 SUNRPC: rework ca... |
193 194 |
if (cd->cache_upcall) return cd->cache_upcall(cd, h); |
21cd1254d SUNRPC: remove "c... |
195 |
return sunrpc_cache_pipe_upcall(cd, h); |
bc74b4f5e SUNRPC: Allow the... |
196 |
} |
989a19b9b sunrpc/cache: rec... |
197 198 199 |
static inline int cache_is_valid(struct cache_detail *detail, struct cache_head *h) { |
d202cce89 sunrpc: never ret... |
200 |
if (!test_bit(CACHE_VALID, &h->flags)) |
989a19b9b sunrpc/cache: rec... |
201 202 203 204 205 |
return -EAGAIN; else { /* entry is valid */ if (test_bit(CACHE_NEGATIVE, &h->flags)) return -ENOENT; |
fdef7aa5d svcrpc: ensure ca... |
206 207 208 209 210 211 212 213 |
else { /* * In combination with write barrier in * sunrpc_cache_update, ensures that anyone * using the cache entry after this sees the * updated contents: */ smp_rmb(); |
989a19b9b sunrpc/cache: rec... |
214 |
return 0; |
fdef7aa5d svcrpc: ensure ca... |
215 |
} |
989a19b9b sunrpc/cache: rec... |
216 217 |
} } |
e9dc12216 Merge branch 'nfs... |
218 |
|
6bab93f87 svcrpc: take lock... |
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h) { int rv; write_lock(&detail->hash_lock); rv = cache_is_valid(detail, h); if (rv != -EAGAIN) { write_unlock(&detail->hash_lock); return rv; } set_bit(CACHE_NEGATIVE, &h->flags); cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY); write_unlock(&detail->hash_lock); cache_fresh_unlocked(h, detail); return -ENOENT; } |
1da177e4c Linux-2.6.12-rc2 |
235 236 237 238 239 240 241 242 |
/* * This is the generic cache management routine for all * the authentication caches. * It checks the currency of a cache item and will (later) * initiate an upcall to fill it if needed. * * * Returns 0 if the cache_head can be used, or cache_puts it and returns |
989a19b9b sunrpc/cache: rec... |
243 244 245 246 |
* -EAGAIN if upcall is pending and request has been queued * -ETIMEDOUT if upcall failed or request could not be queue or * upcall completed but item is still invalid (implying that * the cache item has been replaced with a newer one). |
1da177e4c Linux-2.6.12-rc2 |
247 248 249 250 251 252 253 254 255 |
* -ENOENT if cache entry was negative */ int cache_check(struct cache_detail *detail, struct cache_head *h, struct cache_req *rqstp) { int rv; long refresh_age, age; /* First decide return status as best we can */ |
989a19b9b sunrpc/cache: rec... |
256 |
rv = cache_is_valid(detail, h); |
1da177e4c Linux-2.6.12-rc2 |
257 258 259 |
/* now see if we want to start an upcall */ refresh_age = (h->expiry_time - h->last_refresh); |
c5b29f885 sunrpc: use secon... |
260 |
age = seconds_since_boot() - h->last_refresh; |
1da177e4c Linux-2.6.12-rc2 |
261 262 263 264 265 |
if (rqstp == NULL) { if (rv == -EAGAIN) rv = -ENOENT; } else if (rv == -EAGAIN || age > refresh_age/2) { |
46121cf7d SUNRPC: fix print... |
266 267 268 |
dprintk("RPC: Want update, refage=%ld, age=%ld ", refresh_age, age); |
1da177e4c Linux-2.6.12-rc2 |
269 270 271 272 |
if (!test_and_set_bit(CACHE_PENDING, &h->flags)) { switch (cache_make_upcall(detail, h)) { case -EINVAL: clear_bit(CACHE_PENDING, &h->flags); |
5c4d26390 sunrpc/cache: mak... |
273 |
cache_revisit_request(h); |
6bab93f87 svcrpc: take lock... |
274 |
rv = try_to_negate_entry(detail, h); |
1da177e4c Linux-2.6.12-rc2 |
275 |
break; |
1da177e4c Linux-2.6.12-rc2 |
276 277 278 279 280 281 282 |
case -EAGAIN: clear_bit(CACHE_PENDING, &h->flags); cache_revisit_request(h); break; } } } |
989a19b9b sunrpc/cache: rec... |
283 |
if (rv == -EAGAIN) { |
d76d1815f svcrpc: avoid dou... |
284 285 286 287 288 |
if (!cache_defer_req(rqstp, h)) { /* * Request was not deferred; handle it as best * we can ourselves: */ |
989a19b9b sunrpc/cache: rec... |
289 290 291 292 293 |
rv = cache_is_valid(detail, h); if (rv == -EAGAIN) rv = -ETIMEDOUT; } } |
4013edea9 [PATCH] knfsd: An... |
294 |
if (rv) |
baab935ff [PATCH] knfsd: Co... |
295 |
cache_put(h, detail); |
1da177e4c Linux-2.6.12-rc2 |
296 297 |
return rv; } |
24c3767e4 SUNRPC: The sunrp... |
298 |
EXPORT_SYMBOL_GPL(cache_check); |
1da177e4c Linux-2.6.12-rc2 |
299 |
|
1da177e4c Linux-2.6.12-rc2 |
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
/* * caches need to be periodically cleaned. * For this we maintain a list of cache_detail and * a current pointer into that list and into the table * for that entry. * * Each time clean_cache is called it finds the next non-empty entry * in the current table and walks the list in that entry * looking for entries that can be removed. * * An entry gets removed if: * - The expiry is before current time * - The last_refresh time is before the flush_time for that cache * * later we might drop old entries with non-NEVER expiry if that table * is getting 'full' for some definition of 'full' * * The question of "how often to scan a table" is an interesting one * and is answered in part by the use of the "nextcheck" field in the * cache_detail. * When a scan of a table begins, the nextcheck field is set to a time * that is well into the future. * While scanning, if an expiry time is found that is earlier than the * current nextcheck time, nextcheck is set to that expiry time. * If the flush_time is ever set to a time earlier than the nextcheck * time, the nextcheck time is then set to that flush_time. * * A table is then only scanned if the current time is at least * the nextcheck time. |
cca5172a7 [NET] SUNRPC: Fix... |
329 |
* |
1da177e4c Linux-2.6.12-rc2 |
330 331 332 333 334 335 |
*/ static LIST_HEAD(cache_list); static DEFINE_SPINLOCK(cache_list_lock); static struct cache_detail *current_detail; static int current_index; |
65f27f384 WorkStruct: Pass ... |
336 |
static void do_cache_clean(struct work_struct *work); |
8eab945c5 sunrpc: make the ... |
337 |
static struct delayed_work cache_cleaner; |
1da177e4c Linux-2.6.12-rc2 |
338 |
|
820f9442e SUNRPC: split cac... |
339 |
void sunrpc_init_cache_detail(struct cache_detail *cd) |
ffe9386b6 nfsd: move cache ... |
340 |
{ |
1da177e4c Linux-2.6.12-rc2 |
341 342 343 344 345 346 347 348 349 350 351 352 |
rwlock_init(&cd->hash_lock); INIT_LIST_HEAD(&cd->queue); spin_lock(&cache_list_lock); cd->nextcheck = 0; cd->entries = 0; atomic_set(&cd->readers, 0); cd->last_close = 0; cd->last_warn = -1; list_add(&cd->others, &cache_list); spin_unlock(&cache_list_lock); /* start the cleaning process */ |
52bad64d9 WorkStruct: Separ... |
353 |
schedule_delayed_work(&cache_cleaner, 0); |
1da177e4c Linux-2.6.12-rc2 |
354 |
} |
820f9442e SUNRPC: split cac... |
355 |
EXPORT_SYMBOL_GPL(sunrpc_init_cache_detail); |
1da177e4c Linux-2.6.12-rc2 |
356 |
|
820f9442e SUNRPC: split cac... |
357 |
void sunrpc_destroy_cache_detail(struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
358 359 360 361 362 363 364 |
{ cache_purge(cd); spin_lock(&cache_list_lock); write_lock(&cd->hash_lock); if (cd->entries || atomic_read(&cd->inuse)) { write_unlock(&cd->hash_lock); spin_unlock(&cache_list_lock); |
df95a9d4f knfsd: cache unre... |
365 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
366 367 368 369 370 371 |
} if (current_detail == cd) current_detail = NULL; list_del_init(&cd->others); write_unlock(&cd->hash_lock); spin_unlock(&cache_list_lock); |
1da177e4c Linux-2.6.12-rc2 |
372 373 |
if (list_empty(&cache_list)) { /* module must be being unloaded so its safe to kill the worker */ |
4011cd978 SUNRPC: Replace f... |
374 |
cancel_delayed_work_sync(&cache_cleaner); |
1da177e4c Linux-2.6.12-rc2 |
375 |
} |
df95a9d4f knfsd: cache unre... |
376 377 378 379 |
return; out: printk(KERN_ERR "nfsd: failed to unregister %s cache ", cd->name); |
1da177e4c Linux-2.6.12-rc2 |
380 |
} |
820f9442e SUNRPC: split cac... |
381 |
EXPORT_SYMBOL_GPL(sunrpc_destroy_cache_detail); |
1da177e4c Linux-2.6.12-rc2 |
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
/* clean cache tries to find something to clean * and cleans it. * It returns 1 if it cleaned something, * 0 if it didn't find anything this time * -1 if it fell off the end of the list. */ static int cache_clean(void) { int rv = 0; struct list_head *next; spin_lock(&cache_list_lock); /* find a suitable table if we don't already have one */ while (current_detail == NULL || current_index >= current_detail->hash_size) { if (current_detail) next = current_detail->others.next; else next = cache_list.next; if (next == &cache_list) { current_detail = NULL; spin_unlock(&cache_list_lock); return -1; } current_detail = list_entry(next, struct cache_detail, others); |
c5b29f885 sunrpc: use secon... |
409 |
if (current_detail->nextcheck > seconds_since_boot()) |
1da177e4c Linux-2.6.12-rc2 |
410 411 412 |
current_index = current_detail->hash_size; else { current_index = 0; |
c5b29f885 sunrpc: use secon... |
413 |
current_detail->nextcheck = seconds_since_boot()+30*60; |
1da177e4c Linux-2.6.12-rc2 |
414 415 416 417 418 419 420 421 422 423 |
} } /* find a non-empty bucket in the table */ while (current_detail && current_index < current_detail->hash_size && current_detail->hash_table[current_index] == NULL) current_index++; /* find a cleanable entry in the bucket and clean it, or set to next bucket */ |
cca5172a7 [NET] SUNRPC: Fix... |
424 |
|
1da177e4c Linux-2.6.12-rc2 |
425 426 427 |
if (current_detail && current_index < current_detail->hash_size) { struct cache_head *ch, **cp; struct cache_detail *d; |
cca5172a7 [NET] SUNRPC: Fix... |
428 |
|
1da177e4c Linux-2.6.12-rc2 |
429 430 431 |
write_lock(¤t_detail->hash_lock); /* Ok, now to clean this strand */ |
cca5172a7 [NET] SUNRPC: Fix... |
432 |
|
1da177e4c Linux-2.6.12-rc2 |
433 |
cp = & current_detail->hash_table[current_index]; |
3af4974eb sunrpc: don't kee... |
434 |
for (ch = *cp ; ch ; cp = & ch->next, ch = *cp) { |
1da177e4c Linux-2.6.12-rc2 |
435 436 |
if (current_detail->nextcheck > ch->expiry_time) current_detail->nextcheck = ch->expiry_time+1; |
2f50d8b63 sunrpc/cache: fac... |
437 |
if (!cache_is_expired(current_detail, ch)) |
1da177e4c Linux-2.6.12-rc2 |
438 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
439 |
|
1da177e4c Linux-2.6.12-rc2 |
440 441 442 443 |
*cp = ch->next; ch->next = NULL; current_detail->entries--; rv = 1; |
3af4974eb sunrpc: don't kee... |
444 |
break; |
1da177e4c Linux-2.6.12-rc2 |
445 |
} |
3af4974eb sunrpc: don't kee... |
446 |
|
1da177e4c Linux-2.6.12-rc2 |
447 448 449 450 451 |
write_unlock(¤t_detail->hash_lock); d = current_detail; if (!ch) current_index ++; spin_unlock(&cache_list_lock); |
5c4d26390 sunrpc/cache: mak... |
452 |
if (ch) { |
3af4974eb sunrpc: don't kee... |
453 454 |
if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) cache_dequeue(current_detail, ch); |
5c4d26390 sunrpc/cache: mak... |
455 |
cache_revisit_request(ch); |
baab935ff [PATCH] knfsd: Co... |
456 |
cache_put(ch, d); |
5c4d26390 sunrpc/cache: mak... |
457 |
} |
1da177e4c Linux-2.6.12-rc2 |
458 459 460 461 462 463 464 465 466 |
} else spin_unlock(&cache_list_lock); return rv; } /* * We want to regularly clean the cache, so we need to schedule some work ... */ |
65f27f384 WorkStruct: Pass ... |
467 |
static void do_cache_clean(struct work_struct *work) |
1da177e4c Linux-2.6.12-rc2 |
468 469 470 |
{ int delay = 5; if (cache_clean() == -1) |
6aad89c83 sunrpc: align cac... |
471 |
delay = round_jiffies_relative(30*HZ); |
1da177e4c Linux-2.6.12-rc2 |
472 473 474 475 476 477 478 |
if (list_empty(&cache_list)) delay = 0; if (delay) schedule_delayed_work(&cache_cleaner, delay); } |
cca5172a7 [NET] SUNRPC: Fix... |
479 |
/* |
1da177e4c Linux-2.6.12-rc2 |
480 |
* Clean all caches promptly. This just calls cache_clean |
cca5172a7 [NET] SUNRPC: Fix... |
481 |
* repeatedly until we are sure that every cache has had a chance to |
1da177e4c Linux-2.6.12-rc2 |
482 483 484 485 486 487 488 489 490 |
* be fully cleaned */ void cache_flush(void) { while (cache_clean() != -1) cond_resched(); while (cache_clean() != -1) cond_resched(); } |
24c3767e4 SUNRPC: The sunrp... |
491 |
EXPORT_SYMBOL_GPL(cache_flush); |
1da177e4c Linux-2.6.12-rc2 |
492 493 494 495 |
void cache_purge(struct cache_detail *detail) { detail->flush_time = LONG_MAX; |
c5b29f885 sunrpc: use secon... |
496 |
detail->nextcheck = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
497 498 499 |
cache_flush(); detail->flush_time = 1; } |
24c3767e4 SUNRPC: The sunrp... |
500 |
EXPORT_SYMBOL_GPL(cache_purge); |
1da177e4c Linux-2.6.12-rc2 |
501 502 503 504 505 506 507 508 509 510 |
/* * Deferral and Revisiting of Requests. * * If a cache lookup finds a pending entry, we * need to defer the request and revisit it later. * All deferred requests are stored in a hash table, * indexed by "struct cache_head *". * As it may be wasteful to store a whole request |
cca5172a7 [NET] SUNRPC: Fix... |
511 |
* structure, we allow the request to provide a |
1da177e4c Linux-2.6.12-rc2 |
512 513 514 515 516 517 518 519 520 521 522 523 524 |
* deferred form, which must contain a * 'struct cache_deferred_req' * This cache_deferred_req contains a method to allow * it to be revisited when cache info is available */ #define DFR_HASHSIZE (PAGE_SIZE/sizeof(struct list_head)) #define DFR_HASH(item) ((((long)item)>>4 ^ (((long)item)>>13)) % DFR_HASHSIZE) #define DFR_MAX 300 /* ??? */ static DEFINE_SPINLOCK(cache_defer_lock); static LIST_HEAD(cache_defer_list); |
111744927 sunrpc/cache: cha... |
525 |
static struct hlist_head cache_defer_hash[DFR_HASHSIZE]; |
1da177e4c Linux-2.6.12-rc2 |
526 |
static int cache_defer_cnt; |
6610f720e svcrpc: minor cac... |
527 528 |
static void __unhash_deferred_req(struct cache_deferred_req *dreq) { |
111744927 sunrpc/cache: cha... |
529 |
hlist_del_init(&dreq->hash); |
e33534d54 sunrpc/cache: cen... |
530 531 532 533 |
if (!list_empty(&dreq->recent)) { list_del_init(&dreq->recent); cache_defer_cnt--; } |
6610f720e svcrpc: minor cac... |
534 535 536 |
} static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item) |
1da177e4c Linux-2.6.12-rc2 |
537 |
{ |
1da177e4c Linux-2.6.12-rc2 |
538 |
int hash = DFR_HASH(item); |
e33534d54 sunrpc/cache: cen... |
539 |
INIT_LIST_HEAD(&dreq->recent); |
111744927 sunrpc/cache: cha... |
540 |
hlist_add_head(&dreq->hash, &cache_defer_hash[hash]); |
6610f720e svcrpc: minor cac... |
541 |
} |
e33534d54 sunrpc/cache: cen... |
542 543 544 |
static void setup_deferral(struct cache_deferred_req *dreq, struct cache_head *item, int count_me) |
1da177e4c Linux-2.6.12-rc2 |
545 |
{ |
1da177e4c Linux-2.6.12-rc2 |
546 547 |
dreq->item = item; |
1da177e4c Linux-2.6.12-rc2 |
548 549 |
spin_lock(&cache_defer_lock); |
6610f720e svcrpc: minor cac... |
550 |
__hash_deferred_req(dreq, item); |
1da177e4c Linux-2.6.12-rc2 |
551 |
|
e33534d54 sunrpc/cache: cen... |
552 553 554 |
if (count_me) { cache_defer_cnt++; list_add(&dreq->recent, &cache_defer_list); |
1da177e4c Linux-2.6.12-rc2 |
555 |
} |
e33534d54 sunrpc/cache: cen... |
556 |
|
1da177e4c Linux-2.6.12-rc2 |
557 |
spin_unlock(&cache_defer_lock); |
3211af111 svcrpc: cache def... |
558 |
} |
f16b6e8d8 sunrpc/cache: all... |
559 |
|
3211af111 svcrpc: cache def... |
560 561 562 563 564 565 566 567 568 569 570 |
struct thread_deferred_req { struct cache_deferred_req handle; struct completion completion; }; static void cache_restart_thread(struct cache_deferred_req *dreq, int too_many) { struct thread_deferred_req *dr = container_of(dreq, struct thread_deferred_req, handle); complete(&dr->completion); } |
d29068c43 sunrpc: Simplify ... |
571 |
static void cache_wait_req(struct cache_req *req, struct cache_head *item) |
3211af111 svcrpc: cache def... |
572 573 574 |
{ struct thread_deferred_req sleeper; struct cache_deferred_req *dreq = &sleeper.handle; |
3211af111 svcrpc: cache def... |
575 576 577 |
sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion); dreq->revisit = cache_restart_thread; |
e33534d54 sunrpc/cache: cen... |
578 |
setup_deferral(dreq, item, 0); |
3211af111 svcrpc: cache def... |
579 |
|
d29068c43 sunrpc: Simplify ... |
580 |
if (!test_bit(CACHE_PENDING, &item->flags) || |
277f68dbb sunrpc: fix race ... |
581 |
wait_for_completion_interruptible_timeout( |
3211af111 svcrpc: cache def... |
582 583 584 585 586 |
&sleeper.completion, req->thread_wait) <= 0) { /* The completion wasn't completed, so we need * to clean up */ spin_lock(&cache_defer_lock); |
111744927 sunrpc/cache: cha... |
587 |
if (!hlist_unhashed(&sleeper.handle.hash)) { |
3211af111 svcrpc: cache def... |
588 589 590 591 592 593 594 |
__unhash_deferred_req(&sleeper.handle); spin_unlock(&cache_defer_lock); } else { /* cache_revisit_request already removed * this from the hash table, but hasn't * called ->revisit yet. It will very soon * and we need to wait for it. |
f16b6e8d8 sunrpc/cache: all... |
595 |
*/ |
3211af111 svcrpc: cache def... |
596 597 |
spin_unlock(&cache_defer_lock); wait_for_completion(&sleeper.completion); |
f16b6e8d8 sunrpc/cache: all... |
598 |
} |
3211af111 svcrpc: cache def... |
599 |
} |
3211af111 svcrpc: cache def... |
600 |
} |
e33534d54 sunrpc/cache: cen... |
601 |
static void cache_limit_defers(void) |
3211af111 svcrpc: cache def... |
602 |
{ |
e33534d54 sunrpc/cache: cen... |
603 604 605 606 |
/* Make sure we haven't exceed the limit of allowed deferred * requests. */ struct cache_deferred_req *discard = NULL; |
3211af111 svcrpc: cache def... |
607 |
|
e33534d54 sunrpc/cache: cen... |
608 609 |
if (cache_defer_cnt <= DFR_MAX) return; |
d29068c43 sunrpc: Simplify ... |
610 |
|
e33534d54 sunrpc/cache: cen... |
611 612 613 614 615 616 617 618 619 620 621 622 623 |
spin_lock(&cache_defer_lock); /* Consider removing either the first or the last */ if (cache_defer_cnt > DFR_MAX) { if (net_random() & 1) discard = list_entry(cache_defer_list.next, struct cache_deferred_req, recent); else discard = list_entry(cache_defer_list.prev, struct cache_deferred_req, recent); __unhash_deferred_req(discard); } spin_unlock(&cache_defer_lock); |
cd68c374e sunrpc/cache: avo... |
624 |
if (discard) |
cd68c374e sunrpc/cache: avo... |
625 |
discard->revisit(discard, 1); |
e33534d54 sunrpc/cache: cen... |
626 |
} |
cd68c374e sunrpc/cache: avo... |
627 |
|
d76d1815f svcrpc: avoid dou... |
628 629 |
/* Return true if and only if a deferred request is queued. */ static bool cache_defer_req(struct cache_req *req, struct cache_head *item) |
e33534d54 sunrpc/cache: cen... |
630 631 |
{ struct cache_deferred_req *dreq; |
d29068c43 sunrpc: Simplify ... |
632 |
|
3211af111 svcrpc: cache def... |
633 |
if (req->thread_wait) { |
d29068c43 sunrpc: Simplify ... |
634 635 |
cache_wait_req(req, item); if (!test_bit(CACHE_PENDING, &item->flags)) |
d76d1815f svcrpc: avoid dou... |
636 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
637 |
} |
3211af111 svcrpc: cache def... |
638 639 |
dreq = req->defer(req); if (dreq == NULL) |
d76d1815f svcrpc: avoid dou... |
640 |
return false; |
e33534d54 sunrpc/cache: cen... |
641 |
setup_deferral(dreq, item, 1); |
d29068c43 sunrpc: Simplify ... |
642 643 644 645 646 |
if (!test_bit(CACHE_PENDING, &item->flags)) /* Bit could have been cleared before we managed to * set up the deferral, so need to revisit just in case */ cache_revisit_request(item); |
e33534d54 sunrpc/cache: cen... |
647 648 |
cache_limit_defers(); |
d76d1815f svcrpc: avoid dou... |
649 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
650 651 652 653 654 655 |
} static void cache_revisit_request(struct cache_head *item) { struct cache_deferred_req *dreq; struct list_head pending; |
b67bfe0d4 hlist: drop the n... |
656 |
struct hlist_node *tmp; |
1da177e4c Linux-2.6.12-rc2 |
657 658 659 660 |
int hash = DFR_HASH(item); INIT_LIST_HEAD(&pending); spin_lock(&cache_defer_lock); |
cca5172a7 [NET] SUNRPC: Fix... |
661 |
|
b67bfe0d4 hlist: drop the n... |
662 |
hlist_for_each_entry_safe(dreq, tmp, &cache_defer_hash[hash], hash) |
111744927 sunrpc/cache: cha... |
663 664 665 |
if (dreq->item == item) { __unhash_deferred_req(dreq); list_add(&dreq->recent, &pending); |
1da177e4c Linux-2.6.12-rc2 |
666 |
} |
111744927 sunrpc/cache: cha... |
667 |
|
1da177e4c Linux-2.6.12-rc2 |
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
spin_unlock(&cache_defer_lock); while (!list_empty(&pending)) { dreq = list_entry(pending.next, struct cache_deferred_req, recent); list_del_init(&dreq->recent); dreq->revisit(dreq, 0); } } void cache_clean_deferred(void *owner) { struct cache_deferred_req *dreq, *tmp; struct list_head pending; INIT_LIST_HEAD(&pending); spin_lock(&cache_defer_lock); |
cca5172a7 [NET] SUNRPC: Fix... |
685 |
|
1da177e4c Linux-2.6.12-rc2 |
686 687 |
list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { if (dreq->owner == owner) { |
6610f720e svcrpc: minor cac... |
688 |
__unhash_deferred_req(dreq); |
e95dffa43 sunrpc/cache: fix... |
689 |
list_add(&dreq->recent, &pending); |
1da177e4c Linux-2.6.12-rc2 |
690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
} } spin_unlock(&cache_defer_lock); while (!list_empty(&pending)) { dreq = list_entry(pending.next, struct cache_deferred_req, recent); list_del_init(&dreq->recent); dreq->revisit(dreq, 1); } } /* * communicate with user-space * |
a490c681c knfsd: fix cache.... |
704 705 706 707 |
* We have a magic /proc file - /proc/sunrpc/<cachename>/channel. * On read, you get a full request, or block. * On write, an update request is processed. * Poll works if anything to read, and always allows write. |
1da177e4c Linux-2.6.12-rc2 |
708 |
* |
cca5172a7 [NET] SUNRPC: Fix... |
709 |
* Implemented by linked list of requests. Each open file has |
a490c681c knfsd: fix cache.... |
710 |
* a ->private that also exists in this list. New requests are added |
1da177e4c Linux-2.6.12-rc2 |
711 712 713 714 715 716 717 |
* to the end and may wakeup and preceding readers. * New readers are added to the head. If, on read, an item is found with * CACHE_UPCALLING clear, we free it from the list. * */ static DEFINE_SPINLOCK(queue_lock); |
4a3e2f711 [NET] sem2mutex: ... |
718 |
static DEFINE_MUTEX(queue_io_mutex); |
1da177e4c Linux-2.6.12-rc2 |
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
struct cache_queue { struct list_head list; int reader; /* if 0, then request */ }; struct cache_request { struct cache_queue q; struct cache_head *item; char * buf; int len; int readers; }; struct cache_reader { struct cache_queue q; int offset; /* if non-0, we have a refcnt on next request */ }; |
d94af6dea SUNRPC: move cach... |
735 736 737 738 739 740 741 742 743 744 745 |
static int cache_request(struct cache_detail *detail, struct cache_request *crq) { char *bp = crq->buf; int len = PAGE_SIZE; detail->cache_request(detail, crq->item, &bp, &len); if (len < 0) return -EAGAIN; return PAGE_SIZE - len; } |
173912a6a SUNRPC: Move proc... |
746 747 |
static ssize_t cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
748 749 750 |
{ struct cache_reader *rp = filp->private_data; struct cache_request *rq; |
496ad9aa8 new helper: file_... |
751 |
struct inode *inode = file_inode(filp); |
1da177e4c Linux-2.6.12-rc2 |
752 753 754 755 |
int err; if (count == 0) return 0; |
da77005f0 SUNRPC: Remove th... |
756 |
mutex_lock(&inode->i_mutex); /* protect against multiple concurrent |
1da177e4c Linux-2.6.12-rc2 |
757 758 759 760 761 762 763 764 765 766 767 768 |
* readers on this file */ again: spin_lock(&queue_lock); /* need to find next request */ while (rp->q.list.next != &cd->queue && list_entry(rp->q.list.next, struct cache_queue, list) ->reader) { struct list_head *next = rp->q.list.next; list_move(&rp->q.list, next); } if (rp->q.list.next == &cd->queue) { spin_unlock(&queue_lock); |
da77005f0 SUNRPC: Remove th... |
769 |
mutex_unlock(&inode->i_mutex); |
0db74d9a2 SUNRPC: remove BU... |
770 |
WARN_ON_ONCE(rp->offset); |
1da177e4c Linux-2.6.12-rc2 |
771 772 773 |
return 0; } rq = container_of(rp->q.list.next, struct cache_request, q.list); |
0db74d9a2 SUNRPC: remove BU... |
774 |
WARN_ON_ONCE(rq->q.reader); |
1da177e4c Linux-2.6.12-rc2 |
775 776 777 |
if (rp->offset == 0) rq->readers++; spin_unlock(&queue_lock); |
d94af6dea SUNRPC: move cach... |
778 779 780 781 782 783 |
if (rq->len == 0) { err = cache_request(cd, rq); if (err < 0) goto out; rq->len = err; } |
1da177e4c Linux-2.6.12-rc2 |
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 |
if (rp->offset == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) { err = -EAGAIN; spin_lock(&queue_lock); list_move(&rp->q.list, &rq->q.list); spin_unlock(&queue_lock); } else { if (rp->offset + count > rq->len) count = rq->len - rp->offset; err = -EFAULT; if (copy_to_user(buf, rq->buf + rp->offset, count)) goto out; rp->offset += count; if (rp->offset >= rq->len) { rp->offset = 0; spin_lock(&queue_lock); list_move(&rp->q.list, &rq->q.list); spin_unlock(&queue_lock); } err = 0; } out: if (rp->offset == 0) { /* need to release rq */ spin_lock(&queue_lock); rq->readers--; if (rq->readers == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) { list_del(&rq->q.list); spin_unlock(&queue_lock); |
baab935ff [PATCH] knfsd: Co... |
813 |
cache_put(rq->item, cd); |
1da177e4c Linux-2.6.12-rc2 |
814 815 816 817 818 819 820 |
kfree(rq->buf); kfree(rq); } else spin_unlock(&queue_lock); } if (err == -EAGAIN) goto again; |
da77005f0 SUNRPC: Remove th... |
821 |
mutex_unlock(&inode->i_mutex); |
1da177e4c Linux-2.6.12-rc2 |
822 823 |
return err ? err : count; } |
da77005f0 SUNRPC: Remove th... |
824 825 826 827 |
static ssize_t cache_do_downcall(char *kaddr, const char __user *buf, size_t count, struct cache_detail *cd) { ssize_t ret; |
1da177e4c Linux-2.6.12-rc2 |
828 |
|
6d8d17499 nfsd: don't allow... |
829 830 |
if (count == 0) return -EINVAL; |
da77005f0 SUNRPC: Remove th... |
831 832 833 834 835 836 837 838 839 840 841 |
if (copy_from_user(kaddr, buf, count)) return -EFAULT; kaddr[count] = '\0'; ret = cd->cache_parse(cd, kaddr, count); if (!ret) ret = count; return ret; } static ssize_t cache_slow_downcall(const char __user *buf, size_t count, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
842 |
{ |
da77005f0 SUNRPC: Remove th... |
843 844 |
static char write_buf[8192]; /* protected by queue_io_mutex */ ssize_t ret = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
845 |
|
1da177e4c Linux-2.6.12-rc2 |
846 |
if (count >= sizeof(write_buf)) |
da77005f0 SUNRPC: Remove th... |
847 |
goto out; |
4a3e2f711 [NET] sem2mutex: ... |
848 |
mutex_lock(&queue_io_mutex); |
da77005f0 SUNRPC: Remove th... |
849 850 851 852 853 |
ret = cache_do_downcall(write_buf, buf, count, cd); mutex_unlock(&queue_io_mutex); out: return ret; } |
1da177e4c Linux-2.6.12-rc2 |
854 |
|
da77005f0 SUNRPC: Remove th... |
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 |
static ssize_t cache_downcall(struct address_space *mapping, const char __user *buf, size_t count, struct cache_detail *cd) { struct page *page; char *kaddr; ssize_t ret = -ENOMEM; if (count >= PAGE_CACHE_SIZE) goto out_slow; page = find_or_create_page(mapping, 0, GFP_KERNEL); if (!page) goto out_slow; kaddr = kmap(page); ret = cache_do_downcall(kaddr, buf, count, cd); kunmap(page); unlock_page(page); page_cache_release(page); return ret; out_slow: return cache_slow_downcall(buf, count, cd); } |
1da177e4c Linux-2.6.12-rc2 |
879 |
|
173912a6a SUNRPC: Move proc... |
880 881 882 |
static ssize_t cache_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos, struct cache_detail *cd) |
da77005f0 SUNRPC: Remove th... |
883 884 |
{ struct address_space *mapping = filp->f_mapping; |
496ad9aa8 new helper: file_... |
885 |
struct inode *inode = file_inode(filp); |
da77005f0 SUNRPC: Remove th... |
886 887 888 889 890 891 892 893 894 895 |
ssize_t ret = -EINVAL; if (!cd->cache_parse) goto out; mutex_lock(&inode->i_mutex); ret = cache_downcall(mapping, buf, count, cd); mutex_unlock(&inode->i_mutex); out: return ret; |
1da177e4c Linux-2.6.12-rc2 |
896 897 898 |
} static DECLARE_WAIT_QUEUE_HEAD(queue_wait); |
173912a6a SUNRPC: Move proc... |
899 900 |
static unsigned int cache_poll(struct file *filp, poll_table *wait, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
901 902 903 904 |
{ unsigned int mask; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; |
1da177e4c Linux-2.6.12-rc2 |
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 |
poll_wait(filp, &queue_wait, wait); /* alway allow write */ mask = POLL_OUT | POLLWRNORM; if (!rp) return mask; spin_lock(&queue_lock); for (cq= &rp->q; &cq->list != &cd->queue; cq = list_entry(cq->list.next, struct cache_queue, list)) if (!cq->reader) { mask |= POLLIN | POLLRDNORM; break; } spin_unlock(&queue_lock); return mask; } |
173912a6a SUNRPC: Move proc... |
925 926 927 |
static int cache_ioctl(struct inode *ino, struct file *filp, unsigned int cmd, unsigned long arg, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
928 929 930 931 |
{ int len = 0; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; |
1da177e4c Linux-2.6.12-rc2 |
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
if (cmd != FIONREAD || !rp) return -EINVAL; spin_lock(&queue_lock); /* only find the length remaining in current request, * or the length of the next request */ for (cq= &rp->q; &cq->list != &cd->queue; cq = list_entry(cq->list.next, struct cache_queue, list)) if (!cq->reader) { struct cache_request *cr = container_of(cq, struct cache_request, q); len = cr->len - rp->offset; break; } spin_unlock(&queue_lock); return put_user(len, (int __user *)arg); } |
173912a6a SUNRPC: Move proc... |
953 954 |
static int cache_open(struct inode *inode, struct file *filp, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
955 956 |
{ struct cache_reader *rp = NULL; |
f7e86ab92 SUNRPC: cache mus... |
957 958 |
if (!cd || !try_module_get(cd->owner)) return -EACCES; |
1da177e4c Linux-2.6.12-rc2 |
959 960 |
nonseekable_open(inode, filp); if (filp->f_mode & FMODE_READ) { |
1da177e4c Linux-2.6.12-rc2 |
961 |
rp = kmalloc(sizeof(*rp), GFP_KERNEL); |
a7823c797 SUNRPC/cache: add... |
962 963 |
if (!rp) { module_put(cd->owner); |
1da177e4c Linux-2.6.12-rc2 |
964 |
return -ENOMEM; |
a7823c797 SUNRPC/cache: add... |
965 |
} |
1da177e4c Linux-2.6.12-rc2 |
966 967 968 969 970 971 972 973 974 975 |
rp->offset = 0; rp->q.reader = 1; atomic_inc(&cd->readers); spin_lock(&queue_lock); list_add(&rp->q.list, &cd->queue); spin_unlock(&queue_lock); } filp->private_data = rp; return 0; } |
173912a6a SUNRPC: Move proc... |
976 977 |
static int cache_release(struct inode *inode, struct file *filp, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
978 979 |
{ struct cache_reader *rp = filp->private_data; |
1da177e4c Linux-2.6.12-rc2 |
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
if (rp) { spin_lock(&queue_lock); if (rp->offset) { struct cache_queue *cq; for (cq= &rp->q; &cq->list != &cd->queue; cq = list_entry(cq->list.next, struct cache_queue, list)) if (!cq->reader) { container_of(cq, struct cache_request, q) ->readers--; break; } rp->offset = 0; } list_del(&rp->q.list); spin_unlock(&queue_lock); filp->private_data = NULL; kfree(rp); |
c5b29f885 sunrpc: use secon... |
999 |
cd->last_close = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
1000 1001 |
atomic_dec(&cd->readers); } |
f7e86ab92 SUNRPC: cache mus... |
1002 |
module_put(cd->owner); |
1da177e4c Linux-2.6.12-rc2 |
1003 1004 |
return 0; } |
f866a8194 sunrpc/cache: ren... |
1005 |
static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) |
1da177e4c Linux-2.6.12-rc2 |
1006 1007 1008 1009 1010 1011 1012 1013 1014 |
{ struct cache_queue *cq; spin_lock(&queue_lock); list_for_each_entry(cq, &detail->queue, list) if (!cq->reader) { struct cache_request *cr = container_of(cq, struct cache_request, q); if (cr->item != ch) continue; if (cr->readers != 0) |
4013edea9 [PATCH] knfsd: An... |
1015 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
1016 1017 |
list_del(&cr->q.list); spin_unlock(&queue_lock); |
baab935ff [PATCH] knfsd: Co... |
1018 |
cache_put(cr->item, detail); |
1da177e4c Linux-2.6.12-rc2 |
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 |
kfree(cr->buf); kfree(cr); return; } spin_unlock(&queue_lock); } /* * Support routines for text-based upcalls. * Fields are separated by spaces. * Fields are either mangled to quote space tab newline slosh with slosh * or a hexified with a leading \x * Record is terminated with newline. * */ void qword_add(char **bpp, int *lp, char *str) { char *bp = *bpp; int len = *lp; char c; if (len < 0) return; while ((c=*str++) && len) switch(c) { case ' ': case '\t': case ' ': case '\\': if (len >= 4) { *bp++ = '\\'; *bp++ = '0' + ((c & 0300)>>6); *bp++ = '0' + ((c & 0070)>>3); *bp++ = '0' + ((c & 0007)>>0); } len -= 4; break; default: *bp++ = c; len--; } if (c || len <1) len = -1; else { *bp++ = ' '; len--; } *bpp = bp; *lp = len; } |
24c3767e4 SUNRPC: The sunrp... |
1070 |
EXPORT_SYMBOL_GPL(qword_add); |
1da177e4c Linux-2.6.12-rc2 |
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 |
void qword_addhex(char **bpp, int *lp, char *buf, int blen) { char *bp = *bpp; int len = *lp; if (len < 0) return; if (len > 2) { *bp++ = '\\'; *bp++ = 'x'; len -= 2; while (blen && len >= 2) { unsigned char c = *buf++; *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); len -= 2; blen--; } } if (blen || len<1) len = -1; else { *bp++ = ' '; len--; } *bpp = bp; *lp = len; } |
24c3767e4 SUNRPC: The sunrp... |
1099 |
EXPORT_SYMBOL_GPL(qword_addhex); |
1da177e4c Linux-2.6.12-rc2 |
1100 1101 1102 1103 1104 1105 |
static void warn_no_listener(struct cache_detail *detail) { if (detail->last_warn != detail->last_close) { detail->last_warn = detail->last_close; if (detail->warn_no_listener) |
2da8ca26c NFSD: Clean up th... |
1106 |
detail->warn_no_listener(detail, detail->last_close != 0); |
1da177e4c Linux-2.6.12-rc2 |
1107 1108 |
} } |
064975245 nfsd4: fix hang o... |
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
static bool cache_listeners_exist(struct cache_detail *detail) { if (atomic_read(&detail->readers)) return true; if (detail->last_close == 0) /* This cache was never opened */ return false; if (detail->last_close < seconds_since_boot() - 30) /* * We allow for the possibility that someone might * restart a userspace daemon without restarting the * server; but after 30 seconds, we give up. */ return false; return true; } |
1da177e4c Linux-2.6.12-rc2 |
1125 |
/* |
bc74b4f5e SUNRPC: Allow the... |
1126 1127 1128 |
* register an upcall request to user-space and queue it up for read() by the * upcall daemon. * |
1da177e4c Linux-2.6.12-rc2 |
1129 1130 |
* Each request is at most one page long. */ |
21cd1254d SUNRPC: remove "c... |
1131 |
int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h) |
1da177e4c Linux-2.6.12-rc2 |
1132 1133 1134 1135 |
{ char *buf; struct cache_request *crq; |
1da177e4c Linux-2.6.12-rc2 |
1136 |
|
2d4383383 SUNRPC: rework ca... |
1137 1138 |
if (!detail->cache_request) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
1139 |
|
064975245 nfsd4: fix hang o... |
1140 1141 1142 |
if (!cache_listeners_exist(detail)) { warn_no_listener(detail); return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 |
} buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -EAGAIN; crq = kmalloc(sizeof (*crq), GFP_KERNEL); if (!crq) { kfree(buf); return -EAGAIN; } |
1da177e4c Linux-2.6.12-rc2 |
1154 1155 1156 |
crq->q.reader = 0; crq->item = cache_get(h); crq->buf = buf; |
d94af6dea SUNRPC: move cach... |
1157 |
crq->len = 0; |
1da177e4c Linux-2.6.12-rc2 |
1158 1159 1160 1161 1162 1163 1164 |
crq->readers = 0; spin_lock(&queue_lock); list_add_tail(&crq->q.list, &detail->queue); spin_unlock(&queue_lock); wake_up(&queue_wait); return 0; } |
bc74b4f5e SUNRPC: Allow the... |
1165 |
EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); |
1da177e4c Linux-2.6.12-rc2 |
1166 1167 1168 1169 1170 1171 1172 1173 |
/* * parse a message from user-space and pass it * to an appropriate cache * Messages are, like requests, separated into fields by * spaces and dequotes as \xHEXSTRING or embedded nn octal * |
cca5172a7 [NET] SUNRPC: Fix... |
1174 |
* Message is |
1da177e4c Linux-2.6.12-rc2 |
1175 1176 |
* reply cachename expiry key ... content.... * |
cca5172a7 [NET] SUNRPC: Fix... |
1177 |
* key and content are both parsed by cache |
1da177e4c Linux-2.6.12-rc2 |
1178 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
int qword_get(char **bpp, char *dest, int bufsize) { /* return bytes copied, or -1 on error */ char *bp = *bpp; int len = 0; while (*bp == ' ') bp++; if (bp[0] == '\\' && bp[1] == 'x') { /* HEX STRING */ bp += 2; |
e7f483eab sunrpc/cache: don... |
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
while (len < bufsize) { int h, l; h = hex_to_bin(bp[0]); if (h < 0) break; l = hex_to_bin(bp[1]); if (l < 0) break; *dest++ = (h << 4) | l; bp += 2; |
1da177e4c Linux-2.6.12-rc2 |
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 |
len++; } } else { /* text with nn octal quoting */ while (*bp != ' ' && *bp != ' ' && *bp && len < bufsize-1) { if (*bp == '\\' && isodigit(bp[1]) && (bp[1] <= '3') && isodigit(bp[2]) && isodigit(bp[3])) { int byte = (*++bp -'0'); bp++; byte = (byte << 3) | (*bp++ - '0'); byte = (byte << 3) | (*bp++ - '0'); *dest++ = byte; len++; } else { *dest++ = *bp++; len++; } } } if (*bp != ' ' && *bp != ' ' && *bp != '\0') return -1; while (*bp == ' ') bp++; *bpp = bp; *dest = '\0'; return len; } |
24c3767e4 SUNRPC: The sunrp... |
1235 |
EXPORT_SYMBOL_GPL(qword_get); |
1da177e4c Linux-2.6.12-rc2 |
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 |
/* * support /proc/sunrpc/cache/$CACHENAME/content * as a seqfile. * We call ->cache_show passing NULL for the item to * get a header, then pass each real item in the cache */ struct handle { struct cache_detail *cd; }; static void *c_start(struct seq_file *m, loff_t *pos) |
9a429c498 [NET]: Add some a... |
1250 |
__acquires(cd->hash_lock) |
1da177e4c Linux-2.6.12-rc2 |
1251 1252 |
{ loff_t n = *pos; |
95c961747 net: cleanup unsi... |
1253 |
unsigned int hash, entry; |
1da177e4c Linux-2.6.12-rc2 |
1254 1255 |
struct cache_head *ch; struct cache_detail *cd = ((struct handle*)m->private)->cd; |
cca5172a7 [NET] SUNRPC: Fix... |
1256 |
|
1da177e4c Linux-2.6.12-rc2 |
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 |
read_lock(&cd->hash_lock); if (!n--) return SEQ_START_TOKEN; hash = n >> 32; entry = n & ((1LL<<32) - 1); for (ch=cd->hash_table[hash]; ch; ch=ch->next) if (!entry--) return ch; n &= ~((1LL<<32) - 1); do { hash++; n += 1LL<<32; |
cca5172a7 [NET] SUNRPC: Fix... |
1271 |
} while(hash < cd->hash_size && |
1da177e4c Linux-2.6.12-rc2 |
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 |
cd->hash_table[hash]==NULL); if (hash >= cd->hash_size) return NULL; *pos = n+1; return cd->hash_table[hash]; } static void *c_next(struct seq_file *m, void *p, loff_t *pos) { struct cache_head *ch = p; int hash = (*pos >> 32); struct cache_detail *cd = ((struct handle*)m->private)->cd; if (p == SEQ_START_TOKEN) hash = 0; else if (ch->next == NULL) { hash++; *pos += 1LL<<32; } else { ++*pos; return ch->next; } *pos &= ~((1LL<<32) - 1); while (hash < cd->hash_size && cd->hash_table[hash] == NULL) { hash++; *pos += 1LL<<32; } if (hash >= cd->hash_size) return NULL; ++*pos; return cd->hash_table[hash]; } static void c_stop(struct seq_file *m, void *p) |
9a429c498 [NET]: Add some a... |
1307 |
__releases(cd->hash_lock) |
1da177e4c Linux-2.6.12-rc2 |
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 |
{ struct cache_detail *cd = ((struct handle*)m->private)->cd; read_unlock(&cd->hash_lock); } static int c_show(struct seq_file *m, void *p) { struct cache_head *cp = p; struct cache_detail *cd = ((struct handle*)m->private)->cd; if (p == SEQ_START_TOKEN) return cd->cache_show(m, cd, NULL); ifdebug(CACHE) |
4013edea9 [PATCH] knfsd: An... |
1322 1323 |
seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx ", |
c5b29f885 sunrpc: use secon... |
1324 1325 |
convert_to_wallclock(cp->expiry_time), atomic_read(&cp->ref.refcount), cp->flags); |
1da177e4c Linux-2.6.12-rc2 |
1326 1327 1328 1329 |
cache_get(cp); if (cache_check(cd, cp, NULL)) /* cache_check does a cache_put on failure */ seq_printf(m, "# "); |
200724a70 SUNRPC/cache: fix... |
1330 1331 1332 |
else { if (cache_is_expired(cd, cp)) seq_printf(m, "# "); |
1da177e4c Linux-2.6.12-rc2 |
1333 |
cache_put(cp, cd); |
200724a70 SUNRPC/cache: fix... |
1334 |
} |
1da177e4c Linux-2.6.12-rc2 |
1335 1336 1337 |
return cd->cache_show(m, cd, cp); } |
56b3d975b [NET]: Make all i... |
1338 |
static const struct seq_operations cache_content_op = { |
1da177e4c Linux-2.6.12-rc2 |
1339 1340 1341 1342 1343 |
.start = c_start, .next = c_next, .stop = c_stop, .show = c_show, }; |
173912a6a SUNRPC: Move proc... |
1344 1345 |
static int content_open(struct inode *inode, struct file *file, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
1346 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1347 |
struct handle *han; |
1da177e4c Linux-2.6.12-rc2 |
1348 |
|
f7e86ab92 SUNRPC: cache mus... |
1349 1350 |
if (!cd || !try_module_get(cd->owner)) return -EACCES; |
ec9310351 [SUNRPC]: Make th... |
1351 |
han = __seq_open_private(file, &cache_content_op, sizeof(*han)); |
a5990ea12 sunrpc/cache: fix... |
1352 1353 |
if (han == NULL) { module_put(cd->owner); |
1da177e4c Linux-2.6.12-rc2 |
1354 |
return -ENOMEM; |
a5990ea12 sunrpc/cache: fix... |
1355 |
} |
1da177e4c Linux-2.6.12-rc2 |
1356 1357 |
han->cd = cd; |
ec9310351 [SUNRPC]: Make th... |
1358 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1359 |
} |
1da177e4c Linux-2.6.12-rc2 |
1360 |
|
f7e86ab92 SUNRPC: cache mus... |
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 |
static int content_release(struct inode *inode, struct file *file, struct cache_detail *cd) { int ret = seq_release_private(inode, file); module_put(cd->owner); return ret; } static int open_flush(struct inode *inode, struct file *file, struct cache_detail *cd) { if (!cd || !try_module_get(cd->owner)) return -EACCES; return nonseekable_open(inode, file); } static int release_flush(struct inode *inode, struct file *file, struct cache_detail *cd) { module_put(cd->owner); return 0; } |
1da177e4c Linux-2.6.12-rc2 |
1383 1384 |
static ssize_t read_flush(struct file *file, char __user *buf, |
173912a6a SUNRPC: Move proc... |
1385 1386 |
size_t count, loff_t *ppos, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
1387 |
{ |
212ba9069 SUNRPC: Prevent k... |
1388 |
char tbuf[22]; |
1da177e4c Linux-2.6.12-rc2 |
1389 |
unsigned long p = *ppos; |
01b2969a8 SUNRPC: Prevent l... |
1390 |
size_t len; |
1da177e4c Linux-2.6.12-rc2 |
1391 |
|
212ba9069 SUNRPC: Prevent k... |
1392 1393 |
snprintf(tbuf, sizeof(tbuf), "%lu ", convert_to_wallclock(cd->flush_time)); |
1da177e4c Linux-2.6.12-rc2 |
1394 1395 1396 1397 |
len = strlen(tbuf); if (p >= len) return 0; len -= p; |
01b2969a8 SUNRPC: Prevent l... |
1398 1399 |
if (len > count) len = count; |
1da177e4c Linux-2.6.12-rc2 |
1400 |
if (copy_to_user(buf, (void*)(tbuf+p), len)) |
01b2969a8 SUNRPC: Prevent l... |
1401 1402 |
return -EFAULT; *ppos += len; |
1da177e4c Linux-2.6.12-rc2 |
1403 1404 |
return len; } |
173912a6a SUNRPC: Move proc... |
1405 1406 1407 |
static ssize_t write_flush(struct file *file, const char __user *buf, size_t count, loff_t *ppos, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
1408 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1409 |
char tbuf[20]; |
c5b29f885 sunrpc: use secon... |
1410 |
char *bp, *ep; |
1da177e4c Linux-2.6.12-rc2 |
1411 1412 1413 1414 1415 |
if (*ppos || count > sizeof(tbuf)-1) return -EINVAL; if (copy_from_user(tbuf, buf, count)) return -EFAULT; tbuf[count] = 0; |
c5b29f885 sunrpc: use secon... |
1416 |
simple_strtoul(tbuf, &ep, 0); |
1da177e4c Linux-2.6.12-rc2 |
1417 1418 1419 |
if (*ep && *ep != ' ') return -EINVAL; |
c5b29f885 sunrpc: use secon... |
1420 1421 1422 |
bp = tbuf; cd->flush_time = get_expiry(&bp); cd->nextcheck = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
1423 1424 1425 1426 1427 |
cache_flush(); *ppos += count; return count; } |
173912a6a SUNRPC: Move proc... |
1428 1429 1430 |
static ssize_t cache_read_procfs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { |
d9dda78ba procfs: new helpe... |
1431 |
struct cache_detail *cd = PDE_DATA(file_inode(filp)); |
173912a6a SUNRPC: Move proc... |
1432 1433 1434 1435 1436 1437 1438 |
return cache_read(filp, buf, count, ppos, cd); } static ssize_t cache_write_procfs(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { |
d9dda78ba procfs: new helpe... |
1439 |
struct cache_detail *cd = PDE_DATA(file_inode(filp)); |
173912a6a SUNRPC: Move proc... |
1440 1441 1442 1443 1444 1445 |
return cache_write(filp, buf, count, ppos, cd); } static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait) { |
d9dda78ba procfs: new helpe... |
1446 |
struct cache_detail *cd = PDE_DATA(file_inode(filp)); |
173912a6a SUNRPC: Move proc... |
1447 1448 1449 |
return cache_poll(filp, wait, cd); } |
d79b6f4de procfs: Push down... |
1450 1451 |
static long cache_ioctl_procfs(struct file *filp, unsigned int cmd, unsigned long arg) |
173912a6a SUNRPC: Move proc... |
1452 |
{ |
496ad9aa8 new helper: file_... |
1453 |
struct inode *inode = file_inode(filp); |
d9dda78ba procfs: new helpe... |
1454 |
struct cache_detail *cd = PDE_DATA(inode); |
173912a6a SUNRPC: Move proc... |
1455 |
|
a6f8dbc65 sunrpc: remove th... |
1456 |
return cache_ioctl(inode, filp, cmd, arg, cd); |
173912a6a SUNRPC: Move proc... |
1457 1458 1459 1460 |
} static int cache_open_procfs(struct inode *inode, struct file *filp) { |
d9dda78ba procfs: new helpe... |
1461 |
struct cache_detail *cd = PDE_DATA(inode); |
173912a6a SUNRPC: Move proc... |
1462 1463 1464 1465 1466 1467 |
return cache_open(inode, filp, cd); } static int cache_release_procfs(struct inode *inode, struct file *filp) { |
d9dda78ba procfs: new helpe... |
1468 |
struct cache_detail *cd = PDE_DATA(inode); |
173912a6a SUNRPC: Move proc... |
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
return cache_release(inode, filp, cd); } static const struct file_operations cache_file_operations_procfs = { .owner = THIS_MODULE, .llseek = no_llseek, .read = cache_read_procfs, .write = cache_write_procfs, .poll = cache_poll_procfs, |
d79b6f4de procfs: Push down... |
1479 |
.unlocked_ioctl = cache_ioctl_procfs, /* for FIONREAD */ |
173912a6a SUNRPC: Move proc... |
1480 1481 |
.open = cache_open_procfs, .release = cache_release_procfs, |
1da177e4c Linux-2.6.12-rc2 |
1482 |
}; |
173912a6a SUNRPC: Move proc... |
1483 1484 1485 |
static int content_open_procfs(struct inode *inode, struct file *filp) { |
d9dda78ba procfs: new helpe... |
1486 |
struct cache_detail *cd = PDE_DATA(inode); |
173912a6a SUNRPC: Move proc... |
1487 1488 1489 |
return content_open(inode, filp, cd); } |
f7e86ab92 SUNRPC: cache mus... |
1490 1491 |
static int content_release_procfs(struct inode *inode, struct file *filp) { |
d9dda78ba procfs: new helpe... |
1492 |
struct cache_detail *cd = PDE_DATA(inode); |
f7e86ab92 SUNRPC: cache mus... |
1493 1494 1495 |
return content_release(inode, filp, cd); } |
173912a6a SUNRPC: Move proc... |
1496 1497 1498 1499 |
static const struct file_operations content_file_operations_procfs = { .open = content_open_procfs, .read = seq_read, .llseek = seq_lseek, |
f7e86ab92 SUNRPC: cache mus... |
1500 |
.release = content_release_procfs, |
173912a6a SUNRPC: Move proc... |
1501 |
}; |
f7e86ab92 SUNRPC: cache mus... |
1502 1503 |
static int open_flush_procfs(struct inode *inode, struct file *filp) { |
d9dda78ba procfs: new helpe... |
1504 |
struct cache_detail *cd = PDE_DATA(inode); |
f7e86ab92 SUNRPC: cache mus... |
1505 1506 1507 1508 1509 1510 |
return open_flush(inode, filp, cd); } static int release_flush_procfs(struct inode *inode, struct file *filp) { |
d9dda78ba procfs: new helpe... |
1511 |
struct cache_detail *cd = PDE_DATA(inode); |
f7e86ab92 SUNRPC: cache mus... |
1512 1513 1514 |
return release_flush(inode, filp, cd); } |
173912a6a SUNRPC: Move proc... |
1515 1516 1517 |
static ssize_t read_flush_procfs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { |
d9dda78ba procfs: new helpe... |
1518 |
struct cache_detail *cd = PDE_DATA(file_inode(filp)); |
173912a6a SUNRPC: Move proc... |
1519 1520 1521 1522 1523 1524 1525 1526 |
return read_flush(filp, buf, count, ppos, cd); } static ssize_t write_flush_procfs(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { |
d9dda78ba procfs: new helpe... |
1527 |
struct cache_detail *cd = PDE_DATA(file_inode(filp)); |
173912a6a SUNRPC: Move proc... |
1528 1529 1530 1531 1532 |
return write_flush(filp, buf, count, ppos, cd); } static const struct file_operations cache_flush_operations_procfs = { |
f7e86ab92 SUNRPC: cache mus... |
1533 |
.open = open_flush_procfs, |
173912a6a SUNRPC: Move proc... |
1534 1535 |
.read = read_flush_procfs, .write = write_flush_procfs, |
f7e86ab92 SUNRPC: cache mus... |
1536 |
.release = release_flush_procfs, |
6038f373a llseek: automatic... |
1537 |
.llseek = no_llseek, |
1da177e4c Linux-2.6.12-rc2 |
1538 |
}; |
173912a6a SUNRPC: Move proc... |
1539 |
|
593ce16b9 sunrpc: Add routi... |
1540 |
static void remove_cache_proc_entries(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1541 |
{ |
4f42d0d53 sunrpc: Make the ... |
1542 |
struct sunrpc_net *sn; |
173912a6a SUNRPC: Move proc... |
1543 1544 1545 1546 1547 1548 1549 1550 1551 |
if (cd->u.procfs.proc_ent == NULL) return; if (cd->u.procfs.flush_ent) remove_proc_entry("flush", cd->u.procfs.proc_ent); if (cd->u.procfs.channel_ent) remove_proc_entry("channel", cd->u.procfs.proc_ent); if (cd->u.procfs.content_ent) remove_proc_entry("content", cd->u.procfs.proc_ent); cd->u.procfs.proc_ent = NULL; |
4f42d0d53 sunrpc: Make the ... |
1552 1553 |
sn = net_generic(net, sunrpc_net_id); remove_proc_entry(cd->name, sn->proc_net_rpc); |
173912a6a SUNRPC: Move proc... |
1554 1555 1556 |
} #ifdef CONFIG_PROC_FS |
593ce16b9 sunrpc: Add routi... |
1557 |
static int create_cache_proc_entries(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1558 1559 |
{ struct proc_dir_entry *p; |
4f42d0d53 sunrpc: Make the ... |
1560 |
struct sunrpc_net *sn; |
173912a6a SUNRPC: Move proc... |
1561 |
|
4f42d0d53 sunrpc: Make the ... |
1562 1563 |
sn = net_generic(net, sunrpc_net_id); cd->u.procfs.proc_ent = proc_mkdir(cd->name, sn->proc_net_rpc); |
173912a6a SUNRPC: Move proc... |
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 |
if (cd->u.procfs.proc_ent == NULL) goto out_nomem; cd->u.procfs.channel_ent = NULL; cd->u.procfs.content_ent = NULL; p = proc_create_data("flush", S_IFREG|S_IRUSR|S_IWUSR, cd->u.procfs.proc_ent, &cache_flush_operations_procfs, cd); cd->u.procfs.flush_ent = p; if (p == NULL) goto out_nomem; |
2d4383383 SUNRPC: rework ca... |
1575 |
if (cd->cache_request || cd->cache_parse) { |
173912a6a SUNRPC: Move proc... |
1576 1577 1578 1579 1580 1581 1582 1583 |
p = proc_create_data("channel", S_IFREG|S_IRUSR|S_IWUSR, cd->u.procfs.proc_ent, &cache_file_operations_procfs, cd); cd->u.procfs.channel_ent = p; if (p == NULL) goto out_nomem; } if (cd->cache_show) { |
ec1686761 nfsd: Remove writ... |
1584 |
p = proc_create_data("content", S_IFREG|S_IRUSR, |
173912a6a SUNRPC: Move proc... |
1585 1586 1587 1588 1589 1590 1591 1592 |
cd->u.procfs.proc_ent, &content_file_operations_procfs, cd); cd->u.procfs.content_ent = p; if (p == NULL) goto out_nomem; } return 0; out_nomem: |
593ce16b9 sunrpc: Add routi... |
1593 |
remove_cache_proc_entries(cd, net); |
173912a6a SUNRPC: Move proc... |
1594 1595 1596 |
return -ENOMEM; } #else /* CONFIG_PROC_FS */ |
593ce16b9 sunrpc: Add routi... |
1597 |
static int create_cache_proc_entries(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1598 1599 1600 1601 |
{ return 0; } #endif |
8eab945c5 sunrpc: make the ... |
1602 1603 |
void __init cache_initialize(void) { |
203b42f73 workqueue: make d... |
1604 |
INIT_DEFERRABLE_WORK(&cache_cleaner, do_cache_clean); |
8eab945c5 sunrpc: make the ... |
1605 |
} |
593ce16b9 sunrpc: Add routi... |
1606 |
int cache_register_net(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1607 1608 1609 1610 |
{ int ret; sunrpc_init_cache_detail(cd); |
593ce16b9 sunrpc: Add routi... |
1611 |
ret = create_cache_proc_entries(cd, net); |
173912a6a SUNRPC: Move proc... |
1612 1613 1614 1615 |
if (ret) sunrpc_destroy_cache_detail(cd); return ret; } |
f5c8593b9 NFSd: use network... |
1616 |
EXPORT_SYMBOL_GPL(cache_register_net); |
593ce16b9 sunrpc: Add routi... |
1617 |
|
593ce16b9 sunrpc: Add routi... |
1618 |
void cache_unregister_net(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1619 |
{ |
593ce16b9 sunrpc: Add routi... |
1620 |
remove_cache_proc_entries(cd, net); |
173912a6a SUNRPC: Move proc... |
1621 1622 |
sunrpc_destroy_cache_detail(cd); } |
f5c8593b9 NFSd: use network... |
1623 |
EXPORT_SYMBOL_GPL(cache_unregister_net); |
593ce16b9 sunrpc: Add routi... |
1624 |
|
0a402d5a6 SUNRPC: cache cre... |
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 |
struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net) { struct cache_detail *cd; cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL); if (cd == NULL) return ERR_PTR(-ENOMEM); cd->hash_table = kzalloc(cd->hash_size * sizeof(struct cache_head *), GFP_KERNEL); if (cd->hash_table == NULL) { kfree(cd); return ERR_PTR(-ENOMEM); } cd->net = net; return cd; } EXPORT_SYMBOL_GPL(cache_create_net); void cache_destroy_net(struct cache_detail *cd, struct net *net) |
593ce16b9 sunrpc: Add routi... |
1645 |
{ |
0a402d5a6 SUNRPC: cache cre... |
1646 1647 |
kfree(cd->hash_table); kfree(cd); |
593ce16b9 sunrpc: Add routi... |
1648 |
} |
0a402d5a6 SUNRPC: cache cre... |
1649 |
EXPORT_SYMBOL_GPL(cache_destroy_net); |
8854e82d9 SUNRPC: Add an rp... |
1650 1651 1652 1653 |
static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { |
496ad9aa8 new helper: file_... |
1654 |
struct cache_detail *cd = RPC_I(file_inode(filp))->private; |
8854e82d9 SUNRPC: Add an rp... |
1655 1656 1657 1658 1659 1660 1661 |
return cache_read(filp, buf, count, ppos, cd); } static ssize_t cache_write_pipefs(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { |
496ad9aa8 new helper: file_... |
1662 |
struct cache_detail *cd = RPC_I(file_inode(filp))->private; |
8854e82d9 SUNRPC: Add an rp... |
1663 1664 1665 1666 1667 1668 |
return cache_write(filp, buf, count, ppos, cd); } static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait) { |
496ad9aa8 new helper: file_... |
1669 |
struct cache_detail *cd = RPC_I(file_inode(filp))->private; |
8854e82d9 SUNRPC: Add an rp... |
1670 1671 1672 |
return cache_poll(filp, wait, cd); } |
9918ff26b sunrpc: Pushdown ... |
1673 |
static long cache_ioctl_pipefs(struct file *filp, |
8854e82d9 SUNRPC: Add an rp... |
1674 1675 |
unsigned int cmd, unsigned long arg) { |
496ad9aa8 new helper: file_... |
1676 |
struct inode *inode = file_inode(filp); |
8854e82d9 SUNRPC: Add an rp... |
1677 |
struct cache_detail *cd = RPC_I(inode)->private; |
a6f8dbc65 sunrpc: remove th... |
1678 |
return cache_ioctl(inode, filp, cmd, arg, cd); |
8854e82d9 SUNRPC: Add an rp... |
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 |
} static int cache_open_pipefs(struct inode *inode, struct file *filp) { struct cache_detail *cd = RPC_I(inode)->private; return cache_open(inode, filp, cd); } static int cache_release_pipefs(struct inode *inode, struct file *filp) { struct cache_detail *cd = RPC_I(inode)->private; return cache_release(inode, filp, cd); } const struct file_operations cache_file_operations_pipefs = { .owner = THIS_MODULE, .llseek = no_llseek, .read = cache_read_pipefs, .write = cache_write_pipefs, .poll = cache_poll_pipefs, |
9918ff26b sunrpc: Pushdown ... |
1701 |
.unlocked_ioctl = cache_ioctl_pipefs, /* for FIONREAD */ |
8854e82d9 SUNRPC: Add an rp... |
1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 |
.open = cache_open_pipefs, .release = cache_release_pipefs, }; static int content_open_pipefs(struct inode *inode, struct file *filp) { struct cache_detail *cd = RPC_I(inode)->private; return content_open(inode, filp, cd); } |
f7e86ab92 SUNRPC: cache mus... |
1712 1713 1714 1715 1716 1717 |
static int content_release_pipefs(struct inode *inode, struct file *filp) { struct cache_detail *cd = RPC_I(inode)->private; return content_release(inode, filp, cd); } |
8854e82d9 SUNRPC: Add an rp... |
1718 1719 1720 1721 |
const struct file_operations content_file_operations_pipefs = { .open = content_open_pipefs, .read = seq_read, .llseek = seq_lseek, |
f7e86ab92 SUNRPC: cache mus... |
1722 |
.release = content_release_pipefs, |
8854e82d9 SUNRPC: Add an rp... |
1723 |
}; |
f7e86ab92 SUNRPC: cache mus... |
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
static int open_flush_pipefs(struct inode *inode, struct file *filp) { struct cache_detail *cd = RPC_I(inode)->private; return open_flush(inode, filp, cd); } static int release_flush_pipefs(struct inode *inode, struct file *filp) { struct cache_detail *cd = RPC_I(inode)->private; return release_flush(inode, filp, cd); } |
8854e82d9 SUNRPC: Add an rp... |
1737 1738 1739 |
static ssize_t read_flush_pipefs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { |
496ad9aa8 new helper: file_... |
1740 |
struct cache_detail *cd = RPC_I(file_inode(filp))->private; |
8854e82d9 SUNRPC: Add an rp... |
1741 1742 1743 1744 1745 1746 1747 1748 |
return read_flush(filp, buf, count, ppos, cd); } static ssize_t write_flush_pipefs(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { |
496ad9aa8 new helper: file_... |
1749 |
struct cache_detail *cd = RPC_I(file_inode(filp))->private; |
8854e82d9 SUNRPC: Add an rp... |
1750 1751 1752 1753 1754 |
return write_flush(filp, buf, count, ppos, cd); } const struct file_operations cache_flush_operations_pipefs = { |
f7e86ab92 SUNRPC: cache mus... |
1755 |
.open = open_flush_pipefs, |
8854e82d9 SUNRPC: Add an rp... |
1756 1757 |
.read = read_flush_pipefs, .write = write_flush_pipefs, |
f7e86ab92 SUNRPC: cache mus... |
1758 |
.release = release_flush_pipefs, |
6038f373a llseek: automatic... |
1759 |
.llseek = no_llseek, |
8854e82d9 SUNRPC: Add an rp... |
1760 1761 1762 |
}; int sunrpc_cache_register_pipefs(struct dentry *parent, |
64f1426f3 sunrpc: propagate... |
1763 |
const char *name, umode_t umode, |
8854e82d9 SUNRPC: Add an rp... |
1764 1765 1766 1767 1768 |
struct cache_detail *cd) { struct qstr q; struct dentry *dir; int ret = 0; |
8854e82d9 SUNRPC: Add an rp... |
1769 1770 1771 1772 1773 1774 |
q.name = name; q.len = strlen(name); q.hash = full_name_hash(q.name, q.len); dir = rpc_create_cache_dir(parent, &q, umode, cd); if (!IS_ERR(dir)) cd->u.pipefs.dir = dir; |
820f9442e SUNRPC: split cac... |
1775 |
else |
8854e82d9 SUNRPC: Add an rp... |
1776 |
ret = PTR_ERR(dir); |
8854e82d9 SUNRPC: Add an rp... |
1777 1778 1779 1780 1781 1782 1783 1784 |
return ret; } EXPORT_SYMBOL_GPL(sunrpc_cache_register_pipefs); void sunrpc_cache_unregister_pipefs(struct cache_detail *cd) { rpc_remove_cache_dir(cd->u.pipefs.dir); cd->u.pipefs.dir = NULL; |
8854e82d9 SUNRPC: Add an rp... |
1785 1786 |
} EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); |