]>
Commit | Line | Data |
---|---|---|
e9ee6d7c | 1 | From c46139b295f9edffd43a12e7f029fce4f9b2ea46 Mon Sep 17 00:00:00 2001 |
ca0fe5f5 WB |
2 | From: Wolfgang Bumiller <w.bumiller@proxmox.com> |
3 | Date: Wed, 9 Dec 2015 15:04:57 +0100 | |
9c3bec39 | 4 | Subject: [PATCH 14/47] backup: modify job api |
ca0fe5f5 WB |
5 | |
6 | Introduces a BackupDump function callback and a pause_count | |
7 | for backup_start. For a dump-backup the target parameter | |
8 | can now be NULL so access to target needs to be guarded now. | |
9 | --- | |
e9ee6d7c | 10 | block/backup.c | 118 +++++++++++++++++++++++++++++----------------- |
1a91ab45 WB |
11 | block/replication.c | 3 +- |
12 | blockdev.c | 4 +- | |
13 | include/block/block_int.h | 5 ++ | |
e9ee6d7c | 14 | 4 files changed, 83 insertions(+), 47 deletions(-) |
ca0fe5f5 WB |
15 | |
16 | diff --git a/block/backup.c b/block/backup.c | |
e9ee6d7c | 17 | index a4fb288..fe4ce7f 100644 |
ca0fe5f5 WB |
18 | --- a/block/backup.c |
19 | +++ b/block/backup.c | |
1a91ab45 | 20 | @@ -36,6 +36,7 @@ typedef struct BackupBlockJob { |
ca0fe5f5 WB |
21 | BdrvDirtyBitmap *sync_bitmap; |
22 | MirrorSyncMode sync_mode; | |
23 | RateLimit limit; | |
24 | + BackupDumpFunc *dump_cb; | |
25 | BlockdevOnError on_source_error; | |
26 | BlockdevOnError on_target_error; | |
27 | CoRwlock flush_rwlock; | |
1a91ab45 | 28 | @@ -145,13 +146,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, |
ca0fe5f5 WB |
29 | goto out; |
30 | } | |
31 | ||
b07d35a5 | 32 | + int64_t start_sec = start * sectors_per_cluster; |
ca0fe5f5 | 33 | if (buffer_is_zero(iov.iov_base, iov.iov_len)) { |
68a30562 WB |
34 | - ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, |
35 | - bounce_qiov.size, BDRV_REQ_MAY_UNMAP); | |
ca0fe5f5 WB |
36 | + if (job->dump_cb) { |
37 | + ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL); | |
38 | + } | |
39 | + if (job->target) { | |
68a30562 WB |
40 | + ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size, |
41 | + bounce_qiov.size, BDRV_REQ_MAY_UNMAP); | |
ca0fe5f5 WB |
42 | + } |
43 | } else { | |
68a30562 | 44 | - ret = blk_co_pwritev(job->target, start * job->cluster_size, |
1a91ab45 WB |
45 | - bounce_qiov.size, &bounce_qiov, |
46 | - job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); | |
ca0fe5f5 WB |
47 | + if (job->dump_cb) { |
48 | + ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer); | |
49 | + } | |
50 | + if (job->target) { | |
68a30562 | 51 | + ret = blk_co_pwritev(job->target, start * job->cluster_size, |
1a91ab45 WB |
52 | + bounce_qiov.size, &bounce_qiov, |
53 | + job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0); | |
ca0fe5f5 WB |
54 | + } |
55 | } | |
56 | if (ret < 0) { | |
57 | trace_backup_do_cow_write_fail(job, start, ret); | |
e9ee6d7c WB |
58 | @@ -246,6 +258,8 @@ static void backup_abort(BlockJob *job) |
59 | static void backup_clean(BlockJob *job) | |
60 | { | |
61 | BackupBlockJob *s = container_of(job, BackupBlockJob, common); | |
62 | + if (!s->target) | |
63 | + return; | |
64 | assert(s->target); | |
65 | blk_unref(s->target); | |
66 | s->target = NULL; | |
67 | @@ -330,9 +344,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job, | |
ca0fe5f5 | 68 | if (read) { |
68a30562 WB |
69 | return block_job_error_action(&job->common, job->on_source_error, |
70 | true, error); | |
ca0fe5f5 WB |
71 | - } else { |
72 | + } else if (job->target) { | |
68a30562 WB |
73 | return block_job_error_action(&job->common, job->on_target_error, |
74 | false, error); | |
ca0fe5f5 WB |
75 | + } else { |
76 | + return BLOCK_ERROR_ACTION_REPORT; | |
77 | } | |
78 | } | |
79 | ||
e9ee6d7c | 80 | @@ -453,6 +469,7 @@ static void coroutine_fn backup_run(void *opaque) |
ca0fe5f5 | 81 | |
b07d35a5 | 82 | job->done_bitmap = bitmap_new(end); |
ca0fe5f5 | 83 | |
68a30562 WB |
84 | + |
85 | job->before_write.notify = backup_before_write_notify; | |
86 | bdrv_add_before_write_notifier(bs, &job->before_write); | |
ca0fe5f5 | 87 | |
e9ee6d7c | 88 | @@ -557,7 +574,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
ca0fe5f5 WB |
89 | BlockdevOnError on_source_error, |
90 | BlockdevOnError on_target_error, | |
1a91ab45 | 91 | int creation_flags, |
ca0fe5f5 WB |
92 | + BackupDumpFunc *dump_cb, |
93 | BlockCompletionFunc *cb, void *opaque, | |
94 | + int pause_count, | |
95 | BlockJobTxn *txn, Error **errp) | |
96 | { | |
97 | int64_t len; | |
e9ee6d7c | 98 | @@ -566,7 +585,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
b07d35a5 | 99 | int ret; |
ca0fe5f5 WB |
100 | |
101 | assert(bs); | |
102 | - assert(target); | |
103 | + assert(target || dump_cb); | |
ca0fe5f5 WB |
104 | |
105 | if (bs == target) { | |
68a30562 | 106 | error_setg(errp, "Source and target cannot be the same"); |
e9ee6d7c | 107 | @@ -579,13 +598,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
1a91ab45 | 108 | return NULL; |
ca0fe5f5 WB |
109 | } |
110 | ||
111 | - if (!bdrv_is_inserted(target)) { | |
112 | + if (target && !bdrv_is_inserted(target)) { | |
113 | error_setg(errp, "Device is not inserted: %s", | |
114 | bdrv_get_device_name(target)); | |
1a91ab45 WB |
115 | return NULL; |
116 | } | |
117 | ||
118 | - if (compress && target->drv->bdrv_co_pwritev_compressed == NULL) { | |
119 | + if (target && compress && target->drv->bdrv_co_pwritev_compressed == NULL) { | |
120 | error_setg(errp, "Compression is not supported for this drive %s", | |
121 | bdrv_get_device_name(target)); | |
122 | return NULL; | |
e9ee6d7c | 123 | @@ -595,7 +614,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
1a91ab45 | 124 | return NULL; |
ca0fe5f5 WB |
125 | } |
126 | ||
127 | - if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { | |
128 | + if (target && bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { | |
1a91ab45 | 129 | return NULL; |
ca0fe5f5 WB |
130 | } |
131 | ||
e9ee6d7c | 132 | @@ -635,15 +654,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
ca0fe5f5 WB |
133 | goto error; |
134 | } | |
135 | ||
1a91ab45 WB |
136 | - /* The target must match the source in size, so no resize here either */ |
137 | - job->target = blk_new(BLK_PERM_WRITE, | |
138 | - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | | |
139 | - BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); | |
140 | - ret = blk_insert_bs(job->target, target, errp); | |
141 | - if (ret < 0) { | |
142 | - goto error; | |
68a30562 | 143 | + if (target) { |
1a91ab45 WB |
144 | + /* The target must match the source in size, so no resize here either */ |
145 | + job->target = blk_new(BLK_PERM_WRITE, | |
146 | + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | | |
147 | + BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD); | |
148 | + ret = blk_insert_bs(job->target, target, errp); | |
149 | + if (ret < 0) { | |
150 | + goto error; | |
151 | + } | |
152 | } | |
68a30562 | 153 | |
ca0fe5f5 WB |
154 | + job->dump_cb = dump_cb; |
155 | job->on_source_error = on_source_error; | |
156 | job->on_target_error = on_target_error; | |
68a30562 | 157 | job->sync_mode = sync_mode; |
e9ee6d7c | 158 | @@ -651,36 +673,44 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
ca0fe5f5 | 159 | sync_bitmap : NULL; |
1a91ab45 | 160 | job->compress = compress; |
b07d35a5 TL |
161 | |
162 | - /* If there is no backing file on the target, we cannot rely on COW if our | |
163 | - * backup cluster size is smaller than the target cluster size. Even for | |
164 | - * targets with a backing file, try to avoid COW if possible. */ | |
68a30562 | 165 | - ret = bdrv_get_info(target, &bdi); |
1a91ab45 WB |
166 | - if (ret == -ENOTSUP && !target->backing) { |
167 | - /* Cluster size is not defined */ | |
168 | - error_report("WARNING: The target block device doesn't provide " | |
169 | - "information about the block size and it doesn't have a " | |
170 | - "backing file. The default block size of %u bytes is " | |
171 | - "used. If the actual block size of the target exceeds " | |
172 | - "this default, the backup may be unusable", | |
173 | - BACKUP_CLUSTER_SIZE_DEFAULT); | |
174 | - job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; | |
175 | - } else if (ret < 0 && !target->backing) { | |
b07d35a5 TL |
176 | - error_setg_errno(errp, -ret, |
177 | - "Couldn't determine the cluster size of the target image, " | |
178 | - "which has no backing file"); | |
179 | - error_append_hint(errp, | |
180 | - "Aborting, since this may create an unusable destination image\n"); | |
181 | - goto error; | |
182 | - } else if (ret < 0 && target->backing) { | |
183 | - /* Not fatal; just trudge on ahead. */ | |
184 | - job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; | |
185 | + if (target) { | |
186 | + /* If there is no backing file on the target, we cannot rely on COW if our | |
187 | + * backup cluster size is smaller than the target cluster size. Even for | |
188 | + * targets with a backing file, try to avoid COW if possible. */ | |
68a30562 | 189 | + ret = bdrv_get_info(target, &bdi); |
1a91ab45 WB |
190 | + if (ret == -ENOTSUP && !target->backing) { |
191 | + /* Cluster size is not defined */ | |
192 | + error_report("WARNING: The target block device doesn't provide " | |
193 | + "information about the block size and it doesn't have a " | |
194 | + "backing file. The default block size of %u bytes is " | |
195 | + "used. If the actual block size of the target exceeds " | |
196 | + "this default, the backup may be unusable", | |
197 | + BACKUP_CLUSTER_SIZE_DEFAULT); | |
198 | + job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; | |
199 | + } else if (ret < 0 && !target->backing) { | |
b07d35a5 TL |
200 | + error_setg_errno(errp, -ret, |
201 | + "Couldn't determine the cluster size of the target image, " | |
202 | + "which has no backing file"); | |
203 | + error_append_hint(errp, | |
204 | + "Aborting, since this may create an unusable destination image\n"); | |
205 | + goto error; | |
206 | + } else if (ret < 0 && target->backing) { | |
207 | + /* Not fatal; just trudge on ahead. */ | |
208 | + job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; | |
209 | + } else { | |
1a91ab45 | 210 | + job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; |
b07d35a5 | 211 | + } |
b07d35a5 TL |
212 | } else { |
213 | - job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size); | |
214 | + job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT; | |
215 | } | |
216 | ||
1a91ab45 WB |
217 | - /* Required permissions are already taken with target's blk_new() */ |
218 | - block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, | |
219 | - &error_abort); | |
220 | + if (target) { | |
221 | + /* Required permissions are already taken with target's blk_new() */ | |
222 | + block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, | |
223 | + &error_abort); | |
224 | + } else { | |
225 | + job->common.pause_count = pause_count; | |
226 | + } | |
ca0fe5f5 | 227 | job->common.len = len; |
ca0fe5f5 | 228 | block_job_txn_add_job(txn, &job->common); |
1a91ab45 WB |
229 | |
230 | diff --git a/block/replication.c b/block/replication.c | |
231 | index bf3c395..60c6524 100644 | |
232 | --- a/block/replication.c | |
233 | +++ b/block/replication.c | |
234 | @@ -531,7 +531,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode, | |
235 | 0, MIRROR_SYNC_MODE_NONE, NULL, false, | |
236 | BLOCKDEV_ON_ERROR_REPORT, | |
237 | BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL, | |
238 | - backup_job_completed, bs, NULL, &local_err); | |
239 | + NULL, | |
240 | + backup_job_completed, bs, 0, NULL, &local_err); | |
241 | if (local_err) { | |
242 | error_propagate(errp, local_err); | |
243 | backup_job_cleanup(bs); | |
ca0fe5f5 | 244 | diff --git a/blockdev.c b/blockdev.c |
1a91ab45 | 245 | index 040c152..bb3fc5b 100644 |
ca0fe5f5 WB |
246 | --- a/blockdev.c |
247 | +++ b/blockdev.c | |
1a91ab45 WB |
248 | @@ -3273,7 +3273,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, |
249 | job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, | |
250 | backup->sync, bmap, backup->compress, | |
251 | backup->on_source_error, backup->on_target_error, | |
252 | - BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); | |
253 | + BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); | |
68a30562 | 254 | bdrv_unref(target_bs); |
ca0fe5f5 | 255 | if (local_err != NULL) { |
ca0fe5f5 | 256 | error_propagate(errp, local_err); |
1a91ab45 WB |
257 | @@ -3352,7 +3352,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, |
258 | job = backup_job_create(backup->job_id, bs, target_bs, backup->speed, | |
259 | backup->sync, NULL, backup->compress, | |
260 | backup->on_source_error, backup->on_target_error, | |
261 | - BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err); | |
262 | + BLOCK_JOB_DEFAULT, NULL, NULL, NULL, 0, txn, &local_err); | |
ca0fe5f5 | 263 | if (local_err != NULL) { |
ca0fe5f5 | 264 | error_propagate(errp, local_err); |
68a30562 | 265 | } |
ca0fe5f5 | 266 | diff --git a/include/block/block_int.h b/include/block/block_int.h |
1a91ab45 | 267 | index 59400bd..ec65581 100644 |
ca0fe5f5 WB |
268 | --- a/include/block/block_int.h |
269 | +++ b/include/block/block_int.h | |
68a30562 | 270 | @@ -59,6 +59,9 @@ |
ca0fe5f5 WB |
271 | |
272 | #define BLOCK_PROBE_BUF_SIZE 512 | |
273 | ||
274 | +typedef int BackupDumpFunc(void *opaque, BlockDriverState *bs, | |
275 | + int64_t sector_num, int n_sectors, unsigned char *buf); | |
276 | + | |
277 | enum BdrvTrackedRequestType { | |
278 | BDRV_TRACKED_READ, | |
279 | BDRV_TRACKED_WRITE, | |
1a91ab45 WB |
280 | @@ -877,7 +880,9 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, |
281 | BlockdevOnError on_source_error, | |
282 | BlockdevOnError on_target_error, | |
283 | int creation_flags, | |
284 | + BackupDumpFunc *dump_cb, | |
285 | BlockCompletionFunc *cb, void *opaque, | |
286 | + int pause_count, | |
287 | BlockJobTxn *txn, Error **errp); | |
ca0fe5f5 | 288 | |
b07d35a5 | 289 | void hmp_drive_add_node(Monitor *mon, const char *optstr); |
ca0fe5f5 WB |
290 | -- |
291 | 2.1.4 | |
292 |