root / block / stream.c @ 737e150e
History | View | Annotate | Download (6.7 kB)
1 | 4f1043b4 | Stefan Hajnoczi | /*
|
---|---|---|---|
2 | 4f1043b4 | Stefan Hajnoczi | * Image streaming
|
3 | 4f1043b4 | Stefan Hajnoczi | *
|
4 | 4f1043b4 | Stefan Hajnoczi | * Copyright IBM, Corp. 2011
|
5 | 4f1043b4 | Stefan Hajnoczi | *
|
6 | 4f1043b4 | Stefan Hajnoczi | * Authors:
|
7 | 4f1043b4 | Stefan Hajnoczi | * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
8 | 4f1043b4 | Stefan Hajnoczi | *
|
9 | 4f1043b4 | Stefan Hajnoczi | * This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
10 | 4f1043b4 | Stefan Hajnoczi | * See the COPYING.LIB file in the top-level directory.
|
11 | 4f1043b4 | Stefan Hajnoczi | *
|
12 | 4f1043b4 | Stefan Hajnoczi | */
|
13 | 4f1043b4 | Stefan Hajnoczi | |
14 | 4f1043b4 | Stefan Hajnoczi | #include "trace.h" |
15 | 737e150e | Paolo Bonzini | #include "block/block_int.h" |
16 | 737e150e | Paolo Bonzini | #include "block/blockjob.h" |
17 | 6ef228fc | Paolo Bonzini | #include "qemu/ratelimit.h" |
18 | 4f1043b4 | Stefan Hajnoczi | |
19 | 4f1043b4 | Stefan Hajnoczi | enum {
|
20 | 4f1043b4 | Stefan Hajnoczi | /*
|
21 | 4f1043b4 | Stefan Hajnoczi | * Size of data buffer for populating the image file. This should be large
|
22 | 4f1043b4 | Stefan Hajnoczi | * enough to process multiple clusters in a single call, so that populating
|
23 | 4f1043b4 | Stefan Hajnoczi | * contiguous regions of the image is efficient.
|
24 | 4f1043b4 | Stefan Hajnoczi | */
|
25 | 4f1043b4 | Stefan Hajnoczi | STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */ |
26 | 4f1043b4 | Stefan Hajnoczi | }; |
27 | 4f1043b4 | Stefan Hajnoczi | |
28 | 5094a6c0 | Stefan Hajnoczi | #define SLICE_TIME 100000000ULL /* ns */ |
29 | 5094a6c0 | Stefan Hajnoczi | |
30 | 4f1043b4 | Stefan Hajnoczi | typedef struct StreamBlockJob { |
31 | 4f1043b4 | Stefan Hajnoczi | BlockJob common; |
32 | 5094a6c0 | Stefan Hajnoczi | RateLimit limit; |
33 | 4f1043b4 | Stefan Hajnoczi | BlockDriverState *base; |
34 | 1d809098 | Paolo Bonzini | BlockdevOnError on_error; |
35 | c8c3080f | Marcelo Tosatti | char backing_file_id[1024]; |
36 | 4f1043b4 | Stefan Hajnoczi | } StreamBlockJob; |
37 | 4f1043b4 | Stefan Hajnoczi | |
38 | 4f1043b4 | Stefan Hajnoczi | static int coroutine_fn stream_populate(BlockDriverState *bs, |
39 | 4f1043b4 | Stefan Hajnoczi | int64_t sector_num, int nb_sectors,
|
40 | 4f1043b4 | Stefan Hajnoczi | void *buf)
|
41 | 4f1043b4 | Stefan Hajnoczi | { |
42 | 4f1043b4 | Stefan Hajnoczi | struct iovec iov = {
|
43 | 4f1043b4 | Stefan Hajnoczi | .iov_base = buf, |
44 | 4f1043b4 | Stefan Hajnoczi | .iov_len = nb_sectors * BDRV_SECTOR_SIZE, |
45 | 4f1043b4 | Stefan Hajnoczi | }; |
46 | 4f1043b4 | Stefan Hajnoczi | QEMUIOVector qiov; |
47 | 4f1043b4 | Stefan Hajnoczi | |
48 | 4f1043b4 | Stefan Hajnoczi | qemu_iovec_init_external(&qiov, &iov, 1);
|
49 | 4f1043b4 | Stefan Hajnoczi | |
50 | 4f1043b4 | Stefan Hajnoczi | /* Copy-on-read the unallocated clusters */
|
51 | 4f1043b4 | Stefan Hajnoczi | return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
|
52 | 4f1043b4 | Stefan Hajnoczi | } |
53 | 4f1043b4 | Stefan Hajnoczi | |
54 | 5a67a104 | Marcelo Tosatti | static void close_unused_images(BlockDriverState *top, BlockDriverState *base, |
55 | 5a67a104 | Marcelo Tosatti | const char *base_id) |
56 | 5a67a104 | Marcelo Tosatti | { |
57 | 5a67a104 | Marcelo Tosatti | BlockDriverState *intermediate; |
58 | 5a67a104 | Marcelo Tosatti | intermediate = top->backing_hd; |
59 | 5a67a104 | Marcelo Tosatti | |
60 | 5a67a104 | Marcelo Tosatti | while (intermediate) {
|
61 | 5a67a104 | Marcelo Tosatti | BlockDriverState *unused; |
62 | 5a67a104 | Marcelo Tosatti | |
63 | 5a67a104 | Marcelo Tosatti | /* reached base */
|
64 | 5a67a104 | Marcelo Tosatti | if (intermediate == base) {
|
65 | 5a67a104 | Marcelo Tosatti | break;
|
66 | 5a67a104 | Marcelo Tosatti | } |
67 | 5a67a104 | Marcelo Tosatti | |
68 | 5a67a104 | Marcelo Tosatti | unused = intermediate; |
69 | 5a67a104 | Marcelo Tosatti | intermediate = intermediate->backing_hd; |
70 | 5a67a104 | Marcelo Tosatti | unused->backing_hd = NULL;
|
71 | 5a67a104 | Marcelo Tosatti | bdrv_delete(unused); |
72 | 5a67a104 | Marcelo Tosatti | } |
73 | 5a67a104 | Marcelo Tosatti | top->backing_hd = base; |
74 | 5a67a104 | Marcelo Tosatti | } |
75 | 5a67a104 | Marcelo Tosatti | |
76 | 4f1043b4 | Stefan Hajnoczi | static void coroutine_fn stream_run(void *opaque) |
77 | 4f1043b4 | Stefan Hajnoczi | { |
78 | 4f1043b4 | Stefan Hajnoczi | StreamBlockJob *s = opaque; |
79 | 4f1043b4 | Stefan Hajnoczi | BlockDriverState *bs = s->common.bs; |
80 | c8c3080f | Marcelo Tosatti | BlockDriverState *base = s->base; |
81 | 4f1043b4 | Stefan Hajnoczi | int64_t sector_num, end; |
82 | 1d809098 | Paolo Bonzini | int error = 0; |
83 | 4f1043b4 | Stefan Hajnoczi | int ret = 0; |
84 | 04120e3b | Anthony Liguori | int n = 0; |
85 | 4f1043b4 | Stefan Hajnoczi | void *buf;
|
86 | 4f1043b4 | Stefan Hajnoczi | |
87 | 4f1043b4 | Stefan Hajnoczi | s->common.len = bdrv_getlength(bs); |
88 | 4f1043b4 | Stefan Hajnoczi | if (s->common.len < 0) { |
89 | 65f46322 | Paolo Bonzini | block_job_completed(&s->common, s->common.len); |
90 | 4f1043b4 | Stefan Hajnoczi | return;
|
91 | 4f1043b4 | Stefan Hajnoczi | } |
92 | 4f1043b4 | Stefan Hajnoczi | |
93 | 4f1043b4 | Stefan Hajnoczi | end = s->common.len >> BDRV_SECTOR_BITS; |
94 | 4f1043b4 | Stefan Hajnoczi | buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE); |
95 | 4f1043b4 | Stefan Hajnoczi | |
96 | 4f1043b4 | Stefan Hajnoczi | /* Turn on copy-on-read for the whole block device so that guest read
|
97 | 4f1043b4 | Stefan Hajnoczi | * requests help us make progress. Only do this when copying the entire
|
98 | 4f1043b4 | Stefan Hajnoczi | * backing chain since the copy-on-read operation does not take base into
|
99 | 4f1043b4 | Stefan Hajnoczi | * account.
|
100 | 4f1043b4 | Stefan Hajnoczi | */
|
101 | 4f1043b4 | Stefan Hajnoczi | if (!base) {
|
102 | 4f1043b4 | Stefan Hajnoczi | bdrv_enable_copy_on_read(bs); |
103 | 4f1043b4 | Stefan Hajnoczi | } |
104 | 4f1043b4 | Stefan Hajnoczi | |
105 | 4f1043b4 | Stefan Hajnoczi | for (sector_num = 0; sector_num < end; sector_num += n) { |
106 | 4513eafe | Paolo Bonzini | uint64_t delay_ns = 0;
|
107 | f9749f28 | Paolo Bonzini | bool copy;
|
108 | 4513eafe | Paolo Bonzini | |
109 | 4513eafe | Paolo Bonzini | wait:
|
110 | 4513eafe | Paolo Bonzini | /* Note that even when no rate limit is applied we need to yield
|
111 | c57b6656 | Kevin Wolf | * with no pending I/O here so that bdrv_drain_all() returns.
|
112 | 4513eafe | Paolo Bonzini | */
|
113 | 4513eafe | Paolo Bonzini | block_job_sleep_ns(&s->common, rt_clock, delay_ns); |
114 | 4f1043b4 | Stefan Hajnoczi | if (block_job_is_cancelled(&s->common)) {
|
115 | 4f1043b4 | Stefan Hajnoczi | break;
|
116 | 4f1043b4 | Stefan Hajnoczi | } |
117 | 4f1043b4 | Stefan Hajnoczi | |
118 | f9749f28 | Paolo Bonzini | ret = bdrv_co_is_allocated(bs, sector_num, |
119 | f9749f28 | Paolo Bonzini | STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n); |
120 | f9749f28 | Paolo Bonzini | if (ret == 1) { |
121 | f9749f28 | Paolo Bonzini | /* Allocated in the top, no need to copy. */
|
122 | f9749f28 | Paolo Bonzini | copy = false;
|
123 | f9749f28 | Paolo Bonzini | } else {
|
124 | f9749f28 | Paolo Bonzini | /* Copy if allocated in the intermediate images. Limit to the
|
125 | f9749f28 | Paolo Bonzini | * known-unallocated area [sector_num, sector_num+n). */
|
126 | 188a7bbf | Paolo Bonzini | ret = bdrv_co_is_allocated_above(bs->backing_hd, base, |
127 | 188a7bbf | Paolo Bonzini | sector_num, n, &n); |
128 | 571cd9dc | Stefan Hajnoczi | |
129 | 571cd9dc | Stefan Hajnoczi | /* Finish early if end of backing file has been reached */
|
130 | 571cd9dc | Stefan Hajnoczi | if (ret == 0 && n == 0) { |
131 | 571cd9dc | Stefan Hajnoczi | n = end - sector_num; |
132 | 571cd9dc | Stefan Hajnoczi | } |
133 | 571cd9dc | Stefan Hajnoczi | |
134 | f9749f28 | Paolo Bonzini | copy = (ret == 1);
|
135 | f9749f28 | Paolo Bonzini | } |
136 | 4f1043b4 | Stefan Hajnoczi | trace_stream_one_iteration(s, sector_num, n, ret); |
137 | f9749f28 | Paolo Bonzini | if (ret >= 0 && copy) { |
138 | 5094a6c0 | Stefan Hajnoczi | if (s->common.speed) {
|
139 | 4513eafe | Paolo Bonzini | delay_ns = ratelimit_calculate_delay(&s->limit, n); |
140 | 5094a6c0 | Stefan Hajnoczi | if (delay_ns > 0) { |
141 | 4513eafe | Paolo Bonzini | goto wait;
|
142 | 5094a6c0 | Stefan Hajnoczi | } |
143 | 5094a6c0 | Stefan Hajnoczi | } |
144 | 4f1043b4 | Stefan Hajnoczi | ret = stream_populate(bs, sector_num, n, buf); |
145 | 4f1043b4 | Stefan Hajnoczi | } |
146 | 4f1043b4 | Stefan Hajnoczi | if (ret < 0) { |
147 | 1d809098 | Paolo Bonzini | BlockErrorAction action = |
148 | 1d809098 | Paolo Bonzini | block_job_error_action(&s->common, s->common.bs, s->on_error, |
149 | 1d809098 | Paolo Bonzini | true, -ret);
|
150 | 1d809098 | Paolo Bonzini | if (action == BDRV_ACTION_STOP) {
|
151 | 1d809098 | Paolo Bonzini | n = 0;
|
152 | 1d809098 | Paolo Bonzini | continue;
|
153 | 1d809098 | Paolo Bonzini | } |
154 | 1d809098 | Paolo Bonzini | if (error == 0) { |
155 | 1d809098 | Paolo Bonzini | error = ret; |
156 | 1d809098 | Paolo Bonzini | } |
157 | 1d809098 | Paolo Bonzini | if (action == BDRV_ACTION_REPORT) {
|
158 | 1d809098 | Paolo Bonzini | break;
|
159 | 1d809098 | Paolo Bonzini | } |
160 | 4f1043b4 | Stefan Hajnoczi | } |
161 | c8c3080f | Marcelo Tosatti | ret = 0;
|
162 | 4f1043b4 | Stefan Hajnoczi | |
163 | 4f1043b4 | Stefan Hajnoczi | /* Publish progress */
|
164 | 4f1043b4 | Stefan Hajnoczi | s->common.offset += n * BDRV_SECTOR_SIZE; |
165 | 4f1043b4 | Stefan Hajnoczi | } |
166 | 4f1043b4 | Stefan Hajnoczi | |
167 | 4f1043b4 | Stefan Hajnoczi | if (!base) {
|
168 | 4f1043b4 | Stefan Hajnoczi | bdrv_disable_copy_on_read(bs); |
169 | 4f1043b4 | Stefan Hajnoczi | } |
170 | 4f1043b4 | Stefan Hajnoczi | |
171 | 1d809098 | Paolo Bonzini | /* Do not remove the backing file if an error was there but ignored. */
|
172 | 1d809098 | Paolo Bonzini | ret = error; |
173 | 1d809098 | Paolo Bonzini | |
174 | 3e914655 | Paolo Bonzini | if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) { |
175 | f6133def | Paolo Bonzini | const char *base_id = NULL, *base_fmt = NULL; |
176 | c8c3080f | Marcelo Tosatti | if (base) {
|
177 | c8c3080f | Marcelo Tosatti | base_id = s->backing_file_id; |
178 | f6133def | Paolo Bonzini | if (base->drv) {
|
179 | f6133def | Paolo Bonzini | base_fmt = base->drv->format_name; |
180 | f6133def | Paolo Bonzini | } |
181 | c8c3080f | Marcelo Tosatti | } |
182 | f6133def | Paolo Bonzini | ret = bdrv_change_backing_file(bs, base_id, base_fmt); |
183 | 5a67a104 | Marcelo Tosatti | close_unused_images(bs, base, base_id); |
184 | 4f1043b4 | Stefan Hajnoczi | } |
185 | 4f1043b4 | Stefan Hajnoczi | |
186 | 4f1043b4 | Stefan Hajnoczi | qemu_vfree(buf); |
187 | 65f46322 | Paolo Bonzini | block_job_completed(&s->common, ret); |
188 | 4f1043b4 | Stefan Hajnoczi | } |
189 | 4f1043b4 | Stefan Hajnoczi | |
190 | 882ec7ce | Stefan Hajnoczi | static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp) |
191 | 5094a6c0 | Stefan Hajnoczi | { |
192 | 5094a6c0 | Stefan Hajnoczi | StreamBlockJob *s = container_of(job, StreamBlockJob, common); |
193 | 5094a6c0 | Stefan Hajnoczi | |
194 | 882ec7ce | Stefan Hajnoczi | if (speed < 0) { |
195 | 882ec7ce | Stefan Hajnoczi | error_set(errp, QERR_INVALID_PARAMETER, "speed");
|
196 | 9e6636c7 | Stefan Hajnoczi | return;
|
197 | 5094a6c0 | Stefan Hajnoczi | } |
198 | 6ef228fc | Paolo Bonzini | ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); |
199 | 5094a6c0 | Stefan Hajnoczi | } |
200 | 5094a6c0 | Stefan Hajnoczi | |
201 | 4f1043b4 | Stefan Hajnoczi | static BlockJobType stream_job_type = {
|
202 | 4f1043b4 | Stefan Hajnoczi | .instance_size = sizeof(StreamBlockJob),
|
203 | 4f1043b4 | Stefan Hajnoczi | .job_type = "stream",
|
204 | 5094a6c0 | Stefan Hajnoczi | .set_speed = stream_set_speed, |
205 | 4f1043b4 | Stefan Hajnoczi | }; |
206 | 4f1043b4 | Stefan Hajnoczi | |
207 | fd7f8c65 | Stefan Hajnoczi | void stream_start(BlockDriverState *bs, BlockDriverState *base,
|
208 | c83c66c3 | Stefan Hajnoczi | const char *base_id, int64_t speed, |
209 | 1d809098 | Paolo Bonzini | BlockdevOnError on_error, |
210 | c83c66c3 | Stefan Hajnoczi | BlockDriverCompletionFunc *cb, |
211 | fd7f8c65 | Stefan Hajnoczi | void *opaque, Error **errp)
|
212 | 4f1043b4 | Stefan Hajnoczi | { |
213 | 4f1043b4 | Stefan Hajnoczi | StreamBlockJob *s; |
214 | 4f1043b4 | Stefan Hajnoczi | |
215 | 1d809098 | Paolo Bonzini | if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
|
216 | 1d809098 | Paolo Bonzini | on_error == BLOCKDEV_ON_ERROR_ENOSPC) && |
217 | 1d809098 | Paolo Bonzini | !bdrv_iostatus_is_enabled(bs)) { |
218 | 1d809098 | Paolo Bonzini | error_set(errp, QERR_INVALID_PARAMETER, "on-error");
|
219 | 1d809098 | Paolo Bonzini | return;
|
220 | 1d809098 | Paolo Bonzini | } |
221 | 1d809098 | Paolo Bonzini | |
222 | c83c66c3 | Stefan Hajnoczi | s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp); |
223 | 4f1043b4 | Stefan Hajnoczi | if (!s) {
|
224 | fd7f8c65 | Stefan Hajnoczi | return;
|
225 | 4f1043b4 | Stefan Hajnoczi | } |
226 | 4f1043b4 | Stefan Hajnoczi | |
227 | 4f1043b4 | Stefan Hajnoczi | s->base = base; |
228 | c8c3080f | Marcelo Tosatti | if (base_id) {
|
229 | c8c3080f | Marcelo Tosatti | pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
|
230 | c8c3080f | Marcelo Tosatti | } |
231 | 4f1043b4 | Stefan Hajnoczi | |
232 | 1d809098 | Paolo Bonzini | s->on_error = on_error; |
233 | fa4478d5 | Paolo Bonzini | s->common.co = qemu_coroutine_create(stream_run); |
234 | fa4478d5 | Paolo Bonzini | trace_stream_start(bs, base, s, s->common.co, opaque); |
235 | fa4478d5 | Paolo Bonzini | qemu_coroutine_enter(s->common.co, s); |
236 | 4f1043b4 | Stefan Hajnoczi | } |