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 char *backing_file_str; 41 } CommitBlockJob; 42 43 static int coroutine_fn commit_populate(BlockDriverState *bs, 44 BlockDriverState *base, 45 int64_t sector_num, int nb_sectors, 46 void *buf) 47 { 48 int ret = 0; 49 50 ret = bdrv_read(bs, sector_num, buf, nb_sectors); 51 if (ret) { 52 return ret; 53 } 54 55 ret = bdrv_write(base, sector_num, buf, nb_sectors); 56 if (ret) { 57 return ret; 58 } 59 60 return 0; 61 } 62 63 static void coroutine_fn commit_run(void *opaque) 64 { 65 CommitBlockJob *s = opaque; 66 BlockDriverState *active = s->active; 67 BlockDriverState *top = s->top; 68 BlockDriverState *base = s->base; 69 BlockDriverState *overlay_bs; 70 int64_t sector_num, end; 71 int ret = 0; 72 int n = 0; 73 void *buf; 74 int bytes_written = 0; 75 int64_t base_len; 76 77 ret = s->common.len = bdrv_getlength(top); 78 79 80 if (s->common.len < 0) { 81 goto exit_restore_reopen; 82 } 83 84 ret = base_len = bdrv_getlength(base); 85 if (base_len < 0) { 86 goto exit_restore_reopen; 87 } 88 89 if (base_len < s->common.len) { 90 ret = bdrv_truncate(base, s->common.len); 91 if (ret) { 92 goto exit_restore_reopen; 93 } 94 } 95 96 end = s->common.len >> BDRV_SECTOR_BITS; 97 buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); 98 99 for (sector_num = 0; sector_num < end; sector_num += n) { 100 uint64_t delay_ns = 0; 101 bool copy; 102 103 wait: 104 /* Note that even when no rate limit is applied we need to yield 105 * with no pending I/O here so that bdrv_drain_all() returns. 106 */ 107 block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); 108 if (block_job_is_cancelled(&s->common)) { 109 break; 110 } 111 /* Copy if allocated above the base */ 112 ret = bdrv_is_allocated_above(top, base, sector_num, 113 COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, 114 &n); 115 copy = (ret == 1); 116 trace_commit_one_iteration(s, sector_num, n, ret); 117 if (copy) { 118 if (s->common.speed) { 119 delay_ns = ratelimit_calculate_delay(&s->limit, n); 120 if (delay_ns > 0) { 121 goto wait; 122 } 123 } 124 ret = commit_populate(top, base, sector_num, n, buf); 125 bytes_written += n * BDRV_SECTOR_SIZE; 126 } 127 if (ret < 0) { 128 if (s->on_error == BLOCKDEV_ON_ERROR_STOP || 129 s->on_error == BLOCKDEV_ON_ERROR_REPORT|| 130 (s->on_error == BLOCKDEV_ON_ERROR_ENOSPC && ret == -ENOSPC)) { 131 goto exit_free_buf; 132 } else { 133 n = 0; 134 continue; 135 } 136 } 137 /* Publish progress */ 138 s->common.offset += n * BDRV_SECTOR_SIZE; 139 } 140 141 ret = 0; 142 143 if (!block_job_is_cancelled(&s->common) && sector_num == end) { 144 /* success */ 145 ret = bdrv_drop_intermediate(active, top, base, s->backing_file_str); 146 } 147 148 exit_free_buf: 149 qemu_vfree(buf); 150 151 exit_restore_reopen: 152 /* restore base open flags here if appropriate (e.g., change the base back 153 * to r/o). These reopens do not need to be atomic, since we won't abort 154 * even on failure here */ 155 if (s->base_flags != bdrv_get_flags(base)) { 156 bdrv_reopen(base, s->base_flags, NULL); 157 } 158 overlay_bs = bdrv_find_overlay(active, top); 159 if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { 160 bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); 161 } 162 g_free(s->backing_file_str); 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 const BlockJobDriver commit_job_driver = { 178 .instance_size = sizeof(CommitBlockJob), 179 .job_type = BLOCK_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, const char *backing_file_str, 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_setg(errp, "Invalid parameter combination"); 199 return; 200 } 201 202 assert(top != bs); 203 if (top == base) { 204 error_setg(errp, "Invalid files for merge: top and base are the same"); 205 return; 206 } 207 208 overlay_bs = bdrv_find_overlay(bs, top); 209 210 if (overlay_bs == NULL) { 211 error_setg(errp, "Could not find overlay image for %s:", top->filename); 212 return; 213 } 214 215 orig_base_flags = bdrv_get_flags(base); 216 orig_overlay_flags = bdrv_get_flags(overlay_bs); 217 218 /* convert base & overlay_bs to r/w, if necessary */ 219 if (!(orig_base_flags & BDRV_O_RDWR)) { 220 reopen_queue = bdrv_reopen_queue(reopen_queue, base, 221 orig_base_flags | BDRV_O_RDWR); 222 } 223 if (!(orig_overlay_flags & BDRV_O_RDWR)) { 224 reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, 225 orig_overlay_flags | BDRV_O_RDWR); 226 } 227 if (reopen_queue) { 228 bdrv_reopen_multiple(reopen_queue, &local_err); 229 if (local_err != NULL) { 230 error_propagate(errp, local_err); 231 return; 232 } 233 } 234 235 236 s = block_job_create(&commit_job_driver, bs, speed, cb, opaque, errp); 237 if (!s) { 238 return; 239 } 240 241 s->base = base; 242 s->top = top; 243 s->active = bs; 244 245 s->base_flags = orig_base_flags; 246 s->orig_overlay_flags = orig_overlay_flags; 247 248 s->backing_file_str = g_strdup(backing_file_str); 249 250 s->on_error = on_error; 251 s->common.co = qemu_coroutine_create(commit_run); 252 253 trace_commit_start(bs, base, top, s, s->common.co, opaque); 254 qemu_coroutine_enter(s->common.co, s); 255 } 256