dmu_send.c (246666) | dmu_send.c (248571) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 33 unchanged lines hidden (view full) --- 42#include <sys/zfs_ioctl.h> 43#include <sys/zap.h> 44#include <sys/zio_checksum.h> 45#include <sys/zfs_znode.h> 46#include <zfs_fletcher.h> 47#include <sys/avl.h> 48#include <sys/ddt.h> 49#include <sys/zfs_onexit.h> | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 33 unchanged lines hidden (view full) --- 42#include <sys/zfs_ioctl.h> 43#include <sys/zap.h> 44#include <sys/zio_checksum.h> 45#include <sys/zfs_znode.h> 46#include <zfs_fletcher.h> 47#include <sys/avl.h> 48#include <sys/ddt.h> 49#include <sys/zfs_onexit.h> |
50#include <sys/dmu_send.h> 51#include <sys/dsl_destroy.h> |
|
50 51/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 52int zfs_send_corrupt_data = B_FALSE; 53 54static char *dmu_recv_tag = "dmu_recv_tag"; | 52 53/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 54int zfs_send_corrupt_data = B_FALSE; 55 56static char *dmu_recv_tag = "dmu_recv_tag"; |
57static const char *recv_clone_name = "%recv"; |
|
55 56static int 57dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 58{ 59 dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 60 struct uio auio; 61 struct iovec aiov; 62 ASSERT0(len % 8); --- 238 unchanged lines hidden (view full) --- 301 302 if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 303 return (EINTR); 304 305 /* free anything past the end of the file */ 306 if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 307 (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 308 return (EINTR); | 58 59static int 60dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 61{ 62 dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 63 struct uio auio; 64 struct iovec aiov; 65 ASSERT0(len % 8); --- 238 unchanged lines hidden (view full) --- 304 305 if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 306 return (EINTR); 307 308 /* free anything past the end of the file */ 309 if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 310 (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 311 return (EINTR); |
309 if (dsp->dsa_err) | 312 if (dsp->dsa_err != 0) |
310 return (EINTR); 311 return (0); 312} 313 314#define BP_SPAN(dnp, level) \ 315 (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 316 (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 317 --- 33 unchanged lines hidden (view full) --- 351 &aflags, zb) != 0) 352 return (EIO); 353 354 blk = abuf->b_data; 355 for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 356 uint64_t dnobj = (zb->zb_blkid << 357 (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 358 err = dump_dnode(dsp, dnobj, blk+i); | 313 return (EINTR); 314 return (0); 315} 316 317#define BP_SPAN(dnp, level) \ 318 (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 319 (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 320 --- 33 unchanged lines hidden (view full) --- 354 &aflags, zb) != 0) 355 return (EIO); 356 357 blk = abuf->b_data; 358 for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 359 uint64_t dnobj = (zb->zb_blkid << 360 (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 361 err = dump_dnode(dsp, dnobj, blk+i); |
359 if (err) | 362 if (err != 0) |
360 break; 361 } 362 (void) arc_buf_remove_ref(abuf, &abuf); 363 } else if (type == DMU_OT_SA) { 364 uint32_t aflags = ARC_WAIT; 365 arc_buf_t *abuf; 366 int blksz = BP_GET_LSIZE(bp); 367 --- 30 unchanged lines hidden (view full) --- 398 blksz, bp, abuf->b_data); 399 (void) arc_buf_remove_ref(abuf, &abuf); 400 } 401 402 ASSERT(err == 0 || err == EINTR); 403 return (err); 404} 405 | 363 break; 364 } 365 (void) arc_buf_remove_ref(abuf, &abuf); 366 } else if (type == DMU_OT_SA) { 367 uint32_t aflags = ARC_WAIT; 368 arc_buf_t *abuf; 369 int blksz = BP_GET_LSIZE(bp); 370 --- 30 unchanged lines hidden (view full) --- 401 blksz, bp, abuf->b_data); 402 (void) arc_buf_remove_ref(abuf, &abuf); 403 } 404 405 ASSERT(err == 0 || err == EINTR); 406 return (err); 407} 408 |
406int 407dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, 408 int outfd, struct file *fp, offset_t *off) | 409/* 410 * Releases dp, ds, and fromds, using the specified tag. 411 */ 412static int 413dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds, 414#ifdef illumos 415 dsl_dataset_t *fromds, int outfd, vnode_t *vp, offset_t *off) 416#else 417 dsl_dataset_t *fromds, int outfd, struct file *fp, offset_t *off) 418#endif |
409{ | 419{ |
410 dsl_dataset_t *ds = tosnap->os_dsl_dataset; 411 dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL; | 420 objset_t *os; |
412 dmu_replay_record_t *drr; 413 dmu_sendarg_t *dsp; 414 int err; 415 uint64_t fromtxg = 0; 416 | 421 dmu_replay_record_t *drr; 422 dmu_sendarg_t *dsp; 423 int err; 424 uint64_t fromtxg = 0; 425 |
417 /* tosnap must be a snapshot */ 418 if (ds->ds_phys->ds_next_snap_obj == 0) 419 return (EINVAL); 420 421 /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 422 if (fromds && (ds->ds_dir != fromds->ds_dir || 423 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg)) | 426 if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) { 427 dsl_dataset_rele(fromds, tag); 428 dsl_dataset_rele(ds, tag); 429 dsl_pool_rele(dp, tag); |
424 return (EXDEV); | 430 return (EXDEV); |
431 } |
|
425 | 432 |
426 if (fromorigin) { 427 dsl_pool_t *dp = ds->ds_dir->dd_pool; 428 429 if (fromsnap) 430 return (EINVAL); 431 432 if (dsl_dir_is_clone(ds->ds_dir)) { 433 rw_enter(&dp->dp_config_rwlock, RW_READER); 434 err = dsl_dataset_hold_obj(dp, 435 ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds); 436 rw_exit(&dp->dp_config_rwlock); 437 if (err) 438 return (err); 439 } else { 440 fromorigin = B_FALSE; 441 } | 433 err = dmu_objset_from_ds(ds, &os); 434 if (err != 0) { 435 if (fromds != NULL) 436 dsl_dataset_rele(fromds, tag); 437 dsl_dataset_rele(ds, tag); 438 dsl_pool_rele(dp, tag); 439 return (err); |
442 } 443 | 440 } 441 |
444 | |
445 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 446 drr->drr_type = DRR_BEGIN; 447 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 448 DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 449 DMU_SUBSTREAM); 450 451#ifdef _KERNEL | 442 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 443 drr->drr_type = DRR_BEGIN; 444 drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 445 DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 446 DMU_SUBSTREAM); 447 448#ifdef _KERNEL |
452 if (dmu_objset_type(tosnap) == DMU_OST_ZFS) { | 449 if (dmu_objset_type(os) == DMU_OST_ZFS) { |
453 uint64_t version; | 450 uint64_t version; |
454 if (zfs_get_zplprop(tosnap, ZFS_PROP_VERSION, &version) != 0) { | 451 if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) { |
455 kmem_free(drr, sizeof (dmu_replay_record_t)); | 452 kmem_free(drr, sizeof (dmu_replay_record_t)); |
453 if (fromds != NULL) 454 dsl_dataset_rele(fromds, tag); 455 dsl_dataset_rele(ds, tag); 456 dsl_pool_rele(dp, tag); |
|
456 return (EINVAL); 457 } | 457 return (EINVAL); 458 } |
458 if (version == ZPL_VERSION_SA) { | 459 if (version >= ZPL_VERSION_SA) { |
459 DMU_SET_FEATUREFLAGS( 460 drr->drr_u.drr_begin.drr_versioninfo, 461 DMU_BACKUP_FEATURE_SA_SPILL); 462 } 463 } 464#endif 465 466 drr->drr_u.drr_begin.drr_creation_time = 467 ds->ds_phys->ds_creation_time; | 460 DMU_SET_FEATUREFLAGS( 461 drr->drr_u.drr_begin.drr_versioninfo, 462 DMU_BACKUP_FEATURE_SA_SPILL); 463 } 464 } 465#endif 466 467 drr->drr_u.drr_begin.drr_creation_time = 468 ds->ds_phys->ds_creation_time; |
468 drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type; 469 if (fromorigin) | 469 drr->drr_u.drr_begin.drr_type = dmu_objset_type(os); 470 if (fromds != NULL && ds->ds_dir != fromds->ds_dir) |
470 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 471 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 472 if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 473 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 474 | 471 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 472 drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 473 if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 474 drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 475 |
475 if (fromds) | 476 if (fromds != NULL) |
476 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 477 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 478 | 477 drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 478 dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 479 |
479 if (fromds) | 480 if (fromds != NULL) { |
480 fromtxg = fromds->ds_phys->ds_creation_txg; | 481 fromtxg = fromds->ds_phys->ds_creation_txg; |
481 if (fromorigin) 482 dsl_dataset_rele(fromds, FTAG); | 482 dsl_dataset_rele(fromds, tag); 483 fromds = NULL; 484 } |
483 484 dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 485 486 dsp->dsa_drr = drr; 487 dsp->dsa_outfd = outfd; 488 dsp->dsa_proc = curproc; 489 dsp->dsa_td = curthread; 490 dsp->dsa_fp = fp; | 485 486 dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 487 488 dsp->dsa_drr = drr; 489 dsp->dsa_outfd = outfd; 490 dsp->dsa_proc = curproc; 491 dsp->dsa_td = curthread; 492 dsp->dsa_fp = fp; |
491 dsp->dsa_os = tosnap; | 493 dsp->dsa_os = os; |
492 dsp->dsa_off = off; 493 dsp->dsa_toguid = ds->ds_phys->ds_guid; 494 ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 495 dsp->dsa_pending_op = PENDING_NONE; 496 497 mutex_enter(&ds->ds_sendstream_lock); 498 list_insert_head(&ds->ds_sendstreams, dsp); 499 mutex_exit(&ds->ds_sendstream_lock); 500 501 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 502 err = dsp->dsa_err; 503 goto out; 504 } 505 | 494 dsp->dsa_off = off; 495 dsp->dsa_toguid = ds->ds_phys->ds_guid; 496 ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 497 dsp->dsa_pending_op = PENDING_NONE; 498 499 mutex_enter(&ds->ds_sendstream_lock); 500 list_insert_head(&ds->ds_sendstreams, dsp); 501 mutex_exit(&ds->ds_sendstream_lock); 502 503 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 504 err = dsp->dsa_err; 505 goto out; 506 } 507 |
508 dsl_dataset_long_hold(ds, FTAG); 509 dsl_pool_rele(dp, tag); 510 |
|
506 err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 507 backup_cb, dsp); 508 509 if (dsp->dsa_pending_op != PENDING_NONE) 510 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 511 err = EINTR; 512 | 511 err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 512 backup_cb, dsp); 513 514 if (dsp->dsa_pending_op != PENDING_NONE) 515 if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 516 err = EINTR; 517 |
513 if (err) { 514 if (err == EINTR && dsp->dsa_err) | 518 if (err != 0) { 519 if (err == EINTR && dsp->dsa_err != 0) |
515 err = dsp->dsa_err; 516 goto out; 517 } 518 519 bzero(drr, sizeof (dmu_replay_record_t)); 520 drr->drr_type = DRR_END; 521 drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 522 drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; --- 6 unchanged lines hidden (view full) --- 529out: 530 mutex_enter(&ds->ds_sendstream_lock); 531 list_remove(&ds->ds_sendstreams, dsp); 532 mutex_exit(&ds->ds_sendstream_lock); 533 534 kmem_free(drr, sizeof (dmu_replay_record_t)); 535 kmem_free(dsp, sizeof (dmu_sendarg_t)); 536 | 520 err = dsp->dsa_err; 521 goto out; 522 } 523 524 bzero(drr, sizeof (dmu_replay_record_t)); 525 drr->drr_type = DRR_END; 526 drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 527 drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; --- 6 unchanged lines hidden (view full) --- 534out: 535 mutex_enter(&ds->ds_sendstream_lock); 536 list_remove(&ds->ds_sendstreams, dsp); 537 mutex_exit(&ds->ds_sendstream_lock); 538 539 kmem_free(drr, sizeof (dmu_replay_record_t)); 540 kmem_free(dsp, sizeof (dmu_sendarg_t)); 541 |
542 dsl_dataset_long_rele(ds, FTAG); 543 dsl_dataset_rele(ds, tag); 544 |
|
537 return (err); 538} 539 540int | 545 return (err); 546} 547 548int |
541dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, 542 uint64_t *sizep) | 549dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, 550#ifdef illumos 551 int outfd, vnode_t *vp, offset_t *off) 552#else 553 int outfd, struct file *fp, offset_t *off) 554#endif |
543{ | 555{ |
544 dsl_dataset_t *ds = tosnap->os_dsl_dataset; 545 dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL; 546 dsl_pool_t *dp = ds->ds_dir->dd_pool; | 556 dsl_pool_t *dp; 557 dsl_dataset_t *ds; 558 dsl_dataset_t *fromds = NULL; |
547 int err; | 559 int err; |
548 uint64_t size; | |
549 | 560 |
550 /* tosnap must be a snapshot */ 551 if (ds->ds_phys->ds_next_snap_obj == 0) | 561 err = dsl_pool_hold(pool, FTAG, &dp); 562 if (err != 0) 563 return (err); 564 565 err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds); 566 if (err != 0) { 567 dsl_pool_rele(dp, FTAG); 568 return (err); 569 } 570 571 if (fromsnap != 0) { 572 err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds); 573 if (err != 0) { 574 dsl_dataset_rele(ds, FTAG); 575 dsl_pool_rele(dp, FTAG); 576 return (err); 577 } 578 } 579 580 return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, fp, off)); 581} 582 583int 584dmu_send(const char *tosnap, const char *fromsnap, 585#ifdef illumos 586 int outfd, vnode_t *vp, offset_t *off) 587#else 588 int outfd, struct file *fp, offset_t *off) 589#endif 590{ 591 dsl_pool_t *dp; 592 dsl_dataset_t *ds; 593 dsl_dataset_t *fromds = NULL; 594 int err; 595 596 if (strchr(tosnap, '@') == NULL) |
552 return (EINVAL); | 597 return (EINVAL); |
598 if (fromsnap != NULL && strchr(fromsnap, '@') == NULL) 599 return (EINVAL); |
|
553 | 600 |
554 /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 555 if (fromds && (ds->ds_dir != fromds->ds_dir || 556 fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg)) 557 return (EXDEV); | 601 err = dsl_pool_hold(tosnap, FTAG, &dp); 602 if (err != 0) 603 return (err); |
558 | 604 |
559 if (fromorigin) { 560 if (fromsnap) 561 return (EINVAL); | 605 err = dsl_dataset_hold(dp, tosnap, FTAG, &ds); 606 if (err != 0) { 607 dsl_pool_rele(dp, FTAG); 608 return (err); 609 } |
562 | 610 |
563 if (dsl_dir_is_clone(ds->ds_dir)) { 564 rw_enter(&dp->dp_config_rwlock, RW_READER); 565 err = dsl_dataset_hold_obj(dp, 566 ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds); 567 rw_exit(&dp->dp_config_rwlock); 568 if (err) 569 return (err); 570 } else { 571 fromorigin = B_FALSE; | 611 if (fromsnap != NULL) { 612 err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds); 613 if (err != 0) { 614 dsl_dataset_rele(ds, FTAG); 615 dsl_pool_rele(dp, FTAG); 616 return (err); |
572 } 573 } | 617 } 618 } |
619 return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, fp, off)); 620} |
|
574 | 621 |
622int 623dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep) 624{ 625 dsl_pool_t *dp = ds->ds_dir->dd_pool; 626 int err; 627 uint64_t size; 628 629 ASSERT(dsl_pool_config_held(dp)); 630 631 /* tosnap must be a snapshot */ 632 if (!dsl_dataset_is_snapshot(ds)) 633 return (EINVAL); 634 635 /* 636 * fromsnap must be an earlier snapshot from the same fs as tosnap, 637 * or the origin's fs. 638 */ 639 if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) 640 return (EXDEV); 641 |
|
575 /* Get uncompressed size estimate of changed data. */ 576 if (fromds == NULL) { 577 size = ds->ds_phys->ds_uncompressed_bytes; 578 } else { 579 uint64_t used, comp; 580 err = dsl_dataset_space_written(fromds, ds, 581 &used, &comp, &size); | 642 /* Get uncompressed size estimate of changed data. */ 643 if (fromds == NULL) { 644 size = ds->ds_phys->ds_uncompressed_bytes; 645 } else { 646 uint64_t used, comp; 647 err = dsl_dataset_space_written(fromds, ds, 648 &used, &comp, &size); |
582 if (fromorigin) 583 dsl_dataset_rele(fromds, FTAG); 584 if (err) | 649 if (err != 0) |
585 return (err); 586 } 587 588 /* 589 * Assume that space (both on-disk and in-stream) is dominated by 590 * data. We will adjust for indirect blocks and the copies property, 591 * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 592 */ 593 594 /* 595 * Subtract out approximate space used by indirect blocks. 596 * Assume most space is used by data blocks (non-indirect, non-dnode). 597 * Assume all blocks are recordsize. Assume ditto blocks and 598 * internal fragmentation counter out compression. 599 * 600 * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 601 * block, which we observe in practice. 602 */ 603 uint64_t recordsize; | 650 return (err); 651 } 652 653 /* 654 * Assume that space (both on-disk and in-stream) is dominated by 655 * data. We will adjust for indirect blocks and the copies property, 656 * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 657 */ 658 659 /* 660 * Subtract out approximate space used by indirect blocks. 661 * Assume most space is used by data blocks (non-indirect, non-dnode). 662 * Assume all blocks are recordsize. Assume ditto blocks and 663 * internal fragmentation counter out compression. 664 * 665 * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 666 * block, which we observe in practice. 667 */ 668 uint64_t recordsize; |
604 rw_enter(&dp->dp_config_rwlock, RW_READER); 605 err = dsl_prop_get_ds(ds, "recordsize", 606 sizeof (recordsize), 1, &recordsize, NULL); 607 rw_exit(&dp->dp_config_rwlock); 608 if (err) | 669 err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize); 670 if (err != 0) |
609 return (err); 610 size -= size / recordsize * sizeof (blkptr_t); 611 612 /* Add in the space for the record associated with each block. */ 613 size += size / recordsize * sizeof (dmu_replay_record_t); 614 615 *sizep = size; 616 617 return (0); 618} 619 | 671 return (err); 672 size -= size / recordsize * sizeof (blkptr_t); 673 674 /* Add in the space for the record associated with each block. */ 675 size += size / recordsize * sizeof (dmu_replay_record_t); 676 677 *sizep = size; 678 679 return (0); 680} 681 |
620struct recvbeginsyncarg { 621 const char *tofs; 622 const char *tosnap; 623 dsl_dataset_t *origin; 624 uint64_t fromguid; 625 dmu_objset_type_t type; 626 void *tag; 627 boolean_t force; 628 uint64_t dsflags; 629 char clonelastname[MAXNAMELEN]; 630 dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */ 631 cred_t *cr; 632}; | 682typedef struct dmu_recv_begin_arg { 683 const char *drba_origin; 684 dmu_recv_cookie_t *drba_cookie; 685 cred_t *drba_cred; 686} dmu_recv_begin_arg_t; |
633 | 687 |
634/* ARGSUSED */ | |
635static int | 688static int |
636recv_new_check(void *arg1, void *arg2, dmu_tx_t *tx) | 689recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds, 690 uint64_t fromguid) |
637{ | 691{ |
638 dsl_dir_t *dd = arg1; 639 struct recvbeginsyncarg *rbsa = arg2; 640 objset_t *mos = dd->dd_pool->dp_meta_objset; | |
641 uint64_t val; | 692 uint64_t val; |
642 int err; | 693 int error; 694 dsl_pool_t *dp = ds->ds_dir->dd_pool; |
643 | 695 |
644 err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 645 strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val); 646 647 if (err != ENOENT) 648 return (err ? err : EEXIST); 649 650 if (rbsa->origin) { 651 /* make sure it's a snap in the same pool */ 652 if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool) 653 return (EXDEV); 654 if (!dsl_dataset_is_snapshot(rbsa->origin)) 655 return (EINVAL); 656 if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 657 return (ENODEV); 658 } 659 660 return (0); 661} 662 663static void 664recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx) 665{ 666 dsl_dir_t *dd = arg1; 667 struct recvbeginsyncarg *rbsa = arg2; 668 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 669 uint64_t dsobj; 670 671 /* Create and open new dataset. */ 672 dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1, 673 rbsa->origin, flags, rbsa->cr, tx); 674 VERIFY(0 == dsl_dataset_own_obj(dd->dd_pool, dsobj, 675 B_TRUE, dmu_recv_tag, &rbsa->ds)); 676 677 if (rbsa->origin == NULL) { 678 (void) dmu_objset_create_impl(dd->dd_pool->dp_spa, 679 rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx); 680 } 681 682 spa_history_log_internal(LOG_DS_REPLAY_FULL_SYNC, 683 dd->dd_pool->dp_spa, tx, "dataset = %lld", dsobj); 684} 685 686/* ARGSUSED */ 687static int 688recv_existing_check(void *arg1, void *arg2, dmu_tx_t *tx) 689{ 690 dsl_dataset_t *ds = arg1; 691 struct recvbeginsyncarg *rbsa = arg2; 692 int err; 693 uint64_t val; 694 | |
695 /* must not have any changes since most recent snapshot */ | 696 /* must not have any changes since most recent snapshot */ |
696 if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds)) | 697 if (!drba->drba_cookie->drc_force && 698 dsl_dataset_modified_since_lastsnap(ds)) |
697 return (ETXTBSY); 698 | 699 return (ETXTBSY); 700 |
701 /* temporary clone name must not exist */ 702 error = zap_lookup(dp->dp_meta_objset, 703 ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name, 704 8, 1, &val); 705 if (error != ENOENT) 706 return (error == 0 ? EBUSY : error); 707 |
|
699 /* new snapshot name must not exist */ | 708 /* new snapshot name must not exist */ |
700 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 701 ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val); 702 if (err == 0) 703 return (EEXIST); 704 if (err != ENOENT) 705 return (err); | 709 error = zap_lookup(dp->dp_meta_objset, 710 ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap, 711 8, 1, &val); 712 if (error != ENOENT) 713 return (error == 0 ? EEXIST : error); |
706 | 714 |
707 if (rbsa->fromguid) { | 715 if (fromguid != 0) { |
708 /* if incremental, most recent snapshot must match fromguid */ 709 if (ds->ds_prev == NULL) 710 return (ENODEV); 711 712 /* 713 * most recent snapshot must match fromguid, or there are no 714 * changes since the fromguid one 715 */ | 716 /* if incremental, most recent snapshot must match fromguid */ 717 if (ds->ds_prev == NULL) 718 return (ENODEV); 719 720 /* 721 * most recent snapshot must match fromguid, or there are no 722 * changes since the fromguid one 723 */ |
716 if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid) { | 724 if (ds->ds_prev->ds_phys->ds_guid != fromguid) { |
717 uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth; 718 uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj; 719 while (obj != 0) { 720 dsl_dataset_t *snap; | 725 uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth; 726 uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj; 727 while (obj != 0) { 728 dsl_dataset_t *snap; |
721 err = dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 722 obj, FTAG, &snap); 723 if (err) | 729 error = dsl_dataset_hold_obj(dp, obj, FTAG, 730 &snap); 731 if (error != 0) |
724 return (ENODEV); 725 if (snap->ds_phys->ds_creation_txg < birth) { 726 dsl_dataset_rele(snap, FTAG); 727 return (ENODEV); 728 } | 732 return (ENODEV); 733 if (snap->ds_phys->ds_creation_txg < birth) { 734 dsl_dataset_rele(snap, FTAG); 735 return (ENODEV); 736 } |
729 if (snap->ds_phys->ds_guid == rbsa->fromguid) { | 737 if (snap->ds_phys->ds_guid == fromguid) { |
730 dsl_dataset_rele(snap, FTAG); 731 break; /* it's ok */ 732 } 733 obj = snap->ds_phys->ds_prev_snap_obj; 734 dsl_dataset_rele(snap, FTAG); 735 } 736 if (obj == 0) 737 return (ENODEV); 738 } 739 } else { 740 /* if full, most recent snapshot must be $ORIGIN */ 741 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 742 return (ENODEV); 743 } 744 | 738 dsl_dataset_rele(snap, FTAG); 739 break; /* it's ok */ 740 } 741 obj = snap->ds_phys->ds_prev_snap_obj; 742 dsl_dataset_rele(snap, FTAG); 743 } 744 if (obj == 0) 745 return (ENODEV); 746 } 747 } else { 748 /* if full, most recent snapshot must be $ORIGIN */ 749 if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 750 return (ENODEV); 751 } 752 |
745 /* temporary clone name must not exist */ 746 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 747 ds->ds_dir->dd_phys->dd_child_dir_zapobj, 748 rbsa->clonelastname, 8, 1, &val); 749 if (err == 0) 750 return (EEXIST); 751 if (err != ENOENT) 752 return (err); 753 | |
754 return (0); | 753 return (0); |
754 |
|
755} 756 | 755} 756 |
757/* ARGSUSED */ | 757static int 758dmu_recv_begin_check(void *arg, dmu_tx_t *tx) 759{ 760 dmu_recv_begin_arg_t *drba = arg; 761 dsl_pool_t *dp = dmu_tx_pool(tx); 762 struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 763 uint64_t fromguid = drrb->drr_fromguid; 764 int flags = drrb->drr_flags; 765 int error; 766 dsl_dataset_t *ds; 767 const char *tofs = drba->drba_cookie->drc_tofs; 768 769 /* already checked */ 770 ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 771 772 if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == 773 DMU_COMPOUNDSTREAM || 774 drrb->drr_type >= DMU_OST_NUMTYPES || 775 ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) 776 return (EINVAL); 777 778 /* Verify pool version supports SA if SA_SPILL feature set */ 779 if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) & 780 DMU_BACKUP_FEATURE_SA_SPILL) && 781 spa_version(dp->dp_spa) < SPA_VERSION_SA) { 782 return (ENOTSUP); 783 } 784 785 error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 786 if (error == 0) { 787 /* target fs already exists; recv into temp clone */ 788 789 /* Can't recv a clone into an existing fs */ 790 if (flags & DRR_FLAG_CLONE) { 791 dsl_dataset_rele(ds, FTAG); 792 return (EINVAL); 793 } 794 795 error = recv_begin_check_existing_impl(drba, ds, fromguid); 796 dsl_dataset_rele(ds, FTAG); 797 } else if (error == ENOENT) { 798 /* target fs does not exist; must be a full backup or clone */ 799 char buf[MAXNAMELEN]; 800 801 /* 802 * If it's a non-clone incremental, we are missing the 803 * target fs, so fail the recv. 804 */ 805 if (fromguid != 0 && !(flags & DRR_FLAG_CLONE)) 806 return (ENOENT); 807 808 /* Open the parent of tofs */ 809 ASSERT3U(strlen(tofs), <, MAXNAMELEN); 810 (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1); 811 error = dsl_dataset_hold(dp, buf, FTAG, &ds); 812 if (error != 0) 813 return (error); 814 815 if (drba->drba_origin != NULL) { 816 dsl_dataset_t *origin; 817 error = dsl_dataset_hold(dp, drba->drba_origin, 818 FTAG, &origin); 819 if (error != 0) { 820 dsl_dataset_rele(ds, FTAG); 821 return (error); 822 } 823 if (!dsl_dataset_is_snapshot(origin)) { 824 dsl_dataset_rele(origin, FTAG); 825 dsl_dataset_rele(ds, FTAG); 826 return (EINVAL); 827 } 828 if (origin->ds_phys->ds_guid != fromguid) { 829 dsl_dataset_rele(origin, FTAG); 830 dsl_dataset_rele(ds, FTAG); 831 return (ENODEV); 832 } 833 dsl_dataset_rele(origin, FTAG); 834 } 835 dsl_dataset_rele(ds, FTAG); 836 error = 0; 837 } 838 return (error); 839} 840 |
758static void | 841static void |
759recv_existing_sync(void *arg1, void *arg2, dmu_tx_t *tx) | 842dmu_recv_begin_sync(void *arg, dmu_tx_t *tx) |
760{ | 843{ |
761 dsl_dataset_t *ohds = arg1; 762 struct recvbeginsyncarg *rbsa = arg2; 763 dsl_pool_t *dp = ohds->ds_dir->dd_pool; 764 dsl_dataset_t *cds; 765 uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; | 844 dmu_recv_begin_arg_t *drba = arg; 845 dsl_pool_t *dp = dmu_tx_pool(tx); 846 struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 847 const char *tofs = drba->drba_cookie->drc_tofs; 848 dsl_dataset_t *ds, *newds; |
766 uint64_t dsobj; | 849 uint64_t dsobj; |
850 int error; 851 uint64_t crflags; |
|
767 | 852 |
768 /* create and open the temporary clone */ 769 dsobj = dsl_dataset_create_sync(ohds->ds_dir, rbsa->clonelastname, 770 ohds->ds_prev, flags, rbsa->cr, tx); 771 VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, B_TRUE, dmu_recv_tag, &cds)); | 853 crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ? 854 DS_FLAG_CI_DATASET : 0; |
772 | 855 |
856 error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 857 if (error == 0) { 858 /* create temporary clone */ 859 dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name, 860 ds->ds_prev, crflags, drba->drba_cred, tx); 861 dsl_dataset_rele(ds, FTAG); 862 } else { 863 dsl_dir_t *dd; 864 const char *tail; 865 dsl_dataset_t *origin = NULL; 866 867 VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail)); 868 869 if (drba->drba_origin != NULL) { 870 VERIFY0(dsl_dataset_hold(dp, drba->drba_origin, 871 FTAG, &origin)); 872 } 873 874 /* Create new dataset. */ 875 dsobj = dsl_dataset_create_sync(dd, 876 strrchr(tofs, '/') + 1, 877 origin, crflags, drba->drba_cred, tx); 878 if (origin != NULL) 879 dsl_dataset_rele(origin, FTAG); 880 dsl_dir_rele(dd, FTAG); 881 drba->drba_cookie->drc_newfs = B_TRUE; 882 } 883 VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds)); 884 885 dmu_buf_will_dirty(newds->ds_dbuf, tx); 886 newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 887 |
|
773 /* 774 * If we actually created a non-clone, we need to create the 775 * objset in our new dataset. 776 */ | 888 /* 889 * If we actually created a non-clone, we need to create the 890 * objset in our new dataset. 891 */ |
777 if (BP_IS_HOLE(dsl_dataset_get_blkptr(cds))) { | 892 if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) { |
778 (void) dmu_objset_create_impl(dp->dp_spa, | 893 (void) dmu_objset_create_impl(dp->dp_spa, |
779 cds, dsl_dataset_get_blkptr(cds), rbsa->type, tx); | 894 newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx); |
780 } 781 | 895 } 896 |
782 rbsa->ds = cds; | 897 drba->drba_cookie->drc_ds = newds; |
783 | 898 |
784 spa_history_log_internal(LOG_DS_REPLAY_INC_SYNC, 785 dp->dp_spa, tx, "dataset = %lld", dsobj); | 899 spa_history_log_internal_ds(newds, "receive", tx, ""); |
786} 787 | 900} 901 |
788static boolean_t 789dmu_recv_verify_features(dsl_dataset_t *ds, struct drr_begin *drrb) 790{ 791 int featureflags; 792 793 featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo); 794 795 /* Verify pool version supports SA if SA_SPILL feature set */ 796 return ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) && 797 (spa_version(dsl_dataset_get_spa(ds)) < SPA_VERSION_SA)); 798} 799 | |
800/* 801 * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 802 * succeeds; otherwise we will leak the holds on the datasets. 803 */ 804int | 902/* 903 * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 904 * succeeds; otherwise we will leak the holds on the datasets. 905 */ 906int |
805dmu_recv_begin(char *tofs, char *tosnap, char *top_ds, struct drr_begin *drrb, 806 boolean_t force, objset_t *origin, dmu_recv_cookie_t *drc) | 907dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 908 boolean_t force, char *origin, dmu_recv_cookie_t *drc) |
807{ | 909{ |
808 int err = 0; 809 boolean_t byteswap; 810 struct recvbeginsyncarg rbsa = { 0 }; 811 uint64_t versioninfo; 812 int flags; 813 dsl_dataset_t *ds; | 910 dmu_recv_begin_arg_t drba = { 0 }; 911 dmu_replay_record_t *drr; |
814 | 912 |
815 if (drrb->drr_magic == DMU_BACKUP_MAGIC) 816 byteswap = FALSE; 817 else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 818 byteswap = TRUE; 819 else 820 return (EINVAL); 821 822 rbsa.tofs = tofs; 823 rbsa.tosnap = tosnap; 824 rbsa.origin = origin ? origin->os_dsl_dataset : NULL; 825 rbsa.fromguid = drrb->drr_fromguid; 826 rbsa.type = drrb->drr_type; 827 rbsa.tag = FTAG; 828 rbsa.dsflags = 0; 829 rbsa.cr = CRED(); 830 versioninfo = drrb->drr_versioninfo; 831 flags = drrb->drr_flags; 832 833 if (byteswap) { 834 rbsa.type = BSWAP_32(rbsa.type); 835 rbsa.fromguid = BSWAP_64(rbsa.fromguid); 836 versioninfo = BSWAP_64(versioninfo); 837 flags = BSWAP_32(flags); 838 } 839 840 if (DMU_GET_STREAM_HDRTYPE(versioninfo) == DMU_COMPOUNDSTREAM || 841 rbsa.type >= DMU_OST_NUMTYPES || 842 ((flags & DRR_FLAG_CLONE) && origin == NULL)) 843 return (EINVAL); 844 845 if (flags & DRR_FLAG_CI_DATA) 846 rbsa.dsflags = DS_FLAG_CI_DATASET; 847 | |
848 bzero(drc, sizeof (dmu_recv_cookie_t)); 849 drc->drc_drrb = drrb; 850 drc->drc_tosnap = tosnap; | 913 bzero(drc, sizeof (dmu_recv_cookie_t)); 914 drc->drc_drrb = drrb; 915 drc->drc_tosnap = tosnap; |
851 drc->drc_top_ds = top_ds; | 916 drc->drc_tofs = tofs; |
852 drc->drc_force = force; 853 | 917 drc->drc_force = force; 918 |
854 /* 855 * Process the begin in syncing context. 856 */ | 919 if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 920 drc->drc_byteswap = B_TRUE; 921 else if (drrb->drr_magic != DMU_BACKUP_MAGIC) 922 return (EINVAL); |
857 | 923 |
858 /* open the dataset we are logically receiving into */ 859 err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds); 860 if (err == 0) { 861 if (dmu_recv_verify_features(ds, drrb)) { 862 dsl_dataset_rele(ds, dmu_recv_tag); 863 return (ENOTSUP); 864 } 865 /* target fs already exists; recv into temp clone */ | 924 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 925 drr->drr_type = DRR_BEGIN; 926 drr->drr_u.drr_begin = *drc->drc_drrb; 927 if (drc->drc_byteswap) { 928 fletcher_4_incremental_byteswap(drr, 929 sizeof (dmu_replay_record_t), &drc->drc_cksum); 930 } else { 931 fletcher_4_incremental_native(drr, 932 sizeof (dmu_replay_record_t), &drc->drc_cksum); 933 } 934 kmem_free(drr, sizeof (dmu_replay_record_t)); |
866 | 935 |
867 /* Can't recv a clone into an existing fs */ 868 if (flags & DRR_FLAG_CLONE) { 869 dsl_dataset_rele(ds, dmu_recv_tag); 870 return (EINVAL); 871 } 872 873 /* must not have an incremental recv already in progress */ 874 if (!mutex_tryenter(&ds->ds_recvlock)) { 875 dsl_dataset_rele(ds, dmu_recv_tag); 876 return (EBUSY); 877 } 878 879 /* tmp clone name is: tofs/%tosnap" */ 880 (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname), 881 "%%%s", tosnap); 882 rbsa.force = force; 883 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 884 recv_existing_check, recv_existing_sync, ds, &rbsa, 5); 885 if (err) { 886 mutex_exit(&ds->ds_recvlock); 887 dsl_dataset_rele(ds, dmu_recv_tag); 888 return (err); 889 } 890 drc->drc_logical_ds = ds; 891 drc->drc_real_ds = rbsa.ds; 892 } else if (err == ENOENT) { 893 /* target fs does not exist; must be a full backup or clone */ 894 char *cp; 895 896 /* 897 * If it's a non-clone incremental, we are missing the 898 * target fs, so fail the recv. 899 */ 900 if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) 901 return (ENOENT); 902 903 /* Open the parent of tofs */ 904 cp = strrchr(tofs, '/'); 905 *cp = '\0'; 906 err = dsl_dataset_hold(tofs, FTAG, &ds); 907 *cp = '/'; 908 if (err) 909 return (err); 910 911 if (dmu_recv_verify_features(ds, drrb)) { 912 dsl_dataset_rele(ds, FTAG); 913 return (ENOTSUP); 914 } 915 916 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 917 recv_new_check, recv_new_sync, ds->ds_dir, &rbsa, 5); 918 dsl_dataset_rele(ds, FTAG); 919 if (err) 920 return (err); 921 drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds; 922 drc->drc_newfs = B_TRUE; | 936 if (drc->drc_byteswap) { 937 drrb->drr_magic = BSWAP_64(drrb->drr_magic); 938 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 939 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 940 drrb->drr_type = BSWAP_32(drrb->drr_type); 941 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 942 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); |
923 } 924 | 943 } 944 |
925 return (err); | 945 drba.drba_origin = origin; 946 drba.drba_cookie = drc; 947 drba.drba_cred = CRED(); 948 949 return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync, 950 &drba, 5)); |
926} 927 928struct restorearg { 929 int err; | 951} 952 953struct restorearg { 954 int err; |
930 int byteswap; | 955 boolean_t byteswap; |
931 kthread_t *td; 932 struct file *fp; 933 char *buf; 934 uint64_t voff; 935 int bufsize; /* amount of memory allocated for buf */ 936 zio_cksum_t cksum; 937 avl_tree_t *guid_to_ds_map; 938}; --- 20 unchanged lines hidden (view full) --- 959static void 960free_guid_map_onexit(void *arg) 961{ 962 avl_tree_t *ca = arg; 963 void *cookie = NULL; 964 guid_map_entry_t *gmep; 965 966 while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { | 956 kthread_t *td; 957 struct file *fp; 958 char *buf; 959 uint64_t voff; 960 int bufsize; /* amount of memory allocated for buf */ 961 zio_cksum_t cksum; 962 avl_tree_t *guid_to_ds_map; 963}; --- 20 unchanged lines hidden (view full) --- 984static void 985free_guid_map_onexit(void *arg) 986{ 987 avl_tree_t *ca = arg; 988 void *cookie = NULL; 989 guid_map_entry_t *gmep; 990 991 while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { |
967 dsl_dataset_rele(gmep->gme_ds, ca); | 992 dsl_dataset_long_rele(gmep->gme_ds, gmep); |
968 kmem_free(gmep, sizeof (guid_map_entry_t)); 969 } 970 avl_destroy(ca); 971 kmem_free(ca, sizeof (avl_tree_t)); 972} 973 974static int 975restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, ssize_t *resid) --- 35 unchanged lines hidden (view full) --- 1011 1012 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done, 1013 len - done, ra->voff, &resid); 1014 1015 if (resid == len - done) 1016 ra->err = EINVAL; 1017 ra->voff += len - done - resid; 1018 done = len - resid; | 993 kmem_free(gmep, sizeof (guid_map_entry_t)); 994 } 995 avl_destroy(ca); 996 kmem_free(ca, sizeof (avl_tree_t)); 997} 998 999static int 1000restore_bytes(struct restorearg *ra, void *buf, int len, off_t off, ssize_t *resid) --- 35 unchanged lines hidden (view full) --- 1036 1037 ra->err = restore_bytes(ra, (caddr_t)ra->buf + done, 1038 len - done, ra->voff, &resid); 1039 1040 if (resid == len - done) 1041 ra->err = EINVAL; 1042 ra->voff += len - done - resid; 1043 done = len - resid; |
1019 if (ra->err) | 1044 if (ra->err != 0) |
1020 return (NULL); 1021 } 1022 1023 ASSERT3U(done, ==, len); 1024 rv = ra->buf; 1025 if (ra->byteswap) 1026 fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 1027 else --- 102 unchanged lines hidden (view full) --- 1130 1131 err = dmu_object_info(os, drro->drr_object, NULL); 1132 1133 if (err != 0 && err != ENOENT) 1134 return (EINVAL); 1135 1136 if (drro->drr_bonuslen) { 1137 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); | 1045 return (NULL); 1046 } 1047 1048 ASSERT3U(done, ==, len); 1049 rv = ra->buf; 1050 if (ra->byteswap) 1051 fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 1052 else --- 102 unchanged lines hidden (view full) --- 1155 1156 err = dmu_object_info(os, drro->drr_object, NULL); 1157 1158 if (err != 0 && err != ENOENT) 1159 return (EINVAL); 1160 1161 if (drro->drr_bonuslen) { 1162 data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); |
1138 if (ra->err) | 1163 if (ra->err != 0) |
1139 return (ra->err); 1140 } 1141 1142 if (err == ENOENT) { 1143 /* currently free, want to be allocated */ 1144 tx = dmu_tx_create(os); 1145 dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1146 err = dmu_tx_assign(tx, TXG_WAIT); | 1164 return (ra->err); 1165 } 1166 1167 if (err == ENOENT) { 1168 /* currently free, want to be allocated */ 1169 tx = dmu_tx_create(os); 1170 dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1171 err = dmu_tx_assign(tx, TXG_WAIT); |
1147 if (err) { | 1172 if (err != 0) { |
1148 dmu_tx_abort(tx); 1149 return (err); 1150 } 1151 err = dmu_object_claim(os, drro->drr_object, 1152 drro->drr_type, drro->drr_blksz, 1153 drro->drr_bonustype, drro->drr_bonuslen, tx); 1154 dmu_tx_commit(tx); 1155 } else { 1156 /* currently allocated, want to be allocated */ 1157 err = dmu_object_reclaim(os, drro->drr_object, 1158 drro->drr_type, drro->drr_blksz, 1159 drro->drr_bonustype, drro->drr_bonuslen); 1160 } | 1173 dmu_tx_abort(tx); 1174 return (err); 1175 } 1176 err = dmu_object_claim(os, drro->drr_object, 1177 drro->drr_type, drro->drr_blksz, 1178 drro->drr_bonustype, drro->drr_bonuslen, tx); 1179 dmu_tx_commit(tx); 1180 } else { 1181 /* currently allocated, want to be allocated */ 1182 err = dmu_object_reclaim(os, drro->drr_object, 1183 drro->drr_type, drro->drr_blksz, 1184 drro->drr_bonustype, drro->drr_bonuslen); 1185 } |
1161 if (err) { | 1186 if (err != 0) { |
1162 return (EINVAL); 1163 } 1164 1165 tx = dmu_tx_create(os); 1166 dmu_tx_hold_bonus(tx, drro->drr_object); 1167 err = dmu_tx_assign(tx, TXG_WAIT); | 1187 return (EINVAL); 1188 } 1189 1190 tx = dmu_tx_create(os); 1191 dmu_tx_hold_bonus(tx, drro->drr_object); 1192 err = dmu_tx_assign(tx, TXG_WAIT); |
1168 if (err) { | 1193 if (err != 0) { |
1169 dmu_tx_abort(tx); 1170 return (err); 1171 } 1172 1173 dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 1174 tx); 1175 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1176 --- 31 unchanged lines hidden (view full) --- 1208 obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1209 (void) dmu_object_next(os, &obj, FALSE, 0)) { 1210 int err; 1211 1212 if (dmu_object_info(os, obj, NULL) != 0) 1213 continue; 1214 1215 err = dmu_free_object(os, obj); | 1194 dmu_tx_abort(tx); 1195 return (err); 1196 } 1197 1198 dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 1199 tx); 1200 dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1201 --- 31 unchanged lines hidden (view full) --- 1233 obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1234 (void) dmu_object_next(os, &obj, FALSE, 0)) { 1235 int err; 1236 1237 if (dmu_object_info(os, obj, NULL) != 0) 1238 continue; 1239 1240 err = dmu_free_object(os, obj); |
1216 if (err) | 1241 if (err != 0) |
1217 return (err); 1218 } 1219 return (0); 1220} 1221 1222static int 1223restore_write(struct restorearg *ra, objset_t *os, 1224 struct drr_write *drrw) --- 13 unchanged lines hidden (view full) --- 1238 if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1239 return (EINVAL); 1240 1241 tx = dmu_tx_create(os); 1242 1243 dmu_tx_hold_write(tx, drrw->drr_object, 1244 drrw->drr_offset, drrw->drr_length); 1245 err = dmu_tx_assign(tx, TXG_WAIT); | 1242 return (err); 1243 } 1244 return (0); 1245} 1246 1247static int 1248restore_write(struct restorearg *ra, objset_t *os, 1249 struct drr_write *drrw) --- 13 unchanged lines hidden (view full) --- 1263 if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1264 return (EINVAL); 1265 1266 tx = dmu_tx_create(os); 1267 1268 dmu_tx_hold_write(tx, drrw->drr_object, 1269 drrw->drr_offset, drrw->drr_length); 1270 err = dmu_tx_assign(tx, TXG_WAIT); |
1246 if (err) { | 1271 if (err != 0) { |
1247 dmu_tx_abort(tx); 1248 return (err); 1249 } 1250 if (ra->byteswap) { 1251 dmu_object_byteswap_t byteswap = 1252 DMU_OT_BYTESWAP(drrw->drr_type); 1253 dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1254 } --- 45 unchanged lines hidden (view full) --- 1300 drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH)) 1301 return (err); 1302 1303 tx = dmu_tx_create(os); 1304 1305 dmu_tx_hold_write(tx, drrwbr->drr_object, 1306 drrwbr->drr_offset, drrwbr->drr_length); 1307 err = dmu_tx_assign(tx, TXG_WAIT); | 1272 dmu_tx_abort(tx); 1273 return (err); 1274 } 1275 if (ra->byteswap) { 1276 dmu_object_byteswap_t byteswap = 1277 DMU_OT_BYTESWAP(drrw->drr_type); 1278 dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1279 } --- 45 unchanged lines hidden (view full) --- 1325 drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH)) 1326 return (err); 1327 1328 tx = dmu_tx_create(os); 1329 1330 dmu_tx_hold_write(tx, drrwbr->drr_object, 1331 drrwbr->drr_offset, drrwbr->drr_length); 1332 err = dmu_tx_assign(tx, TXG_WAIT); |
1308 if (err) { | 1333 if (err != 0) { |
1309 dmu_tx_abort(tx); 1310 return (err); 1311 } 1312 dmu_write(os, drrwbr->drr_object, 1313 drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 1314 dmu_buf_rele(dbp, FTAG); 1315 dmu_tx_commit(tx); 1316 return (0); --- 24 unchanged lines hidden (view full) --- 1341 return (err); 1342 } 1343 1344 tx = dmu_tx_create(os); 1345 1346 dmu_tx_hold_spill(tx, db->db_object); 1347 1348 err = dmu_tx_assign(tx, TXG_WAIT); | 1334 dmu_tx_abort(tx); 1335 return (err); 1336 } 1337 dmu_write(os, drrwbr->drr_object, 1338 drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 1339 dmu_buf_rele(dbp, FTAG); 1340 dmu_tx_commit(tx); 1341 return (0); --- 24 unchanged lines hidden (view full) --- 1366 return (err); 1367 } 1368 1369 tx = dmu_tx_create(os); 1370 1371 dmu_tx_hold_spill(tx, db->db_object); 1372 1373 err = dmu_tx_assign(tx, TXG_WAIT); |
1349 if (err) { | 1374 if (err != 0) { |
1350 dmu_buf_rele(db, FTAG); 1351 dmu_buf_rele(db_spill, FTAG); 1352 dmu_tx_abort(tx); 1353 return (err); 1354 } 1355 dmu_buf_will_dirty(db_spill, tx); 1356 1357 if (db_spill->db_size < drrs->drr_length) --- 22 unchanged lines hidden (view full) --- 1380 if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1381 return (EINVAL); 1382 1383 err = dmu_free_long_range(os, drrf->drr_object, 1384 drrf->drr_offset, drrf->drr_length); 1385 return (err); 1386} 1387 | 1375 dmu_buf_rele(db, FTAG); 1376 dmu_buf_rele(db_spill, FTAG); 1377 dmu_tx_abort(tx); 1378 return (err); 1379 } 1380 dmu_buf_will_dirty(db_spill, tx); 1381 1382 if (db_spill->db_size < drrs->drr_length) --- 22 unchanged lines hidden (view full) --- 1405 if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1406 return (EINVAL); 1407 1408 err = dmu_free_long_range(os, drrf->drr_object, 1409 drrf->drr_offset, drrf->drr_length); 1410 return (err); 1411} 1412 |
1413/* used to destroy the drc_ds on error */ 1414static void 1415dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) 1416{ 1417 char name[MAXNAMELEN]; 1418 dsl_dataset_name(drc->drc_ds, name); 1419 dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 1420 (void) dsl_destroy_head(name); 1421} 1422 |
|
1388/* 1389 * NB: callers *must* call dmu_recv_end() if this succeeds. 1390 */ 1391int 1392dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp, 1393 int cleanup_fd, uint64_t *action_handlep) 1394{ 1395 struct restorearg ra = { 0 }; 1396 dmu_replay_record_t *drr; 1397 objset_t *os; 1398 zio_cksum_t pcksum; 1399 int featureflags; 1400 | 1423/* 1424 * NB: callers *must* call dmu_recv_end() if this succeeds. 1425 */ 1426int 1427dmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp, 1428 int cleanup_fd, uint64_t *action_handlep) 1429{ 1430 struct restorearg ra = { 0 }; 1431 dmu_replay_record_t *drr; 1432 objset_t *os; 1433 zio_cksum_t pcksum; 1434 int featureflags; 1435 |
1401 if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 1402 ra.byteswap = TRUE; 1403 1404 { 1405 /* compute checksum of drr_begin record */ 1406 dmu_replay_record_t *drr; 1407 drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 1408 1409 drr->drr_type = DRR_BEGIN; 1410 drr->drr_u.drr_begin = *drc->drc_drrb; 1411 if (ra.byteswap) { 1412 fletcher_4_incremental_byteswap(drr, 1413 sizeof (dmu_replay_record_t), &ra.cksum); 1414 } else { 1415 fletcher_4_incremental_native(drr, 1416 sizeof (dmu_replay_record_t), &ra.cksum); 1417 } 1418 kmem_free(drr, sizeof (dmu_replay_record_t)); 1419 } 1420 1421 if (ra.byteswap) { 1422 struct drr_begin *drrb = drc->drc_drrb; 1423 drrb->drr_magic = BSWAP_64(drrb->drr_magic); 1424 drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 1425 drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 1426 drrb->drr_type = BSWAP_32(drrb->drr_type); 1427 drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 1428 drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 1429 } 1430 | 1436 ra.byteswap = drc->drc_byteswap; 1437 ra.cksum = drc->drc_cksum; |
1431 ra.td = curthread; 1432 ra.fp = fp; 1433 ra.voff = *voffp; 1434 ra.bufsize = 1<<20; 1435 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1436 1437 /* these were verified in dmu_recv_begin */ | 1438 ra.td = curthread; 1439 ra.fp = fp; 1440 ra.voff = *voffp; 1441 ra.bufsize = 1<<20; 1442 ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1443 1444 /* these were verified in dmu_recv_begin */ |
1438 ASSERT(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo) == | 1445 ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==, |
1439 DMU_SUBSTREAM); | 1446 DMU_SUBSTREAM); |
1440 ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES); | 1447 ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES); |
1441 1442 /* 1443 * Open the objset we are modifying. 1444 */ | 1448 1449 /* 1450 * Open the objset we are modifying. 1451 */ |
1445 VERIFY(dmu_objset_from_ds(drc->drc_real_ds, &os) == 0); | 1452 VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os)); |
1446 | 1453 |
1447 ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); | 1454 ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); |
1448 1449 featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 1450 1451 /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 1452 if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1453 minor_t minor; 1454 1455 if (cleanup_fd == -1) { 1456 ra.err = EBADF; 1457 goto out; 1458 } 1459 ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); | 1455 1456 featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 1457 1458 /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 1459 if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1460 minor_t minor; 1461 1462 if (cleanup_fd == -1) { 1463 ra.err = EBADF; 1464 goto out; 1465 } 1466 ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); |
1460 if (ra.err) { | 1467 if (ra.err != 0) { |
1461 cleanup_fd = -1; 1462 goto out; 1463 } 1464 1465 if (*action_handlep == 0) { 1466 ra.guid_to_ds_map = 1467 kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1468 avl_create(ra.guid_to_ds_map, guid_compare, 1469 sizeof (guid_map_entry_t), 1470 offsetof(guid_map_entry_t, avlnode)); 1471 ra.err = zfs_onexit_add_cb(minor, 1472 free_guid_map_onexit, ra.guid_to_ds_map, 1473 action_handlep); | 1468 cleanup_fd = -1; 1469 goto out; 1470 } 1471 1472 if (*action_handlep == 0) { 1473 ra.guid_to_ds_map = 1474 kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1475 avl_create(ra.guid_to_ds_map, guid_compare, 1476 sizeof (guid_map_entry_t), 1477 offsetof(guid_map_entry_t, avlnode)); 1478 ra.err = zfs_onexit_add_cb(minor, 1479 free_guid_map_onexit, ra.guid_to_ds_map, 1480 action_handlep); |
1474 if (ra.err) | 1481 if (ra.err != 0) |
1475 goto out; 1476 } else { 1477 ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1478 (void **)&ra.guid_to_ds_map); | 1482 goto out; 1483 } else { 1484 ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1485 (void **)&ra.guid_to_ds_map); |
1479 if (ra.err) | 1486 if (ra.err != 0) |
1480 goto out; 1481 } 1482 1483 drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 1484 } 1485 1486 /* 1487 * Read records and process them. --- 77 unchanged lines hidden (view full) --- 1565 if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1566 zfs_onexit_fd_rele(cleanup_fd); 1567 1568 if (ra.err != 0) { 1569 /* 1570 * destroy what we created, so we don't leave it in the 1571 * inconsistent restoring state. 1572 */ | 1487 goto out; 1488 } 1489 1490 drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 1491 } 1492 1493 /* 1494 * Read records and process them. --- 77 unchanged lines hidden (view full) --- 1572 if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1573 zfs_onexit_fd_rele(cleanup_fd); 1574 1575 if (ra.err != 0) { 1576 /* 1577 * destroy what we created, so we don't leave it in the 1578 * inconsistent restoring state. 1579 */ |
1573 txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0); 1574 1575 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, 1576 B_FALSE); 1577 if (drc->drc_real_ds != drc->drc_logical_ds) { 1578 mutex_exit(&drc->drc_logical_ds->ds_recvlock); 1579 dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag); 1580 } | 1580 dmu_recv_cleanup_ds(drc); |
1581 } 1582 1583 kmem_free(ra.buf, ra.bufsize); 1584 *voffp = ra.voff; 1585 return (ra.err); 1586} 1587 | 1581 } 1582 1583 kmem_free(ra.buf, ra.bufsize); 1584 *voffp = ra.voff; 1585 return (ra.err); 1586} 1587 |
1588struct recvendsyncarg { 1589 char *tosnap; 1590 uint64_t creation_time; 1591 uint64_t toguid; 1592}; 1593 | |
1594static int | 1588static int |
1595recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx) | 1589dmu_recv_end_check(void *arg, dmu_tx_t *tx) |
1596{ | 1590{ |
1597 dsl_dataset_t *ds = arg1; 1598 struct recvendsyncarg *resa = arg2; | 1591 dmu_recv_cookie_t *drc = arg; 1592 dsl_pool_t *dp = dmu_tx_pool(tx); 1593 int error; |
1599 | 1594 |
1600 return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx)); | 1595 ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag); 1596 1597 if (!drc->drc_newfs) { 1598 dsl_dataset_t *origin_head; 1599 1600 error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head); 1601 if (error != 0) 1602 return (error); 1603 error = dsl_dataset_clone_swap_check_impl(drc->drc_ds, 1604 origin_head, drc->drc_force); 1605 if (error != 0) { 1606 dsl_dataset_rele(origin_head, FTAG); 1607 return (error); 1608 } 1609 error = dsl_dataset_snapshot_check_impl(origin_head, 1610 drc->drc_tosnap, tx); 1611 dsl_dataset_rele(origin_head, FTAG); 1612 if (error != 0) 1613 return (error); 1614 1615 error = dsl_destroy_head_check_impl(drc->drc_ds, 1); 1616 } else { 1617 error = dsl_dataset_snapshot_check_impl(drc->drc_ds, 1618 drc->drc_tosnap, tx); 1619 } 1620 return (error); |
1601} 1602 1603static void | 1621} 1622 1623static void |
1604recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx) | 1624dmu_recv_end_sync(void *arg, dmu_tx_t *tx) |
1605{ | 1625{ |
1606 dsl_dataset_t *ds = arg1; 1607 struct recvendsyncarg *resa = arg2; | 1626 dmu_recv_cookie_t *drc = arg; 1627 dsl_pool_t *dp = dmu_tx_pool(tx); |
1608 | 1628 |
1609 dsl_dataset_snapshot_sync(ds, resa->tosnap, tx); | 1629 spa_history_log_internal_ds(drc->drc_ds, "finish receiving", 1630 tx, "snap=%s", drc->drc_tosnap); |
1610 | 1631 |
1611 /* set snapshot's creation time and guid */ 1612 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1613 ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time; 1614 ds->ds_prev->ds_phys->ds_guid = resa->toguid; 1615 ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; | 1632 if (!drc->drc_newfs) { 1633 dsl_dataset_t *origin_head; |
1616 | 1634 |
1617 dmu_buf_will_dirty(ds->ds_dbuf, tx); 1618 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; | 1635 VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG, 1636 &origin_head)); 1637 dsl_dataset_clone_swap_sync_impl(drc->drc_ds, 1638 origin_head, tx); 1639 dsl_dataset_snapshot_sync_impl(origin_head, 1640 drc->drc_tosnap, tx); 1641 1642 /* set snapshot's creation time and guid */ 1643 dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx); 1644 origin_head->ds_prev->ds_phys->ds_creation_time = 1645 drc->drc_drrb->drr_creation_time; 1646 origin_head->ds_prev->ds_phys->ds_guid = 1647 drc->drc_drrb->drr_toguid; 1648 origin_head->ds_prev->ds_phys->ds_flags &= 1649 ~DS_FLAG_INCONSISTENT; 1650 1651 dmu_buf_will_dirty(origin_head->ds_dbuf, tx); 1652 origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1653 1654 dsl_dataset_rele(origin_head, FTAG); 1655 dsl_destroy_head_sync_impl(drc->drc_ds, tx); 1656 } else { 1657 dsl_dataset_t *ds = drc->drc_ds; 1658 1659 dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx); 1660 1661 /* set snapshot's creation time and guid */ 1662 dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1663 ds->ds_prev->ds_phys->ds_creation_time = 1664 drc->drc_drrb->drr_creation_time; 1665 ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid; 1666 ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1667 1668 dmu_buf_will_dirty(ds->ds_dbuf, tx); 1669 ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1670 } 1671 drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj; 1672 /* 1673 * Release the hold from dmu_recv_begin. This must be done before 1674 * we return to open context, so that when we free the dataset's dnode, 1675 * we can evict its bonus buffer. 1676 */ 1677 dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 1678 drc->drc_ds = NULL; |
1619} 1620 1621static int | 1679} 1680 1681static int |
1622add_ds_to_guidmap(avl_tree_t *guid_map, dsl_dataset_t *ds) | 1682add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj) |
1623{ | 1683{ |
1624 dsl_pool_t *dp = ds->ds_dir->dd_pool; 1625 uint64_t snapobj = ds->ds_phys->ds_prev_snap_obj; | 1684 dsl_pool_t *dp; |
1626 dsl_dataset_t *snapds; 1627 guid_map_entry_t *gmep; 1628 int err; 1629 1630 ASSERT(guid_map != NULL); 1631 | 1685 dsl_dataset_t *snapds; 1686 guid_map_entry_t *gmep; 1687 int err; 1688 1689 ASSERT(guid_map != NULL); 1690 |
1632 rw_enter(&dp->dp_config_rwlock, RW_READER); 1633 err = dsl_dataset_hold_obj(dp, snapobj, guid_map, &snapds); | 1691 err = dsl_pool_hold(name, FTAG, &dp); 1692 if (err != 0) 1693 return (err); 1694 err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snapds); |
1634 if (err == 0) { 1635 gmep = kmem_alloc(sizeof (guid_map_entry_t), KM_SLEEP); 1636 gmep->guid = snapds->ds_phys->ds_guid; 1637 gmep->gme_ds = snapds; 1638 avl_add(guid_map, gmep); | 1695 if (err == 0) { 1696 gmep = kmem_alloc(sizeof (guid_map_entry_t), KM_SLEEP); 1697 gmep->guid = snapds->ds_phys->ds_guid; 1698 gmep->gme_ds = snapds; 1699 avl_add(guid_map, gmep); |
1700 dsl_dataset_long_hold(snapds, gmep); 1701 dsl_dataset_rele(snapds, FTAG); |
|
1639 } 1640 | 1702 } 1703 |
1641 rw_exit(&dp->dp_config_rwlock); | 1704 dsl_pool_rele(dp, FTAG); |
1642 return (err); 1643} 1644 | 1705 return (err); 1706} 1707 |
1708static int dmu_recv_end_modified_blocks = 3; 1709 |
|
1645static int 1646dmu_recv_existing_end(dmu_recv_cookie_t *drc) 1647{ | 1710static int 1711dmu_recv_existing_end(dmu_recv_cookie_t *drc) 1712{ |
1648 struct recvendsyncarg resa; 1649 dsl_dataset_t *ds = drc->drc_logical_ds; 1650 int err, myerr; | 1713 int error; 1714 char name[MAXNAMELEN]; |
1651 | 1715 |
1652 if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) { 1653 err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, 1654 drc->drc_force); 1655 if (err) 1656 goto out; 1657 } else { 1658 mutex_exit(&ds->ds_recvlock); 1659 dsl_dataset_rele(ds, dmu_recv_tag); 1660 (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, 1661 B_FALSE); 1662 return (EBUSY); 1663 } | 1716#ifdef _KERNEL 1717 /* 1718 * We will be destroying the ds; make sure its origin is unmounted if 1719 * necessary. 1720 */ 1721 dsl_dataset_name(drc->drc_ds, name); 1722 zfs_destroy_unmount_origin(name); 1723#endif |
1664 | 1724 |
1665 resa.creation_time = drc->drc_drrb->drr_creation_time; 1666 resa.toguid = drc->drc_drrb->drr_toguid; 1667 resa.tosnap = drc->drc_tosnap; | 1725 error = dsl_sync_task(drc->drc_tofs, 1726 dmu_recv_end_check, dmu_recv_end_sync, drc, 1727 dmu_recv_end_modified_blocks); |
1668 | 1728 |
1669 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1670 recv_end_check, recv_end_sync, ds, &resa, 3); 1671 if (err) { 1672 /* swap back */ 1673 (void) dsl_dataset_clone_swap(drc->drc_real_ds, ds, B_TRUE); 1674 } 1675 1676out: 1677 mutex_exit(&ds->ds_recvlock); 1678 if (err == 0 && drc->drc_guid_to_ds_map != NULL) 1679 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds); 1680 dsl_dataset_disown(ds, dmu_recv_tag); 1681 myerr = dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE); 1682 ASSERT0(myerr); 1683 return (err); | 1729 if (error != 0) 1730 dmu_recv_cleanup_ds(drc); 1731 return (error); |
1684} 1685 1686static int 1687dmu_recv_new_end(dmu_recv_cookie_t *drc) 1688{ | 1732} 1733 1734static int 1735dmu_recv_new_end(dmu_recv_cookie_t *drc) 1736{ |
1689 struct recvendsyncarg resa; 1690 dsl_dataset_t *ds = drc->drc_logical_ds; 1691 int err; | 1737 int error; |
1692 | 1738 |
1693 /* 1694 * XXX hack; seems the ds is still dirty and dsl_pool_zil_clean() 1695 * expects it to have a ds_user_ptr (and zil), but clone_swap() 1696 * can close it. 1697 */ 1698 txg_wait_synced(ds->ds_dir->dd_pool, 0); | 1739 error = dsl_sync_task(drc->drc_tofs, 1740 dmu_recv_end_check, dmu_recv_end_sync, drc, 1741 dmu_recv_end_modified_blocks); |
1699 | 1742 |
1700 resa.creation_time = drc->drc_drrb->drr_creation_time; 1701 resa.toguid = drc->drc_drrb->drr_toguid; 1702 resa.tosnap = drc->drc_tosnap; 1703 1704 err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1705 recv_end_check, recv_end_sync, ds, &resa, 3); 1706 if (err) { 1707 /* clean up the fs we just recv'd into */ 1708 (void) dsl_dataset_destroy(ds, dmu_recv_tag, B_FALSE); 1709 } else { 1710 if (drc->drc_guid_to_ds_map != NULL) 1711 (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds); 1712 /* release the hold from dmu_recv_begin */ 1713 dsl_dataset_disown(ds, dmu_recv_tag); | 1743 if (error != 0) { 1744 dmu_recv_cleanup_ds(drc); 1745 } else if (drc->drc_guid_to_ds_map != NULL) { 1746 (void) add_ds_to_guidmap(drc->drc_tofs, 1747 drc->drc_guid_to_ds_map, 1748 drc->drc_newsnapobj); |
1714 } | 1749 } |
1715 return (err); | 1750 return (error); |
1716} 1717 1718int 1719dmu_recv_end(dmu_recv_cookie_t *drc) 1720{ | 1751} 1752 1753int 1754dmu_recv_end(dmu_recv_cookie_t *drc) 1755{ |
1721 if (drc->drc_logical_ds != drc->drc_real_ds) 1722 return (dmu_recv_existing_end(drc)); 1723 else | 1756 if (drc->drc_newfs) |
1724 return (dmu_recv_new_end(drc)); | 1757 return (dmu_recv_new_end(drc)); |
1758 else 1759 return (dmu_recv_existing_end(drc)); |
|
1725} | 1760} |