diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-12-20 18:49:14 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-12-20 18:49:14 -0500 |
commit | 21e89c0c48bb799beb09181740796fc80c9676e2 (patch) | |
tree | bd5aef34a980f189ad41c75e881d225bc854bf44 /fs | |
parent | b911a6bdeef5848c468597d040e3407e0aee04ce (diff) | |
parent | 91c7fbbf63f33c77d8d28de624834a21888842bb (diff) |
Merge branch 'fscache' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into for-linus
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cachefiles/interface.c | 57 | ||||
-rw-r--r-- | fs/cachefiles/internal.h | 2 | ||||
-rw-r--r-- | fs/cachefiles/key.c | 2 | ||||
-rw-r--r-- | fs/cachefiles/namei.c | 3 | ||||
-rw-r--r-- | fs/cachefiles/rdwr.c | 114 | ||||
-rw-r--r-- | fs/cachefiles/xattr.c | 2 | ||||
-rw-r--r-- | fs/fscache/cache.c | 8 | ||||
-rw-r--r-- | fs/fscache/cookie.c | 78 | ||||
-rw-r--r-- | fs/fscache/internal.h | 15 | ||||
-rw-r--r-- | fs/fscache/object-list.c | 2 | ||||
-rw-r--r-- | fs/fscache/object.c | 101 | ||||
-rw-r--r-- | fs/fscache/operation.c | 140 | ||||
-rw-r--r-- | fs/fscache/page.c | 195 | ||||
-rw-r--r-- | fs/fscache/stats.c | 17 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 1 | ||||
-rw-r--r-- | fs/nfs/fscache.h | 20 | ||||
-rw-r--r-- | fs/nfs/inode.c | 20 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 3 | ||||
-rw-r--r-- | fs/nfs/write.c | 3 | ||||
-rw-r--r-- | fs/open.c | 50 |
21 files changed, 664 insertions, 171 deletions
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 67bef6d01484..746ce532e130 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -41,12 +41,12 @@ static struct fscache_object *cachefiles_alloc_object( | |||
41 | 41 | ||
42 | _enter("{%s},%p,", cache->cache.identifier, cookie); | 42 | _enter("{%s},%p,", cache->cache.identifier, cookie); |
43 | 43 | ||
44 | lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL); | 44 | lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp); |
45 | if (!lookup_data) | 45 | if (!lookup_data) |
46 | goto nomem_lookup_data; | 46 | goto nomem_lookup_data; |
47 | 47 | ||
48 | /* create a new object record and a temporary leaf image */ | 48 | /* create a new object record and a temporary leaf image */ |
49 | object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL); | 49 | object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp); |
50 | if (!object) | 50 | if (!object) |
51 | goto nomem_object; | 51 | goto nomem_object; |
52 | 52 | ||
@@ -63,7 +63,7 @@ static struct fscache_object *cachefiles_alloc_object( | |||
63 | * - stick the length on the front and leave space on the back for the | 63 | * - stick the length on the front and leave space on the back for the |
64 | * encoder | 64 | * encoder |
65 | */ | 65 | */ |
66 | buffer = kmalloc((2 + 512) + 3, GFP_KERNEL); | 66 | buffer = kmalloc((2 + 512) + 3, cachefiles_gfp); |
67 | if (!buffer) | 67 | if (!buffer) |
68 | goto nomem_buffer; | 68 | goto nomem_buffer; |
69 | 69 | ||
@@ -219,7 +219,7 @@ static void cachefiles_update_object(struct fscache_object *_object) | |||
219 | return; | 219 | return; |
220 | } | 220 | } |
221 | 221 | ||
222 | auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL); | 222 | auxdata = kmalloc(2 + 512 + 3, cachefiles_gfp); |
223 | if (!auxdata) { | 223 | if (!auxdata) { |
224 | _leave(" [nomem]"); | 224 | _leave(" [nomem]"); |
225 | return; | 225 | return; |
@@ -441,6 +441,54 @@ truncate_failed: | |||
441 | } | 441 | } |
442 | 442 | ||
443 | /* | 443 | /* |
444 | * Invalidate an object | ||
445 | */ | ||
446 | static void cachefiles_invalidate_object(struct fscache_operation *op) | ||
447 | { | ||
448 | struct cachefiles_object *object; | ||
449 | struct cachefiles_cache *cache; | ||
450 | const struct cred *saved_cred; | ||
451 | struct path path; | ||
452 | uint64_t ni_size; | ||
453 | int ret; | ||
454 | |||
455 | object = container_of(op->object, struct cachefiles_object, fscache); | ||
456 | cache = container_of(object->fscache.cache, | ||
457 | struct cachefiles_cache, cache); | ||
458 | |||
459 | op->object->cookie->def->get_attr(op->object->cookie->netfs_data, | ||
460 | &ni_size); | ||
461 | |||
462 | _enter("{OBJ%x},[%llu]", | ||
463 | op->object->debug_id, (unsigned long long)ni_size); | ||
464 | |||
465 | if (object->backer) { | ||
466 | ASSERT(S_ISREG(object->backer->d_inode->i_mode)); | ||
467 | |||
468 | fscache_set_store_limit(&object->fscache, ni_size); | ||
469 | |||
470 | path.dentry = object->backer; | ||
471 | path.mnt = cache->mnt; | ||
472 | |||
473 | cachefiles_begin_secure(cache, &saved_cred); | ||
474 | ret = vfs_truncate(&path, 0); | ||
475 | if (ret == 0) | ||
476 | ret = vfs_truncate(&path, ni_size); | ||
477 | cachefiles_end_secure(cache, saved_cred); | ||
478 | |||
479 | if (ret != 0) { | ||
480 | fscache_set_store_limit(&object->fscache, 0); | ||
481 | if (ret == -EIO) | ||
482 | cachefiles_io_error_obj(object, | ||
483 | "Invalidate failed"); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | fscache_op_complete(op, true); | ||
488 | _leave(""); | ||
489 | } | ||
490 | |||
491 | /* | ||
444 | * dissociate a cache from all the pages it was backing | 492 | * dissociate a cache from all the pages it was backing |
445 | */ | 493 | */ |
446 | static void cachefiles_dissociate_pages(struct fscache_cache *cache) | 494 | static void cachefiles_dissociate_pages(struct fscache_cache *cache) |
@@ -455,6 +503,7 @@ const struct fscache_cache_ops cachefiles_cache_ops = { | |||
455 | .lookup_complete = cachefiles_lookup_complete, | 503 | .lookup_complete = cachefiles_lookup_complete, |
456 | .grab_object = cachefiles_grab_object, | 504 | .grab_object = cachefiles_grab_object, |
457 | .update_object = cachefiles_update_object, | 505 | .update_object = cachefiles_update_object, |
506 | .invalidate_object = cachefiles_invalidate_object, | ||
458 | .drop_object = cachefiles_drop_object, | 507 | .drop_object = cachefiles_drop_object, |
459 | .put_object = cachefiles_put_object, | 508 | .put_object = cachefiles_put_object, |
460 | .sync_cache = cachefiles_sync_cache, | 509 | .sync_cache = cachefiles_sync_cache, |
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index bd6bc1bde2d7..49382519907a 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h | |||
@@ -23,6 +23,8 @@ extern unsigned cachefiles_debug; | |||
23 | #define CACHEFILES_DEBUG_KLEAVE 2 | 23 | #define CACHEFILES_DEBUG_KLEAVE 2 |
24 | #define CACHEFILES_DEBUG_KDEBUG 4 | 24 | #define CACHEFILES_DEBUG_KDEBUG 4 |
25 | 25 | ||
26 | #define cachefiles_gfp (__GFP_WAIT | __GFP_NORETRY | __GFP_NOMEMALLOC) | ||
27 | |||
26 | /* | 28 | /* |
27 | * node records | 29 | * node records |
28 | */ | 30 | */ |
diff --git a/fs/cachefiles/key.c b/fs/cachefiles/key.c index 81b8b2b3a674..33b58c60f2d1 100644 --- a/fs/cachefiles/key.c +++ b/fs/cachefiles/key.c | |||
@@ -78,7 +78,7 @@ char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type) | |||
78 | 78 | ||
79 | _debug("max: %d", max); | 79 | _debug("max: %d", max); |
80 | 80 | ||
81 | key = kmalloc(max, GFP_KERNEL); | 81 | key = kmalloc(max, cachefiles_gfp); |
82 | if (!key) | 82 | if (!key) |
83 | return NULL; | 83 | return NULL; |
84 | 84 | ||
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index b0b5f7cdfffa..8c01c5fcdf75 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -40,8 +40,7 @@ void __cachefiles_printk_object(struct cachefiles_object *object, | |||
40 | printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", | 40 | printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", |
41 | prefix, fscache_object_states[object->fscache.state], | 41 | prefix, fscache_object_states[object->fscache.state], |
42 | object->fscache.flags, work_busy(&object->fscache.work), | 42 | object->fscache.flags, work_busy(&object->fscache.work), |
43 | object->fscache.events, | 43 | object->fscache.events, object->fscache.event_mask); |
44 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); | ||
45 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", | 44 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", |
46 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, | 45 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, |
47 | object->fscache.n_exclusive); | 46 | object->fscache.n_exclusive); |
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index c994691d9445..480992259707 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
@@ -77,25 +77,25 @@ static int cachefiles_read_reissue(struct cachefiles_object *object, | |||
77 | struct page *backpage = monitor->back_page, *backpage2; | 77 | struct page *backpage = monitor->back_page, *backpage2; |
78 | int ret; | 78 | int ret; |
79 | 79 | ||
80 | kenter("{ino=%lx},{%lx,%lx}", | 80 | _enter("{ino=%lx},{%lx,%lx}", |
81 | object->backer->d_inode->i_ino, | 81 | object->backer->d_inode->i_ino, |
82 | backpage->index, backpage->flags); | 82 | backpage->index, backpage->flags); |
83 | 83 | ||
84 | /* skip if the page was truncated away completely */ | 84 | /* skip if the page was truncated away completely */ |
85 | if (backpage->mapping != bmapping) { | 85 | if (backpage->mapping != bmapping) { |
86 | kleave(" = -ENODATA [mapping]"); | 86 | _leave(" = -ENODATA [mapping]"); |
87 | return -ENODATA; | 87 | return -ENODATA; |
88 | } | 88 | } |
89 | 89 | ||
90 | backpage2 = find_get_page(bmapping, backpage->index); | 90 | backpage2 = find_get_page(bmapping, backpage->index); |
91 | if (!backpage2) { | 91 | if (!backpage2) { |
92 | kleave(" = -ENODATA [gone]"); | 92 | _leave(" = -ENODATA [gone]"); |
93 | return -ENODATA; | 93 | return -ENODATA; |
94 | } | 94 | } |
95 | 95 | ||
96 | if (backpage != backpage2) { | 96 | if (backpage != backpage2) { |
97 | put_page(backpage2); | 97 | put_page(backpage2); |
98 | kleave(" = -ENODATA [different]"); | 98 | _leave(" = -ENODATA [different]"); |
99 | return -ENODATA; | 99 | return -ENODATA; |
100 | } | 100 | } |
101 | 101 | ||
@@ -114,7 +114,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object, | |||
114 | if (PageUptodate(backpage)) | 114 | if (PageUptodate(backpage)) |
115 | goto unlock_discard; | 115 | goto unlock_discard; |
116 | 116 | ||
117 | kdebug("reissue read"); | 117 | _debug("reissue read"); |
118 | ret = bmapping->a_ops->readpage(NULL, backpage); | 118 | ret = bmapping->a_ops->readpage(NULL, backpage); |
119 | if (ret < 0) | 119 | if (ret < 0) |
120 | goto unlock_discard; | 120 | goto unlock_discard; |
@@ -129,7 +129,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object, | |||
129 | } | 129 | } |
130 | 130 | ||
131 | /* it'll reappear on the todo list */ | 131 | /* it'll reappear on the todo list */ |
132 | kleave(" = -EINPROGRESS"); | 132 | _leave(" = -EINPROGRESS"); |
133 | return -EINPROGRESS; | 133 | return -EINPROGRESS; |
134 | 134 | ||
135 | unlock_discard: | 135 | unlock_discard: |
@@ -137,7 +137,7 @@ unlock_discard: | |||
137 | spin_lock_irq(&object->work_lock); | 137 | spin_lock_irq(&object->work_lock); |
138 | list_del(&monitor->op_link); | 138 | list_del(&monitor->op_link); |
139 | spin_unlock_irq(&object->work_lock); | 139 | spin_unlock_irq(&object->work_lock); |
140 | kleave(" = %d", ret); | 140 | _leave(" = %d", ret); |
141 | return ret; | 141 | return ret; |
142 | } | 142 | } |
143 | 143 | ||
@@ -174,11 +174,13 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
174 | _debug("- copy {%lu}", monitor->back_page->index); | 174 | _debug("- copy {%lu}", monitor->back_page->index); |
175 | 175 | ||
176 | recheck: | 176 | recheck: |
177 | if (PageUptodate(monitor->back_page)) { | 177 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, |
178 | &object->fscache.cookie->flags)) { | ||
179 | error = -ESTALE; | ||
180 | } else if (PageUptodate(monitor->back_page)) { | ||
178 | copy_highpage(monitor->netfs_page, monitor->back_page); | 181 | copy_highpage(monitor->netfs_page, monitor->back_page); |
179 | 182 | fscache_mark_page_cached(monitor->op, | |
180 | pagevec_add(&pagevec, monitor->netfs_page); | 183 | monitor->netfs_page); |
181 | fscache_mark_pages_cached(monitor->op, &pagevec); | ||
182 | error = 0; | 184 | error = 0; |
183 | } else if (!PageError(monitor->back_page)) { | 185 | } else if (!PageError(monitor->back_page)) { |
184 | /* the page has probably been truncated */ | 186 | /* the page has probably been truncated */ |
@@ -198,6 +200,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
198 | 200 | ||
199 | fscache_end_io(op, monitor->netfs_page, error); | 201 | fscache_end_io(op, monitor->netfs_page, error); |
200 | page_cache_release(monitor->netfs_page); | 202 | page_cache_release(monitor->netfs_page); |
203 | fscache_retrieval_complete(op, 1); | ||
201 | fscache_put_retrieval(op); | 204 | fscache_put_retrieval(op); |
202 | kfree(monitor); | 205 | kfree(monitor); |
203 | 206 | ||
@@ -239,7 +242,7 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object, | |||
239 | _debug("read back %p{%lu,%d}", | 242 | _debug("read back %p{%lu,%d}", |
240 | netpage, netpage->index, page_count(netpage)); | 243 | netpage, netpage->index, page_count(netpage)); |
241 | 244 | ||
242 | monitor = kzalloc(sizeof(*monitor), GFP_KERNEL); | 245 | monitor = kzalloc(sizeof(*monitor), cachefiles_gfp); |
243 | if (!monitor) | 246 | if (!monitor) |
244 | goto nomem; | 247 | goto nomem; |
245 | 248 | ||
@@ -258,13 +261,14 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object, | |||
258 | goto backing_page_already_present; | 261 | goto backing_page_already_present; |
259 | 262 | ||
260 | if (!newpage) { | 263 | if (!newpage) { |
261 | newpage = page_cache_alloc_cold(bmapping); | 264 | newpage = __page_cache_alloc(cachefiles_gfp | |
265 | __GFP_COLD); | ||
262 | if (!newpage) | 266 | if (!newpage) |
263 | goto nomem_monitor; | 267 | goto nomem_monitor; |
264 | } | 268 | } |
265 | 269 | ||
266 | ret = add_to_page_cache(newpage, bmapping, | 270 | ret = add_to_page_cache(newpage, bmapping, |
267 | netpage->index, GFP_KERNEL); | 271 | netpage->index, cachefiles_gfp); |
268 | if (ret == 0) | 272 | if (ret == 0) |
269 | goto installed_new_backing_page; | 273 | goto installed_new_backing_page; |
270 | if (ret != -EEXIST) | 274 | if (ret != -EEXIST) |
@@ -335,11 +339,11 @@ backing_page_already_present: | |||
335 | backing_page_already_uptodate: | 339 | backing_page_already_uptodate: |
336 | _debug("- uptodate"); | 340 | _debug("- uptodate"); |
337 | 341 | ||
338 | pagevec_add(pagevec, netpage); | 342 | fscache_mark_page_cached(op, netpage); |
339 | fscache_mark_pages_cached(op, pagevec); | ||
340 | 343 | ||
341 | copy_highpage(netpage, backpage); | 344 | copy_highpage(netpage, backpage); |
342 | fscache_end_io(op, netpage, 0); | 345 | fscache_end_io(op, netpage, 0); |
346 | fscache_retrieval_complete(op, 1); | ||
343 | 347 | ||
344 | success: | 348 | success: |
345 | _debug("success"); | 349 | _debug("success"); |
@@ -357,10 +361,13 @@ out: | |||
357 | 361 | ||
358 | read_error: | 362 | read_error: |
359 | _debug("read error %d", ret); | 363 | _debug("read error %d", ret); |
360 | if (ret == -ENOMEM) | 364 | if (ret == -ENOMEM) { |
365 | fscache_retrieval_complete(op, 1); | ||
361 | goto out; | 366 | goto out; |
367 | } | ||
362 | io_error: | 368 | io_error: |
363 | cachefiles_io_error_obj(object, "Page read error on backing file"); | 369 | cachefiles_io_error_obj(object, "Page read error on backing file"); |
370 | fscache_retrieval_complete(op, 1); | ||
364 | ret = -ENOBUFS; | 371 | ret = -ENOBUFS; |
365 | goto out; | 372 | goto out; |
366 | 373 | ||
@@ -370,6 +377,7 @@ nomem_monitor: | |||
370 | fscache_put_retrieval(monitor->op); | 377 | fscache_put_retrieval(monitor->op); |
371 | kfree(monitor); | 378 | kfree(monitor); |
372 | nomem: | 379 | nomem: |
380 | fscache_retrieval_complete(op, 1); | ||
373 | _leave(" = -ENOMEM"); | 381 | _leave(" = -ENOMEM"); |
374 | return -ENOMEM; | 382 | return -ENOMEM; |
375 | } | 383 | } |
@@ -408,7 +416,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
408 | _enter("{%p},{%lx},,,", object, page->index); | 416 | _enter("{%p},{%lx},,,", object, page->index); |
409 | 417 | ||
410 | if (!object->backer) | 418 | if (!object->backer) |
411 | return -ENOBUFS; | 419 | goto enobufs; |
412 | 420 | ||
413 | inode = object->backer->d_inode; | 421 | inode = object->backer->d_inode; |
414 | ASSERT(S_ISREG(inode->i_mode)); | 422 | ASSERT(S_ISREG(inode->i_mode)); |
@@ -417,7 +425,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
417 | 425 | ||
418 | /* calculate the shift required to use bmap */ | 426 | /* calculate the shift required to use bmap */ |
419 | if (inode->i_sb->s_blocksize > PAGE_SIZE) | 427 | if (inode->i_sb->s_blocksize > PAGE_SIZE) |
420 | return -ENOBUFS; | 428 | goto enobufs; |
421 | 429 | ||
422 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 430 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
423 | 431 | ||
@@ -448,15 +456,20 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
448 | &pagevec); | 456 | &pagevec); |
449 | } else if (cachefiles_has_space(cache, 0, 1) == 0) { | 457 | } else if (cachefiles_has_space(cache, 0, 1) == 0) { |
450 | /* there's space in the cache we can use */ | 458 | /* there's space in the cache we can use */ |
451 | pagevec_add(&pagevec, page); | 459 | fscache_mark_page_cached(op, page); |
452 | fscache_mark_pages_cached(op, &pagevec); | 460 | fscache_retrieval_complete(op, 1); |
453 | ret = -ENODATA; | 461 | ret = -ENODATA; |
454 | } else { | 462 | } else { |
455 | ret = -ENOBUFS; | 463 | goto enobufs; |
456 | } | 464 | } |
457 | 465 | ||
458 | _leave(" = %d", ret); | 466 | _leave(" = %d", ret); |
459 | return ret; | 467 | return ret; |
468 | |||
469 | enobufs: | ||
470 | fscache_retrieval_complete(op, 1); | ||
471 | _leave(" = -ENOBUFS"); | ||
472 | return -ENOBUFS; | ||
460 | } | 473 | } |
461 | 474 | ||
462 | /* | 475 | /* |
@@ -465,8 +478,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
465 | */ | 478 | */ |
466 | static int cachefiles_read_backing_file(struct cachefiles_object *object, | 479 | static int cachefiles_read_backing_file(struct cachefiles_object *object, |
467 | struct fscache_retrieval *op, | 480 | struct fscache_retrieval *op, |
468 | struct list_head *list, | 481 | struct list_head *list) |
469 | struct pagevec *mark_pvec) | ||
470 | { | 482 | { |
471 | struct cachefiles_one_read *monitor = NULL; | 483 | struct cachefiles_one_read *monitor = NULL; |
472 | struct address_space *bmapping = object->backer->d_inode->i_mapping; | 484 | struct address_space *bmapping = object->backer->d_inode->i_mapping; |
@@ -485,7 +497,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
485 | netpage, netpage->index, page_count(netpage)); | 497 | netpage, netpage->index, page_count(netpage)); |
486 | 498 | ||
487 | if (!monitor) { | 499 | if (!monitor) { |
488 | monitor = kzalloc(sizeof(*monitor), GFP_KERNEL); | 500 | monitor = kzalloc(sizeof(*monitor), cachefiles_gfp); |
489 | if (!monitor) | 501 | if (!monitor) |
490 | goto nomem; | 502 | goto nomem; |
491 | 503 | ||
@@ -500,13 +512,14 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
500 | goto backing_page_already_present; | 512 | goto backing_page_already_present; |
501 | 513 | ||
502 | if (!newpage) { | 514 | if (!newpage) { |
503 | newpage = page_cache_alloc_cold(bmapping); | 515 | newpage = __page_cache_alloc(cachefiles_gfp | |
516 | __GFP_COLD); | ||
504 | if (!newpage) | 517 | if (!newpage) |
505 | goto nomem; | 518 | goto nomem; |
506 | } | 519 | } |
507 | 520 | ||
508 | ret = add_to_page_cache(newpage, bmapping, | 521 | ret = add_to_page_cache(newpage, bmapping, |
509 | netpage->index, GFP_KERNEL); | 522 | netpage->index, cachefiles_gfp); |
510 | if (ret == 0) | 523 | if (ret == 0) |
511 | goto installed_new_backing_page; | 524 | goto installed_new_backing_page; |
512 | if (ret != -EEXIST) | 525 | if (ret != -EEXIST) |
@@ -536,10 +549,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
536 | _debug("- monitor add"); | 549 | _debug("- monitor add"); |
537 | 550 | ||
538 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, | 551 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, |
539 | GFP_KERNEL); | 552 | cachefiles_gfp); |
540 | if (ret < 0) { | 553 | if (ret < 0) { |
541 | if (ret == -EEXIST) { | 554 | if (ret == -EEXIST) { |
542 | page_cache_release(netpage); | 555 | page_cache_release(netpage); |
556 | fscache_retrieval_complete(op, 1); | ||
543 | continue; | 557 | continue; |
544 | } | 558 | } |
545 | goto nomem; | 559 | goto nomem; |
@@ -612,10 +626,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
612 | _debug("- uptodate"); | 626 | _debug("- uptodate"); |
613 | 627 | ||
614 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, | 628 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, |
615 | GFP_KERNEL); | 629 | cachefiles_gfp); |
616 | if (ret < 0) { | 630 | if (ret < 0) { |
617 | if (ret == -EEXIST) { | 631 | if (ret == -EEXIST) { |
618 | page_cache_release(netpage); | 632 | page_cache_release(netpage); |
633 | fscache_retrieval_complete(op, 1); | ||
619 | continue; | 634 | continue; |
620 | } | 635 | } |
621 | goto nomem; | 636 | goto nomem; |
@@ -626,16 +641,17 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
626 | page_cache_release(backpage); | 641 | page_cache_release(backpage); |
627 | backpage = NULL; | 642 | backpage = NULL; |
628 | 643 | ||
629 | if (!pagevec_add(mark_pvec, netpage)) | 644 | fscache_mark_page_cached(op, netpage); |
630 | fscache_mark_pages_cached(op, mark_pvec); | ||
631 | 645 | ||
632 | page_cache_get(netpage); | 646 | page_cache_get(netpage); |
633 | if (!pagevec_add(&lru_pvec, netpage)) | 647 | if (!pagevec_add(&lru_pvec, netpage)) |
634 | __pagevec_lru_add_file(&lru_pvec); | 648 | __pagevec_lru_add_file(&lru_pvec); |
635 | 649 | ||
650 | /* the netpage is unlocked and marked up to date here */ | ||
636 | fscache_end_io(op, netpage, 0); | 651 | fscache_end_io(op, netpage, 0); |
637 | page_cache_release(netpage); | 652 | page_cache_release(netpage); |
638 | netpage = NULL; | 653 | netpage = NULL; |
654 | fscache_retrieval_complete(op, 1); | ||
639 | continue; | 655 | continue; |
640 | } | 656 | } |
641 | 657 | ||
@@ -661,6 +677,7 @@ out: | |||
661 | list_for_each_entry_safe(netpage, _n, list, lru) { | 677 | list_for_each_entry_safe(netpage, _n, list, lru) { |
662 | list_del(&netpage->lru); | 678 | list_del(&netpage->lru); |
663 | page_cache_release(netpage); | 679 | page_cache_release(netpage); |
680 | fscache_retrieval_complete(op, 1); | ||
664 | } | 681 | } |
665 | 682 | ||
666 | _leave(" = %d", ret); | 683 | _leave(" = %d", ret); |
@@ -669,15 +686,17 @@ out: | |||
669 | nomem: | 686 | nomem: |
670 | _debug("nomem"); | 687 | _debug("nomem"); |
671 | ret = -ENOMEM; | 688 | ret = -ENOMEM; |
672 | goto out; | 689 | goto record_page_complete; |
673 | 690 | ||
674 | read_error: | 691 | read_error: |
675 | _debug("read error %d", ret); | 692 | _debug("read error %d", ret); |
676 | if (ret == -ENOMEM) | 693 | if (ret == -ENOMEM) |
677 | goto out; | 694 | goto record_page_complete; |
678 | io_error: | 695 | io_error: |
679 | cachefiles_io_error_obj(object, "Page read error on backing file"); | 696 | cachefiles_io_error_obj(object, "Page read error on backing file"); |
680 | ret = -ENOBUFS; | 697 | ret = -ENOBUFS; |
698 | record_page_complete: | ||
699 | fscache_retrieval_complete(op, 1); | ||
681 | goto out; | 700 | goto out; |
682 | } | 701 | } |
683 | 702 | ||
@@ -709,7 +728,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
709 | *nr_pages); | 728 | *nr_pages); |
710 | 729 | ||
711 | if (!object->backer) | 730 | if (!object->backer) |
712 | return -ENOBUFS; | 731 | goto all_enobufs; |
713 | 732 | ||
714 | space = 1; | 733 | space = 1; |
715 | if (cachefiles_has_space(cache, 0, *nr_pages) < 0) | 734 | if (cachefiles_has_space(cache, 0, *nr_pages) < 0) |
@@ -722,7 +741,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
722 | 741 | ||
723 | /* calculate the shift required to use bmap */ | 742 | /* calculate the shift required to use bmap */ |
724 | if (inode->i_sb->s_blocksize > PAGE_SIZE) | 743 | if (inode->i_sb->s_blocksize > PAGE_SIZE) |
725 | return -ENOBUFS; | 744 | goto all_enobufs; |
726 | 745 | ||
727 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 746 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
728 | 747 | ||
@@ -762,7 +781,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
762 | nrbackpages++; | 781 | nrbackpages++; |
763 | } else if (space && pagevec_add(&pagevec, page) == 0) { | 782 | } else if (space && pagevec_add(&pagevec, page) == 0) { |
764 | fscache_mark_pages_cached(op, &pagevec); | 783 | fscache_mark_pages_cached(op, &pagevec); |
784 | fscache_retrieval_complete(op, 1); | ||
765 | ret = -ENODATA; | 785 | ret = -ENODATA; |
786 | } else { | ||
787 | fscache_retrieval_complete(op, 1); | ||
766 | } | 788 | } |
767 | } | 789 | } |
768 | 790 | ||
@@ -775,18 +797,18 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
775 | /* submit the apparently valid pages to the backing fs to be read from | 797 | /* submit the apparently valid pages to the backing fs to be read from |
776 | * disk */ | 798 | * disk */ |
777 | if (nrbackpages > 0) { | 799 | if (nrbackpages > 0) { |
778 | ret2 = cachefiles_read_backing_file(object, op, &backpages, | 800 | ret2 = cachefiles_read_backing_file(object, op, &backpages); |
779 | &pagevec); | ||
780 | if (ret2 == -ENOMEM || ret2 == -EINTR) | 801 | if (ret2 == -ENOMEM || ret2 == -EINTR) |
781 | ret = ret2; | 802 | ret = ret2; |
782 | } | 803 | } |
783 | 804 | ||
784 | if (pagevec_count(&pagevec) > 0) | ||
785 | fscache_mark_pages_cached(op, &pagevec); | ||
786 | |||
787 | _leave(" = %d [nr=%u%s]", | 805 | _leave(" = %d [nr=%u%s]", |
788 | ret, *nr_pages, list_empty(pages) ? " empty" : ""); | 806 | ret, *nr_pages, list_empty(pages) ? " empty" : ""); |
789 | return ret; | 807 | return ret; |
808 | |||
809 | all_enobufs: | ||
810 | fscache_retrieval_complete(op, *nr_pages); | ||
811 | return -ENOBUFS; | ||
790 | } | 812 | } |
791 | 813 | ||
792 | /* | 814 | /* |
@@ -806,7 +828,6 @@ int cachefiles_allocate_page(struct fscache_retrieval *op, | |||
806 | { | 828 | { |
807 | struct cachefiles_object *object; | 829 | struct cachefiles_object *object; |
808 | struct cachefiles_cache *cache; | 830 | struct cachefiles_cache *cache; |
809 | struct pagevec pagevec; | ||
810 | int ret; | 831 | int ret; |
811 | 832 | ||
812 | object = container_of(op->op.object, | 833 | object = container_of(op->op.object, |
@@ -817,14 +838,12 @@ int cachefiles_allocate_page(struct fscache_retrieval *op, | |||
817 | _enter("%p,{%lx},", object, page->index); | 838 | _enter("%p,{%lx},", object, page->index); |
818 | 839 | ||
819 | ret = cachefiles_has_space(cache, 0, 1); | 840 | ret = cachefiles_has_space(cache, 0, 1); |
820 | if (ret == 0) { | 841 | if (ret == 0) |
821 | pagevec_init(&pagevec, 0); | 842 | fscache_mark_page_cached(op, page); |
822 | pagevec_add(&pagevec, page); | 843 | else |
823 | fscache_mark_pages_cached(op, &pagevec); | ||
824 | } else { | ||
825 | ret = -ENOBUFS; | 844 | ret = -ENOBUFS; |
826 | } | ||
827 | 845 | ||
846 | fscache_retrieval_complete(op, 1); | ||
828 | _leave(" = %d", ret); | 847 | _leave(" = %d", ret); |
829 | return ret; | 848 | return ret; |
830 | } | 849 | } |
@@ -874,6 +893,7 @@ int cachefiles_allocate_pages(struct fscache_retrieval *op, | |||
874 | ret = -ENOBUFS; | 893 | ret = -ENOBUFS; |
875 | } | 894 | } |
876 | 895 | ||
896 | fscache_retrieval_complete(op, *nr_pages); | ||
877 | _leave(" = %d", ret); | 897 | _leave(" = %d", ret); |
878 | return ret; | 898 | return ret; |
879 | } | 899 | } |
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c index e18b183b47e1..73b46288b54b 100644 --- a/fs/cachefiles/xattr.c +++ b/fs/cachefiles/xattr.c | |||
@@ -174,7 +174,7 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object, | |||
174 | ASSERT(dentry); | 174 | ASSERT(dentry); |
175 | ASSERT(dentry->d_inode); | 175 | ASSERT(dentry->d_inode); |
176 | 176 | ||
177 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); | 177 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp); |
178 | if (!auxbuf) { | 178 | if (!auxbuf) { |
179 | _leave(" = -ENOMEM"); | 179 | _leave(" = -ENOMEM"); |
180 | return -ENOMEM; | 180 | return -ENOMEM; |
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c index 6a3c48abd677..b52aed1dca97 100644 --- a/fs/fscache/cache.c +++ b/fs/fscache/cache.c | |||
@@ -314,10 +314,10 @@ EXPORT_SYMBOL(fscache_add_cache); | |||
314 | */ | 314 | */ |
315 | void fscache_io_error(struct fscache_cache *cache) | 315 | void fscache_io_error(struct fscache_cache *cache) |
316 | { | 316 | { |
317 | set_bit(FSCACHE_IOERROR, &cache->flags); | 317 | if (!test_and_set_bit(FSCACHE_IOERROR, &cache->flags)) |
318 | 318 | printk(KERN_ERR "FS-Cache:" | |
319 | printk(KERN_ERR "FS-Cache: Cache %s stopped due to I/O error\n", | 319 | " Cache '%s' stopped due to I/O error\n", |
320 | cache->ops->name); | 320 | cache->ops->name); |
321 | } | 321 | } |
322 | EXPORT_SYMBOL(fscache_io_error); | 322 | EXPORT_SYMBOL(fscache_io_error); |
323 | 323 | ||
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 990535071a8a..8dcb114758e3 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -370,6 +370,66 @@ cant_attach_object: | |||
370 | } | 370 | } |
371 | 371 | ||
372 | /* | 372 | /* |
373 | * Invalidate an object. Callable with spinlocks held. | ||
374 | */ | ||
375 | void __fscache_invalidate(struct fscache_cookie *cookie) | ||
376 | { | ||
377 | struct fscache_object *object; | ||
378 | |||
379 | _enter("{%s}", cookie->def->name); | ||
380 | |||
381 | fscache_stat(&fscache_n_invalidates); | ||
382 | |||
383 | /* Only permit invalidation of data files. Invalidating an index will | ||
384 | * require the caller to release all its attachments to the tree rooted | ||
385 | * there, and if it's doing that, it may as well just retire the | ||
386 | * cookie. | ||
387 | */ | ||
388 | ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); | ||
389 | |||
390 | /* We will be updating the cookie too. */ | ||
391 | BUG_ON(!cookie->def->get_aux); | ||
392 | |||
393 | /* If there's an object, we tell the object state machine to handle the | ||
394 | * invalidation on our behalf, otherwise there's nothing to do. | ||
395 | */ | ||
396 | if (!hlist_empty(&cookie->backing_objects)) { | ||
397 | spin_lock(&cookie->lock); | ||
398 | |||
399 | if (!hlist_empty(&cookie->backing_objects) && | ||
400 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, | ||
401 | &cookie->flags)) { | ||
402 | object = hlist_entry(cookie->backing_objects.first, | ||
403 | struct fscache_object, | ||
404 | cookie_link); | ||
405 | if (object->state < FSCACHE_OBJECT_DYING) | ||
406 | fscache_raise_event( | ||
407 | object, FSCACHE_OBJECT_EV_INVALIDATE); | ||
408 | } | ||
409 | |||
410 | spin_unlock(&cookie->lock); | ||
411 | } | ||
412 | |||
413 | _leave(""); | ||
414 | } | ||
415 | EXPORT_SYMBOL(__fscache_invalidate); | ||
416 | |||
417 | /* | ||
418 | * Wait for object invalidation to complete. | ||
419 | */ | ||
420 | void __fscache_wait_on_invalidate(struct fscache_cookie *cookie) | ||
421 | { | ||
422 | _enter("%p", cookie); | ||
423 | |||
424 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING, | ||
425 | fscache_wait_bit_interruptible, | ||
426 | TASK_UNINTERRUPTIBLE); | ||
427 | |||
428 | _leave(""); | ||
429 | } | ||
430 | EXPORT_SYMBOL(__fscache_wait_on_invalidate); | ||
431 | |||
432 | /* | ||
373 | * update the index entries backing a cookie | 433 | * update the index entries backing a cookie |
374 | */ | 434 | */ |
375 | void __fscache_update_cookie(struct fscache_cookie *cookie) | 435 | void __fscache_update_cookie(struct fscache_cookie *cookie) |
@@ -442,16 +502,34 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
442 | 502 | ||
443 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; | 503 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; |
444 | 504 | ||
505 | try_again: | ||
445 | spin_lock(&cookie->lock); | 506 | spin_lock(&cookie->lock); |
446 | 507 | ||
447 | /* break links with all the active objects */ | 508 | /* break links with all the active objects */ |
448 | while (!hlist_empty(&cookie->backing_objects)) { | 509 | while (!hlist_empty(&cookie->backing_objects)) { |
510 | int n_reads; | ||
449 | object = hlist_entry(cookie->backing_objects.first, | 511 | object = hlist_entry(cookie->backing_objects.first, |
450 | struct fscache_object, | 512 | struct fscache_object, |
451 | cookie_link); | 513 | cookie_link); |
452 | 514 | ||
453 | _debug("RELEASE OBJ%x", object->debug_id); | 515 | _debug("RELEASE OBJ%x", object->debug_id); |
454 | 516 | ||
517 | set_bit(FSCACHE_COOKIE_WAITING_ON_READS, &cookie->flags); | ||
518 | n_reads = atomic_read(&object->n_reads); | ||
519 | if (n_reads) { | ||
520 | int n_ops = object->n_ops; | ||
521 | int n_in_progress = object->n_in_progress; | ||
522 | spin_unlock(&cookie->lock); | ||
523 | printk(KERN_ERR "FS-Cache:" | ||
524 | " Cookie '%s' still has %d outstanding reads (%d,%d)\n", | ||
525 | cookie->def->name, | ||
526 | n_reads, n_ops, n_in_progress); | ||
527 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_WAITING_ON_READS, | ||
528 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
529 | printk("Wait finished\n"); | ||
530 | goto try_again; | ||
531 | } | ||
532 | |||
455 | /* detach each cache object from the object cookie */ | 533 | /* detach each cache object from the object cookie */ |
456 | spin_lock(&object->lock); | 534 | spin_lock(&object->lock); |
457 | hlist_del_init(&object->cookie_link); | 535 | hlist_del_init(&object->cookie_link); |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index f6aad48d38a8..ee38fef4be51 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -121,12 +121,19 @@ extern int fscache_submit_exclusive_op(struct fscache_object *, | |||
121 | struct fscache_operation *); | 121 | struct fscache_operation *); |
122 | extern int fscache_submit_op(struct fscache_object *, | 122 | extern int fscache_submit_op(struct fscache_object *, |
123 | struct fscache_operation *); | 123 | struct fscache_operation *); |
124 | extern int fscache_cancel_op(struct fscache_operation *); | 124 | extern int fscache_cancel_op(struct fscache_operation *, |
125 | void (*)(struct fscache_operation *)); | ||
126 | extern void fscache_cancel_all_ops(struct fscache_object *); | ||
125 | extern void fscache_abort_object(struct fscache_object *); | 127 | extern void fscache_abort_object(struct fscache_object *); |
126 | extern void fscache_start_operations(struct fscache_object *); | 128 | extern void fscache_start_operations(struct fscache_object *); |
127 | extern void fscache_operation_gc(struct work_struct *); | 129 | extern void fscache_operation_gc(struct work_struct *); |
128 | 130 | ||
129 | /* | 131 | /* |
132 | * page.c | ||
133 | */ | ||
134 | extern void fscache_invalidate_writes(struct fscache_cookie *); | ||
135 | |||
136 | /* | ||
130 | * proc.c | 137 | * proc.c |
131 | */ | 138 | */ |
132 | #ifdef CONFIG_PROC_FS | 139 | #ifdef CONFIG_PROC_FS |
@@ -194,6 +201,7 @@ extern atomic_t fscache_n_store_vmscan_not_storing; | |||
194 | extern atomic_t fscache_n_store_vmscan_gone; | 201 | extern atomic_t fscache_n_store_vmscan_gone; |
195 | extern atomic_t fscache_n_store_vmscan_busy; | 202 | extern atomic_t fscache_n_store_vmscan_busy; |
196 | extern atomic_t fscache_n_store_vmscan_cancelled; | 203 | extern atomic_t fscache_n_store_vmscan_cancelled; |
204 | extern atomic_t fscache_n_store_vmscan_wait; | ||
197 | 205 | ||
198 | extern atomic_t fscache_n_marks; | 206 | extern atomic_t fscache_n_marks; |
199 | extern atomic_t fscache_n_uncaches; | 207 | extern atomic_t fscache_n_uncaches; |
@@ -205,6 +213,9 @@ extern atomic_t fscache_n_acquires_ok; | |||
205 | extern atomic_t fscache_n_acquires_nobufs; | 213 | extern atomic_t fscache_n_acquires_nobufs; |
206 | extern atomic_t fscache_n_acquires_oom; | 214 | extern atomic_t fscache_n_acquires_oom; |
207 | 215 | ||
216 | extern atomic_t fscache_n_invalidates; | ||
217 | extern atomic_t fscache_n_invalidates_run; | ||
218 | |||
208 | extern atomic_t fscache_n_updates; | 219 | extern atomic_t fscache_n_updates; |
209 | extern atomic_t fscache_n_updates_null; | 220 | extern atomic_t fscache_n_updates_null; |
210 | extern atomic_t fscache_n_updates_run; | 221 | extern atomic_t fscache_n_updates_run; |
@@ -237,6 +248,7 @@ extern atomic_t fscache_n_cop_alloc_object; | |||
237 | extern atomic_t fscache_n_cop_lookup_object; | 248 | extern atomic_t fscache_n_cop_lookup_object; |
238 | extern atomic_t fscache_n_cop_lookup_complete; | 249 | extern atomic_t fscache_n_cop_lookup_complete; |
239 | extern atomic_t fscache_n_cop_grab_object; | 250 | extern atomic_t fscache_n_cop_grab_object; |
251 | extern atomic_t fscache_n_cop_invalidate_object; | ||
240 | extern atomic_t fscache_n_cop_update_object; | 252 | extern atomic_t fscache_n_cop_update_object; |
241 | extern atomic_t fscache_n_cop_drop_object; | 253 | extern atomic_t fscache_n_cop_drop_object; |
242 | extern atomic_t fscache_n_cop_put_object; | 254 | extern atomic_t fscache_n_cop_put_object; |
@@ -278,6 +290,7 @@ extern const struct file_operations fscache_stats_fops; | |||
278 | static inline void fscache_raise_event(struct fscache_object *object, | 290 | static inline void fscache_raise_event(struct fscache_object *object, |
279 | unsigned event) | 291 | unsigned event) |
280 | { | 292 | { |
293 | BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS); | ||
281 | if (!test_and_set_bit(event, &object->events) && | 294 | if (!test_and_set_bit(event, &object->events) && |
282 | test_bit(event, &object->event_mask)) | 295 | test_bit(event, &object->event_mask)) |
283 | fscache_enqueue_object(object); | 296 | fscache_enqueue_object(object); |
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index ebe29c581380..f27c89d17885 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c | |||
@@ -245,7 +245,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
245 | obj->n_in_progress, | 245 | obj->n_in_progress, |
246 | obj->n_exclusive, | 246 | obj->n_exclusive, |
247 | atomic_read(&obj->n_reads), | 247 | atomic_read(&obj->n_reads), |
248 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, | 248 | obj->event_mask, |
249 | obj->events, | 249 | obj->events, |
250 | obj->flags, | 250 | obj->flags, |
251 | work_busy(&obj->work)); | 251 | work_busy(&obj->work)); |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index b6b897c550ac..50d41c180211 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | ||
17 | #include "internal.h" | 18 | #include "internal.h" |
18 | 19 | ||
19 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | 20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
@@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | |||
22 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", | 23 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", |
23 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", | 24 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", |
24 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", | 25 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", |
26 | [FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING", | ||
25 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", | 27 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", |
26 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", | 28 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", |
27 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", | 29 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", |
@@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | |||
39 | [FSCACHE_OBJECT_CREATING] = "CRTN", | 41 | [FSCACHE_OBJECT_CREATING] = "CRTN", |
40 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", | 42 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", |
41 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", | 43 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", |
44 | [FSCACHE_OBJECT_INVALIDATING] = "INVL", | ||
42 | [FSCACHE_OBJECT_UPDATING] = "UPDT", | 45 | [FSCACHE_OBJECT_UPDATING] = "UPDT", |
43 | [FSCACHE_OBJECT_DYING] = "DYNG", | 46 | [FSCACHE_OBJECT_DYING] = "DYNG", |
44 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", | 47 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", |
@@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *); | |||
54 | static void fscache_initialise_object(struct fscache_object *); | 57 | static void fscache_initialise_object(struct fscache_object *); |
55 | static void fscache_lookup_object(struct fscache_object *); | 58 | static void fscache_lookup_object(struct fscache_object *); |
56 | static void fscache_object_available(struct fscache_object *); | 59 | static void fscache_object_available(struct fscache_object *); |
60 | static void fscache_invalidate_object(struct fscache_object *); | ||
57 | static void fscache_release_object(struct fscache_object *); | 61 | static void fscache_release_object(struct fscache_object *); |
58 | static void fscache_withdraw_object(struct fscache_object *); | 62 | static void fscache_withdraw_object(struct fscache_object *); |
59 | static void fscache_enqueue_dependents(struct fscache_object *); | 63 | static void fscache_enqueue_dependents(struct fscache_object *); |
@@ -79,6 +83,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
79 | } | 83 | } |
80 | 84 | ||
81 | /* | 85 | /* |
86 | * Notify netfs of invalidation completion. | ||
87 | */ | ||
88 | static inline void fscache_invalidation_complete(struct fscache_cookie *cookie) | ||
89 | { | ||
90 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
91 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
92 | } | ||
93 | |||
94 | /* | ||
82 | * process events that have been sent to an object's state machine | 95 | * process events that have been sent to an object's state machine |
83 | * - initiates parent lookup | 96 | * - initiates parent lookup |
84 | * - does object lookup | 97 | * - does object lookup |
@@ -90,6 +103,7 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
90 | { | 103 | { |
91 | enum fscache_object_state new_state; | 104 | enum fscache_object_state new_state; |
92 | struct fscache_cookie *cookie; | 105 | struct fscache_cookie *cookie; |
106 | int event; | ||
93 | 107 | ||
94 | ASSERT(object != NULL); | 108 | ASSERT(object != NULL); |
95 | 109 | ||
@@ -101,7 +115,8 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
101 | /* wait for the parent object to become ready */ | 115 | /* wait for the parent object to become ready */ |
102 | case FSCACHE_OBJECT_INIT: | 116 | case FSCACHE_OBJECT_INIT: |
103 | object->event_mask = | 117 | object->event_mask = |
104 | ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED); | 118 | FSCACHE_OBJECT_EVENTS_MASK & |
119 | ~(1 << FSCACHE_OBJECT_EV_CLEARED); | ||
105 | fscache_initialise_object(object); | 120 | fscache_initialise_object(object); |
106 | goto done; | 121 | goto done; |
107 | 122 | ||
@@ -125,6 +140,16 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
125 | case FSCACHE_OBJECT_ACTIVE: | 140 | case FSCACHE_OBJECT_ACTIVE: |
126 | goto active_transit; | 141 | goto active_transit; |
127 | 142 | ||
143 | /* Invalidate an object on disk */ | ||
144 | case FSCACHE_OBJECT_INVALIDATING: | ||
145 | clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events); | ||
146 | fscache_stat(&fscache_n_invalidates_run); | ||
147 | fscache_stat(&fscache_n_cop_invalidate_object); | ||
148 | fscache_invalidate_object(object); | ||
149 | fscache_stat_d(&fscache_n_cop_invalidate_object); | ||
150 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | ||
151 | goto active_transit; | ||
152 | |||
128 | /* update the object metadata on disk */ | 153 | /* update the object metadata on disk */ |
129 | case FSCACHE_OBJECT_UPDATING: | 154 | case FSCACHE_OBJECT_UPDATING: |
130 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); | 155 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); |
@@ -251,13 +276,17 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
251 | 276 | ||
252 | /* determine the transition from a lookup state */ | 277 | /* determine the transition from a lookup state */ |
253 | lookup_transit: | 278 | lookup_transit: |
254 | switch (fls(object->events & object->event_mask) - 1) { | 279 | event = fls(object->events & object->event_mask) - 1; |
280 | switch (event) { | ||
255 | case FSCACHE_OBJECT_EV_WITHDRAW: | 281 | case FSCACHE_OBJECT_EV_WITHDRAW: |
256 | case FSCACHE_OBJECT_EV_RETIRE: | 282 | case FSCACHE_OBJECT_EV_RETIRE: |
257 | case FSCACHE_OBJECT_EV_RELEASE: | 283 | case FSCACHE_OBJECT_EV_RELEASE: |
258 | case FSCACHE_OBJECT_EV_ERROR: | 284 | case FSCACHE_OBJECT_EV_ERROR: |
259 | new_state = FSCACHE_OBJECT_LC_DYING; | 285 | new_state = FSCACHE_OBJECT_LC_DYING; |
260 | goto change_state; | 286 | goto change_state; |
287 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
288 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
289 | goto change_state; | ||
261 | case FSCACHE_OBJECT_EV_REQUEUE: | 290 | case FSCACHE_OBJECT_EV_REQUEUE: |
262 | goto done; | 291 | goto done; |
263 | case -1: | 292 | case -1: |
@@ -268,13 +297,17 @@ lookup_transit: | |||
268 | 297 | ||
269 | /* determine the transition from an active state */ | 298 | /* determine the transition from an active state */ |
270 | active_transit: | 299 | active_transit: |
271 | switch (fls(object->events & object->event_mask) - 1) { | 300 | event = fls(object->events & object->event_mask) - 1; |
301 | switch (event) { | ||
272 | case FSCACHE_OBJECT_EV_WITHDRAW: | 302 | case FSCACHE_OBJECT_EV_WITHDRAW: |
273 | case FSCACHE_OBJECT_EV_RETIRE: | 303 | case FSCACHE_OBJECT_EV_RETIRE: |
274 | case FSCACHE_OBJECT_EV_RELEASE: | 304 | case FSCACHE_OBJECT_EV_RELEASE: |
275 | case FSCACHE_OBJECT_EV_ERROR: | 305 | case FSCACHE_OBJECT_EV_ERROR: |
276 | new_state = FSCACHE_OBJECT_DYING; | 306 | new_state = FSCACHE_OBJECT_DYING; |
277 | goto change_state; | 307 | goto change_state; |
308 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
309 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
310 | goto change_state; | ||
278 | case FSCACHE_OBJECT_EV_UPDATE: | 311 | case FSCACHE_OBJECT_EV_UPDATE: |
279 | new_state = FSCACHE_OBJECT_UPDATING; | 312 | new_state = FSCACHE_OBJECT_UPDATING; |
280 | goto change_state; | 313 | goto change_state; |
@@ -287,7 +320,8 @@ active_transit: | |||
287 | 320 | ||
288 | /* determine the transition from a terminal state */ | 321 | /* determine the transition from a terminal state */ |
289 | terminal_transit: | 322 | terminal_transit: |
290 | switch (fls(object->events & object->event_mask) - 1) { | 323 | event = fls(object->events & object->event_mask) - 1; |
324 | switch (event) { | ||
291 | case FSCACHE_OBJECT_EV_WITHDRAW: | 325 | case FSCACHE_OBJECT_EV_WITHDRAW: |
292 | new_state = FSCACHE_OBJECT_WITHDRAWING; | 326 | new_state = FSCACHE_OBJECT_WITHDRAWING; |
293 | goto change_state; | 327 | goto change_state; |
@@ -320,8 +354,8 @@ done: | |||
320 | 354 | ||
321 | unsupported_event: | 355 | unsupported_event: |
322 | printk(KERN_ERR "FS-Cache:" | 356 | printk(KERN_ERR "FS-Cache:" |
323 | " Unsupported event %lx [mask %lx] in state %s\n", | 357 | " Unsupported event %d [%lx/%lx] in state %s\n", |
324 | object->events, object->event_mask, | 358 | event, object->events, object->event_mask, |
325 | fscache_object_states[object->state]); | 359 | fscache_object_states[object->state]); |
326 | BUG(); | 360 | BUG(); |
327 | } | 361 | } |
@@ -587,8 +621,6 @@ static void fscache_object_available(struct fscache_object *object) | |||
587 | if (object->n_in_progress == 0) { | 621 | if (object->n_in_progress == 0) { |
588 | if (object->n_ops > 0) { | 622 | if (object->n_ops > 0) { |
589 | ASSERTCMP(object->n_ops, >=, object->n_obj_ops); | 623 | ASSERTCMP(object->n_ops, >=, object->n_obj_ops); |
590 | ASSERTIF(object->n_ops > object->n_obj_ops, | ||
591 | !list_empty(&object->pending_ops)); | ||
592 | fscache_start_operations(object); | 624 | fscache_start_operations(object); |
593 | } else { | 625 | } else { |
594 | ASSERT(list_empty(&object->pending_ops)); | 626 | ASSERT(list_empty(&object->pending_ops)); |
@@ -681,6 +713,7 @@ static void fscache_withdraw_object(struct fscache_object *object) | |||
681 | if (object->cookie == cookie) { | 713 | if (object->cookie == cookie) { |
682 | hlist_del_init(&object->cookie_link); | 714 | hlist_del_init(&object->cookie_link); |
683 | object->cookie = NULL; | 715 | object->cookie = NULL; |
716 | fscache_invalidation_complete(cookie); | ||
684 | detached = true; | 717 | detached = true; |
685 | } | 718 | } |
686 | spin_unlock(&cookie->lock); | 719 | spin_unlock(&cookie->lock); |
@@ -890,3 +923,55 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object, | |||
890 | return result; | 923 | return result; |
891 | } | 924 | } |
892 | EXPORT_SYMBOL(fscache_check_aux); | 925 | EXPORT_SYMBOL(fscache_check_aux); |
926 | |||
927 | /* | ||
928 | * Asynchronously invalidate an object. | ||
929 | */ | ||
930 | static void fscache_invalidate_object(struct fscache_object *object) | ||
931 | { | ||
932 | struct fscache_operation *op; | ||
933 | struct fscache_cookie *cookie = object->cookie; | ||
934 | |||
935 | _enter("{OBJ%x}", object->debug_id); | ||
936 | |||
937 | /* Reject any new read/write ops and abort any that are pending. */ | ||
938 | fscache_invalidate_writes(cookie); | ||
939 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | ||
940 | fscache_cancel_all_ops(object); | ||
941 | |||
942 | /* Now we have to wait for in-progress reads and writes */ | ||
943 | op = kzalloc(sizeof(*op), GFP_KERNEL); | ||
944 | if (!op) { | ||
945 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | ||
946 | _leave(" [ENOMEM]"); | ||
947 | return; | ||
948 | } | ||
949 | |||
950 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); | ||
951 | op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); | ||
952 | |||
953 | spin_lock(&cookie->lock); | ||
954 | if (fscache_submit_exclusive_op(object, op) < 0) | ||
955 | goto submit_op_failed; | ||
956 | spin_unlock(&cookie->lock); | ||
957 | fscache_put_operation(op); | ||
958 | |||
959 | /* Once we've completed the invalidation, we know there will be no data | ||
960 | * stored in the cache and thus we can reinstate the data-check-skip | ||
961 | * optimisation. | ||
962 | */ | ||
963 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | ||
964 | |||
965 | /* We can allow read and write requests to come in once again. They'll | ||
966 | * queue up behind our exclusive invalidation operation. | ||
967 | */ | ||
968 | fscache_invalidation_complete(cookie); | ||
969 | _leave(""); | ||
970 | return; | ||
971 | |||
972 | submit_op_failed: | ||
973 | spin_unlock(&cookie->lock); | ||
974 | kfree(op); | ||
975 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | ||
976 | _leave(" [EIO]"); | ||
977 | } | ||
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 30afdfa7aec7..762a9ec4ffa4 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -37,6 +37,7 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
37 | ASSERT(op->processor != NULL); | 37 | ASSERT(op->processor != NULL); |
38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
39 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 39 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
40 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
40 | 41 | ||
41 | fscache_stat(&fscache_n_op_enqueue); | 42 | fscache_stat(&fscache_n_op_enqueue); |
42 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
@@ -64,6 +65,9 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
64 | static void fscache_run_op(struct fscache_object *object, | 65 | static void fscache_run_op(struct fscache_object *object, |
65 | struct fscache_operation *op) | 66 | struct fscache_operation *op) |
66 | { | 67 | { |
68 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
69 | |||
70 | op->state = FSCACHE_OP_ST_IN_PROGRESS; | ||
67 | object->n_in_progress++; | 71 | object->n_in_progress++; |
68 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 72 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
69 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 73 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
@@ -84,18 +88,21 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
84 | 88 | ||
85 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 89 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
86 | 90 | ||
91 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
92 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
93 | |||
87 | spin_lock(&object->lock); | 94 | spin_lock(&object->lock); |
88 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 95 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
89 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 96 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
90 | ASSERT(list_empty(&op->pend_link)); | 97 | ASSERT(list_empty(&op->pend_link)); |
91 | 98 | ||
92 | ret = -ENOBUFS; | 99 | op->state = FSCACHE_OP_ST_PENDING; |
93 | if (fscache_object_is_active(object)) { | 100 | if (fscache_object_is_active(object)) { |
94 | op->object = object; | 101 | op->object = object; |
95 | object->n_ops++; | 102 | object->n_ops++; |
96 | object->n_exclusive++; /* reads and writes must wait */ | 103 | object->n_exclusive++; /* reads and writes must wait */ |
97 | 104 | ||
98 | if (object->n_ops > 1) { | 105 | if (object->n_in_progress > 0) { |
99 | atomic_inc(&op->usage); | 106 | atomic_inc(&op->usage); |
100 | list_add_tail(&op->pend_link, &object->pending_ops); | 107 | list_add_tail(&op->pend_link, &object->pending_ops); |
101 | fscache_stat(&fscache_n_op_pend); | 108 | fscache_stat(&fscache_n_op_pend); |
@@ -121,8 +128,11 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
121 | fscache_stat(&fscache_n_op_pend); | 128 | fscache_stat(&fscache_n_op_pend); |
122 | ret = 0; | 129 | ret = 0; |
123 | } else { | 130 | } else { |
124 | /* not allowed to submit ops in any other state */ | 131 | /* If we're in any other state, there must have been an I/O |
125 | BUG(); | 132 | * error of some nature. |
133 | */ | ||
134 | ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags)); | ||
135 | ret = -EIO; | ||
126 | } | 136 | } |
127 | 137 | ||
128 | spin_unlock(&object->lock); | 138 | spin_unlock(&object->lock); |
@@ -186,6 +196,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
186 | _enter("{OBJ%x OP%x},{%u}", | 196 | _enter("{OBJ%x OP%x},{%u}", |
187 | object->debug_id, op->debug_id, atomic_read(&op->usage)); | 197 | object->debug_id, op->debug_id, atomic_read(&op->usage)); |
188 | 198 | ||
199 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
189 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 200 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
190 | 201 | ||
191 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
@@ -196,6 +207,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
196 | ostate = object->state; | 207 | ostate = object->state; |
197 | smp_rmb(); | 208 | smp_rmb(); |
198 | 209 | ||
210 | op->state = FSCACHE_OP_ST_PENDING; | ||
199 | if (fscache_object_is_active(object)) { | 211 | if (fscache_object_is_active(object)) { |
200 | op->object = object; | 212 | op->object = object; |
201 | object->n_ops++; | 213 | object->n_ops++; |
@@ -225,12 +237,15 @@ int fscache_submit_op(struct fscache_object *object, | |||
225 | object->state == FSCACHE_OBJECT_LC_DYING || | 237 | object->state == FSCACHE_OBJECT_LC_DYING || |
226 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | 238 | object->state == FSCACHE_OBJECT_WITHDRAWING) { |
227 | fscache_stat(&fscache_n_op_rejected); | 239 | fscache_stat(&fscache_n_op_rejected); |
240 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
228 | ret = -ENOBUFS; | 241 | ret = -ENOBUFS; |
229 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 242 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
230 | fscache_report_unexpected_submission(object, op, ostate); | 243 | fscache_report_unexpected_submission(object, op, ostate); |
231 | ASSERT(!fscache_object_is_active(object)); | 244 | ASSERT(!fscache_object_is_active(object)); |
245 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
232 | ret = -ENOBUFS; | 246 | ret = -ENOBUFS; |
233 | } else { | 247 | } else { |
248 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
234 | ret = -ENOBUFS; | 249 | ret = -ENOBUFS; |
235 | } | 250 | } |
236 | 251 | ||
@@ -283,20 +298,28 @@ void fscache_start_operations(struct fscache_object *object) | |||
283 | /* | 298 | /* |
284 | * cancel an operation that's pending on an object | 299 | * cancel an operation that's pending on an object |
285 | */ | 300 | */ |
286 | int fscache_cancel_op(struct fscache_operation *op) | 301 | int fscache_cancel_op(struct fscache_operation *op, |
302 | void (*do_cancel)(struct fscache_operation *)) | ||
287 | { | 303 | { |
288 | struct fscache_object *object = op->object; | 304 | struct fscache_object *object = op->object; |
289 | int ret; | 305 | int ret; |
290 | 306 | ||
291 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | 307 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); |
292 | 308 | ||
309 | ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING); | ||
310 | ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED); | ||
311 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
312 | |||
293 | spin_lock(&object->lock); | 313 | spin_lock(&object->lock); |
294 | 314 | ||
295 | ret = -EBUSY; | 315 | ret = -EBUSY; |
296 | if (!list_empty(&op->pend_link)) { | 316 | if (op->state == FSCACHE_OP_ST_PENDING) { |
317 | ASSERT(!list_empty(&op->pend_link)); | ||
297 | fscache_stat(&fscache_n_op_cancelled); | 318 | fscache_stat(&fscache_n_op_cancelled); |
298 | list_del_init(&op->pend_link); | 319 | list_del_init(&op->pend_link); |
299 | object->n_ops--; | 320 | if (do_cancel) |
321 | do_cancel(op); | ||
322 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
300 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | 323 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) |
301 | object->n_exclusive--; | 324 | object->n_exclusive--; |
302 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 325 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
@@ -311,6 +334,70 @@ int fscache_cancel_op(struct fscache_operation *op) | |||
311 | } | 334 | } |
312 | 335 | ||
313 | /* | 336 | /* |
337 | * Cancel all pending operations on an object | ||
338 | */ | ||
339 | void fscache_cancel_all_ops(struct fscache_object *object) | ||
340 | { | ||
341 | struct fscache_operation *op; | ||
342 | |||
343 | _enter("OBJ%x", object->debug_id); | ||
344 | |||
345 | spin_lock(&object->lock); | ||
346 | |||
347 | while (!list_empty(&object->pending_ops)) { | ||
348 | op = list_entry(object->pending_ops.next, | ||
349 | struct fscache_operation, pend_link); | ||
350 | fscache_stat(&fscache_n_op_cancelled); | ||
351 | list_del_init(&op->pend_link); | ||
352 | |||
353 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
354 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
355 | |||
356 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
357 | object->n_exclusive--; | ||
358 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
359 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
360 | fscache_put_operation(op); | ||
361 | cond_resched_lock(&object->lock); | ||
362 | } | ||
363 | |||
364 | spin_unlock(&object->lock); | ||
365 | _leave(""); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Record the completion or cancellation of an in-progress operation. | ||
370 | */ | ||
371 | void fscache_op_complete(struct fscache_operation *op, bool cancelled) | ||
372 | { | ||
373 | struct fscache_object *object = op->object; | ||
374 | |||
375 | _enter("OBJ%x", object->debug_id); | ||
376 | |||
377 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
378 | ASSERTCMP(object->n_in_progress, >, 0); | ||
379 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
380 | object->n_exclusive, >, 0); | ||
381 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
382 | object->n_in_progress, ==, 1); | ||
383 | |||
384 | spin_lock(&object->lock); | ||
385 | |||
386 | op->state = cancelled ? | ||
387 | FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE; | ||
388 | |||
389 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
390 | object->n_exclusive--; | ||
391 | object->n_in_progress--; | ||
392 | if (object->n_in_progress == 0) | ||
393 | fscache_start_operations(object); | ||
394 | |||
395 | spin_unlock(&object->lock); | ||
396 | _leave(""); | ||
397 | } | ||
398 | EXPORT_SYMBOL(fscache_op_complete); | ||
399 | |||
400 | /* | ||
314 | * release an operation | 401 | * release an operation |
315 | * - queues pending ops if this is the last in-progress op | 402 | * - queues pending ops if this is the last in-progress op |
316 | */ | 403 | */ |
@@ -328,8 +415,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
328 | return; | 415 | return; |
329 | 416 | ||
330 | _debug("PUT OP"); | 417 | _debug("PUT OP"); |
331 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 418 | ASSERTIFCMP(op->state != FSCACHE_OP_ST_COMPLETE, |
332 | BUG(); | 419 | op->state, ==, FSCACHE_OP_ST_CANCELLED); |
420 | op->state = FSCACHE_OP_ST_DEAD; | ||
333 | 421 | ||
334 | fscache_stat(&fscache_n_op_release); | 422 | fscache_stat(&fscache_n_op_release); |
335 | 423 | ||
@@ -340,8 +428,14 @@ void fscache_put_operation(struct fscache_operation *op) | |||
340 | 428 | ||
341 | object = op->object; | 429 | object = op->object; |
342 | 430 | ||
343 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) | 431 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) { |
344 | atomic_dec(&object->n_reads); | 432 | if (atomic_dec_and_test(&object->n_reads)) { |
433 | clear_bit(FSCACHE_COOKIE_WAITING_ON_READS, | ||
434 | &object->cookie->flags); | ||
435 | wake_up_bit(&object->cookie->flags, | ||
436 | FSCACHE_COOKIE_WAITING_ON_READS); | ||
437 | } | ||
438 | } | ||
345 | 439 | ||
346 | /* now... we may get called with the object spinlock held, so we | 440 | /* now... we may get called with the object spinlock held, so we |
347 | * complete the cleanup here only if we can immediately acquire the | 441 | * complete the cleanup here only if we can immediately acquire the |
@@ -359,16 +453,6 @@ void fscache_put_operation(struct fscache_operation *op) | |||
359 | return; | 453 | return; |
360 | } | 454 | } |
361 | 455 | ||
362 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
363 | ASSERTCMP(object->n_exclusive, >, 0); | ||
364 | object->n_exclusive--; | ||
365 | } | ||
366 | |||
367 | ASSERTCMP(object->n_in_progress, >, 0); | ||
368 | object->n_in_progress--; | ||
369 | if (object->n_in_progress == 0) | ||
370 | fscache_start_operations(object); | ||
371 | |||
372 | ASSERTCMP(object->n_ops, >, 0); | 456 | ASSERTCMP(object->n_ops, >, 0); |
373 | object->n_ops--; | 457 | object->n_ops--; |
374 | if (object->n_ops == 0) | 458 | if (object->n_ops == 0) |
@@ -407,23 +491,14 @@ void fscache_operation_gc(struct work_struct *work) | |||
407 | spin_unlock(&cache->op_gc_list_lock); | 491 | spin_unlock(&cache->op_gc_list_lock); |
408 | 492 | ||
409 | object = op->object; | 493 | object = op->object; |
494 | spin_lock(&object->lock); | ||
410 | 495 | ||
411 | _debug("GC DEFERRED REL OBJ%x OP%x", | 496 | _debug("GC DEFERRED REL OBJ%x OP%x", |
412 | object->debug_id, op->debug_id); | 497 | object->debug_id, op->debug_id); |
413 | fscache_stat(&fscache_n_op_gc); | 498 | fscache_stat(&fscache_n_op_gc); |
414 | 499 | ||
415 | ASSERTCMP(atomic_read(&op->usage), ==, 0); | 500 | ASSERTCMP(atomic_read(&op->usage), ==, 0); |
416 | 501 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD); | |
417 | spin_lock(&object->lock); | ||
418 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
419 | ASSERTCMP(object->n_exclusive, >, 0); | ||
420 | object->n_exclusive--; | ||
421 | } | ||
422 | |||
423 | ASSERTCMP(object->n_in_progress, >, 0); | ||
424 | object->n_in_progress--; | ||
425 | if (object->n_in_progress == 0) | ||
426 | fscache_start_operations(object); | ||
427 | 502 | ||
428 | ASSERTCMP(object->n_ops, >, 0); | 503 | ASSERTCMP(object->n_ops, >, 0); |
429 | object->n_ops--; | 504 | object->n_ops--; |
@@ -431,6 +506,7 @@ void fscache_operation_gc(struct work_struct *work) | |||
431 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); | 506 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); |
432 | 507 | ||
433 | spin_unlock(&object->lock); | 508 | spin_unlock(&object->lock); |
509 | kfree(op); | ||
434 | 510 | ||
435 | } while (count++ < 20); | 511 | } while (count++ < 20); |
436 | 512 | ||
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 3f7a59bfa7ad..ff000e52072d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -56,6 +56,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie, | |||
56 | 56 | ||
57 | _enter("%p,%p,%x", cookie, page, gfp); | 57 | _enter("%p,%p,%x", cookie, page, gfp); |
58 | 58 | ||
59 | try_again: | ||
59 | rcu_read_lock(); | 60 | rcu_read_lock(); |
60 | val = radix_tree_lookup(&cookie->stores, page->index); | 61 | val = radix_tree_lookup(&cookie->stores, page->index); |
61 | if (!val) { | 62 | if (!val) { |
@@ -104,11 +105,19 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie, | |||
104 | return true; | 105 | return true; |
105 | 106 | ||
106 | page_busy: | 107 | page_busy: |
107 | /* we might want to wait here, but that could deadlock the allocator as | 108 | /* We will wait here if we're allowed to, but that could deadlock the |
108 | * the work threads writing to the cache may all end up sleeping | 109 | * allocator as the work threads writing to the cache may all end up |
109 | * on memory allocation */ | 110 | * sleeping on memory allocation, so we may need to impose a timeout |
110 | fscache_stat(&fscache_n_store_vmscan_busy); | 111 | * too. */ |
111 | return false; | 112 | if (!(gfp & __GFP_WAIT)) { |
113 | fscache_stat(&fscache_n_store_vmscan_busy); | ||
114 | return false; | ||
115 | } | ||
116 | |||
117 | fscache_stat(&fscache_n_store_vmscan_wait); | ||
118 | __fscache_wait_on_page_write(cookie, page); | ||
119 | gfp &= ~__GFP_WAIT; | ||
120 | goto try_again; | ||
112 | } | 121 | } |
113 | EXPORT_SYMBOL(__fscache_maybe_release_page); | 122 | EXPORT_SYMBOL(__fscache_maybe_release_page); |
114 | 123 | ||
@@ -162,6 +171,7 @@ static void fscache_attr_changed_op(struct fscache_operation *op) | |||
162 | fscache_abort_object(object); | 171 | fscache_abort_object(object); |
163 | } | 172 | } |
164 | 173 | ||
174 | fscache_op_complete(op, true); | ||
165 | _leave(""); | 175 | _leave(""); |
166 | } | 176 | } |
167 | 177 | ||
@@ -223,6 +233,8 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) | |||
223 | 233 | ||
224 | _enter("{OP%x}", op->op.debug_id); | 234 | _enter("{OP%x}", op->op.debug_id); |
225 | 235 | ||
236 | ASSERTCMP(op->n_pages, ==, 0); | ||
237 | |||
226 | fscache_hist(fscache_retrieval_histogram, op->start_time); | 238 | fscache_hist(fscache_retrieval_histogram, op->start_time); |
227 | if (op->context) | 239 | if (op->context) |
228 | fscache_put_context(op->op.object->cookie, op->context); | 240 | fscache_put_context(op->op.object->cookie, op->context); |
@@ -291,6 +303,17 @@ static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) | |||
291 | } | 303 | } |
292 | 304 | ||
293 | /* | 305 | /* |
306 | * Handle cancellation of a pending retrieval op | ||
307 | */ | ||
308 | static void fscache_do_cancel_retrieval(struct fscache_operation *_op) | ||
309 | { | ||
310 | struct fscache_retrieval *op = | ||
311 | container_of(_op, struct fscache_retrieval, op); | ||
312 | |||
313 | op->n_pages = 0; | ||
314 | } | ||
315 | |||
316 | /* | ||
294 | * wait for an object to become active (or dead) | 317 | * wait for an object to become active (or dead) |
295 | */ | 318 | */ |
296 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | 319 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, |
@@ -307,8 +330,8 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | |||
307 | fscache_stat(stat_op_waits); | 330 | fscache_stat(stat_op_waits); |
308 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 331 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, |
309 | fscache_wait_bit_interruptible, | 332 | fscache_wait_bit_interruptible, |
310 | TASK_INTERRUPTIBLE) < 0) { | 333 | TASK_INTERRUPTIBLE) != 0) { |
311 | ret = fscache_cancel_op(&op->op); | 334 | ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); |
312 | if (ret == 0) | 335 | if (ret == 0) |
313 | return -ERESTARTSYS; | 336 | return -ERESTARTSYS; |
314 | 337 | ||
@@ -320,7 +343,14 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | |||
320 | _debug("<<< GO"); | 343 | _debug("<<< GO"); |
321 | 344 | ||
322 | check_if_dead: | 345 | check_if_dead: |
346 | if (op->op.state == FSCACHE_OP_ST_CANCELLED) { | ||
347 | fscache_stat(stat_object_dead); | ||
348 | _leave(" = -ENOBUFS [cancelled]"); | ||
349 | return -ENOBUFS; | ||
350 | } | ||
323 | if (unlikely(fscache_object_is_dead(object))) { | 351 | if (unlikely(fscache_object_is_dead(object))) { |
352 | pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state); | ||
353 | fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); | ||
324 | fscache_stat(stat_object_dead); | 354 | fscache_stat(stat_object_dead); |
325 | return -ENOBUFS; | 355 | return -ENOBUFS; |
326 | } | 356 | } |
@@ -353,6 +383,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
353 | if (hlist_empty(&cookie->backing_objects)) | 383 | if (hlist_empty(&cookie->backing_objects)) |
354 | goto nobufs; | 384 | goto nobufs; |
355 | 385 | ||
386 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
387 | _leave(" = -ENOBUFS [invalidating]"); | ||
388 | return -ENOBUFS; | ||
389 | } | ||
390 | |||
356 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 391 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
357 | ASSERTCMP(page, !=, NULL); | 392 | ASSERTCMP(page, !=, NULL); |
358 | 393 | ||
@@ -364,6 +399,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
364 | _leave(" = -ENOMEM"); | 399 | _leave(" = -ENOMEM"); |
365 | return -ENOMEM; | 400 | return -ENOMEM; |
366 | } | 401 | } |
402 | op->n_pages = 1; | ||
367 | 403 | ||
368 | spin_lock(&cookie->lock); | 404 | spin_lock(&cookie->lock); |
369 | 405 | ||
@@ -375,10 +411,10 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
375 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); | 411 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); |
376 | 412 | ||
377 | atomic_inc(&object->n_reads); | 413 | atomic_inc(&object->n_reads); |
378 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 414 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
379 | 415 | ||
380 | if (fscache_submit_op(object, &op->op) < 0) | 416 | if (fscache_submit_op(object, &op->op) < 0) |
381 | goto nobufs_unlock; | 417 | goto nobufs_unlock_dec; |
382 | spin_unlock(&cookie->lock); | 418 | spin_unlock(&cookie->lock); |
383 | 419 | ||
384 | fscache_stat(&fscache_n_retrieval_ops); | 420 | fscache_stat(&fscache_n_retrieval_ops); |
@@ -425,6 +461,8 @@ error: | |||
425 | _leave(" = %d", ret); | 461 | _leave(" = %d", ret); |
426 | return ret; | 462 | return ret; |
427 | 463 | ||
464 | nobufs_unlock_dec: | ||
465 | atomic_dec(&object->n_reads); | ||
428 | nobufs_unlock: | 466 | nobufs_unlock: |
429 | spin_unlock(&cookie->lock); | 467 | spin_unlock(&cookie->lock); |
430 | kfree(op); | 468 | kfree(op); |
@@ -472,6 +510,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
472 | if (hlist_empty(&cookie->backing_objects)) | 510 | if (hlist_empty(&cookie->backing_objects)) |
473 | goto nobufs; | 511 | goto nobufs; |
474 | 512 | ||
513 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
514 | _leave(" = -ENOBUFS [invalidating]"); | ||
515 | return -ENOBUFS; | ||
516 | } | ||
517 | |||
475 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 518 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
476 | ASSERTCMP(*nr_pages, >, 0); | 519 | ASSERTCMP(*nr_pages, >, 0); |
477 | ASSERT(!list_empty(pages)); | 520 | ASSERT(!list_empty(pages)); |
@@ -482,6 +525,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
482 | op = fscache_alloc_retrieval(mapping, end_io_func, context); | 525 | op = fscache_alloc_retrieval(mapping, end_io_func, context); |
483 | if (!op) | 526 | if (!op) |
484 | return -ENOMEM; | 527 | return -ENOMEM; |
528 | op->n_pages = *nr_pages; | ||
485 | 529 | ||
486 | spin_lock(&cookie->lock); | 530 | spin_lock(&cookie->lock); |
487 | 531 | ||
@@ -491,10 +535,10 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
491 | struct fscache_object, cookie_link); | 535 | struct fscache_object, cookie_link); |
492 | 536 | ||
493 | atomic_inc(&object->n_reads); | 537 | atomic_inc(&object->n_reads); |
494 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 538 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
495 | 539 | ||
496 | if (fscache_submit_op(object, &op->op) < 0) | 540 | if (fscache_submit_op(object, &op->op) < 0) |
497 | goto nobufs_unlock; | 541 | goto nobufs_unlock_dec; |
498 | spin_unlock(&cookie->lock); | 542 | spin_unlock(&cookie->lock); |
499 | 543 | ||
500 | fscache_stat(&fscache_n_retrieval_ops); | 544 | fscache_stat(&fscache_n_retrieval_ops); |
@@ -541,6 +585,8 @@ error: | |||
541 | _leave(" = %d", ret); | 585 | _leave(" = %d", ret); |
542 | return ret; | 586 | return ret; |
543 | 587 | ||
588 | nobufs_unlock_dec: | ||
589 | atomic_dec(&object->n_reads); | ||
544 | nobufs_unlock: | 590 | nobufs_unlock: |
545 | spin_unlock(&cookie->lock); | 591 | spin_unlock(&cookie->lock); |
546 | kfree(op); | 592 | kfree(op); |
@@ -577,12 +623,18 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
577 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 623 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
578 | ASSERTCMP(page, !=, NULL); | 624 | ASSERTCMP(page, !=, NULL); |
579 | 625 | ||
626 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
627 | _leave(" = -ENOBUFS [invalidating]"); | ||
628 | return -ENOBUFS; | ||
629 | } | ||
630 | |||
580 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | 631 | if (fscache_wait_for_deferred_lookup(cookie) < 0) |
581 | return -ERESTARTSYS; | 632 | return -ERESTARTSYS; |
582 | 633 | ||
583 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); | 634 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); |
584 | if (!op) | 635 | if (!op) |
585 | return -ENOMEM; | 636 | return -ENOMEM; |
637 | op->n_pages = 1; | ||
586 | 638 | ||
587 | spin_lock(&cookie->lock); | 639 | spin_lock(&cookie->lock); |
588 | 640 | ||
@@ -658,9 +710,27 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
658 | spin_lock(&object->lock); | 710 | spin_lock(&object->lock); |
659 | cookie = object->cookie; | 711 | cookie = object->cookie; |
660 | 712 | ||
661 | if (!fscache_object_is_active(object) || !cookie) { | 713 | if (!fscache_object_is_active(object)) { |
714 | /* If we get here, then the on-disk cache object likely longer | ||
715 | * exists, so we should just cancel this write operation. | ||
716 | */ | ||
717 | spin_unlock(&object->lock); | ||
718 | fscache_op_complete(&op->op, false); | ||
719 | _leave(" [inactive]"); | ||
720 | return; | ||
721 | } | ||
722 | |||
723 | if (!cookie) { | ||
724 | /* If we get here, then the cookie belonging to the object was | ||
725 | * detached, probably by the cookie being withdrawn due to | ||
726 | * memory pressure, which means that the pages we might write | ||
727 | * to the cache from no longer exist - therefore, we can just | ||
728 | * cancel this write operation. | ||
729 | */ | ||
662 | spin_unlock(&object->lock); | 730 | spin_unlock(&object->lock); |
663 | _leave(""); | 731 | fscache_op_complete(&op->op, false); |
732 | _leave(" [cancel] op{f=%lx s=%u} obj{s=%u f=%lx}", | ||
733 | _op->flags, _op->state, object->state, object->flags); | ||
664 | return; | 734 | return; |
665 | } | 735 | } |
666 | 736 | ||
@@ -696,6 +766,7 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
696 | fscache_end_page_write(object, page); | 766 | fscache_end_page_write(object, page); |
697 | if (ret < 0) { | 767 | if (ret < 0) { |
698 | fscache_abort_object(object); | 768 | fscache_abort_object(object); |
769 | fscache_op_complete(&op->op, true); | ||
699 | } else { | 770 | } else { |
700 | fscache_enqueue_operation(&op->op); | 771 | fscache_enqueue_operation(&op->op); |
701 | } | 772 | } |
@@ -710,6 +781,38 @@ superseded: | |||
710 | spin_unlock(&cookie->stores_lock); | 781 | spin_unlock(&cookie->stores_lock); |
711 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 782 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
712 | spin_unlock(&object->lock); | 783 | spin_unlock(&object->lock); |
784 | fscache_op_complete(&op->op, true); | ||
785 | _leave(""); | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * Clear the pages pending writing for invalidation | ||
790 | */ | ||
791 | void fscache_invalidate_writes(struct fscache_cookie *cookie) | ||
792 | { | ||
793 | struct page *page; | ||
794 | void *results[16]; | ||
795 | int n, i; | ||
796 | |||
797 | _enter(""); | ||
798 | |||
799 | while (spin_lock(&cookie->stores_lock), | ||
800 | n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, | ||
801 | ARRAY_SIZE(results), | ||
802 | FSCACHE_COOKIE_PENDING_TAG), | ||
803 | n > 0) { | ||
804 | for (i = n - 1; i >= 0; i--) { | ||
805 | page = results[i]; | ||
806 | radix_tree_delete(&cookie->stores, page->index); | ||
807 | } | ||
808 | |||
809 | spin_unlock(&cookie->stores_lock); | ||
810 | |||
811 | for (i = n - 1; i >= 0; i--) | ||
812 | page_cache_release(results[i]); | ||
813 | } | ||
814 | |||
815 | spin_unlock(&cookie->stores_lock); | ||
713 | _leave(""); | 816 | _leave(""); |
714 | } | 817 | } |
715 | 818 | ||
@@ -759,7 +862,12 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
759 | 862 | ||
760 | fscache_stat(&fscache_n_stores); | 863 | fscache_stat(&fscache_n_stores); |
761 | 864 | ||
762 | op = kzalloc(sizeof(*op), GFP_NOIO); | 865 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { |
866 | _leave(" = -ENOBUFS [invalidating]"); | ||
867 | return -ENOBUFS; | ||
868 | } | ||
869 | |||
870 | op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY); | ||
763 | if (!op) | 871 | if (!op) |
764 | goto nomem; | 872 | goto nomem; |
765 | 873 | ||
@@ -915,6 +1023,40 @@ done: | |||
915 | EXPORT_SYMBOL(__fscache_uncache_page); | 1023 | EXPORT_SYMBOL(__fscache_uncache_page); |
916 | 1024 | ||
917 | /** | 1025 | /** |
1026 | * fscache_mark_page_cached - Mark a page as being cached | ||
1027 | * @op: The retrieval op pages are being marked for | ||
1028 | * @page: The page to be marked | ||
1029 | * | ||
1030 | * Mark a netfs page as being cached. After this is called, the netfs | ||
1031 | * must call fscache_uncache_page() to remove the mark. | ||
1032 | */ | ||
1033 | void fscache_mark_page_cached(struct fscache_retrieval *op, struct page *page) | ||
1034 | { | ||
1035 | struct fscache_cookie *cookie = op->op.object->cookie; | ||
1036 | |||
1037 | #ifdef CONFIG_FSCACHE_STATS | ||
1038 | atomic_inc(&fscache_n_marks); | ||
1039 | #endif | ||
1040 | |||
1041 | _debug("- mark %p{%lx}", page, page->index); | ||
1042 | if (TestSetPageFsCache(page)) { | ||
1043 | static bool once_only; | ||
1044 | if (!once_only) { | ||
1045 | once_only = true; | ||
1046 | printk(KERN_WARNING "FS-Cache:" | ||
1047 | " Cookie type %s marked page %lx" | ||
1048 | " multiple times\n", | ||
1049 | cookie->def->name, page->index); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | if (cookie->def->mark_page_cached) | ||
1054 | cookie->def->mark_page_cached(cookie->netfs_data, | ||
1055 | op->mapping, page); | ||
1056 | } | ||
1057 | EXPORT_SYMBOL(fscache_mark_page_cached); | ||
1058 | |||
1059 | /** | ||
918 | * fscache_mark_pages_cached - Mark pages as being cached | 1060 | * fscache_mark_pages_cached - Mark pages as being cached |
919 | * @op: The retrieval op pages are being marked for | 1061 | * @op: The retrieval op pages are being marked for |
920 | * @pagevec: The pages to be marked | 1062 | * @pagevec: The pages to be marked |
@@ -925,32 +1067,11 @@ EXPORT_SYMBOL(__fscache_uncache_page); | |||
925 | void fscache_mark_pages_cached(struct fscache_retrieval *op, | 1067 | void fscache_mark_pages_cached(struct fscache_retrieval *op, |
926 | struct pagevec *pagevec) | 1068 | struct pagevec *pagevec) |
927 | { | 1069 | { |
928 | struct fscache_cookie *cookie = op->op.object->cookie; | ||
929 | unsigned long loop; | 1070 | unsigned long loop; |
930 | 1071 | ||
931 | #ifdef CONFIG_FSCACHE_STATS | 1072 | for (loop = 0; loop < pagevec->nr; loop++) |
932 | atomic_add(pagevec->nr, &fscache_n_marks); | 1073 | fscache_mark_page_cached(op, pagevec->pages[loop]); |
933 | #endif | ||
934 | |||
935 | for (loop = 0; loop < pagevec->nr; loop++) { | ||
936 | struct page *page = pagevec->pages[loop]; | ||
937 | |||
938 | _debug("- mark %p{%lx}", page, page->index); | ||
939 | if (TestSetPageFsCache(page)) { | ||
940 | static bool once_only; | ||
941 | if (!once_only) { | ||
942 | once_only = true; | ||
943 | printk(KERN_WARNING "FS-Cache:" | ||
944 | " Cookie type %s marked page %lx" | ||
945 | " multiple times\n", | ||
946 | cookie->def->name, page->index); | ||
947 | } | ||
948 | } | ||
949 | } | ||
950 | 1074 | ||
951 | if (cookie->def->mark_pages_cached) | ||
952 | cookie->def->mark_pages_cached(cookie->netfs_data, | ||
953 | op->mapping, pagevec); | ||
954 | pagevec_reinit(pagevec); | 1075 | pagevec_reinit(pagevec); |
955 | } | 1076 | } |
956 | EXPORT_SYMBOL(fscache_mark_pages_cached); | 1077 | EXPORT_SYMBOL(fscache_mark_pages_cached); |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 4765190d537f..8179e8bc4a3d 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -69,6 +69,7 @@ atomic_t fscache_n_store_vmscan_not_storing; | |||
69 | atomic_t fscache_n_store_vmscan_gone; | 69 | atomic_t fscache_n_store_vmscan_gone; |
70 | atomic_t fscache_n_store_vmscan_busy; | 70 | atomic_t fscache_n_store_vmscan_busy; |
71 | atomic_t fscache_n_store_vmscan_cancelled; | 71 | atomic_t fscache_n_store_vmscan_cancelled; |
72 | atomic_t fscache_n_store_vmscan_wait; | ||
72 | 73 | ||
73 | atomic_t fscache_n_marks; | 74 | atomic_t fscache_n_marks; |
74 | atomic_t fscache_n_uncaches; | 75 | atomic_t fscache_n_uncaches; |
@@ -80,6 +81,9 @@ atomic_t fscache_n_acquires_ok; | |||
80 | atomic_t fscache_n_acquires_nobufs; | 81 | atomic_t fscache_n_acquires_nobufs; |
81 | atomic_t fscache_n_acquires_oom; | 82 | atomic_t fscache_n_acquires_oom; |
82 | 83 | ||
84 | atomic_t fscache_n_invalidates; | ||
85 | atomic_t fscache_n_invalidates_run; | ||
86 | |||
83 | atomic_t fscache_n_updates; | 87 | atomic_t fscache_n_updates; |
84 | atomic_t fscache_n_updates_null; | 88 | atomic_t fscache_n_updates_null; |
85 | atomic_t fscache_n_updates_run; | 89 | atomic_t fscache_n_updates_run; |
@@ -112,6 +116,7 @@ atomic_t fscache_n_cop_alloc_object; | |||
112 | atomic_t fscache_n_cop_lookup_object; | 116 | atomic_t fscache_n_cop_lookup_object; |
113 | atomic_t fscache_n_cop_lookup_complete; | 117 | atomic_t fscache_n_cop_lookup_complete; |
114 | atomic_t fscache_n_cop_grab_object; | 118 | atomic_t fscache_n_cop_grab_object; |
119 | atomic_t fscache_n_cop_invalidate_object; | ||
115 | atomic_t fscache_n_cop_update_object; | 120 | atomic_t fscache_n_cop_update_object; |
116 | atomic_t fscache_n_cop_drop_object; | 121 | atomic_t fscache_n_cop_drop_object; |
117 | atomic_t fscache_n_cop_put_object; | 122 | atomic_t fscache_n_cop_put_object; |
@@ -168,6 +173,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
168 | atomic_read(&fscache_n_object_created), | 173 | atomic_read(&fscache_n_object_created), |
169 | atomic_read(&fscache_n_object_lookups_timed_out)); | 174 | atomic_read(&fscache_n_object_lookups_timed_out)); |
170 | 175 | ||
176 | seq_printf(m, "Invals : n=%u run=%u\n", | ||
177 | atomic_read(&fscache_n_invalidates), | ||
178 | atomic_read(&fscache_n_invalidates_run)); | ||
179 | |||
171 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", | 180 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", |
172 | atomic_read(&fscache_n_updates), | 181 | atomic_read(&fscache_n_updates), |
173 | atomic_read(&fscache_n_updates_null), | 182 | atomic_read(&fscache_n_updates_null), |
@@ -224,11 +233,12 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
224 | atomic_read(&fscache_n_store_radix_deletes), | 233 | atomic_read(&fscache_n_store_radix_deletes), |
225 | atomic_read(&fscache_n_store_pages_over_limit)); | 234 | atomic_read(&fscache_n_store_pages_over_limit)); |
226 | 235 | ||
227 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n", | 236 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u wt=%u\n", |
228 | atomic_read(&fscache_n_store_vmscan_not_storing), | 237 | atomic_read(&fscache_n_store_vmscan_not_storing), |
229 | atomic_read(&fscache_n_store_vmscan_gone), | 238 | atomic_read(&fscache_n_store_vmscan_gone), |
230 | atomic_read(&fscache_n_store_vmscan_busy), | 239 | atomic_read(&fscache_n_store_vmscan_busy), |
231 | atomic_read(&fscache_n_store_vmscan_cancelled)); | 240 | atomic_read(&fscache_n_store_vmscan_cancelled), |
241 | atomic_read(&fscache_n_store_vmscan_wait)); | ||
232 | 242 | ||
233 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", | 243 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", |
234 | atomic_read(&fscache_n_op_pend), | 244 | atomic_read(&fscache_n_op_pend), |
@@ -246,7 +256,8 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
246 | atomic_read(&fscache_n_cop_lookup_object), | 256 | atomic_read(&fscache_n_cop_lookup_object), |
247 | atomic_read(&fscache_n_cop_lookup_complete), | 257 | atomic_read(&fscache_n_cop_lookup_complete), |
248 | atomic_read(&fscache_n_cop_grab_object)); | 258 | atomic_read(&fscache_n_cop_grab_object)); |
249 | seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n", | 259 | seq_printf(m, "CacheOp: inv=%d upo=%d dro=%d pto=%d atc=%d syn=%d\n", |
260 | atomic_read(&fscache_n_cop_invalidate_object), | ||
250 | atomic_read(&fscache_n_cop_update_object), | 261 | atomic_read(&fscache_n_cop_update_object), |
251 | atomic_read(&fscache_n_cop_drop_object), | 262 | atomic_read(&fscache_n_cop_drop_object), |
252 | atomic_read(&fscache_n_cop_put_object), | 263 | atomic_read(&fscache_n_cop_put_object), |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index c817787fbdb4..24d1d1c5fcaf 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -307,6 +307,7 @@ void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | |||
307 | nfs_fscache_inode_unlock(inode); | 307 | nfs_fscache_inode_unlock(inode); |
308 | } | 308 | } |
309 | } | 309 | } |
310 | EXPORT_SYMBOL_GPL(nfs_fscache_set_inode_cookie); | ||
310 | 311 | ||
311 | /* | 312 | /* |
312 | * Replace a per-inode cookie due to revalidation detecting a file having | 313 | * Replace a per-inode cookie due to revalidation detecting a file having |
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h index c5b11b53ff33..277b02782897 100644 --- a/fs/nfs/fscache.h +++ b/fs/nfs/fscache.h | |||
@@ -153,6 +153,22 @@ static inline void nfs_readpage_to_fscache(struct inode *inode, | |||
153 | } | 153 | } |
154 | 154 | ||
155 | /* | 155 | /* |
156 | * Invalidate the contents of fscache for this inode. This will not sleep. | ||
157 | */ | ||
158 | static inline void nfs_fscache_invalidate(struct inode *inode) | ||
159 | { | ||
160 | fscache_invalidate(NFS_I(inode)->fscache); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Wait for an object to finish being invalidated. | ||
165 | */ | ||
166 | static inline void nfs_fscache_wait_on_invalidate(struct inode *inode) | ||
167 | { | ||
168 | fscache_wait_on_invalidate(NFS_I(inode)->fscache); | ||
169 | } | ||
170 | |||
171 | /* | ||
156 | * indicate the client caching state as readable text | 172 | * indicate the client caching state as readable text |
157 | */ | 173 | */ |
158 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) | 174 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
@@ -162,7 +178,6 @@ static inline const char *nfs_server_fscache_state(struct nfs_server *server) | |||
162 | return "no "; | 178 | return "no "; |
163 | } | 179 | } |
164 | 180 | ||
165 | |||
166 | #else /* CONFIG_NFS_FSCACHE */ | 181 | #else /* CONFIG_NFS_FSCACHE */ |
167 | static inline int nfs_fscache_register(void) { return 0; } | 182 | static inline int nfs_fscache_register(void) { return 0; } |
168 | static inline void nfs_fscache_unregister(void) {} | 183 | static inline void nfs_fscache_unregister(void) {} |
@@ -205,6 +220,9 @@ static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx, | |||
205 | static inline void nfs_readpage_to_fscache(struct inode *inode, | 220 | static inline void nfs_readpage_to_fscache(struct inode *inode, |
206 | struct page *page, int sync) {} | 221 | struct page *page, int sync) {} |
207 | 222 | ||
223 | |||
224 | static inline void nfs_fscache_invalidate(struct inode *inode) {} | ||
225 | |||
208 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) | 226 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
209 | { | 227 | { |
210 | return "no "; | 228 | return "no "; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2faae14d89f4..ebeb94ce1b0b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -161,10 +161,12 @@ static void nfs_zap_caches_locked(struct inode *inode) | |||
161 | nfsi->attrtimeo_timestamp = jiffies; | 161 | nfsi->attrtimeo_timestamp = jiffies; |
162 | 162 | ||
163 | memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); | 163 | memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); |
164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) | 164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { |
165 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | 165 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
166 | else | 166 | nfs_fscache_invalidate(inode); |
167 | } else { | ||
167 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | 168 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
169 | } | ||
168 | } | 170 | } |
169 | 171 | ||
170 | void nfs_zap_caches(struct inode *inode) | 172 | void nfs_zap_caches(struct inode *inode) |
@@ -179,6 +181,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) | |||
179 | if (mapping->nrpages != 0) { | 181 | if (mapping->nrpages != 0) { |
180 | spin_lock(&inode->i_lock); | 182 | spin_lock(&inode->i_lock); |
181 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; | 183 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; |
184 | nfs_fscache_invalidate(inode); | ||
182 | spin_unlock(&inode->i_lock); | 185 | spin_unlock(&inode->i_lock); |
183 | } | 186 | } |
184 | } | 187 | } |
@@ -881,7 +884,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map | |||
881 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 884 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
882 | spin_unlock(&inode->i_lock); | 885 | spin_unlock(&inode->i_lock); |
883 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | 886 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); |
884 | nfs_fscache_reset_inode_cookie(inode); | 887 | nfs_fscache_wait_on_invalidate(inode); |
885 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | 888 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", |
886 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); | 889 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); |
887 | return 0; | 890 | return 0; |
@@ -957,6 +960,10 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr | |||
957 | i_size_write(inode, nfs_size_to_loff_t(fattr->size)); | 960 | i_size_write(inode, nfs_size_to_loff_t(fattr->size)); |
958 | ret |= NFS_INO_INVALID_ATTR; | 961 | ret |= NFS_INO_INVALID_ATTR; |
959 | } | 962 | } |
963 | |||
964 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
965 | nfs_fscache_invalidate(inode); | ||
966 | |||
960 | return ret; | 967 | return ret; |
961 | } | 968 | } |
962 | 969 | ||
@@ -1205,8 +1212,10 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr | |||
1205 | struct nfs_inode *nfsi = NFS_I(inode); | 1212 | struct nfs_inode *nfsi = NFS_I(inode); |
1206 | 1213 | ||
1207 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; | 1214 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; |
1208 | if (S_ISDIR(inode->i_mode)) | 1215 | if (S_ISDIR(inode->i_mode)) { |
1209 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 1216 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
1217 | nfs_fscache_invalidate(inode); | ||
1218 | } | ||
1210 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1219 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
1211 | return 0; | 1220 | return 0; |
1212 | return nfs_refresh_inode_locked(inode, fattr); | 1221 | return nfs_refresh_inode_locked(inode, fattr); |
@@ -1494,6 +1503,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1494 | (save_cache_validity & NFS_INO_REVAL_FORCED)) | 1503 | (save_cache_validity & NFS_INO_REVAL_FORCED)) |
1495 | nfsi->cache_validity |= invalid; | 1504 | nfsi->cache_validity |= invalid; |
1496 | 1505 | ||
1506 | if (invalid & NFS_INO_INVALID_DATA) | ||
1507 | nfs_fscache_invalidate(inode); | ||
1508 | |||
1497 | return 0; | 1509 | return 0; |
1498 | out_err: | 1510 | out_err: |
1499 | /* | 1511 | /* |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index e7699308364a..08ddcccb8887 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | #include <linux/nfs_fs.h> | 6 | #include <linux/nfs_fs.h> |
7 | #include "internal.h" | 7 | #include "internal.h" |
8 | #include "fscache.h" | ||
8 | #include "pnfs.h" | 9 | #include "pnfs.h" |
9 | 10 | ||
10 | #define NFSDBG_FACILITY NFSDBG_FILE | 11 | #define NFSDBG_FACILITY NFSDBG_FILE |
@@ -74,6 +75,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) | |||
74 | 75 | ||
75 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 76 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
76 | nfs_file_set_open_context(filp, ctx); | 77 | nfs_file_set_open_context(filp, ctx); |
78 | nfs_fscache_set_inode_cookie(inode, filp); | ||
77 | err = 0; | 79 | err = 0; |
78 | 80 | ||
79 | out_put_ctx: | 81 | out_put_ctx: |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 493f0f41c554..5d864fb36578 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -64,7 +64,7 @@ | |||
64 | #include "pnfs.h" | 64 | #include "pnfs.h" |
65 | #include "netns.h" | 65 | #include "netns.h" |
66 | #include "nfs4session.h" | 66 | #include "nfs4session.h" |
67 | 67 | #include "fscache.h" | |
68 | 68 | ||
69 | #define NFSDBG_FACILITY NFSDBG_PROC | 69 | #define NFSDBG_FACILITY NFSDBG_PROC |
70 | 70 | ||
@@ -734,6 +734,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
734 | if (!cinfo->atomic || cinfo->before != dir->i_version) | 734 | if (!cinfo->atomic || cinfo->before != dir->i_version) |
735 | nfs_force_lookup_revalidate(dir); | 735 | nfs_force_lookup_revalidate(dir); |
736 | dir->i_version = cinfo->after; | 736 | dir->i_version = cinfo->after; |
737 | nfs_fscache_invalidate(dir); | ||
737 | spin_unlock(&dir->i_lock); | 738 | spin_unlock(&dir->i_lock); |
738 | } | 739 | } |
739 | 740 | ||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5209916e1222..b673be31590e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1794,7 +1794,8 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
1794 | if (PagePrivate(page)) | 1794 | if (PagePrivate(page)) |
1795 | return -EBUSY; | 1795 | return -EBUSY; |
1796 | 1796 | ||
1797 | nfs_fscache_release_page(page, GFP_KERNEL); | 1797 | if (!nfs_fscache_release_page(page, GFP_KERNEL)) |
1798 | return -EBUSY; | ||
1798 | 1799 | ||
1799 | return migrate_page(mapping, newpage, page, mode); | 1800 | return migrate_page(mapping, newpage, page, mode); |
1800 | } | 1801 | } |
@@ -61,33 +61,22 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | |||
61 | return ret; | 61 | return ret; |
62 | } | 62 | } |
63 | 63 | ||
64 | static long do_sys_truncate(const char __user *pathname, loff_t length) | 64 | long vfs_truncate(struct path *path, loff_t length) |
65 | { | 65 | { |
66 | struct path path; | ||
67 | struct inode *inode; | 66 | struct inode *inode; |
68 | int error; | 67 | long error; |
69 | |||
70 | error = -EINVAL; | ||
71 | if (length < 0) /* sorry, but loff_t says... */ | ||
72 | goto out; | ||
73 | 68 | ||
74 | error = user_path(pathname, &path); | 69 | inode = path->dentry->d_inode; |
75 | if (error) | ||
76 | goto out; | ||
77 | inode = path.dentry->d_inode; | ||
78 | 70 | ||
79 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ | 71 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ |
80 | error = -EISDIR; | ||
81 | if (S_ISDIR(inode->i_mode)) | 72 | if (S_ISDIR(inode->i_mode)) |
82 | goto dput_and_out; | 73 | return -EISDIR; |
83 | |||
84 | error = -EINVAL; | ||
85 | if (!S_ISREG(inode->i_mode)) | 74 | if (!S_ISREG(inode->i_mode)) |
86 | goto dput_and_out; | 75 | return -EINVAL; |
87 | 76 | ||
88 | error = mnt_want_write(path.mnt); | 77 | error = mnt_want_write(path->mnt); |
89 | if (error) | 78 | if (error) |
90 | goto dput_and_out; | 79 | goto out; |
91 | 80 | ||
92 | error = inode_permission(inode, MAY_WRITE); | 81 | error = inode_permission(inode, MAY_WRITE); |
93 | if (error) | 82 | if (error) |
@@ -111,19 +100,34 @@ static long do_sys_truncate(const char __user *pathname, loff_t length) | |||
111 | 100 | ||
112 | error = locks_verify_truncate(inode, NULL, length); | 101 | error = locks_verify_truncate(inode, NULL, length); |
113 | if (!error) | 102 | if (!error) |
114 | error = security_path_truncate(&path); | 103 | error = security_path_truncate(path); |
115 | if (!error) | 104 | if (!error) |
116 | error = do_truncate(path.dentry, length, 0, NULL); | 105 | error = do_truncate(path->dentry, length, 0, NULL); |
117 | 106 | ||
118 | put_write_and_out: | 107 | put_write_and_out: |
119 | put_write_access(inode); | 108 | put_write_access(inode); |
120 | mnt_drop_write_and_out: | 109 | mnt_drop_write_and_out: |
121 | mnt_drop_write(path.mnt); | 110 | mnt_drop_write(path->mnt); |
122 | dput_and_out: | ||
123 | path_put(&path); | ||
124 | out: | 111 | out: |
125 | return error; | 112 | return error; |
126 | } | 113 | } |
114 | EXPORT_SYMBOL_GPL(vfs_truncate); | ||
115 | |||
116 | static long do_sys_truncate(const char __user *pathname, loff_t length) | ||
117 | { | ||
118 | struct path path; | ||
119 | int error; | ||
120 | |||
121 | if (length < 0) /* sorry, but loff_t says... */ | ||
122 | return -EINVAL; | ||
123 | |||
124 | error = user_path(pathname, &path); | ||
125 | if (!error) { | ||
126 | error = vfs_truncate(&path, length); | ||
127 | path_put(&path); | ||
128 | } | ||
129 | return error; | ||
130 | } | ||
127 | 131 | ||
128 | SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) | 132 | SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) |
129 | { | 133 | { |