xref: /openbmc/qemu/block/commit.c (revision 61b9251a)
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 "qapi/qmp/qerror.h"
19 #include "qemu/ratelimit.h"
20 #include "sysemu/block-backend.h"
21 
22 enum {
23     /*
24      * Size of data buffer for populating the image file.  This should be large
25      * enough to process multiple clusters in a single call, so that populating
26      * contiguous regions of the image is efficient.
27      */
28     COMMIT_BUFFER_SIZE = 512 * 1024, /* in bytes */
29 };
30 
31 #define SLICE_TIME 100000000ULL /* ns */
32 
33 typedef struct CommitBlockJob {
34     BlockJob common;
35     RateLimit limit;
36     BlockDriverState *active;
37     BlockDriverState *top;
38     BlockDriverState *base;
39     BlockdevOnError on_error;
40     int base_flags;
41     int orig_overlay_flags;
42     char *backing_file_str;
43 } CommitBlockJob;
44 
45 static int coroutine_fn commit_populate(BlockDriverState *bs,
46                                         BlockDriverState *base,
47                                         int64_t sector_num, int nb_sectors,
48                                         void *buf)
49 {
50     int ret = 0;
51 
52     ret = bdrv_read(bs, sector_num, buf, nb_sectors);
53     if (ret) {
54         return ret;
55     }
56 
57     ret = bdrv_write(base, sector_num, buf, nb_sectors);
58     if (ret) {
59         return ret;
60     }
61 
62     return 0;
63 }
64 
65 typedef struct {
66     int ret;
67 } CommitCompleteData;
68 
69 static void commit_complete(BlockJob *job, void *opaque)
70 {
71     CommitBlockJob *s = container_of(job, CommitBlockJob, common);
72     CommitCompleteData *data = opaque;
73     BlockDriverState *active = s->active;
74     BlockDriverState *top = s->top;
75     BlockDriverState *base = s->base;
76     BlockDriverState *overlay_bs;
77     int ret = data->ret;
78 
79     if (!block_job_is_cancelled(&s->common) && ret == 0) {
80         /* success */
81         ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str);
82     }
83 
84     /* restore base open flags here if appropriate (e.g., change the base back
85      * to r/o). These reopens do not need to be atomic, since we won't abort
86      * even on failure here */
87     if (s->base_flags != bdrv_get_flags(base)) {
88         bdrv_reopen(base, s->base_flags, NULL);
89     }
90     overlay_bs = bdrv_find_overlay(active, top);
91     if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
92         bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
93     }
94     g_free(s->backing_file_str);
95     block_job_completed(&s->common, ret);
96     g_free(data);
97 }
98 
99 static void coroutine_fn commit_run(void *opaque)
100 {
101     CommitBlockJob *s = opaque;
102     CommitCompleteData *data;
103     BlockDriverState *top = s->top;
104     BlockDriverState *base = s->base;
105     int64_t sector_num, end;
106     int ret = 0;
107     int n = 0;
108     void *buf = NULL;
109     int bytes_written = 0;
110     int64_t base_len;
111 
112     ret = s->common.len = bdrv_getlength(top);
113 
114 
115     if (s->common.len < 0) {
116         goto out;
117     }
118 
119     ret = base_len = bdrv_getlength(base);
120     if (base_len < 0) {
121         goto out;
122     }
123 
124     if (base_len < s->common.len) {
125         ret = bdrv_truncate(base, s->common.len);
126         if (ret) {
127             goto out;
128         }
129     }
130 
131     end = s->common.len >> BDRV_SECTOR_BITS;
132     buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE);
133 
134     for (sector_num = 0; sector_num < end; sector_num += n) {
135         uint64_t delay_ns = 0;
136         bool copy;
137 
138 wait:
139         /* Note that even when no rate limit is applied we need to yield
140          * with no pending I/O here so that bdrv_drain_all() returns.
141          */
142         block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
143         if (block_job_is_cancelled(&s->common)) {
144             break;
145         }
146         /* Copy if allocated above the base */
147         ret = bdrv_is_allocated_above(top, base, sector_num,
148                                       COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE,
149                                       &n);
150         copy = (ret == 1);
151         trace_commit_one_iteration(s, sector_num, n, ret);
152         if (copy) {
153             if (s->common.speed) {
154                 delay_ns = ratelimit_calculate_delay(&s->limit, n);
155                 if (delay_ns > 0) {
156                     goto wait;
157                 }
158             }
159             ret = commit_populate(top, base, sector_num, n, buf);
160             bytes_written += n * BDRV_SECTOR_SIZE;
161         }
162         if (ret < 0) {
163             if (s->on_error == BLOCKDEV_ON_ERROR_STOP ||
164                 s->on_error == BLOCKDEV_ON_ERROR_REPORT||
165                 (s->on_error == BLOCKDEV_ON_ERROR_ENOSPC && ret == -ENOSPC)) {
166                 goto out;
167             } else {
168                 n = 0;
169                 continue;
170             }
171         }
172         /* Publish progress */
173         s->common.offset += n * BDRV_SECTOR_SIZE;
174     }
175 
176     ret = 0;
177 
178 out:
179     qemu_vfree(buf);
180 
181     data = g_malloc(sizeof(*data));
182     data->ret = ret;
183     block_job_defer_to_main_loop(&s->common, commit_complete, data);
184 }
185 
186 static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp)
187 {
188     CommitBlockJob *s = container_of(job, CommitBlockJob, common);
189 
190     if (speed < 0) {
191         error_setg(errp, QERR_INVALID_PARAMETER, "speed");
192         return;
193     }
194     ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
195 }
196 
197 static const BlockJobDriver commit_job_driver = {
198     .instance_size = sizeof(CommitBlockJob),
199     .job_type      = BLOCK_JOB_TYPE_COMMIT,
200     .set_speed     = commit_set_speed,
201 };
202 
203 void commit_start(BlockDriverState *bs, BlockDriverState *base,
204                   BlockDriverState *top, int64_t speed,
205                   BlockdevOnError on_error, BlockCompletionFunc *cb,
206                   void *opaque, const char *backing_file_str, Error **errp)
207 {
208     CommitBlockJob *s;
209     BlockReopenQueue *reopen_queue = NULL;
210     int orig_overlay_flags;
211     int orig_base_flags;
212     BlockDriverState *overlay_bs;
213     Error *local_err = NULL;
214 
215     if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
216          on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
217         (!bs->blk || !blk_iostatus_is_enabled(bs->blk))) {
218         error_setg(errp, "Invalid parameter combination");
219         return;
220     }
221 
222     assert(top != bs);
223     if (top == base) {
224         error_setg(errp, "Invalid files for merge: top and base are the same");
225         return;
226     }
227 
228     overlay_bs = bdrv_find_overlay(bs, top);
229 
230     if (overlay_bs == NULL) {
231         error_setg(errp, "Could not find overlay image for %s:", top->filename);
232         return;
233     }
234 
235     orig_base_flags    = bdrv_get_flags(base);
236     orig_overlay_flags = bdrv_get_flags(overlay_bs);
237 
238     /* convert base & overlay_bs to r/w, if necessary */
239     if (!(orig_overlay_flags & BDRV_O_RDWR)) {
240         reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
241                                          orig_overlay_flags | BDRV_O_RDWR);
242     }
243     if (!(orig_base_flags & BDRV_O_RDWR)) {
244         reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
245                                          orig_base_flags | BDRV_O_RDWR);
246     }
247     if (reopen_queue) {
248         bdrv_reopen_multiple(reopen_queue, &local_err);
249         if (local_err != NULL) {
250             error_propagate(errp, local_err);
251             return;
252         }
253     }
254 
255 
256     s = block_job_create(&commit_job_driver, bs, speed, cb, opaque, errp);
257     if (!s) {
258         return;
259     }
260 
261     s->base   = base;
262     s->top    = top;
263     s->active = bs;
264 
265     s->base_flags          = orig_base_flags;
266     s->orig_overlay_flags  = orig_overlay_flags;
267 
268     s->backing_file_str = g_strdup(backing_file_str);
269 
270     s->on_error = on_error;
271     s->common.co = qemu_coroutine_create(commit_run);
272 
273     trace_commit_start(bs, base, top, s, s->common.co, opaque);
274     qemu_coroutine_enter(s->common.co, s);
275 }
276