diff options
| author | Mikulas Patocka <mpatocka@redhat.com> | 2013-07-10 18:41:18 -0400 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2013-07-10 18:41:18 -0400 |
| commit | 2480945cd44b50ba8b1646544eec2db21f064f12 (patch) | |
| tree | e9e3d5b75c4b1bdd83eaf7727016f607310c6574 | |
| parent | 43aeaa29573924df76f44eda2bbd94ca36e407b5 (diff) | |
dm bufio: submit writes outside lock
This patch changes dm-bufio so that it submits write I/Os outside of the
lock. If the number of submitted buffers is greater than the number of
requests on the target queue, submit_bio blocks. We want to block outside
of the lock to improve latency of other threads that may need the lock.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
| -rw-r--r-- | drivers/md/dm-bufio.c | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 9588b864d311..5227e079a6e3 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c | |||
| @@ -145,6 +145,7 @@ struct dm_buffer { | |||
| 145 | unsigned long state; | 145 | unsigned long state; |
| 146 | unsigned long last_accessed; | 146 | unsigned long last_accessed; |
| 147 | struct dm_bufio_client *c; | 147 | struct dm_bufio_client *c; |
| 148 | struct list_head write_list; | ||
| 148 | struct bio bio; | 149 | struct bio bio; |
| 149 | struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS]; | 150 | struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS]; |
| 150 | }; | 151 | }; |
| @@ -630,7 +631,8 @@ static int do_io_schedule(void *word) | |||
| 630 | * - Submit our write and don't wait on it. We set B_WRITING indicating | 631 | * - Submit our write and don't wait on it. We set B_WRITING indicating |
| 631 | * that there is a write in progress. | 632 | * that there is a write in progress. |
| 632 | */ | 633 | */ |
| 633 | static void __write_dirty_buffer(struct dm_buffer *b) | 634 | static void __write_dirty_buffer(struct dm_buffer *b, |
| 635 | struct list_head *write_list) | ||
| 634 | { | 636 | { |
| 635 | if (!test_bit(B_DIRTY, &b->state)) | 637 | if (!test_bit(B_DIRTY, &b->state)) |
| 636 | return; | 638 | return; |
| @@ -639,7 +641,24 @@ static void __write_dirty_buffer(struct dm_buffer *b) | |||
| 639 | wait_on_bit_lock(&b->state, B_WRITING, | 641 | wait_on_bit_lock(&b->state, B_WRITING, |
| 640 | do_io_schedule, TASK_UNINTERRUPTIBLE); | 642 | do_io_schedule, TASK_UNINTERRUPTIBLE); |
| 641 | 643 | ||
| 642 | submit_io(b, WRITE, b->block, write_endio); | 644 | if (!write_list) |
| 645 | submit_io(b, WRITE, b->block, write_endio); | ||
| 646 | else | ||
| 647 | list_add_tail(&b->write_list, write_list); | ||
| 648 | } | ||
| 649 | |||
| 650 | static void __flush_write_list(struct list_head *write_list) | ||
| 651 | { | ||
| 652 | struct blk_plug plug; | ||
| 653 | blk_start_plug(&plug); | ||
| 654 | while (!list_empty(write_list)) { | ||
| 655 | struct dm_buffer *b = | ||
| 656 | list_entry(write_list->next, struct dm_buffer, write_list); | ||
| 657 | list_del(&b->write_list); | ||
| 658 | submit_io(b, WRITE, b->block, write_endio); | ||
| 659 | dm_bufio_cond_resched(); | ||
| 660 | } | ||
| 661 | blk_finish_plug(&plug); | ||
| 643 | } | 662 | } |
| 644 | 663 | ||
| 645 | /* | 664 | /* |
| @@ -655,7 +674,7 @@ static void __make_buffer_clean(struct dm_buffer *b) | |||
| 655 | return; | 674 | return; |
| 656 | 675 | ||
| 657 | wait_on_bit(&b->state, B_READING, do_io_schedule, TASK_UNINTERRUPTIBLE); | 676 | wait_on_bit(&b->state, B_READING, do_io_schedule, TASK_UNINTERRUPTIBLE); |
| 658 | __write_dirty_buffer(b); | 677 | __write_dirty_buffer(b, NULL); |
| 659 | wait_on_bit(&b->state, B_WRITING, do_io_schedule, TASK_UNINTERRUPTIBLE); | 678 | wait_on_bit(&b->state, B_WRITING, do_io_schedule, TASK_UNINTERRUPTIBLE); |
| 660 | } | 679 | } |
| 661 | 680 | ||
| @@ -802,7 +821,8 @@ static void __free_buffer_wake(struct dm_buffer *b) | |||
| 802 | wake_up(&c->free_buffer_wait); | 821 | wake_up(&c->free_buffer_wait); |
| 803 | } | 822 | } |
| 804 | 823 | ||
| 805 | static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait) | 824 | static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait, |
| 825 | struct list_head *write_list) | ||
| 806 | { | 826 | { |
| 807 | struct dm_buffer *b, *tmp; | 827 | struct dm_buffer *b, *tmp; |
| 808 | 828 | ||
| @@ -818,7 +838,7 @@ static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait) | |||
| 818 | if (no_wait && test_bit(B_WRITING, &b->state)) | 838 | if (no_wait && test_bit(B_WRITING, &b->state)) |
| 819 | return; | 839 | return; |
| 820 | 840 | ||
| 821 | __write_dirty_buffer(b); | 841 | __write_dirty_buffer(b, write_list); |
| 822 | dm_bufio_cond_resched(); | 842 | dm_bufio_cond_resched(); |
| 823 | } | 843 | } |
| 824 | } | 844 | } |
| @@ -853,7 +873,8 @@ static void __get_memory_limit(struct dm_bufio_client *c, | |||
| 853 | * If we are over threshold_buffers, start freeing buffers. | 873 | * If we are over threshold_buffers, start freeing buffers. |
| 854 | * If we're over "limit_buffers", block until we get under the limit. | 874 | * If we're over "limit_buffers", block until we get under the limit. |
| 855 | */ | 875 | */ |
| 856 | static void __check_watermark(struct dm_bufio_client *c) | 876 | static void __check_watermark(struct dm_bufio_client *c, |
| 877 | struct list_head *write_list) | ||
| 857 | { | 878 | { |
| 858 | unsigned long threshold_buffers, limit_buffers; | 879 | unsigned long threshold_buffers, limit_buffers; |
| 859 | 880 | ||
| @@ -872,7 +893,7 @@ static void __check_watermark(struct dm_bufio_client *c) | |||
| 872 | } | 893 | } |
| 873 | 894 | ||
| 874 | if (c->n_buffers[LIST_DIRTY] > threshold_buffers) | 895 | if (c->n_buffers[LIST_DIRTY] > threshold_buffers) |
| 875 | __write_dirty_buffers_async(c, 1); | 896 | __write_dirty_buffers_async(c, 1, write_list); |
| 876 | } | 897 | } |
| 877 | 898 | ||
| 878 | /* | 899 | /* |
| @@ -897,7 +918,8 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block) | |||
| 897 | *--------------------------------------------------------------*/ | 918 | *--------------------------------------------------------------*/ |
| 898 | 919 | ||
| 899 | static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block, | 920 | static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block, |
| 900 | enum new_flag nf, int *need_submit) | 921 | enum new_flag nf, int *need_submit, |
| 922 | struct list_head *write_list) | ||
| 901 | { | 923 | { |
| 902 | struct dm_buffer *b, *new_b = NULL; | 924 | struct dm_buffer *b, *new_b = NULL; |
| 903 | 925 | ||
| @@ -924,7 +946,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block, | |||
| 924 | goto found_buffer; | 946 | goto found_buffer; |
| 925 | } | 947 | } |
| 926 | 948 | ||
| 927 | __check_watermark(c); | 949 | __check_watermark(c, write_list); |
| 928 | 950 | ||
| 929 | b = new_b; | 951 | b = new_b; |
| 930 | b->hold_count = 1; | 952 | b->hold_count = 1; |
| @@ -992,10 +1014,14 @@ static void *new_read(struct dm_bufio_client *c, sector_t block, | |||
| 992 | int need_submit; | 1014 | int need_submit; |
| 993 | struct dm_buffer *b; | 1015 | struct dm_buffer *b; |
| 994 | 1016 | ||
| 1017 | LIST_HEAD(write_list); | ||
| 1018 | |||
| 995 | dm_bufio_lock(c); | 1019 | dm_bufio_lock(c); |
| 996 | b = __bufio_new(c, block, nf, &need_submit); | 1020 | b = __bufio_new(c, block, nf, &need_submit, &write_list); |
| 997 | dm_bufio_unlock(c); | 1021 | dm_bufio_unlock(c); |
| 998 | 1022 | ||
| 1023 | __flush_write_list(&write_list); | ||
| 1024 | |||
| 999 | if (!b) | 1025 | if (!b) |
| 1000 | return b; | 1026 | return b; |
| 1001 | 1027 | ||
| @@ -1047,6 +1073,8 @@ void dm_bufio_prefetch(struct dm_bufio_client *c, | |||
| 1047 | { | 1073 | { |
| 1048 | struct blk_plug plug; | 1074 | struct blk_plug plug; |
| 1049 | 1075 | ||
| 1076 | LIST_HEAD(write_list); | ||
| 1077 | |||
| 1050 | BUG_ON(dm_bufio_in_request()); | 1078 | BUG_ON(dm_bufio_in_request()); |
| 1051 | 1079 | ||
| 1052 | blk_start_plug(&plug); | 1080 | blk_start_plug(&plug); |
| @@ -1055,7 +1083,15 @@ void dm_bufio_prefetch(struct dm_bufio_client *c, | |||
| 1055 | for (; n_blocks--; block++) { | 1083 | for (; n_blocks--; block++) { |
| 1056 | int need_submit; | 1084 | int need_submit; |
| 1057 | struct dm_buffer *b; | 1085 | struct dm_buffer *b; |
| 1058 | b = __bufio_new(c, block, NF_PREFETCH, &need_submit); | 1086 | b = __bufio_new(c, block, NF_PREFETCH, &need_submit, |
| 1087 | &write_list); | ||
| 1088 | if (unlikely(!list_empty(&write_list))) { | ||
| 1089 | dm_bufio_unlock(c); | ||
| 1090 | blk_finish_plug(&plug); | ||
| 1091 | __flush_write_list(&write_list); | ||
| 1092 | blk_start_plug(&plug); | ||
| 1093 | dm_bufio_lock(c); | ||
| 1094 | } | ||
| 1059 | if (unlikely(b != NULL)) { | 1095 | if (unlikely(b != NULL)) { |
| 1060 | dm_bufio_unlock(c); | 1096 | dm_bufio_unlock(c); |
| 1061 | 1097 | ||
| @@ -1069,7 +1105,6 @@ void dm_bufio_prefetch(struct dm_bufio_client *c, | |||
| 1069 | goto flush_plug; | 1105 | goto flush_plug; |
| 1070 | dm_bufio_lock(c); | 1106 | dm_bufio_lock(c); |
| 1071 | } | 1107 | } |
| 1072 | |||
| 1073 | } | 1108 | } |
| 1074 | 1109 | ||
| 1075 | dm_bufio_unlock(c); | 1110 | dm_bufio_unlock(c); |
| @@ -1126,11 +1161,14 @@ EXPORT_SYMBOL_GPL(dm_bufio_mark_buffer_dirty); | |||
| 1126 | 1161 | ||
| 1127 | void dm_bufio_write_dirty_buffers_async(struct dm_bufio_client *c) | 1162 | void dm_bufio_write_dirty_buffers_async(struct dm_bufio_client *c) |
| 1128 | { | 1163 | { |
| 1164 | LIST_HEAD(write_list); | ||
| 1165 | |||
| 1129 | BUG_ON(dm_bufio_in_request()); | 1166 | BUG_ON(dm_bufio_in_request()); |
| 1130 | 1167 | ||
| 1131 | dm_bufio_lock(c); | 1168 | dm_bufio_lock(c); |
| 1132 | __write_dirty_buffers_async(c, 0); | 1169 | __write_dirty_buffers_async(c, 0, &write_list); |
| 1133 | dm_bufio_unlock(c); | 1170 | dm_bufio_unlock(c); |
| 1171 | __flush_write_list(&write_list); | ||
| 1134 | } | 1172 | } |
| 1135 | EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers_async); | 1173 | EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers_async); |
| 1136 | 1174 | ||
| @@ -1147,8 +1185,13 @@ int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c) | |||
| 1147 | unsigned long buffers_processed = 0; | 1185 | unsigned long buffers_processed = 0; |
| 1148 | struct dm_buffer *b, *tmp; | 1186 | struct dm_buffer *b, *tmp; |
| 1149 | 1187 | ||
| 1188 | LIST_HEAD(write_list); | ||
| 1189 | |||
| 1190 | dm_bufio_lock(c); | ||
| 1191 | __write_dirty_buffers_async(c, 0, &write_list); | ||
| 1192 | dm_bufio_unlock(c); | ||
| 1193 | __flush_write_list(&write_list); | ||
| 1150 | dm_bufio_lock(c); | 1194 | dm_bufio_lock(c); |
| 1151 | __write_dirty_buffers_async(c, 0); | ||
| 1152 | 1195 | ||
| 1153 | again: | 1196 | again: |
| 1154 | list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_DIRTY], lru_list) { | 1197 | list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_DIRTY], lru_list) { |
| @@ -1274,7 +1317,7 @@ retry: | |||
| 1274 | BUG_ON(!b->hold_count); | 1317 | BUG_ON(!b->hold_count); |
| 1275 | BUG_ON(test_bit(B_READING, &b->state)); | 1318 | BUG_ON(test_bit(B_READING, &b->state)); |
| 1276 | 1319 | ||
| 1277 | __write_dirty_buffer(b); | 1320 | __write_dirty_buffer(b, NULL); |
| 1278 | if (b->hold_count == 1) { | 1321 | if (b->hold_count == 1) { |
| 1279 | wait_on_bit(&b->state, B_WRITING, | 1322 | wait_on_bit(&b->state, B_WRITING, |
| 1280 | do_io_schedule, TASK_UNINTERRUPTIBLE); | 1323 | do_io_schedule, TASK_UNINTERRUPTIBLE); |
