aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-05-11 19:07:42 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-05-11 19:07:42 -0400
commita549984b8c95acbecefd1fdd4bfdbea4d29b0588 (patch)
treeeb25bf90acc6c084de08616ebb26ee091158c46e
parente6155736ad76b2070652745f9e54cdea3f0d8567 (diff)
ext4: revert "ext4: use io_end for multiple bios"
This reverts commit 4eec708d263f0ee10861d69251708a225b64cac7. Multiple users have reported crashes which is apparently caused by this commit. Thanks to Dmitry Monakhov for bisecting it. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: Dmitry Monakhov <dmonakhov@openvz.org> Cc: Jan Kara <jack@suse.cz>
-rw-r--r--fs/ext4/ext4.h8
-rw-r--r--fs/ext4/inode.c85
-rw-r--r--fs/ext4/page-io.c121
3 files changed, 85 insertions, 129 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0aabb344b02e..5aae3d12d400 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -209,7 +209,6 @@ typedef struct ext4_io_end {
209 ssize_t size; /* size of the extent */ 209 ssize_t size; /* size of the extent */
210 struct kiocb *iocb; /* iocb struct for AIO */ 210 struct kiocb *iocb; /* iocb struct for AIO */
211 int result; /* error value for AIO */ 211 int result; /* error value for AIO */
212 atomic_t count; /* reference counter */
213} ext4_io_end_t; 212} ext4_io_end_t;
214 213
215struct ext4_io_submit { 214struct ext4_io_submit {
@@ -2651,14 +2650,11 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
2651 2650
2652/* page-io.c */ 2651/* page-io.c */
2653extern int __init ext4_init_pageio(void); 2652extern int __init ext4_init_pageio(void);
2653extern void ext4_add_complete_io(ext4_io_end_t *io_end);
2654extern void ext4_exit_pageio(void); 2654extern void ext4_exit_pageio(void);
2655extern void ext4_ioend_shutdown(struct inode *); 2655extern void ext4_ioend_shutdown(struct inode *);
2656extern void ext4_free_io_end(ext4_io_end_t *io);
2656extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags); 2657extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
2657extern ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end);
2658extern int ext4_put_io_end(ext4_io_end_t *io_end);
2659extern void ext4_put_io_end_defer(ext4_io_end_t *io_end);
2660extern void ext4_io_submit_init(struct ext4_io_submit *io,
2661 struct writeback_control *wbc);
2662extern void ext4_end_io_work(struct work_struct *work); 2658extern void ext4_end_io_work(struct work_struct *work);
2663extern void ext4_io_submit(struct ext4_io_submit *io); 2659extern void ext4_io_submit(struct ext4_io_submit *io);
2664extern int ext4_bio_write_page(struct ext4_io_submit *io, 2660extern int ext4_bio_write_page(struct ext4_io_submit *io,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 793d44b84d7f..d66656992358 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1487,10 +1487,7 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
1487 struct ext4_io_submit io_submit; 1487 struct ext4_io_submit io_submit;
1488 1488
1489 BUG_ON(mpd->next_page <= mpd->first_page); 1489 BUG_ON(mpd->next_page <= mpd->first_page);
1490 ext4_io_submit_init(&io_submit, mpd->wbc); 1490 memset(&io_submit, 0, sizeof(io_submit));
1491 io_submit.io_end = ext4_init_io_end(inode, GFP_NOFS);
1492 if (!io_submit.io_end)
1493 return -ENOMEM;
1494 /* 1491 /*
1495 * We need to start from the first_page to the next_page - 1 1492 * We need to start from the first_page to the next_page - 1
1496 * to make sure we also write the mapped dirty buffer_heads. 1493 * to make sure we also write the mapped dirty buffer_heads.
@@ -1578,8 +1575,6 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
1578 pagevec_release(&pvec); 1575 pagevec_release(&pvec);
1579 } 1576 }
1580 ext4_io_submit(&io_submit); 1577 ext4_io_submit(&io_submit);
1581 /* Drop io_end reference we got from init */
1582 ext4_put_io_end_defer(io_submit.io_end);
1583 return ret; 1578 return ret;
1584} 1579}
1585 1580
@@ -2238,16 +2233,9 @@ static int ext4_writepage(struct page *page,
2238 */ 2233 */
2239 return __ext4_journalled_writepage(page, len); 2234 return __ext4_journalled_writepage(page, len);
2240 2235
2241 ext4_io_submit_init(&io_submit, wbc); 2236 memset(&io_submit, 0, sizeof(io_submit));
2242 io_submit.io_end = ext4_init_io_end(inode, GFP_NOFS);
2243 if (!io_submit.io_end) {
2244 redirty_page_for_writepage(wbc, page);
2245 return -ENOMEM;
2246 }
2247 ret = ext4_bio_write_page(&io_submit, page, len, wbc); 2237 ret = ext4_bio_write_page(&io_submit, page, len, wbc);
2248 ext4_io_submit(&io_submit); 2238 ext4_io_submit(&io_submit);
2249 /* Drop io_end reference we got from init */
2250 ext4_put_io_end_defer(io_submit.io_end);
2251 return ret; 2239 return ret;
2252} 2240}
2253 2241
@@ -3078,13 +3066,9 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
3078 struct inode *inode = file_inode(iocb->ki_filp); 3066 struct inode *inode = file_inode(iocb->ki_filp);
3079 ext4_io_end_t *io_end = iocb->private; 3067 ext4_io_end_t *io_end = iocb->private;
3080 3068
3081 /* if not async direct IO just return */ 3069 /* if not async direct IO or dio with 0 bytes write, just return */
3082 if (!io_end) { 3070 if (!io_end || !size)
3083 inode_dio_done(inode); 3071 goto out;
3084 if (is_async)
3085 aio_complete(iocb, ret, 0);
3086 return;
3087 }
3088 3072
3089 ext_debug("ext4_end_io_dio(): io_end 0x%p " 3073 ext_debug("ext4_end_io_dio(): io_end 0x%p "
3090 "for inode %lu, iocb 0x%p, offset %llu, size %zd\n", 3074 "for inode %lu, iocb 0x%p, offset %llu, size %zd\n",
@@ -3092,13 +3076,25 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
3092 size); 3076 size);
3093 3077
3094 iocb->private = NULL; 3078 iocb->private = NULL;
3079
3080 /* if not aio dio with unwritten extents, just free io and return */
3081 if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
3082 ext4_free_io_end(io_end);
3083out:
3084 inode_dio_done(inode);
3085 if (is_async)
3086 aio_complete(iocb, ret, 0);
3087 return;
3088 }
3089
3095 io_end->offset = offset; 3090 io_end->offset = offset;
3096 io_end->size = size; 3091 io_end->size = size;
3097 if (is_async) { 3092 if (is_async) {
3098 io_end->iocb = iocb; 3093 io_end->iocb = iocb;
3099 io_end->result = ret; 3094 io_end->result = ret;
3100 } 3095 }
3101 ext4_put_io_end_defer(io_end); 3096
3097 ext4_add_complete_io(io_end);
3102} 3098}
3103 3099
3104/* 3100/*
@@ -3132,7 +3128,6 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
3132 get_block_t *get_block_func = NULL; 3128 get_block_t *get_block_func = NULL;
3133 int dio_flags = 0; 3129 int dio_flags = 0;
3134 loff_t final_size = offset + count; 3130 loff_t final_size = offset + count;
3135 ext4_io_end_t *io_end = NULL;
3136 3131
3137 /* Use the old path for reads and writes beyond i_size. */ 3132 /* Use the old path for reads and writes beyond i_size. */
3138 if (rw != WRITE || final_size > inode->i_size) 3133 if (rw != WRITE || final_size > inode->i_size)
@@ -3171,16 +3166,13 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
3171 iocb->private = NULL; 3166 iocb->private = NULL;
3172 ext4_inode_aio_set(inode, NULL); 3167 ext4_inode_aio_set(inode, NULL);
3173 if (!is_sync_kiocb(iocb)) { 3168 if (!is_sync_kiocb(iocb)) {
3174 io_end = ext4_init_io_end(inode, GFP_NOFS); 3169 ext4_io_end_t *io_end = ext4_init_io_end(inode, GFP_NOFS);
3175 if (!io_end) { 3170 if (!io_end) {
3176 ret = -ENOMEM; 3171 ret = -ENOMEM;
3177 goto retake_lock; 3172 goto retake_lock;
3178 } 3173 }
3179 io_end->flag |= EXT4_IO_END_DIRECT; 3174 io_end->flag |= EXT4_IO_END_DIRECT;
3180 /* 3175 iocb->private = io_end;
3181 * Grab reference for DIO. Will be dropped in ext4_end_io_dio()
3182 */
3183 iocb->private = ext4_get_io_end(io_end);
3184 /* 3176 /*
3185 * we save the io structure for current async direct 3177 * we save the io structure for current async direct
3186 * IO, so that later ext4_map_blocks() could flag the 3178 * IO, so that later ext4_map_blocks() could flag the
@@ -3204,27 +3196,26 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
3204 NULL, 3196 NULL,
3205 dio_flags); 3197 dio_flags);
3206 3198
3199 if (iocb->private)
3200 ext4_inode_aio_set(inode, NULL);
3207 /* 3201 /*
3208 * Put our reference to io_end. This can free the io_end structure e.g. 3202 * The io_end structure takes a reference to the inode, that
3209 * in sync IO case or in case of error. It can even perform extent 3203 * structure needs to be destroyed and the reference to the
3210 * conversion if all bios we submitted finished before we got here. 3204 * inode need to be dropped, when IO is complete, even with 0
3211 * Note that in that case iocb->private can be already set to NULL 3205 * byte write, or failed.
3212 * here. 3206 *
3207 * In the successful AIO DIO case, the io_end structure will
3208 * be destroyed and the reference to the inode will be dropped
3209 * after the end_io call back function is called.
3210 *
3211 * In the case there is 0 byte write, or error case, since VFS
3212 * direct IO won't invoke the end_io call back function, we
3213 * need to free the end_io structure here.
3213 */ 3214 */
3214 if (io_end) { 3215 if (ret != -EIOCBQUEUED && ret <= 0 && iocb->private) {
3215 ext4_inode_aio_set(inode, NULL); 3216