diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-17 16:09:22 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-05-06 17:39:36 -0400 |
commit | 9b884164d59707216840159d45f6be68073fac6e (patch) | |
tree | c1e6f2ffef22003502bd8f118492b16ae03723bc /fs/ext4 | |
parent | a8324754889c0a491b216bc0502ef9ba557eeac7 (diff) |
convert ext4 to ->write_iter()
unfortunately, Ted's changes to ext4_file_write() are *still* an
incomplete fix - playing with rlimits can let you smuggle an
unaligned request past the checks. So there almost certainly
will be more merge PITA around that place...
[fix from Peter Ujfalusi <peter.ujfalusi@ti.com> folded]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/file.c | 29 |
1 files changed, 11 insertions, 18 deletions
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 86a13a514e4a..48383a5f37a1 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -74,26 +74,22 @@ void ext4_unwritten_wait(struct inode *inode) | |||
74 | * or one thread will zero the other's data, causing corruption. | 74 | * or one thread will zero the other's data, causing corruption. |
75 | */ | 75 | */ |
76 | static int | 76 | static int |
77 | ext4_unaligned_aio(struct inode *inode, const struct iovec *iov, | 77 | ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos) |
78 | unsigned long nr_segs, loff_t pos) | ||
79 | { | 78 | { |
80 | struct super_block *sb = inode->i_sb; | 79 | struct super_block *sb = inode->i_sb; |
81 | int blockmask = sb->s_blocksize - 1; | 80 | int blockmask = sb->s_blocksize - 1; |
82 | size_t count = iov_length(iov, nr_segs); | ||
83 | loff_t final_size = pos + count; | ||
84 | 81 | ||
85 | if (pos >= i_size_read(inode)) | 82 | if (pos >= i_size_read(inode)) |
86 | return 0; | 83 | return 0; |
87 | 84 | ||
88 | if ((pos & blockmask) || (final_size & blockmask)) | 85 | if ((pos | iov_iter_alignment(from)) & blockmask) |
89 | return 1; | 86 | return 1; |
90 | 87 | ||
91 | return 0; | 88 | return 0; |
92 | } | 89 | } |
93 | 90 | ||
94 | static ssize_t | 91 | static ssize_t |
95 | ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | 92 | ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
96 | unsigned long nr_segs, loff_t pos) | ||
97 | { | 93 | { |
98 | struct file *file = iocb->ki_filp; | 94 | struct file *file = iocb->ki_filp; |
99 | struct inode *inode = file_inode(iocb->ki_filp); | 95 | struct inode *inode = file_inode(iocb->ki_filp); |
@@ -101,10 +97,9 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
101 | struct blk_plug plug; | 97 | struct blk_plug plug; |
102 | int o_direct = file->f_flags & O_DIRECT; | 98 | int o_direct = file->f_flags & O_DIRECT; |
103 | int overwrite = 0; | 99 | int overwrite = 0; |
104 | size_t length = iov_length(iov, nr_segs); | 100 | size_t length = iov_iter_count(from); |
105 | ssize_t ret; | 101 | ssize_t ret; |
106 | 102 | loff_t pos = iocb->ki_pos; | |
107 | BUG_ON(iocb->ki_pos != pos); | ||
108 | 103 | ||
109 | /* | 104 | /* |
110 | * Unaligned direct AIO must be serialized; see comment above | 105 | * Unaligned direct AIO must be serialized; see comment above |
@@ -114,7 +109,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
114 | ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && | 109 | ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && |
115 | !is_sync_kiocb(iocb) && | 110 | !is_sync_kiocb(iocb) && |
116 | (file->f_flags & O_APPEND || | 111 | (file->f_flags & O_APPEND || |
117 | ext4_unaligned_aio(inode, iov, nr_segs, pos))) { | 112 | ext4_unaligned_aio(inode, from, pos))) { |
118 | aio_mutex = ext4_aio_mutex(inode); | 113 | aio_mutex = ext4_aio_mutex(inode); |
119 | mutex_lock(aio_mutex); | 114 | mutex_lock(aio_mutex); |
120 | ext4_unwritten_wait(inode); | 115 | ext4_unwritten_wait(inode); |
@@ -138,10 +133,8 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
138 | goto errout; | 133 | goto errout; |
139 | } | 134 | } |
140 | 135 | ||
141 | if (pos + length > sbi->s_bitmap_maxbytes) { | 136 | if (pos + length > sbi->s_bitmap_maxbytes) |
142 | nr_segs = iov_shorten((struct iovec *)iov, nr_segs, | 137 | iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); |
143 | sbi->s_bitmap_maxbytes - pos); | ||
144 | } | ||
145 | } | 138 | } |
146 | 139 | ||
147 | if (o_direct) { | 140 | if (o_direct) { |
@@ -179,7 +172,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
179 | } | 172 | } |
180 | } | 173 | } |
181 | 174 | ||
182 | ret = __generic_file_aio_write(iocb, iov, nr_segs); | 175 | ret = __generic_file_write_iter(iocb, from); |
183 | mutex_unlock(&inode->i_mutex); | 176 | mutex_unlock(&inode->i_mutex); |
184 | 177 | ||
185 | if (ret > 0) { | 178 | if (ret > 0) { |
@@ -594,9 +587,9 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int whence) | |||
594 | const struct file_operations ext4_file_operations = { | 587 | const struct file_operations ext4_file_operations = { |
595 | .llseek = ext4_llseek, | 588 | .llseek = ext4_llseek, |
596 | .read = new_sync_read, | 589 | .read = new_sync_read, |
597 | .write = do_sync_write, | 590 | .write = new_sync_write, |
598 | .read_iter = generic_file_read_iter, | 591 | .read_iter = generic_file_read_iter, |
599 | .aio_write = ext4_file_write, | 592 | .write_iter = ext4_file_write_iter, |
600 | .unlocked_ioctl = ext4_ioctl, | 593 | .unlocked_ioctl = ext4_ioctl, |
601 | #ifdef CONFIG_COMPAT | 594 | #ifdef CONFIG_COMPAT |
602 | .compat_ioctl = ext4_compat_ioctl, | 595 | .compat_ioctl = ext4_compat_ioctl, |