aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/page-io.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2013-04-11 23:56:53 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-04-11 23:56:53 -0400
commit4eec708d263f0ee10861d69251708a225b64cac7 (patch)
tree2db2d3f0431d98ed83d7e7ad8fbeaca7d7a2dcc2 /fs/ext4/page-io.c
parent0058f9658c94037173f7603fc8bae2007cc10253 (diff)
ext4: use io_end for multiple bios
Change writeback path to create just one io_end structure for the extent to which we submit IO and share it among bios writing that extent. This prevents needless splitting and joining of unwritten extents when they cannot be submitted as a single bio. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reviewed-by: Dmitry Monakhov <dmonakhov@openvz.org> Reviewed-by: Zheng Liu <wenqing.lz@taobao.com>
Diffstat (limited to 'fs/ext4/page-io.c')
-rw-r--r--fs/ext4/page-io.c121
1 files changed, 75 insertions, 46 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 1d98fcfc2ff0..14f9837350d1 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -61,17 +61,28 @@ 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
64void ext4_free_io_end(ext4_io_end_t *io) 64static void ext4_release_io_end(ext4_io_end_t *io_end)
65{ 65{
66 int i; 66 BUG_ON(!list_empty(&io_end->list));
67 BUG_ON(io_end->flag & EXT4_IO_END_UNWRITTEN);
68
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}
67 77
68 BUG_ON(!io); 78static void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
69 BUG_ON(!list_empty(&io->list)); 79{
70 BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); 80 struct inode *inode = io_end->inode;
71 81
72 if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count)) 82 io_end->flag &= ~EXT4_IO_END_UNWRITTEN;
73 wake_up_all(ext4_ioend_wq(io->inode)); 83 /* Wake up anyone waiting on unwritten extent conversion */
74 kmem_cache_free(io_end_cachep, io); 84 if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten))
85 wake_up_all(ext4_ioend_wq(inode));
75} 86}
76 87
77/* check a range of space and convert unwritten extents to written. */ 88/* check a range of space and convert unwritten extents to written. */
@@ -94,13 +105,8 @@ static int ext4_end_io(ext4_io_end_t *io)
94 "(inode %lu, offset %llu, size %zd, error %d)", 105 "(inode %lu, offset %llu, size %zd, error %d)",
95 inode->i_ino, offset, size, ret); 106 inode->i_ino, offset, size, ret);
96 } 107 }
97 /* Wake up anyone waiting on unwritten extent conversion */ 108 ext4_clear_io_unwritten_flag(io);
98 if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) 109 ext4_release_io_end(io);
99 wake_up_all(ext4_ioend_wq(inode));
100 if (io->flag & EXT4_IO_END_DIRECT)
101 inode_dio_done(inode);
102 if (io->iocb)
103 aio_complete(io->iocb, io->result, 0);
104 return ret; 110 return ret;
105} 111}
106 112
@@ -131,7 +137,7 @@ static void dump_completed_IO(struct inode *inode)
131} 137}
132 138
133/* Add the io_end to per-inode completed end_io list. */ 139/* Add the io_end to per-inode completed end_io list. */
134void ext4_add_complete_io(ext4_io_end_t *io_end) 140static void ext4_add_complete_io(ext4_io_end_t *io_end)
135{ 141{
136 struct ext4_inode_info *ei = EXT4_I(io_end->inode); 142 struct ext4_inode_info *ei = EXT4_I(io_end->inode);
137 struct workqueue_struct *wq; 143 struct workqueue_struct *wq;
@@ -168,8 +174,6 @@ static int ext4_do_flush_completed_IO(struct inode *inode)
168 err = ext4_end_io(io); 174 err = ext4_end_io(io);
169 if (unlikely(!ret && err)) 175 if (unlikely(!ret && err))
170 ret = err; 176 ret = err;
171 io->flag &= ~EXT4_IO_END_UNWRITTEN;
172 ext4_free_io_end(io);
173 } 177 }
174 return ret; 178 return ret;
175} 179}
@@ -201,10 +205,43 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
201 atomic_inc(&EXT4_I(inode)->i_ioend_count); 205 atomic_inc(&EXT4_I(inode)->i_ioend_count);
202 io->inode = inode; 206 io->inode = inode;
203 INIT_LIST_HEAD(&io->list); 207 INIT_LIST_HEAD(&io->list);
208 atomic_set(&io->count, 1);
204 } 209 }
205 return io; 210 return io;
206} 211}
207 212
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
208/* 245/*
209 * Print an buffer I/O error compatible with the fs/buffer.c. This 246 * Print an buffer I/O error compatible with the fs/buffer.c. This
210 * provides compatibility with dmesg scrapers that look for a specific 247 * provides compatibility with dmesg scrapers that look for a specific
@@ -287,12 +324,7 @@ static void ext4_end_bio(struct bio *bio, int error)
287 bi_sector >> (inode->i_blkbits - 9)); 324 bi_sector >> (inode->i_blkbits - 9));
288 } 325 }
289 326
290 if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { 327 ext4_put_io_end_defer(io_end);
291 ext4_free_io_end(io_end);
292 return;
293 }
294
295 ext4_add_complete_io(io_end);
296} 328}
297 329
298void ext4_io_submit(struct ext4_io_submit *io) 330void ext4_io_submit(struct ext4_io_submit *io)
@@ -306,40 +338,37 @@ void ext4_io_submit(struct ext4_io_submit *io)
306 bio_put(io->io_bio); 338 bio_put(io->io_bio);
307 } 339 }
308 io->io_bio = NULL; 340 io->io_bio = NULL;
309 io->io_op = 0; 341}
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;
310 io->io_end = NULL; 348 io->io_end = NULL;
311} 349}
312 350
313static int io_submit_init(struct ext4_io_submit *io, 351static int io_submit_init_bio(struct ext4_io_submit *io,
314 struct inode *inode, 352 struct buffer_head *bh)
315 struct writeback_control *wbc,
316 struct buffer_head *bh)
317{ 353{
318 ext4_io_end_t *io_end;
319 struct page *page = bh->b_page;
320 int nvecs = bio_get_nr_vecs(bh->b_bdev); 354 int nvecs = bio_get_nr_vecs(bh->b_bdev);
321 struct bio *bio; 355 struct bio *bio;
322 356
323 io_end = ext4_init_io_end(inode, GFP_NOFS);
324 if (!io_end)
325 return -ENOMEM;
326 bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); 357 bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
327 bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); 358 bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
328 bio->bi_bdev = bh->b_bdev; 359 bio->bi_bdev = bh->b_bdev;
329 bio->bi_private = io->io_end = io_end;
330 bio->bi_end_io = ext4_end_bio; 360 bio->bi_end_io = ext4_end_bio;
331 361 bio->bi_private = ext4_get_io_end(io->io_end);
332 io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh); 362 if (!io->io_end->size)
333 363 io->io_end->offset = (bh->b_page->index << PAGE_CACHE_SHIFT)
364 + bh_offset(bh);
334 io->io_bio = bio; 365 io->io_bio = bio;
335 io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
336 io->io_next_block = bh->b_blocknr; 366 io->io_next_block = bh->b_blocknr;
337 return 0; 367 return 0;
338} 368}
339 369
340static int io_submit_add_bh(struct ext4_io_submit *io, 370static int io_submit_add_bh(struct ext4_io_submit *io,
341 struct inode *inode, 371 struct inode *inode,
342 struct writeback_control *wbc,
343 struct buffer_head *bh) 372 struct buffer_head *bh)
344{ 373{
345 ext4_io_end_t *io_end; 374 ext4_io_end_t *io_end;
@@ -350,18 +379,18 @@ submit_and_retry:
350 ext4_io_submit(io); 379 ext4_io_submit(io);
351 } 380 }
352 if (io->io_bio == NULL) { 381 if (io->io_bio == NULL) {
353 ret = io_submit_init(io, inode, wbc, bh); 382 ret = io_submit_init_bio(io, bh);
354 if (ret) 383 if (ret)
355 return ret; 384 return ret;
356 } 385 }
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;
357 io_end = io->io_end; 389 io_end = io->io_end;
358 if (buffer_uninit(bh)) 390 if (buffer_uninit(bh))
359 ext4_set_io_unwritten_flag(inode, io_end); 391 ext4_set_io_unwritten_flag(inode, io_end);
360 io->io_end->size += bh->b_size; 392 io_end->size += bh->b_size;
361 io->io_next_block++; 393 io->io_next_block++;
362 ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
363 if (ret != bh->b_size)
364 goto submit_and_retry;
365 return 0; 394 return 0;
366} 395}
367 396
@@ -433,7 +462,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
433 do { 462 do {
434 if (!buffer_async_write(bh)) 463 if (!buffer_async_write(bh))
435 continue; 464 continue;
436 ret = io_submit_add_bh(io, inode, wbc, bh); 465 ret = io_submit_add_bh(io, inode, bh);
437 if (ret) { 466 if (ret) {
438 /* 467 /*
439 * We only get here on ENOMEM. Not much else 468 * We only get here on ENOMEM. Not much else