diff options
Diffstat (limited to 'fs/buffer.c')
| -rw-r--r-- | fs/buffer.c | 180 |
1 files changed, 36 insertions, 144 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index d54812b198e9..50efa339e051 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -1833,9 +1833,10 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) | |||
| 1833 | } | 1833 | } |
| 1834 | EXPORT_SYMBOL(page_zero_new_buffers); | 1834 | EXPORT_SYMBOL(page_zero_new_buffers); |
| 1835 | 1835 | ||
| 1836 | static int __block_prepare_write(struct inode *inode, struct page *page, | 1836 | int block_prepare_write(struct page *page, unsigned from, unsigned to, |
| 1837 | unsigned from, unsigned to, get_block_t *get_block) | 1837 | get_block_t *get_block) |
| 1838 | { | 1838 | { |
| 1839 | struct inode *inode = page->mapping->host; | ||
| 1839 | unsigned block_start, block_end; | 1840 | unsigned block_start, block_end; |
| 1840 | sector_t block; | 1841 | sector_t block; |
| 1841 | int err = 0; | 1842 | int err = 0; |
| @@ -1908,10 +1909,13 @@ static int __block_prepare_write(struct inode *inode, struct page *page, | |||
| 1908 | if (!buffer_uptodate(*wait_bh)) | 1909 | if (!buffer_uptodate(*wait_bh)) |
| 1909 | err = -EIO; | 1910 | err = -EIO; |
| 1910 | } | 1911 | } |
| 1911 | if (unlikely(err)) | 1912 | if (unlikely(err)) { |
| 1912 | page_zero_new_buffers(page, from, to); | 1913 | page_zero_new_buffers(page, from, to); |
| 1914 | ClearPageUptodate(page); | ||
| 1915 | } | ||
| 1913 | return err; | 1916 | return err; |
| 1914 | } | 1917 | } |
| 1918 | EXPORT_SYMBOL(block_prepare_write); | ||
| 1915 | 1919 | ||
| 1916 | static int __block_commit_write(struct inode *inode, struct page *page, | 1920 | static int __block_commit_write(struct inode *inode, struct page *page, |
| 1917 | unsigned from, unsigned to) | 1921 | unsigned from, unsigned to) |
| @@ -1948,90 +1952,41 @@ static int __block_commit_write(struct inode *inode, struct page *page, | |||
| 1948 | return 0; | 1952 | return 0; |
| 1949 | } | 1953 | } |
| 1950 | 1954 | ||
| 1951 | /* | 1955 | int __block_write_begin(struct page *page, loff_t pos, unsigned len, |
| 1952 | * Filesystems implementing the new truncate sequence should use the | 1956 | get_block_t *get_block) |
| 1953 | * _newtrunc postfix variant which won't incorrectly call vmtruncate. | ||
| 1954 | * The filesystem needs to handle block truncation upon failure. | ||
| 1955 | */ | ||
| 1956 | int block_write_begin_newtrunc(struct file *file, struct address_space *mapping, | ||
| 1957 | loff_t pos, unsigned len, unsigned flags, | ||
| 1958 | struct page **pagep, void **fsdata, | ||
| 1959 | get_block_t *get_block) | ||
| 1960 | { | 1957 | { |
| 1961 | struct inode *inode = mapping->host; | 1958 | unsigned start = pos & (PAGE_CACHE_SIZE - 1); |
| 1962 | int status = 0; | ||
| 1963 | struct page *page; | ||
| 1964 | pgoff_t index; | ||
| 1965 | unsigned start, end; | ||
| 1966 | int ownpage = 0; | ||
| 1967 | |||
| 1968 | index = pos >> PAGE_CACHE_SHIFT; | ||
| 1969 | start = pos & (PAGE_CACHE_SIZE - 1); | ||
| 1970 | end = start + len; | ||
| 1971 | |||
| 1972 | page = *pagep; | ||
| 1973 | if (page == NULL) { | ||
| 1974 | ownpage = 1; | ||
| 1975 | page = grab_cache_page_write_begin(mapping, index, flags); | ||
| 1976 | if (!page) { | ||
| 1977 | status = -ENOMEM; | ||
| 1978 | goto out; | ||
| 1979 | } | ||
| 1980 | *pagep = page; | ||
| 1981 | } else | ||
| 1982 | BUG_ON(!PageLocked(page)); | ||
| 1983 | |||
| 1984 | status = __block_prepare_write(inode, page, start, end, get_block); | ||
| 1985 | if (unlikely(status)) { | ||
| 1986 | ClearPageUptodate(page); | ||
| 1987 | 1959 | ||
| 1988 | if (ownpage) { | 1960 | return block_prepare_write(page, start, start + len, get_block); |
| 1989 | unlock_page(page); | ||
| 1990 | page_cache_release(page); | ||
| 1991 | *pagep = NULL; | ||
| 1992 | } | ||
| 1993 | } | ||
| 1994 | |||
| 1995 | out: | ||
| 1996 | return status; | ||
| 1997 | } | 1961 | } |
| 1998 | EXPORT_SYMBOL(block_write_begin_newtrunc); | 1962 | EXPORT_SYMBOL(__block_write_begin); |
| 1999 | 1963 | ||
| 2000 | /* | 1964 | /* |
| 2001 | * block_write_begin takes care of the basic task of block allocation and | 1965 | * block_write_begin takes care of the basic task of block allocation and |
| 2002 | * bringing partial write blocks uptodate first. | 1966 | * bringing partial write blocks uptodate first. |
| 2003 | * | 1967 | * |
| 2004 | * If *pagep is not NULL, then block_write_begin uses the locked page | 1968 | * The filesystem needs to handle block truncation upon failure. |
| 2005 | * at *pagep rather than allocating its own. In this case, the page will | ||
| 2006 | * not be unlocked or deallocated on failure. | ||
| 2007 | */ | 1969 | */ |
| 2008 | int block_write_begin(struct file *file, struct address_space *mapping, | 1970 | int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, |
| 2009 | loff_t pos, unsigned len, unsigned flags, | 1971 | unsigned flags, struct page **pagep, get_block_t *get_block) |
| 2010 | struct page **pagep, void **fsdata, | ||
| 2011 | get_block_t *get_block) | ||
| 2012 | { | 1972 | { |
| 2013 | int ret; | 1973 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
| 1974 | struct page *page; | ||
| 1975 | int status; | ||
| 2014 | 1976 | ||
| 2015 | ret = block_write_begin_newtrunc(file, mapping, pos, len, flags, | 1977 | page = grab_cache_page_write_begin(mapping, index, flags); |
| 2016 | pagep, fsdata, get_block); | 1978 | if (!page) |
| 1979 | return -ENOMEM; | ||
| 2017 | 1980 | ||
| 2018 | /* | 1981 | status = __block_write_begin(page, pos, len, get_block); |
| 2019 | * prepare_write() may have instantiated a few blocks | 1982 | if (unlikely(status)) { |
| 2020 | * outside i_size. Trim these off again. Don't need | 1983 | unlock_page(page); |
| 2021 | * i_size_read because we hold i_mutex. | 1984 | page_cache_release(page); |
| 2022 | * | 1985 | page = NULL; |
| 2023 | * Filesystems which pass down their own page also cannot | ||
| 2024 | * call into vmtruncate here because it would lead to lock | ||
| 2025 | * inversion problems (*pagep is locked). This is a further | ||
| 2026 | * example of where the old truncate sequence is inadequate. | ||
| 2027 | */ | ||
| 2028 | if (unlikely(ret) && *pagep == NULL) { | ||
| 2029 | loff_t isize = mapping->host->i_size; | ||
| 2030 | if (pos + len > isize) | ||
| 2031 | vmtruncate(mapping->host, isize); | ||
| 2032 | } | 1986 | } |
| 2033 | 1987 | ||
| 2034 | return ret; | 1988 | *pagep = page; |
| 1989 | return status; | ||
| 2035 | } | 1990 | } |
| 2036 | EXPORT_SYMBOL(block_write_begin); | 1991 | EXPORT_SYMBOL(block_write_begin); |
| 2037 | 1992 | ||
| @@ -2351,7 +2306,7 @@ out: | |||
| 2351 | * For moronic filesystems that do not allow holes in file. | 2306 | * For moronic filesystems that do not allow holes in file. |
| 2352 | * We may have to extend the file. | 2307 | * We may have to extend the file. |
| 2353 | */ | 2308 | */ |
| 2354 | int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping, | 2309 | int cont_write_begin(struct file *file, struct address_space *mapping, |
| 2355 | loff_t pos, unsigned len, unsigned flags, | 2310 | loff_t pos, unsigned len, unsigned flags, |
| 2356 | struct page **pagep, void **fsdata, | 2311 | struct page **pagep, void **fsdata, |
| 2357 | get_block_t *get_block, loff_t *bytes) | 2312 | get_block_t *get_block, loff_t *bytes) |
| @@ -2363,7 +2318,7 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping, | |||
| 2363 | 2318 | ||
| 2364 | err = cont_expand_zero(file, mapping, pos, bytes); | 2319 | err = cont_expand_zero(file, mapping, pos, bytes); |
| 2365 | if (err) | 2320 | if (err) |
| 2366 | goto out; | 2321 | return err; |
| 2367 | 2322 | ||
| 2368 | zerofrom = *bytes & ~PAGE_CACHE_MASK; | 2323 | zerofrom = *bytes & ~PAGE_CACHE_MASK; |
| 2369 | if (pos+len > *bytes && zerofrom & (blocksize-1)) { | 2324 | if (pos+len > *bytes && zerofrom & (blocksize-1)) { |
| @@ -2371,44 +2326,10 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping, | |||
| 2371 | (*bytes)++; | 2326 | (*bytes)++; |
| 2372 | } | 2327 | } |
| 2373 | 2328 | ||
| 2374 | *pagep = NULL; | 2329 | return block_write_begin(mapping, pos, len, flags, pagep, get_block); |
| 2375 | err = block_write_begin_newtrunc(file, mapping, pos, len, | ||
| 2376 | flags, pagep, fsdata, get_block); | ||
| 2377 | out: | ||
| 2378 | return err; | ||
| 2379 | } | ||
| 2380 | EXPORT_SYMBOL(cont_write_begin_newtrunc); | ||
| 2381 | |||
| 2382 | int cont_write_begin(struct file *file, struct address_space *mapping, | ||
| 2383 | loff_t pos, unsigned len, unsigned flags, | ||
| 2384 | struct page **pagep, void **fsdata, | ||
| 2385 | get_block_t *get_block, loff_t *bytes) | ||
| 2386 | { | ||
| 2387 | int ret; | ||
| 2388 | |||
| 2389 | ret = cont_write_begin_newtrunc(file, mapping, pos, len, flags, | ||
| 2390 | pagep, fsdata, get_block, bytes); | ||
| 2391 | if (unlikely(ret)) { | ||
| 2392 | loff_t isize = mapping->host->i_size; | ||
| 2393 | if (pos + len > isize) | ||
| 2394 | vmtruncate(mapping->host, isize); | ||
| 2395 | } | ||
| 2396 | |||
| 2397 | return ret; | ||
| 2398 | } | 2330 | } |
| 2399 | EXPORT_SYMBOL(cont_write_begin); | 2331 | EXPORT_SYMBOL(cont_write_begin); |
| 2400 | 2332 | ||
| 2401 | int block_prepare_write(struct page *page, unsigned from, unsigned to, | ||
| 2402 | get_block_t *get_block) | ||
| 2403 | { | ||
| 2404 | struct inode *inode = page->mapping->host; | ||
| 2405 | int err = __block_prepare_write(inode, page, from, to, get_block); | ||
| 2406 | if (err) | ||
| 2407 | ClearPageUptodate(page); | ||
| 2408 | return err; | ||
| 2409 | } | ||
| 2410 | EXPORT_SYMBOL(block_prepare_write); | ||
| 2411 | |||
| 2412 | int block_commit_write(struct page *page, unsigned from, unsigned to) | 2333 | int block_commit_write(struct page *page, unsigned from, unsigned to) |
| 2413 | { | 2334 | { |
| 2414 | struct inode *inode = page->mapping->host; | 2335 | struct inode *inode = page->mapping->host; |
| @@ -2510,11 +2431,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head) | |||
| 2510 | } | 2431 | } |
| 2511 | 2432 | ||
| 2512 | /* | 2433 | /* |
| 2513 | * Filesystems implementing the new truncate sequence should use the | 2434 | * On entry, the page is fully not uptodate. |
| 2514 | * _newtrunc postfix variant which won't incorrectly call vmtruncate. | 2435 | * On exit the page is fully uptodate in the areas outside (from,to) |
| 2515 | * The filesystem needs to handle block truncation upon failure. | 2436 | * The filesystem needs to handle block truncation upon failure. |
| 2516 | */ | 2437 | */ |
| 2517 | int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping, | 2438 | int nobh_write_begin(struct address_space *mapping, |
| 2518 | loff_t pos, unsigned len, unsigned flags, | 2439 | loff_t pos, unsigned len, unsigned flags, |
| 2519 | struct page **pagep, void **fsdata, | 2440 | struct page **pagep, void **fsdata, |
| 2520 | get_block_t *get_block) | 2441 | get_block_t *get_block) |
| @@ -2547,8 +2468,8 @@ int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping, | |||
| 2547 | unlock_page(page); | 2468 | unlock_page(page); |
| 2548 | page_cache_release(page); | 2469 | page_cache_release(page); |
| 2549 | *pagep = NULL; | 2470 | *pagep = NULL; |
| 2550 | return block_write_begin_newtrunc(file, mapping, pos, len, | 2471 | return block_write_begin(mapping, pos, len, flags, pagep, |
| 2551 | flags, pagep, fsdata, get_block); | 2472 | get_block); |
| 2552 | } | 2473 | } |
| 2553 | 2474 | ||
| 2554 | if (PageMappedToDisk(page)) | 2475 | if (PageMappedToDisk(page)) |
| @@ -2654,35 +2575,6 @@ out_release: | |||
| 2654 | 2575 | ||
| 2655 | return ret; | 2576 | return ret; |
| 2656 | } | 2577 | } |
| 2657 | EXPORT_SYMBOL(nobh_write_begin_newtrunc); | ||
| 2658 | |||
| 2659 | /* | ||
| 2660 | * On entry, the page is fully not uptodate. | ||
| 2661 | * On exit the page is fully uptodate in the areas outside (from,to) | ||
| 2662 | */ | ||
| 2663 | int nobh_write_begin(struct file *file, struct address_space *mapping, | ||
| 2664 | loff_t pos, unsigned len, unsigned flags, | ||
| 2665 | struct page **pagep, void **fsdata, | ||
| 2666 | get_block_t *get_block) | ||
| 2667 | { | ||
| 2668 | int ret; | ||
| 2669 | |||
| 2670 | ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, | ||
| 2671 | pagep, fsdata, get_block); | ||
| 2672 | |||
| 2673 | /* | ||
| 2674 | * prepare_write() may have instantiated a few blocks | ||
| 2675 | * outside i_size. Trim these off again. Don't need | ||
| 2676 | * i_size_read because we hold i_mutex. | ||
| 2677 | */ | ||
| 2678 | if (unlikely(ret)) { | ||
| 2679 | loff_t isize = mapping->host->i_size; | ||
| 2680 | if (pos + len > isize) | ||
| 2681 | vmtruncate(mapping->host, isize); | ||
| 2682 | } | ||
| 2683 | |||
| 2684 | return ret; | ||
| 2685 | } | ||
| 2686 | EXPORT_SYMBOL(nobh_write_begin); | 2578 | EXPORT_SYMBOL(nobh_write_begin); |
| 2687 | 2579 | ||
| 2688 | int nobh_write_end(struct file *file, struct address_space *mapping, | 2580 | int nobh_write_end(struct file *file, struct address_space *mapping, |
