Statistics
| Branch: | Revision:

root / block / commit.c @ 737e150e

History | View | Annotate | Download (7.3 kB)

1
/*
2
 * Live block commit
3
 *
4
 * Copyright Red Hat, Inc. 2012
5
 *
6
 * Authors:
7
 *  Jeff Cody   <jcody@redhat.com>
8
 *  Based on stream.c by Stefan Hajnoczi
9
 *
10
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
11
 * See the COPYING.LIB file in the top-level directory.
12
 *
13
 */
14

    
15
#include "trace.h"
16
#include "block/block_int.h"
17
#include "block/blockjob.h"
18
#include "qemu/ratelimit.h"
19

    
20
enum {
21
    /*
22
     * Size of data buffer for populating the image file.  This should be large
23
     * enough to process multiple clusters in a single call, so that populating
24
     * contiguous regions of the image is efficient.
25
     */
26
    COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */
27
};
28

    
29
#define SLICE_TIME 100000000ULL /* ns */
30

    
31
typedef struct CommitBlockJob {
32
    BlockJob common;
33
    RateLimit limit;
34
    BlockDriverState *active;
35
    BlockDriverState *top;
36
    BlockDriverState *base;
37
    BlockdevOnError on_error;
38
    int base_flags;
39
    int orig_overlay_flags;
40
} CommitBlockJob;
41

    
42
static int coroutine_fn commit_populate(BlockDriverState *bs,
43
                                        BlockDriverState *base,
44
                                        int64_t sector_num, int nb_sectors,
45
                                        void *buf)
46
{
47
    int ret = 0;
48

    
49
    ret = bdrv_read(bs, sector_num, buf, nb_sectors);
50
    if (ret) {
51
        return ret;
52
    }
53

    
54
    ret = bdrv_write(base, sector_num, buf, nb_sectors);
55
    if (ret) {
56
        return ret;
57
    }
58

    
59
    return 0;
60
}
61

    
62
static void coroutine_fn commit_run(void *opaque)
63
{
64
    CommitBlockJob *s = opaque;
65
    BlockDriverState *active = s->active;
66
    BlockDriverState *top = s->top;
67
    BlockDriverState *base = s->base;
68
    BlockDriverState *overlay_bs = NULL;
69
    int64_t sector_num, end;
70
    int ret = 0;
71
    int n = 0;
72
    void *buf;
73
    int bytes_written = 0;
74
    int64_t base_len;
75

    
76
    ret = s->common.len = bdrv_getlength(top);
77

    
78

    
79
    if (s->common.len < 0) {
80
        goto exit_restore_reopen;
81
    }
82

    
83
    ret = base_len = bdrv_getlength(base);
84
    if (base_len < 0) {
85
        goto exit_restore_reopen;
86
    }
87

    
88
    if (base_len < s->common.len) {
89
        ret = bdrv_truncate(base, s->common.len);
90
        if (ret) {
91
            goto exit_restore_reopen;
92
        }
93
    }
94

    
95
    overlay_bs = bdrv_find_overlay(active, top);
96

    
97
    end = s->common.len >> BDRV_SECTOR_BITS;
98
    buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE);
99

    
100
    for (sector_num = 0; sector_num < end; sector_num += n) {
101
        uint64_t delay_ns = 0;
102
        bool copy;
103

    
104
wait:
105
        /* Note that even when no rate limit is applied we need to yield
106
         * with no pending I/O here so that bdrv_drain_all() returns.
107
         */
108
        block_job_sleep_ns(&s->common, rt_clock, delay_ns);
109
        if (block_job_is_cancelled(&s->common)) {
110
            break;
111
        }
112
        /* Copy if allocated above the base */
113
        ret = bdrv_co_is_allocated_above(top, base, sector_num,
114
                                         COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE,
115
                                         &n);
116
        copy = (ret == 1);
117
        trace_commit_one_iteration(s, sector_num, n, ret);
118
        if (copy) {
119
            if (s->common.speed) {
120
                delay_ns = ratelimit_calculate_delay(&s->limit, n);
121
                if (delay_ns > 0) {
122
                    goto wait;
123
                }
124
            }
125
            ret = commit_populate(top, base, sector_num, n, buf);
126
            bytes_written += n * BDRV_SECTOR_SIZE;
127
        }
128
        if (ret < 0) {
129
            if (s->on_error == BLOCKDEV_ON_ERROR_STOP ||
130
                s->on_error == BLOCKDEV_ON_ERROR_REPORT||
131
                (s->on_error == BLOCKDEV_ON_ERROR_ENOSPC && ret == -ENOSPC)) {
132
                goto exit_free_buf;
133
            } else {
134
                n = 0;
135
                continue;
136
            }
137
        }
138
        /* Publish progress */
139
        s->common.offset += n * BDRV_SECTOR_SIZE;
140
    }
141

    
142
    ret = 0;
143

    
144
    if (!block_job_is_cancelled(&s->common) && sector_num == end) {
145
        /* success */
146
        ret = bdrv_drop_intermediate(active, top, base);
147
    }
148

    
149
exit_free_buf:
150
    qemu_vfree(buf);
151

    
152
exit_restore_reopen:
153
    /* restore base open flags here if appropriate (e.g., change the base back
154
     * to r/o). These reopens do not need to be atomic, since we won't abort
155
     * even on failure here */
156
    if (s->base_flags != bdrv_get_flags(base)) {
157
        bdrv_reopen(base, s->base_flags, NULL);
158
    }
159
    if (s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
160
        bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
161
    }
162

    
163
    block_job_completed(&s->common, ret);
164
}
165

    
166
static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp)
167
{
168
    CommitBlockJob *s = container_of(job, CommitBlockJob, common);
169

    
170
    if (speed < 0) {
171
        error_set(errp, QERR_INVALID_PARAMETER, "speed");
172
        return;
173
    }
174
    ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
175
}
176

    
177
static BlockJobType commit_job_type = {
178
    .instance_size = sizeof(CommitBlockJob),
179
    .job_type      = "commit",
180
    .set_speed     = commit_set_speed,
181
};
182

    
183
void commit_start(BlockDriverState *bs, BlockDriverState *base,
184
                  BlockDriverState *top, int64_t speed,
185
                  BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
186
                  void *opaque, Error **errp)
187
{
188
    CommitBlockJob *s;
189
    BlockReopenQueue *reopen_queue = NULL;
190
    int orig_overlay_flags;
191
    int orig_base_flags;
192
    BlockDriverState *overlay_bs;
193
    Error *local_err = NULL;
194

    
195
    if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
196
         on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
197
        !bdrv_iostatus_is_enabled(bs)) {
198
        error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
199
        return;
200
    }
201

    
202
    /* Once we support top == active layer, remove this check */
203
    if (top == bs) {
204
        error_setg(errp,
205
                   "Top image as the active layer is currently unsupported");
206
        return;
207
    }
208

    
209
    if (top == base) {
210
        error_setg(errp, "Invalid files for merge: top and base are the same");
211
        return;
212
    }
213

    
214
    overlay_bs = bdrv_find_overlay(bs, top);
215

    
216
    if (overlay_bs == NULL) {
217
        error_setg(errp, "Could not find overlay image for %s:", top->filename);
218
        return;
219
    }
220

    
221
    orig_base_flags    = bdrv_get_flags(base);
222
    orig_overlay_flags = bdrv_get_flags(overlay_bs);
223

    
224
    /* convert base & overlay_bs to r/w, if necessary */
225
    if (!(orig_base_flags & BDRV_O_RDWR)) {
226
        reopen_queue = bdrv_reopen_queue(reopen_queue, base,
227
                                         orig_base_flags | BDRV_O_RDWR);
228
    }
229
    if (!(orig_overlay_flags & BDRV_O_RDWR)) {
230
        reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs,
231
                                         orig_overlay_flags | BDRV_O_RDWR);
232
    }
233
    if (reopen_queue) {
234
        bdrv_reopen_multiple(reopen_queue, &local_err);
235
        if (local_err != NULL) {
236
            error_propagate(errp, local_err);
237
            return;
238
        }
239
    }
240

    
241

    
242
    s = block_job_create(&commit_job_type, bs, speed, cb, opaque, errp);
243
    if (!s) {
244
        return;
245
    }
246

    
247
    s->base   = base;
248
    s->top    = top;
249
    s->active = bs;
250

    
251
    s->base_flags          = orig_base_flags;
252
    s->orig_overlay_flags  = orig_overlay_flags;
253

    
254
    s->on_error = on_error;
255
    s->common.co = qemu_coroutine_create(commit_run);
256

    
257
    trace_commit_start(bs, base, top, s, s->common.co, opaque);
258
    qemu_coroutine_enter(s->common.co, s);
259
}