Print this page
*** NO COMMENTS ***
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libzfs/common/libzfs_sendrecv.c
+++ new/usr/src/lib/libzfs/common/libzfs_sendrecv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 25 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 + * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
26 27 */
27 28
28 29 #include <assert.h>
29 30 #include <ctype.h>
30 31 #include <errno.h>
31 32 #include <libintl.h>
32 33 #include <stdio.h>
33 34 #include <stdlib.h>
34 35 #include <strings.h>
35 36 #include <unistd.h>
36 37 #include <stddef.h>
37 38 #include <fcntl.h>
38 39 #include <sys/mount.h>
39 40 #include <pthread.h>
40 41 #include <umem.h>
41 42 #include <time.h>
42 43
43 44 #include <libzfs.h>
44 45
45 46 #include "zfs_namecheck.h"
46 47 #include "zfs_prop.h"
47 48 #include "zfs_fletcher.h"
48 49 #include "libzfs_impl.h"
49 50 #include <sha2.h>
50 51 #include <sys/zio_checksum.h>
51 52 #include <sys/ddt.h>
52 53
53 54 /* in libzfs_dataset.c */
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
54 55 extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
55 56
56 57 static int zfs_receive_impl(libzfs_handle_t *, const char *, recvflags_t *,
57 58 int, const char *, nvlist_t *, avl_tree_t *, char **, int, uint64_t *);
58 59
59 60 static const zio_cksum_t zero_cksum = { 0 };
60 61
61 62 typedef struct dedup_arg {
62 63 int inputfd;
63 64 int outputfd;
65 + uint64_t dedup_data_sz;
66 + boolean_t sendsize;
64 67 libzfs_handle_t *dedup_hdl;
65 68 } dedup_arg_t;
66 69
67 70 typedef struct progress_arg {
68 71 zfs_handle_t *pa_zhp;
69 72 int pa_fd;
70 73 boolean_t pa_parsable;
71 74 } progress_arg_t;
72 75
73 76 typedef struct dataref {
74 77 uint64_t ref_guid;
75 78 uint64_t ref_object;
76 79 uint64_t ref_offset;
77 80 } dataref_t;
78 81
79 82 typedef struct dedup_entry {
80 83 struct dedup_entry *dde_next;
81 84 zio_cksum_t dde_chksum;
82 85 uint64_t dde_prop;
83 86 dataref_t dde_ref;
84 87 } dedup_entry_t;
85 88
86 89 #define MAX_DDT_PHYSMEM_PERCENT 20
87 90 #define SMALLEST_POSSIBLE_MAX_DDT_MB 128
88 91
89 92 typedef struct dedup_table {
90 93 dedup_entry_t **dedup_hash_array;
91 94 umem_cache_t *ddecache;
92 95 uint64_t max_ddt_size; /* max dedup table size in bytes */
93 96 uint64_t cur_ddt_size; /* current dedup table size in bytes */
94 97 uint64_t ddt_count;
95 98 int numhashbits;
96 99 boolean_t ddt_full;
97 100 } dedup_table_t;
98 101
99 102 static int
100 103 high_order_bit(uint64_t n)
101 104 {
102 105 int count;
103 106
104 107 for (count = 0; n != 0; count++)
105 108 n >>= 1;
106 109 return (count);
107 110 }
108 111
109 112 static size_t
110 113 ssread(void *buf, size_t len, FILE *stream)
111 114 {
112 115 size_t outlen;
113 116
114 117 if ((outlen = fread(buf, len, 1, stream)) == 0)
115 118 return (0);
116 119
117 120 return (outlen);
118 121 }
119 122
120 123 static void
121 124 ddt_hash_append(libzfs_handle_t *hdl, dedup_table_t *ddt, dedup_entry_t **ddepp,
122 125 zio_cksum_t *cs, uint64_t prop, dataref_t *dr)
123 126 {
124 127 dedup_entry_t *dde;
125 128
126 129 if (ddt->cur_ddt_size >= ddt->max_ddt_size) {
127 130 if (ddt->ddt_full == B_FALSE) {
128 131 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
129 132 "Dedup table full. Deduplication will continue "
130 133 "with existing table entries"));
131 134 ddt->ddt_full = B_TRUE;
132 135 }
133 136 return;
134 137 }
135 138
136 139 if ((dde = umem_cache_alloc(ddt->ddecache, UMEM_DEFAULT))
137 140 != NULL) {
138 141 assert(*ddepp == NULL);
139 142 dde->dde_next = NULL;
140 143 dde->dde_chksum = *cs;
141 144 dde->dde_prop = prop;
142 145 dde->dde_ref = *dr;
143 146 *ddepp = dde;
144 147 ddt->cur_ddt_size += sizeof (dedup_entry_t);
145 148 ddt->ddt_count++;
146 149 }
147 150 }
148 151
149 152 /*
150 153 * Using the specified dedup table, do a lookup for an entry with
151 154 * the checksum cs. If found, return the block's reference info
152 155 * in *dr. Otherwise, insert a new entry in the dedup table, using
153 156 * the reference information specified by *dr.
154 157 *
155 158 * return value: true - entry was found
156 159 * false - entry was not found
157 160 */
158 161 static boolean_t
159 162 ddt_update(libzfs_handle_t *hdl, dedup_table_t *ddt, zio_cksum_t *cs,
160 163 uint64_t prop, dataref_t *dr)
161 164 {
162 165 uint32_t hashcode;
163 166 dedup_entry_t **ddepp;
164 167
165 168 hashcode = BF64_GET(cs->zc_word[0], 0, ddt->numhashbits);
166 169
167 170 for (ddepp = &(ddt->dedup_hash_array[hashcode]); *ddepp != NULL;
168 171 ddepp = &((*ddepp)->dde_next)) {
169 172 if (ZIO_CHECKSUM_EQUAL(((*ddepp)->dde_chksum), *cs) &&
170 173 (*ddepp)->dde_prop == prop) {
171 174 *dr = (*ddepp)->dde_ref;
172 175 return (B_TRUE);
173 176 }
174 177 }
175 178 ddt_hash_append(hdl, ddt, ddepp, cs, prop, dr);
176 179 return (B_FALSE);
|
↓ open down ↓ |
103 lines elided |
↑ open up ↑ |
177 180 }
178 181
179 182 static int
180 183 cksum_and_write(const void *buf, uint64_t len, zio_cksum_t *zc, int outfd)
181 184 {
182 185 fletcher_4_incremental_native(buf, len, zc);
183 186 return (write(outfd, buf, len));
184 187 }
185 188
186 189 /*
190 + * the function used by the cksummer thread that needs to know
191 + * about the sendsize flag
192 + */
193 +static int
194 +dedup_cksum_and_write(dedup_arg_t *dda, const void *buf, uint64_t len,
195 + zio_cksum_t *zc, int outfd)
196 +{
197 + int ret = len;
198 +
199 + dda->dedup_data_sz += len;
200 + fletcher_4_incremental_native(buf, len, zc);
201 + if (!dda->sendsize)
202 + ret = (write(outfd, buf, len));
203 +
204 + return (ret);
205 +}
206 +
207 +/*
187 208 * This function is started in a separate thread when the dedup option
188 209 * has been requested. The main send thread determines the list of
189 210 * snapshots to be included in the send stream and makes the ioctl calls
190 211 * for each one. But instead of having the ioctl send the output to the
191 212 * the output fd specified by the caller of zfs_send()), the
192 213 * ioctl is told to direct the output to a pipe, which is read by the
193 214 * alternate thread running THIS function. This function does the
194 215 * dedup'ing by:
195 216 * 1. building a dedup table (the DDT)
196 217 * 2. doing checksums on each data block and inserting a record in the DDT
197 218 * 3. looking for matching checksums, and
198 219 * 4. sending a DRR_WRITE_BYREF record instead of a write record whenever
199 220 * a duplicate block is found.
200 221 * The output of this function then goes to the output fd requested
201 222 * by the caller of zfs_send().
202 223 */
203 224 static void *
204 225 cksummer(void *arg)
205 226 {
206 227 dedup_arg_t *dda = arg;
207 228 char *buf = malloc(1<<20);
208 229 dmu_replay_record_t thedrr;
209 230 dmu_replay_record_t *drr = &thedrr;
210 231 struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
211 232 struct drr_end *drre = &thedrr.drr_u.drr_end;
212 233 struct drr_object *drro = &thedrr.drr_u.drr_object;
213 234 struct drr_write *drrw = &thedrr.drr_u.drr_write;
214 235 struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
215 236 FILE *ofp;
216 237 int outfd;
217 238 dmu_replay_record_t wbr_drr = {0};
218 239 struct drr_write_byref *wbr_drrr = &wbr_drr.drr_u.drr_write_byref;
219 240 dedup_table_t ddt;
220 241 zio_cksum_t stream_cksum;
221 242 uint64_t physmem = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
222 243 uint64_t numbuckets;
223 244
224 245 ddt.max_ddt_size =
225 246 MAX((physmem * MAX_DDT_PHYSMEM_PERCENT)/100,
226 247 SMALLEST_POSSIBLE_MAX_DDT_MB<<20);
227 248
228 249 numbuckets = ddt.max_ddt_size/(sizeof (dedup_entry_t));
229 250
230 251 /*
231 252 * numbuckets must be a power of 2. Increase number to
232 253 * a power of 2 if necessary.
233 254 */
234 255 if (!ISP2(numbuckets))
235 256 numbuckets = 1 << high_order_bit(numbuckets);
236 257
237 258 ddt.dedup_hash_array = calloc(numbuckets, sizeof (dedup_entry_t *));
238 259 ddt.ddecache = umem_cache_create("dde", sizeof (dedup_entry_t), 0,
239 260 NULL, NULL, NULL, NULL, NULL, 0);
240 261 ddt.cur_ddt_size = numbuckets * sizeof (dedup_entry_t *);
241 262 ddt.numhashbits = high_order_bit(numbuckets) - 1;
242 263 ddt.ddt_full = B_FALSE;
243 264
244 265 /* Initialize the write-by-reference block. */
245 266 wbr_drr.drr_type = DRR_WRITE_BYREF;
246 267 wbr_drr.drr_payloadlen = 0;
247 268
248 269 outfd = dda->outputfd;
249 270 ofp = fdopen(dda->inputfd, "r");
250 271 while (ssread(drr, sizeof (dmu_replay_record_t), ofp) != 0) {
251 272
252 273 switch (drr->drr_type) {
253 274 case DRR_BEGIN:
|
↓ open down ↓ |
57 lines elided |
↑ open up ↑ |
254 275 {
255 276 int fflags;
256 277 ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
257 278
258 279 /* set the DEDUP feature flag for this stream */
259 280 fflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
260 281 fflags |= (DMU_BACKUP_FEATURE_DEDUP |
261 282 DMU_BACKUP_FEATURE_DEDUPPROPS);
262 283 DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
263 284
264 - if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
285 + if (dedup_cksum_and_write(dda, drr,
286 + sizeof (dmu_replay_record_t),
265 287 &stream_cksum, outfd) == -1)
266 288 goto out;
267 289 if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
268 290 DMU_COMPOUNDSTREAM && drr->drr_payloadlen != 0) {
269 291 int sz = drr->drr_payloadlen;
270 292
271 293 if (sz > 1<<20) {
272 294 free(buf);
273 295 buf = malloc(sz);
274 296 }
275 297 (void) ssread(buf, sz, ofp);
276 298 if (ferror(stdin))
277 299 perror("fread");
278 - if (cksum_and_write(buf, sz, &stream_cksum,
279 - outfd) == -1)
300 + if (dedup_cksum_and_write(dda, buf, sz,
301 + &stream_cksum, outfd) == -1)
280 302 goto out;
281 303 }
282 304 break;
283 305 }
284 306
285 307 case DRR_END:
286 308 {
287 309 /* use the recalculated checksum */
288 310 ZIO_SET_CHECKSUM(&drre->drr_checksum,
289 311 stream_cksum.zc_word[0], stream_cksum.zc_word[1],
290 312 stream_cksum.zc_word[2], stream_cksum.zc_word[3]);
291 313 if ((write(outfd, drr,
292 314 sizeof (dmu_replay_record_t))) == -1)
293 315 goto out;
316 + dda->dedup_data_sz += sizeof (dmu_replay_record_t);
294 317 break;
295 318 }
296 319
297 320 case DRR_OBJECT:
298 321 {
299 - if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
322 + if (dedup_cksum_and_write(dda, drr,
323 + sizeof (dmu_replay_record_t),
300 324 &stream_cksum, outfd) == -1)
301 325 goto out;
302 326 if (drro->drr_bonuslen > 0) {
303 327 (void) ssread(buf,
304 328 P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
305 329 ofp);
306 - if (cksum_and_write(buf,
330 + if (dedup_cksum_and_write(dda, buf,
307 331 P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
308 332 &stream_cksum, outfd) == -1)
309 333 goto out;
310 334 }
311 335 break;
312 336 }
313 337
314 338 case DRR_SPILL:
315 339 {
316 - if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
340 + if (dedup_cksum_and_write(dda, drr,
341 + sizeof (dmu_replay_record_t),
317 342 &stream_cksum, outfd) == -1)
318 343 goto out;
319 344 (void) ssread(buf, drrs->drr_length, ofp);
320 - if (cksum_and_write(buf, drrs->drr_length,
345 + if (dedup_cksum_and_write(dda, buf, drrs->drr_length,
321 346 &stream_cksum, outfd) == -1)
322 347 goto out;
323 348 break;
324 349 }
325 350
326 351 case DRR_FREEOBJECTS:
327 352 {
328 - if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
353 + if (dedup_cksum_and_write(dda, drr,
354 + sizeof (dmu_replay_record_t),
329 355 &stream_cksum, outfd) == -1)
330 356 goto out;
331 357 break;
332 358 }
333 359
334 360 case DRR_WRITE:
335 361 {
336 362 dataref_t dataref;
337 363
338 364 (void) ssread(buf, drrw->drr_length, ofp);
339 365
340 366 /*
341 367 * Use the existing checksum if it's dedup-capable,
342 368 * else calculate a SHA256 checksum for it.
343 369 */
344 370
345 371 if (ZIO_CHECKSUM_EQUAL(drrw->drr_key.ddk_cksum,
346 372 zero_cksum) ||
347 373 !DRR_IS_DEDUP_CAPABLE(drrw->drr_checksumflags)) {
348 374 SHA256_CTX ctx;
349 375 zio_cksum_t tmpsha256;
350 376
351 377 SHA256Init(&ctx);
352 378 SHA256Update(&ctx, buf, drrw->drr_length);
353 379 SHA256Final(&tmpsha256, &ctx);
354 380 drrw->drr_key.ddk_cksum.zc_word[0] =
355 381 BE_64(tmpsha256.zc_word[0]);
356 382 drrw->drr_key.ddk_cksum.zc_word[1] =
357 383 BE_64(tmpsha256.zc_word[1]);
358 384 drrw->drr_key.ddk_cksum.zc_word[2] =
359 385 BE_64(tmpsha256.zc_word[2]);
360 386 drrw->drr_key.ddk_cksum.zc_word[3] =
361 387 BE_64(tmpsha256.zc_word[3]);
362 388 drrw->drr_checksumtype = ZIO_CHECKSUM_SHA256;
363 389 drrw->drr_checksumflags = DRR_CHECKSUM_DEDUP;
364 390 }
365 391
366 392 dataref.ref_guid = drrw->drr_toguid;
367 393 dataref.ref_object = drrw->drr_object;
368 394 dataref.ref_offset = drrw->drr_offset;
369 395
370 396 if (ddt_update(dda->dedup_hdl, &ddt,
371 397 &drrw->drr_key.ddk_cksum, drrw->drr_key.ddk_prop,
372 398 &dataref)) {
373 399 /* block already present in stream */
374 400 wbr_drrr->drr_object = drrw->drr_object;
375 401 wbr_drrr->drr_offset = drrw->drr_offset;
376 402 wbr_drrr->drr_length = drrw->drr_length;
377 403 wbr_drrr->drr_toguid = drrw->drr_toguid;
378 404 wbr_drrr->drr_refguid = dataref.ref_guid;
379 405 wbr_drrr->drr_refobject =
380 406 dataref.ref_object;
381 407 wbr_drrr->drr_refoffset =
382 408 dataref.ref_offset;
|
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
383 409
384 410 wbr_drrr->drr_checksumtype =
385 411 drrw->drr_checksumtype;
386 412 wbr_drrr->drr_checksumflags =
387 413 drrw->drr_checksumtype;
388 414 wbr_drrr->drr_key.ddk_cksum =
389 415 drrw->drr_key.ddk_cksum;
390 416 wbr_drrr->drr_key.ddk_prop =
391 417 drrw->drr_key.ddk_prop;
392 418
393 - if (cksum_and_write(&wbr_drr,
419 + if (dedup_cksum_and_write(dda, &wbr_drr,
394 420 sizeof (dmu_replay_record_t), &stream_cksum,
395 421 outfd) == -1)
396 422 goto out;
397 423 } else {
398 424 /* block not previously seen */
399 - if (cksum_and_write(drr,
425 + if (dedup_cksum_and_write(dda, drr,
400 426 sizeof (dmu_replay_record_t), &stream_cksum,
401 427 outfd) == -1)
402 428 goto out;
403 - if (cksum_and_write(buf,
429 + if (dedup_cksum_and_write(dda, buf,
404 430 drrw->drr_length,
405 431 &stream_cksum, outfd) == -1)
406 432 goto out;
407 433 }
408 434 break;
409 435 }
410 436
411 437 case DRR_FREE:
412 438 {
413 - if (cksum_and_write(drr, sizeof (dmu_replay_record_t),
439 + if (dedup_cksum_and_write(dda, drr,
440 + sizeof (dmu_replay_record_t),
414 441 &stream_cksum, outfd) == -1)
415 442 goto out;
416 443 break;
417 444 }
418 445
419 446 default:
420 447 (void) printf("INVALID record type 0x%x\n",
421 448 drr->drr_type);
422 449 /* should never happen, so assert */
423 450 assert(B_FALSE);
424 451 }
425 452 }
426 453 out:
427 454 umem_cache_destroy(ddt.ddecache);
428 455 free(ddt.dedup_hash_array);
429 456 free(buf);
430 457 (void) fclose(ofp);
431 458
432 459 return (NULL);
433 460 }
434 461
435 462 /*
436 463 * Routines for dealing with the AVL tree of fs-nvlists
437 464 */
438 465 typedef struct fsavl_node {
439 466 avl_node_t fn_node;
440 467 nvlist_t *fn_nvfs;
441 468 char *fn_snapname;
442 469 uint64_t fn_guid;
443 470 } fsavl_node_t;
444 471
445 472 static int
446 473 fsavl_compare(const void *arg1, const void *arg2)
447 474 {
448 475 const fsavl_node_t *fn1 = arg1;
449 476 const fsavl_node_t *fn2 = arg2;
450 477
451 478 if (fn1->fn_guid > fn2->fn_guid)
452 479 return (+1);
453 480 else if (fn1->fn_guid < fn2->fn_guid)
454 481 return (-1);
455 482 else
456 483 return (0);
457 484 }
458 485
459 486 /*
460 487 * Given the GUID of a snapshot, find its containing filesystem and
461 488 * (optionally) name.
462 489 */
463 490 static nvlist_t *
464 491 fsavl_find(avl_tree_t *avl, uint64_t snapguid, char **snapname)
465 492 {
466 493 fsavl_node_t fn_find;
467 494 fsavl_node_t *fn;
468 495
469 496 fn_find.fn_guid = snapguid;
470 497
471 498 fn = avl_find(avl, &fn_find, NULL);
472 499 if (fn) {
473 500 if (snapname)
474 501 *snapname = fn->fn_snapname;
475 502 return (fn->fn_nvfs);
476 503 }
477 504 return (NULL);
478 505 }
479 506
480 507 static void
481 508 fsavl_destroy(avl_tree_t *avl)
482 509 {
483 510 fsavl_node_t *fn;
484 511 void *cookie;
485 512
486 513 if (avl == NULL)
487 514 return;
488 515
489 516 cookie = NULL;
490 517 while ((fn = avl_destroy_nodes(avl, &cookie)) != NULL)
491 518 free(fn);
492 519 avl_destroy(avl);
493 520 free(avl);
494 521 }
495 522
496 523 /*
497 524 * Given an nvlist, produce an avl tree of snapshots, ordered by guid
498 525 */
499 526 static avl_tree_t *
500 527 fsavl_create(nvlist_t *fss)
501 528 {
502 529 avl_tree_t *fsavl;
503 530 nvpair_t *fselem = NULL;
504 531
505 532 if ((fsavl = malloc(sizeof (avl_tree_t))) == NULL)
506 533 return (NULL);
507 534
508 535 avl_create(fsavl, fsavl_compare, sizeof (fsavl_node_t),
509 536 offsetof(fsavl_node_t, fn_node));
510 537
511 538 while ((fselem = nvlist_next_nvpair(fss, fselem)) != NULL) {
512 539 nvlist_t *nvfs, *snaps;
513 540 nvpair_t *snapelem = NULL;
514 541
515 542 VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs));
516 543 VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps));
517 544
518 545 while ((snapelem =
519 546 nvlist_next_nvpair(snaps, snapelem)) != NULL) {
520 547 fsavl_node_t *fn;
521 548 uint64_t guid;
522 549
523 550 VERIFY(0 == nvpair_value_uint64(snapelem, &guid));
524 551 if ((fn = malloc(sizeof (fsavl_node_t))) == NULL) {
525 552 fsavl_destroy(fsavl);
526 553 return (NULL);
527 554 }
528 555 fn->fn_nvfs = nvfs;
529 556 fn->fn_snapname = nvpair_name(snapelem);
530 557 fn->fn_guid = guid;
531 558
532 559 /*
533 560 * Note: if there are multiple snaps with the
534 561 * same GUID, we ignore all but one.
535 562 */
536 563 if (avl_find(fsavl, fn, NULL) == NULL)
537 564 avl_add(fsavl, fn);
538 565 else
539 566 free(fn);
540 567 }
541 568 }
542 569
543 570 return (fsavl);
544 571 }
545 572
546 573 /*
547 574 * Routines for dealing with the giant nvlist of fs-nvlists, etc.
548 575 */
549 576 typedef struct send_data {
550 577 uint64_t parent_fromsnap_guid;
551 578 nvlist_t *parent_snaps;
552 579 nvlist_t *fss;
553 580 nvlist_t *snapprops;
554 581 const char *fromsnap;
555 582 const char *tosnap;
556 583 boolean_t recursive;
557 584
558 585 /*
559 586 * The header nvlist is of the following format:
560 587 * {
561 588 * "tosnap" -> string
562 589 * "fromsnap" -> string (if incremental)
563 590 * "fss" -> {
564 591 * id -> {
565 592 *
566 593 * "name" -> string (full name; for debugging)
567 594 * "parentfromsnap" -> number (guid of fromsnap in parent)
568 595 *
569 596 * "props" -> { name -> value (only if set here) }
570 597 * "snaps" -> { name (lastname) -> number (guid) }
571 598 * "snapprops" -> { name (lastname) -> { name -> value } }
572 599 *
573 600 * "origin" -> number (guid) (if clone)
574 601 * "sent" -> boolean (not on-disk)
575 602 * }
576 603 * }
577 604 * }
578 605 *
579 606 */
580 607 } send_data_t;
581 608
582 609 static void send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv);
583 610
584 611 static int
585 612 send_iterate_snap(zfs_handle_t *zhp, void *arg)
586 613 {
587 614 send_data_t *sd = arg;
588 615 uint64_t guid = zhp->zfs_dmustats.dds_guid;
589 616 char *snapname;
590 617 nvlist_t *nv;
591 618
592 619 snapname = strrchr(zhp->zfs_name, '@')+1;
593 620
594 621 VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid));
595 622 /*
596 623 * NB: if there is no fromsnap here (it's a newly created fs in
597 624 * an incremental replication), we will substitute the tosnap.
598 625 */
599 626 if ((sd->fromsnap && strcmp(snapname, sd->fromsnap) == 0) ||
600 627 (sd->parent_fromsnap_guid == 0 && sd->tosnap &&
601 628 strcmp(snapname, sd->tosnap) == 0)) {
602 629 sd->parent_fromsnap_guid = guid;
603 630 }
604 631
605 632 VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
606 633 send_iterate_prop(zhp, nv);
607 634 VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv));
608 635 nvlist_free(nv);
609 636
610 637 zfs_close(zhp);
611 638 return (0);
612 639 }
613 640
614 641 static void
615 642 send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv)
616 643 {
617 644 nvpair_t *elem = NULL;
618 645
619 646 while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) {
620 647 char *propname = nvpair_name(elem);
621 648 zfs_prop_t prop = zfs_name_to_prop(propname);
622 649 nvlist_t *propnv;
623 650
624 651 if (!zfs_prop_user(propname)) {
625 652 /*
626 653 * Realistically, this should never happen. However,
627 654 * we want the ability to add DSL properties without
628 655 * needing to make incompatible version changes. We
629 656 * need to ignore unknown properties to allow older
630 657 * software to still send datasets containing these
631 658 * properties, with the unknown properties elided.
632 659 */
633 660 if (prop == ZPROP_INVAL)
634 661 continue;
635 662
636 663 if (zfs_prop_readonly(prop))
637 664 continue;
638 665 }
639 666
640 667 verify(nvpair_value_nvlist(elem, &propnv) == 0);
641 668 if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION ||
642 669 prop == ZFS_PROP_REFQUOTA ||
643 670 prop == ZFS_PROP_REFRESERVATION) {
644 671 char *source;
645 672 uint64_t value;
646 673 verify(nvlist_lookup_uint64(propnv,
647 674 ZPROP_VALUE, &value) == 0);
648 675 if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
649 676 continue;
650 677 /*
651 678 * May have no source before SPA_VERSION_RECVD_PROPS,
652 679 * but is still modifiable.
653 680 */
654 681 if (nvlist_lookup_string(propnv,
655 682 ZPROP_SOURCE, &source) == 0) {
656 683 if ((strcmp(source, zhp->zfs_name) != 0) &&
657 684 (strcmp(source,
658 685 ZPROP_SOURCE_VAL_RECVD) != 0))
659 686 continue;
660 687 }
661 688 } else {
662 689 char *source;
663 690 if (nvlist_lookup_string(propnv,
664 691 ZPROP_SOURCE, &source) != 0)
665 692 continue;
666 693 if ((strcmp(source, zhp->zfs_name) != 0) &&
667 694 (strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0))
668 695 continue;
669 696 }
670 697
671 698 if (zfs_prop_user(propname) ||
672 699 zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
673 700 char *value;
674 701 verify(nvlist_lookup_string(propnv,
675 702 ZPROP_VALUE, &value) == 0);
676 703 VERIFY(0 == nvlist_add_string(nv, propname, value));
677 704 } else {
678 705 uint64_t value;
679 706 verify(nvlist_lookup_uint64(propnv,
680 707 ZPROP_VALUE, &value) == 0);
681 708 VERIFY(0 == nvlist_add_uint64(nv, propname, value));
682 709 }
683 710 }
684 711 }
685 712
686 713 /*
687 714 * recursively generate nvlists describing datasets. See comment
688 715 * for the data structure send_data_t above for description of contents
689 716 * of the nvlist.
690 717 */
691 718 static int
692 719 send_iterate_fs(zfs_handle_t *zhp, void *arg)
693 720 {
694 721 send_data_t *sd = arg;
695 722 nvlist_t *nvfs, *nv;
696 723 int rv = 0;
697 724 uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
698 725 uint64_t guid = zhp->zfs_dmustats.dds_guid;
699 726 char guidstring[64];
700 727
701 728 VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0));
702 729 VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name));
703 730 VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap",
704 731 sd->parent_fromsnap_guid));
705 732
706 733 if (zhp->zfs_dmustats.dds_origin[0]) {
707 734 zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
708 735 zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT);
709 736 if (origin == NULL)
710 737 return (-1);
711 738 VERIFY(0 == nvlist_add_uint64(nvfs, "origin",
712 739 origin->zfs_dmustats.dds_guid));
713 740 }
714 741
715 742 /* iterate over props */
716 743 VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
717 744 send_iterate_prop(zhp, nv);
718 745 VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv));
719 746 nvlist_free(nv);
720 747
721 748 /* iterate over snaps, and set sd->parent_fromsnap_guid */
722 749 sd->parent_fromsnap_guid = 0;
723 750 VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
724 751 VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
725 752 (void) zfs_iter_snapshots(zhp, send_iterate_snap, sd);
726 753 VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
727 754 VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
728 755 nvlist_free(sd->parent_snaps);
729 756 nvlist_free(sd->snapprops);
730 757
731 758 /* add this fs to nvlist */
732 759 (void) snprintf(guidstring, sizeof (guidstring),
733 760 "0x%llx", (longlong_t)guid);
734 761 VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs));
735 762 nvlist_free(nvfs);
736 763
737 764 /* iterate over children */
738 765 if (sd->recursive)
739 766 rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd);
740 767
741 768 sd->parent_fromsnap_guid = parent_fromsnap_guid_save;
742 769
743 770 zfs_close(zhp);
744 771 return (rv);
745 772 }
746 773
747 774 static int
748 775 gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
749 776 const char *tosnap, boolean_t recursive, nvlist_t **nvlp, avl_tree_t **avlp)
750 777 {
751 778 zfs_handle_t *zhp;
752 779 send_data_t sd = { 0 };
753 780 int error;
754 781
755 782 zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
756 783 if (zhp == NULL)
757 784 return (EZFS_BADTYPE);
758 785
759 786 VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0));
760 787 sd.fromsnap = fromsnap;
761 788 sd.tosnap = tosnap;
762 789 sd.recursive = recursive;
763 790
764 791 if ((error = send_iterate_fs(zhp, &sd)) != 0) {
765 792 nvlist_free(sd.fss);
766 793 if (avlp != NULL)
767 794 *avlp = NULL;
768 795 *nvlp = NULL;
769 796 return (error);
770 797 }
771 798
772 799 if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) {
773 800 nvlist_free(sd.fss);
774 801 *nvlp = NULL;
775 802 return (EZFS_NOMEM);
776 803 }
777 804
778 805 *nvlp = sd.fss;
779 806 return (0);
780 807 }
781 808
|
↓ open down ↓ |
358 lines elided |
↑ open up ↑ |
782 809 /*
783 810 * Routines specific to "zfs send"
784 811 */
785 812 typedef struct send_dump_data {
786 813 /* these are all just the short snapname (the part after the @) */
787 814 const char *fromsnap;
788 815 const char *tosnap;
789 816 char prevsnap[ZFS_MAXNAMELEN];
790 817 uint64_t prevsnap_obj;
791 818 boolean_t seenfrom, seento, replicate, doall, fromorigin;
792 - boolean_t verbose, dryrun, parsable, progress;
819 + boolean_t verbose, dryrun, dedup, parsable, progress;
820 + boolean_t sendsize;
821 + uint32_t hdr_send_sz;
822 + uint64_t send_sz;
793 823 int outfd;
794 824 boolean_t err;
795 825 nvlist_t *fss;
796 826 avl_tree_t *fsavl;
797 827 snapfilter_cb_t *filter_cb;
798 828 void *filter_cb_arg;
799 829 nvlist_t *debugnv;
800 830 char holdtag[ZFS_MAXNAMELEN];
801 831 int cleanup_fd;
802 832 uint64_t size;
803 833 } send_dump_data_t;
804 834
805 835 static int
806 836 estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj,
807 837 boolean_t fromorigin, uint64_t *sizep)
808 838 {
809 839 zfs_cmd_t zc = { 0 };
810 840 libzfs_handle_t *hdl = zhp->zfs_hdl;
811 841
812 842 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
813 843 assert(fromsnap_obj == 0 || !fromorigin);
814 844
815 845 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
816 846 zc.zc_obj = fromorigin;
817 847 zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
818 848 zc.zc_fromobj = fromsnap_obj;
819 849 zc.zc_guid = 1; /* estimate flag */
820 850
821 851 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
822 852 char errbuf[1024];
823 853 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
824 854 "warning: cannot estimate space for '%s'"), zhp->zfs_name);
825 855
826 856 switch (errno) {
827 857 case EXDEV:
828 858 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
829 859 "not an earlier snapshot from the same fs"));
830 860 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
831 861
832 862 case ENOENT:
833 863 if (zfs_dataset_exists(hdl, zc.zc_name,
834 864 ZFS_TYPE_SNAPSHOT)) {
835 865 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
836 866 "incremental source (@%s) does not exist"),
837 867 zc.zc_value);
838 868 }
839 869 return (zfs_error(hdl, EZFS_NOENT, errbuf));
840 870
841 871 case EDQUOT:
842 872 case EFBIG:
843 873 case EIO:
844 874 case ENOLINK:
845 875 case ENOSPC:
846 876 case ENOSTR:
847 877 case ENXIO:
848 878 case EPIPE:
849 879 case ERANGE:
850 880 case EFAULT:
851 881 case EROFS:
852 882 zfs_error_aux(hdl, strerror(errno));
853 883 return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
854 884
855 885 default:
856 886 return (zfs_standard_error(hdl, errno, errbuf));
857 887 }
858 888 }
859 889
860 890 *sizep = zc.zc_objset_type;
|
↓ open down ↓ |
58 lines elided |
↑ open up ↑ |
861 891
862 892 return (0);
863 893 }
864 894
865 895 /*
866 896 * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
867 897 * NULL) to the file descriptor specified by outfd.
868 898 */
869 899 static int
870 900 dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
871 - boolean_t fromorigin, int outfd, nvlist_t *debugnv)
901 + boolean_t fromorigin, int outfd, nvlist_t *debugnv,
902 + boolean_t sendsize, uint64_t *sendcounter)
872 903 {
873 904 zfs_cmd_t zc = { 0 };
874 905 libzfs_handle_t *hdl = zhp->zfs_hdl;
875 906 nvlist_t *thisdbg;
876 907
877 908 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
878 909 assert(fromsnap_obj == 0 || !fromorigin);
879 910
880 911 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
881 912 zc.zc_cookie = outfd;
882 913 zc.zc_obj = fromorigin;
883 914 zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
884 915 zc.zc_fromobj = fromsnap_obj;
916 + zc.zc_sendsize = sendsize;
917 + zc.zc_sendcounter = 0;
885 918
886 919 VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
887 920 if (fromsnap && fromsnap[0] != '\0') {
888 921 VERIFY(0 == nvlist_add_string(thisdbg,
889 922 "fromsnap", fromsnap));
890 923 }
891 924
892 925 if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
893 926 char errbuf[1024];
894 927 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
895 928 "warning: cannot send '%s'"), zhp->zfs_name);
896 929
897 930 VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno));
898 931 if (debugnv) {
899 932 VERIFY(0 == nvlist_add_nvlist(debugnv,
900 933 zhp->zfs_name, thisdbg));
901 934 }
902 935 nvlist_free(thisdbg);
903 936
904 937 switch (errno) {
905 938 case EXDEV:
906 939 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
907 940 "not an earlier snapshot from the same fs"));
908 941 return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
909 942
910 943 case ENOENT:
911 944 if (zfs_dataset_exists(hdl, zc.zc_name,
912 945 ZFS_TYPE_SNAPSHOT)) {
913 946 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
914 947 "incremental source (@%s) does not exist"),
915 948 zc.zc_value);
916 949 }
917 950 return (zfs_error(hdl, EZFS_NOENT, errbuf));
918 951
919 952 case EDQUOT:
920 953 case EFBIG:
921 954 case EIO:
922 955 case ENOLINK:
923 956 case ENOSPC:
924 957 case ENOSTR:
925 958 case ENXIO:
926 959 case EPIPE:
927 960 case ERANGE:
|
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
928 961 case EFAULT:
929 962 case EROFS:
930 963 zfs_error_aux(hdl, strerror(errno));
931 964 return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
932 965
933 966 default:
934 967 return (zfs_standard_error(hdl, errno, errbuf));
935 968 }
936 969 }
937 970
971 + *sendcounter = (uint64_t)zc.zc_sendcounter;
938 972 if (debugnv)
939 973 VERIFY(0 == nvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg));
940 974 nvlist_free(thisdbg);
941 975
942 976 return (0);
943 977 }
944 978
945 979 static int
946 980 hold_for_send(zfs_handle_t *zhp, send_dump_data_t *sdd)
947 981 {
948 982 zfs_handle_t *pzhp;
949 983 int error = 0;
950 984 char *thissnap;
951 985
952 986 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
953 987
954 988 if (sdd->dryrun)
955 989 return (0);
956 990
957 991 /*
958 992 * zfs_send() only opens a cleanup_fd for sends that need it,
959 993 * e.g. replication and doall.
960 994 */
961 995 if (sdd->cleanup_fd == -1)
962 996 return (0);
963 997
964 998 thissnap = strchr(zhp->zfs_name, '@') + 1;
965 999 *(thissnap - 1) = '\0';
966 1000 pzhp = zfs_open(zhp->zfs_hdl, zhp->zfs_name, ZFS_TYPE_DATASET);
967 1001 *(thissnap - 1) = '@';
968 1002
969 1003 /*
970 1004 * It's OK if the parent no longer exists. The send code will
971 1005 * handle that error.
972 1006 */
973 1007 if (pzhp) {
974 1008 error = zfs_hold(pzhp, thissnap, sdd->holdtag,
975 1009 B_FALSE, B_TRUE, B_TRUE, sdd->cleanup_fd,
976 1010 zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID),
977 1011 zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG));
978 1012 zfs_close(pzhp);
979 1013 }
980 1014
981 1015 return (error);
982 1016 }
983 1017
984 1018 static void *
985 1019 send_progress_thread(void *arg)
986 1020 {
987 1021 progress_arg_t *pa = arg;
988 1022
989 1023 zfs_cmd_t zc = { 0 };
990 1024 zfs_handle_t *zhp = pa->pa_zhp;
991 1025 libzfs_handle_t *hdl = zhp->zfs_hdl;
992 1026 unsigned long long bytes;
993 1027 char buf[16];
994 1028
995 1029 time_t t;
996 1030 struct tm *tm;
997 1031
998 1032 assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
999 1033 (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
1000 1034
1001 1035 if (!pa->pa_parsable)
1002 1036 (void) fprintf(stderr, "TIME SENT SNAPSHOT\n");
1003 1037
1004 1038 /*
1005 1039 * Print the progress from ZFS_IOC_SEND_PROGRESS every second.
1006 1040 */
1007 1041 for (;;) {
1008 1042 (void) sleep(1);
1009 1043
1010 1044 zc.zc_cookie = pa->pa_fd;
1011 1045 if (zfs_ioctl(hdl, ZFS_IOC_SEND_PROGRESS, &zc) != 0)
1012 1046 return ((void *)-1);
1013 1047
1014 1048 (void) time(&t);
1015 1049 tm = localtime(&t);
1016 1050 bytes = zc.zc_cookie;
1017 1051
1018 1052 if (pa->pa_parsable) {
1019 1053 (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
1020 1054 tm->tm_hour, tm->tm_min, tm->tm_sec,
1021 1055 bytes, zhp->zfs_name);
1022 1056 } else {
1023 1057 zfs_nicenum(bytes, buf, sizeof (buf));
1024 1058 (void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n",
1025 1059 tm->tm_hour, tm->tm_min, tm->tm_sec,
1026 1060 buf, zhp->zfs_name);
1027 1061 }
1028 1062 }
1029 1063 }
1030 1064
1031 1065 static int
1032 1066 dump_snapshot(zfs_handle_t *zhp, void *arg)
1033 1067 {
1034 1068 send_dump_data_t *sdd = arg;
1035 1069 progress_arg_t pa = { 0 };
1036 1070 pthread_t tid;
1037 1071
1038 1072 char *thissnap;
1039 1073 int err;
1040 1074 boolean_t isfromsnap, istosnap, fromorigin;
1041 1075 boolean_t exclude = B_FALSE;
1042 1076
1043 1077 thissnap = strchr(zhp->zfs_name, '@') + 1;
1044 1078 isfromsnap = (sdd->fromsnap != NULL &&
1045 1079 strcmp(sdd->fromsnap, thissnap) == 0);
1046 1080
1047 1081 if (!sdd->seenfrom && isfromsnap) {
1048 1082 err = hold_for_send(zhp, sdd);
1049 1083 if (err == 0) {
1050 1084 sdd->seenfrom = B_TRUE;
1051 1085 (void) strcpy(sdd->prevsnap, thissnap);
1052 1086 sdd->prevsnap_obj = zfs_prop_get_int(zhp,
1053 1087 ZFS_PROP_OBJSETID);
1054 1088 } else if (err == ENOENT) {
1055 1089 err = 0;
1056 1090 }
1057 1091 zfs_close(zhp);
1058 1092 return (err);
1059 1093 }
1060 1094
1061 1095 if (sdd->seento || !sdd->seenfrom) {
1062 1096 zfs_close(zhp);
1063 1097 return (0);
1064 1098 }
1065 1099
1066 1100 istosnap = (strcmp(sdd->tosnap, thissnap) == 0);
1067 1101 if (istosnap)
1068 1102 sdd->seento = B_TRUE;
1069 1103
1070 1104 if (!sdd->doall && !isfromsnap && !istosnap) {
1071 1105 if (sdd->replicate) {
1072 1106 char *snapname;
1073 1107 nvlist_t *snapprops;
1074 1108 /*
1075 1109 * Filter out all intermediate snapshots except origin
1076 1110 * snapshots needed to replicate clones.
1077 1111 */
1078 1112 nvlist_t *nvfs = fsavl_find(sdd->fsavl,
1079 1113 zhp->zfs_dmustats.dds_guid, &snapname);
1080 1114
1081 1115 VERIFY(0 == nvlist_lookup_nvlist(nvfs,
1082 1116 "snapprops", &snapprops));
1083 1117 VERIFY(0 == nvlist_lookup_nvlist(snapprops,
1084 1118 thissnap, &snapprops));
1085 1119 exclude = !nvlist_exists(snapprops, "is_clone_origin");
1086 1120 } else {
1087 1121 exclude = B_TRUE;
1088 1122 }
1089 1123 }
1090 1124
1091 1125 /*
1092 1126 * If a filter function exists, call it to determine whether
1093 1127 * this snapshot will be sent.
1094 1128 */
1095 1129 if (exclude || (sdd->filter_cb != NULL &&
1096 1130 sdd->filter_cb(zhp, sdd->filter_cb_arg) == B_FALSE)) {
1097 1131 /*
1098 1132 * This snapshot is filtered out. Don't send it, and don't
1099 1133 * set prevsnap_obj, so it will be as if this snapshot didn't
1100 1134 * exist, and the next accepted snapshot will be sent as
1101 1135 * an incremental from the last accepted one, or as the
1102 1136 * first (and full) snapshot in the case of a replication,
1103 1137 * non-incremental send.
1104 1138 */
1105 1139 zfs_close(zhp);
1106 1140 return (0);
1107 1141 }
1108 1142
1109 1143 err = hold_for_send(zhp, sdd);
|
↓ open down ↓ |
162 lines elided |
↑ open up ↑ |
1110 1144 if (err) {
1111 1145 if (err == ENOENT)
1112 1146 err = 0;
1113 1147 zfs_close(zhp);
1114 1148 return (err);
1115 1149 }
1116 1150
1117 1151 fromorigin = sdd->prevsnap[0] == '\0' &&
1118 1152 (sdd->fromorigin || sdd->replicate);
1119 1153
1154 + /* print out to-from and approximate size in verbose mode */
1120 1155 if (sdd->verbose) {
1121 - uint64_t size;
1122 - err = estimate_ioctl(zhp, sdd->prevsnap_obj,
1123 - fromorigin, &size);
1124 -
1156 + /* print preamble */
1125 1157 if (sdd->parsable) {
1126 1158 if (sdd->prevsnap[0] != '\0') {
1127 1159 (void) fprintf(stderr, "incremental\t%s\t%s",
1128 1160 sdd->prevsnap, zhp->zfs_name);
1129 1161 } else {
1130 1162 (void) fprintf(stderr, "full\t%s",
1131 1163 zhp->zfs_name);
1132 1164 }
1133 1165 } else {
1134 1166 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1135 1167 "send from @%s to %s"),
1136 1168 sdd->prevsnap, zhp->zfs_name);
1137 1169 }
1138 - if (err == 0) {
1139 - if (sdd->parsable) {
1140 - (void) fprintf(stderr, "\t%llu\n",
1141 - (longlong_t)size);
1170 +
1171 + if (sdd->sendsize) {
1172 + /*
1173 + * we are going to print out the exact stream size info,
1174 + * so skip the estimate
1175 + */
1176 + (void) fprintf(stderr, "\n");
1177 + } else {
1178 + /*
1179 + * provide stream size estimate otherwise
1180 + */
1181 + uint64_t size;
1182 + err = estimate_ioctl(zhp, sdd->prevsnap_obj,
1183 + fromorigin, &size);
1184 +
1185 + if (err == 0) {
1186 + if (sdd->parsable) {
1187 + (void) fprintf(stderr, "\t%llu\n",
1188 + (longlong_t)size);
1189 + } else {
1190 + char buf[16];
1191 + zfs_nicenum(size, buf, sizeof (buf));
1192 + (void) fprintf(stderr,
1193 + dgettext(TEXT_DOMAIN,
1194 + " estimated size is %s\n"),
1195 + buf);
1196 + }
1197 + sdd->size += size;
1142 1198 } else {
1143 - char buf[16];
1144 - zfs_nicenum(size, buf, sizeof (buf));
1145 - (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1146 - " estimated size is %s\n"), buf);
1199 + /* could not estimate */
1200 + (void) fprintf(stderr, "\n");
1147 1201 }
1148 - sdd->size += size;
1149 - } else {
1150 - (void) fprintf(stderr, "\n");
1151 1202 }
1152 1203 }
1153 1204
1154 1205 if (!sdd->dryrun) {
1206 + uint64_t sendcounter = 0;
1207 + boolean_t track_progress = (sdd->progress && !sdd->sendsize);
1208 + boolean_t sendsize = B_FALSE;
1155 1209 /*
1156 1210 * If progress reporting is requested, spawn a new thread to
1157 1211 * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
1158 1212 */
1159 - if (sdd->progress) {
1213 + if (track_progress) {
1160 1214 pa.pa_zhp = zhp;
1161 1215 pa.pa_fd = sdd->outfd;
1162 1216 pa.pa_parsable = sdd->parsable;
1163 1217
1164 1218 if (err = pthread_create(&tid, NULL,
1165 1219 send_progress_thread, &pa)) {
1166 1220 zfs_close(zhp);
1167 1221 return (err);
1168 1222 }
1169 1223 }
1170 1224
1225 +
1226 + /*
1227 + * We need to reset the sendsize flag being sent to
1228 + * kernel if sdd->dedup is set. With dedup, the file
1229 + * descriptor sent to kernel is one end of the pipe,
1230 + * and we would want the data back in the pipe for
1231 + * cksummer() to calculate the exact size of the dedup-ed
1232 + * stream. So reset the sendsize flag such that
1233 + * kernel writes to the pipe.
1234 + */
1235 +
1236 + sendsize = sdd->dedup ? B_FALSE : sdd->sendsize;
1237 +
1171 1238 err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
1172 - fromorigin, sdd->outfd, sdd->debugnv);
1239 + fromorigin, sdd->outfd, sdd->debugnv,
1240 + sendsize, &sendcounter);
1173 1241
1174 - if (sdd->progress) {
1242 + sdd->send_sz += sendcounter;
1243 +
1244 + if (track_progress) {
1175 1245 (void) pthread_cancel(tid);
1176 1246 (void) pthread_join(tid, NULL);
1177 1247 }
1178 1248 }
1179 1249
1180 1250 (void) strcpy(sdd->prevsnap, thissnap);
1181 1251 sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
1182 1252 zfs_close(zhp);
1183 1253 return (err);
1184 1254 }
1185 1255
1186 1256 static int
1187 1257 dump_filesystem(zfs_handle_t *zhp, void *arg)
1188 1258 {
1189 1259 int rv = 0;
1190 1260 send_dump_data_t *sdd = arg;
1191 1261 boolean_t missingfrom = B_FALSE;
1192 1262 zfs_cmd_t zc = { 0 };
1193 1263
1194 1264 (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
1195 1265 zhp->zfs_name, sdd->tosnap);
1196 1266 if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
1197 1267 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1198 1268 "WARNING: could not send %s@%s: does not exist\n"),
1199 1269 zhp->zfs_name, sdd->tosnap);
1200 1270 sdd->err = B_TRUE;
1201 1271 return (0);
1202 1272 }
1203 1273
1204 1274 if (sdd->replicate && sdd->fromsnap) {
1205 1275 /*
1206 1276 * If this fs does not have fromsnap, and we're doing
1207 1277 * recursive, we need to send a full stream from the
1208 1278 * beginning (or an incremental from the origin if this
1209 1279 * is a clone). If we're doing non-recursive, then let
1210 1280 * them get the error.
1211 1281 */
1212 1282 (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
1213 1283 zhp->zfs_name, sdd->fromsnap);
1214 1284 if (ioctl(zhp->zfs_hdl->libzfs_fd,
1215 1285 ZFS_IOC_OBJSET_STATS, &zc) != 0) {
1216 1286 missingfrom = B_TRUE;
1217 1287 }
1218 1288 }
1219 1289
1220 1290 sdd->seenfrom = sdd->seento = sdd->prevsnap[0] = 0;
1221 1291 sdd->prevsnap_obj = 0;
1222 1292 if (sdd->fromsnap == NULL || missingfrom)
1223 1293 sdd->seenfrom = B_TRUE;
1224 1294
1225 1295 rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg);
1226 1296 if (!sdd->seenfrom) {
1227 1297 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1228 1298 "WARNING: could not send %s@%s:\n"
1229 1299 "incremental source (%s@%s) does not exist\n"),
1230 1300 zhp->zfs_name, sdd->tosnap,
1231 1301 zhp->zfs_name, sdd->fromsnap);
1232 1302 sdd->err = B_TRUE;
1233 1303 } else if (!sdd->seento) {
1234 1304 if (sdd->fromsnap) {
1235 1305 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1236 1306 "WARNING: could not send %s@%s:\n"
1237 1307 "incremental source (%s@%s) "
1238 1308 "is not earlier than it\n"),
1239 1309 zhp->zfs_name, sdd->tosnap,
1240 1310 zhp->zfs_name, sdd->fromsnap);
1241 1311 } else {
1242 1312 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
1243 1313 "WARNING: "
1244 1314 "could not send %s@%s: does not exist\n"),
1245 1315 zhp->zfs_name, sdd->tosnap);
1246 1316 }
1247 1317 sdd->err = B_TRUE;
1248 1318 }
1249 1319
1250 1320 return (rv);
1251 1321 }
1252 1322
1253 1323 static int
1254 1324 dump_filesystems(zfs_handle_t *rzhp, void *arg)
1255 1325 {
1256 1326 send_dump_data_t *sdd = arg;
1257 1327 nvpair_t *fspair;
1258 1328 boolean_t needagain, progress;
1259 1329
1260 1330 if (!sdd->replicate)
1261 1331 return (dump_filesystem(rzhp, sdd));
1262 1332
1263 1333 /* Mark the clone origin snapshots. */
1264 1334 for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
1265 1335 fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
1266 1336 nvlist_t *nvfs;
1267 1337 uint64_t origin_guid = 0;
1268 1338
1269 1339 VERIFY(0 == nvpair_value_nvlist(fspair, &nvfs));
1270 1340 (void) nvlist_lookup_uint64(nvfs, "origin", &origin_guid);
1271 1341 if (origin_guid != 0) {
1272 1342 char *snapname;
1273 1343 nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
1274 1344 origin_guid, &snapname);
1275 1345 if (origin_nv != NULL) {
1276 1346 nvlist_t *snapprops;
1277 1347 VERIFY(0 == nvlist_lookup_nvlist(origin_nv,
1278 1348 "snapprops", &snapprops));
1279 1349 VERIFY(0 == nvlist_lookup_nvlist(snapprops,
1280 1350 snapname, &snapprops));
1281 1351 VERIFY(0 == nvlist_add_boolean(
1282 1352 snapprops, "is_clone_origin"));
1283 1353 }
1284 1354 }
1285 1355 }
1286 1356 again:
1287 1357 needagain = progress = B_FALSE;
1288 1358 for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
1289 1359 fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
1290 1360 nvlist_t *fslist, *parent_nv;
1291 1361 char *fsname;
1292 1362 zfs_handle_t *zhp;
1293 1363 int err;
1294 1364 uint64_t origin_guid = 0;
1295 1365 uint64_t parent_guid = 0;
1296 1366
1297 1367 VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
1298 1368 if (nvlist_lookup_boolean(fslist, "sent") == 0)
1299 1369 continue;
1300 1370
1301 1371 VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0);
1302 1372 (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid);
1303 1373 (void) nvlist_lookup_uint64(fslist, "parentfromsnap",
1304 1374 &parent_guid);
1305 1375
1306 1376 if (parent_guid != 0) {
1307 1377 parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);
1308 1378 if (!nvlist_exists(parent_nv, "sent")) {
1309 1379 /* parent has not been sent; skip this one */
1310 1380 needagain = B_TRUE;
1311 1381 continue;
1312 1382 }
1313 1383 }
1314 1384
1315 1385 if (origin_guid != 0) {
1316 1386 nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
1317 1387 origin_guid, NULL);
1318 1388 if (origin_nv != NULL &&
1319 1389 !nvlist_exists(origin_nv, "sent")) {
1320 1390 /*
1321 1391 * origin has not been sent yet;
1322 1392 * skip this clone.
1323 1393 */
1324 1394 needagain = B_TRUE;
1325 1395 continue;
1326 1396 }
1327 1397 }
1328 1398
1329 1399 zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET);
1330 1400 if (zhp == NULL)
1331 1401 return (-1);
1332 1402 err = dump_filesystem(zhp, sdd);
1333 1403 VERIFY(nvlist_add_boolean(fslist, "sent") == 0);
1334 1404 progress = B_TRUE;
1335 1405 zfs_close(zhp);
1336 1406 if (err)
1337 1407 return (err);
1338 1408 }
1339 1409 if (needagain) {
1340 1410 assert(progress);
1341 1411 goto again;
1342 1412 }
1343 1413
1344 1414 /* clean out the sent flags in case we reuse this fss */
1345 1415 for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
1346 1416 fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
1347 1417 nvlist_t *fslist;
1348 1418
1349 1419 VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
1350 1420 (void) nvlist_remove_all(fslist, "sent");
1351 1421 }
1352 1422
1353 1423 return (0);
1354 1424 }
1355 1425
1356 1426 /*
1357 1427 * Generate a send stream for the dataset identified by the argument zhp.
1358 1428 *
1359 1429 * The content of the send stream is the snapshot identified by
1360 1430 * 'tosnap'. Incremental streams are requested in two ways:
1361 1431 * - from the snapshot identified by "fromsnap" (if non-null) or
1362 1432 * - from the origin of the dataset identified by zhp, which must
1363 1433 * be a clone. In this case, "fromsnap" is null and "fromorigin"
1364 1434 * is TRUE.
1365 1435 *
1366 1436 * The send stream is recursive (i.e. dumps a hierarchy of snapshots) and
1367 1437 * uses a special header (with a hdrtype field of DMU_COMPOUNDSTREAM)
1368 1438 * if "replicate" is set. If "doall" is set, dump all the intermediate
1369 1439 * snapshots. The DMU_COMPOUNDSTREAM header is used in the "doall"
1370 1440 * case too. If "props" is set, send properties.
1371 1441 */
1372 1442 int
1373 1443 zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
1374 1444 sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
1375 1445 void *cb_arg, nvlist_t **debugnvp)
1376 1446 {
1377 1447 char errbuf[1024];
1378 1448 send_dump_data_t sdd = { 0 };
1379 1449 int err = 0;
1380 1450 nvlist_t *fss = NULL;
1381 1451 avl_tree_t *fsavl = NULL;
1382 1452 static uint64_t holdseq;
1383 1453 int spa_version;
1384 1454 pthread_t tid;
1385 1455 int pipefd[2];
1386 1456 dedup_arg_t dda = { 0 };
1387 1457 int featureflags = 0;
1388 1458
1389 1459 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
1390 1460 "cannot send '%s'"), zhp->zfs_name);
1391 1461
1392 1462 if (fromsnap && fromsnap[0] == '\0') {
1393 1463 zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
1394 1464 "zero-length incremental source"));
1395 1465 return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
1396 1466 }
1397 1467
1398 1468 if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) {
1399 1469 uint64_t version;
1400 1470 version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
1401 1471 if (version >= ZPL_VERSION_SA) {
1402 1472 featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;
1403 1473 }
1404 1474 }
1405 1475
1406 1476 if (flags->dedup && !flags->dryrun) {
|
↓ open down ↓ |
222 lines elided |
↑ open up ↑ |
1407 1477 featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
1408 1478 DMU_BACKUP_FEATURE_DEDUPPROPS);
1409 1479 if (err = pipe(pipefd)) {
1410 1480 zfs_error_aux(zhp->zfs_hdl, strerror(errno));
1411 1481 return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED,
1412 1482 errbuf));
1413 1483 }
1414 1484 dda.outputfd = outfd;
1415 1485 dda.inputfd = pipefd[1];
1416 1486 dda.dedup_hdl = zhp->zfs_hdl;
1487 + dda.sendsize = flags->sendsize;
1417 1488 if (err = pthread_create(&tid, NULL, cksummer, &dda)) {
1418 1489 (void) close(pipefd[0]);
1419 1490 (void) close(pipefd[1]);
1420 1491 zfs_error_aux(zhp->zfs_hdl, strerror(errno));
1421 1492 return (zfs_error(zhp->zfs_hdl,
1422 1493 EZFS_THREADCREATEFAILED, errbuf));
1423 1494 }
1424 1495 }
1425 1496
1426 1497 if (flags->replicate || flags->doall || flags->props) {
1427 1498 dmu_replay_record_t drr = { 0 };
1428 1499 char *packbuf = NULL;
1429 1500 size_t buflen = 0;
1430 1501 zio_cksum_t zc = { 0 };
1431 1502
1432 1503 if (flags->replicate || flags->props) {
1433 1504 nvlist_t *hdrnv;
1434 1505
1435 1506 VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0));
1436 1507 if (fromsnap) {
1437 1508 VERIFY(0 == nvlist_add_string(hdrnv,
1438 1509 "fromsnap", fromsnap));
1439 1510 }
1440 1511 VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap));
1441 1512 if (!flags->replicate) {
1442 1513 VERIFY(0 == nvlist_add_boolean(hdrnv,
1443 1514 "not_recursive"));
1444 1515 }
1445 1516
1446 1517 err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
1447 1518 fromsnap, tosnap, flags->replicate, &fss, &fsavl);
1448 1519 if (err)
1449 1520 goto err_out;
1450 1521 VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
1451 1522 err = nvlist_pack(hdrnv, &packbuf, &buflen,
1452 1523 NV_ENCODE_XDR, 0);
1453 1524 if (debugnvp)
1454 1525 *debugnvp = hdrnv;
1455 1526 else
1456 1527 nvlist_free(hdrnv);
1457 1528 if (err) {
1458 1529 fsavl_destroy(fsavl);
1459 1530 nvlist_free(fss);
1460 1531 goto stderr_out;
1461 1532 }
1462 1533 }
1463 1534
1464 1535 if (!flags->dryrun) {
1465 1536 /* write first begin record */
1466 1537 drr.drr_type = DRR_BEGIN;
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
1467 1538 drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
1468 1539 DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
1469 1540 drr_versioninfo, DMU_COMPOUNDSTREAM);
1470 1541 DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
1471 1542 drr_versioninfo, featureflags);
1472 1543 (void) snprintf(drr.drr_u.drr_begin.drr_toname,
1473 1544 sizeof (drr.drr_u.drr_begin.drr_toname),
1474 1545 "%s@%s", zhp->zfs_name, tosnap);
1475 1546 drr.drr_payloadlen = buflen;
1476 1547 err = cksum_and_write(&drr, sizeof (drr), &zc, outfd);
1548 + sdd.hdr_send_sz += sizeof (drr);
1477 1549
1478 1550 /* write header nvlist */
1479 1551 if (err != -1 && packbuf != NULL) {
1480 1552 err = cksum_and_write(packbuf, buflen, &zc,
1481 1553 outfd);
1554 + sdd.hdr_send_sz += buflen;
1482 1555 }
1483 1556 free(packbuf);
1484 1557 if (err == -1) {
1485 1558 fsavl_destroy(fsavl);
1486 1559 nvlist_free(fss);
1487 1560 err = errno;
1488 1561 goto stderr_out;
1489 1562 }
1490 1563
1491 1564 /* write end record */
1492 1565 bzero(&drr, sizeof (drr));
1493 1566 drr.drr_type = DRR_END;
1494 1567 drr.drr_u.drr_end.drr_checksum = zc;
1495 1568 err = write(outfd, &drr, sizeof (drr));
1569 + sdd.hdr_send_sz += sizeof (drr);
1496 1570 if (err == -1) {
1497 1571 fsavl_destroy(fsavl);
1498 1572 nvlist_free(fss);
1499 1573 err = errno;
1500 1574 goto stderr_out;
1501 1575 }
1502 1576
1503 1577 err = 0;
1504 1578 }
1505 1579 }
1506 1580
1507 1581 /* dump each stream */
1508 1582 sdd.fromsnap = fromsnap;
1509 1583 sdd.tosnap = tosnap;
|
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
1510 1584 if (flags->dedup)
1511 1585 sdd.outfd = pipefd[0];
1512 1586 else
1513 1587 sdd.outfd = outfd;
1514 1588 sdd.replicate = flags->replicate;
1515 1589 sdd.doall = flags->doall;
1516 1590 sdd.fromorigin = flags->fromorigin;
1517 1591 sdd.fss = fss;
1518 1592 sdd.fsavl = fsavl;
1519 1593 sdd.verbose = flags->verbose;
1594 + sdd.dedup = flags->dedup;
1595 + sdd.sendsize = flags->sendsize;
1520 1596 sdd.parsable = flags->parsable;
1521 1597 sdd.progress = flags->progress;
1522 1598 sdd.dryrun = flags->dryrun;
1523 1599 sdd.filter_cb = filter_func;
1524 1600 sdd.filter_cb_arg = cb_arg;
1525 1601 if (debugnvp)
1526 1602 sdd.debugnv = *debugnvp;
1527 1603
1528 1604 /*
1529 1605 * Some flags require that we place user holds on the datasets that are
1530 1606 * being sent so they don't get destroyed during the send. We can skip
1531 1607 * this step if the pool is imported read-only since the datasets cannot
1532 1608 * be destroyed.
1533 1609 */
1534 1610 if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),
1535 1611 ZPOOL_PROP_READONLY, NULL) &&
1536 1612 zfs_spa_version(zhp, &spa_version) == 0 &&
1537 1613 spa_version >= SPA_VERSION_USERREFS &&
1538 1614 (flags->doall || flags->replicate)) {
1539 1615 ++holdseq;
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
1540 1616 (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
1541 1617 ".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
1542 1618 sdd.cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
1543 1619 if (sdd.cleanup_fd < 0) {
1544 1620 err = errno;
1545 1621 goto stderr_out;
1546 1622 }
1547 1623 } else {
1548 1624 sdd.cleanup_fd = -1;
1549 1625 }
1550 - if (flags->verbose) {
1626 + if (flags->verbose && !flags->sendsize) {
1551 1627 /*
1552 1628 * Do a verbose no-op dry run to get all the verbose output
1553 1629 * before generating any data. Then do a non-verbose real
1554 1630 * run to generate the streams.
1555 1631 */
1556 1632 sdd.dryrun = B_TRUE;
1557 1633 err = dump_filesystems(zhp, &sdd);
1558 1634 sdd.dryrun = flags->dryrun;
1559 1635 sdd.verbose = B_FALSE;
1560 1636 if (flags->parsable) {
1561 1637 (void) fprintf(stderr, "size\t%llu\n",
1562 1638 (longlong_t)sdd.size);
1563 1639 } else {
1564 1640 char buf[16];
1565 1641 zfs_nicenum(sdd.size, buf, sizeof (buf));
1566 1642 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
|
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
1567 1643 "total estimated size is %s\n"), buf);
1568 1644 }
1569 1645 }
1570 1646 err = dump_filesystems(zhp, &sdd);
1571 1647 fsavl_destroy(fsavl);
1572 1648 nvlist_free(fss);
1573 1649
1574 1650 if (flags->dedup) {
1575 1651 (void) close(pipefd[0]);
1576 1652 (void) pthread_join(tid, NULL);
1653 + sdd.send_sz = dda.dedup_data_sz;
1577 1654 }
1578 1655
1579 1656 if (sdd.cleanup_fd != -1) {
1580 1657 VERIFY(0 == close(sdd.cleanup_fd));
1581 1658 sdd.cleanup_fd = -1;
1582 1659 }
1583 1660
1584 1661 if (!flags->dryrun && (flags->replicate || flags->doall ||
1585 1662 flags->props)) {
1586 1663 /*
1587 1664 * write final end record. NB: want to do this even if
1588 1665 * there was some error, because it might not be totally
1589 1666 * failed.
1590 1667 */
1591 1668 dmu_replay_record_t drr = { 0 };
1592 1669 drr.drr_type = DRR_END;
1593 1670 if (write(outfd, &drr, sizeof (drr)) == -1) {
1594 1671 return (zfs_standard_error(zhp->zfs_hdl,
1595 1672 errno, errbuf));
1596 1673 }
1674 + sdd.hdr_send_sz += sizeof (drr);
1597 1675 }
1676 +
1677 + if (flags->sendsize) {
1678 + if (flags->verbose) {
1679 + fprintf(stderr, "Send stream header size (bytes): "
1680 + "%u\n", sdd.hdr_send_sz);
1681 + fprintf(stderr, "Send stream data size (bytes): "
1682 + "%llu\n", sdd.send_sz);
1683 + fprintf(stderr, "Total send stream size (bytes): "
1684 + "%llu\n", sdd.send_sz + (uint64_t)sdd.hdr_send_sz);
1685 + } else {
1686 + fprintf(stderr, "Total send stream size (bytes): "
1687 + "%llu\n", sdd.send_sz + (uint64_t)sdd.hdr_send_sz);
1688 + }
1689 + }
1598 1690
1599 1691 return (err || sdd.err);
1600 1692
1601 1693 stderr_out:
1602 1694 err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);
1603 1695 err_out:
1604 1696 if (sdd.cleanup_fd != -1)
1605 1697 VERIFY(0 == close(sdd.cleanup_fd));
1606 1698 if (flags->dedup) {
1607 1699 (void) pthread_cancel(tid);
1608 1700 (void) pthread_join(tid, NULL);
1609 1701 (void) close(pipefd[0]);
1610 1702 }
1611 1703 return (err);
1612 1704 }
1613 1705
1614 1706 /*
1615 1707 * Routines specific to "zfs recv"
1616 1708 */
1617 1709
1618 1710 static int
1619 1711 recv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen,
1620 1712 boolean_t byteswap, zio_cksum_t *zc)
1621 1713 {
1622 1714 char *cp = buf;
1623 1715 int rv;
1624 1716 int len = ilen;
1625 1717
1626 1718 do {
1627 1719 rv = read(fd, cp, len);
1628 1720 cp += rv;
1629 1721 len -= rv;
1630 1722 } while (rv > 0);
1631 1723
1632 1724 if (rv < 0 || len != 0) {
1633 1725 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
1634 1726 "failed to read from stream"));
1635 1727 return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN,
1636 1728 "cannot receive")));
1637 1729 }
1638 1730
1639 1731 if (zc) {
1640 1732 if (byteswap)
1641 1733 fletcher_4_incremental_byteswap(buf, ilen, zc);
1642 1734 else
1643 1735 fletcher_4_incremental_native(buf, ilen, zc);
1644 1736 }
1645 1737 return (0);
1646 1738 }
1647 1739
1648 1740 static int
1649 1741 recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp,
1650 1742 boolean_t byteswap, zio_cksum_t *zc)
1651 1743 {
1652 1744 char *buf;
1653 1745 int err;
1654 1746
1655 1747 buf = zfs_alloc(hdl, len);
1656 1748 if (buf == NULL)
1657 1749 return (ENOMEM);
1658 1750
1659 1751 err = recv_read(hdl, fd, buf, len, byteswap, zc);
1660 1752 if (err != 0) {
1661 1753 free(buf);
1662 1754 return (err);
1663 1755 }
1664 1756
1665 1757 err = nvlist_unpack(buf, len, nvp, 0);
1666 1758 free(buf);
1667 1759 if (err != 0) {
1668 1760 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
1669 1761 "stream (malformed nvlist)"));
1670 1762 return (EINVAL);
1671 1763 }
1672 1764 return (0);
1673 1765 }
1674 1766
1675 1767 static int
1676 1768 recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
1677 1769 int baselen, char *newname, recvflags_t *flags)
1678 1770 {
1679 1771 static int seq;
1680 1772 zfs_cmd_t zc = { 0 };
1681 1773 int err;
1682 1774 prop_changelist_t *clp;
1683 1775 zfs_handle_t *zhp;
1684 1776
1685 1777 zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
1686 1778 if (zhp == NULL)
1687 1779 return (-1);
1688 1780 clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
1689 1781 flags->force ? MS_FORCE : 0);
1690 1782 zfs_close(zhp);
1691 1783 if (clp == NULL)
1692 1784 return (-1);
1693 1785 err = changelist_prefix(clp);
1694 1786 if (err)
1695 1787 return (err);
1696 1788
1697 1789 zc.zc_objset_type = DMU_OST_ZFS;
1698 1790 (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
1699 1791
1700 1792 if (tryname) {
1701 1793 (void) strcpy(newname, tryname);
1702 1794
1703 1795 (void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value));
1704 1796
1705 1797 if (flags->verbose) {
1706 1798 (void) printf("attempting rename %s to %s\n",
1707 1799 zc.zc_name, zc.zc_value);
1708 1800 }
1709 1801 err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc);
1710 1802 if (err == 0)
1711 1803 changelist_rename(clp, name, tryname);
1712 1804 } else {
1713 1805 err = ENOENT;
1714 1806 }
1715 1807
1716 1808 if (err != 0 && strncmp(name+baselen, "recv-", 5) != 0) {
1717 1809 seq++;
1718 1810
1719 1811 (void) strncpy(newname, name, baselen);
1720 1812 (void) snprintf(newname+baselen, ZFS_MAXNAMELEN-baselen,
1721 1813 "recv-%u-%u", getpid(), seq);
1722 1814 (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
1723 1815
1724 1816 if (flags->verbose) {
1725 1817 (void) printf("failed - trying rename %s to %s\n",
1726 1818 zc.zc_name, zc.zc_value);
1727 1819 }
1728 1820 err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc);
1729 1821 if (err == 0)
1730 1822 changelist_rename(clp, name, newname);
1731 1823 if (err && flags->verbose) {
1732 1824 (void) printf("failed (%u) - "
1733 1825 "will try again on next pass\n", errno);
1734 1826 }
1735 1827 err = EAGAIN;
1736 1828 } else if (flags->verbose) {
1737 1829 if (err == 0)
1738 1830 (void) printf("success\n");
1739 1831 else
1740 1832 (void) printf("failed (%u)\n", errno);
1741 1833 }
1742 1834
1743 1835 (void) changelist_postfix(clp);
1744 1836 changelist_free(clp);
1745 1837
1746 1838 return (err);
1747 1839 }
1748 1840
1749 1841 static int
1750 1842 recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
1751 1843 char *newname, recvflags_t *flags)
1752 1844 {
1753 1845 zfs_cmd_t zc = { 0 };
1754 1846 int err = 0;
1755 1847 prop_changelist_t *clp;
1756 1848 zfs_handle_t *zhp;
1757 1849 boolean_t defer = B_FALSE;
1758 1850 int spa_version;
1759 1851
1760 1852 zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
1761 1853 if (zhp == NULL)
1762 1854 return (-1);
1763 1855 clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
1764 1856 flags->force ? MS_FORCE : 0);
1765 1857 if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
1766 1858 zfs_spa_version(zhp, &spa_version) == 0 &&
1767 1859 spa_version >= SPA_VERSION_USERREFS)
1768 1860 defer = B_TRUE;
1769 1861 zfs_close(zhp);
1770 1862 if (clp == NULL)
1771 1863 return (-1);
1772 1864 err = changelist_prefix(clp);
1773 1865 if (err)
1774 1866 return (err);
1775 1867
1776 1868 zc.zc_objset_type = DMU_OST_ZFS;
1777 1869 zc.zc_defer_destroy = defer;
1778 1870 (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
1779 1871
1780 1872 if (flags->verbose)
1781 1873 (void) printf("attempting destroy %s\n", zc.zc_name);
1782 1874 err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc);
1783 1875 if (err == 0) {
1784 1876 if (flags->verbose)
1785 1877 (void) printf("success\n");
1786 1878 changelist_remove(clp, zc.zc_name);
1787 1879 }
1788 1880
1789 1881 (void) changelist_postfix(clp);
1790 1882 changelist_free(clp);
1791 1883
1792 1884 /*
1793 1885 * Deferred destroy might destroy the snapshot or only mark it to be
1794 1886 * destroyed later, and it returns success in either case.
1795 1887 */
1796 1888 if (err != 0 || (defer && zfs_dataset_exists(hdl, name,
1797 1889 ZFS_TYPE_SNAPSHOT))) {
1798 1890 err = recv_rename(hdl, name, NULL, baselen, newname, flags);
1799 1891 }
1800 1892
1801 1893 return (err);
1802 1894 }
1803 1895
1804 1896 typedef struct guid_to_name_data {
1805 1897 uint64_t guid;
1806 1898 char *name;
1807 1899 char *skip;
1808 1900 } guid_to_name_data_t;
1809 1901
1810 1902 static int
1811 1903 guid_to_name_cb(zfs_handle_t *zhp, void *arg)
1812 1904 {
1813 1905 guid_to_name_data_t *gtnd = arg;
1814 1906 int err;
1815 1907
1816 1908 if (gtnd->skip != NULL &&
1817 1909 strcmp(zhp->zfs_name, gtnd->skip) == 0) {
1818 1910 return (0);
1819 1911 }
1820 1912
1821 1913 if (zhp->zfs_dmustats.dds_guid == gtnd->guid) {
1822 1914 (void) strcpy(gtnd->name, zhp->zfs_name);
1823 1915 zfs_close(zhp);
1824 1916 return (EEXIST);
1825 1917 }
1826 1918
1827 1919 err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
1828 1920 zfs_close(zhp);
1829 1921 return (err);
1830 1922 }
1831 1923
1832 1924 /*
1833 1925 * Attempt to find the local dataset associated with this guid. In the case of
1834 1926 * multiple matches, we attempt to find the "best" match by searching
1835 1927 * progressively larger portions of the hierarchy. This allows one to send a
1836 1928 * tree of datasets individually and guarantee that we will find the source
1837 1929 * guid within that hierarchy, even if there are multiple matches elsewhere.
1838 1930 */
1839 1931 static int
1840 1932 guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
1841 1933 char *name)
1842 1934 {
1843 1935 /* exhaustive search all local snapshots */
1844 1936 char pname[ZFS_MAXNAMELEN];
1845 1937 guid_to_name_data_t gtnd;
1846 1938 int err = 0;
1847 1939 zfs_handle_t *zhp;
1848 1940 char *cp;
1849 1941
1850 1942 gtnd.guid = guid;
1851 1943 gtnd.name = name;
1852 1944 gtnd.skip = NULL;
1853 1945
1854 1946 (void) strlcpy(pname, parent, sizeof (pname));
1855 1947
1856 1948 /*
1857 1949 * Search progressively larger portions of the hierarchy. This will
1858 1950 * select the "most local" version of the origin snapshot in the case
1859 1951 * that there are multiple matching snapshots in the system.
1860 1952 */
1861 1953 while ((cp = strrchr(pname, '/')) != NULL) {
1862 1954
1863 1955 /* Chop off the last component and open the parent */
1864 1956 *cp = '\0';
1865 1957 zhp = make_dataset_handle(hdl, pname);
1866 1958
1867 1959 if (zhp == NULL)
1868 1960 continue;
1869 1961
1870 1962 err = zfs_iter_children(zhp, guid_to_name_cb, >nd);
1871 1963 zfs_close(zhp);
1872 1964 if (err == EEXIST)
1873 1965 return (0);
1874 1966
1875 1967 /*
1876 1968 * Remember the dataset that we already searched, so we
1877 1969 * skip it next time through.
1878 1970 */
1879 1971 gtnd.skip = pname;
1880 1972 }
1881 1973
1882 1974 return (ENOENT);
1883 1975 }
1884 1976
1885 1977 /*
1886 1978 * Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if
1887 1979 * guid1 is after guid2.
1888 1980 */
1889 1981 static int
1890 1982 created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
1891 1983 uint64_t guid1, uint64_t guid2)
1892 1984 {
1893 1985 nvlist_t *nvfs;
1894 1986 char *fsname, *snapname;
1895 1987 char buf[ZFS_MAXNAMELEN];
1896 1988 int rv;
1897 1989 zfs_handle_t *guid1hdl, *guid2hdl;
1898 1990 uint64_t create1, create2;
1899 1991
1900 1992 if (guid2 == 0)
1901 1993 return (0);
1902 1994 if (guid1 == 0)
1903 1995 return (1);
1904 1996
1905 1997 nvfs = fsavl_find(avl, guid1, &snapname);
1906 1998 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
1907 1999 (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
1908 2000 guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
1909 2001 if (guid1hdl == NULL)
1910 2002 return (-1);
1911 2003
1912 2004 nvfs = fsavl_find(avl, guid2, &snapname);
1913 2005 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
1914 2006 (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
1915 2007 guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
1916 2008 if (guid2hdl == NULL) {
1917 2009 zfs_close(guid1hdl);
1918 2010 return (-1);
1919 2011 }
1920 2012
1921 2013 create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG);
1922 2014 create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG);
1923 2015
1924 2016 if (create1 < create2)
1925 2017 rv = -1;
1926 2018 else if (create1 > create2)
1927 2019 rv = +1;
1928 2020 else
1929 2021 rv = 0;
1930 2022
1931 2023 zfs_close(guid1hdl);
1932 2024 zfs_close(guid2hdl);
1933 2025
1934 2026 return (rv);
1935 2027 }
1936 2028
1937 2029 static int
1938 2030 recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
1939 2031 recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
1940 2032 nvlist_t *renamed)
1941 2033 {
1942 2034 nvlist_t *local_nv;
1943 2035 avl_tree_t *local_avl;
1944 2036 nvpair_t *fselem, *nextfselem;
1945 2037 char *fromsnap;
1946 2038 char newname[ZFS_MAXNAMELEN];
1947 2039 int error;
1948 2040 boolean_t needagain, progress, recursive;
1949 2041 char *s1, *s2;
1950 2042
1951 2043 VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap));
1952 2044
1953 2045 recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
1954 2046 ENOENT);
1955 2047
1956 2048 if (flags->dryrun)
1957 2049 return (0);
1958 2050
1959 2051 again:
1960 2052 needagain = progress = B_FALSE;
1961 2053
1962 2054 if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
1963 2055 recursive, &local_nv, &local_avl)) != 0)
1964 2056 return (error);
1965 2057
1966 2058 /*
1967 2059 * Process deletes and renames
1968 2060 */
1969 2061 for (fselem = nvlist_next_nvpair(local_nv, NULL);
1970 2062 fselem; fselem = nextfselem) {
1971 2063 nvlist_t *nvfs, *snaps;
1972 2064 nvlist_t *stream_nvfs = NULL;
1973 2065 nvpair_t *snapelem, *nextsnapelem;
1974 2066 uint64_t fromguid = 0;
1975 2067 uint64_t originguid = 0;
1976 2068 uint64_t stream_originguid = 0;
1977 2069 uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid;
1978 2070 char *fsname, *stream_fsname;
1979 2071
1980 2072 nextfselem = nvlist_next_nvpair(local_nv, fselem);
1981 2073
1982 2074 VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs));
1983 2075 VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps));
1984 2076 VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
1985 2077 VERIFY(0 == nvlist_lookup_uint64(nvfs, "parentfromsnap",
1986 2078 &parent_fromsnap_guid));
1987 2079 (void) nvlist_lookup_uint64(nvfs, "origin", &originguid);
1988 2080
1989 2081 /*
1990 2082 * First find the stream's fs, so we can check for
1991 2083 * a different origin (due to "zfs promote")
1992 2084 */
1993 2085 for (snapelem = nvlist_next_nvpair(snaps, NULL);
1994 2086 snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {
1995 2087 uint64_t thisguid;
1996 2088
1997 2089 VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid));
1998 2090 stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);
1999 2091
2000 2092 if (stream_nvfs != NULL)
2001 2093 break;
2002 2094 }
2003 2095
2004 2096 /* check for promote */
2005 2097 (void) nvlist_lookup_uint64(stream_nvfs, "origin",
2006 2098 &stream_originguid);
2007 2099 if (stream_nvfs && originguid != stream_originguid) {
2008 2100 switch (created_before(hdl, local_avl,
2009 2101 stream_originguid, originguid)) {
2010 2102 case 1: {
2011 2103 /* promote it! */
2012 2104 zfs_cmd_t zc = { 0 };
2013 2105 nvlist_t *origin_nvfs;
2014 2106 char *origin_fsname;
2015 2107
2016 2108 if (flags->verbose)
2017 2109 (void) printf("promoting %s\n", fsname);
2018 2110
2019 2111 origin_nvfs = fsavl_find(local_avl, originguid,
2020 2112 NULL);
2021 2113 VERIFY(0 == nvlist_lookup_string(origin_nvfs,
2022 2114 "name", &origin_fsname));
2023 2115 (void) strlcpy(zc.zc_value, origin_fsname,
2024 2116 sizeof (zc.zc_value));
2025 2117 (void) strlcpy(zc.zc_name, fsname,
2026 2118 sizeof (zc.zc_name));
2027 2119 error = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
2028 2120 if (error == 0)
2029 2121 progress = B_TRUE;
2030 2122 break;
2031 2123 }
2032 2124 default:
2033 2125 break;
2034 2126 case -1:
2035 2127 fsavl_destroy(local_avl);
2036 2128 nvlist_free(local_nv);
2037 2129 return (-1);
2038 2130 }
2039 2131 /*
2040 2132 * We had/have the wrong origin, therefore our
2041 2133 * list of snapshots is wrong. Need to handle
2042 2134 * them on the next pass.
2043 2135 */
2044 2136 needagain = B_TRUE;
2045 2137 continue;
2046 2138 }
2047 2139
2048 2140 for (snapelem = nvlist_next_nvpair(snaps, NULL);
2049 2141 snapelem; snapelem = nextsnapelem) {
2050 2142 uint64_t thisguid;
2051 2143 char *stream_snapname;
2052 2144 nvlist_t *found, *props;
2053 2145
2054 2146 nextsnapelem = nvlist_next_nvpair(snaps, snapelem);
2055 2147
2056 2148 VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid));
2057 2149 found = fsavl_find(stream_avl, thisguid,
2058 2150 &stream_snapname);
2059 2151
2060 2152 /* check for delete */
2061 2153 if (found == NULL) {
2062 2154 char name[ZFS_MAXNAMELEN];
2063 2155
2064 2156 if (!flags->force)
2065 2157 continue;
2066 2158
2067 2159 (void) snprintf(name, sizeof (name), "%s@%s",
2068 2160 fsname, nvpair_name(snapelem));
2069 2161
2070 2162 error = recv_destroy(hdl, name,
2071 2163 strlen(fsname)+1, newname, flags);
2072 2164 if (error)
2073 2165 needagain = B_TRUE;
2074 2166 else
2075 2167 progress = B_TRUE;
2076 2168 continue;
2077 2169 }
2078 2170
2079 2171 stream_nvfs = found;
2080 2172
2081 2173 if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",
2082 2174 &props) && 0 == nvlist_lookup_nvlist(props,
2083 2175 stream_snapname, &props)) {
2084 2176 zfs_cmd_t zc = { 0 };
2085 2177
2086 2178 zc.zc_cookie = B_TRUE; /* received */
2087 2179 (void) snprintf(zc.zc_name, sizeof (zc.zc_name),
2088 2180 "%s@%s", fsname, nvpair_name(snapelem));
2089 2181 if (zcmd_write_src_nvlist(hdl, &zc,
2090 2182 props) == 0) {
2091 2183 (void) zfs_ioctl(hdl,
2092 2184 ZFS_IOC_SET_PROP, &zc);
2093 2185 zcmd_free_nvlists(&zc);
2094 2186 }
2095 2187 }
2096 2188
2097 2189 /* check for different snapname */
2098 2190 if (strcmp(nvpair_name(snapelem),
2099 2191 stream_snapname) != 0) {
2100 2192 char name[ZFS_MAXNAMELEN];
2101 2193 char tryname[ZFS_MAXNAMELEN];
2102 2194
2103 2195 (void) snprintf(name, sizeof (name), "%s@%s",
2104 2196 fsname, nvpair_name(snapelem));
2105 2197 (void) snprintf(tryname, sizeof (name), "%s@%s",
2106 2198 fsname, stream_snapname);
2107 2199
2108 2200 error = recv_rename(hdl, name, tryname,
2109 2201 strlen(fsname)+1, newname, flags);
2110 2202 if (error)
2111 2203 needagain = B_TRUE;
2112 2204 else
2113 2205 progress = B_TRUE;
2114 2206 }
2115 2207
2116 2208 if (strcmp(stream_snapname, fromsnap) == 0)
2117 2209 fromguid = thisguid;
2118 2210 }
2119 2211
2120 2212 /* check for delete */
2121 2213 if (stream_nvfs == NULL) {
2122 2214 if (!flags->force)
2123 2215 continue;
2124 2216
2125 2217 error = recv_destroy(hdl, fsname, strlen(tofs)+1,
2126 2218 newname, flags);
2127 2219 if (error)
2128 2220 needagain = B_TRUE;
2129 2221 else
2130 2222 progress = B_TRUE;
2131 2223 continue;
2132 2224 }
2133 2225
2134 2226 if (fromguid == 0) {
2135 2227 if (flags->verbose) {
2136 2228 (void) printf("local fs %s does not have "
2137 2229 "fromsnap (%s in stream); must have "
2138 2230 "been deleted locally; ignoring\n",
2139 2231 fsname, fromsnap);
2140 2232 }
2141 2233 continue;
2142 2234 }
2143 2235
2144 2236 VERIFY(0 == nvlist_lookup_string(stream_nvfs,
2145 2237 "name", &stream_fsname));
2146 2238 VERIFY(0 == nvlist_lookup_uint64(stream_nvfs,
2147 2239 "parentfromsnap", &stream_parent_fromsnap_guid));
2148 2240
2149 2241 s1 = strrchr(fsname, '/');
2150 2242 s2 = strrchr(stream_fsname, '/');
2151 2243
2152 2244 /*
2153 2245 * Check for rename. If the exact receive path is specified, it
2154 2246 * does not count as a rename, but we still need to check the
2155 2247 * datasets beneath it.
2156 2248 */
2157 2249 if ((stream_parent_fromsnap_guid != 0 &&
2158 2250 parent_fromsnap_guid != 0 &&
2159 2251 stream_parent_fromsnap_guid != parent_fromsnap_guid) ||
2160 2252 ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
2161 2253 (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
2162 2254 nvlist_t *parent;
2163 2255 char tryname[ZFS_MAXNAMELEN];
2164 2256
2165 2257 parent = fsavl_find(local_avl,
2166 2258 stream_parent_fromsnap_guid, NULL);
2167 2259 /*
2168 2260 * NB: parent might not be found if we used the
2169 2261 * tosnap for stream_parent_fromsnap_guid,
2170 2262 * because the parent is a newly-created fs;
2171 2263 * we'll be able to rename it after we recv the
2172 2264 * new fs.
2173 2265 */
2174 2266 if (parent != NULL) {
2175 2267 char *pname;
2176 2268
2177 2269 VERIFY(0 == nvlist_lookup_string(parent, "name",
2178 2270 &pname));
2179 2271 (void) snprintf(tryname, sizeof (tryname),
2180 2272 "%s%s", pname, strrchr(stream_fsname, '/'));
2181 2273 } else {
2182 2274 tryname[0] = '\0';
2183 2275 if (flags->verbose) {
2184 2276 (void) printf("local fs %s new parent "
2185 2277 "not found\n", fsname);
2186 2278 }
2187 2279 }
2188 2280
2189 2281 newname[0] = '\0';
2190 2282
2191 2283 error = recv_rename(hdl, fsname, tryname,
2192 2284 strlen(tofs)+1, newname, flags);
2193 2285
2194 2286 if (renamed != NULL && newname[0] != '\0') {
2195 2287 VERIFY(0 == nvlist_add_boolean(renamed,
2196 2288 newname));
2197 2289 }
2198 2290
2199 2291 if (error)
2200 2292 needagain = B_TRUE;
2201 2293 else
2202 2294 progress = B_TRUE;
2203 2295 }
2204 2296 }
2205 2297
2206 2298 fsavl_destroy(local_avl);
2207 2299 nvlist_free(local_nv);
2208 2300
2209 2301 if (needagain && progress) {
2210 2302 /* do another pass to fix up temporary names */
2211 2303 if (flags->verbose)
2212 2304 (void) printf("another pass:\n");
2213 2305 goto again;
2214 2306 }
2215 2307
2216 2308 return (needagain);
2217 2309 }
2218 2310
2219 2311 static int
2220 2312 zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
2221 2313 recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
2222 2314 char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
2223 2315 {
2224 2316 nvlist_t *stream_nv = NULL;
2225 2317 avl_tree_t *stream_avl = NULL;
2226 2318 char *fromsnap = NULL;
2227 2319 char *cp;
2228 2320 char tofs[ZFS_MAXNAMELEN];
2229 2321 char sendfs[ZFS_MAXNAMELEN];
2230 2322 char errbuf[1024];
2231 2323 dmu_replay_record_t drre;
2232 2324 int error;
2233 2325 boolean_t anyerr = B_FALSE;
2234 2326 boolean_t softerr = B_FALSE;
2235 2327 boolean_t recursive;
2236 2328
2237 2329 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2238 2330 "cannot receive"));
2239 2331
2240 2332 assert(drr->drr_type == DRR_BEGIN);
2241 2333 assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
2242 2334 assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
2243 2335 DMU_COMPOUNDSTREAM);
2244 2336
2245 2337 /*
2246 2338 * Read in the nvlist from the stream.
2247 2339 */
2248 2340 if (drr->drr_payloadlen != 0) {
2249 2341 error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,
2250 2342 &stream_nv, flags->byteswap, zc);
2251 2343 if (error) {
2252 2344 error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2253 2345 goto out;
2254 2346 }
2255 2347 }
2256 2348
2257 2349 recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2258 2350 ENOENT);
2259 2351
2260 2352 if (recursive && strchr(destname, '@')) {
2261 2353 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2262 2354 "cannot specify snapshot name for multi-snapshot stream"));
2263 2355 error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2264 2356 goto out;
2265 2357 }
2266 2358
2267 2359 /*
2268 2360 * Read in the end record and verify checksum.
2269 2361 */
2270 2362 if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),
2271 2363 flags->byteswap, NULL)))
2272 2364 goto out;
2273 2365 if (flags->byteswap) {
2274 2366 drre.drr_type = BSWAP_32(drre.drr_type);
2275 2367 drre.drr_u.drr_end.drr_checksum.zc_word[0] =
2276 2368 BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);
2277 2369 drre.drr_u.drr_end.drr_checksum.zc_word[1] =
2278 2370 BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]);
2279 2371 drre.drr_u.drr_end.drr_checksum.zc_word[2] =
2280 2372 BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]);
2281 2373 drre.drr_u.drr_end.drr_checksum.zc_word[3] =
2282 2374 BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]);
2283 2375 }
2284 2376 if (drre.drr_type != DRR_END) {
2285 2377 error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2286 2378 goto out;
2287 2379 }
2288 2380 if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) {
2289 2381 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2290 2382 "incorrect header checksum"));
2291 2383 error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2292 2384 goto out;
2293 2385 }
2294 2386
2295 2387 (void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap);
2296 2388
2297 2389 if (drr->drr_payloadlen != 0) {
2298 2390 nvlist_t *stream_fss;
2299 2391
2300 2392 VERIFY(0 == nvlist_lookup_nvlist(stream_nv, "fss",
2301 2393 &stream_fss));
2302 2394 if ((stream_avl = fsavl_create(stream_fss)) == NULL) {
2303 2395 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2304 2396 "couldn't allocate avl tree"));
2305 2397 error = zfs_error(hdl, EZFS_NOMEM, errbuf);
2306 2398 goto out;
2307 2399 }
2308 2400
2309 2401 if (fromsnap != NULL) {
2310 2402 nvlist_t *renamed = NULL;
2311 2403 nvpair_t *pair = NULL;
2312 2404
2313 2405 (void) strlcpy(tofs, destname, ZFS_MAXNAMELEN);
2314 2406 if (flags->isprefix) {
2315 2407 struct drr_begin *drrb = &drr->drr_u.drr_begin;
2316 2408 int i;
2317 2409
2318 2410 if (flags->istail) {
2319 2411 cp = strrchr(drrb->drr_toname, '/');
2320 2412 if (cp == NULL) {
2321 2413 (void) strlcat(tofs, "/",
2322 2414 ZFS_MAXNAMELEN);
2323 2415 i = 0;
2324 2416 } else {
2325 2417 i = (cp - drrb->drr_toname);
2326 2418 }
2327 2419 } else {
2328 2420 i = strcspn(drrb->drr_toname, "/@");
2329 2421 }
2330 2422 /* zfs_receive_one() will create_parents() */
2331 2423 (void) strlcat(tofs, &drrb->drr_toname[i],
2332 2424 ZFS_MAXNAMELEN);
2333 2425 *strchr(tofs, '@') = '\0';
2334 2426 }
2335 2427
2336 2428 if (recursive && !flags->dryrun && !flags->nomount) {
2337 2429 VERIFY(0 == nvlist_alloc(&renamed,
2338 2430 NV_UNIQUE_NAME, 0));
2339 2431 }
2340 2432
2341 2433 softerr = recv_incremental_replication(hdl, tofs, flags,
2342 2434 stream_nv, stream_avl, renamed);
2343 2435
2344 2436 /* Unmount renamed filesystems before receiving. */
2345 2437 while ((pair = nvlist_next_nvpair(renamed,
2346 2438 pair)) != NULL) {
2347 2439 zfs_handle_t *zhp;
2348 2440 prop_changelist_t *clp = NULL;
2349 2441
2350 2442 zhp = zfs_open(hdl, nvpair_name(pair),
2351 2443 ZFS_TYPE_FILESYSTEM);
2352 2444 if (zhp != NULL) {
2353 2445 clp = changelist_gather(zhp,
2354 2446 ZFS_PROP_MOUNTPOINT, 0, 0);
2355 2447 zfs_close(zhp);
2356 2448 if (clp != NULL) {
2357 2449 softerr |=
2358 2450 changelist_prefix(clp);
2359 2451 changelist_free(clp);
2360 2452 }
2361 2453 }
2362 2454 }
2363 2455
2364 2456 nvlist_free(renamed);
2365 2457 }
2366 2458 }
2367 2459
2368 2460 /*
2369 2461 * Get the fs specified by the first path in the stream (the top level
2370 2462 * specified by 'zfs send') and pass it to each invocation of
2371 2463 * zfs_receive_one().
2372 2464 */
2373 2465 (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
2374 2466 ZFS_MAXNAMELEN);
2375 2467 if ((cp = strchr(sendfs, '@')) != NULL)
2376 2468 *cp = '\0';
2377 2469
2378 2470 /* Finally, receive each contained stream */
2379 2471 do {
2380 2472 /*
2381 2473 * we should figure out if it has a recoverable
2382 2474 * error, in which case do a recv_skip() and drive on.
2383 2475 * Note, if we fail due to already having this guid,
2384 2476 * zfs_receive_one() will take care of it (ie,
2385 2477 * recv_skip() and return 0).
2386 2478 */
2387 2479 error = zfs_receive_impl(hdl, destname, flags, fd,
2388 2480 sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
2389 2481 action_handlep);
2390 2482 if (error == ENODATA) {
2391 2483 error = 0;
2392 2484 break;
2393 2485 }
2394 2486 anyerr |= error;
2395 2487 } while (error == 0);
2396 2488
2397 2489 if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
2398 2490 /*
2399 2491 * Now that we have the fs's they sent us, try the
2400 2492 * renames again.
2401 2493 */
2402 2494 softerr = recv_incremental_replication(hdl, tofs, flags,
2403 2495 stream_nv, stream_avl, NULL);
2404 2496 }
2405 2497
2406 2498 out:
2407 2499 fsavl_destroy(stream_avl);
2408 2500 if (stream_nv)
2409 2501 nvlist_free(stream_nv);
2410 2502 if (softerr)
2411 2503 error = -2;
2412 2504 if (anyerr)
2413 2505 error = -1;
2414 2506 return (error);
2415 2507 }
2416 2508
2417 2509 static void
2418 2510 trunc_prop_errs(int truncated)
2419 2511 {
2420 2512 ASSERT(truncated != 0);
2421 2513
2422 2514 if (truncated == 1)
2423 2515 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2424 2516 "1 more property could not be set\n"));
2425 2517 else
2426 2518 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2427 2519 "%d more properties could not be set\n"), truncated);
2428 2520 }
2429 2521
2430 2522 static int
2431 2523 recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
2432 2524 {
2433 2525 dmu_replay_record_t *drr;
2434 2526 void *buf = malloc(1<<20);
2435 2527 char errbuf[1024];
2436 2528
2437 2529 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2438 2530 "cannot receive:"));
2439 2531
2440 2532 /* XXX would be great to use lseek if possible... */
2441 2533 drr = buf;
2442 2534
2443 2535 while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t),
2444 2536 byteswap, NULL) == 0) {
2445 2537 if (byteswap)
2446 2538 drr->drr_type = BSWAP_32(drr->drr_type);
2447 2539
2448 2540 switch (drr->drr_type) {
2449 2541 case DRR_BEGIN:
2450 2542 /* NB: not to be used on v2 stream packages */
2451 2543 if (drr->drr_payloadlen != 0) {
2452 2544 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2453 2545 "invalid substream header"));
2454 2546 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2455 2547 }
2456 2548 break;
2457 2549
2458 2550 case DRR_END:
2459 2551 free(buf);
2460 2552 return (0);
2461 2553
2462 2554 case DRR_OBJECT:
2463 2555 if (byteswap) {
2464 2556 drr->drr_u.drr_object.drr_bonuslen =
2465 2557 BSWAP_32(drr->drr_u.drr_object.
2466 2558 drr_bonuslen);
2467 2559 }
2468 2560 (void) recv_read(hdl, fd, buf,
2469 2561 P2ROUNDUP(drr->drr_u.drr_object.drr_bonuslen, 8),
2470 2562 B_FALSE, NULL);
2471 2563 break;
2472 2564
2473 2565 case DRR_WRITE:
2474 2566 if (byteswap) {
2475 2567 drr->drr_u.drr_write.drr_length =
2476 2568 BSWAP_64(drr->drr_u.drr_write.drr_length);
2477 2569 }
2478 2570 (void) recv_read(hdl, fd, buf,
2479 2571 drr->drr_u.drr_write.drr_length, B_FALSE, NULL);
2480 2572 break;
2481 2573 case DRR_SPILL:
2482 2574 if (byteswap) {
2483 2575 drr->drr_u.drr_write.drr_length =
2484 2576 BSWAP_64(drr->drr_u.drr_spill.drr_length);
2485 2577 }
2486 2578 (void) recv_read(hdl, fd, buf,
2487 2579 drr->drr_u.drr_spill.drr_length, B_FALSE, NULL);
2488 2580 break;
2489 2581 case DRR_WRITE_BYREF:
2490 2582 case DRR_FREEOBJECTS:
2491 2583 case DRR_FREE:
2492 2584 break;
2493 2585
2494 2586 default:
2495 2587 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2496 2588 "invalid record type"));
2497 2589 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2498 2590 }
2499 2591 }
2500 2592
2501 2593 free(buf);
2502 2594 return (-1);
2503 2595 }
2504 2596
2505 2597 /*
2506 2598 * Restores a backup of tosnap from the file descriptor specified by infd.
2507 2599 */
2508 2600 static int
2509 2601 zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
2510 2602 recvflags_t *flags, dmu_replay_record_t *drr,
2511 2603 dmu_replay_record_t *drr_noswap, const char *sendfs,
2512 2604 nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
2513 2605 uint64_t *action_handlep)
2514 2606 {
2515 2607 zfs_cmd_t zc = { 0 };
2516 2608 time_t begin_time;
2517 2609 int ioctl_err, ioctl_errno, err;
2518 2610 char *cp;
2519 2611 struct drr_begin *drrb = &drr->drr_u.drr_begin;
2520 2612 char errbuf[1024];
2521 2613 char prop_errbuf[1024];
2522 2614 const char *chopprefix;
2523 2615 boolean_t newfs = B_FALSE;
2524 2616 boolean_t stream_wantsnewfs;
2525 2617 uint64_t parent_snapguid = 0;
2526 2618 prop_changelist_t *clp = NULL;
2527 2619 nvlist_t *snapprops_nvlist = NULL;
2528 2620 zprop_errflags_t prop_errflags;
2529 2621 boolean_t recursive;
2530 2622
2531 2623 begin_time = time(NULL);
2532 2624
2533 2625 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2534 2626 "cannot receive"));
2535 2627
2536 2628 recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
2537 2629 ENOENT);
2538 2630
2539 2631 if (stream_avl != NULL) {
2540 2632 char *snapname;
2541 2633 nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
2542 2634 &snapname);
2543 2635 nvlist_t *props;
2544 2636 int ret;
2545 2637
2546 2638 (void) nvlist_lookup_uint64(fs, "parentfromsnap",
2547 2639 &parent_snapguid);
2548 2640 err = nvlist_lookup_nvlist(fs, "props", &props);
2549 2641 if (err)
2550 2642 VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
2551 2643
2552 2644 if (flags->canmountoff) {
2553 2645 VERIFY(0 == nvlist_add_uint64(props,
2554 2646 zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
2555 2647 }
2556 2648 ret = zcmd_write_src_nvlist(hdl, &zc, props);
2557 2649 if (err)
2558 2650 nvlist_free(props);
2559 2651
2560 2652 if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
2561 2653 VERIFY(0 == nvlist_lookup_nvlist(props,
2562 2654 snapname, &snapprops_nvlist));
2563 2655 }
2564 2656
2565 2657 if (ret != 0)
2566 2658 return (-1);
2567 2659 }
2568 2660
2569 2661 cp = NULL;
2570 2662
2571 2663 /*
2572 2664 * Determine how much of the snapshot name stored in the stream
2573 2665 * we are going to tack on to the name they specified on the
2574 2666 * command line, and how much we are going to chop off.
2575 2667 *
2576 2668 * If they specified a snapshot, chop the entire name stored in
2577 2669 * the stream.
2578 2670 */
2579 2671 if (flags->istail) {
2580 2672 /*
2581 2673 * A filesystem was specified with -e. We want to tack on only
2582 2674 * the tail of the sent snapshot path.
2583 2675 */
2584 2676 if (strchr(tosnap, '@')) {
2585 2677 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2586 2678 "argument - snapshot not allowed with -e"));
2587 2679 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2588 2680 }
2589 2681
2590 2682 chopprefix = strrchr(sendfs, '/');
2591 2683
2592 2684 if (chopprefix == NULL) {
2593 2685 /*
2594 2686 * The tail is the poolname, so we need to
2595 2687 * prepend a path separator.
2596 2688 */
2597 2689 int len = strlen(drrb->drr_toname);
2598 2690 cp = malloc(len + 2);
2599 2691 cp[0] = '/';
2600 2692 (void) strcpy(&cp[1], drrb->drr_toname);
2601 2693 chopprefix = cp;
2602 2694 } else {
2603 2695 chopprefix = drrb->drr_toname + (chopprefix - sendfs);
2604 2696 }
2605 2697 } else if (flags->isprefix) {
2606 2698 /*
2607 2699 * A filesystem was specified with -d. We want to tack on
2608 2700 * everything but the first element of the sent snapshot path
2609 2701 * (all but the pool name).
2610 2702 */
2611 2703 if (strchr(tosnap, '@')) {
2612 2704 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
2613 2705 "argument - snapshot not allowed with -d"));
2614 2706 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2615 2707 }
2616 2708
2617 2709 chopprefix = strchr(drrb->drr_toname, '/');
2618 2710 if (chopprefix == NULL)
2619 2711 chopprefix = strchr(drrb->drr_toname, '@');
2620 2712 } else if (strchr(tosnap, '@') == NULL) {
2621 2713 /*
2622 2714 * If a filesystem was specified without -d or -e, we want to
2623 2715 * tack on everything after the fs specified by 'zfs send'.
2624 2716 */
2625 2717 chopprefix = drrb->drr_toname + strlen(sendfs);
2626 2718 } else {
2627 2719 /* A snapshot was specified as an exact path (no -d or -e). */
2628 2720 if (recursive) {
2629 2721 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2630 2722 "cannot specify snapshot name for multi-snapshot "
2631 2723 "stream"));
2632 2724 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
2633 2725 }
2634 2726 chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);
2635 2727 }
2636 2728
2637 2729 ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);
2638 2730 ASSERT(chopprefix > drrb->drr_toname);
2639 2731 ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname));
2640 2732 ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||
2641 2733 chopprefix[0] == '\0');
2642 2734
2643 2735 /*
2644 2736 * Determine name of destination snapshot, store in zc_value.
2645 2737 */
2646 2738 (void) strcpy(zc.zc_top_ds, tosnap);
2647 2739 (void) strcpy(zc.zc_value, tosnap);
2648 2740 (void) strncat(zc.zc_value, chopprefix, sizeof (zc.zc_value));
2649 2741 free(cp);
2650 2742 if (!zfs_name_valid(zc.zc_value, ZFS_TYPE_SNAPSHOT)) {
2651 2743 zcmd_free_nvlists(&zc);
2652 2744 return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
2653 2745 }
2654 2746
2655 2747 /*
2656 2748 * Determine the name of the origin snapshot, store in zc_string.
2657 2749 */
2658 2750 if (drrb->drr_flags & DRR_FLAG_CLONE) {
2659 2751 if (guid_to_name(hdl, zc.zc_value,
2660 2752 drrb->drr_fromguid, zc.zc_string) != 0) {
2661 2753 zcmd_free_nvlists(&zc);
2662 2754 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2663 2755 "local origin for clone %s does not exist"),
2664 2756 zc.zc_value);
2665 2757 return (zfs_error(hdl, EZFS_NOENT, errbuf));
2666 2758 }
2667 2759 if (flags->verbose)
2668 2760 (void) printf("found clone origin %s\n", zc.zc_string);
2669 2761 }
2670 2762
2671 2763 stream_wantsnewfs = (drrb->drr_fromguid == NULL ||
2672 2764 (drrb->drr_flags & DRR_FLAG_CLONE));
2673 2765
2674 2766 if (stream_wantsnewfs) {
2675 2767 /*
2676 2768 * if the parent fs does not exist, look for it based on
2677 2769 * the parent snap GUID
2678 2770 */
2679 2771 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2680 2772 "cannot receive new filesystem stream"));
2681 2773
2682 2774 (void) strcpy(zc.zc_name, zc.zc_value);
2683 2775 cp = strrchr(zc.zc_name, '/');
2684 2776 if (cp)
2685 2777 *cp = '\0';
2686 2778 if (cp &&
2687 2779 !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
2688 2780 char suffix[ZFS_MAXNAMELEN];
2689 2781 (void) strcpy(suffix, strrchr(zc.zc_value, '/'));
2690 2782 if (guid_to_name(hdl, zc.zc_name, parent_snapguid,
2691 2783 zc.zc_value) == 0) {
2692 2784 *strchr(zc.zc_value, '@') = '\0';
2693 2785 (void) strcat(zc.zc_value, suffix);
2694 2786 }
2695 2787 }
2696 2788 } else {
2697 2789 /*
2698 2790 * if the fs does not exist, look for it based on the
2699 2791 * fromsnap GUID
2700 2792 */
2701 2793 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2702 2794 "cannot receive incremental stream"));
2703 2795
2704 2796 (void) strcpy(zc.zc_name, zc.zc_value);
2705 2797 *strchr(zc.zc_name, '@') = '\0';
2706 2798
2707 2799 /*
2708 2800 * If the exact receive path was specified and this is the
2709 2801 * topmost path in the stream, then if the fs does not exist we
2710 2802 * should look no further.
2711 2803 */
2712 2804 if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +
2713 2805 strlen(sendfs)) != '\0' && *chopprefix != '@')) &&
2714 2806 !zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
2715 2807 char snap[ZFS_MAXNAMELEN];
2716 2808 (void) strcpy(snap, strchr(zc.zc_value, '@'));
2717 2809 if (guid_to_name(hdl, zc.zc_name, drrb->drr_fromguid,
2718 2810 zc.zc_value) == 0) {
2719 2811 *strchr(zc.zc_value, '@') = '\0';
2720 2812 (void) strcat(zc.zc_value, snap);
2721 2813 }
2722 2814 }
2723 2815 }
2724 2816
2725 2817 (void) strcpy(zc.zc_name, zc.zc_value);
2726 2818 *strchr(zc.zc_name, '@') = '\0';
2727 2819
2728 2820 if (zfs_dataset_exists(hdl, zc.zc_name, ZFS_TYPE_DATASET)) {
2729 2821 zfs_handle_t *zhp;
2730 2822
2731 2823 /*
2732 2824 * Destination fs exists. Therefore this should either
2733 2825 * be an incremental, or the stream specifies a new fs
2734 2826 * (full stream or clone) and they want us to blow it
2735 2827 * away (and have therefore specified -F and removed any
2736 2828 * snapshots).
2737 2829 */
2738 2830 if (stream_wantsnewfs) {
2739 2831 if (!flags->force) {
2740 2832 zcmd_free_nvlists(&zc);
2741 2833 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2742 2834 "destination '%s' exists\n"
2743 2835 "must specify -F to overwrite it"),
2744 2836 zc.zc_name);
2745 2837 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2746 2838 }
2747 2839 if (ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
2748 2840 &zc) == 0) {
2749 2841 zcmd_free_nvlists(&zc);
2750 2842 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2751 2843 "destination has snapshots (eg. %s)\n"
2752 2844 "must destroy them to overwrite it"),
2753 2845 zc.zc_name);
2754 2846 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2755 2847 }
2756 2848 }
2757 2849
2758 2850 if ((zhp = zfs_open(hdl, zc.zc_name,
2759 2851 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
2760 2852 zcmd_free_nvlists(&zc);
2761 2853 return (-1);
2762 2854 }
2763 2855
2764 2856 if (stream_wantsnewfs &&
2765 2857 zhp->zfs_dmustats.dds_origin[0]) {
2766 2858 zcmd_free_nvlists(&zc);
2767 2859 zfs_close(zhp);
2768 2860 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2769 2861 "destination '%s' is a clone\n"
2770 2862 "must destroy it to overwrite it"),
2771 2863 zc.zc_name);
2772 2864 return (zfs_error(hdl, EZFS_EXISTS, errbuf));
2773 2865 }
2774 2866
2775 2867 if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
2776 2868 stream_wantsnewfs) {
2777 2869 /* We can't do online recv in this case */
2778 2870 clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
2779 2871 if (clp == NULL) {
2780 2872 zfs_close(zhp);
2781 2873 zcmd_free_nvlists(&zc);
2782 2874 return (-1);
2783 2875 }
2784 2876 if (changelist_prefix(clp) != 0) {
2785 2877 changelist_free(clp);
2786 2878 zfs_close(zhp);
2787 2879 zcmd_free_nvlists(&zc);
2788 2880 return (-1);
2789 2881 }
2790 2882 }
2791 2883 zfs_close(zhp);
2792 2884 } else {
2793 2885 /*
2794 2886 * Destination filesystem does not exist. Therefore we better
2795 2887 * be creating a new filesystem (either from a full backup, or
2796 2888 * a clone). It would therefore be invalid if the user
2797 2889 * specified only the pool name (i.e. if the destination name
2798 2890 * contained no slash character).
2799 2891 */
2800 2892 if (!stream_wantsnewfs ||
2801 2893 (cp = strrchr(zc.zc_name, '/')) == NULL) {
2802 2894 zcmd_free_nvlists(&zc);
2803 2895 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2804 2896 "destination '%s' does not exist"), zc.zc_name);
2805 2897 return (zfs_error(hdl, EZFS_NOENT, errbuf));
2806 2898 }
2807 2899
2808 2900 /*
2809 2901 * Trim off the final dataset component so we perform the
2810 2902 * recvbackup ioctl to the filesystems's parent.
2811 2903 */
2812 2904 *cp = '\0';
2813 2905
2814 2906 if (flags->isprefix && !flags->istail && !flags->dryrun &&
2815 2907 create_parents(hdl, zc.zc_value, strlen(tosnap)) != 0) {
2816 2908 zcmd_free_nvlists(&zc);
2817 2909 return (zfs_error(hdl, EZFS_BADRESTORE, errbuf));
2818 2910 }
2819 2911
2820 2912 newfs = B_TRUE;
2821 2913 }
2822 2914
2823 2915 zc.zc_begin_record = drr_noswap->drr_u.drr_begin;
2824 2916 zc.zc_cookie = infd;
2825 2917 zc.zc_guid = flags->force;
2826 2918 if (flags->verbose) {
2827 2919 (void) printf("%s %s stream of %s into %s\n",
2828 2920 flags->dryrun ? "would receive" : "receiving",
2829 2921 drrb->drr_fromguid ? "incremental" : "full",
2830 2922 drrb->drr_toname, zc.zc_value);
2831 2923 (void) fflush(stdout);
2832 2924 }
2833 2925
2834 2926 if (flags->dryrun) {
2835 2927 zcmd_free_nvlists(&zc);
2836 2928 return (recv_skip(hdl, infd, flags->byteswap));
2837 2929 }
2838 2930
2839 2931 zc.zc_nvlist_dst = (uint64_t)(uintptr_t)prop_errbuf;
2840 2932 zc.zc_nvlist_dst_size = sizeof (prop_errbuf);
2841 2933 zc.zc_cleanup_fd = cleanup_fd;
2842 2934 zc.zc_action_handle = *action_handlep;
2843 2935
2844 2936 err = ioctl_err = zfs_ioctl(hdl, ZFS_IOC_RECV, &zc);
2845 2937 ioctl_errno = errno;
2846 2938 prop_errflags = (zprop_errflags_t)zc.zc_obj;
2847 2939
2848 2940 if (err == 0) {
2849 2941 nvlist_t *prop_errors;
2850 2942 VERIFY(0 == nvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
2851 2943 zc.zc_nvlist_dst_size, &prop_errors, 0));
2852 2944
2853 2945 nvpair_t *prop_err = NULL;
2854 2946
2855 2947 while ((prop_err = nvlist_next_nvpair(prop_errors,
2856 2948 prop_err)) != NULL) {
2857 2949 char tbuf[1024];
2858 2950 zfs_prop_t prop;
2859 2951 int intval;
2860 2952
2861 2953 prop = zfs_name_to_prop(nvpair_name(prop_err));
2862 2954 (void) nvpair_value_int32(prop_err, &intval);
2863 2955 if (strcmp(nvpair_name(prop_err),
2864 2956 ZPROP_N_MORE_ERRORS) == 0) {
2865 2957 trunc_prop_errs(intval);
2866 2958 break;
2867 2959 } else {
2868 2960 (void) snprintf(tbuf, sizeof (tbuf),
2869 2961 dgettext(TEXT_DOMAIN,
2870 2962 "cannot receive %s property on %s"),
2871 2963 nvpair_name(prop_err), zc.zc_name);
2872 2964 zfs_setprop_error(hdl, prop, intval, tbuf);
2873 2965 }
2874 2966 }
2875 2967 nvlist_free(prop_errors);
2876 2968 }
2877 2969
2878 2970 zc.zc_nvlist_dst = 0;
2879 2971 zc.zc_nvlist_dst_size = 0;
2880 2972 zcmd_free_nvlists(&zc);
2881 2973
2882 2974 if (err == 0 && snapprops_nvlist) {
2883 2975 zfs_cmd_t zc2 = { 0 };
2884 2976
2885 2977 (void) strcpy(zc2.zc_name, zc.zc_value);
2886 2978 zc2.zc_cookie = B_TRUE; /* received */
2887 2979 if (zcmd_write_src_nvlist(hdl, &zc2, snapprops_nvlist) == 0) {
2888 2980 (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc2);
2889 2981 zcmd_free_nvlists(&zc2);
2890 2982 }
2891 2983 }
2892 2984
2893 2985 if (err && (ioctl_errno == ENOENT || ioctl_errno == EEXIST)) {
2894 2986 /*
2895 2987 * It may be that this snapshot already exists,
2896 2988 * in which case we want to consume & ignore it
2897 2989 * rather than failing.
2898 2990 */
2899 2991 avl_tree_t *local_avl;
2900 2992 nvlist_t *local_nv, *fs;
2901 2993 cp = strchr(zc.zc_value, '@');
2902 2994
2903 2995 /*
2904 2996 * XXX Do this faster by just iterating over snaps in
2905 2997 * this fs. Also if zc_value does not exist, we will
2906 2998 * get a strange "does not exist" error message.
2907 2999 */
2908 3000 *cp = '\0';
2909 3001 if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE,
2910 3002 &local_nv, &local_avl) == 0) {
2911 3003 *cp = '@';
2912 3004 fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
2913 3005 fsavl_destroy(local_avl);
2914 3006 nvlist_free(local_nv);
2915 3007
2916 3008 if (fs != NULL) {
2917 3009 if (flags->verbose) {
2918 3010 (void) printf("snap %s already exists; "
2919 3011 "ignoring\n", zc.zc_value);
2920 3012 }
2921 3013 err = ioctl_err = recv_skip(hdl, infd,
2922 3014 flags->byteswap);
2923 3015 }
2924 3016 }
2925 3017 *cp = '@';
2926 3018 }
2927 3019
2928 3020 if (ioctl_err != 0) {
2929 3021 switch (ioctl_errno) {
2930 3022 case ENODEV:
2931 3023 cp = strchr(zc.zc_value, '@');
2932 3024 *cp = '\0';
2933 3025 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2934 3026 "most recent snapshot of %s does not\n"
2935 3027 "match incremental source"), zc.zc_value);
2936 3028 (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
2937 3029 *cp = '@';
2938 3030 break;
2939 3031 case ETXTBSY:
2940 3032 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2941 3033 "destination %s has been modified\n"
2942 3034 "since most recent snapshot"), zc.zc_name);
2943 3035 (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
2944 3036 break;
2945 3037 case EEXIST:
2946 3038 cp = strchr(zc.zc_value, '@');
2947 3039 if (newfs) {
2948 3040 /* it's the containing fs that exists */
2949 3041 *cp = '\0';
2950 3042 }
2951 3043 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2952 3044 "destination already exists"));
2953 3045 (void) zfs_error_fmt(hdl, EZFS_EXISTS,
2954 3046 dgettext(TEXT_DOMAIN, "cannot restore to %s"),
2955 3047 zc.zc_value);
2956 3048 *cp = '@';
2957 3049 break;
2958 3050 case EINVAL:
2959 3051 (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2960 3052 break;
2961 3053 case ECKSUM:
2962 3054 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2963 3055 "invalid stream (checksum mismatch)"));
2964 3056 (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
2965 3057 break;
2966 3058 case ENOTSUP:
2967 3059 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2968 3060 "pool must be upgraded to receive this stream."));
2969 3061 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
2970 3062 break;
2971 3063 case EDQUOT:
2972 3064 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
2973 3065 "destination %s space quota exceeded"), zc.zc_name);
2974 3066 (void) zfs_error(hdl, EZFS_NOSPC, errbuf);
2975 3067 break;
2976 3068 default:
2977 3069 (void) zfs_standard_error(hdl, ioctl_errno, errbuf);
2978 3070 }
2979 3071 }
2980 3072
2981 3073 /*
2982 3074 * Mount the target filesystem (if created). Also mount any
2983 3075 * children of the target filesystem if we did a replication
2984 3076 * receive (indicated by stream_avl being non-NULL).
2985 3077 */
2986 3078 cp = strchr(zc.zc_value, '@');
2987 3079 if (cp && (ioctl_err == 0 || !newfs)) {
2988 3080 zfs_handle_t *h;
2989 3081
2990 3082 *cp = '\0';
2991 3083 h = zfs_open(hdl, zc.zc_value,
2992 3084 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
2993 3085 if (h != NULL) {
2994 3086 if (h->zfs_type == ZFS_TYPE_VOLUME) {
2995 3087 *cp = '@';
2996 3088 } else if (newfs || stream_avl) {
2997 3089 /*
2998 3090 * Track the first/top of hierarchy fs,
2999 3091 * for mounting and sharing later.
3000 3092 */
3001 3093 if (top_zfs && *top_zfs == NULL)
3002 3094 *top_zfs = zfs_strdup(hdl, zc.zc_value);
3003 3095 }
3004 3096 zfs_close(h);
3005 3097 }
3006 3098 *cp = '@';
3007 3099 }
3008 3100
3009 3101 if (clp) {
3010 3102 err |= changelist_postfix(clp);
3011 3103 changelist_free(clp);
3012 3104 }
3013 3105
3014 3106 if (prop_errflags & ZPROP_ERR_NOCLEAR) {
3015 3107 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
3016 3108 "failed to clear unreceived properties on %s"),
3017 3109 zc.zc_name);
3018 3110 (void) fprintf(stderr, "\n");
3019 3111 }
3020 3112 if (prop_errflags & ZPROP_ERR_NORESTORE) {
3021 3113 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
3022 3114 "failed to restore original properties on %s"),
3023 3115 zc.zc_name);
3024 3116 (void) fprintf(stderr, "\n");
3025 3117 }
3026 3118
3027 3119 if (err || ioctl_err)
3028 3120 return (-1);
3029 3121
3030 3122 *action_handlep = zc.zc_action_handle;
3031 3123
3032 3124 if (flags->verbose) {
3033 3125 char buf1[64];
3034 3126 char buf2[64];
3035 3127 uint64_t bytes = zc.zc_cookie;
3036 3128 time_t delta = time(NULL) - begin_time;
3037 3129 if (delta == 0)
3038 3130 delta = 1;
3039 3131 zfs_nicenum(bytes, buf1, sizeof (buf1));
3040 3132 zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
3041 3133
3042 3134 (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
3043 3135 buf1, delta, buf2);
3044 3136 }
3045 3137
3046 3138 return (0);
3047 3139 }
3048 3140
3049 3141 static int
3050 3142 zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3051 3143 int infd, const char *sendfs, nvlist_t *stream_nv, avl_tree_t *stream_avl,
3052 3144 char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
3053 3145 {
3054 3146 int err;
3055 3147 dmu_replay_record_t drr, drr_noswap;
3056 3148 struct drr_begin *drrb = &drr.drr_u.drr_begin;
3057 3149 char errbuf[1024];
3058 3150 zio_cksum_t zcksum = { 0 };
3059 3151 uint64_t featureflags;
3060 3152 int hdrtype;
3061 3153
3062 3154 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
3063 3155 "cannot receive"));
3064 3156
3065 3157 if (flags->isprefix &&
3066 3158 !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
3067 3159 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
3068 3160 "(%s) does not exist"), tosnap);
3069 3161 return (zfs_error(hdl, EZFS_NOENT, errbuf));
3070 3162 }
3071 3163
3072 3164 /* read in the BEGIN record */
3073 3165 if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE,
3074 3166 &zcksum)))
3075 3167 return (err);
3076 3168
3077 3169 if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) {
3078 3170 /* It's the double end record at the end of a package */
3079 3171 return (ENODATA);
3080 3172 }
3081 3173
3082 3174 /* the kernel needs the non-byteswapped begin record */
3083 3175 drr_noswap = drr;
3084 3176
3085 3177 flags->byteswap = B_FALSE;
3086 3178 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
3087 3179 /*
3088 3180 * We computed the checksum in the wrong byteorder in
3089 3181 * recv_read() above; do it again correctly.
3090 3182 */
3091 3183 bzero(&zcksum, sizeof (zio_cksum_t));
3092 3184 fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum);
3093 3185 flags->byteswap = B_TRUE;
3094 3186
3095 3187 drr.drr_type = BSWAP_32(drr.drr_type);
3096 3188 drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);
3097 3189 drrb->drr_magic = BSWAP_64(drrb->drr_magic);
3098 3190 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);
3099 3191 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
3100 3192 drrb->drr_type = BSWAP_32(drrb->drr_type);
3101 3193 drrb->drr_flags = BSWAP_32(drrb->drr_flags);
3102 3194 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
3103 3195 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
3104 3196 }
3105 3197
3106 3198 if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) {
3107 3199 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3108 3200 "stream (bad magic number)"));
3109 3201 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3110 3202 }
3111 3203
3112 3204 featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
3113 3205 hdrtype = DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo);
3114 3206
3115 3207 if (!DMU_STREAM_SUPPORTED(featureflags) ||
3116 3208 (hdrtype != DMU_SUBSTREAM && hdrtype != DMU_COMPOUNDSTREAM)) {
3117 3209 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
3118 3210 "stream has unsupported feature, feature flags = %lx"),
3119 3211 featureflags);
3120 3212 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3121 3213 }
3122 3214
3123 3215 if (strchr(drrb->drr_toname, '@') == NULL) {
3124 3216 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
3125 3217 "stream (bad snapshot name)"));
3126 3218 return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
3127 3219 }
3128 3220
3129 3221 if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
3130 3222 char nonpackage_sendfs[ZFS_MAXNAMELEN];
3131 3223 if (sendfs == NULL) {
3132 3224 /*
3133 3225 * We were not called from zfs_receive_package(). Get
3134 3226 * the fs specified by 'zfs send'.
3135 3227 */
3136 3228 char *cp;
3137 3229 (void) strlcpy(nonpackage_sendfs,
3138 3230 drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
3139 3231 if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
3140 3232 *cp = '\0';
3141 3233 sendfs = nonpackage_sendfs;
3142 3234 }
3143 3235 return (zfs_receive_one(hdl, infd, tosnap, flags,
3144 3236 &drr, &drr_noswap, sendfs, stream_nv, stream_avl,
3145 3237 top_zfs, cleanup_fd, action_handlep));
3146 3238 } else {
3147 3239 assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
3148 3240 DMU_COMPOUNDSTREAM);
3149 3241 return (zfs_receive_package(hdl, infd, tosnap, flags,
3150 3242 &drr, &zcksum, top_zfs, cleanup_fd, action_handlep));
3151 3243 }
3152 3244 }
3153 3245
3154 3246 /*
3155 3247 * Restores a backup of tosnap from the file descriptor specified by infd.
3156 3248 * Return 0 on total success, -2 if some things couldn't be
3157 3249 * destroyed/renamed/promoted, -1 if some things couldn't be received.
3158 3250 * (-1 will override -2).
3159 3251 */
3160 3252 int
3161 3253 zfs_receive(libzfs_handle_t *hdl, const char *tosnap, recvflags_t *flags,
3162 3254 int infd, avl_tree_t *stream_avl)
3163 3255 {
3164 3256 char *top_zfs = NULL;
3165 3257 int err;
3166 3258 int cleanup_fd;
3167 3259 uint64_t action_handle = 0;
3168 3260
3169 3261 cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
3170 3262 VERIFY(cleanup_fd >= 0);
3171 3263
3172 3264 err = zfs_receive_impl(hdl, tosnap, flags, infd, NULL, NULL,
3173 3265 stream_avl, &top_zfs, cleanup_fd, &action_handle);
3174 3266
3175 3267 VERIFY(0 == close(cleanup_fd));
3176 3268
3177 3269 if (err == 0 && !flags->nomount && top_zfs) {
3178 3270 zfs_handle_t *zhp;
3179 3271 prop_changelist_t *clp;
3180 3272
3181 3273 zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
3182 3274 if (zhp != NULL) {
3183 3275 clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
3184 3276 CL_GATHER_MOUNT_ALWAYS, 0);
3185 3277 zfs_close(zhp);
3186 3278 if (clp != NULL) {
3187 3279 /* mount and share received datasets */
3188 3280 err = changelist_postfix(clp);
3189 3281 changelist_free(clp);
3190 3282 }
3191 3283 }
3192 3284 if (zhp == NULL || clp == NULL || err)
3193 3285 err = -1;
3194 3286 }
3195 3287 if (top_zfs)
3196 3288 free(top_zfs);
3197 3289
3198 3290 return (err);
3199 3291 }
|
↓ open down ↓ |
1592 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX