diff options
Diffstat (limited to 'block/blk-core.c')
-rw-r--r-- | block/blk-core.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 25f25271b42a..be43481bcb12 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -2023,7 +2023,14 @@ end_io: | |||
2023 | */ | 2023 | */ |
2024 | blk_qc_t generic_make_request(struct bio *bio) | 2024 | blk_qc_t generic_make_request(struct bio *bio) |
2025 | { | 2025 | { |
2026 | struct bio_list bio_list_on_stack; | 2026 | /* |
2027 | * bio_list_on_stack[0] contains bios submitted by the current | ||
2028 | * make_request_fn. | ||
2029 | * bio_list_on_stack[1] contains bios that were submitted before | ||
2030 | * the current make_request_fn, but that haven't been processed | ||
2031 | * yet. | ||
2032 | */ | ||
2033 | struct bio_list bio_list_on_stack[2]; | ||
2027 | blk_qc_t ret = BLK_QC_T_NONE; | 2034 | blk_qc_t ret = BLK_QC_T_NONE; |
2028 | 2035 | ||
2029 | if (!generic_make_request_checks(bio)) | 2036 | if (!generic_make_request_checks(bio)) |
@@ -2040,7 +2047,7 @@ blk_qc_t generic_make_request(struct bio *bio) | |||
2040 | * should be added at the tail | 2047 | * should be added at the tail |
2041 | */ | 2048 | */ |
2042 | if (current->bio_list) { | 2049 | if (current->bio_list) { |
2043 | bio_list_add(current->bio_list, bio); | 2050 | bio_list_add(¤t->bio_list[0], bio); |
2044 | goto out; | 2051 | goto out; |
2045 | } | 2052 | } |
2046 | 2053 | ||
@@ -2059,24 +2066,39 @@ blk_qc_t generic_make_request(struct bio *bio) | |||
2059 | * bio_list, and call into ->make_request() again. | 2066 | * bio_list, and call into ->make_request() again. |
2060 | */ | 2067 | */ |
2061 | BUG_ON(bio->bi_next); | 2068 | BUG_ON(bio->bi_next); |
2062 | bio_list_init(&bio_list_on_stack); | 2069 | bio_list_init(&bio_list_on_stack[0]); |
2063 | current->bio_list = &bio_list_on_stack; | 2070 | current->bio_list = bio_list_on_stack; |
2064 | do { | 2071 | do { |
2065 | struct request_queue *q = bdev_get_queue(bio->bi_bdev); | 2072 | struct request_queue *q = bdev_get_queue(bio->bi_bdev); |
2066 | 2073 | ||
2067 | if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) { | 2074 | if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) { |
2075 | struct bio_list lower, same; | ||
2076 | |||
2077 | /* Create a fresh bio_list for all subordinate requests */ | ||
2078 | bio_list_on_stack[1] = bio_list_on_stack[0]; | ||
2079 | bio_list_init(&bio_list_on_stack[0]); | ||
2068 | 2080 | ||
2069 | ret = q->make_request_fn(q, bio); | 2081 | ret = q->make_request_fn(q, bio); |
2070 | 2082 | ||
2071 | blk_queue_exit(q); | 2083 | blk_queue_exit(q); |
2072 | 2084 | /* sort new bios into those for a lower level | |
2073 | bio = bio_list_pop(current->bio_list); | 2085 | * and those for the same level |
2086 | */ | ||
2087 | bio_list_init(&lower); | ||
2088 | bio_list_init(&same); | ||
2089 | while ((bio = bio_list_pop(&bio_list_on_stack[0])) != NULL) | ||
2090 | if (q == bdev_get_queue(bio->bi_bdev)) | ||
2091 | bio_list_add(&same, bio); | ||
2092 | else | ||
2093 | bio_list_add(&lower, bio); | ||
2094 | /* now assemble so we handle the lowest level first */ | ||
2095 | bio_list_merge(&bio_list_on_stack[0], &lower); | ||
2096 | bio_list_merge(&bio_list_on_stack[0], &same); | ||
2097 | bio_list_merge(&bio_list_on_stack[0], &bio_list_on_stack[1]); | ||
2074 | } else { | 2098 | } else { |
2075 | struct bio *bio_next = bio_list_pop(current->bio_list); | ||
2076 | |||
2077 | bio_io_error(bio); | 2099 | bio_io_error(bio); |
2078 | bio = bio_next; | ||
2079 | } | 2100 | } |
2101 | bio = bio_list_pop(&bio_list_on_stack[0]); | ||
2080 | } while (bio); | 2102 | } while (bio); |
2081 | current->bio_list = NULL; /* deactivate */ | 2103 | current->bio_list = NULL; /* deactivate */ |
2082 | 2104 | ||