diff options
| -rw-r--r-- | fs/ext4/ext4.h | 2 | ||||
| -rw-r--r-- | fs/ext4/page-io.c | 59 | ||||
| -rw-r--r-- | fs/ext4/super.c | 2 |
3 files changed, 38 insertions, 25 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8b5dd6369f82..670d1343f914 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -858,6 +858,7 @@ struct ext4_inode_info { | |||
| 858 | spinlock_t i_completed_io_lock; | 858 | spinlock_t i_completed_io_lock; |
| 859 | /* current io_end structure for async DIO write*/ | 859 | /* current io_end structure for async DIO write*/ |
| 860 | ext4_io_end_t *cur_aio_dio; | 860 | ext4_io_end_t *cur_aio_dio; |
| 861 | atomic_t i_ioend_count; /* Number of outstanding io_end structs */ | ||
| 861 | 862 | ||
| 862 | /* | 863 | /* |
| 863 | * Transactions that contain inode's metadata needed to complete | 864 | * Transactions that contain inode's metadata needed to complete |
| @@ -2060,6 +2061,7 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 2060 | /* page-io.c */ | 2061 | /* page-io.c */ |
| 2061 | extern int __init ext4_init_pageio(void); | 2062 | extern int __init ext4_init_pageio(void); |
| 2062 | extern void ext4_exit_pageio(void); | 2063 | extern void ext4_exit_pageio(void); |
| 2064 | extern void ext4_ioend_wait(struct inode *); | ||
| 2063 | extern void ext4_free_io_end(ext4_io_end_t *io); | 2065 | extern void ext4_free_io_end(ext4_io_end_t *io); |
| 2064 | extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags); | 2066 | extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags); |
| 2065 | extern int ext4_end_io_nolock(ext4_io_end_t *io); | 2067 | extern int ext4_end_io_nolock(ext4_io_end_t *io); |
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 46a7d6a9d976..a24c8cca7370 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
| @@ -32,8 +32,14 @@ | |||
| 32 | 32 | ||
| 33 | static struct kmem_cache *io_page_cachep, *io_end_cachep; | 33 | static struct kmem_cache *io_page_cachep, *io_end_cachep; |
| 34 | 34 | ||
| 35 | #define WQ_HASH_SZ 37 | ||
| 36 | #define to_ioend_wq(v) (&ioend_wq[((unsigned long)v) % WQ_HASH_SZ]) | ||
| 37 | static wait_queue_head_t ioend_wq[WQ_HASH_SZ]; | ||
| 38 | |||
| 35 | int __init ext4_init_pageio(void) | 39 | int __init ext4_init_pageio(void) |
| 36 | { | 40 | { |
| 41 | int i; | ||
| 42 | |||
| 37 | io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT); | 43 | io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT); |
| 38 | if (io_page_cachep == NULL) | 44 | if (io_page_cachep == NULL) |
| 39 | return -ENOMEM; | 45 | return -ENOMEM; |
| @@ -42,6 +48,8 @@ int __init ext4_init_pageio(void) | |||
| 42 | kmem_cache_destroy(io_page_cachep); | 48 | kmem_cache_destroy(io_page_cachep); |
| 43 | return -ENOMEM; | 49 | return -ENOMEM; |
| 44 | } | 50 | } |
| 51 | for (i = 0; i < WQ_HASH_SZ; i++) | ||
| 52 | init_waitqueue_head(&ioend_wq[i]); | ||
| 45 | 53 | ||
| 46 | return 0; | 54 | return 0; |
| 47 | } | 55 | } |
| @@ -52,9 +60,17 @@ void ext4_exit_pageio(void) | |||
| 52 | kmem_cache_destroy(io_page_cachep); | 60 | kmem_cache_destroy(io_page_cachep); |
| 53 | } | 61 | } |
| 54 | 62 | ||
| 63 | void ext4_ioend_wait(struct inode *inode) | ||
| 64 | { | ||
| 65 | wait_queue_head_t *wq = to_ioend_wq(inode); | ||
| 66 | |||
| 67 | wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0)); | ||
| 68 | } | ||
| 69 | |||
| 55 | void ext4_free_io_end(ext4_io_end_t *io) | 70 | void ext4_free_io_end(ext4_io_end_t *io) |
| 56 | { | 71 | { |
| 57 | int i; | 72 | int i; |
| 73 | wait_queue_head_t *wq; | ||
| 58 | 74 | ||
| 59 | BUG_ON(!io); | 75 | BUG_ON(!io); |
| 60 | if (io->page) | 76 | if (io->page) |
| @@ -69,7 +85,10 @@ void ext4_free_io_end(ext4_io_end_t *io) | |||
| 69 | } | 85 | } |
| 70 | } | 86 | } |
| 71 | io->num_io_pages = 0; | 87 | io->num_io_pages = 0; |
| 72 | iput(io->inode); | 88 | wq = to_ioend_wq(io->inode); |
| 89 | if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) && | ||
| 90 | waitqueue_active(wq)) | ||
| 91 | wake_up_all(wq); | ||
| 73 | kmem_cache_free(io_end_cachep, io); | 92 | kmem_cache_free(io_end_cachep, io); |
| 74 | } | 93 | } |
| 75 | 94 | ||
| @@ -142,8 +161,8 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) | |||
| 142 | io = kmem_cache_alloc(io_end_cachep, flags); | 161 | io = kmem_cache_alloc(io_end_cachep, flags); |
| 143 | if (io) { | 162 | if (io) { |
| 144 | memset(io, 0, sizeof(*io)); | 163 | memset(io, 0, sizeof(*io)); |
| 145 | io->inode = igrab(inode); | 164 | atomic_inc(&EXT4_I(inode)->i_ioend_count); |
| 146 | BUG_ON(!io->inode); | 165 | io->inode = inode; |
| 147 | INIT_WORK(&io->work, ext4_end_io_work); | 166 | INIT_WORK(&io->work, ext4_end_io_work); |
| 148 | INIT_LIST_HEAD(&io->list); | 167 | INIT_LIST_HEAD(&io->list); |
| 149 | } | 168 | } |
| @@ -171,35 +190,15 @@ static void ext4_end_bio(struct bio *bio, int error) | |||
| 171 | struct workqueue_struct *wq; | 190 | struct workqueue_struct *wq; |
| 172 | struct inode *inode; | 191 | struct inode *inode; |
| 173 | unsigned long flags; | 192 | unsigned long flags; |
| 174 | ext4_fsblk_t err_block; | ||
| 175 | int i; | 193 | int i; |
| 176 | 194 | ||
| 177 | BUG_ON(!io_end); | 195 | BUG_ON(!io_end); |
| 178 | inode = io_end->inode; | ||
| 179 | bio->bi_private = NULL; | 196 | bio->bi_private = NULL; |
| 180 | bio->bi_end_io = NULL; | 197 | bio->bi_end_io = NULL; |
| 181 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) | 198 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) |
| 182 | error = 0; | 199 | error = 0; |
| 183 | err_block = bio->bi_sector >> (inode->i_blkbits - 9); | ||
| 184 | bio_put(bio); | 200 | bio_put(bio); |
| 185 | 201 | ||
| 186 | if (!(inode->i_sb->s_flags & MS_ACTIVE)) { | ||
| 187 | pr_err("sb umounted, discard end_io request for inode %lu\n", | ||
| 188 | io_end->inode->i_ino); | ||
| 189 | ext4_free_io_end(io_end); | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | |||
| 193 | if (error) { | ||
| 194 | io_end->flag |= EXT4_IO_END_ERROR; | ||
| 195 | ext4_warning(inode->i_sb, "I/O error writing to inode %lu " | ||
| 196 | "(offset %llu size %ld starting block %llu)", | ||
| 197 | inode->i_ino, | ||
| 198 | (unsigned long long) io_end->offset, | ||
| 199 | (long) io_end->size, | ||
| 200 | (unsigned long long) err_block); | ||
| 201 | } | ||
| 202 | |||
| 203 | for (i = 0; i < io_end->num_io_pages; i++) { | 202 | for (i = 0; i < io_end->num_io_pages; i++) { |
| 204 | struct page *page = io_end->pages[i]->p_page; | 203 | struct page *page = io_end->pages[i]->p_page; |
| 205 | struct buffer_head *bh, *head; | 204 | struct buffer_head *bh, *head; |
| @@ -254,8 +253,19 @@ static void ext4_end_bio(struct bio *bio, int error) | |||
| 254 | if (!partial_write) | 253 | if (!partial_write) |
| 255 | SetPageUptodate(page); | 254 | SetPageUptodate(page); |
| 256 | } | 255 | } |
| 257 | |||
| 258 | io_end->num_io_pages = 0; | 256 | io_end->num_io_pages = 0; |
| 257 | inode = io_end->inode; | ||
| 258 | |||
| 259 | if (error) { | ||
| 260 | io_end->flag |= EXT4_IO_END_ERROR; | ||
| 261 | ext4_warning(inode->i_sb, "I/O error writing to inode %lu " | ||
| 262 | "(offset %llu size %ld starting block %llu)", | ||
| 263 | inode->i_ino, | ||
| 264 | (unsigned long long) io_end->offset, | ||
| 265 | (long) io_end->size, | ||
| 266 | (unsigned long long) | ||
| 267 | bio->bi_sector >> (inode->i_blkbits - 9)); | ||
| 268 | } | ||
| 259 | 269 | ||
| 260 | /* Add the io_end to per-inode completed io list*/ | 270 | /* Add the io_end to per-inode completed io list*/ |
| 261 | spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); | 271 | spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags); |
| @@ -305,7 +315,6 @@ static int io_submit_init(struct ext4_io_submit *io, | |||
| 305 | bio->bi_private = io->io_end = io_end; | 315 | bio->bi_private = io->io_end = io_end; |
| 306 | bio->bi_end_io = ext4_end_bio; | 316 | bio->bi_end_io = ext4_end_bio; |
| 307 | 317 | ||
| 308 | io_end->inode = inode; | ||
| 309 | io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh); | 318 | io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh); |
| 310 | 319 | ||
| 311 | io->io_bio = bio; | 320 | io->io_bio = bio; |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 04352e9729d0..45653af88953 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -828,12 +828,14 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
| 828 | ei->cur_aio_dio = NULL; | 828 | ei->cur_aio_dio = NULL; |
| 829 | ei->i_sync_tid = 0; | 829 | ei->i_sync_tid = 0; |
| 830 | ei->i_datasync_tid = 0; | 830 | ei->i_datasync_tid = 0; |
| 831 | atomic_set(&ei->i_ioend_count, 0); | ||
| 831 | 832 | ||
| 832 | return &ei->vfs_inode; | 833 | return &ei->vfs_inode; |
| 833 | } | 834 | } |
| 834 | 835 | ||
| 835 | static void ext4_destroy_inode(struct inode *inode) | 836 | static void ext4_destroy_inode(struct inode *inode) |
| 836 | { | 837 | { |
| 838 | ext4_ioend_wait(inode); | ||
| 837 | if (!list_empty(&(EXT4_I(inode)->i_orphan))) { | 839 | if (!list_empty(&(EXT4_I(inode)->i_orphan))) { |
| 838 | ext4_msg(inode->i_sb, KERN_ERR, | 840 | ext4_msg(inode->i_sb, KERN_ERR, |
| 839 | "Inode %lu (%p): orphan list check failed!", | 841 | "Inode %lu (%p): orphan list check failed!", |
