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; 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 end = s->common.len >> BDRV_SECTOR_BITS; 96 buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); 97 98 for (sector_num = 0; sector_num < end; sector_num += n) { 99 uint64_t delay_ns = 0; 100 bool copy; 101 102 wait: 103 /* Note that even when no rate limit is applied we need to yield 104 * with no pending I/O here so that bdrv_drain_all() returns. 105 */ 106 block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); 107 if (block_job_is_cancelled(&s->common)) { 108 break; 109 } 110 /* Copy if allocated above the base */ 111 ret = bdrv_is_allocated_above(top, base, sector_num, 112 COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, 113 &n); 114 copy = (ret == 1); 115 trace_commit_one_iteration(s, sector_num, n, ret); 116 if (copy) { 117 if (s->common.speed) { 118 delay_ns = ratelimit_calculate_delay(&s->limit, n); 119 if (delay_ns > 0) { 120 goto wait; 121 } 122 } 123 ret = commit_populate(top, base, sector_num, n, buf); 124 bytes_written += n * BDRV_SECTOR_SIZE; 125 } 126 if (ret < 0) { 127 if (s->on_error == BLOCKDEV_ON_ERROR_STOP || 128 s->on_error == BLOCKDEV_ON_ERROR_REPORT|| 129 (s->on_error == BLOCKDEV_ON_ERROR_ENOSPC && ret == -ENOSPC)) { 130 goto exit_free_buf; 131 } else { 132 n = 0; 133 continue; 134 } 135 } 136 /* Publish progress */ 137 s->common.offset += n * BDRV_SECTOR_SIZE; 138 } 139 140 ret = 0; 141 142 if (!block_job_is_cancelled(&s->common) && sector_num == end) { 143 /* success */ 144 ret = bdrv_drop_intermediate(active, top, base); 145 } 146 147 exit_free_buf: 148 qemu_vfree(buf); 149 150 exit_restore_reopen: 151 /* restore base open flags here if appropriate (e.g., change the base back 152 * to r/o). These reopens do not need to be atomic, since we won't abort 153 * even on failure here */ 154 if (s->base_flags != bdrv_get_flags(base)) { 155 bdrv_reopen(base, s->base_flags, NULL); 156 } 157 overlay_bs = bdrv_find_overlay(active, top); 158 if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { 159 bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); 160 } 161 162 block_job_completed(&s->common, ret); 163 } 164 165 static void commit_set_speed(BlockJob *job, int64_t speed, Error **errp) 166 { 167 CommitBlockJob *s = container_of(job, CommitBlockJob, common); 168 169 if (speed < 0) { 170 error_set(errp, QERR_INVALID_PARAMETER, "speed"); 171 return; 172 } 173 ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME); 174 } 175 176 static const BlockJobDriver commit_job_driver = { 177 .instance_size = sizeof(CommitBlockJob), 178 .job_type = BLOCK_JOB_TYPE_COMMIT, 179 .set_speed = commit_set_speed, 180 }; 181 182 void commit_start(BlockDriverState *bs, BlockDriverState *base, 183 BlockDriverState *top, int64_t speed, 184 BlockdevOnError on_error, BlockDriverCompletionFunc *cb, 185 void *opaque, Error **errp) 186 { 187 CommitBlockJob *s; 188 BlockReopenQueue *reopen_queue = NULL; 189 int orig_overlay_flags; 190 int orig_base_flags; 191 BlockDriverState *overlay_bs; 192 Error *local_err = NULL; 193 194 if ((on_error == BLOCKDEV_ON_ERROR_STOP || 195 on_error == BLOCKDEV_ON_ERROR_ENOSPC) && 196 !bdrv_iostatus_is_enabled(bs)) { 197 error_setg(errp, "Invalid parameter combination"); 198 return; 199 } 200 201 assert(top != bs); 202 if (top == base) { 203 error_setg(errp, "Invalid files for merge: top and base are the same"); 204 return; 205 } 206 207 overlay_bs = bdrv_find_overlay(bs, top); 208 209 if (overlay_bs == NULL) { 210 error_setg(errp, "Could not find overlay image for %s:", top->filename); 211 return; 212 } 213 214 orig_base_flags = bdrv_get_flags(base); 215 orig_overlay_flags = bdrv_get_flags(overlay_bs); 216 217 /* convert base & overlay_bs to r/w, if necessary */ 218 if (!(orig_base_flags & BDRV_O_RDWR)) { 219 reopen_queue = bdrv_reopen_queue(reopen_queue, base, 220 orig_base_flags | BDRV_O_RDWR); 221 } 222 if (!(orig_overlay_flags & BDRV_O_RDWR)) { 223 reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, 224 orig_overlay_flags | BDRV_O_RDWR); 225 } 226 if (reopen_queue) { 227 bdrv_reopen_multiple(reopen_queue, &local_err); 228 if (local_err != NULL) { 229 error_propagate(errp, local_err); 230 return; 231 } 232 } 233 234 235 s = block_job_create(&commit_job_driver, bs, speed, cb, opaque, errp); 236 if (!s) { 237 return; 238 } 239 240 s->base = base; 241 s->top = top; 242 s->active = bs; 243 244 s->base_flags = orig_base_flags; 245 s->orig_overlay_flags = orig_overlay_flags; 246 247 s->on_error = on_error; 248 s->common.co = qemu_coroutine_create(commit_run); 249 250 trace_commit_start(bs, base, top, s, s->common.co, opaque); 251 qemu_coroutine_enter(s->common.co, s); 252 } 253