diff options
| -rw-r--r-- | fs/ext4/ext4.h | 25 | ||||
| -rw-r--r-- | fs/ext4/page-io.c | 65 | ||||
| -rw-r--r-- | fs/ext4/super.c | 38 |
3 files changed, 88 insertions, 40 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 8de219b758fb..b69a733b5b42 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -887,12 +887,22 @@ struct ext4_inode_info { | |||
| 887 | qsize_t i_reserved_quota; | 887 | qsize_t i_reserved_quota; |
| 888 | #endif | 888 | #endif |
| 889 | 889 | ||
| 890 | /* completed IOs that might need unwritten extents handling */ | 890 | /* Lock protecting lists below */ |
| 891 | struct list_head i_completed_io_list; | ||
| 892 | spinlock_t i_completed_io_lock; | 891 | spinlock_t i_completed_io_lock; |
| 892 | /* | ||
| 893 | * Completed IOs that need unwritten extents handling and have | ||
| 894 | * transaction reserved | ||
| 895 | */ | ||
| 896 | struct list_head i_rsv_conversion_list; | ||
| 897 | /* | ||
| 898 | * Completed IOs that need unwritten extents handling and don't have | ||
| 899 | * transaction reserved | ||
| 900 | */ | ||
| 901 | struct list_head i_unrsv_conversion_list; | ||
| 893 | atomic_t i_ioend_count; /* Number of outstanding io_end structs */ | 902 | atomic_t i_ioend_count; /* Number of outstanding io_end structs */ |
| 894 | atomic_t i_unwritten; /* Nr. of inflight conversions pending */ | 903 | atomic_t i_unwritten; /* Nr. of inflight conversions pending */ |
| 895 | struct work_struct i_unwritten_work; /* deferred extent conversion */ | 904 | struct work_struct i_rsv_conversion_work; |
| 905 | struct work_struct i_unrsv_conversion_work; | ||
| 896 | 906 | ||
| 897 | spinlock_t i_block_reservation_lock; | 907 | spinlock_t i_block_reservation_lock; |
| 898 | 908 | ||
| @@ -1264,8 +1274,10 @@ struct ext4_sb_info { | |||
| 1264 | struct flex_groups *s_flex_groups; | 1274 | struct flex_groups *s_flex_groups; |
| 1265 | ext4_group_t s_flex_groups_allocated; | 1275 | ext4_group_t s_flex_groups_allocated; |
| 1266 | 1276 | ||
| 1267 | /* workqueue for dio unwritten */ | 1277 | /* workqueue for unreserved extent convertions (dio) */ |
| 1268 | struct workqueue_struct *dio_unwritten_wq; | 1278 | struct workqueue_struct *unrsv_conversion_wq; |
| 1279 | /* workqueue for reserved extent conversions (buffered io) */ | ||
| 1280 | struct workqueue_struct *rsv_conversion_wq; | ||
| 1269 | 1281 | ||
| 1270 | /* timer for periodic error stats printing */ | 1282 | /* timer for periodic error stats printing */ |
| 1271 | struct timer_list s_err_report; | 1283 | struct timer_list s_err_report; |
| @@ -2646,7 +2658,8 @@ extern int ext4_put_io_end(ext4_io_end_t *io_end); | |||
| 2646 | extern void ext4_put_io_end_defer(ext4_io_end_t *io_end); | 2658 | extern void ext4_put_io_end_defer(ext4_io_end_t *io_end); |
| 2647 | extern void ext4_io_submit_init(struct ext4_io_submit *io, | 2659 | extern void ext4_io_submit_init(struct ext4_io_submit *io, |
| 2648 | struct writeback_control *wbc); | 2660 | struct writeback_control *wbc); |
| 2649 | extern void ext4_end_io_work(struct work_struct *work); | 2661 | extern void ext4_end_io_rsv_work(struct work_struct *work); |
| 2662 | extern void ext4_end_io_unrsv_work(struct work_struct *work); | ||
| 2650 | extern void ext4_io_submit(struct ext4_io_submit *io); | 2663 | extern void ext4_io_submit(struct ext4_io_submit *io); |
| 2651 | extern int ext4_bio_write_page(struct ext4_io_submit *io, | 2664 | extern int ext4_bio_write_page(struct ext4_io_submit *io, |
| 2652 | struct page *page, | 2665 | struct page *page, |
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 5f20bc481041..bcdfd6bdde06 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
| @@ -58,8 +58,10 @@ void ext4_ioend_shutdown(struct inode *inode) | |||
| 58 | * We need to make sure the work structure is finished being | 58 | * We need to make sure the work structure is finished being |
| 59 | * used before we let the inode get destroyed. | 59 | * used before we let the inode get destroyed. |
| 60 | */ | 60 | */ |
| 61 | if (work_pending(&EXT4_I(inode)->i_unwritten_work)) | 61 | if (work_pending(&EXT4_I(inode)->i_rsv_conversion_work)) |
| 62 | cancel_work_sync(&EXT4_I(inode)->i_unwritten_work); | 62 | cancel_work_sync(&EXT4_I(inode)->i_rsv_conversion_work); |
| 63 | if (work_pending(&EXT4_I(inode)->i_unrsv_conversion_work)) | ||
| 64 | cancel_work_sync(&EXT4_I(inode)->i_unrsv_conversion_work); | ||
| 63 | } | 65 | } |
| 64 | 66 | ||
| 65 | static void ext4_release_io_end(ext4_io_end_t *io_end) | 67 | static void ext4_release_io_end(ext4_io_end_t *io_end) |
| @@ -114,20 +116,17 @@ static int ext4_end_io(ext4_io_end_t *io) | |||
| 114 | return ret; | 116 | return ret; |
| 115 | } | 117 | } |
| 116 | 118 | ||
| 117 | static void dump_completed_IO(struct inode *inode) | 119 | static void dump_completed_IO(struct inode *inode, struct list_head *head) |
| 118 | { | 120 | { |
| 119 | #ifdef EXT4FS_DEBUG | 121 | #ifdef EXT4FS_DEBUG |
| 120 | struct list_head *cur, *before, *after; | 122 | struct list_head *cur, *before, *after; |
| 121 | ext4_io_end_t *io, *io0, *io1; | 123 | ext4_io_end_t *io, *io0, *io1; |
| 122 | 124 | ||
| 123 | if (list_empty(&EXT4_I(inode)->i_completed_io_list)) { | 125 | if (list_empty(head)) |
| 124 | ext4_debug("inode %lu completed_io list is empty\n", | ||
| 125 | inode->i_ino); | ||
| 126 | return; | 126 | return; |
| 127 | } | ||
| 128 | 127 | ||
| 129 | ext4_debug("Dump inode %lu completed_io list\n", inode->i_ino); | 128 | ext4_debug("Dump inode %lu completed io list\n", inode->i_ino); |
| 130 | list_for_each_entry(io, &EXT4_I(inode)->i_completed_io_list, list) { | 129 | list_for_each_entry(io, head, list) { |
| 131 | cur = &io->list; | 130 | cur = &io->list; |
| 132 | before = cur->prev; | 131 | before = cur->prev; |
| 133 | io0 = container_of(before, ext4_io_end_t, list); | 132 | io0 = container_of(before, ext4_io_end_t, list); |
| @@ -148,16 +147,23 @@ static void ext4_add_complete_io(ext4_io_end_t *io_end) | |||
| 148 | unsigned long flags; | 147 | unsigned long flags; |
| 149 | 148 | ||
| 150 | BUG_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); | 149 | BUG_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); |
| 151 | wq = EXT4_SB(io_end->inode->i_sb)->dio_unwritten_wq; | ||
| 152 | |||
| 153 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | 150 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); |
| 154 | if (list_empty(&ei->i_completed_io_list)) | 151 | if (io_end->handle) { |
| 155 | queue_work(wq, &ei->i_unwritten_work); | 152 | wq = EXT4_SB(io_end->inode->i_sb)->rsv_conversion_wq; |
| 156 | list_add_tail(&io_end->list, &ei->i_completed_io_list); | 153 | if (list_empty(&ei->i_rsv_conversion_list)) |
| 154 | queue_work(wq, &ei->i_rsv_conversion_work); | ||
| 155 | list_add_tail(&io_end->list, &ei->i_rsv_conversion_list); | ||
| 156 | } else { | ||
| 157 | wq = EXT4_SB(io_end->inode->i_sb)->unrsv_conversion_wq; | ||
| 158 | if (list_empty(&ei->i_unrsv_conversion_list)) | ||
| 159 | queue_work(wq, &ei->i_unrsv_conversion_work); | ||
| 160 | list_add_tail(&io_end->list, &ei->i_unrsv_conversion_list); | ||
| 161 | } | ||
| 157 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | 162 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); |
| 158 | } | 163 | } |
| 159 | 164 | ||
| 160 | static int ext4_do_flush_completed_IO(struct inode *inode) | 165 | static int ext4_do_flush_completed_IO(struct inode *inode, |
| 166 | struct list_head *head) | ||
| 161 | { | 167 | { |
| 162 | ext4_io_end_t *io; | 168 | ext4_io_end_t *io; |
| 163 | struct list_head unwritten; | 169 | struct list_head unwritten; |
| @@ -166,8 +172,8 @@ static int ext4_do_flush_completed_IO(struct inode *inode) | |||
| 166 | int err, ret = 0; | 172 | int err, ret = 0; |
| 167 | 173 | ||
| 168 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); | 174 | spin_lock_irqsave(&ei->i_completed_io_lock, flags); |
| 169 | dump_completed_IO(inode); | 175 | dump_completed_IO(inode, head); |
| 170 | list_replace_init(&ei->i_completed_io_list, &unwritten); | 176 | list_replace_init(head, &unwritten); |
| 171 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); | 177 | spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); |
| 172 | 178 | ||
| 173 | while (!list_empty(&unwritten)) { | 179 | while (!list_empty(&unwritten)) { |
| @@ -183,21 +189,34 @@ static int ext4_do_flush_completed_IO(struct inode *inode) | |||
| 183 | } | 189 | } |
| 184 | 190 | ||
| 185 | /* | 191 | /* |
| 186 | * work on completed aio dio IO, to convert unwritten extents to extents | 192 | * work on completed IO, to convert unwritten extents to extents |
| 187 | */ | 193 | */ |
| 188 | void ext4_end_io_work(struct work_struct *work) | 194 | void ext4_end_io_rsv_work(struct work_struct *work) |
| 189 | { | 195 | { |
| 190 | struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info, | 196 | struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info, |
| 191 | i_unwritten_work); | 197 | i_rsv_conversion_work); |
| 192 | ext4_do_flush_completed_IO(&ei->vfs_inode); | 198 | ext4_do_flush_completed_IO(&ei->vfs_inode, &ei->i_rsv_conversion_list); |
| 199 | } | ||
| 200 | |||
| 201 | void ext4_end_io_unrsv_work(struct work_struct *work) | ||
| 202 | { | ||
| 203 | struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info, | ||
| 204 | i_unrsv_conversion_work); | ||
| 205 | ext4_do_flush_completed_IO(&ei->vfs_inode, &ei->i_unrsv_conversion_list); | ||
| 193 | } | 206 | } |
| 194 | 207 | ||
| 195 | int ext4_flush_unwritten_io(struct inode *inode) | 208 | int ext4_flush_unwritten_io(struct inode *inode) |
| 196 | { | 209 | { |
| 197 | int ret; | 210 | int ret, err; |
| 211 | |||
| 198 | WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex) && | 212 | WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex) && |
| 199 | !(inode->i_state & I_FREEING)); | 213 | !(inode->i_state & I_FREEING)); |
| 200 | ret = ext4_do_flush_completed_IO(inode); | 214 | ret = ext4_do_flush_completed_IO(inode, |
| 215 | &EXT4_I(inode)->i_rsv_conversion_list); | ||
| 216 | err = ext4_do_flush_completed_IO(inode, | ||
| 217 | &EXT4_I(inode)->i_unrsv_conversion_list); | ||
| 218 | if (!ret) | ||
| 219 | ret = err; | ||
| 201 | ext4_unwritten_wait(inode); | 220 | ext4_unwritten_wait(inode); |
| 202 | return ret; | 221 | return ret; |
| 203 | } | 222 | } |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index eac4d3081ba4..7c8e1713e203 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -750,8 +750,10 @@ static void ext4_put_super(struct super_block *sb) | |||
| 750 | ext4_unregister_li_request(sb); | 750 | ext4_unregister_li_request(sb); |
| 751 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); | 751 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); |
| 752 | 752 | ||
| 753 | flush_workqueue(sbi->dio_unwritten_wq); | 753 | flush_workqueue(sbi->unrsv_conversion_wq); |
| 754 | destroy_workqueue(sbi->dio_unwritten_wq); | 754 | flush_workqueue(sbi->rsv_conversion_wq); |
| 755 | destroy_workqueue(sbi->unrsv_conversion_wq); | ||
| 756 | destroy_workqueue(sbi->rsv_conversion_wq); | ||
| 755 | 757 | ||
| 756 | if (sbi->s_journal) { | 758 | if (sbi->s_journal) { |
| 757 | err = jbd2_journal_destroy(sbi->s_journal); | 759 | err = jbd2_journal_destroy(sbi->s_journal); |
| @@ -859,13 +861,15 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
| 859 | ei->i_reserved_quota = 0; | 861 | ei->i_reserved_quota = 0; |
| 860 | #endif | 862 | #endif |
| 861 | ei->jinode = NULL; | 863 | ei->jinode = NULL; |
| 862 | INIT_LIST_HEAD(&ei->i_completed_io_list); | 864 | INIT_LIST_HEAD(&ei->i_rsv_conversion_list); |
| 865 | INIT_LIST_HEAD(&ei->i_unrsv_conversion_list); | ||
| 863 | spin_lock_init(&ei->i_completed_io_lock); | 866 | spin_lock_init(&ei->i_completed_io_lock); |
| 864 | ei->i_sync_tid = 0; | 867 | ei->i_sync_tid = 0; |
| 865 | ei->i_datasync_tid = 0; | 868 | ei->i_datasync_tid = 0; |
| 866 | atomic_set(&ei->i_ioend_count, 0); | 869 | atomic_set(&ei->i_ioend_count, 0); |
| 867 | atomic_set(&ei->i_unwritten, 0); | 870 | atomic_set(&ei->i_unwritten, 0); |
| 868 | INIT_WORK(&ei->i_unwritten_work, ext4_end_io_work); | 871 | INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work); |
| 872 | INIT_WORK(&ei->i_unrsv_conversion_work, ext4_end_io_unrsv_work); | ||
| 869 | 873 | ||
| 870 | return &ei->vfs_inode; | 874 | return &ei->vfs_inode; |
| 871 | } | 875 | } |
| @@ -3936,12 +3940,20 @@ no_journal: | |||
| 3936 | * The maximum number of concurrent works can be high and | 3940 | * The maximum number of concurrent works can be high and |
| 3937 | * concurrency isn't really necessary. Limit it to 1. | 3941 | * concurrency isn't really necessary. Limit it to 1. |
| 3938 | */ | 3942 | */ |
| 3939 | EXT4_SB(sb)->dio_unwritten_wq = | 3943 | EXT4_SB(sb)->rsv_conversion_wq = |
| 3940 | alloc_workqueue("ext4-dio-unwritten", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); | 3944 | alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); |
| 3941 | if (!EXT4_SB(sb)->dio_unwritten_wq) { | 3945 | if (!EXT4_SB(sb)->rsv_conversion_wq) { |
| 3942 | printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n"); | 3946 | printk(KERN_ERR "EXT4-fs: failed to create workqueue\n"); |
| 3943 | ret = -ENOMEM; | 3947 | ret = -ENOMEM; |
| 3944 | goto failed_mount_wq; | 3948 | goto failed_mount4; |
| 3949 | } | ||
| 3950 | |||
| 3951 | EXT4_SB(sb)->unrsv_conversion_wq = | ||
| 3952 | alloc_workqueue("ext4-unrsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); | ||
| 3953 | if (!EXT4_SB(sb)->unrsv_conversion_wq) { | ||
| 3954 | printk(KERN_ERR "EXT4-fs: failed to create workqueue\n"); | ||
| 3955 | ret = -ENOMEM; | ||
| 3956 | goto failed_mount4; | ||
| 3945 | } | 3957 | } |
| 3946 | 3958 | ||
| 3947 | /* | 3959 | /* |
| @@ -4095,7 +4107,10 @@ failed_mount4a: | |||
| 4095 | sb->s_root = NULL; | 4107 | sb->s_root = NULL; |
| 4096 | failed_mount4: | 4108 | failed_mount4: |
| 4097 | ext4_msg(sb, KERN_ERR, "mount failed"); | 4109 | ext4_msg(sb, KERN_ERR, "mount failed"); |
| 4098 | destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq); | 4110 | if (EXT4_SB(sb)->rsv_conversion_wq) |
| 4111 | destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq); | ||
| 4112 | if (EXT4_SB(sb)->unrsv_conversion_wq) | ||
| 4113 | destroy_workqueue(EXT4_SB(sb)->unrsv_conversion_wq); | ||
| 4099 | failed_mount_wq: | 4114 | failed_mount_wq: |
| 4100 | if (sbi->s_journal) { | 4115 | if (sbi->s_journal) { |
| 4101 | jbd2_journal_destroy(sbi->s_journal); | 4116 | jbd2_journal_destroy(sbi->s_journal); |
| @@ -4541,7 +4556,8 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
| 4541 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 4556 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 4542 | 4557 | ||
| 4543 | trace_ext4_sync_fs(sb, wait); | 4558 | trace_ext4_sync_fs(sb, wait); |
| 4544 | flush_workqueue(sbi->dio_unwritten_wq); | 4559 | flush_workqueue(sbi->rsv_conversion_wq); |
| 4560 | flush_workqueue(sbi->unrsv_conversion_wq); | ||
| 4545 | /* | 4561 | /* |
| 4546 | * Writeback quota in non-journalled quota case - journalled quota has | 4562 | * Writeback quota in non-journalled quota case - journalled quota has |
| 4547 | * no dirty dquots | 4563 | * no dirty dquots |
