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