diff options
Diffstat (limited to 'fs/afs/file.c')
-rw-r--r-- | fs/afs/file.c | 220 |
1 files changed, 143 insertions, 77 deletions
diff --git a/fs/afs/file.c b/fs/afs/file.c index a3901769a96c..7a1d942ef68d 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -23,6 +23,9 @@ static void afs_invalidatepage(struct page *page, unsigned long offset); | |||
23 | static int afs_releasepage(struct page *page, gfp_t gfp_flags); | 23 | static int afs_releasepage(struct page *page, gfp_t gfp_flags); |
24 | static int afs_launder_page(struct page *page); | 24 | static int afs_launder_page(struct page *page); |
25 | 25 | ||
26 | static int afs_readpages(struct file *filp, struct address_space *mapping, | ||
27 | struct list_head *pages, unsigned nr_pages); | ||
28 | |||
26 | const struct file_operations afs_file_operations = { | 29 | const struct file_operations afs_file_operations = { |
27 | .open = afs_open, | 30 | .open = afs_open, |
28 | .release = afs_release, | 31 | .release = afs_release, |
@@ -46,6 +49,7 @@ const struct inode_operations afs_file_inode_operations = { | |||
46 | 49 | ||
47 | const struct address_space_operations afs_fs_aops = { | 50 | const struct address_space_operations afs_fs_aops = { |
48 | .readpage = afs_readpage, | 51 | .readpage = afs_readpage, |
52 | .readpages = afs_readpages, | ||
49 | .set_page_dirty = afs_set_page_dirty, | 53 | .set_page_dirty = afs_set_page_dirty, |
50 | .launder_page = afs_launder_page, | 54 | .launder_page = afs_launder_page, |
51 | .releasepage = afs_releasepage, | 55 | .releasepage = afs_releasepage, |
@@ -101,37 +105,18 @@ int afs_release(struct inode *inode, struct file *file) | |||
101 | /* | 105 | /* |
102 | * deal with notification that a page was read from the cache | 106 | * deal with notification that a page was read from the cache |
103 | */ | 107 | */ |
104 | #ifdef AFS_CACHING_SUPPORT | 108 | static void afs_file_readpage_read_complete(struct page *page, |
105 | static void afs_readpage_read_complete(void *cookie_data, | 109 | void *data, |
106 | struct page *page, | 110 | int error) |
107 | void *data, | ||
108 | int error) | ||
109 | { | 111 | { |
110 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); | 112 | _enter("%p,%p,%d", page, data, error); |
111 | 113 | ||
112 | if (error) | 114 | /* if the read completes with an error, we just unlock the page and let |
113 | SetPageError(page); | 115 | * the VM reissue the readpage */ |
114 | else | 116 | if (!error) |
115 | SetPageUptodate(page); | 117 | SetPageUptodate(page); |
116 | unlock_page(page); | 118 | unlock_page(page); |
117 | |||
118 | } | 119 | } |
119 | #endif | ||
120 | |||
121 | /* | ||
122 | * deal with notification that a page was written to the cache | ||
123 | */ | ||
124 | #ifdef AFS_CACHING_SUPPORT | ||
125 | static void afs_readpage_write_complete(void *cookie_data, | ||
126 | struct page *page, | ||
127 | void *data, | ||
128 | int error) | ||
129 | { | ||
130 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); | ||
131 | |||
132 | unlock_page(page); | ||
133 | } | ||
134 | #endif | ||
135 | 120 | ||
136 | /* | 121 | /* |
137 | * AFS read page from file, directory or symlink | 122 | * AFS read page from file, directory or symlink |
@@ -161,9 +146,9 @@ static int afs_readpage(struct file *file, struct page *page) | |||
161 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | 146 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
162 | goto error; | 147 | goto error; |
163 | 148 | ||
164 | #ifdef AFS_CACHING_SUPPORT | ||
165 | /* is it cached? */ | 149 | /* is it cached? */ |
166 | ret = cachefs_read_or_alloc_page(vnode->cache, | 150 | #ifdef CONFIG_AFS_FSCACHE |
151 | ret = fscache_read_or_alloc_page(vnode->cache, | ||
167 | page, | 152 | page, |
168 | afs_file_readpage_read_complete, | 153 | afs_file_readpage_read_complete, |
169 | NULL, | 154 | NULL, |
@@ -171,20 +156,21 @@ static int afs_readpage(struct file *file, struct page *page) | |||
171 | #else | 156 | #else |
172 | ret = -ENOBUFS; | 157 | ret = -ENOBUFS; |
173 | #endif | 158 | #endif |
174 | |||
175 | switch (ret) { | 159 | switch (ret) { |
176 | /* read BIO submitted and wb-journal entry found */ | ||
177 | case 1: | ||
178 | BUG(); // TODO - handle wb-journal match | ||
179 | |||
180 | /* read BIO submitted (page in cache) */ | 160 | /* read BIO submitted (page in cache) */ |
181 | case 0: | 161 | case 0: |
182 | break; | 162 | break; |
183 | 163 | ||
184 | /* no page available in cache */ | 164 | /* page not yet cached */ |
185 | case -ENOBUFS: | ||
186 | case -ENODATA: | 165 | case -ENODATA: |
166 | _debug("cache said ENODATA"); | ||
167 | goto go_on; | ||
168 | |||
169 | /* page will not be cached */ | ||
170 | case -ENOBUFS: | ||
171 | _debug("cache said ENOBUFS"); | ||
187 | default: | 172 | default: |
173 | go_on: | ||
188 | offset = page->index << PAGE_CACHE_SHIFT; | 174 | offset = page->index << PAGE_CACHE_SHIFT; |
189 | len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); | 175 | len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE); |
190 | 176 | ||
@@ -198,27 +184,25 @@ static int afs_readpage(struct file *file, struct page *page) | |||
198 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 184 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
199 | ret = -ESTALE; | 185 | ret = -ESTALE; |
200 | } | 186 | } |
201 | #ifdef AFS_CACHING_SUPPORT | 187 | |
202 | cachefs_uncache_page(vnode->cache, page); | 188 | #ifdef CONFIG_AFS_FSCACHE |
189 | fscache_uncache_page(vnode->cache, page); | ||
203 | #endif | 190 | #endif |
191 | BUG_ON(PageFsCache(page)); | ||
204 | goto error; | 192 | goto error; |
205 | } | 193 | } |
206 | 194 | ||
207 | SetPageUptodate(page); | 195 | SetPageUptodate(page); |
208 | 196 | ||
209 | #ifdef AFS_CACHING_SUPPORT | 197 | /* send the page to the cache */ |
210 | if (cachefs_write_page(vnode->cache, | 198 | #ifdef CONFIG_AFS_FSCACHE |
211 | page, | 199 | if (PageFsCache(page) && |
212 | afs_file_readpage_write_complete, | 200 | fscache_write_page(vnode->cache, page, GFP_KERNEL) != 0) { |
213 | NULL, | 201 | fscache_uncache_page(vnode->cache, page); |
214 | GFP_KERNEL) != 0 | 202 | BUG_ON(PageFsCache(page)); |
215 | ) { | ||
216 | cachefs_uncache_page(vnode->cache, page); | ||
217 | unlock_page(page); | ||
218 | } | 203 | } |
219 | #else | ||
220 | unlock_page(page); | ||
221 | #endif | 204 | #endif |
205 | unlock_page(page); | ||
222 | } | 206 | } |
223 | 207 | ||
224 | _leave(" = 0"); | 208 | _leave(" = 0"); |
@@ -232,34 +216,59 @@ error: | |||
232 | } | 216 | } |
233 | 217 | ||
234 | /* | 218 | /* |
235 | * invalidate part or all of a page | 219 | * read a set of pages |
236 | */ | 220 | */ |
237 | static void afs_invalidatepage(struct page *page, unsigned long offset) | 221 | static int afs_readpages(struct file *file, struct address_space *mapping, |
222 | struct list_head *pages, unsigned nr_pages) | ||
238 | { | 223 | { |
239 | int ret = 1; | 224 | struct afs_vnode *vnode; |
225 | int ret = 0; | ||
240 | 226 | ||
241 | _enter("{%lu},%lu", page->index, offset); | 227 | _enter(",{%lu},,%d", mapping->host->i_ino, nr_pages); |
242 | 228 | ||
243 | BUG_ON(!PageLocked(page)); | 229 | vnode = AFS_FS_I(mapping->host); |
230 | if (vnode->flags & AFS_VNODE_DELETED) { | ||
231 | _leave(" = -ESTALE"); | ||
232 | return -ESTALE; | ||
233 | } | ||
244 | 234 | ||
245 | if (PagePrivate(page)) { | 235 | /* attempt to read as many of the pages as possible */ |
246 | /* We release buffers only if the entire page is being | 236 | #ifdef CONFIG_AFS_FSCACHE |
247 | * invalidated. | 237 | ret = fscache_read_or_alloc_pages(vnode->cache, |
248 | * The get_block cached value has been unconditionally | 238 | mapping, |
249 | * invalidated, so real IO is not possible anymore. | 239 | pages, |
250 | */ | 240 | &nr_pages, |
251 | if (offset == 0) { | 241 | afs_file_readpage_read_complete, |
252 | BUG_ON(!PageLocked(page)); | 242 | NULL, |
253 | 243 | mapping_gfp_mask(mapping)); | |
254 | ret = 0; | 244 | #else |
255 | if (!PageWriteback(page)) | 245 | ret = -ENOBUFS; |
256 | ret = page->mapping->a_ops->releasepage(page, | 246 | #endif |
257 | 0); | 247 | |
258 | /* possibly should BUG_ON(!ret); - neilb */ | 248 | switch (ret) { |
259 | } | 249 | /* all pages are being read from the cache */ |
250 | case 0: | ||
251 | BUG_ON(!list_empty(pages)); | ||
252 | BUG_ON(nr_pages != 0); | ||
253 | _leave(" = 0 [reading all]"); | ||
254 | return 0; | ||
255 | |||
256 | /* there were pages that couldn't be read from the cache */ | ||
257 | case -ENODATA: | ||
258 | case -ENOBUFS: | ||
259 | break; | ||
260 | |||
261 | /* other error */ | ||
262 | default: | ||
263 | _leave(" = %d", ret); | ||
264 | return ret; | ||
260 | } | 265 | } |
261 | 266 | ||
262 | _leave(" = %d", ret); | 267 | /* load the missing pages from the network */ |
268 | ret = read_cache_pages(mapping, pages, (void *) afs_readpage, file); | ||
269 | |||
270 | _leave(" = %d [netting]", ret); | ||
271 | return ret; | ||
263 | } | 272 | } |
264 | 273 | ||
265 | /* | 274 | /* |
@@ -273,25 +282,82 @@ static int afs_launder_page(struct page *page) | |||
273 | } | 282 | } |
274 | 283 | ||
275 | /* | 284 | /* |
276 | * release a page and cleanup its private data | 285 | * invalidate part or all of a page |
286 | * - release a page and clean up its private data if offset is 0 (indicating | ||
287 | * the entire page) | ||
288 | */ | ||
289 | static void afs_invalidatepage(struct page *page, unsigned long offset) | ||
290 | { | ||
291 | struct afs_writeback *wb = (struct afs_writeback *) page_private(page); | ||
292 | |||
293 | _enter("{%lu},%lu", page->index, offset); | ||
294 | |||
295 | BUG_ON(!PageLocked(page)); | ||
296 | |||
297 | /* we clean up only if the entire page is being invalidated */ | ||
298 | if (offset == 0) { | ||
299 | #ifdef CONFIG_AFS_FSCACHE | ||
300 | if (PageFsCache(page)) { | ||
301 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | ||
302 | fscache_wait_on_page_write(vnode->cache, page); | ||
303 | fscache_uncache_page(vnode->cache, page); | ||
304 | ClearPageFsCache(page); | ||
305 | } | ||
306 | #endif | ||
307 | |||
308 | if (PagePrivate(page)) { | ||
309 | if (wb && !PageWriteback(page)) { | ||
310 | set_page_private(page, 0); | ||
311 | afs_put_writeback(wb); | ||
312 | } | ||
313 | |||
314 | if (!page_private(page)) | ||
315 | ClearPagePrivate(page); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | _leave(""); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * release a page and clean up its private state if it's not busy | ||
324 | * - return true if the page can now be released, false if not | ||
277 | */ | 325 | */ |
278 | static int afs_releasepage(struct page *page, gfp_t gfp_flags) | 326 | static int afs_releasepage(struct page *page, gfp_t gfp_flags) |
279 | { | 327 | { |
328 | struct afs_writeback *wb = (struct afs_writeback *) page_private(page); | ||
280 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | 329 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
281 | struct afs_writeback *wb; | ||
282 | 330 | ||
283 | _enter("{{%x:%u}[%lu],%lx},%x", | 331 | _enter("{{%x:%u}[%lu],%lx},%x", |
284 | vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, | 332 | vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, |
285 | gfp_flags); | 333 | gfp_flags); |
286 | 334 | ||
335 | /* deny if page is being written to the cache and the caller hasn't | ||
336 | * elected to wait */ | ||
337 | #ifdef CONFIG_AFS_FSCACHE | ||
338 | if (PageFsCache(page)) { | ||
339 | if (fscache_check_page_write(vnode->cache, page)) { | ||
340 | if (!(gfp_flags & __GFP_WAIT)) { | ||
341 | _leave(" = F [cache busy]"); | ||
342 | return 0; | ||
343 | } | ||
344 | fscache_wait_on_page_write(vnode->cache, page); | ||
345 | } | ||
346 | |||
347 | fscache_uncache_page(vnode->cache, page); | ||
348 | ClearPageFsCache(page); | ||
349 | } | ||
350 | #endif | ||
351 | |||
287 | if (PagePrivate(page)) { | 352 | if (PagePrivate(page)) { |
288 | wb = (struct afs_writeback *) page_private(page); | 353 | if (wb) { |
289 | ASSERT(wb != NULL); | 354 | set_page_private(page, 0); |
290 | set_page_private(page, 0); | 355 | afs_put_writeback(wb); |
356 | } | ||
291 | ClearPagePrivate(page); | 357 | ClearPagePrivate(page); |
292 | afs_put_writeback(wb); | ||
293 | } | 358 | } |
294 | 359 | ||
295 | _leave(" = 0"); | 360 | /* indicate that the page can be released */ |
296 | return 0; | 361 | _leave(" = T"); |
362 | return 1; | ||
297 | } | 363 | } |