GFS2: fix block allocation check for fallocate
PATCH 1/1 GFS2: fix block allocation check for fallocate
GFS2 fallocate wasn't properly checking if a blocks were already allocated. In write_empty_blocks(), if a page didn't have buffer_heads attached, GFS2 was always treating it as if there were no blocks allocated for that page. GFS2 now calls gfs2_block_map() to check if the blocks are allocated before writing them out.
--- fs/gfs2/file.c | 56 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 25 deletions(-)
fs/gfs2/file.c +31 -25
@@ -622,8 +622,7 @@ static void empty_write_end(struct page {struct gfs2_inode *ip =GFS2_I (page->mapping->host); -page_zero_new_buffers (page, from, to); -flush_dcache_page (page); +zero_user (page, from, to-from);mark_page_accessed (page);if (!gfs2_is_writeback (ip))
@@ -632,36 +631,43 @@ static void empty_write_end(struct pageblock_commit_write (page, from, to); } -static int write_empty_blocks (struct page *page,unsigned from,unsigned to) +static int needs_empty_write (sector_t block,struct inode *inode) { -unsigned start, end, next; -struct buffer_head *bh, *head;int error; +struct buffer_head bh_map = { .b_state =0 , .b_blocknr =0 }; -if (!page_has_buffers (page)) { - error =__block_write_begin (page, from, to - from, gfs2_block_map); -if (unlikely (error)) -return error; + bh_map.b_size =1 << inode->i_blkbits; + error =gfs2_block_map (inode, block, &bh_map,0 ); +if (unlikely (error)) +return error; +return !buffer_mapped (&bh_map); +} -empty_write_end (page, from, to); -return 0 ; - } +static int write_empty_blocks (struct page *page,unsigned from,unsigned to) +{ +struct inode *inode = page->mapping->host; +unsigned start, end, next, blksize; +sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); +int ret; - bh = head =page_buffers (page); + blksize =1 << inode->i_blkbits; next = end =0 ;while (next < from) { - next += bh->b_size; - bh = bh->b_this_page; + next += blksize; + block++; } start = next; do { - next += bh->b_size; - if (buffer_mapped(bh)) { + next += blksize; + ret = needs_empty_write(block, inode); + if (unlikely(ret < 0)) + return ret; + if (ret == 0) { if (end) { - error = __block_write_begin(page, start, end - start, - gfs2_block_map); - if (unlikely(error)) - return error; + ret = __block_write_begin(page, start, end - start, + gfs2_block_map); + if (unlikely(ret)) + return ret; empty_write_end(page, start, end); end = 0; }
@@ -669,13 +675,13 @@ static int write_empty_blocks(struct pag }else end = next; - bh = bh->b_this_page; + block++; }while (next < to);if (end) { - error =__block_write_begin (page, start, end - start, gfs2_block_map); -if (unlikely (error)) -return error; + ret =__block_write_begin (page, start, end - start, gfs2_block_map); +if (unlikely (ret)) +return ret;empty_write_end (page, start, end); }
PATCH 1/1 GFS2: fix block allocation check for fallocate
Hi,
Quoted 11 lines · Benjamin Marzinski
GFS2 fallocate wasn't properly checking if a blocks were already allocated. In
write_empty_blocks(), if a page didn't havebuffer_headsattached, GFS2 was always treating it as if there were no blocks allocated for that page. GFS2 now callsgfs2_block_map()to check if the blocks are allocated before writing them out.Signed-off-by Benjamin Marzinski <[email protected]>--- fs/gfs2/file.c | 56 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 25 deletions(-)
Thanks for the patch. Now in the -nmw git tree,
Steve.
Quoted 96 lines
Index:
gfs2-2.6-nmw/fs/gfs2/file.c
===================================================================fs/gfs2/file.c +31
-25@@ -622,8 +622,7 @@ static void empty_write_end(struct page {struct gfs2_inode *ip =GFS2_I (page->mapping->host); -page_zero_new_buffers (page, from, to); -flush_dcache_page (page); +zero_user (page, from, to-from);mark_page_accessed (page);if (!gfs2_is_writeback (ip))@@ -632,36 +631,43 @@ static void empty_write_end(struct pageblock_commit_write (page, from, to); } -static int write_empty_blocks (struct page *page,unsigned from,unsigned to) +static int needs_empty_write (sector_t block,struct inode *inode) { -unsigned start, end, next; -struct buffer_head *bh, *head;int error; +struct buffer_head bh_map = { .b_state =0 , .b_blocknr =0 }; -if (!page_has_buffers (page)) { - error =__block_write_begin (page, from, to - from, gfs2_block_map); -if (unlikely (error)) -return error; + bh_map.b_size =1 << inode->i_blkbits; + error =gfs2_block_map (inode, block, &bh_map,0 ); +if (unlikely (error)) +return error; +return !buffer_mapped (&bh_map); +} -empty_write_end (page, from, to); -return 0 ; - } +static int write_empty_blocks (struct page *page,unsigned from,unsigned to) +{ +struct inode *inode = page->mapping->host; +unsigned start, end, next, blksize; +sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); +int ret; - bh = head =page_buffers (page); + blksize =1 << inode->i_blkbits; next = end =0 ;while (next < from) { - next += bh->b_size; - bh = bh->b_this_page; + next += blksize; + block++; } start = next; do { - next += bh->b_size; - if (buffer_mapped(bh)) { + next += blksize; + ret = needs_empty_write(block, inode); + if (unlikely(ret < 0)) + return ret; + if (ret == 0) { if (end) { - error = __block_write_begin(page, start, end - start, - gfs2_block_map); - if (unlikely(error)) - return error; + ret = __block_write_begin(page, start, end - start, + gfs2_block_map); + if (unlikely(ret)) + return ret; empty_write_end(page, start, end); end = 0; }@@ -669,13 +675,13 @@ static int write_empty_blocks(struct pag }else end = next; - bh = bh->b_this_page; + block++; }while (next < to);if (end) { - error =__block_write_begin (page, start, end - start, gfs2_block_map); -if (unlikely (error)) -return error; + ret =__block_write_begin (page, start, end - start, gfs2_block_map); +if (unlikely (ret)) +return ret;empty_write_end (page, start, end); }