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 | } |
