Blame view
net/sunrpc/cache.c
43 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 193 194 195 196 |
static int cache_make_upcall(struct cache_detail *cd, struct cache_head *h) { if (!cd->cache_upcall) return -EINVAL; return cd->cache_upcall(cd, h); } |
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 |
|
5b7a1b9f9 SUNRPC: Ensure we... |
339 |
static 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 |
} |
5b7a1b9f9 SUNRPC: Ensure we... |
355 |
static void sunrpc_destroy_cache_detail(struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
356 357 358 359 360 361 362 |
{ 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... |
363 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
364 365 366 367 368 369 |
} 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 |
370 371 |
if (list_empty(&cache_list)) { /* module must be being unloaded so its safe to kill the worker */ |
4011cd978 SUNRPC: Replace f... |
372 |
cancel_delayed_work_sync(&cache_cleaner); |
1da177e4c Linux-2.6.12-rc2 |
373 |
} |
df95a9d4f knfsd: cache unre... |
374 375 376 377 |
return; out: printk(KERN_ERR "nfsd: failed to unregister %s cache ", cd->name); |
1da177e4c Linux-2.6.12-rc2 |
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
} /* 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... |
406 |
if (current_detail->nextcheck > seconds_since_boot()) |
1da177e4c Linux-2.6.12-rc2 |
407 408 409 |
current_index = current_detail->hash_size; else { current_index = 0; |
c5b29f885 sunrpc: use secon... |
410 |
current_detail->nextcheck = seconds_since_boot()+30*60; |
1da177e4c Linux-2.6.12-rc2 |
411 412 413 414 415 416 417 418 419 420 |
} } /* 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... |
421 |
|
1da177e4c Linux-2.6.12-rc2 |
422 423 424 |
if (current_detail && current_index < current_detail->hash_size) { struct cache_head *ch, **cp; struct cache_detail *d; |
cca5172a7 [NET] SUNRPC: Fix... |
425 |
|
1da177e4c Linux-2.6.12-rc2 |
426 427 428 |
write_lock(¤t_detail->hash_lock); /* Ok, now to clean this strand */ |
cca5172a7 [NET] SUNRPC: Fix... |
429 |
|
1da177e4c Linux-2.6.12-rc2 |
430 |
cp = & current_detail->hash_table[current_index]; |
3af4974eb sunrpc: don't kee... |
431 |
for (ch = *cp ; ch ; cp = & ch->next, ch = *cp) { |
1da177e4c Linux-2.6.12-rc2 |
432 433 |
if (current_detail->nextcheck > ch->expiry_time) current_detail->nextcheck = ch->expiry_time+1; |
2f50d8b63 sunrpc/cache: fac... |
434 |
if (!cache_is_expired(current_detail, ch)) |
1da177e4c Linux-2.6.12-rc2 |
435 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
436 |
|
1da177e4c Linux-2.6.12-rc2 |
437 438 439 440 |
*cp = ch->next; ch->next = NULL; current_detail->entries--; rv = 1; |
3af4974eb sunrpc: don't kee... |
441 |
break; |
1da177e4c Linux-2.6.12-rc2 |
442 |
} |
3af4974eb sunrpc: don't kee... |
443 |
|
1da177e4c Linux-2.6.12-rc2 |
444 445 446 447 448 |
write_unlock(¤t_detail->hash_lock); d = current_detail; if (!ch) current_index ++; spin_unlock(&cache_list_lock); |
5c4d26390 sunrpc/cache: mak... |
449 |
if (ch) { |
3af4974eb sunrpc: don't kee... |
450 451 |
if (test_and_clear_bit(CACHE_PENDING, &ch->flags)) cache_dequeue(current_detail, ch); |
5c4d26390 sunrpc/cache: mak... |
452 |
cache_revisit_request(ch); |
baab935ff [PATCH] knfsd: Co... |
453 |
cache_put(ch, d); |
5c4d26390 sunrpc/cache: mak... |
454 |
} |
1da177e4c Linux-2.6.12-rc2 |
455 456 457 458 459 460 461 462 463 |
} 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 ... |
464 |
static void do_cache_clean(struct work_struct *work) |
1da177e4c Linux-2.6.12-rc2 |
465 466 467 |
{ int delay = 5; if (cache_clean() == -1) |
6aad89c83 sunrpc: align cac... |
468 |
delay = round_jiffies_relative(30*HZ); |
1da177e4c Linux-2.6.12-rc2 |
469 470 471 472 473 474 475 |
if (list_empty(&cache_list)) delay = 0; if (delay) schedule_delayed_work(&cache_cleaner, delay); } |
cca5172a7 [NET] SUNRPC: Fix... |
476 |
/* |
1da177e4c Linux-2.6.12-rc2 |
477 |
* Clean all caches promptly. This just calls cache_clean |
cca5172a7 [NET] SUNRPC: Fix... |
478 |
* repeatedly until we are sure that every cache has had a chance to |
1da177e4c Linux-2.6.12-rc2 |
479 480 481 482 483 484 485 486 487 |
* be fully cleaned */ void cache_flush(void) { while (cache_clean() != -1) cond_resched(); while (cache_clean() != -1) cond_resched(); } |
24c3767e4 SUNRPC: The sunrp... |
488 |
EXPORT_SYMBOL_GPL(cache_flush); |
1da177e4c Linux-2.6.12-rc2 |
489 490 491 492 |
void cache_purge(struct cache_detail *detail) { detail->flush_time = LONG_MAX; |
c5b29f885 sunrpc: use secon... |
493 |
detail->nextcheck = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
494 495 496 |
cache_flush(); detail->flush_time = 1; } |
24c3767e4 SUNRPC: The sunrp... |
497 |
EXPORT_SYMBOL_GPL(cache_purge); |
1da177e4c Linux-2.6.12-rc2 |
498 499 500 501 502 503 504 505 506 507 |
/* * 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... |
508 |
* structure, we allow the request to provide a |
1da177e4c Linux-2.6.12-rc2 |
509 510 511 512 513 514 515 516 517 518 519 520 521 |
* 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... |
522 |
static struct hlist_head cache_defer_hash[DFR_HASHSIZE]; |
1da177e4c Linux-2.6.12-rc2 |
523 |
static int cache_defer_cnt; |
6610f720e svcrpc: minor cac... |
524 525 |
static void __unhash_deferred_req(struct cache_deferred_req *dreq) { |
111744927 sunrpc/cache: cha... |
526 |
hlist_del_init(&dreq->hash); |
e33534d54 sunrpc/cache: cen... |
527 528 529 530 |
if (!list_empty(&dreq->recent)) { list_del_init(&dreq->recent); cache_defer_cnt--; } |
6610f720e svcrpc: minor cac... |
531 532 533 |
} static void __hash_deferred_req(struct cache_deferred_req *dreq, struct cache_head *item) |
1da177e4c Linux-2.6.12-rc2 |
534 |
{ |
1da177e4c Linux-2.6.12-rc2 |
535 |
int hash = DFR_HASH(item); |
e33534d54 sunrpc/cache: cen... |
536 |
INIT_LIST_HEAD(&dreq->recent); |
111744927 sunrpc/cache: cha... |
537 |
hlist_add_head(&dreq->hash, &cache_defer_hash[hash]); |
6610f720e svcrpc: minor cac... |
538 |
} |
e33534d54 sunrpc/cache: cen... |
539 540 541 |
static void setup_deferral(struct cache_deferred_req *dreq, struct cache_head *item, int count_me) |
1da177e4c Linux-2.6.12-rc2 |
542 |
{ |
1da177e4c Linux-2.6.12-rc2 |
543 544 |
dreq->item = item; |
1da177e4c Linux-2.6.12-rc2 |
545 546 |
spin_lock(&cache_defer_lock); |
6610f720e svcrpc: minor cac... |
547 |
__hash_deferred_req(dreq, item); |
1da177e4c Linux-2.6.12-rc2 |
548 |
|
e33534d54 sunrpc/cache: cen... |
549 550 551 |
if (count_me) { cache_defer_cnt++; list_add(&dreq->recent, &cache_defer_list); |
1da177e4c Linux-2.6.12-rc2 |
552 |
} |
e33534d54 sunrpc/cache: cen... |
553 |
|
1da177e4c Linux-2.6.12-rc2 |
554 |
spin_unlock(&cache_defer_lock); |
3211af111 svcrpc: cache def... |
555 |
} |
f16b6e8d8 sunrpc/cache: all... |
556 |
|
3211af111 svcrpc: cache def... |
557 558 559 560 561 562 563 564 565 566 567 |
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 ... |
568 |
static void cache_wait_req(struct cache_req *req, struct cache_head *item) |
3211af111 svcrpc: cache def... |
569 570 571 |
{ struct thread_deferred_req sleeper; struct cache_deferred_req *dreq = &sleeper.handle; |
3211af111 svcrpc: cache def... |
572 573 574 |
sleeper.completion = COMPLETION_INITIALIZER_ONSTACK(sleeper.completion); dreq->revisit = cache_restart_thread; |
e33534d54 sunrpc/cache: cen... |
575 |
setup_deferral(dreq, item, 0); |
3211af111 svcrpc: cache def... |
576 |
|
d29068c43 sunrpc: Simplify ... |
577 |
if (!test_bit(CACHE_PENDING, &item->flags) || |
277f68dbb sunrpc: fix race ... |
578 |
wait_for_completion_interruptible_timeout( |
3211af111 svcrpc: cache def... |
579 580 581 582 583 |
&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... |
584 |
if (!hlist_unhashed(&sleeper.handle.hash)) { |
3211af111 svcrpc: cache def... |
585 586 587 588 589 590 591 |
__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... |
592 |
*/ |
3211af111 svcrpc: cache def... |
593 594 |
spin_unlock(&cache_defer_lock); wait_for_completion(&sleeper.completion); |
f16b6e8d8 sunrpc/cache: all... |
595 |
} |
3211af111 svcrpc: cache def... |
596 |
} |
3211af111 svcrpc: cache def... |
597 |
} |
e33534d54 sunrpc/cache: cen... |
598 |
static void cache_limit_defers(void) |
3211af111 svcrpc: cache def... |
599 |
{ |
e33534d54 sunrpc/cache: cen... |
600 601 602 603 |
/* Make sure we haven't exceed the limit of allowed deferred * requests. */ struct cache_deferred_req *discard = NULL; |
3211af111 svcrpc: cache def... |
604 |
|
e33534d54 sunrpc/cache: cen... |
605 606 |
if (cache_defer_cnt <= DFR_MAX) return; |
d29068c43 sunrpc: Simplify ... |
607 |
|
e33534d54 sunrpc/cache: cen... |
608 609 610 611 612 613 614 615 616 617 618 619 620 |
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... |
621 |
if (discard) |
cd68c374e sunrpc/cache: avo... |
622 |
discard->revisit(discard, 1); |
e33534d54 sunrpc/cache: cen... |
623 |
} |
cd68c374e sunrpc/cache: avo... |
624 |
|
d76d1815f svcrpc: avoid dou... |
625 626 |
/* 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... |
627 628 |
{ struct cache_deferred_req *dreq; |
d29068c43 sunrpc: Simplify ... |
629 |
|
3211af111 svcrpc: cache def... |
630 |
if (req->thread_wait) { |
d29068c43 sunrpc: Simplify ... |
631 632 |
cache_wait_req(req, item); if (!test_bit(CACHE_PENDING, &item->flags)) |
d76d1815f svcrpc: avoid dou... |
633 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
634 |
} |
3211af111 svcrpc: cache def... |
635 636 |
dreq = req->defer(req); if (dreq == NULL) |
d76d1815f svcrpc: avoid dou... |
637 |
return false; |
e33534d54 sunrpc/cache: cen... |
638 |
setup_deferral(dreq, item, 1); |
d29068c43 sunrpc: Simplify ... |
639 640 641 642 643 |
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... |
644 645 |
cache_limit_defers(); |
d76d1815f svcrpc: avoid dou... |
646 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
647 648 649 650 651 652 |
} static void cache_revisit_request(struct cache_head *item) { struct cache_deferred_req *dreq; struct list_head pending; |
111744927 sunrpc/cache: cha... |
653 |
struct hlist_node *lp, *tmp; |
1da177e4c Linux-2.6.12-rc2 |
654 655 656 657 |
int hash = DFR_HASH(item); INIT_LIST_HEAD(&pending); spin_lock(&cache_defer_lock); |
cca5172a7 [NET] SUNRPC: Fix... |
658 |
|
111744927 sunrpc/cache: cha... |
659 660 661 662 |
hlist_for_each_entry_safe(dreq, lp, tmp, &cache_defer_hash[hash], hash) if (dreq->item == item) { __unhash_deferred_req(dreq); list_add(&dreq->recent, &pending); |
1da177e4c Linux-2.6.12-rc2 |
663 |
} |
111744927 sunrpc/cache: cha... |
664 |
|
1da177e4c Linux-2.6.12-rc2 |
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
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... |
682 |
|
1da177e4c Linux-2.6.12-rc2 |
683 684 |
list_for_each_entry_safe(dreq, tmp, &cache_defer_list, recent) { if (dreq->owner == owner) { |
6610f720e svcrpc: minor cac... |
685 |
__unhash_deferred_req(dreq); |
e95dffa43 sunrpc/cache: fix... |
686 |
list_add(&dreq->recent, &pending); |
1da177e4c Linux-2.6.12-rc2 |
687 688 689 690 691 692 693 694 695 696 697 698 699 700 |
} } 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.... |
701 702 703 704 |
* 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 |
705 |
* |
cca5172a7 [NET] SUNRPC: Fix... |
706 |
* Implemented by linked list of requests. Each open file has |
a490c681c knfsd: fix cache.... |
707 |
* a ->private that also exists in this list. New requests are added |
1da177e4c Linux-2.6.12-rc2 |
708 709 710 711 712 713 714 |
* 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: ... |
715 |
static DEFINE_MUTEX(queue_io_mutex); |
1da177e4c Linux-2.6.12-rc2 |
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 |
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 */ }; |
173912a6a SUNRPC: Move proc... |
732 733 |
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 |
734 735 736 |
{ struct cache_reader *rp = filp->private_data; struct cache_request *rq; |
da77005f0 SUNRPC: Remove th... |
737 |
struct inode *inode = filp->f_path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
738 739 740 741 |
int err; if (count == 0) return 0; |
da77005f0 SUNRPC: Remove th... |
742 |
mutex_lock(&inode->i_mutex); /* protect against multiple concurrent |
1da177e4c Linux-2.6.12-rc2 |
743 744 745 746 747 748 749 750 751 752 753 754 |
* 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... |
755 |
mutex_unlock(&inode->i_mutex); |
09a626600 [NET]: Change som... |
756 |
BUG_ON(rp->offset); |
1da177e4c Linux-2.6.12-rc2 |
757 758 759 |
return 0; } rq = container_of(rp->q.list.next, struct cache_request, q.list); |
09a626600 [NET]: Change som... |
760 |
BUG_ON(rq->q.reader); |
1da177e4c Linux-2.6.12-rc2 |
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
if (rp->offset == 0) rq->readers++; spin_unlock(&queue_lock); 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... |
794 |
cache_put(rq->item, cd); |
1da177e4c Linux-2.6.12-rc2 |
795 796 797 798 799 800 801 |
kfree(rq->buf); kfree(rq); } else spin_unlock(&queue_lock); } if (err == -EAGAIN) goto again; |
da77005f0 SUNRPC: Remove th... |
802 |
mutex_unlock(&inode->i_mutex); |
1da177e4c Linux-2.6.12-rc2 |
803 804 |
return err ? err : count; } |
da77005f0 SUNRPC: Remove th... |
805 806 807 808 |
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 |
809 |
|
da77005f0 SUNRPC: Remove th... |
810 811 812 813 814 815 816 817 818 819 820 |
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 |
821 |
{ |
da77005f0 SUNRPC: Remove th... |
822 823 |
static char write_buf[8192]; /* protected by queue_io_mutex */ ssize_t ret = -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
824 |
|
1da177e4c Linux-2.6.12-rc2 |
825 |
if (count >= sizeof(write_buf)) |
da77005f0 SUNRPC: Remove th... |
826 |
goto out; |
4a3e2f711 [NET] sem2mutex: ... |
827 |
mutex_lock(&queue_io_mutex); |
da77005f0 SUNRPC: Remove th... |
828 829 830 831 832 |
ret = cache_do_downcall(write_buf, buf, count, cd); mutex_unlock(&queue_io_mutex); out: return ret; } |
1da177e4c Linux-2.6.12-rc2 |
833 |
|
da77005f0 SUNRPC: Remove th... |
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 |
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 |
858 |
|
173912a6a SUNRPC: Move proc... |
859 860 861 |
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... |
862 863 864 |
{ struct address_space *mapping = filp->f_mapping; struct inode *inode = filp->f_path.dentry->d_inode; |
da77005f0 SUNRPC: Remove th... |
865 866 867 868 869 870 871 872 873 874 |
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 |
875 876 877 |
} static DECLARE_WAIT_QUEUE_HEAD(queue_wait); |
173912a6a SUNRPC: Move proc... |
878 879 |
static unsigned int cache_poll(struct file *filp, poll_table *wait, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
880 881 882 883 |
{ unsigned int mask; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; |
1da177e4c Linux-2.6.12-rc2 |
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 |
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... |
904 905 906 |
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 |
907 908 909 910 |
{ int len = 0; struct cache_reader *rp = filp->private_data; struct cache_queue *cq; |
1da177e4c Linux-2.6.12-rc2 |
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 |
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... |
932 933 |
static int cache_open(struct inode *inode, struct file *filp, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
934 935 |
{ struct cache_reader *rp = NULL; |
f7e86ab92 SUNRPC: cache mus... |
936 937 |
if (!cd || !try_module_get(cd->owner)) return -EACCES; |
1da177e4c Linux-2.6.12-rc2 |
938 939 |
nonseekable_open(inode, filp); if (filp->f_mode & FMODE_READ) { |
1da177e4c Linux-2.6.12-rc2 |
940 941 942 943 944 945 946 947 948 949 950 951 952 |
rp = kmalloc(sizeof(*rp), GFP_KERNEL); if (!rp) return -ENOMEM; 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... |
953 954 |
static int cache_release(struct inode *inode, struct file *filp, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
955 956 |
{ struct cache_reader *rp = filp->private_data; |
1da177e4c Linux-2.6.12-rc2 |
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 |
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... |
976 |
cd->last_close = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
977 978 |
atomic_dec(&cd->readers); } |
f7e86ab92 SUNRPC: cache mus... |
979 |
module_put(cd->owner); |
1da177e4c Linux-2.6.12-rc2 |
980 981 |
return 0; } |
f866a8194 sunrpc/cache: ren... |
982 |
static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) |
1da177e4c Linux-2.6.12-rc2 |
983 984 985 986 987 988 989 990 991 |
{ 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... |
992 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
993 994 |
list_del(&cr->q.list); spin_unlock(&queue_lock); |
baab935ff [PATCH] knfsd: Co... |
995 |
cache_put(cr->item, detail); |
1da177e4c Linux-2.6.12-rc2 |
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 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 |
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... |
1047 |
EXPORT_SYMBOL_GPL(qword_add); |
1da177e4c Linux-2.6.12-rc2 |
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
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... |
1076 |
EXPORT_SYMBOL_GPL(qword_addhex); |
1da177e4c Linux-2.6.12-rc2 |
1077 1078 1079 1080 1081 1082 |
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... |
1083 |
detail->warn_no_listener(detail, detail->last_close != 0); |
1da177e4c Linux-2.6.12-rc2 |
1084 1085 |
} } |
064975245 nfsd4: fix hang o... |
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 |
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 |
1102 |
/* |
bc74b4f5e SUNRPC: Allow the... |
1103 1104 1105 |
* register an upcall request to user-space and queue it up for read() by the * upcall daemon. * |
1da177e4c Linux-2.6.12-rc2 |
1106 1107 |
* Each request is at most one page long. */ |
bc74b4f5e SUNRPC: Allow the... |
1108 1109 1110 1111 1112 |
int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h, void (*cache_request)(struct cache_detail *, struct cache_head *, char **, int *)) |
1da177e4c Linux-2.6.12-rc2 |
1113 1114 1115 1116 1117 1118 |
{ char *buf; struct cache_request *crq; char *bp; int len; |
064975245 nfsd4: fix hang o... |
1119 1120 1121 |
if (!cache_listeners_exist(detail)) { warn_no_listener(detail); return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 |
} buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -EAGAIN; crq = kmalloc(sizeof (*crq), GFP_KERNEL); if (!crq) { kfree(buf); return -EAGAIN; } bp = buf; len = PAGE_SIZE; |
bc74b4f5e SUNRPC: Allow the... |
1135 |
cache_request(detail, h, &bp, &len); |
1da177e4c Linux-2.6.12-rc2 |
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 |
if (len < 0) { kfree(buf); kfree(crq); return -EAGAIN; } crq->q.reader = 0; crq->item = cache_get(h); crq->buf = buf; crq->len = PAGE_SIZE - len; 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... |
1153 |
EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall); |
1da177e4c Linux-2.6.12-rc2 |
1154 1155 1156 1157 1158 1159 1160 1161 |
/* * 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... |
1162 |
* Message is |
1da177e4c Linux-2.6.12-rc2 |
1163 1164 |
* reply cachename expiry key ... content.... * |
cca5172a7 [NET] SUNRPC: Fix... |
1165 |
* key and content are both parsed by cache |
1da177e4c Linux-2.6.12-rc2 |
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 |
*/ #define isodigit(c) (isdigit(c) && c <= '7') 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... |
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 |
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 |
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
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... |
1225 |
EXPORT_SYMBOL_GPL(qword_get); |
1da177e4c Linux-2.6.12-rc2 |
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
/* * 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... |
1240 |
__acquires(cd->hash_lock) |
1da177e4c Linux-2.6.12-rc2 |
1241 1242 1243 1244 1245 |
{ loff_t n = *pos; unsigned hash, entry; struct cache_head *ch; struct cache_detail *cd = ((struct handle*)m->private)->cd; |
cca5172a7 [NET] SUNRPC: Fix... |
1246 |
|
1da177e4c Linux-2.6.12-rc2 |
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 |
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... |
1261 |
} while(hash < cd->hash_size && |
1da177e4c Linux-2.6.12-rc2 |
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 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 |
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... |
1297 |
__releases(cd->hash_lock) |
1da177e4c Linux-2.6.12-rc2 |
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 |
{ 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... |
1312 1313 |
seq_printf(m, "# expiry=%ld refcnt=%d flags=%lx ", |
c5b29f885 sunrpc: use secon... |
1314 1315 |
convert_to_wallclock(cp->expiry_time), atomic_read(&cp->ref.refcount), cp->flags); |
1da177e4c Linux-2.6.12-rc2 |
1316 1317 1318 1319 1320 1321 1322 1323 1324 |
cache_get(cp); if (cache_check(cd, cp, NULL)) /* cache_check does a cache_put on failure */ seq_printf(m, "# "); else cache_put(cp, cd); return cd->cache_show(m, cd, cp); } |
56b3d975b [NET]: Make all i... |
1325 |
static const struct seq_operations cache_content_op = { |
1da177e4c Linux-2.6.12-rc2 |
1326 1327 1328 1329 1330 |
.start = c_start, .next = c_next, .stop = c_stop, .show = c_show, }; |
173912a6a SUNRPC: Move proc... |
1331 1332 |
static int content_open(struct inode *inode, struct file *file, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
1333 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1334 |
struct handle *han; |
1da177e4c Linux-2.6.12-rc2 |
1335 |
|
f7e86ab92 SUNRPC: cache mus... |
1336 1337 |
if (!cd || !try_module_get(cd->owner)) return -EACCES; |
ec9310351 [SUNRPC]: Make th... |
1338 |
han = __seq_open_private(file, &cache_content_op, sizeof(*han)); |
a5990ea12 sunrpc/cache: fix... |
1339 1340 |
if (han == NULL) { module_put(cd->owner); |
1da177e4c Linux-2.6.12-rc2 |
1341 |
return -ENOMEM; |
a5990ea12 sunrpc/cache: fix... |
1342 |
} |
1da177e4c Linux-2.6.12-rc2 |
1343 1344 |
han->cd = cd; |
ec9310351 [SUNRPC]: Make th... |
1345 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
1346 |
} |
1da177e4c Linux-2.6.12-rc2 |
1347 |
|
f7e86ab92 SUNRPC: cache mus... |
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 |
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 |
1370 1371 |
static ssize_t read_flush(struct file *file, char __user *buf, |
173912a6a SUNRPC: Move proc... |
1372 1373 |
size_t count, loff_t *ppos, struct cache_detail *cd) |
1da177e4c Linux-2.6.12-rc2 |
1374 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1375 1376 |
char tbuf[20]; unsigned long p = *ppos; |
01b2969a8 SUNRPC: Prevent l... |
1377 |
size_t len; |
1da177e4c Linux-2.6.12-rc2 |
1378 |
|
c5b29f885 sunrpc: use secon... |
1379 1380 |
sprintf(tbuf, "%lu ", convert_to_wallclock(cd->flush_time)); |
1da177e4c Linux-2.6.12-rc2 |
1381 1382 1383 1384 |
len = strlen(tbuf); if (p >= len) return 0; len -= p; |
01b2969a8 SUNRPC: Prevent l... |
1385 1386 |
if (len > count) len = count; |
1da177e4c Linux-2.6.12-rc2 |
1387 |
if (copy_to_user(buf, (void*)(tbuf+p), len)) |
01b2969a8 SUNRPC: Prevent l... |
1388 1389 |
return -EFAULT; *ppos += len; |
1da177e4c Linux-2.6.12-rc2 |
1390 1391 |
return len; } |
173912a6a SUNRPC: Move proc... |
1392 1393 1394 |
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 |
1395 |
{ |
1da177e4c Linux-2.6.12-rc2 |
1396 |
char tbuf[20]; |
c5b29f885 sunrpc: use secon... |
1397 |
char *bp, *ep; |
1da177e4c Linux-2.6.12-rc2 |
1398 1399 1400 1401 1402 |
if (*ppos || count > sizeof(tbuf)-1) return -EINVAL; if (copy_from_user(tbuf, buf, count)) return -EFAULT; tbuf[count] = 0; |
c5b29f885 sunrpc: use secon... |
1403 |
simple_strtoul(tbuf, &ep, 0); |
1da177e4c Linux-2.6.12-rc2 |
1404 1405 1406 |
if (*ep && *ep != ' ') return -EINVAL; |
c5b29f885 sunrpc: use secon... |
1407 1408 1409 |
bp = tbuf; cd->flush_time = get_expiry(&bp); cd->nextcheck = seconds_since_boot(); |
1da177e4c Linux-2.6.12-rc2 |
1410 1411 1412 1413 1414 |
cache_flush(); *ppos += count; return count; } |
173912a6a SUNRPC: Move proc... |
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 |
static ssize_t cache_read_procfs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; 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) { struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; return cache_write(filp, buf, count, ppos, cd); } static unsigned int cache_poll_procfs(struct file *filp, poll_table *wait) { struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; return cache_poll(filp, wait, cd); } |
d79b6f4de procfs: Push down... |
1437 1438 |
static long cache_ioctl_procfs(struct file *filp, unsigned int cmd, unsigned long arg) |
173912a6a SUNRPC: Move proc... |
1439 |
{ |
d79b6f4de procfs: Push down... |
1440 |
struct inode *inode = filp->f_path.dentry->d_inode; |
173912a6a SUNRPC: Move proc... |
1441 |
struct cache_detail *cd = PDE(inode)->data; |
a6f8dbc65 sunrpc: remove th... |
1442 |
return cache_ioctl(inode, filp, cmd, arg, cd); |
173912a6a SUNRPC: Move proc... |
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 |
} static int cache_open_procfs(struct inode *inode, struct file *filp) { struct cache_detail *cd = PDE(inode)->data; return cache_open(inode, filp, cd); } static int cache_release_procfs(struct inode *inode, struct file *filp) { struct cache_detail *cd = PDE(inode)->data; 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... |
1465 |
.unlocked_ioctl = cache_ioctl_procfs, /* for FIONREAD */ |
173912a6a SUNRPC: Move proc... |
1466 1467 |
.open = cache_open_procfs, .release = cache_release_procfs, |
1da177e4c Linux-2.6.12-rc2 |
1468 |
}; |
173912a6a SUNRPC: Move proc... |
1469 1470 1471 1472 1473 1474 1475 |
static int content_open_procfs(struct inode *inode, struct file *filp) { struct cache_detail *cd = PDE(inode)->data; return content_open(inode, filp, cd); } |
f7e86ab92 SUNRPC: cache mus... |
1476 1477 1478 1479 1480 1481 |
static int content_release_procfs(struct inode *inode, struct file *filp) { struct cache_detail *cd = PDE(inode)->data; return content_release(inode, filp, cd); } |
173912a6a SUNRPC: Move proc... |
1482 1483 1484 1485 |
static const struct file_operations content_file_operations_procfs = { .open = content_open_procfs, .read = seq_read, .llseek = seq_lseek, |
f7e86ab92 SUNRPC: cache mus... |
1486 |
.release = content_release_procfs, |
173912a6a SUNRPC: Move proc... |
1487 |
}; |
f7e86ab92 SUNRPC: cache mus... |
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 |
static int open_flush_procfs(struct inode *inode, struct file *filp) { struct cache_detail *cd = PDE(inode)->data; return open_flush(inode, filp, cd); } static int release_flush_procfs(struct inode *inode, struct file *filp) { struct cache_detail *cd = PDE(inode)->data; return release_flush(inode, filp, cd); } |
173912a6a SUNRPC: Move proc... |
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 |
static ssize_t read_flush_procfs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; 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) { struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; return write_flush(filp, buf, count, ppos, cd); } static const struct file_operations cache_flush_operations_procfs = { |
f7e86ab92 SUNRPC: cache mus... |
1519 |
.open = open_flush_procfs, |
173912a6a SUNRPC: Move proc... |
1520 1521 |
.read = read_flush_procfs, .write = write_flush_procfs, |
f7e86ab92 SUNRPC: cache mus... |
1522 |
.release = release_flush_procfs, |
6038f373a llseek: automatic... |
1523 |
.llseek = no_llseek, |
1da177e4c Linux-2.6.12-rc2 |
1524 |
}; |
173912a6a SUNRPC: Move proc... |
1525 |
|
593ce16b9 sunrpc: Add routi... |
1526 |
static void remove_cache_proc_entries(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1527 |
{ |
4f42d0d53 sunrpc: Make the ... |
1528 |
struct sunrpc_net *sn; |
173912a6a SUNRPC: Move proc... |
1529 1530 1531 1532 1533 1534 1535 1536 1537 |
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 ... |
1538 1539 |
sn = net_generic(net, sunrpc_net_id); remove_proc_entry(cd->name, sn->proc_net_rpc); |
173912a6a SUNRPC: Move proc... |
1540 1541 1542 |
} #ifdef CONFIG_PROC_FS |
593ce16b9 sunrpc: Add routi... |
1543 |
static int create_cache_proc_entries(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1544 1545 |
{ struct proc_dir_entry *p; |
4f42d0d53 sunrpc: Make the ... |
1546 |
struct sunrpc_net *sn; |
173912a6a SUNRPC: Move proc... |
1547 |
|
4f42d0d53 sunrpc: Make the ... |
1548 1549 |
sn = net_generic(net, sunrpc_net_id); cd->u.procfs.proc_ent = proc_mkdir(cd->name, sn->proc_net_rpc); |
173912a6a SUNRPC: Move proc... |
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 |
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; if (cd->cache_upcall || cd->cache_parse) { 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) { p = proc_create_data("content", S_IFREG|S_IRUSR|S_IWUSR, 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... |
1580 |
remove_cache_proc_entries(cd, net); |
173912a6a SUNRPC: Move proc... |
1581 1582 1583 |
return -ENOMEM; } #else /* CONFIG_PROC_FS */ |
593ce16b9 sunrpc: Add routi... |
1584 |
static int create_cache_proc_entries(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1585 1586 1587 1588 |
{ return 0; } #endif |
8eab945c5 sunrpc: make the ... |
1589 1590 1591 1592 |
void __init cache_initialize(void) { INIT_DELAYED_WORK_DEFERRABLE(&cache_cleaner, do_cache_clean); } |
593ce16b9 sunrpc: Add routi... |
1593 |
int cache_register_net(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1594 1595 1596 1597 |
{ int ret; sunrpc_init_cache_detail(cd); |
593ce16b9 sunrpc: Add routi... |
1598 |
ret = create_cache_proc_entries(cd, net); |
173912a6a SUNRPC: Move proc... |
1599 1600 1601 1602 |
if (ret) sunrpc_destroy_cache_detail(cd); return ret; } |
f5c8593b9 NFSd: use network... |
1603 |
EXPORT_SYMBOL_GPL(cache_register_net); |
593ce16b9 sunrpc: Add routi... |
1604 1605 1606 1607 1608 |
int cache_register(struct cache_detail *cd) { return cache_register_net(cd, &init_net); } |
173912a6a SUNRPC: Move proc... |
1609 |
EXPORT_SYMBOL_GPL(cache_register); |
593ce16b9 sunrpc: Add routi... |
1610 |
void cache_unregister_net(struct cache_detail *cd, struct net *net) |
173912a6a SUNRPC: Move proc... |
1611 |
{ |
593ce16b9 sunrpc: Add routi... |
1612 |
remove_cache_proc_entries(cd, net); |
173912a6a SUNRPC: Move proc... |
1613 1614 |
sunrpc_destroy_cache_detail(cd); } |
f5c8593b9 NFSd: use network... |
1615 |
EXPORT_SYMBOL_GPL(cache_unregister_net); |
593ce16b9 sunrpc: Add routi... |
1616 1617 1618 1619 1620 |
void cache_unregister(struct cache_detail *cd) { cache_unregister_net(cd, &init_net); } |
173912a6a SUNRPC: Move proc... |
1621 |
EXPORT_SYMBOL_GPL(cache_unregister); |
8854e82d9 SUNRPC: Add an rp... |
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 |
static ssize_t cache_read_pipefs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; 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) { struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; return cache_write(filp, buf, count, ppos, cd); } static unsigned int cache_poll_pipefs(struct file *filp, poll_table *wait) { struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; return cache_poll(filp, wait, cd); } |
9918ff26b sunrpc: Pushdown ... |
1645 |
static long cache_ioctl_pipefs(struct file *filp, |
8854e82d9 SUNRPC: Add an rp... |
1646 1647 |
unsigned int cmd, unsigned long arg) { |
9918ff26b sunrpc: Pushdown ... |
1648 |
struct inode *inode = filp->f_dentry->d_inode; |
8854e82d9 SUNRPC: Add an rp... |
1649 |
struct cache_detail *cd = RPC_I(inode)->private; |
a6f8dbc65 sunrpc: remove th... |
1650 |
return cache_ioctl(inode, filp, cmd, arg, cd); |
8854e82d9 SUNRPC: Add an rp... |
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 |
} 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 ... |
1673 |
.unlocked_ioctl = cache_ioctl_pipefs, /* for FIONREAD */ |
8854e82d9 SUNRPC: Add an rp... |
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 |
.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... |
1684 1685 1686 1687 1688 1689 |
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... |
1690 1691 1692 1693 |
const struct file_operations content_file_operations_pipefs = { .open = content_open_pipefs, .read = seq_read, .llseek = seq_lseek, |
f7e86ab92 SUNRPC: cache mus... |
1694 |
.release = content_release_pipefs, |
8854e82d9 SUNRPC: Add an rp... |
1695 |
}; |
f7e86ab92 SUNRPC: cache mus... |
1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 |
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... |
1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 |
static ssize_t read_flush_pipefs(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; 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) { struct cache_detail *cd = RPC_I(filp->f_path.dentry->d_inode)->private; return write_flush(filp, buf, count, ppos, cd); } const struct file_operations cache_flush_operations_pipefs = { |
f7e86ab92 SUNRPC: cache mus... |
1727 |
.open = open_flush_pipefs, |
8854e82d9 SUNRPC: Add an rp... |
1728 1729 |
.read = read_flush_pipefs, .write = write_flush_pipefs, |
f7e86ab92 SUNRPC: cache mus... |
1730 |
.release = release_flush_pipefs, |
6038f373a llseek: automatic... |
1731 |
.llseek = no_llseek, |
8854e82d9 SUNRPC: Add an rp... |
1732 1733 1734 |
}; int sunrpc_cache_register_pipefs(struct dentry *parent, |
64f1426f3 sunrpc: propagate... |
1735 |
const char *name, umode_t umode, |
8854e82d9 SUNRPC: Add an rp... |
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 |
struct cache_detail *cd) { struct qstr q; struct dentry *dir; int ret = 0; sunrpc_init_cache_detail(cd); 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; else { sunrpc_destroy_cache_detail(cd); ret = PTR_ERR(dir); } 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; sunrpc_destroy_cache_detail(cd); } EXPORT_SYMBOL_GPL(sunrpc_cache_unregister_pipefs); |