aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/page-io.c
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 /fs/ext4/page-io.c
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>
Diffstat (limited to 'fs/ext4/page-io.c')
-rw-r--r--fs/ext4/page-io.c121
1 files changed, 45 insertions, 76 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 5929cd0baa20..6626aba57ebb 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -61,28 +61,15 @@ void ext4_ioend_shutdown(struct inode *inode)
61 cancel_work_sync(&EXT4_I(inode)->i_unwritten_work); 61 cancel_work_sync(&EXT4_I(inode)->i_unwritten_work);
62} 62}
63 63
64static void ext4_release_io_end(ext4_io_end_t *io_end) 64void ext4_free_io_end(ext4_io_end_t *io)
65{ 65{
66 BUG_ON(!list_empty(&io_end->list)); 66 BUG_ON(!io);
67 BUG_ON(io_end->flag & EXT4_IO_END_UNWRITTEN); 67 BUG_ON(!list_empty(&io->list));
68 68 BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN);
69 if (atomic_dec_and_test(&EXT4_I(io_end->inode)->i_ioend_count))
70 wake_up_all(ext4_ioend_wq(io_end->inode));
71 if (io_end->flag & EXT4_IO_END_DIRECT)
72 inode_dio_done(io_end->inode);
73 if (io_end->iocb)
74 aio_complete(io_end->iocb, io_end->result, 0);
75 kmem_cache_free(io_end_cachep, io_end);
76}
77
78static void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
79{
80 struct inode *inode = io_end->inode;
81 69
82 io_end->flag &= ~EXT4_IO_END_UNWRITTEN; 70 if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count))
83 /* Wake up anyone waiting on unwritten extent conversion */ 71 wake_up_all(ext4_ioend_wq(io->inode));
84 if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) 72 kmem_cache_free(io_end_cachep, io);
85 wake_up_all(ext4_ioend_wq(inode));
86} 73}
87 74
88/* check a range of space and convert unwritten extents to written. */ 75/* check a range of space and convert unwritten extents to written. */
@@ -105,8 +92,13 @@ static int ext4_end_io(ext4_io_end_t *io)
105 "(inode %lu, offset %llu, size %zd, error %d)", 92 "(inode %lu, offset %llu, size %zd, error %d)",
106 inode->i_ino, offset, size, ret); 93 inode->i_ino, offset, size, ret);
107 } 94 }
108 ext4_clear_io_unwritten_flag(io); 95 /* Wake up anyone waiting on unwritten extent conversion */
109 ext4_release_io_end(io); 96 if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten))
97 wake_up_all(ext4_ioend_wq(inode));
98 if (io->flag & EXT4_IO_END_DIRECT)
99 inode_dio_done(inode);
100 if (io->iocb)
101 aio_complete(io->iocb, io->result, 0);
110 return ret; 102 return ret;
111} 103}
112 104
@@ -137,7 +129,7 @@ static void dump_completed_IO(struct inode *inode)
137} 129}
138 130
139/* Add the io_end to per-inode completed end_io list. */ 131/* Add the io_end to per-inode completed end_io list. */
140static void ext4_add_complete_io(ext4_io_end_t *io_end) 132void ext4_add_complete_io(ext4_io_end_t *io_end)
141{ 133{
142 struct ext4_inode_info *ei = EXT4_I(io_end->inode); 134 struct ext4_inode_info *ei = EXT4_I(io_end->inode);
143 struct workqueue_struct *wq; 135 struct workqueue_struct *wq;
@@ -174,6 +166,8 @@ static int ext4_do_flush_completed_IO(struct inode *inode)
174 err = ext4_end_io(io); 166 err = ext4_end_io(io);
175 if (unlikely(!ret && err)) 167 if (unlikely(!ret && err))
176 ret = err; 168 ret = err;
169 io->flag &= ~EXT4_IO_END_UNWRITTEN;
170 ext4_free_io_end(io);
177 } 171 }
178 return ret; 172 return ret;
179} 173}
@@ -205,43 +199,10 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
205 atomic_inc(&EXT4_I(inode)->i_ioend_count); 199 atomic_inc(&EXT4_I(inode)->i_ioend_count);
206 io->inode = inode; 200 io->inode = inode;
207 INIT_LIST_HEAD(&io->list); 201 INIT_LIST_HEAD(&io->list);
208 atomic_set(&io->count, 1);
209 } 202 }
210 return io; 203 return io;
211} 204}
212 205
213void ext4_put_io_end_defer(ext4_io_end_t *io_end)
214{
215 if (atomic_dec_and_test(&io_end->count)) {
216 if (!(io_end->flag & EXT4_IO_END_UNWRITTEN) || !io_end->size) {
217 ext4_release_io_end(io_end);
218 return;
219 }
220 ext4_add_complete_io(io_end);
221 }
222}
223
224int ext4_put_io_end(ext4_io_end_t *io_end)
225{
226 int err = 0;
227
228 if (atomic_dec_and_test(&io_end->count)) {
229 if (io_end->flag & EXT4_IO_END_UNWRITTEN) {
230 err = ext4_convert_unwritten_extents(io_end->inode,
231 io_end->offset, io_end->size);
232 ext4_clear_io_unwritten_flag(io_end);
233 }
234 ext4_release_io_end(io_end);
235 }
236 return err;
237}
238
239ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end)
240{
241 atomic_inc(&io_end->count);
242 return io_end;
243}
244
245/* 206/*
246 * Print an buffer I/O error compatible with the fs/buffer.c. This 207 * Print an buffer I/O error compatible with the fs/buffer.c. This
247 * provides compatibility with dmesg scrapers that look for a specific 208 * provides compatibility with dmesg scrapers that look for a specific
@@ -324,7 +285,12 @@ static void ext4_end_bio(struct bio *bio, int error)
324 bi_sector >> (inode->i_blkbits - 9)); 285 bi_sector >> (inode->i_blkbits - 9));
325 } 286 }
326 287
327 ext4_put_io_end_defer(io_end); 288 if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
289 ext4_free_io_end(io_end);
290 return;
291 }
292
293 ext4_add_complete_io(io_end);
328} 294}
329 295
330void ext4_io_submit(struct ext4_io_submit *io) 296void ext4_io_submit(struct ext4_io_submit *io)
@@ -338,37 +304,40 @@ void ext4_io_submit(struct ext4_io_submit *io)
338 bio_put(io->io_bio); 304 bio_put(io->io_bio);
339 } 305 }
340 io->io_bio = NULL; 306 io->io_bio = NULL;
341} 307 io->io_op = 0;
342
343void ext4_io_submit_init(struct ext4_io_submit *io,
344 struct writeback_control *wbc)
345{
346 io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
347 io->io_bio = NULL;
348 io->io_end = NULL; 308 io->io_end = NULL;
349} 309}
350 310
351static int io_submit_init_bio(struct ext4_io_submit *io, 311static int io_submit_init(struct ext4_io_submit *io,
352 struct buffer_head *bh) 312 struct inode *inode,
313 struct writeback_control *wbc,
314 struct buffer_head *bh)
353{ 315{
316 ext4_io_end_t *io_end;
317 struct page *page = bh->b_page;
354 int nvecs = bio_get_nr_vecs(bh->b_bdev); 318 int nvecs = bio_get_nr_vecs(bh->b_bdev);
355 struct bio *bio; 319 struct bio *bio;
356 320
321 io_end = ext4_init_io_end(inode, GFP_NOFS);
322 if (!io_end)
323 return -ENOMEM;
357 bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); 324 bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
358 bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); 325 bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
359 bio->bi_bdev = bh->b_bdev; 326 bio->bi_bdev = bh->b_bdev;
327 bio->bi_private = io->io_end = io_end;
360 bio->bi_end_io = ext4_end_bio; 328 bio->bi_end_io = ext4_end_bio;
361 bio->bi_private = ext4_get_io_end(io->io_end); 329
362 if (!io->io_end->size) 330 io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
363 io->io_end->offset = (bh->b_page->index << PAGE_CACHE_SHIFT) 331
364 + bh_offset(bh);
365 io->io_bio = bio; 332 io->io_bio = bio;
333 io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
366 io->io_next_block = bh->b_blocknr; 334 io->io_next_block = bh->b_blocknr;
367 return 0; 335 return 0;
368} 336}
369 337
370static int io_submit_add_bh(struct ext4_io_submit *io, 338static int io_submit_add_bh(struct ext4_io_submit *io,
371 struct inode *inode, 339 struct inode *inode,
340 struct writeback_control *wbc,
372 struct buffer_head *bh) 341 struct buffer_head *bh)
373{ 342{
374 ext4_io_end_t *io_end; 343 ext4_io_end_t *io_end;
@@ -379,18 +348,18 @@ submit_and_retry:
379 ext4_io_submit(io); 348 ext4_io_submit(io);
380 } 349 }
381 if (io->io_bio == NULL) { 350 if (io->io_bio == NULL) {
382 ret = io_submit_init_bio(io, bh); 351 ret = io_submit_init(io, inode, wbc, bh);
383 if (ret) 352 if (ret)
384 return ret; 353 return ret;
385 } 354 }
386 ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
387 if (ret != bh->b_size)
388 goto submit_and_retry;
389 io_end = io->io_end; 355 io_end = io->io_end;
390 if (test_clear_buffer_uninit(bh)) 356 if (test_clear_buffer_uninit(bh))
391 ext4_set_io_unwritten_flag(inode, io_end); 357 ext4_set_io_unwritten_flag(inode, io_end);
392 io_end->size += bh->b_size; 358 io->io_end->size += bh->b_size;
393 io->io_next_block++; 359 io->io_next_block++;
360 ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
361 if (ret != bh->b_size)
362 goto submit_and_retry;
394 return 0; 363 return 0;
395} 364}
396 365
@@ -462,7 +431,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
462 do { 431 do {
463 if (!buffer_async_write(bh)) 432 if (!buffer_async_write(bh))
464 continue; 433 continue;
465 ret = io_submit_add_bh(io, inode, bh); 434 ret = io_submit_add_bh(io, inode, wbc, bh);
466 if (ret) { 435 if (ret) {
467 /* 436 /*
468 * We only get here on ENOMEM. Not much else 437 * We only get here on ENOMEM. Not much else