diff options
author | Christoph Hellwig <hch@lst.de> | 2016-09-18 21:30:29 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-09-18 21:30:29 -0400 |
commit | 25f4e70291a309749a93b30ffa58d2eac9f200f8 (patch) | |
tree | 0b8f01267a81cb947303b362b6073f126fe78f3a | |
parent | 6750ad71986d286a666e6245f160b89f4c15e7b0 (diff) |
ext2: use iomap to implement DAX
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/ext2/Kconfig | 1 | ||||
-rw-r--r-- | fs/ext2/ext2.h | 1 | ||||
-rw-r--r-- | fs/ext2/file.c | 76 | ||||
-rw-r--r-- | fs/ext2/inode.c | 63 |
4 files changed, 129 insertions, 12 deletions
diff --git a/fs/ext2/Kconfig b/fs/ext2/Kconfig index c634874e12d9..36bea5adcaba 100644 --- a/fs/ext2/Kconfig +++ b/fs/ext2/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config EXT2_FS | 1 | config EXT2_FS |
2 | tristate "Second extended fs support" | 2 | tristate "Second extended fs support" |
3 | select FS_IOMAP if FS_DAX | ||
3 | help | 4 | help |
4 | Ext2 is a standard Linux file system for hard disks. | 5 | Ext2 is a standard Linux file system for hard disks. |
5 | 6 | ||
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 06af2f92226c..37e2be784ac7 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -814,6 +814,7 @@ extern const struct file_operations ext2_file_operations; | |||
814 | /* inode.c */ | 814 | /* inode.c */ |
815 | extern const struct address_space_operations ext2_aops; | 815 | extern const struct address_space_operations ext2_aops; |
816 | extern const struct address_space_operations ext2_nobh_aops; | 816 | extern const struct address_space_operations ext2_nobh_aops; |
817 | extern struct iomap_ops ext2_iomap_ops; | ||
817 | 818 | ||
818 | /* namei.c */ | 819 | /* namei.c */ |
819 | extern const struct inode_operations ext2_dir_inode_operations; | 820 | extern const struct inode_operations ext2_dir_inode_operations; |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 5efeefe17abb..423cc01c9d41 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -22,11 +22,59 @@ | |||
22 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
23 | #include <linux/dax.h> | 23 | #include <linux/dax.h> |
24 | #include <linux/quotaops.h> | 24 | #include <linux/quotaops.h> |
25 | #include <linux/iomap.h> | ||
26 | #include <linux/uio.h> | ||
25 | #include "ext2.h" | 27 | #include "ext2.h" |
26 | #include "xattr.h" | 28 | #include "xattr.h" |
27 | #include "acl.h" | 29 | #include "acl.h" |
28 | 30 | ||
29 | #ifdef CONFIG_FS_DAX | 31 | #ifdef CONFIG_FS_DAX |
32 | static ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to) | ||
33 | { | ||
34 | struct inode *inode = iocb->ki_filp->f_mapping->host; | ||
35 | ssize_t ret; | ||
36 | |||
37 | if (!iov_iter_count(to)) | ||
38 | return 0; /* skip atime */ | ||
39 | |||
40 | inode_lock_shared(inode); | ||
41 | ret = iomap_dax_rw(iocb, to, &ext2_iomap_ops); | ||
42 | inode_unlock_shared(inode); | ||
43 | |||
44 | file_accessed(iocb->ki_filp); | ||
45 | return ret; | ||
46 | } | ||
47 | |||
48 | static ssize_t ext2_dax_write_iter(struct kiocb *iocb, struct iov_iter *from) | ||
49 | { | ||
50 | struct file *file = iocb->ki_filp; | ||
51 | struct inode *inode = file->f_mapping->host; | ||
52 | ssize_t ret; | ||
53 | |||
54 | inode_lock(inode); | ||
55 | ret = generic_write_checks(iocb, from); | ||
56 | if (ret <= 0) | ||
57 | goto out_unlock; | ||
58 | ret = file_remove_privs(file); | ||
59 | if (ret) | ||
60 | goto out_unlock; | ||
61 | ret = file_update_time(file); | ||
62 | if (ret) | ||
63 | goto out_unlock; | ||
64 | |||
65 | ret = iomap_dax_rw(iocb, from, &ext2_iomap_ops); | ||
66 | if (ret > 0 && iocb->ki_pos > i_size_read(inode)) { | ||
67 | i_size_write(inode, iocb->ki_pos); | ||
68 | mark_inode_dirty(inode); | ||
69 | } | ||
70 | |||
71 | out_unlock: | ||
72 | inode_unlock(inode); | ||
73 | if (ret > 0) | ||
74 | ret = generic_write_sync(iocb, ret); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
30 | /* | 78 | /* |
31 | * The lock ordering for ext2 DAX fault paths is: | 79 | * The lock ordering for ext2 DAX fault paths is: |
32 | * | 80 | * |
@@ -51,7 +99,7 @@ static int ext2_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
51 | } | 99 | } |
52 | down_read(&ei->dax_sem); | 100 | down_read(&ei->dax_sem); |
53 | 101 | ||
54 | ret = dax_fault(vma, vmf, ext2_get_block); | 102 | ret = iomap_dax_fault(vma, vmf, &ext2_iomap_ops); |
55 | 103 | ||
56 | up_read(&ei->dax_sem); | 104 | up_read(&ei->dax_sem); |
57 | if (vmf->flags & FAULT_FLAG_WRITE) | 105 | if (vmf->flags & FAULT_FLAG_WRITE) |
@@ -156,14 +204,28 @@ int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
156 | return ret; | 204 | return ret; |
157 | } | 205 | } |
158 | 206 | ||
159 | /* | 207 | static ssize_t ext2_file_read_iter(struct kiocb *iocb, struct iov_iter *to) |
160 | * We have mostly NULL's here: the current defaults are ok for | 208 | { |
161 | * the ext2 filesystem. | 209 | #ifdef CONFIG_FS_DAX |
162 | */ | 210 | if (IS_DAX(iocb->ki_filp->f_mapping->host)) |
211 | return ext2_dax_read_iter(iocb, to); | ||
212 | #endif | ||
213 | return generic_file_read_iter(iocb, to); | ||
214 | } | ||
215 | |||
216 | static ssize_t ext2_file_write_iter(struct kiocb *iocb, struct iov_iter *from) | ||
217 | { | ||
218 | #ifdef CONFIG_FS_DAX | ||
219 | if (IS_DAX(iocb->ki_filp->f_mapping->host)) | ||
220 | return ext2_dax_write_iter(iocb, from); | ||
221 | #endif | ||
222 | return generic_file_write_iter(iocb, from); | ||
223 | } | ||
224 | |||
163 | const struct file_operations ext2_file_operations = { | 225 | const struct file_operations ext2_file_operations = { |
164 | .llseek = generic_file_llseek, | 226 | .llseek = generic_file_llseek, |
165 | .read_iter = generic_file_read_iter, | 227 | .read_iter = ext2_file_read_iter, |
166 | .write_iter = generic_file_write_iter, | 228 | .write_iter = ext2_file_write_iter, |
167 | .unlocked_ioctl = ext2_ioctl, | 229 | .unlocked_ioctl = ext2_ioctl, |
168 | #ifdef CONFIG_COMPAT | 230 | #ifdef CONFIG_COMPAT |
169 | .compat_ioctl = ext2_compat_ioctl, | 231 | .compat_ioctl = ext2_compat_ioctl, |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 2a69ab2e7bb0..aae5f61f980b 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" |
@@ -787,6 +788,59 @@ int ext2_get_block(struct inode *inode, sector_t iblock, | |||
787 | 788 | ||
788 | } | 789 | } |
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 = 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; | ||
820 | } | ||
821 | |||
822 | if (new) | ||
823 | iomap->flags |= IOMAP_F_NEW; | ||
824 | return 0; | ||
825 | } | ||
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 | |||
790 | int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 844 | int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
791 | u64 start, u64 len) | 845 | u64 start, u64 len) |
792 | { | 846 | { |
@@ -872,11 +926,10 @@ ext2_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
872 | loff_t offset = iocb->ki_pos; | 926 | loff_t offset = iocb->ki_pos; |
873 | ssize_t ret; | 927 | ssize_t ret; |
874 | 928 | ||
875 | if (IS_DAX(inode)) | 929 | if (WARN_ON_ONCE(IS_DAX(inode))) |
876 | ret = dax_do_io(iocb, inode, iter, ext2_get_block, NULL, | 930 | return -EIO; |
877 | DIO_LOCKING); | 931 | |
878 | else | 932 | ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); |
879 | ret = blockdev_direct_IO(iocb, inode, iter, ext2_get_block); | ||
880 | if (ret < 0 && iov_iter_rw(iter) == WRITE) | 933 | if (ret < 0 && iov_iter_rw(iter) == WRITE) |
881 | ext2_write_failed(mapping, offset + count); | 934 | ext2_write_failed(mapping, offset + count); |
882 | return ret; | 935 | return ret; |