diff options
Diffstat (limited to 'fs/ext2/inode.c')
-rw-r--r-- | fs/ext2/inode.c | 100 |
1 files changed, 81 insertions, 19 deletions
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index d5c7d09919f3..c7dbb4661119 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/buffer_head.h> | 32 | #include <linux/buffer_head.h> |
33 | #include <linux/mpage.h> | 33 | #include <linux/mpage.h> |
34 | #include <linux/fiemap.h> | 34 | #include <linux/fiemap.h> |
35 | #include <linux/iomap.h> | ||
35 | #include <linux/namei.h> | 36 | #include <linux/namei.h> |
36 | #include <linux/uio.h> | 37 | #include <linux/uio.h> |
37 | #include "ext2.h" | 38 | #include "ext2.h" |
@@ -618,7 +619,7 @@ static void ext2_splice_branch(struct inode *inode, | |||
618 | */ | 619 | */ |
619 | static int ext2_get_blocks(struct inode *inode, | 620 | static int ext2_get_blocks(struct inode *inode, |
620 | sector_t iblock, unsigned long maxblocks, | 621 | sector_t iblock, unsigned long maxblocks, |
621 | struct buffer_head *bh_result, | 622 | u32 *bno, bool *new, bool *boundary, |
622 | int create) | 623 | int create) |
623 | { | 624 | { |
624 | int err = -EIO; | 625 | int err = -EIO; |
@@ -644,7 +645,6 @@ static int ext2_get_blocks(struct inode *inode, | |||
644 | /* Simplest case - block found, no allocation needed */ | 645 | /* Simplest case - block found, no allocation needed */ |
645 | if (!partial) { | 646 | if (!partial) { |
646 | first_block = le32_to_cpu(chain[depth - 1].key); | 647 | first_block = le32_to_cpu(chain[depth - 1].key); |
647 | clear_buffer_new(bh_result); /* What's this do? */ | ||
648 | count++; | 648 | count++; |
649 | /*map more blocks*/ | 649 | /*map more blocks*/ |
650 | while (count < maxblocks && count <= blocks_to_boundary) { | 650 | while (count < maxblocks && count <= blocks_to_boundary) { |
@@ -699,7 +699,6 @@ static int ext2_get_blocks(struct inode *inode, | |||
699 | mutex_unlock(&ei->truncate_mutex); | 699 | mutex_unlock(&ei->truncate_mutex); |
700 | if (err) | 700 | if (err) |
701 | goto cleanup; | 701 | goto cleanup; |
702 | clear_buffer_new(bh_result); | ||
703 | goto got_it; | 702 | goto got_it; |
704 | } | 703 | } |
705 | } | 704 | } |
@@ -745,15 +744,16 @@ static int ext2_get_blocks(struct inode *inode, | |||
745 | mutex_unlock(&ei->truncate_mutex); | 744 | mutex_unlock(&ei->truncate_mutex); |
746 | goto cleanup; | 745 | goto cleanup; |
747 | } | 746 | } |
748 | } else | 747 | } else { |
749 | set_buffer_new(bh_result); | 748 | *new = true; |
749 | } | ||
750 | 750 | ||
751 | ext2_splice_branch(inode, iblock, partial, indirect_blks, count); | 751 | ext2_splice_branch(inode, iblock, partial, indirect_blks, count); |
752 | mutex_unlock(&ei->truncate_mutex); | 752 | mutex_unlock(&ei->truncate_mutex); |
753 | got_it: | 753 | got_it: |
754 | map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); | 754 | *bno = le32_to_cpu(chain[depth-1].key); |
755 | if (count > blocks_to_boundary) | 755 | if (count > blocks_to_boundary) |
756 | set_buffer_boundary(bh_result); | 756 | *boundary = true; |
757 | err = count; | 757 | err = count; |
758 | /* Clean up and exit */ | 758 | /* Clean up and exit */ |
759 | partial = chain + depth - 1; /* the whole chain */ | 759 | partial = chain + depth - 1; /* the whole chain */ |
@@ -765,19 +765,82 @@ cleanup: | |||
765 | return err; | 765 | return err; |
766 | } | 766 | } |
767 | 767 | ||
768 | int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) | 768 | int ext2_get_block(struct inode *inode, sector_t iblock, |
769 | struct buffer_head *bh_result, int create) | ||
769 | { | 770 | { |
770 | unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; | 771 | unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; |
771 | int ret = ext2_get_blocks(inode, iblock, max_blocks, | 772 | bool new = false, boundary = false; |
772 | bh_result, create); | 773 | u32 bno; |
773 | if (ret > 0) { | 774 | int ret; |
774 | bh_result->b_size = (ret << inode->i_blkbits); | 775 | |
775 | ret = 0; | 776 | ret = ext2_get_blocks(inode, iblock, max_blocks, &bno, &new, &boundary, |
777 | create); | ||
778 | if (ret <= 0) | ||
779 | return ret; | ||
780 | |||
781 | map_bh(bh_result, inode->i_sb, bno); | ||
782 | bh_result->b_size = (ret << inode->i_blkbits); | ||
783 | if (new) | ||
784 | set_buffer_new(bh_result); | ||
785 | if (boundary) | ||
786 | set_buffer_boundary(bh_result); | ||
787 | return 0; | ||
788 | |||
789 | } | ||
790 | |||
791 | #ifdef CONFIG_FS_DAX | ||
792 | static int ext2_iomap_begin(struct inode *inode, loff_t offset, loff_t length, | ||
793 | unsigned flags, struct iomap *iomap) | ||
794 | { | ||
795 | unsigned int blkbits = inode->i_blkbits; | ||
796 | unsigned long first_block = offset >> blkbits; | ||
797 | unsigned long max_blocks = (length + (1 << blkbits) - 1) >> blkbits; | ||
798 | bool new = false, boundary = false; | ||
799 | u32 bno; | ||
800 | int ret; | ||
801 | |||
802 | ret = ext2_get_blocks(inode, first_block, max_blocks, | ||
803 | &bno, &new, &boundary, flags & IOMAP_WRITE); | ||
804 | if (ret < 0) | ||
805 | return ret; | ||
806 | |||
807 | iomap->flags = 0; | ||
808 | iomap->bdev = inode->i_sb->s_bdev; | ||
809 | iomap->offset = (u64)first_block << blkbits; | ||
810 | |||
811 | if (ret == 0) { | ||
812 | iomap->type = IOMAP_HOLE; | ||
813 | iomap->blkno = IOMAP_NULL_BLOCK; | ||
814 | iomap->length = 1 << blkbits; | ||
815 | } else { | ||
816 | iomap->type = IOMAP_MAPPED; | ||
817 | iomap->blkno = (sector_t)bno << (blkbits - 9); | ||
818 | iomap->length = (u64)ret << blkbits; | ||
819 | iomap->flags |= IOMAP_F_MERGED; | ||
776 | } | 820 | } |
777 | return ret; | ||
778 | 821 | ||
822 | if (new) | ||
823 | iomap->flags |= IOMAP_F_NEW; | ||
824 | return 0; | ||
779 | } | 825 | } |
780 | 826 | ||
827 | static int | ||
828 | ext2_iomap_end(struct inode *inode, loff_t offset, loff_t length, | ||
829 | ssize_t written, unsigned flags, struct iomap *iomap) | ||
830 | { | ||
831 | if (iomap->type == IOMAP_MAPPED && | ||
832 | written < length && | ||
833 | (flags & IOMAP_WRITE)) | ||
834 | ext2_write_failed(inode->i_mapping, offset + length); | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | struct iomap_ops ext2_iomap_ops = { | ||
839 | .iomap_begin = ext2_iomap_begin, | ||
840 | .iomap_end = ext2_iomap_end, | ||
841 | }; | ||
842 | #endif /* CONFIG_FS_DAX */ | ||
843 | |||
781 | int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 844 | int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
782 | u64 start, u64 len) | 845 | u64 start, u64 len) |
783 | { | 846 | { |
@@ -863,11 +926,10 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
863 | loff_t offset = iocb->ki_pos; | 926 | loff_t offset = iocb->ki_pos; |
864 | ssize_t ret; | 927 | ssize_t ret; |
865 | 928 | ||
866 | if (IS_DAX(inode)) | 929 | if (WARN_ON_ONCE(IS_DAX(inode))) |
867 | ret = dax_do_io(iocb, inode, iter, ext2_get_block, NULL, | 930 | return -EIO; |
868 | DIO_LOCKING); | 931 | |
869 | else | 932 | ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); |
870 | ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); | ||
871 | if (ret < 0 && iov_iter_rw(iter) == WRITE) | 933 | if (ret < 0 && iov_iter_rw(iter) == WRITE) |
872 | ext2_write_failed(mapping, offset + count); | 934 | ext2_write_failed(mapping, offset + count); |
873 | return ret; | 935 | return ret; |