|
21 | 21 | #include <linux/kernel.h> |
22 | 22 | #include <linux/syscalls.h> |
23 | 23 | #include <linux/fs.h> |
| 24 | +#include <linux/iomap.h> |
24 | 25 | #include <linux/mm.h> |
25 | 26 | #include <linux/percpu.h> |
26 | 27 | #include <linux/slab.h> |
@@ -1892,8 +1893,62 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) |
1892 | 1893 | } |
1893 | 1894 | EXPORT_SYMBOL(page_zero_new_buffers); |
1894 | 1895 |
|
1895 | | -int __block_write_begin(struct page *page, loff_t pos, unsigned len, |
1896 | | - get_block_t *get_block) |
| 1896 | +static void |
| 1897 | +iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh, |
| 1898 | + struct iomap *iomap) |
| 1899 | +{ |
| 1900 | + loff_t offset = block << inode->i_blkbits; |
| 1901 | + |
| 1902 | + bh->b_bdev = iomap->bdev; |
| 1903 | + |
| 1904 | + /* |
| 1905 | + * Block points to offset in file we need to map, iomap contains |
| 1906 | + * the offset at which the map starts. If the map ends before the |
| 1907 | + * current block, then do not map the buffer and let the caller |
| 1908 | + * handle it. |
| 1909 | + */ |
| 1910 | + BUG_ON(offset >= iomap->offset + iomap->length); |
| 1911 | + |
| 1912 | + switch (iomap->type) { |
| 1913 | + case IOMAP_HOLE: |
| 1914 | + /* |
| 1915 | + * If the buffer is not up to date or beyond the current EOF, |
| 1916 | + * we need to mark it as new to ensure sub-block zeroing is |
| 1917 | + * executed if necessary. |
| 1918 | + */ |
| 1919 | + if (!buffer_uptodate(bh) || |
| 1920 | + (offset >= i_size_read(inode))) |
| 1921 | + set_buffer_new(bh); |
| 1922 | + break; |
| 1923 | + case IOMAP_DELALLOC: |
| 1924 | + if (!buffer_uptodate(bh) || |
| 1925 | + (offset >= i_size_read(inode))) |
| 1926 | + set_buffer_new(bh); |
| 1927 | + set_buffer_uptodate(bh); |
| 1928 | + set_buffer_mapped(bh); |
| 1929 | + set_buffer_delay(bh); |
| 1930 | + break; |
| 1931 | + case IOMAP_UNWRITTEN: |
| 1932 | + /* |
| 1933 | + * For unwritten regions, we always need to ensure that |
| 1934 | + * sub-block writes cause the regions in the block we are not |
| 1935 | + * writing to are zeroed. Set the buffer as new to ensure this. |
| 1936 | + */ |
| 1937 | + set_buffer_new(bh); |
| 1938 | + set_buffer_unwritten(bh); |
| 1939 | + /* FALLTHRU */ |
| 1940 | + case IOMAP_MAPPED: |
| 1941 | + if (offset >= i_size_read(inode)) |
| 1942 | + set_buffer_new(bh); |
| 1943 | + bh->b_blocknr = (iomap->blkno >> (inode->i_blkbits - 9)) + |
| 1944 | + ((offset - iomap->offset) >> inode->i_blkbits); |
| 1945 | + set_buffer_mapped(bh); |
| 1946 | + break; |
| 1947 | + } |
| 1948 | +} |
| 1949 | + |
| 1950 | +int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, |
| 1951 | + get_block_t *get_block, struct iomap *iomap) |
1897 | 1952 | { |
1898 | 1953 | unsigned from = pos & (PAGE_SIZE - 1); |
1899 | 1954 | unsigned to = from + len; |
@@ -1929,9 +1984,14 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len, |
1929 | 1984 | clear_buffer_new(bh); |
1930 | 1985 | if (!buffer_mapped(bh)) { |
1931 | 1986 | WARN_ON(bh->b_size != blocksize); |
1932 | | - err = get_block(inode, block, bh, 1); |
1933 | | - if (err) |
1934 | | - break; |
| 1987 | + if (get_block) { |
| 1988 | + err = get_block(inode, block, bh, 1); |
| 1989 | + if (err) |
| 1990 | + break; |
| 1991 | + } else { |
| 1992 | + iomap_to_bh(inode, block, bh, iomap); |
| 1993 | + } |
| 1994 | + |
1935 | 1995 | if (buffer_new(bh)) { |
1936 | 1996 | unmap_underlying_metadata(bh->b_bdev, |
1937 | 1997 | bh->b_blocknr); |
@@ -1972,6 +2032,12 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len, |
1972 | 2032 | page_zero_new_buffers(page, from, to); |
1973 | 2033 | return err; |
1974 | 2034 | } |
| 2035 | + |
| 2036 | +int __block_write_begin(struct page *page, loff_t pos, unsigned len, |
| 2037 | + get_block_t *get_block) |
| 2038 | +{ |
| 2039 | + return __block_write_begin_int(page, pos, len, get_block, NULL); |
| 2040 | +} |
1975 | 2041 | EXPORT_SYMBOL(__block_write_begin); |
1976 | 2042 |
|
1977 | 2043 | static int __block_commit_write(struct inode *inode, struct page *page, |
|
0 commit comments