diff options
Diffstat (limited to 'fs/ext4/page-io.c')
-rw-r--r-- | fs/ext4/page-io.c | 85 |
1 files changed, 26 insertions, 59 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 0016fbca2a40..809b31003ecc 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/mm.h> | ||
26 | 27 | ||
27 | #include "ext4_jbd2.h" | 28 | #include "ext4_jbd2.h" |
28 | #include "xattr.h" | 29 | #include "xattr.h" |
@@ -73,8 +74,6 @@ void ext4_free_io_end(ext4_io_end_t *io) | |||
73 | BUG_ON(!list_empty(&io->list)); | 74 | BUG_ON(!list_empty(&io->list)); |
74 | BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); | 75 | BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN); |
75 | 76 | ||
76 | if (io->page) | ||
77 | put_page(io->page); | ||
78 | for (i = 0; i < io->num_io_pages; i++) | 77 | for (i = 0; i < io->num_io_pages; i++) |
79 | put_io_page(io->pages[i]); | 78 | put_io_page(io->pages[i]); |
80 | io->num_io_pages = 0; | 79 | io->num_io_pages = 0; |
@@ -103,14 +102,13 @@ static int ext4_end_io(ext4_io_end_t *io) | |||
103 | "(inode %lu, offset %llu, size %zd, error %d)", | 102 | "(inode %lu, offset %llu, size %zd, error %d)", |
104 | inode->i_ino, offset, size, ret); | 103 | inode->i_ino, offset, size, ret); |
105 | } | 104 | } |
106 | if (io->iocb) | ||
107 | aio_complete(io->iocb, io->result, 0); | ||
108 | |||
109 | if (io->flag & EXT4_IO_END_DIRECT) | ||
110 | inode_dio_done(inode); | ||
111 | /* Wake up anyone waiting on unwritten extent conversion */ | 105 | /* Wake up anyone waiting on unwritten extent conversion */ |
112 | if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) | 106 | if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) |
113 | wake_up_all(ext4_ioend_wq(inode)); | 107 | wake_up_all(ext4_ioend_wq(inode)); |
108 | if (io->flag & EXT4_IO_END_DIRECT) | ||
109 | inode_dio_done(inode); | ||
110 | if (io->iocb) | ||
111 | aio_complete(io->iocb, io->result, 0); | ||
114 | return ret; | 112 | return ret; |
115 | } | 113 | } |
116 | 114 | ||
@@ -119,7 +117,6 @@ static void dump_completed_IO(struct inode *inode) | |||
119 | #ifdef EXT4FS_DEBUG | 117 | #ifdef EXT4FS_DEBUG |
120 | struct list_head *cur, *before, *after; | 118 | struct list_head *cur, *before, *after; |
121 | ext4_io_end_t *io, *io0, *io1; | 119 | ext4_io_end_t *io, *io0, *io1; |
122 | unsigned long flags; | ||
123 | 120 | ||
124 | if (list_empty(&EXT4_I(inode)->i_completed_io_list)) { | 121 | if (list_empty(&EXT4_I(inode)->i_completed_io_list)) { |
125 | ext4_debug("inode %lu completed_io list is empty\n", | 122 | ext4_debug("inode %lu completed_io list is empty\n", |
@@ -152,26 +149,20 @@ void ext4_add_complete_io(ext4_io_end_t *io_end) | |||
152 | wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; | 149 | wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; |
153 | 150 | ||
154 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | 151 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); |
155 | if (list_empty(&ei->i_completed_io_list)) { | 152 | if (list_empty(&ei->i_completed_io_list)) |
156 | io_end->flag |= EXT4_IO_END_QUEUED; | 153 | queue_work(wq, &ei->i_unwritten_work); |
157 | queue_work(wq, &io_end->work); | ||
158 | } | ||
159 | list_add_tail(&io_end->list, &ei->i_completed_io_list); | 154 | list_add_tail(&io_end->list, &ei->i_completed_io_list); |
160 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | 155 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); |
161 | } | 156 | } |
162 | 157 | ||
163 | static int ext4_do_flush_completed_IO(struct inode *inode, | 158 | static int ext4_do_flush_completed_IO(struct inode *inode) |
164 | ext4_io_end_t *work_io) | ||
165 | { | 159 | { |
166 | ext4_io_end_t *io; | 160 | ext4_io_end_t *io; |
167 | struct list_head unwritten, complete, to_free; | 161 | struct list_head unwritten; |
168 | unsigned long flags; | 162 | unsigned long flags; |
169 | struct ext4_inode_info *ei = EXT4_I(inode); | 163 | struct ext4_inode_info *ei = EXT4_I(inode); |
170 | int err, ret = 0; | 164 | int err, ret = 0; |
171 | 165 | ||
172 | INIT_LIST_HEAD(&complete); | ||
173 | INIT_LIST_HEAD(&to_free); | ||
174 | |||
175 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | 166 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); |
176 | dump_completed_IO(inode); | 167 | dump_completed_IO(inode); |
177 | list_replace_init(&ei->i_completed_io_list, &unwritten); | 168 | list_replace_init(&ei->i_completed_io_list, &unwritten); |
@@ -185,32 +176,7 @@ static int ext4_do_flush_completed_IO(struct inode *inode, | |||
185 | err = ext4_end_io(io); | 176 | err = ext4_end_io(io); |
186 | if (unlikely(!ret && err)) | 177 | if (unlikely(!ret && err)) |
187 | ret = err; | 178 | ret = err; |
188 | |||
189 | list_add_tail(&io->list, &complete); | ||
190 | } | ||
191 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | ||
192 | while (!list_empty(&complete)) { | ||
193 | io = list_entry(complete.next, ext4_io_end_t, list); | ||
194 | io->flag &= ~EXT4_IO_END_UNWRITTEN; | 179 | io->flag &= ~EXT4_IO_END_UNWRITTEN; |
195 | /* end_io context can not be destroyed now because it still | ||
196 | * used by queued worker. Worker thread will destroy it later */ | ||
197 | if (io->flag & EXT4_IO_END_QUEUED) | ||
198 | list_del_init(&io->list); | ||
199 | else | ||
200 | list_move(&io->list, &to_free); | ||
201 | } | ||
202 | /* If we are called from worker context, it is time to clear queued | ||
203 | * flag, and destroy it's end_io if it was converted already */ | ||
204 | if (work_io) { | ||
205 | work_io->flag &= ~EXT4_IO_END_QUEUED; | ||
206 | if (!(work_io->flag & EXT4_IO_END_UNWRITTEN)) | ||
207 | list_add_tail(&work_io->list, &to_free); | ||
208 | } | ||
209 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | ||
210 | |||
211 | while (!list_empty(&to_free)) { | ||
212 | io = list_entry(to_free.next, ext4_io_end_t, list); | ||
213 | list_del_init(&io->list); | ||
214 | ext4_free_io_end(io); | 180 | ext4_free_io_end(io); |
215 | } | 181 | } |
216 | return ret; | 182 | return ret; |
@@ -219,10 +185,11 @@ static int ext4_do_flush_completed_IO(struct inode *inode, | |||
219 | /* | 185 | /* |
220 | * work on completed aio dio IO, to convert unwritten extents to extents | 186 | * work on completed aio dio IO, to convert unwritten extents to extents |
221 | */ | 187 | */ |
222 | static void ext4_end_io_work(struct work_struct *work) | 188 | void ext4_end_io_work(struct work_struct *work) |
223 | { | 189 | { |
224 | ext4_io_end_t *io = container_of(work, ext4_io_end_t, work); | 190 | struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info, |
225 | ext4_do_flush_completed_IO(io->inode, io); | 191 | i_unwritten_work); |
192 | ext4_do_flush_completed_IO(&ei->vfs_inode); | ||
226 | } | 193 | } |
227 | 194 | ||
228 | int ext4_flush_unwritten_io(struct inode *inode) | 195 | int ext4_flush_unwritten_io(struct inode *inode) |
@@ -230,7 +197,7 @@ int ext4_flush_unwritten_io(struct inode *inode) | |||
230 | int ret; | 197 | int ret; |
231 | WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex) && | 198 | WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex) && |
232 | !(inode->i_state & I_FREEING)); | 199 | !(inode->i_state & I_FREEING)); |
233 | ret = ext4_do_flush_completed_IO(inode, NULL); | 200 | ret = ext4_do_flush_completed_IO(inode); |
234 | ext4_unwritten_wait(inode); | 201 | ext4_unwritten_wait(inode); |
235 | return ret; | 202 | return ret; |
236 | } | 203 | } |
@@ -241,7 +208,6 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) | |||
241 | if (io) { | 208 | if (io) { |
242 | atomic_inc(&EXT4_I(inode)->i_ioend_count); | 209 | atomic_inc(&EXT4_I(inode)->i_ioend_count); |
243 | io->inode = inode; | 210 | io->inode = inode; |
244 | INIT_WORK(&io->work, ext4_end_io_work); | ||
245 | INIT_LIST_HEAD(&io->list); | 211 | INIT_LIST_HEAD(&io->list); |
246 | } | 212 | } |
247 | return io; | 213 | return io; |
@@ -382,14 +348,6 @@ static int io_submit_add_bh(struct ext4_io_submit *io, | |||
382 | unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); | 348 | unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); |
383 | } | 349 | } |
384 | 350 | ||
385 | if (!buffer_mapped(bh) || buffer_delay(bh)) { | ||
386 | if (!buffer_mapped(bh)) | ||
387 | clear_buffer_dirty(bh); | ||
388 | if (io->io_bio) | ||
389 | ext4_io_submit(io); | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | if (io->io_bio && bh->b_blocknr != io->io_next_block) { | 351 | if (io->io_bio && bh->b_blocknr != io->io_next_block) { |
394 | submit_and_retry: | 352 | submit_and_retry: |
395 | ext4_io_submit(io); | 353 | ext4_io_submit(io); |
@@ -436,7 +394,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
436 | 394 | ||
437 | io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS); | 395 | io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS); |
438 | if (!io_page) { | 396 | if (!io_page) { |
439 | set_page_dirty(page); | 397 | redirty_page_for_writepage(wbc, page); |
440 | unlock_page(page); | 398 | unlock_page(page); |
441 | return -ENOMEM; | 399 | return -ENOMEM; |
442 | } | 400 | } |
@@ -468,7 +426,15 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
468 | set_buffer_uptodate(bh); | 426 | set_buffer_uptodate(bh); |
469 | continue; | 427 | continue; |
470 | } | 428 | } |
471 | clear_buffer_dirty(bh); | 429 | if (!buffer_dirty(bh) || buffer_delay(bh) || |
430 | !buffer_mapped(bh) || buffer_unwritten(bh)) { | ||
431 | /* A hole? We can safely clear the dirty bit */ | ||
432 | if (!buffer_mapped(bh)) | ||
433 | clear_buffer_dirty(bh); | ||
434 | if (io->io_bio) | ||
435 | ext4_io_submit(io); | ||
436 | continue; | ||
437 | } | ||
472 | ret = io_submit_add_bh(io, io_page, inode, wbc, bh); | 438 | ret = io_submit_add_bh(io, io_page, inode, wbc, bh); |
473 | if (ret) { | 439 | if (ret) { |
474 | /* | 440 | /* |
@@ -476,9 +442,10 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
476 | * we can do but mark the page as dirty, and | 442 | * we can do but mark the page as dirty, and |
477 | * better luck next time. | 443 | * better luck next time. |
478 | */ | 444 | */ |
479 | set_page_dirty(page); | 445 | redirty_page_for_writepage(wbc, page); |
480 | break; | 446 | break; |
481 | } | 447 | } |
448 | clear_buffer_dirty(bh); | ||
482 | } | 449 | } |
483 | unlock_page(page); | 450 | unlock_page(page); |
484 | /* | 451 | /* |