diff options
author | Zach Brown <zach.brown@oracle.com> | 2010-10-22 12:56:59 -0700 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-01-24 16:17:46 -0500 |
commit | fecba4f36954053d98eeb86a466bd74876e170dc (patch) | |
tree | 1b4ad592612cf2c0e7d75dfc9c20f05259ebd900 | |
parent | 45c8ab1ea075e32ed76f80bdfc115f4e4210f79c (diff) | |
download | linux-test-odirectloop.tar.gz |
ext3: add support for .read_iter and .write_iterodirectloop
ext3 uses the generic .read_iter and .write_iter functions.
ext3_direct_IO() is refactored in to helpers which are called by the
.direct_IO{,bvec}() methods which call __blockdev_direct_IO{,_bvec}().
Signed-off-by: Zach Brown <zach.brown@oracle.com>
(cherry picked from commit 7033fac02ea52fe425545c70f260abaf667f7093)
-rw-r--r-- | fs/ext3/file.c | 2 | ||||
-rw-r--r-- | fs/ext3/inode.c | 145 |
2 files changed, 103 insertions, 44 deletions
diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 388bbdfa0b4e0..4838e609ba385 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -57,6 +57,8 @@ const struct file_operations ext3_file_operations = { .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .unlocked_ioctl = ext3_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext3_compat_ioctl, diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index f9d69378caaae..effb39f72e96c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1728,6 +1728,69 @@ static int ext3_releasepage(struct page *page, gfp_t wait) return journal_try_to_free_buffers(journal, page, wait); } +static ssize_t ext3_journal_orphan_add(struct inode *inode) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + handle_t *handle; + ssize_t ret; + + /* Credits for sb + inode write */ + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } + ret = ext3_orphan_add(handle, inode); + if (ret) { + ext3_journal_stop(handle); + goto out; + } + ei->i_disksize = inode->i_size; + ext3_journal_stop(handle); +out: + return ret; +} + +static ssize_t ext3_journal_orphan_del(struct inode *inode, ssize_t ret, + loff_t offset) +{ + struct ext3_inode_info *ei = EXT3_I(inode); + handle_t *handle; + int err; + + /* Credits for sb + inode write */ + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) { + /* This is really bad luck. We've written the data + * but cannot extend i_size. Bail out and pretend + * the write failed... */ + ret = PTR_ERR(handle); + goto out; + } + if (inode->i_nlink) + ext3_orphan_del(handle, inode); + if (ret > 0) { + loff_t end = offset + ret; + if (end > inode->i_size) { + ei->i_disksize = end; + i_size_write(inode, end); + /* + * We're going to return a positive `ret' + * here due to non-zero-length I/O, so there's + * no way of reporting error returns from + * ext3_mark_inode_dirty() to userspace. So + * ignore it. + */ + ext3_mark_inode_dirty(handle, inode); + } + } + err = ext3_journal_stop(handle); + if (ret == 0) + ret = err; +out: + return ret; +} + /* * If the O_DIRECT write will extend the file then add this inode to the * orphan list. So recovery will truncate it back to the original size @@ -1743,8 +1806,6 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct ext3_inode_info *ei = EXT3_I(inode); - handle_t *handle; ssize_t ret; int orphan = 0; size_t count = iov_length(iov, nr_segs); @@ -1754,20 +1815,10 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, loff_t final_size = offset + count; if (final_size > inode->i_size) { - /* Credits for sb + inode write */ - handle = ext3_journal_start(inode, 2); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); + ret = ext3_journal_orphan_add(inode); + if (ret) goto out; - } - ret = ext3_orphan_add(handle, inode); - if (ret) { - ext3_journal_stop(handle); - goto out; - } orphan = 1; - ei->i_disksize = inode->i_size; - ext3_journal_stop(handle); } } @@ -1778,39 +1829,43 @@ retry: if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) goto retry; - if (orphan) { - int err; + if (orphan) + ret = ext3_journal_orphan_del(inode, ret, offset); +out: + return ret; +} - /* Credits for sb + inode write */ - handle = ext3_journal_start(inode, 2); - if (IS_ERR(handle)) { - /* This is really bad luck. We've written the data - * but cannot extend i_size. Bail out and pretend - * the write failed... */ - ret = PTR_ERR(handle); - goto out; - } - if (inode->i_nlink) - ext3_orphan_del(handle, inode); - if (ret > 0) { - loff_t end = offset + ret; - if (end > inode->i_size) { - ei->i_disksize = end; - i_size_write(inode, end); - /* - * We're going to return a positive `ret' - * here due to non-zero-length I/O, so there's - * no way of reporting error returns from - * ext3_mark_inode_dirty() to userspace. So - * ignore it. - */ - ext3_mark_inode_dirty(handle, inode); - } +static ssize_t ext3_direct_IO_bvec(int rw, struct kiocb *iocb, + struct bio_vec *bvec, loff_t offset, + unsigned long bvec_len) +{ + struct file *file = iocb->ki_filp; + struct inode *inode = file->f_mapping->host; + ssize_t ret; + int orphan = 0; + size_t count = bvec_length(bvec, bvec_len); + int retries = 0; + + if (rw == WRITE) { + loff_t final_size = offset + count; + + if (final_size > inode->i_size) { + ret = ext3_journal_orphan_add(inode); + if (ret) + goto out; + orphan = 1; } - err = ext3_journal_stop(handle); - if (ret == 0) - ret = err; } + +retry: + ret = blockdev_direct_IO_bvec(rw, iocb, inode, inode->i_sb->s_bdev, + bvec, offset, bvec_len, ext3_get_block, + NULL); + if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + + if (orphan) + ret = ext3_journal_orphan_del(inode, ret, offset); out: return ret; } @@ -1845,6 +1900,7 @@ static const struct address_space_operations ext3_ordered_aops = { .invalidatepage = ext3_invalidatepage, .releasepage = ext3_releasepage, .direct_IO = ext3_direct_IO, + .direct_IO_bvec = ext3_direct_IO_bvec, .migratepage = buffer_migrate_page, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, @@ -1861,6 +1917,7 @@ static const struct address_space_operations ext3_writeback_aops = { .invalidatepage = ext3_invalidatepage, .releasepage = ext3_releasepage, .direct_IO = ext3_direct_IO, + .direct_IO_bvec = ext3_direct_IO_bvec, .migratepage = buffer_migrate_page, .is_partially_uptodate = block_is_partially_uptodate, .error_remove_page = generic_error_remove_page, |