diff options
author | Benjamin Marzinski <bmarzins@redhat.com> | 2011-03-11 01:49:09 -0500 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-03-11 04:26:48 -0500 |
commit | e4a7b7b0c98efcdcc4c1f6eb10925dec1fbc4016 (patch) | |
tree | 72b28371e1e0397a1fb39c103d2062593e3a3a24 /fs/gfs2/file.c | |
parent | fa1bbdea300a15ec7c1186a5e53de33a5b1672f5 (diff) |
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.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/file.c')
-rw-r--r-- | fs/gfs2/file.c | 56 |
1 files changed, 31 insertions, 25 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 2878481f72a9..4074b952b059 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -622,8 +622,7 @@ static void empty_write_end(struct page *page, unsigned from, | |||
622 | { | 622 | { |
623 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | 623 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); |
624 | 624 | ||
625 | page_zero_new_buffers(page, from, to); | 625 | zero_user(page, from, to-from); |
626 | flush_dcache_page(page); | ||
627 | mark_page_accessed(page); | 626 | mark_page_accessed(page); |
628 | 627 | ||
629 | if (!gfs2_is_writeback(ip)) | 628 | if (!gfs2_is_writeback(ip)) |
@@ -632,36 +631,43 @@ static void empty_write_end(struct page *page, unsigned from, | |||
632 | block_commit_write(page, from, to); | 631 | block_commit_write(page, from, to); |
633 | } | 632 | } |
634 | 633 | ||
635 | static int write_empty_blocks(struct page *page, unsigned from, unsigned to) | 634 | static int needs_empty_write(sector_t block, struct inode *inode) |
636 | { | 635 | { |
637 | unsigned start, end, next; | ||
638 | struct buffer_head *bh, *head; | ||
639 | int error; | 636 | int error; |
637 | struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; | ||
640 | 638 | ||
641 | if (!page_has_buffers(page)) { | 639 | bh_map.b_size = 1 << inode->i_blkbits; |
642 | error = __block_write_begin(page, from, to - from, gfs2_block_map); | 640 | error = gfs2_block_map(inode, block, &bh_map, 0); |
643 | if (unlikely(error)) | 641 | if (unlikely(error)) |
644 | return error; | 642 | return error; |
643 | return !buffer_mapped(&bh_map); | ||
644 | } | ||
645 | 645 | ||
646 | empty_write_end(page, from, to); | 646 | static int write_empty_blocks(struct page *page, unsigned from, unsigned to) |
647 | return 0; | 647 | { |
648 | } | 648 | struct inode *inode = page->mapping->host; |
649 | unsigned start, end, next, blksize; | ||
650 | sector_t block = page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
651 | int ret; | ||
649 | 652 | ||
650 | bh = head = page_buffers(page); | 653 | blksize = 1 << inode->i_blkbits; |
651 | next = end = 0; | 654 | next = end = 0; |
652 | while (next < from) { | 655 | while (next < from) { |
653 | next += bh->b_size; | 656 | next += blksize; |
654 | bh = bh->b_this_page; | 657 | block++; |
655 | } | 658 | } |
656 | start = next; | 659 | start = next; |
657 | do { | 660 | do { |
658 | next += bh->b_size; | 661 | next += blksize; |
659 | if (buffer_mapped(bh)) { | 662 | ret = needs_empty_write(block, inode); |
663 | if (unlikely(ret < 0)) | ||
664 | return ret; | ||
665 | if (ret == 0) { | ||
660 | if (end) { | 666 | if (end) { |
661 | error = __block_write_begin(page, start, end - start, | 667 | ret = __block_write_begin(page, start, end - start, |
662 | gfs2_block_map); | 668 | gfs2_block_map); |
663 | if (unlikely(error)) | 669 | if (unlikely(ret)) |
664 | return error; | 670 | return ret; |
665 | empty_write_end(page, start, end); | 671 | empty_write_end(page, start, end); |
666 | end = 0; | 672 | end = 0; |
667 | } | 673 | } |
@@ -669,13 +675,13 @@ static int write_empty_blocks(struct page *page, unsigned from, unsigned to) | |||
669 | } | 675 | } |
670 | else | 676 | else |
671 | end = next; | 677 | end = next; |
672 | bh = bh->b_this_page; | 678 | block++; |
673 | } while (next < to); | 679 | } while (next < to); |
674 | 680 | ||
675 | if (end) { | 681 | if (end) { |
676 | error = __block_write_begin(page, start, end - start, gfs2_block_map); | 682 | ret = __block_write_begin(page, start, end - start, gfs2_block_map); |
677 | if (unlikely(error)) | 683 | if (unlikely(ret)) |
678 | return error; | 684 | return ret; |
679 | empty_write_end(page, start, end); | 685 | empty_write_end(page, start, end); |
680 | } | 686 | } |
681 | 687 | ||