~fboudra/qemu-linaro/new-upstream-release-1.2.0-2012.09-0ubuntu1

« back to all changes in this revision

Viewing changes to block/stream.c

  • Committer: Fathi Boudra
  • Author(s): Fathi Boudra
  • Date: 2012-08-21 06:47:11 UTC
  • mfrom: (0.1.16)
  • Revision ID: fathi.boudra@linaro.org-20120821064711-7yxmubp2v8a44xce
Tags: 1.1.50-2012.08-0ubuntu1
* New upstream release.
  - support emulated systems with more than 2G of memory. (LP: #1030588)
* Drop powerpc-missing-include.patch - merged upstream.
* Update debian/control: 
  - drop perl build dependency.
  - add libfdt-dev build dependency.
* Update debian/qemu-keymaps.install file.
* Update debian/rules:
  - update QEMU_CPU for ARM architecture: armv4l -> armv7l.
  - update conf_audio_drv: default to PulseAudio since PA is the default on
    Ubuntu.
  - enable KVM on ARM architecture.
  - enable flat device tree support (--enable-fdt). (LP: #1030594)

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 
14
14
#include "trace.h"
15
15
#include "block_int.h"
 
16
#include "qemu/ratelimit.h"
16
17
 
17
18
enum {
18
19
    /*
25
26
 
26
27
#define SLICE_TIME 100000000ULL /* ns */
27
28
 
28
 
typedef struct {
29
 
    int64_t next_slice_time;
30
 
    uint64_t slice_quota;
31
 
    uint64_t dispatched;
32
 
} RateLimit;
33
 
 
34
 
static int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
35
 
{
36
 
    int64_t delay_ns = 0;
37
 
    int64_t now = qemu_get_clock_ns(rt_clock);
38
 
 
39
 
    if (limit->next_slice_time < now) {
40
 
        limit->next_slice_time = now + SLICE_TIME;
41
 
        limit->dispatched = 0;
42
 
    }
43
 
    if (limit->dispatched + n > limit->slice_quota) {
44
 
        delay_ns = limit->next_slice_time - now;
45
 
    } else {
46
 
        limit->dispatched += n;
47
 
    }
48
 
    return delay_ns;
49
 
}
50
 
 
51
 
static void ratelimit_set_speed(RateLimit *limit, uint64_t speed)
52
 
{
53
 
    limit->slice_quota = speed / (1000000000ULL / SLICE_TIME);
54
 
}
55
 
 
56
29
typedef struct StreamBlockJob {
57
30
    BlockJob common;
58
31
    RateLimit limit;
76
49
    return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
77
50
}
78
51
 
79
 
/*
80
 
 * Given an image chain: [BASE] -> [INTER1] -> [INTER2] -> [TOP]
81
 
 *
82
 
 * Return true if the given sector is allocated in top.
83
 
 * Return false if the given sector is allocated in intermediate images.
84
 
 * Return true otherwise.
85
 
 *
86
 
 * 'pnum' is set to the number of sectors (including and immediately following
87
 
 *  the specified sector) that are known to be in the same
88
 
 *  allocated/unallocated state.
89
 
 *
90
 
 */
91
 
static int coroutine_fn is_allocated_base(BlockDriverState *top,
92
 
                                          BlockDriverState *base,
93
 
                                          int64_t sector_num,
94
 
                                          int nb_sectors, int *pnum)
 
52
static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
 
53
                                const char *base_id)
95
54
{
96
55
    BlockDriverState *intermediate;
97
 
    int ret, n;
98
 
 
99
 
    ret = bdrv_co_is_allocated(top, sector_num, nb_sectors, &n);
100
 
    if (ret) {
101
 
        *pnum = n;
102
 
        return ret;
103
 
    }
104
 
 
105
 
    /*
106
 
     * Is the unallocated chunk [sector_num, n] also
107
 
     * unallocated between base and top?
108
 
     */
109
56
    intermediate = top->backing_hd;
110
57
 
111
58
    while (intermediate) {
112
 
        int pnum_inter;
 
59
        BlockDriverState *unused;
113
60
 
114
61
        /* reached base */
115
62
        if (intermediate == base) {
116
 
            *pnum = n;
117
 
            return 1;
118
 
        }
119
 
        ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
120
 
                                   &pnum_inter);
121
 
        if (ret < 0) {
122
 
            return ret;
123
 
        } else if (ret) {
124
 
            *pnum = pnum_inter;
125
 
            return 0;
126
 
        }
127
 
 
128
 
        /*
129
 
         * [sector_num, nb_sectors] is unallocated on top but intermediate
130
 
         * might have
131
 
         *
132
 
         * [sector_num+x, nr_sectors] allocated.
133
 
         */
134
 
        if (n > pnum_inter) {
135
 
            n = pnum_inter;
136
 
        }
137
 
 
 
63
            break;
 
64
        }
 
65
 
 
66
        unused = intermediate;
138
67
        intermediate = intermediate->backing_hd;
 
68
        unused->backing_hd = NULL;
 
69
        bdrv_delete(unused);
139
70
    }
140
 
 
141
 
    return 1;
 
71
    top->backing_hd = base;
142
72
}
143
73
 
144
74
static void coroutine_fn stream_run(void *opaque)
148
78
    BlockDriverState *base = s->base;
149
79
    int64_t sector_num, end;
150
80
    int ret = 0;
151
 
    int n;
 
81
    int n = 0;
152
82
    void *buf;
153
83
 
154
84
    s->common.len = bdrv_getlength(bs);
170
100
    }
171
101
 
172
102
    for (sector_num = 0; sector_num < end; sector_num += n) {
173
 
retry:
 
103
        uint64_t delay_ns = 0;
 
104
        bool copy;
 
105
 
 
106
wait:
 
107
        /* Note that even when no rate limit is applied we need to yield
 
108
         * with no pending I/O here so that qemu_aio_flush() returns.
 
109
         */
 
110
        block_job_sleep_ns(&s->common, rt_clock, delay_ns);
174
111
        if (block_job_is_cancelled(&s->common)) {
175
112
            break;
176
113
        }
177
114
 
178
 
 
179
 
        if (base) {
180
 
            ret = is_allocated_base(bs, base, sector_num,
181
 
                                    STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
 
115
        ret = bdrv_co_is_allocated(bs, sector_num,
 
116
                                   STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
 
117
        if (ret == 1) {
 
118
            /* Allocated in the top, no need to copy.  */
 
119
            copy = false;
182
120
        } else {
183
 
            ret = bdrv_co_is_allocated(bs, sector_num,
184
 
                                       STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE,
185
 
                                       &n);
 
121
            /* Copy if allocated in the intermediate images.  Limit to the
 
122
             * known-unallocated area [sector_num, sector_num+n).  */
 
123
            ret = bdrv_co_is_allocated_above(bs->backing_hd, base,
 
124
                                             sector_num, n, &n);
 
125
            copy = (ret == 1);
186
126
        }
187
127
        trace_stream_one_iteration(s, sector_num, n, ret);
188
 
        if (ret == 0) {
 
128
        if (ret >= 0 && copy) {
189
129
            if (s->common.speed) {
190
 
                uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
 
130
                delay_ns = ratelimit_calculate_delay(&s->limit, n);
191
131
                if (delay_ns > 0) {
192
 
                    co_sleep_ns(rt_clock, delay_ns);
193
 
 
194
 
                    /* Recheck cancellation and that sectors are unallocated */
195
 
                    goto retry;
 
132
                    goto wait;
196
133
                }
197
134
            }
198
135
            ret = stream_populate(bs, sector_num, n, buf);
204
141
 
205
142
        /* Publish progress */
206
143
        s->common.offset += n * BDRV_SECTOR_SIZE;
207
 
 
208
 
        /* Note that even when no rate limit is applied we need to yield
209
 
         * with no pending I/O here so that qemu_aio_flush() returns.
210
 
         */
211
 
        co_sleep_ns(rt_clock, 0);
212
144
    }
213
145
 
214
146
    if (!base) {
215
147
        bdrv_disable_copy_on_read(bs);
216
148
    }
217
149
 
218
 
    if (sector_num == end && ret == 0) {
219
 
        const char *base_id = NULL;
 
150
    if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
 
151
        const char *base_id = NULL, *base_fmt = NULL;
220
152
        if (base) {
221
153
            base_id = s->backing_file_id;
 
154
            if (base->drv) {
 
155
                base_fmt = base->drv->format_name;
 
156
            }
222
157
        }
223
 
        ret = bdrv_change_backing_file(bs, base_id, NULL);
 
158
        ret = bdrv_change_backing_file(bs, base_id, base_fmt);
 
159
        close_unused_images(bs, base, base_id);
224
160
    }
225
161
 
226
162
    qemu_vfree(buf);
227
163
    block_job_complete(&s->common, ret);
228
164
}
229
165
 
230
 
static int stream_set_speed(BlockJob *job, int64_t value)
 
166
static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp)
231
167
{
232
168
    StreamBlockJob *s = container_of(job, StreamBlockJob, common);
233
169
 
234
 
    if (value < 0) {
235
 
        return -EINVAL;
 
170
    if (speed < 0) {
 
171
        error_set(errp, QERR_INVALID_PARAMETER, "speed");
 
172
        return;
236
173
    }
237
 
    job->speed = value;
238
 
    ratelimit_set_speed(&s->limit, value / BDRV_SECTOR_SIZE);
239
 
    return 0;
 
174
    ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
240
175
}
241
176
 
242
177
static BlockJobType stream_job_type = {
245
180
    .set_speed     = stream_set_speed,
246
181
};
247
182
 
248
 
int stream_start(BlockDriverState *bs, BlockDriverState *base,
249
 
                 const char *base_id, BlockDriverCompletionFunc *cb,
250
 
                 void *opaque)
 
183
void stream_start(BlockDriverState *bs, BlockDriverState *base,
 
184
                  const char *base_id, int64_t speed,
 
185
                  BlockDriverCompletionFunc *cb,
 
186
                  void *opaque, Error **errp)
251
187
{
252
188
    StreamBlockJob *s;
253
 
    Coroutine *co;
254
189
 
255
 
    s = block_job_create(&stream_job_type, bs, cb, opaque);
 
190
    s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp);
256
191
    if (!s) {
257
 
        return -EBUSY; /* bs must already be in use */
 
192
        return;
258
193
    }
259
194
 
260
195
    s->base = base;
262
197
        pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
263
198
    }
264
199
 
265
 
    co = qemu_coroutine_create(stream_run);
266
 
    trace_stream_start(bs, base, s, co, opaque);
267
 
    qemu_coroutine_enter(co, s);
268
 
    return 0;
 
200
    s->common.co = qemu_coroutine_create(stream_run);
 
201
    trace_stream_start(bs, base, s, s->common.co, opaque);
 
202
    qemu_coroutine_enter(s->common.co, s);
269
203
}