diff options
Diffstat (limited to 'fs/ext4/page-io.c')
-rw-r--r-- | fs/ext4/page-io.c | 121 |
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 | ||
64 | void ext4_free_io_end(ext4_io_end_t *io) | 64 | static 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); | 78 | static 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. */ |
134 | void ext4_add_complete_io(ext4_io_end_t *io_end) | 140 | static 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 | ||
213 | void 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 | |||
224 | int 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 | |||
239 | ext4_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 | ||
298 | void ext4_io_submit(struct ext4_io_submit *io) | 330 | void 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 | |||
343 | void 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 | ||
313 | static int io_submit_init(struct ext4_io_submit *io, | 351 | static 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 | ||
340 | static int io_submit_add_bh(struct ext4_io_submit *io, | 370 | static 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 |