diff options
-rw-r--r-- | Documentation/filesystems/Locking | 8 | ||||
-rw-r--r-- | fs/nfs/file.c | 16 | ||||
-rw-r--r-- | include/linux/fs.h | 1 | ||||
-rw-r--r-- | mm/truncate.c | 12 |
4 files changed, 28 insertions, 9 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 790ef6fbe495..28bfea75bcf2 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -171,6 +171,7 @@ prototypes: | |||
171 | int (*releasepage) (struct page *, int); | 171 | int (*releasepage) (struct page *, int); |
172 | int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, | 172 | int (*direct_IO)(int, struct kiocb *, const struct iovec *iov, |
173 | loff_t offset, unsigned long nr_segs); | 173 | loff_t offset, unsigned long nr_segs); |
174 | int (*launder_page) (struct page *); | ||
174 | 175 | ||
175 | locking rules: | 176 | locking rules: |
176 | All except set_page_dirty may block | 177 | All except set_page_dirty may block |
@@ -188,6 +189,7 @@ bmap: yes | |||
188 | invalidatepage: no yes | 189 | invalidatepage: no yes |
189 | releasepage: no yes | 190 | releasepage: no yes |
190 | direct_IO: no | 191 | direct_IO: no |
192 | launder_page: no yes | ||
191 | 193 | ||
192 | ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() | 194 | ->prepare_write(), ->commit_write(), ->sync_page() and ->readpage() |
193 | may be called from the request handler (/dev/loop). | 195 | may be called from the request handler (/dev/loop). |
@@ -281,6 +283,12 @@ buffers from the page in preparation for freeing it. It returns zero to | |||
281 | indicate that the buffers are (or may be) freeable. If ->releasepage is zero, | 283 | indicate that the buffers are (or may be) freeable. If ->releasepage is zero, |
282 | the kernel assumes that the fs has no private interest in the buffers. | 284 | the kernel assumes that the fs has no private interest in the buffers. |
283 | 285 | ||
286 | ->launder_page() may be called prior to releasing a page if | ||
287 | it is still found to be dirty. It returns zero if the page was successfully | ||
288 | cleaned, or an error value if not. Note that in order to prevent the page | ||
289 | getting mapped back in and redirtied, it needs to be kept locked | ||
290 | across the entire operation. | ||
291 | |||
284 | Note: currently almost all instances of address_space methods are | 292 | Note: currently almost all instances of address_space methods are |
285 | using BKL for internal serialization and that's one of the worst sources | 293 | using BKL for internal serialization and that's one of the worst sources |
286 | of contention. Normally they are calling library functions (in fs/buffer.c) | 294 | of contention. Normally they are calling library functions (in fs/buffer.c) |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0dd6be346aa7..fab20d06d936 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -315,14 +315,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) | |||
315 | 315 | ||
316 | static int nfs_release_page(struct page *page, gfp_t gfp) | 316 | static int nfs_release_page(struct page *page, gfp_t gfp) |
317 | { | 317 | { |
318 | /* | 318 | /* If PagePrivate() is set, then the page is not freeable */ |
319 | * Avoid deadlock on nfs_wait_on_request(). | 319 | return 0; |
320 | */ | 320 | } |
321 | if (!(gfp & __GFP_FS)) | 321 | |
322 | return 0; | 322 | static int nfs_launder_page(struct page *page) |
323 | /* Hack... Force nfs_wb_page() to write out the page */ | 323 | { |
324 | SetPageDirty(page); | 324 | return nfs_wb_page(page->mapping->host, page); |
325 | return !nfs_wb_page(page->mapping->host, page); | ||
326 | } | 325 | } |
327 | 326 | ||
328 | const struct address_space_operations nfs_file_aops = { | 327 | const struct address_space_operations nfs_file_aops = { |
@@ -338,6 +337,7 @@ const struct address_space_operations nfs_file_aops = { | |||
338 | #ifdef CONFIG_NFS_DIRECTIO | 337 | #ifdef CONFIG_NFS_DIRECTIO |
339 | .direct_IO = nfs_direct_IO, | 338 | .direct_IO = nfs_direct_IO, |
340 | #endif | 339 | #endif |
340 | .launder_page = nfs_launder_page, | ||
341 | }; | 341 | }; |
342 | 342 | ||
343 | static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | 343 | static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 186da813541e..14a337cc3464 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -426,6 +426,7 @@ struct address_space_operations { | |||
426 | /* migrate the contents of a page to the specified target */ | 426 | /* migrate the contents of a page to the specified target */ |
427 | int (*migratepage) (struct address_space *, | 427 | int (*migratepage) (struct address_space *, |
428 | struct page *, struct page *); | 428 | struct page *, struct page *); |
429 | int (*launder_page) (struct page *); | ||
429 | }; | 430 | }; |
430 | 431 | ||
431 | struct backing_dev_info; | 432 | struct backing_dev_info; |
diff --git a/mm/truncate.c b/mm/truncate.c index ecdfdcc50522..6c79ca4a1ca7 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -341,6 +341,15 @@ failed: | |||
341 | return 0; | 341 | return 0; |
342 | } | 342 | } |
343 | 343 | ||
344 | static int do_launder_page(struct address_space *mapping, struct page *page) | ||
345 | { | ||
346 | if (!PageDirty(page)) | ||
347 | return 0; | ||
348 | if (page->mapping != mapping || mapping->a_ops->launder_page == NULL) | ||
349 | return 0; | ||
350 | return mapping->a_ops->launder_page(page); | ||
351 | } | ||
352 | |||
344 | /** | 353 | /** |
345 | * invalidate_inode_pages2_range - remove range of pages from an address_space | 354 | * invalidate_inode_pages2_range - remove range of pages from an address_space |
346 | * @mapping: the address_space | 355 | * @mapping: the address_space |
@@ -405,7 +414,8 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
405 | PAGE_CACHE_SIZE, 0); | 414 | PAGE_CACHE_SIZE, 0); |
406 | } | 415 | } |
407 | } | 416 | } |
408 | if (!invalidate_complete_page2(mapping, page)) | 417 | ret = do_launder_page(mapping, page); |
418 | if (ret == 0 && !invalidate_complete_page2(mapping, page)) | ||
409 | ret = -EIO; | 419 | ret = -EIO; |
410 | unlock_page(page); | 420 | unlock_page(page); |
411 | } | 421 | } |