diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/9p/cache.c | 14 | ||||
-rw-r--r-- | fs/afs/file.c | 15 | ||||
-rw-r--r-- | fs/fscache/internal.h | 5 | ||||
-rw-r--r-- | fs/fscache/page.c | 79 | ||||
-rw-r--r-- | fs/fscache/stats.c | 11 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 10 |
6 files changed, 100 insertions, 34 deletions
diff --git a/fs/9p/cache.c b/fs/9p/cache.c index 51c94e26a346..bcc5357a9069 100644 --- a/fs/9p/cache.c +++ b/fs/9p/cache.c | |||
@@ -343,18 +343,7 @@ int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) | |||
343 | 343 | ||
344 | BUG_ON(!vcookie->fscache); | 344 | BUG_ON(!vcookie->fscache); |
345 | 345 | ||
346 | if (PageFsCache(page)) { | 346 | return fscache_maybe_release_page(vnode->cache, page, gfp); |
347 | if (fscache_check_page_write(vcookie->fscache, page)) { | ||
348 | if (!(gfp & __GFP_WAIT)) | ||
349 | return 0; | ||
350 | fscache_wait_on_page_write(vcookie->fscache, page); | ||
351 | } | ||
352 | |||
353 | fscache_uncache_page(vcookie->fscache, page); | ||
354 | ClearPageFsCache(page); | ||
355 | } | ||
356 | |||
357 | return 1; | ||
358 | } | 347 | } |
359 | 348 | ||
360 | void __v9fs_fscache_invalidate_page(struct page *page) | 349 | void __v9fs_fscache_invalidate_page(struct page *page) |
@@ -368,7 +357,6 @@ void __v9fs_fscache_invalidate_page(struct page *page) | |||
368 | fscache_wait_on_page_write(vcookie->fscache, page); | 357 | fscache_wait_on_page_write(vcookie->fscache, page); |
369 | BUG_ON(!PageLocked(page)); | 358 | BUG_ON(!PageLocked(page)); |
370 | fscache_uncache_page(vcookie->fscache, page); | 359 | fscache_uncache_page(vcookie->fscache, page); |
371 | ClearPageFsCache(page); | ||
372 | } | 360 | } |
373 | } | 361 | } |
374 | 362 | ||
diff --git a/fs/afs/file.c b/fs/afs/file.c index 681c2a7b013f..39b301662f22 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -315,7 +315,6 @@ static void afs_invalidatepage(struct page *page, unsigned long offset) | |||
315 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | 315 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
316 | fscache_wait_on_page_write(vnode->cache, page); | 316 | fscache_wait_on_page_write(vnode->cache, page); |
317 | fscache_uncache_page(vnode->cache, page); | 317 | fscache_uncache_page(vnode->cache, page); |
318 | ClearPageFsCache(page); | ||
319 | } | 318 | } |
320 | #endif | 319 | #endif |
321 | 320 | ||
@@ -349,17 +348,9 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) | |||
349 | /* deny if page is being written to the cache and the caller hasn't | 348 | /* deny if page is being written to the cache and the caller hasn't |
350 | * elected to wait */ | 349 | * elected to wait */ |
351 | #ifdef CONFIG_AFS_FSCACHE | 350 | #ifdef CONFIG_AFS_FSCACHE |
352 | if (PageFsCache(page)) { | 351 | if (!fscache_maybe_release_page(vnode->cache, page, gfp_flags)) { |
353 | if (fscache_check_page_write(vnode->cache, page)) { | 352 | _leave(" = F [cache busy]"); |
354 | if (!(gfp_flags & __GFP_WAIT)) { | 353 | return 0; |
355 | _leave(" = F [cache busy]"); | ||
356 | return 0; | ||
357 | } | ||
358 | fscache_wait_on_page_write(vnode->cache, page); | ||
359 | } | ||
360 | |||
361 | fscache_uncache_page(vnode->cache, page); | ||
362 | ClearPageFsCache(page); | ||
363 | } | 354 | } |
364 | #endif | 355 | #endif |
365 | 356 | ||
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index a0769872b19c..e5046519b153 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -180,6 +180,11 @@ extern atomic_t fscache_n_store_pages; | |||
180 | extern atomic_t fscache_n_store_radix_deletes; | 180 | extern atomic_t fscache_n_store_radix_deletes; |
181 | extern atomic_t fscache_n_store_pages_over_limit; | 181 | extern atomic_t fscache_n_store_pages_over_limit; |
182 | 182 | ||
183 | extern atomic_t fscache_n_store_vmscan_not_storing; | ||
184 | extern atomic_t fscache_n_store_vmscan_gone; | ||
185 | extern atomic_t fscache_n_store_vmscan_busy; | ||
186 | extern atomic_t fscache_n_store_vmscan_cancelled; | ||
187 | |||
183 | extern atomic_t fscache_n_marks; | 188 | extern atomic_t fscache_n_marks; |
184 | extern atomic_t fscache_n_uncaches; | 189 | extern atomic_t fscache_n_uncaches; |
185 | 190 | ||
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 022a5da8e130..fc76798bd968 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -43,6 +43,75 @@ void __fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *pa | |||
43 | EXPORT_SYMBOL(__fscache_wait_on_page_write); | 43 | EXPORT_SYMBOL(__fscache_wait_on_page_write); |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * decide whether a page can be released, possibly by cancelling a store to it | ||
47 | * - we're allowed to sleep if __GFP_WAIT is flagged | ||
48 | */ | ||
49 | bool __fscache_maybe_release_page(struct fscache_cookie *cookie, | ||
50 | struct page *page, | ||
51 | gfp_t gfp) | ||
52 | { | ||
53 | struct page *xpage; | ||
54 | void *val; | ||
55 | |||
56 | _enter("%p,%p,%x", cookie, page, gfp); | ||
57 | |||
58 | rcu_read_lock(); | ||
59 | val = radix_tree_lookup(&cookie->stores, page->index); | ||
60 | if (!val) { | ||
61 | rcu_read_unlock(); | ||
62 | fscache_stat(&fscache_n_store_vmscan_not_storing); | ||
63 | __fscache_uncache_page(cookie, page); | ||
64 | return true; | ||
65 | } | ||
66 | |||
67 | /* see if the page is actually undergoing storage - if so we can't get | ||
68 | * rid of it till the cache has finished with it */ | ||
69 | if (radix_tree_tag_get(&cookie->stores, page->index, | ||
70 | FSCACHE_COOKIE_STORING_TAG)) { | ||
71 | rcu_read_unlock(); | ||
72 | goto page_busy; | ||
73 | } | ||
74 | |||
75 | /* the page is pending storage, so we attempt to cancel the store and | ||
76 | * discard the store request so that the page can be reclaimed */ | ||
77 | spin_lock(&cookie->stores_lock); | ||
78 | rcu_read_unlock(); | ||
79 | |||
80 | if (radix_tree_tag_get(&cookie->stores, page->index, | ||
81 | FSCACHE_COOKIE_STORING_TAG)) { | ||
82 | /* the page started to undergo storage whilst we were looking, | ||
83 | * so now we can only wait or return */ | ||
84 | spin_unlock(&cookie->stores_lock); | ||
85 | goto page_busy; | ||
86 | } | ||
87 | |||
88 | xpage = radix_tree_delete(&cookie->stores, page->index); | ||
89 | spin_unlock(&cookie->stores_lock); | ||
90 | |||
91 | if (xpage) { | ||
92 | fscache_stat(&fscache_n_store_vmscan_cancelled); | ||
93 | fscache_stat(&fscache_n_store_radix_deletes); | ||
94 | ASSERTCMP(xpage, ==, page); | ||
95 | } else { | ||
96 | fscache_stat(&fscache_n_store_vmscan_gone); | ||
97 | } | ||
98 | |||
99 | wake_up_bit(&cookie->flags, 0); | ||
100 | if (xpage) | ||
101 | page_cache_release(xpage); | ||
102 | __fscache_uncache_page(cookie, page); | ||
103 | return true; | ||
104 | |||
105 | page_busy: | ||
106 | /* we might want to wait here, but that could deadlock the allocator as | ||
107 | * the slow-work threads writing to the cache may all end up sleeping | ||
108 | * on memory allocation */ | ||
109 | fscache_stat(&fscache_n_store_vmscan_busy); | ||
110 | return false; | ||
111 | } | ||
112 | EXPORT_SYMBOL(__fscache_maybe_release_page); | ||
113 | |||
114 | /* | ||
46 | * note that a page has finished being written to the cache | 115 | * note that a page has finished being written to the cache |
47 | */ | 116 | */ |
48 | static void fscache_end_page_write(struct fscache_object *object, | 117 | static void fscache_end_page_write(struct fscache_object *object, |
@@ -57,6 +126,8 @@ static void fscache_end_page_write(struct fscache_object *object, | |||
57 | /* delete the page from the tree if it is now no longer | 126 | /* delete the page from the tree if it is now no longer |
58 | * pending */ | 127 | * pending */ |
59 | spin_lock(&cookie->stores_lock); | 128 | spin_lock(&cookie->stores_lock); |
129 | radix_tree_tag_clear(&cookie->stores, page->index, | ||
130 | FSCACHE_COOKIE_STORING_TAG); | ||
60 | if (!radix_tree_tag_get(&cookie->stores, page->index, | 131 | if (!radix_tree_tag_get(&cookie->stores, page->index, |
61 | FSCACHE_COOKIE_PENDING_TAG)) { | 132 | FSCACHE_COOKIE_PENDING_TAG)) { |
62 | fscache_stat(&fscache_n_store_radix_deletes); | 133 | fscache_stat(&fscache_n_store_radix_deletes); |
@@ -640,8 +711,12 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
640 | goto superseded; | 711 | goto superseded; |
641 | } | 712 | } |
642 | 713 | ||
643 | radix_tree_tag_clear(&cookie->stores, page->index, | 714 | if (page) { |
644 | FSCACHE_COOKIE_PENDING_TAG); | 715 | radix_tree_tag_set(&cookie->stores, page->index, |
716 | FSCACHE_COOKIE_STORING_TAG); | ||
717 | radix_tree_tag_clear(&cookie->stores, page->index, | ||
718 | FSCACHE_COOKIE_PENDING_TAG); | ||
719 | } | ||
645 | 720 | ||
646 | spin_unlock(&cookie->stores_lock); | 721 | spin_unlock(&cookie->stores_lock); |
647 | spin_unlock(&object->lock); | 722 | spin_unlock(&object->lock); |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 045ba396dbf2..cda69994e06d 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -63,6 +63,11 @@ atomic_t fscache_n_store_pages; | |||
63 | atomic_t fscache_n_store_radix_deletes; | 63 | atomic_t fscache_n_store_radix_deletes; |
64 | atomic_t fscache_n_store_pages_over_limit; | 64 | atomic_t fscache_n_store_pages_over_limit; |
65 | 65 | ||
66 | atomic_t fscache_n_store_vmscan_not_storing; | ||
67 | atomic_t fscache_n_store_vmscan_gone; | ||
68 | atomic_t fscache_n_store_vmscan_busy; | ||
69 | atomic_t fscache_n_store_vmscan_cancelled; | ||
70 | |||
66 | atomic_t fscache_n_marks; | 71 | atomic_t fscache_n_marks; |
67 | atomic_t fscache_n_uncaches; | 72 | atomic_t fscache_n_uncaches; |
68 | 73 | ||
@@ -211,6 +216,12 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
211 | atomic_read(&fscache_n_store_radix_deletes), | 216 | atomic_read(&fscache_n_store_radix_deletes), |
212 | atomic_read(&fscache_n_store_pages_over_limit)); | 217 | atomic_read(&fscache_n_store_pages_over_limit)); |
213 | 218 | ||
219 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n", | ||
220 | atomic_read(&fscache_n_store_vmscan_not_storing), | ||
221 | atomic_read(&fscache_n_store_vmscan_gone), | ||
222 | atomic_read(&fscache_n_store_vmscan_busy), | ||
223 | atomic_read(&fscache_n_store_vmscan_cancelled)); | ||
224 | |||
214 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", | 225 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", |
215 | atomic_read(&fscache_n_op_pend), | 226 | atomic_read(&fscache_n_op_pend), |
216 | atomic_read(&fscache_n_op_run), | 227 | atomic_read(&fscache_n_op_run), |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index 70fad69eb959..fa588006588d 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -359,17 +359,13 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp) | |||
359 | 359 | ||
360 | BUG_ON(!cookie); | 360 | BUG_ON(!cookie); |
361 | 361 | ||
362 | if (fscache_check_page_write(cookie, page)) { | ||
363 | if (!(gfp & __GFP_WAIT)) | ||
364 | return 0; | ||
365 | fscache_wait_on_page_write(cookie, page); | ||
366 | } | ||
367 | |||
368 | if (PageFsCache(page)) { | 362 | if (PageFsCache(page)) { |
369 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | 363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", |
370 | cookie, page, nfsi); | 364 | cookie, page, nfsi); |
371 | 365 | ||
372 | fscache_uncache_page(cookie, page); | 366 | if (!fscache_maybe_release_page(cookie, page, gfp)) |
367 | return 0; | ||
368 | |||
373 | nfs_add_fscache_stats(page->mapping->host, | 369 | nfs_add_fscache_stats(page->mapping->host, |
374 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); | 370 | NFSIOS_FSCACHE_PAGES_UNCACHED, 1); |
375 | } | 371 | } |