diff options
Diffstat (limited to 'fs/fscache/page.c')
-rw-r--r-- | fs/fscache/page.c | 79 |
1 files changed, 77 insertions, 2 deletions
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); |