diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-07-25 17:24:12 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-07-25 17:24:12 -0400 |
commit | a9e5f4d0780ec9cda7a70b08294d7718431b62a1 (patch) | |
tree | f21fa310b6ea63f49cf6d710fcd84fe8d66282f3 | |
parent | 52f341cf75d2da84811127582616984eb0602360 (diff) |
[GFS2] Alter direct I/O path
As per comments received, alter the GFS2 direct I/O path so that
it uses the standard read functions "out of the box". Needs a
small change to one of the VFS functions. This reduces the size
of the code quite a lot and also removes the need for one new export.
Some more work remains to be done, but this is the bones of the
thing.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r-- | fs/gfs2/ops_address.c | 54 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 170 | ||||
-rw-r--r-- | mm/filemap.c | 4 |
3 files changed, 21 insertions, 207 deletions
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 031270ad55e2..d33f6aa79731 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -589,8 +589,9 @@ static void gfs2_invalidatepage(struct page *page, unsigned long offset) | |||
589 | return; | 589 | return; |
590 | } | 590 | } |
591 | 591 | ||
592 | static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, | 592 | static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, |
593 | loff_t offset, unsigned long nr_segs) | 593 | const struct iovec *iov, loff_t offset, |
594 | unsigned long nr_segs) | ||
594 | { | 595 | { |
595 | struct file *file = iocb->ki_filp; | 596 | struct file *file = iocb->ki_filp; |
596 | struct inode *inode = file->f_mapping->host; | 597 | struct inode *inode = file->f_mapping->host; |
@@ -598,8 +599,10 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, | |||
598 | struct gfs2_holder gh; | 599 | struct gfs2_holder gh; |
599 | int rv; | 600 | int rv; |
600 | 601 | ||
602 | if (rw == READ) | ||
603 | mutex_lock(&inode->i_mutex); | ||
601 | /* | 604 | /* |
602 | * Shared lock, even though its write, since we do no allocation | 605 | * Shared lock, even if its a write, since we do no allocation |
603 | * on this path. All we need change is atime. | 606 | * on this path. All we need change is atime. |
604 | */ | 607 | */ |
605 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); | 608 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); |
@@ -607,6 +610,9 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, | |||
607 | if (rv) | 610 | if (rv) |
608 | goto out; | 611 | goto out; |
609 | 612 | ||
613 | if (offset > i_size_read(inode)) | ||
614 | goto out; | ||
615 | |||
610 | /* | 616 | /* |
611 | * Should we return an error here? I can't see that O_DIRECT for | 617 | * Should we return an error here? I can't see that O_DIRECT for |
612 | * a journaled file makes any sense. For now we'll silently fall | 618 | * a journaled file makes any sense. For now we'll silently fall |
@@ -619,48 +625,20 @@ static ssize_t gfs2_direct_IO_write(struct kiocb *iocb, const struct iovec *iov, | |||
619 | if (gfs2_is_stuffed(ip)) | 625 | if (gfs2_is_stuffed(ip)) |
620 | goto out; | 626 | goto out; |
621 | 627 | ||
622 | rv = __blockdev_direct_IO(WRITE, iocb, inode, inode->i_sb->s_bdev, | 628 | rv = blockdev_direct_IO_own_locking(rw, iocb, inode, |
623 | iov, offset, nr_segs, gfs2_get_block, | 629 | inode->i_sb->s_bdev, |
624 | NULL, DIO_OWN_LOCKING); | 630 | iov, offset, nr_segs, |
631 | gfs2_get_block, NULL); | ||
625 | out: | 632 | out: |
626 | gfs2_glock_dq_m(1, &gh); | 633 | gfs2_glock_dq_m(1, &gh); |
627 | gfs2_holder_uninit(&gh); | 634 | gfs2_holder_uninit(&gh); |
635 | if (rw == READ) | ||
636 | mutex_unlock(&inode->i_mutex); | ||
628 | 637 | ||
629 | return rv; | 638 | return rv; |
630 | } | 639 | } |
631 | 640 | ||
632 | /** | 641 | /** |
633 | * gfs2_direct_IO | ||
634 | * | ||
635 | * This is called with a shared lock already held for the read path. | ||
636 | * Currently, no locks are held when the write path is called. | ||
637 | */ | ||
638 | static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | ||
639 | const struct iovec *iov, loff_t offset, | ||
640 | unsigned long nr_segs) | ||
641 | { | ||
642 | struct file *file = iocb->ki_filp; | ||
643 | struct inode *inode = file->f_mapping->host; | ||
644 | struct gfs2_inode *ip = GFS2_I(inode); | ||
645 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
646 | int ret; | ||
647 | |||
648 | if (rw == WRITE) | ||
649 | return gfs2_direct_IO_write(iocb, iov, offset, nr_segs); | ||
650 | |||
651 | if (gfs2_assert_warn(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)) || | ||
652 | gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip))) | ||
653 | return -EINVAL; | ||
654 | |||
655 | mutex_lock(&inode->i_mutex); | ||
656 | ret = __blockdev_direct_IO(READ, iocb, inode, inode->i_sb->s_bdev, iov, | ||
657 | offset, nr_segs, gfs2_get_block, NULL, | ||
658 | DIO_OWN_LOCKING); | ||
659 | mutex_unlock(&inode->i_mutex); | ||
660 | return ret; | ||
661 | } | ||
662 | |||
663 | /** | ||
664 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. | 642 | * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out. |
665 | * @bh: the buffer we're stuck on | 643 | * @bh: the buffer we're stuck on |
666 | * | 644 | * |
@@ -765,7 +743,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask) | |||
765 | } | 743 | } |
766 | while (bh != head); | 744 | while (bh != head); |
767 | 745 | ||
768 | out: | 746 | out: |
769 | return try_to_free_buffers(page); | 747 | return try_to_free_buffers(page); |
770 | } | 748 | } |
771 | 749 | ||
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 6764ca69bc52..d13e04e8a96a 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -148,170 +148,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) | |||
148 | return error; | 148 | return error; |
149 | } | 149 | } |
150 | 150 | ||
151 | |||
152 | static ssize_t gfs2_direct_IO_read(struct kiocb *iocb, const struct iovec *iov, | ||
153 | loff_t offset, unsigned long nr_segs) | ||
154 | { | ||
155 | struct file *file = iocb->ki_filp; | ||
156 | struct address_space *mapping = file->f_mapping; | ||
157 | ssize_t retval; | ||
158 | |||
159 | retval = filemap_write_and_wait(mapping); | ||
160 | if (retval == 0) { | ||
161 | retval = mapping->a_ops->direct_IO(READ, iocb, iov, offset, | ||
162 | nr_segs); | ||
163 | } | ||
164 | return retval; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * __gfs2_file_aio_read - The main GFS2 read function | ||
169 | * | ||
170 | * N.B. This is almost, but not quite the same as __generic_file_aio_read() | ||
171 | * the important subtle different being that inode->i_size isn't valid | ||
172 | * unless we are holding a lock, and we do this _only_ on the O_DIRECT | ||
173 | * path since otherwise locking is done entirely at the page cache | ||
174 | * layer. | ||
175 | */ | ||
176 | static ssize_t __gfs2_file_aio_read(struct kiocb *iocb, | ||
177 | const struct iovec *iov, | ||
178 | unsigned long nr_segs, loff_t *ppos) | ||
179 | { | ||
180 | struct file *filp = iocb->ki_filp; | ||
181 | struct gfs2_inode *ip = GFS2_I(filp->f_mapping->host); | ||
182 | struct gfs2_holder gh; | ||
183 | ssize_t retval; | ||
184 | unsigned long seg; | ||
185 | size_t count; | ||
186 | |||
187 | count = 0; | ||
188 | for (seg = 0; seg < nr_segs; seg++) { | ||
189 | const struct iovec *iv = &iov[seg]; | ||
190 | |||
191 | /* | ||
192 | * If any segment has a negative length, or the cumulative | ||
193 | * length ever wraps negative then return -EINVAL. | ||
194 | */ | ||
195 | count += iv->iov_len; | ||
196 | if (unlikely((ssize_t)(count|iv->iov_len) < 0)) | ||
197 | return -EINVAL; | ||
198 | if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len)) | ||
199 | continue; | ||
200 | if (seg == 0) | ||
201 | return -EFAULT; | ||
202 | nr_segs = seg; | ||
203 | count -= iv->iov_len; /* This segment is no good */ | ||
204 | break; | ||
205 | } | ||
206 | |||
207 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | ||
208 | if (filp->f_flags & O_DIRECT) { | ||
209 | loff_t pos = *ppos, size; | ||
210 | struct address_space *mapping; | ||
211 | struct inode *inode; | ||
212 | |||
213 | mapping = filp->f_mapping; | ||
214 | inode = mapping->host; | ||
215 | retval = 0; | ||
216 | if (!count) | ||
217 | goto out; /* skip atime */ | ||
218 | |||
219 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh); | ||
220 | retval = gfs2_glock_nq_m_atime(1, &gh); | ||
221 | if (retval) | ||
222 | goto out; | ||
223 | if (gfs2_is_stuffed(ip)) { | ||
224 | gfs2_glock_dq_m(1, &gh); | ||
225 | gfs2_holder_uninit(&gh); | ||
226 | goto fallback_to_normal; | ||
227 | } | ||
228 | size = i_size_read(inode); | ||
229 | if (pos < size) { | ||
230 | retval = gfs2_direct_IO_read(iocb, iov, pos, nr_segs); | ||
231 | if (retval > 0 && !is_sync_kiocb(iocb)) | ||
232 | retval = -EIOCBQUEUED; | ||
233 | if (retval > 0) | ||
234 | *ppos = pos + retval; | ||
235 | } | ||
236 | file_accessed(filp); | ||
237 | gfs2_glock_dq_m(1, &gh); | ||
238 | gfs2_holder_uninit(&gh); | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | fallback_to_normal: | ||
243 | retval = 0; | ||
244 | if (count) { | ||
245 | for (seg = 0; seg < nr_segs; seg++) { | ||
246 | read_descriptor_t desc; | ||
247 | |||
248 | desc.written = 0; | ||
249 | desc.arg.buf = iov[seg].iov_base; | ||
250 | desc.count = iov[seg].iov_len; | ||
251 | if (desc.count == 0) | ||
252 | continue; | ||
253 | desc.error = 0; | ||
254 | do_generic_file_read(filp,ppos,&desc,file_read_actor); | ||
255 | retval += desc.written; | ||
256 | if (desc.error) { | ||
257 | retval = retval ?: desc.error; | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | out: | ||
263 | return retval; | ||
264 | } | ||
265 | |||
266 | /** | ||
267 | * gfs2_read - Read bytes from a file | ||
268 | * @file: The file to read from | ||
269 | * @buf: The buffer to copy into | ||
270 | * @size: The amount of data requested | ||
271 | * @offset: The current file offset | ||
272 | * | ||
273 | * Outputs: Offset - updated according to number of bytes read | ||
274 | * | ||
275 | * Returns: The number of bytes read, errno on failure | ||
276 | */ | ||
277 | |||
278 | static ssize_t gfs2_read(struct file *filp, char __user *buf, size_t size, | ||
279 | loff_t *offset) | ||
280 | { | ||
281 | struct iovec local_iov = { .iov_base = buf, .iov_len = size }; | ||
282 | struct kiocb kiocb; | ||
283 | ssize_t ret; | ||
284 | |||
285 | init_sync_kiocb(&kiocb, filp); | ||
286 | ret = __gfs2_file_aio_read(&kiocb, &local_iov, 1, offset); | ||
287 | if (-EIOCBQUEUED == ret) | ||
288 | ret = wait_on_sync_kiocb(&kiocb); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | static ssize_t gfs2_file_readv(struct file *filp, const struct iovec *iov, | ||
293 | unsigned long nr_segs, loff_t *ppos) | ||
294 | { | ||
295 | struct kiocb kiocb; | ||
296 | ssize_t ret; | ||
297 | |||
298 | init_sync_kiocb(&kiocb, filp); | ||
299 | ret = __gfs2_file_aio_read(&kiocb, iov, nr_segs, ppos); | ||
300 | if (-EIOCBQUEUED == ret) | ||
301 | ret = wait_on_sync_kiocb(&kiocb); | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | static ssize_t gfs2_file_aio_read(struct kiocb *iocb, char __user *buf, | ||
306 | size_t count, loff_t pos) | ||
307 | { | ||
308 | struct iovec local_iov = { .iov_base = buf, .iov_len = count }; | ||
309 | |||
310 | BUG_ON(iocb->ki_pos != pos); | ||
311 | return __gfs2_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | 151 | /** |
316 | * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() | 152 | * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() |
317 | * @opaque: opaque data used by the function | 153 | * @opaque: opaque data used by the function |
@@ -949,9 +785,9 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl) | |||
949 | 785 | ||
950 | const struct file_operations gfs2_file_fops = { | 786 | const struct file_operations gfs2_file_fops = { |
951 | .llseek = gfs2_llseek, | 787 | .llseek = gfs2_llseek, |
952 | .read = gfs2_read, | 788 | .read = generic_file_read, |
953 | .readv = gfs2_file_readv, | 789 | .readv = generic_file_readv, |
954 | .aio_read = gfs2_file_aio_read, | 790 | .aio_read = generic_file_aio_read, |
955 | .write = generic_file_write, | 791 | .write = generic_file_write, |
956 | .writev = generic_file_writev, | 792 | .writev = generic_file_writev, |
957 | .aio_write = generic_file_aio_write, | 793 | .aio_write = generic_file_aio_write, |
diff --git a/mm/filemap.c b/mm/filemap.c index b9c91ab7f0f8..a92d690b3ae5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1122,7 +1122,6 @@ success: | |||
1122 | desc->arg.buf += size; | 1122 | desc->arg.buf += size; |
1123 | return size; | 1123 | return size; |
1124 | } | 1124 | } |
1125 | EXPORT_SYMBOL_GPL(file_read_actor); | ||
1126 | 1125 | ||
1127 | /** | 1126 | /** |
1128 | * __generic_file_aio_read - generic filesystem read routine | 1127 | * __generic_file_aio_read - generic filesystem read routine |
@@ -1184,7 +1183,8 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
1184 | *ppos = pos + retval; | 1183 | *ppos = pos + retval; |
1185 | } | 1184 | } |
1186 | file_accessed(filp); | 1185 | file_accessed(filp); |
1187 | goto out; | 1186 | if (retval != 0) |
1187 | goto out; | ||
1188 | } | 1188 | } |
1189 | 1189 | ||
1190 | retval = 0; | 1190 | retval = 0; |