diff options
Diffstat (limited to 'fs/libfs.c')
| -rw-r--r-- | fs/libfs.c | 77 |
1 files changed, 39 insertions, 38 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index 6e8d17e1dc4c..9e50bcf55857 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -338,28 +338,14 @@ int simple_readpage(struct file *file, struct page *page) | |||
| 338 | return 0; | 338 | return 0; |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | int simple_prepare_write(struct file *file, struct page *page, | ||
| 342 | unsigned from, unsigned to) | ||
| 343 | { | ||
| 344 | if (!PageUptodate(page)) { | ||
| 345 | if (to - from != PAGE_CACHE_SIZE) | ||
| 346 | zero_user_segments(page, | ||
| 347 | 0, from, | ||
| 348 | to, PAGE_CACHE_SIZE); | ||
| 349 | } | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | int simple_write_begin(struct file *file, struct address_space *mapping, | 341 | int simple_write_begin(struct file *file, struct address_space *mapping, |
| 354 | loff_t pos, unsigned len, unsigned flags, | 342 | loff_t pos, unsigned len, unsigned flags, |
| 355 | struct page **pagep, void **fsdata) | 343 | struct page **pagep, void **fsdata) |
| 356 | { | 344 | { |
| 357 | struct page *page; | 345 | struct page *page; |
| 358 | pgoff_t index; | 346 | pgoff_t index; |
| 359 | unsigned from; | ||
| 360 | 347 | ||
| 361 | index = pos >> PAGE_CACHE_SHIFT; | 348 | index = pos >> PAGE_CACHE_SHIFT; |
| 362 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
| 363 | 349 | ||
| 364 | page = grab_cache_page_write_begin(mapping, index, flags); | 350 | page = grab_cache_page_write_begin(mapping, index, flags); |
| 365 | if (!page) | 351 | if (!page) |
| @@ -367,43 +353,59 @@ int simple_write_begin(struct file *file, struct address_space *mapping, | |||
| 367 | 353 | ||
| 368 | *pagep = page; | 354 | *pagep = page; |
| 369 | 355 | ||
| 370 | return simple_prepare_write(file, page, from, from+len); | 356 | if (!PageUptodate(page) && (len != PAGE_CACHE_SIZE)) { |
| 371 | } | 357 | unsigned from = pos & (PAGE_CACHE_SIZE - 1); |
| 372 | |||
| 373 | static int simple_commit_write(struct file *file, struct page *page, | ||
| 374 | unsigned from, unsigned to) | ||
| 375 | { | ||
| 376 | struct inode *inode = page->mapping->host; | ||
| 377 | loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; | ||
| 378 | 358 | ||
| 379 | if (!PageUptodate(page)) | 359 | zero_user_segments(page, 0, from, from + len, PAGE_CACHE_SIZE); |
| 380 | SetPageUptodate(page); | 360 | } |
| 381 | /* | ||
| 382 | * No need to use i_size_read() here, the i_size | ||
| 383 | * cannot change under us because we hold the i_mutex. | ||
| 384 | */ | ||
| 385 | if (pos > inode->i_size) | ||
| 386 | i_size_write(inode, pos); | ||
| 387 | set_page_dirty(page); | ||
| 388 | return 0; | 361 | return 0; |
| 389 | } | 362 | } |
| 390 | 363 | ||
| 364 | /** | ||
| 365 | * simple_write_end - .write_end helper for non-block-device FSes | ||
| 366 | * @available: See .write_end of address_space_operations | ||
| 367 | * @file: " | ||
| 368 | * @mapping: " | ||
| 369 | * @pos: " | ||
| 370 | * @len: " | ||
| 371 | * @copied: " | ||
| 372 | * @page: " | ||
| 373 | * @fsdata: " | ||
| 374 | * | ||
| 375 | * simple_write_end does the minimum needed for updating a page after writing is | ||
| 376 | * done. It has the same API signature as the .write_end of | ||
| 377 | * address_space_operations vector. So it can just be set onto .write_end for | ||
| 378 | * FSes that don't need any other processing. i_mutex is assumed to be held. | ||
| 379 | * Block based filesystems should use generic_write_end(). | ||
| 380 | * NOTE: Even though i_size might get updated by this function, mark_inode_dirty | ||
| 381 | * is not called, so a filesystem that actually does store data in .write_inode | ||
| 382 | * should extend on what's done here with a call to mark_inode_dirty() in the | ||
| 383 | * case that i_size has changed. | ||
| 384 | */ | ||
| 391 | int simple_write_end(struct file *file, struct address_space *mapping, | 385 | int simple_write_end(struct file *file, struct address_space *mapping, |
| 392 | loff_t pos, unsigned len, unsigned copied, | 386 | loff_t pos, unsigned len, unsigned copied, |
| 393 | struct page *page, void *fsdata) | 387 | struct page *page, void *fsdata) |
| 394 | { | 388 | { |
| 395 | unsigned from = pos & (PAGE_CACHE_SIZE - 1); | 389 | struct inode *inode = page->mapping->host; |
| 390 | loff_t last_pos = pos + copied; | ||
| 396 | 391 | ||
| 397 | /* zero the stale part of the page if we did a short copy */ | 392 | /* zero the stale part of the page if we did a short copy */ |
| 398 | if (copied < len) { | 393 | if (copied < len) { |
| 399 | void *kaddr = kmap_atomic(page, KM_USER0); | 394 | unsigned from = pos & (PAGE_CACHE_SIZE - 1); |
| 400 | memset(kaddr + from + copied, 0, len - copied); | 395 | |
| 401 | flush_dcache_page(page); | 396 | zero_user(page, from + copied, len - copied); |
| 402 | kunmap_atomic(kaddr, KM_USER0); | ||
| 403 | } | 397 | } |
| 404 | 398 | ||
| 405 | simple_commit_write(file, page, from, from+copied); | 399 | if (!PageUptodate(page)) |
| 400 | SetPageUptodate(page); | ||
| 401 | /* | ||
| 402 | * No need to use i_size_read() here, the i_size | ||
| 403 | * cannot change under us because we hold the i_mutex. | ||
| 404 | */ | ||
| 405 | if (last_pos > inode->i_size) | ||
| 406 | i_size_write(inode, last_pos); | ||
| 406 | 407 | ||
| 408 | set_page_dirty(page); | ||
| 407 | unlock_page(page); | 409 | unlock_page(page); |
| 408 | page_cache_release(page); | 410 | page_cache_release(page); |
| 409 | 411 | ||
| @@ -853,7 +855,6 @@ EXPORT_SYMBOL(simple_getattr); | |||
| 853 | EXPORT_SYMBOL(simple_link); | 855 | EXPORT_SYMBOL(simple_link); |
| 854 | EXPORT_SYMBOL(simple_lookup); | 856 | EXPORT_SYMBOL(simple_lookup); |
| 855 | EXPORT_SYMBOL(simple_pin_fs); | 857 | EXPORT_SYMBOL(simple_pin_fs); |
| 856 | EXPORT_UNUSED_SYMBOL(simple_prepare_write); | ||
| 857 | EXPORT_SYMBOL(simple_readpage); | 858 | EXPORT_SYMBOL(simple_readpage); |
| 858 | EXPORT_SYMBOL(simple_release_fs); | 859 | EXPORT_SYMBOL(simple_release_fs); |
| 859 | EXPORT_SYMBOL(simple_rename); | 860 | EXPORT_SYMBOL(simple_rename); |
