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 |