aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2010-07-06 17:36:06 -0400
committerJoel Becker <joel.becker@oracle.com>2010-07-08 16:24:49 -0400
commita4bfb4cf11fd2211b788af59dc8a8b4394bca227 (patch)
treec06f45ac5a992575a0e47dbc80bdf187db030cca
parent1739da40543ed2129050ccfa8a076a851ab6ed00 (diff)
ocfs2: When zero extending, do it by page.
ocfs2_zero_extend() does its zeroing block by block, but it calls a function named ocfs2_write_zero_page(). Let's have ocfs2_write_zero_page() handle the page level. From ocfs2_zero_extend()'s perspective, it is now page-at-a-time. Signed-off-by: Joel Becker <joel.becker@oracle.com> Cc: stable@kernel.org
-rw-r--r--fs/ocfs2/aops.c30
-rw-r--r--fs/ocfs2/file.c118
2 files changed, 84 insertions, 64 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 3623ca20cc18..9a5c931439bd 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -459,36 +459,6 @@ int walk_page_buffers( handle_t *handle,
459 return ret; 459 return ret;
460} 460}
461 461
462handle_t *ocfs2_start_walk_page_trans(struct inode *inode,
463 struct page *page,
464 unsigned from,
465 unsigned to)
466{
467 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
468 handle_t *handle;
469 int ret = 0;
470
471 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
472 if (IS_ERR(handle)) {
473 ret = -ENOMEM;
474 mlog_errno(ret);
475 goto out;
476 }
477
478 if (ocfs2_should_order_data(inode)) {
479 ret = ocfs2_jbd2_file_inode(handle, inode);
480 if (ret < 0)
481 mlog_errno(ret);
482 }
483out:
484 if (ret) {
485 if (!IS_ERR(handle))
486 ocfs2_commit_trans(osb, handle);
487 handle = ERR_PTR(ret);
488 }
489 return handle;
490}
491
492static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) 462static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
493{ 463{
494 sector_t status; 464 sector_t status;
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 6a13ea64c447..4cfc976a9067 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -724,28 +724,55 @@ leave:
724 return status; 724 return status;
725} 725}
726 726
727/*
728 * While a write will already be ordering the data, a truncate will not.
729 * Thus, we need to explicitly order the zeroed pages.
730 */
731static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode)
732{
733 struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
734 handle_t *handle = NULL;
735 int ret = 0;
736
737 if (!ocfs2_should_order_data(inode))
738 goto out;
739
740 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
741 if (IS_ERR(handle)) {
742 ret = -ENOMEM;
743 mlog_errno(ret);
744 goto out;
745 }
746
747 ret = ocfs2_jbd2_file_inode(handle, inode);
748 if (ret < 0)
749 mlog_errno(ret);
750
751out:
752 if (ret) {
753 if (!IS_ERR(handle))
754 ocfs2_commit_trans(osb, handle);
755 handle = ERR_PTR(ret);
756 }
757 return handle;
758}
759
727/* Some parts of this taken from generic_cont_expand, which turned out 760/* Some parts of this taken from generic_cont_expand, which turned out
728 * to be too fragile to do exactly what we need without us having to 761 * to be too fragile to do exactly what we need without us having to
729 * worry about recursive locking in ->write_begin() and ->write_end(). */ 762 * worry about recursive locking in ->write_begin() and ->write_end(). */
730static int ocfs2_write_zero_page(struct inode *inode, 763static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
731 u64 size) 764 u64 abs_to)
732{ 765{
733 struct address_space *mapping = inode->i_mapping; 766 struct address_space *mapping = inode->i_mapping;
734 struct page *page; 767 struct page *page;
735 unsigned long index; 768 unsigned long index = abs_from >> PAGE_CACHE_SHIFT;
736 unsigned int offset;
737 handle_t *handle = NULL; 769 handle_t *handle = NULL;
738 int ret; 770 int ret;
771 unsigned zero_from, zero_to, block_start, block_end;
739 772
740 offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */ 773 BUG_ON(abs_from >= abs_to);
741 /* ugh. in prepare/commit_write, if from==to==start of block, we 774 BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT));
742 ** skip the prepare. make sure we never send an offset for the start 775 BUG_ON(abs_from & (inode->i_blkbits - 1));
743 ** of a block
744 */
745 if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) {
746 offset++;
747 }
748 index = size >> PAGE_CACHE_SHIFT;
749 776
750 page = grab_cache_page(mapping, index); 777 page = grab_cache_page(mapping, index);
751 if (!page) { 778 if (!page) {
@@ -754,31 +781,51 @@ static int ocfs2_write_zero_page(struct inode *inode,
754 goto out; 781 goto out;
755 } 782 }
756 783
757 ret = ocfs2_prepare_write_nolock(inode, page, offset, offset); 784 /* Get the offsets within the page that we want to zero */
758 if (ret < 0) { 785 zero_from = abs_from & (PAGE_CACHE_SIZE - 1);
759 mlog_errno(ret); 786 zero_to = abs_to & (PAGE_CACHE_SIZE - 1);
760 goto out_unlock; 787 if (!zero_to)
761 } 788 zero_to = PAGE_CACHE_SIZE;
762 789
763 if (ocfs2_should_order_data(inode)) { 790 /* We know that zero_from is block aligned */
764 handle = ocfs2_start_walk_page_trans(inode, page, offset, 791 for (block_start = zero_from; block_start < zero_to;
765 offset); 792 block_start = block_end) {
766 if (IS_ERR(handle)) { 793 block_end = block_start + (1 << inode->i_blkbits);
767 ret = PTR_ERR(handle); 794
768 handle = NULL; 795 /*
796 * block_start is block-aligned. Bump it by one to
797 * force ocfs2_{prepare,commit}_write() to zero the
798 * whole block.
799 */
800 ret = ocfs2_prepare_write_nolock(inode, page,
801 block_start + 1,
802 block_start + 1);
803 if (ret < 0) {
804 mlog_errno(ret);
769 goto out_unlock; 805 goto out_unlock;
770 } 806 }
771 }
772 807
773 /* must not update i_size! */ 808 if (!handle) {
774 ret = block_commit_write(page, offset, offset); 809 handle = ocfs2_zero_start_ordered_transaction(inode);
775 if (ret < 0) 810 if (IS_ERR(handle)) {
776 mlog_errno(ret); 811 ret = PTR_ERR(handle);
777 else 812 handle = NULL;
778 ret = 0; 813 break;
814 }
815 }
816
817 /* must not update i_size! */
818 ret = block_commit_write(page, block_start + 1,
819 block_start + 1);
820 if (ret < 0)
821 mlog_errno(ret);
822 else
823 ret = 0;
824 }
779 825
780 if (handle) 826 if (handle)
781 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); 827 ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
828
782out_unlock: 829out_unlock:
783 unlock_page(page); 830 unlock_page(page);
784 page_cache_release(page); 831 page_cache_release(page);
@@ -790,18 +837,21 @@ static int ocfs2_zero_extend(struct inode *inode,
790 u64 zero_to_size) 837 u64 zero_to_size)
791{ 838{
792 int ret = 0; 839 int ret = 0;
793 u64 start_off; 840 u64 start_off, next_off;
794 struct super_block *sb = inode->i_sb; 841 struct super_block *sb = inode->i_sb;
795 842
796 start_off = ocfs2_align_bytes_to_blocks(sb, i_size_read(inode)); 843 start_off = ocfs2_align_bytes_to_blocks(sb, i_size_read(inode));
797 while (start_off < zero_to_size) { 844 while (start_off < zero_to_size) {
798 ret = ocfs2_write_zero_page(inode, start_off); 845 next_off = (start_off & PAGE_CACHE_MASK) + PAGE_CACHE_SIZE;
846 if (next_off > zero_to_size)
847 next_off = zero_to_size;
848 ret = ocfs2_write_zero_page(inode, start_off, next_off);
799 if (ret < 0) { 849 if (ret < 0) {
800 mlog_errno(ret); 850 mlog_errno(ret);
801 goto out; 851 goto out;
802 } 852 }
803 853
804 start_off += sb->s_blocksize; 854 start_off = next_off;
805 855
806 /* 856 /*
807 * Very large extends have the potential to lock up 857 * Very large extends have the potential to lock up