1efb80947Sahrens /* 2efb80947Sahrens * CDDL HEADER START 3efb80947Sahrens * 4efb80947Sahrens * The contents of this file are subject to the terms of the 5efb80947Sahrens * Common Development and Distribution License (the "License"). 6efb80947Sahrens * You may not use this file except in compliance with the License. 7efb80947Sahrens * 8efb80947Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9efb80947Sahrens * or http://www.opensolaris.org/os/licensing. 10efb80947Sahrens * See the License for the specific language governing permissions 11efb80947Sahrens * and limitations under the License. 12efb80947Sahrens * 13efb80947Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14efb80947Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15efb80947Sahrens * If applicable, add the following below this CDDL HEADER, with the 16efb80947Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17efb80947Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18efb80947Sahrens * 19efb80947Sahrens * CDDL HEADER END 20efb80947Sahrens */ 21efb80947Sahrens /* 22dc7cd546SMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23ec5cf9d5SAlexander Stetsenko * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24ad135b5dSChristopher Siden * Copyright (c) 2012 by Delphix. All rights reserved. 254e3c9f44SBill Pijewski * Copyright (c) 2012, Joyent, Inc. All rights reserved. 26ec5cf9d5SAlexander Stetsenko */ 27efb80947Sahrens 28efb80947Sahrens #include <sys/dmu.h> 29efb80947Sahrens #include <sys/dmu_impl.h> 30efb80947Sahrens #include <sys/dmu_tx.h> 31efb80947Sahrens #include <sys/dbuf.h> 32efb80947Sahrens #include <sys/dnode.h> 33efb80947Sahrens #include <sys/zfs_context.h> 34efb80947Sahrens #include <sys/dmu_objset.h> 35efb80947Sahrens #include <sys/dmu_traverse.h> 36efb80947Sahrens #include <sys/dsl_dataset.h> 37efb80947Sahrens #include <sys/dsl_dir.h> 3892241e0bSTom Erickson #include <sys/dsl_prop.h> 39efb80947Sahrens #include <sys/dsl_pool.h> 40efb80947Sahrens #include <sys/dsl_synctask.h> 41efb80947Sahrens #include <sys/zfs_ioctl.h> 42efb80947Sahrens #include <sys/zap.h> 43efb80947Sahrens #include <sys/zio_checksum.h> 44dc7cd546SMark Shellenbaum #include <sys/zfs_znode.h> 45cde58dbcSMatthew Ahrens #include <zfs_fletcher.h> 469e69d7d0SLori Alt #include <sys/avl.h> 478e714474SLori Alt #include <sys/ddt.h> 48c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 49*3b2aab18SMatthew Ahrens #include <sys/dmu_send.h> 50*3b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 51efb80947Sahrens 5219b94df9SMatthew Ahrens /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 5319b94df9SMatthew Ahrens int zfs_send_corrupt_data = B_FALSE; 5419b94df9SMatthew Ahrens 553cb34c60Sahrens static char *dmu_recv_tag = "dmu_recv_tag"; 56*3b2aab18SMatthew Ahrens static const char *recv_clone_name = "%recv"; 573cb34c60Sahrens 58efb80947Sahrens static int 594e3c9f44SBill Pijewski dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 60efb80947Sahrens { 614e3c9f44SBill Pijewski dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 62efb80947Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 63fb09f5aaSMadhav Suresh ASSERT0(len % 8); 64efb80947Sahrens 654e3c9f44SBill Pijewski fletcher_4_incremental_native(buf, len, &dsp->dsa_zc); 664e3c9f44SBill Pijewski dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp, 67efb80947Sahrens (caddr_t)buf, len, 68efb80947Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 694e3c9f44SBill Pijewski 704e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 714e3c9f44SBill Pijewski *dsp->dsa_off += len; 724e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 734e3c9f44SBill Pijewski 744e3c9f44SBill Pijewski return (dsp->dsa_err); 75efb80947Sahrens } 76efb80947Sahrens 77efb80947Sahrens static int 784e3c9f44SBill Pijewski dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 79efb80947Sahrens uint64_t length) 80efb80947Sahrens { 814e3c9f44SBill Pijewski struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free); 829e69d7d0SLori Alt 83534029e5SSimon Klinkert if (length != -1ULL && offset + length < offset) 84534029e5SSimon Klinkert length = -1ULL; 85534029e5SSimon Klinkert 869e69d7d0SLori Alt /* 879e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREE, push it out, 889e69d7d0SLori Alt * since free block aggregation can only be done for blocks of the 899e69d7d0SLori Alt * same type (i.e., DRR_FREE records can only be aggregated with 909e69d7d0SLori Alt * other DRR_FREE records. DRR_FREEOBJECTS records can only be 919e69d7d0SLori Alt * aggregated with other DRR_FREEOBJECTS records. 929e69d7d0SLori Alt */ 934e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 944e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREE) { 954e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 964e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 979e69d7d0SLori Alt return (EINTR); 984e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 999e69d7d0SLori Alt } 1009e69d7d0SLori Alt 1014e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREE) { 1029e69d7d0SLori Alt /* 1039e69d7d0SLori Alt * There should never be a PENDING_FREE if length is -1 1049e69d7d0SLori Alt * (because dump_dnode is the only place where this 1059e69d7d0SLori Alt * function is called with a -1, and only after flushing 1069e69d7d0SLori Alt * any pending record). 1079e69d7d0SLori Alt */ 1089e69d7d0SLori Alt ASSERT(length != -1ULL); 1099e69d7d0SLori Alt /* 1109e69d7d0SLori Alt * Check to see whether this free block can be aggregated 1119e69d7d0SLori Alt * with pending one. 1129e69d7d0SLori Alt */ 1139e69d7d0SLori Alt if (drrf->drr_object == object && drrf->drr_offset + 1149e69d7d0SLori Alt drrf->drr_length == offset) { 1159e69d7d0SLori Alt drrf->drr_length += length; 1169e69d7d0SLori Alt return (0); 1179e69d7d0SLori Alt } else { 1189e69d7d0SLori Alt /* not a continuation. Push out pending record */ 1194e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1209e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 1219e69d7d0SLori Alt return (EINTR); 1224e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1239e69d7d0SLori Alt } 1249e69d7d0SLori Alt } 1259e69d7d0SLori Alt /* create a FREE record and make it pending */ 1264e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 1274e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREE; 1289e69d7d0SLori Alt drrf->drr_object = object; 1299e69d7d0SLori Alt drrf->drr_offset = offset; 1309e69d7d0SLori Alt drrf->drr_length = length; 1314e3c9f44SBill Pijewski drrf->drr_toguid = dsp->dsa_toguid; 1329e69d7d0SLori Alt if (length == -1ULL) { 1334e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1344e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 1359e69d7d0SLori Alt return (EINTR); 1369e69d7d0SLori Alt } else { 1374e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREE; 1389e69d7d0SLori Alt } 139efb80947Sahrens 140efb80947Sahrens return (0); 141efb80947Sahrens } 142efb80947Sahrens 143efb80947Sahrens static int 1444e3c9f44SBill Pijewski dump_data(dmu_sendarg_t *dsp, dmu_object_type_t type, 1458e714474SLori Alt uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) 146efb80947Sahrens { 1474e3c9f44SBill Pijewski struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write); 1489e69d7d0SLori Alt 1498e714474SLori Alt 1509e69d7d0SLori Alt /* 1519e69d7d0SLori Alt * If there is any kind of pending aggregation (currently either 1529e69d7d0SLori Alt * a grouping of free objects or free blocks), push it out to 1539e69d7d0SLori Alt * the stream, since aggregation can't be done across operations 1549e69d7d0SLori Alt * of different types. 1559e69d7d0SLori Alt */ 1564e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 1574e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1584e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 1599e69d7d0SLori Alt return (EINTR); 1604e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1619e69d7d0SLori Alt } 162efb80947Sahrens /* write a DATA record */ 1634e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 1644e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_WRITE; 1659e69d7d0SLori Alt drrw->drr_object = object; 1669e69d7d0SLori Alt drrw->drr_type = type; 1679e69d7d0SLori Alt drrw->drr_offset = offset; 1689e69d7d0SLori Alt drrw->drr_length = blksz; 1694e3c9f44SBill Pijewski drrw->drr_toguid = dsp->dsa_toguid; 1708e714474SLori Alt drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); 1718e714474SLori Alt if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) 1728e714474SLori Alt drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; 1738e714474SLori Alt DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); 1748e714474SLori Alt DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); 1758e714474SLori Alt DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); 1768e714474SLori Alt drrw->drr_key.ddk_cksum = bp->blk_cksum; 177efb80947Sahrens 1784e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 179efb80947Sahrens return (EINTR); 1804e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz) != 0) 181efb80947Sahrens return (EINTR); 182efb80947Sahrens return (0); 183efb80947Sahrens } 184efb80947Sahrens 1850a586ceaSMark Shellenbaum static int 1864e3c9f44SBill Pijewski dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data) 1870a586ceaSMark Shellenbaum { 1884e3c9f44SBill Pijewski struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill); 1890a586ceaSMark Shellenbaum 1904e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 1914e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1924e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 1930a586ceaSMark Shellenbaum return (EINTR); 1944e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1950a586ceaSMark Shellenbaum } 1960a586ceaSMark Shellenbaum 1970a586ceaSMark Shellenbaum /* write a SPILL record */ 1984e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 1994e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_SPILL; 2000a586ceaSMark Shellenbaum drrs->drr_object = object; 2010a586ceaSMark Shellenbaum drrs->drr_length = blksz; 2024e3c9f44SBill Pijewski drrs->drr_toguid = dsp->dsa_toguid; 2030a586ceaSMark Shellenbaum 2044e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t))) 2050a586ceaSMark Shellenbaum return (EINTR); 2064e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz)) 2070a586ceaSMark Shellenbaum return (EINTR); 2080a586ceaSMark Shellenbaum return (0); 2090a586ceaSMark Shellenbaum } 2100a586ceaSMark Shellenbaum 211efb80947Sahrens static int 2124e3c9f44SBill Pijewski dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs) 213efb80947Sahrens { 2144e3c9f44SBill Pijewski struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects); 2159e69d7d0SLori Alt 2169e69d7d0SLori Alt /* 2179e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREEOBJECTS, 2189e69d7d0SLori Alt * push it out, since free block aggregation can only be done for 2199e69d7d0SLori Alt * blocks of the same type (i.e., DRR_FREE records can only be 2209e69d7d0SLori Alt * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records 2219e69d7d0SLori Alt * can only be aggregated with other DRR_FREEOBJECTS records. 2229e69d7d0SLori Alt */ 2234e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 2244e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREEOBJECTS) { 2254e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2264e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 2279e69d7d0SLori Alt return (EINTR); 2284e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2299e69d7d0SLori Alt } 2304e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) { 2319e69d7d0SLori Alt /* 2329e69d7d0SLori Alt * See whether this free object array can be aggregated 2339e69d7d0SLori Alt * with pending one 2349e69d7d0SLori Alt */ 2359e69d7d0SLori Alt if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { 2369e69d7d0SLori Alt drrfo->drr_numobjs += numobjs; 2379e69d7d0SLori Alt return (0); 2389e69d7d0SLori Alt } else { 2399e69d7d0SLori Alt /* can't be aggregated. Push out pending record */ 2404e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2419e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 2429e69d7d0SLori Alt return (EINTR); 2434e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2449e69d7d0SLori Alt } 2459e69d7d0SLori Alt } 2469e69d7d0SLori Alt 247efb80947Sahrens /* write a FREEOBJECTS record */ 2484e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2494e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREEOBJECTS; 2509e69d7d0SLori Alt drrfo->drr_firstobj = firstobj; 2519e69d7d0SLori Alt drrfo->drr_numobjs = numobjs; 2524e3c9f44SBill Pijewski drrfo->drr_toguid = dsp->dsa_toguid; 2539e69d7d0SLori Alt 2544e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREEOBJECTS; 255efb80947Sahrens 256efb80947Sahrens return (0); 257efb80947Sahrens } 258efb80947Sahrens 259efb80947Sahrens static int 2604e3c9f44SBill Pijewski dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp) 261efb80947Sahrens { 2624e3c9f44SBill Pijewski struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object); 2639e69d7d0SLori Alt 264efb80947Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 2654e3c9f44SBill Pijewski return (dump_freeobjects(dsp, object, 1)); 266efb80947Sahrens 2674e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 2684e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2694e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 2709e69d7d0SLori Alt return (EINTR); 2714e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2729e69d7d0SLori Alt } 2739e69d7d0SLori Alt 274efb80947Sahrens /* write an OBJECT record */ 2754e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2764e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_OBJECT; 2779e69d7d0SLori Alt drro->drr_object = object; 2789e69d7d0SLori Alt drro->drr_type = dnp->dn_type; 2799e69d7d0SLori Alt drro->drr_bonustype = dnp->dn_bonustype; 2809e69d7d0SLori Alt drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 2819e69d7d0SLori Alt drro->drr_bonuslen = dnp->dn_bonuslen; 2829e69d7d0SLori Alt drro->drr_checksumtype = dnp->dn_checksum; 2839e69d7d0SLori Alt drro->drr_compress = dnp->dn_compress; 2844e3c9f44SBill Pijewski drro->drr_toguid = dsp->dsa_toguid; 2859e69d7d0SLori Alt 2864e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 287efb80947Sahrens return (EINTR); 288efb80947Sahrens 2894e3c9f44SBill Pijewski if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 290efb80947Sahrens return (EINTR); 291efb80947Sahrens 292efb80947Sahrens /* free anything past the end of the file */ 2934e3c9f44SBill Pijewski if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 294efb80947Sahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 295efb80947Sahrens return (EINTR); 296*3b2aab18SMatthew Ahrens if (dsp->dsa_err != 0) 297efb80947Sahrens return (EINTR); 298efb80947Sahrens return (0); 299efb80947Sahrens } 300efb80947Sahrens 301efb80947Sahrens #define BP_SPAN(dnp, level) \ 302efb80947Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 303efb80947Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 304efb80947Sahrens 305b24ab676SJeff Bonwick /* ARGSUSED */ 306efb80947Sahrens static int 3071b912ec7SGeorge Wilson backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 308b24ab676SJeff Bonwick const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 309efb80947Sahrens { 3104e3c9f44SBill Pijewski dmu_sendarg_t *dsp = arg; 311efb80947Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 312efb80947Sahrens int err = 0; 313efb80947Sahrens 314efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 315efb80947Sahrens return (EINTR); 316efb80947Sahrens 317b24ab676SJeff Bonwick if (zb->zb_object != DMU_META_DNODE_OBJECT && 318b24ab676SJeff Bonwick DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 31914843421SMatthew Ahrens return (0); 320b24ab676SJeff Bonwick } else if (bp == NULL && zb->zb_object == DMU_META_DNODE_OBJECT) { 32188b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 32288b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 3234e3c9f44SBill Pijewski err = dump_freeobjects(dsp, dnobj, span >> DNODE_SHIFT); 324efb80947Sahrens } else if (bp == NULL) { 32588b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 3264e3c9f44SBill Pijewski err = dump_free(dsp, zb->zb_object, zb->zb_blkid * span, span); 32788b7b0f2SMatthew Ahrens } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 32888b7b0f2SMatthew Ahrens return (0); 32988b7b0f2SMatthew Ahrens } else if (type == DMU_OT_DNODE) { 33088b7b0f2SMatthew Ahrens dnode_phys_t *blk; 331efb80947Sahrens int i; 332efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 33388b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 33488b7b0f2SMatthew Ahrens arc_buf_t *abuf; 335efb80947Sahrens 3361b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 3371b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 3381b912ec7SGeorge Wilson &aflags, zb) != 0) 33988b7b0f2SMatthew Ahrens return (EIO); 34088b7b0f2SMatthew Ahrens 34188b7b0f2SMatthew Ahrens blk = abuf->b_data; 342efb80947Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 34388b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid << 34488b7b0f2SMatthew Ahrens (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 3454e3c9f44SBill Pijewski err = dump_dnode(dsp, dnobj, blk+i); 346*3b2aab18SMatthew Ahrens if (err != 0) 347efb80947Sahrens break; 348efb80947Sahrens } 34988b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 3500a586ceaSMark Shellenbaum } else if (type == DMU_OT_SA) { 3510a586ceaSMark Shellenbaum uint32_t aflags = ARC_WAIT; 3520a586ceaSMark Shellenbaum arc_buf_t *abuf; 3530a586ceaSMark Shellenbaum int blksz = BP_GET_LSIZE(bp); 3540a586ceaSMark Shellenbaum 3551b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 3561b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 3571b912ec7SGeorge Wilson &aflags, zb) != 0) 3580a586ceaSMark Shellenbaum return (EIO); 3590a586ceaSMark Shellenbaum 3604e3c9f44SBill Pijewski err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data); 3610a586ceaSMark Shellenbaum (void) arc_buf_remove_ref(abuf, &abuf); 36288b7b0f2SMatthew Ahrens } else { /* it's a level-0 block of a regular object */ 36388b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 36488b7b0f2SMatthew Ahrens arc_buf_t *abuf; 365efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 36688b7b0f2SMatthew Ahrens 3671b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 3681b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 3691b912ec7SGeorge Wilson &aflags, zb) != 0) { 37019b94df9SMatthew Ahrens if (zfs_send_corrupt_data) { 37119b94df9SMatthew Ahrens /* Send a block filled with 0x"zfs badd bloc" */ 37219b94df9SMatthew Ahrens abuf = arc_buf_alloc(spa, blksz, &abuf, 37319b94df9SMatthew Ahrens ARC_BUFC_DATA); 37419b94df9SMatthew Ahrens uint64_t *ptr; 37519b94df9SMatthew Ahrens for (ptr = abuf->b_data; 37619b94df9SMatthew Ahrens (char *)ptr < (char *)abuf->b_data + blksz; 37719b94df9SMatthew Ahrens ptr++) 37819b94df9SMatthew Ahrens *ptr = 0x2f5baddb10c; 37919b94df9SMatthew Ahrens } else { 38019b94df9SMatthew Ahrens return (EIO); 38119b94df9SMatthew Ahrens } 38219b94df9SMatthew Ahrens } 38388b7b0f2SMatthew Ahrens 3844e3c9f44SBill Pijewski err = dump_data(dsp, type, zb->zb_object, zb->zb_blkid * blksz, 3858e714474SLori Alt blksz, bp, abuf->b_data); 38688b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 387efb80947Sahrens } 388efb80947Sahrens 389efb80947Sahrens ASSERT(err == 0 || err == EINTR); 390efb80947Sahrens return (err); 391efb80947Sahrens } 392efb80947Sahrens 3934445fffbSMatthew Ahrens /* 394*3b2aab18SMatthew Ahrens * Releases dp, ds, and fromds, using the specified tag. 3954445fffbSMatthew Ahrens */ 396*3b2aab18SMatthew Ahrens static int 397*3b2aab18SMatthew Ahrens dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds, 398*3b2aab18SMatthew Ahrens dsl_dataset_t *fromds, int outfd, vnode_t *vp, offset_t *off) 399efb80947Sahrens { 400*3b2aab18SMatthew Ahrens objset_t *os; 401efb80947Sahrens dmu_replay_record_t *drr; 4024e3c9f44SBill Pijewski dmu_sendarg_t *dsp; 403efb80947Sahrens int err; 4043cb34c60Sahrens uint64_t fromtxg = 0; 405efb80947Sahrens 406*3b2aab18SMatthew Ahrens if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) { 407*3b2aab18SMatthew Ahrens dsl_dataset_rele(fromds, tag); 408*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, tag); 409*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 410efb80947Sahrens return (EXDEV); 411*3b2aab18SMatthew Ahrens } 412*3b2aab18SMatthew Ahrens 413*3b2aab18SMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 414*3b2aab18SMatthew Ahrens if (err != 0) { 415*3b2aab18SMatthew Ahrens if (fromds != NULL) 416*3b2aab18SMatthew Ahrens dsl_dataset_rele(fromds, tag); 417*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, tag); 418*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 419*3b2aab18SMatthew Ahrens return (err); 420*3b2aab18SMatthew Ahrens } 421efb80947Sahrens 422efb80947Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 423efb80947Sahrens drr->drr_type = DRR_BEGIN; 424efb80947Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 4259e69d7d0SLori Alt DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 4269e69d7d0SLori Alt DMU_SUBSTREAM); 427dc7cd546SMark Shellenbaum 428dc7cd546SMark Shellenbaum #ifdef _KERNEL 429*3b2aab18SMatthew Ahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 430dc7cd546SMark Shellenbaum uint64_t version; 431*3b2aab18SMatthew Ahrens if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) { 4324e3c9f44SBill Pijewski kmem_free(drr, sizeof (dmu_replay_record_t)); 433*3b2aab18SMatthew Ahrens if (fromds != NULL) 434*3b2aab18SMatthew Ahrens dsl_dataset_rele(fromds, tag); 435*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, tag); 436*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 437dc7cd546SMark Shellenbaum return (EINVAL); 4384e3c9f44SBill Pijewski } 439*3b2aab18SMatthew Ahrens if (version >= ZPL_VERSION_SA) { 440dc7cd546SMark Shellenbaum DMU_SET_FEATUREFLAGS( 441dc7cd546SMark Shellenbaum drr->drr_u.drr_begin.drr_versioninfo, 442dc7cd546SMark Shellenbaum DMU_BACKUP_FEATURE_SA_SPILL); 443dc7cd546SMark Shellenbaum } 444dc7cd546SMark Shellenbaum } 445dc7cd546SMark Shellenbaum #endif 446dc7cd546SMark Shellenbaum 447efb80947Sahrens drr->drr_u.drr_begin.drr_creation_time = 448efb80947Sahrens ds->ds_phys->ds_creation_time; 449*3b2aab18SMatthew Ahrens drr->drr_u.drr_begin.drr_type = dmu_objset_type(os); 4504445fffbSMatthew Ahrens if (fromds != NULL && ds->ds_dir != fromds->ds_dir) 4513cb34c60Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 452efb80947Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 453ab04eb8eStimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 454ab04eb8eStimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 455ab04eb8eStimh 456*3b2aab18SMatthew Ahrens if (fromds != NULL) 457efb80947Sahrens drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 458efb80947Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 459efb80947Sahrens 460*3b2aab18SMatthew Ahrens if (fromds != NULL) { 4613cb34c60Sahrens fromtxg = fromds->ds_phys->ds_creation_txg; 462*3b2aab18SMatthew Ahrens dsl_dataset_rele(fromds, tag); 463*3b2aab18SMatthew Ahrens fromds = NULL; 464*3b2aab18SMatthew Ahrens } 4653cb34c60Sahrens 4664e3c9f44SBill Pijewski dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 4674e3c9f44SBill Pijewski 4684e3c9f44SBill Pijewski dsp->dsa_drr = drr; 4694e3c9f44SBill Pijewski dsp->dsa_vp = vp; 4704e3c9f44SBill Pijewski dsp->dsa_outfd = outfd; 4714e3c9f44SBill Pijewski dsp->dsa_proc = curproc; 472*3b2aab18SMatthew Ahrens dsp->dsa_os = os; 4734e3c9f44SBill Pijewski dsp->dsa_off = off; 4744e3c9f44SBill Pijewski dsp->dsa_toguid = ds->ds_phys->ds_guid; 4754e3c9f44SBill Pijewski ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 4764e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 4774e3c9f44SBill Pijewski 4784e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 4794e3c9f44SBill Pijewski list_insert_head(&ds->ds_sendstreams, dsp); 4804e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 4814e3c9f44SBill Pijewski 4824e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 4834e3c9f44SBill Pijewski err = dsp->dsa_err; 4844e3c9f44SBill Pijewski goto out; 485efb80947Sahrens } 486efb80947Sahrens 487*3b2aab18SMatthew Ahrens dsl_dataset_long_hold(ds, FTAG); 488*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 489*3b2aab18SMatthew Ahrens 49088b7b0f2SMatthew Ahrens err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 4914e3c9f44SBill Pijewski backup_cb, dsp); 492efb80947Sahrens 4934e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) 4944e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 4959e69d7d0SLori Alt err = EINTR; 4969e69d7d0SLori Alt 497*3b2aab18SMatthew Ahrens if (err != 0) { 498*3b2aab18SMatthew Ahrens if (err == EINTR && dsp->dsa_err != 0) 4994e3c9f44SBill Pijewski err = dsp->dsa_err; 5004e3c9f44SBill Pijewski goto out; 501efb80947Sahrens } 502efb80947Sahrens 503efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 504efb80947Sahrens drr->drr_type = DRR_END; 5054e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 5064e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; 507efb80947Sahrens 5084e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 5094e3c9f44SBill Pijewski err = dsp->dsa_err; 5104e3c9f44SBill Pijewski goto out; 5117b5309bbSgw } 512efb80947Sahrens 5134e3c9f44SBill Pijewski out: 5144e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 5154e3c9f44SBill Pijewski list_remove(&ds->ds_sendstreams, dsp); 5164e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 5174e3c9f44SBill Pijewski 518efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 5194e3c9f44SBill Pijewski kmem_free(dsp, sizeof (dmu_sendarg_t)); 520efb80947Sahrens 521*3b2aab18SMatthew Ahrens dsl_dataset_long_rele(ds, FTAG); 522*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, tag); 523*3b2aab18SMatthew Ahrens 5244e3c9f44SBill Pijewski return (err); 525efb80947Sahrens } 526efb80947Sahrens 52719b94df9SMatthew Ahrens int 528*3b2aab18SMatthew Ahrens dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, 529*3b2aab18SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 530*3b2aab18SMatthew Ahrens { 531*3b2aab18SMatthew Ahrens dsl_pool_t *dp; 532*3b2aab18SMatthew Ahrens dsl_dataset_t *ds; 533*3b2aab18SMatthew Ahrens dsl_dataset_t *fromds = NULL; 534*3b2aab18SMatthew Ahrens int err; 535*3b2aab18SMatthew Ahrens 536*3b2aab18SMatthew Ahrens err = dsl_pool_hold(pool, FTAG, &dp); 537*3b2aab18SMatthew Ahrens if (err != 0) 538*3b2aab18SMatthew Ahrens return (err); 539*3b2aab18SMatthew Ahrens 540*3b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds); 541*3b2aab18SMatthew Ahrens if (err != 0) { 542*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 543*3b2aab18SMatthew Ahrens return (err); 544*3b2aab18SMatthew Ahrens } 545*3b2aab18SMatthew Ahrens 546*3b2aab18SMatthew Ahrens if (fromsnap != 0) { 547*3b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds); 548*3b2aab18SMatthew Ahrens if (err != 0) { 549*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 550*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 551*3b2aab18SMatthew Ahrens return (err); 552*3b2aab18SMatthew Ahrens } 553*3b2aab18SMatthew Ahrens } 554*3b2aab18SMatthew Ahrens 555*3b2aab18SMatthew Ahrens return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, vp, off)); 556*3b2aab18SMatthew Ahrens } 557*3b2aab18SMatthew Ahrens 558*3b2aab18SMatthew Ahrens int 559*3b2aab18SMatthew Ahrens dmu_send(const char *tosnap, const char *fromsnap, 560*3b2aab18SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 561*3b2aab18SMatthew Ahrens { 562*3b2aab18SMatthew Ahrens dsl_pool_t *dp; 563*3b2aab18SMatthew Ahrens dsl_dataset_t *ds; 564*3b2aab18SMatthew Ahrens dsl_dataset_t *fromds = NULL; 565*3b2aab18SMatthew Ahrens int err; 566*3b2aab18SMatthew Ahrens 567*3b2aab18SMatthew Ahrens if (strchr(tosnap, '@') == NULL) 568*3b2aab18SMatthew Ahrens return (EINVAL); 569*3b2aab18SMatthew Ahrens if (fromsnap != NULL && strchr(fromsnap, '@') == NULL) 570*3b2aab18SMatthew Ahrens return (EINVAL); 571*3b2aab18SMatthew Ahrens 572*3b2aab18SMatthew Ahrens err = dsl_pool_hold(tosnap, FTAG, &dp); 573*3b2aab18SMatthew Ahrens if (err != 0) 574*3b2aab18SMatthew Ahrens return (err); 575*3b2aab18SMatthew Ahrens 576*3b2aab18SMatthew Ahrens err = dsl_dataset_hold(dp, tosnap, FTAG, &ds); 577*3b2aab18SMatthew Ahrens if (err != 0) { 578*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 579*3b2aab18SMatthew Ahrens return (err); 580*3b2aab18SMatthew Ahrens } 581*3b2aab18SMatthew Ahrens 582*3b2aab18SMatthew Ahrens if (fromsnap != NULL) { 583*3b2aab18SMatthew Ahrens err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds); 584*3b2aab18SMatthew Ahrens if (err != 0) { 585*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 586*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 587*3b2aab18SMatthew Ahrens return (err); 588*3b2aab18SMatthew Ahrens } 589*3b2aab18SMatthew Ahrens } 590*3b2aab18SMatthew Ahrens return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, vp, off)); 591*3b2aab18SMatthew Ahrens } 592*3b2aab18SMatthew Ahrens 593*3b2aab18SMatthew Ahrens int 594*3b2aab18SMatthew Ahrens dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep) 59519b94df9SMatthew Ahrens { 59619b94df9SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 59719b94df9SMatthew Ahrens int err; 59819b94df9SMatthew Ahrens uint64_t size; 59919b94df9SMatthew Ahrens 600*3b2aab18SMatthew Ahrens ASSERT(dsl_pool_config_held(dp)); 601*3b2aab18SMatthew Ahrens 60219b94df9SMatthew Ahrens /* tosnap must be a snapshot */ 603*3b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) 60419b94df9SMatthew Ahrens return (EINVAL); 60519b94df9SMatthew Ahrens 6064445fffbSMatthew Ahrens /* 6074445fffbSMatthew Ahrens * fromsnap must be an earlier snapshot from the same fs as tosnap, 6084445fffbSMatthew Ahrens * or the origin's fs. 6094445fffbSMatthew Ahrens */ 610*3b2aab18SMatthew Ahrens if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) 61119b94df9SMatthew Ahrens return (EXDEV); 61219b94df9SMatthew Ahrens 61319b94df9SMatthew Ahrens /* Get uncompressed size estimate of changed data. */ 61419b94df9SMatthew Ahrens if (fromds == NULL) { 61519b94df9SMatthew Ahrens size = ds->ds_phys->ds_uncompressed_bytes; 61619b94df9SMatthew Ahrens } else { 61719b94df9SMatthew Ahrens uint64_t used, comp; 61819b94df9SMatthew Ahrens err = dsl_dataset_space_written(fromds, ds, 61919b94df9SMatthew Ahrens &used, &comp, &size); 620*3b2aab18SMatthew Ahrens if (err != 0) 62119b94df9SMatthew Ahrens return (err); 62219b94df9SMatthew Ahrens } 62319b94df9SMatthew Ahrens 62419b94df9SMatthew Ahrens /* 62519b94df9SMatthew Ahrens * Assume that space (both on-disk and in-stream) is dominated by 62619b94df9SMatthew Ahrens * data. We will adjust for indirect blocks and the copies property, 62719b94df9SMatthew Ahrens * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 62819b94df9SMatthew Ahrens */ 62919b94df9SMatthew Ahrens 63019b94df9SMatthew Ahrens /* 63119b94df9SMatthew Ahrens * Subtract out approximate space used by indirect blocks. 63219b94df9SMatthew Ahrens * Assume most space is used by data blocks (non-indirect, non-dnode). 63319b94df9SMatthew Ahrens * Assume all blocks are recordsize. Assume ditto blocks and 63419b94df9SMatthew Ahrens * internal fragmentation counter out compression. 63519b94df9SMatthew Ahrens * 63619b94df9SMatthew Ahrens * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 63719b94df9SMatthew Ahrens * block, which we observe in practice. 63819b94df9SMatthew Ahrens */ 63919b94df9SMatthew Ahrens uint64_t recordsize; 640*3b2aab18SMatthew Ahrens err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize); 641*3b2aab18SMatthew Ahrens if (err != 0) 64219b94df9SMatthew Ahrens return (err); 64319b94df9SMatthew Ahrens size -= size / recordsize * sizeof (blkptr_t); 64419b94df9SMatthew Ahrens 64519b94df9SMatthew Ahrens /* Add in the space for the record associated with each block. */ 64619b94df9SMatthew Ahrens size += size / recordsize * sizeof (dmu_replay_record_t); 64719b94df9SMatthew Ahrens 64819b94df9SMatthew Ahrens *sizep = size; 64919b94df9SMatthew Ahrens 65019b94df9SMatthew Ahrens return (0); 65119b94df9SMatthew Ahrens } 65219b94df9SMatthew Ahrens 653*3b2aab18SMatthew Ahrens typedef struct dmu_recv_begin_arg { 654*3b2aab18SMatthew Ahrens const char *drba_origin; 655*3b2aab18SMatthew Ahrens dmu_recv_cookie_t *drba_cookie; 656*3b2aab18SMatthew Ahrens cred_t *drba_cred; 657*3b2aab18SMatthew Ahrens } dmu_recv_begin_arg_t; 658f18faf3fSek 659f18faf3fSek static int 660*3b2aab18SMatthew Ahrens recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds, 661*3b2aab18SMatthew Ahrens uint64_t fromguid) 662f18faf3fSek { 6633cb34c60Sahrens uint64_t val; 664*3b2aab18SMatthew Ahrens int error; 665*3b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 666f18faf3fSek 6673cb34c60Sahrens /* must not have any changes since most recent snapshot */ 668*3b2aab18SMatthew Ahrens if (!drba->drba_cookie->drc_force && 669*3b2aab18SMatthew Ahrens dsl_dataset_modified_since_lastsnap(ds)) 670f18faf3fSek return (ETXTBSY); 671f18faf3fSek 672*3b2aab18SMatthew Ahrens /* temporary clone name must not exist */ 673*3b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 674*3b2aab18SMatthew Ahrens ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name, 675*3b2aab18SMatthew Ahrens 8, 1, &val); 676*3b2aab18SMatthew Ahrens if (error != ENOENT) 677*3b2aab18SMatthew Ahrens return (error == 0 ? EBUSY : error); 678*3b2aab18SMatthew Ahrens 679feaa74e4SMark Maybee /* new snapshot name must not exist */ 680*3b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 681*3b2aab18SMatthew Ahrens ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap, 682*3b2aab18SMatthew Ahrens 8, 1, &val); 683*3b2aab18SMatthew Ahrens if (error != ENOENT) 684*3b2aab18SMatthew Ahrens return (error == 0 ? EEXIST : error); 685feaa74e4SMark Maybee 686*3b2aab18SMatthew Ahrens if (fromguid != 0) { 687ae46e4c7SMatthew Ahrens /* if incremental, most recent snapshot must match fromguid */ 688ae46e4c7SMatthew Ahrens if (ds->ds_prev == NULL) 689ae46e4c7SMatthew Ahrens return (ENODEV); 69092241e0bSTom Erickson 69192241e0bSTom Erickson /* 69292241e0bSTom Erickson * most recent snapshot must match fromguid, or there are no 69392241e0bSTom Erickson * changes since the fromguid one 69492241e0bSTom Erickson */ 695*3b2aab18SMatthew Ahrens if (ds->ds_prev->ds_phys->ds_guid != fromguid) { 69692241e0bSTom Erickson uint64_t birth = ds->ds_prev->ds_phys->ds_bp.blk_birth; 69792241e0bSTom Erickson uint64_t obj = ds->ds_prev->ds_phys->ds_prev_snap_obj; 69892241e0bSTom Erickson while (obj != 0) { 69992241e0bSTom Erickson dsl_dataset_t *snap; 700*3b2aab18SMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 701*3b2aab18SMatthew Ahrens &snap); 702*3b2aab18SMatthew Ahrens if (error != 0) 70392241e0bSTom Erickson return (ENODEV); 70492241e0bSTom Erickson if (snap->ds_phys->ds_creation_txg < birth) { 70592241e0bSTom Erickson dsl_dataset_rele(snap, FTAG); 70692241e0bSTom Erickson return (ENODEV); 70792241e0bSTom Erickson } 708*3b2aab18SMatthew Ahrens if (snap->ds_phys->ds_guid == fromguid) { 70992241e0bSTom Erickson dsl_dataset_rele(snap, FTAG); 71092241e0bSTom Erickson break; /* it's ok */ 71192241e0bSTom Erickson } 71292241e0bSTom Erickson obj = snap->ds_phys->ds_prev_snap_obj; 71392241e0bSTom Erickson dsl_dataset_rele(snap, FTAG); 71492241e0bSTom Erickson } 71592241e0bSTom Erickson if (obj == 0) 71692241e0bSTom Erickson return (ENODEV); 71792241e0bSTom Erickson } 718ae46e4c7SMatthew Ahrens } else { 719ae46e4c7SMatthew Ahrens /* if full, most recent snapshot must be $ORIGIN */ 720ae46e4c7SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 721ae46e4c7SMatthew Ahrens return (ENODEV); 722ae46e4c7SMatthew Ahrens } 7233cb34c60Sahrens 7243cb34c60Sahrens return (0); 725*3b2aab18SMatthew Ahrens 726*3b2aab18SMatthew Ahrens } 727*3b2aab18SMatthew Ahrens 728*3b2aab18SMatthew Ahrens static int 729*3b2aab18SMatthew Ahrens dmu_recv_begin_check(void *arg, dmu_tx_t *tx) 730*3b2aab18SMatthew Ahrens { 731*3b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 732*3b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 733*3b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 734*3b2aab18SMatthew Ahrens uint64_t fromguid = drrb->drr_fromguid; 735*3b2aab18SMatthew Ahrens int flags = drrb->drr_flags; 736*3b2aab18SMatthew Ahrens int error; 737*3b2aab18SMatthew Ahrens dsl_dataset_t *ds; 738*3b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 739*3b2aab18SMatthew Ahrens 740*3b2aab18SMatthew Ahrens /* already checked */ 741*3b2aab18SMatthew Ahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 742*3b2aab18SMatthew Ahrens 743*3b2aab18SMatthew Ahrens if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == 744*3b2aab18SMatthew Ahrens DMU_COMPOUNDSTREAM || 745*3b2aab18SMatthew Ahrens drrb->drr_type >= DMU_OST_NUMTYPES || 746*3b2aab18SMatthew Ahrens ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) 747*3b2aab18SMatthew Ahrens return (EINVAL); 748*3b2aab18SMatthew Ahrens 749*3b2aab18SMatthew Ahrens /* Verify pool version supports SA if SA_SPILL feature set */ 750*3b2aab18SMatthew Ahrens if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) & 751*3b2aab18SMatthew Ahrens DMU_BACKUP_FEATURE_SA_SPILL) && 752*3b2aab18SMatthew Ahrens spa_version(dp->dp_spa) < SPA_VERSION_SA) { 753*3b2aab18SMatthew Ahrens return (ENOTSUP); 754*3b2aab18SMatthew Ahrens } 755*3b2aab18SMatthew Ahrens 756*3b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 757*3b2aab18SMatthew Ahrens if (error == 0) { 758*3b2aab18SMatthew Ahrens /* target fs already exists; recv into temp clone */ 759*3b2aab18SMatthew Ahrens 760*3b2aab18SMatthew Ahrens /* Can't recv a clone into an existing fs */ 761*3b2aab18SMatthew Ahrens if (flags & DRR_FLAG_CLONE) { 762*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 763*3b2aab18SMatthew Ahrens return (EINVAL); 764*3b2aab18SMatthew Ahrens } 765*3b2aab18SMatthew Ahrens 766*3b2aab18SMatthew Ahrens error = recv_begin_check_existing_impl(drba, ds, fromguid); 767*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 768*3b2aab18SMatthew Ahrens } else if (error == ENOENT) { 769*3b2aab18SMatthew Ahrens /* target fs does not exist; must be a full backup or clone */ 770*3b2aab18SMatthew Ahrens char buf[MAXNAMELEN]; 771*3b2aab18SMatthew Ahrens 772*3b2aab18SMatthew Ahrens /* 773*3b2aab18SMatthew Ahrens * If it's a non-clone incremental, we are missing the 774*3b2aab18SMatthew Ahrens * target fs, so fail the recv. 775*3b2aab18SMatthew Ahrens */ 776*3b2aab18SMatthew Ahrens if (fromguid != 0 && !(flags & DRR_FLAG_CLONE)) 777*3b2aab18SMatthew Ahrens return (ENOENT); 778*3b2aab18SMatthew Ahrens 779*3b2aab18SMatthew Ahrens /* Open the parent of tofs */ 780*3b2aab18SMatthew Ahrens ASSERT3U(strlen(tofs), <, MAXNAMELEN); 781*3b2aab18SMatthew Ahrens (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1); 782*3b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, buf, FTAG, &ds); 783*3b2aab18SMatthew Ahrens if (error != 0) 784*3b2aab18SMatthew Ahrens return (error); 785*3b2aab18SMatthew Ahrens 786*3b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 787*3b2aab18SMatthew Ahrens dsl_dataset_t *origin; 788*3b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drba->drba_origin, 789*3b2aab18SMatthew Ahrens FTAG, &origin); 790*3b2aab18SMatthew Ahrens if (error != 0) { 791*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 792*3b2aab18SMatthew Ahrens return (error); 793*3b2aab18SMatthew Ahrens } 794*3b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(origin)) { 795*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 796*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 797*3b2aab18SMatthew Ahrens return (EINVAL); 798*3b2aab18SMatthew Ahrens } 799*3b2aab18SMatthew Ahrens if (origin->ds_phys->ds_guid != fromguid) { 800*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 801*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 802*3b2aab18SMatthew Ahrens return (ENODEV); 803*3b2aab18SMatthew Ahrens } 804*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 805*3b2aab18SMatthew Ahrens } 806*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 807*3b2aab18SMatthew Ahrens error = 0; 808*3b2aab18SMatthew Ahrens } 809*3b2aab18SMatthew Ahrens return (error); 810f18faf3fSek } 811f18faf3fSek 812f18faf3fSek static void 813*3b2aab18SMatthew Ahrens dmu_recv_begin_sync(void *arg, dmu_tx_t *tx) 814f18faf3fSek { 815*3b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 816*3b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 817*3b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 818*3b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 819*3b2aab18SMatthew Ahrens dsl_dataset_t *ds, *newds; 820f18faf3fSek uint64_t dsobj; 821*3b2aab18SMatthew Ahrens int error; 822*3b2aab18SMatthew Ahrens uint64_t crflags; 823*3b2aab18SMatthew Ahrens 824*3b2aab18SMatthew Ahrens crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ? 825*3b2aab18SMatthew Ahrens DS_FLAG_CI_DATASET : 0; 826f18faf3fSek 827*3b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 828*3b2aab18SMatthew Ahrens if (error == 0) { 829*3b2aab18SMatthew Ahrens /* create temporary clone */ 830*3b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name, 831*3b2aab18SMatthew Ahrens ds->ds_prev, crflags, drba->drba_cred, tx); 832*3b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 833*3b2aab18SMatthew Ahrens } else { 834*3b2aab18SMatthew Ahrens dsl_dir_t *dd; 835*3b2aab18SMatthew Ahrens const char *tail; 836*3b2aab18SMatthew Ahrens dsl_dataset_t *origin = NULL; 837*3b2aab18SMatthew Ahrens 838*3b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail)); 839*3b2aab18SMatthew Ahrens 840*3b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 841*3b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drba->drba_origin, 842*3b2aab18SMatthew Ahrens FTAG, &origin)); 843*3b2aab18SMatthew Ahrens } 844*3b2aab18SMatthew Ahrens 845*3b2aab18SMatthew Ahrens /* Create new dataset. */ 846*3b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(dd, 847*3b2aab18SMatthew Ahrens strrchr(tofs, '/') + 1, 848*3b2aab18SMatthew Ahrens origin, crflags, drba->drba_cred, tx); 849*3b2aab18SMatthew Ahrens if (origin != NULL) 850*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 851*3b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 852*3b2aab18SMatthew Ahrens drba->drba_cookie->drc_newfs = B_TRUE; 853*3b2aab18SMatthew Ahrens } 854*3b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds)); 855*3b2aab18SMatthew Ahrens 856*3b2aab18SMatthew Ahrens dmu_buf_will_dirty(newds->ds_dbuf, tx); 857*3b2aab18SMatthew Ahrens newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 8583cb34c60Sahrens 859ae46e4c7SMatthew Ahrens /* 860ae46e4c7SMatthew Ahrens * If we actually created a non-clone, we need to create the 861ae46e4c7SMatthew Ahrens * objset in our new dataset. 862ae46e4c7SMatthew Ahrens */ 863*3b2aab18SMatthew Ahrens if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) { 864ae46e4c7SMatthew Ahrens (void) dmu_objset_create_impl(dp->dp_spa, 865*3b2aab18SMatthew Ahrens newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx); 866ae46e4c7SMatthew Ahrens } 867ae46e4c7SMatthew Ahrens 868*3b2aab18SMatthew Ahrens drba->drba_cookie->drc_ds = newds; 869dc7cd546SMark Shellenbaum 870*3b2aab18SMatthew Ahrens spa_history_log_internal_ds(newds, "receive", tx, ""); 871dc7cd546SMark Shellenbaum } 872dc7cd546SMark Shellenbaum 8733cb34c60Sahrens /* 8743cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 8753cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 8763cb34c60Sahrens */ 8773cb34c60Sahrens int 878*3b2aab18SMatthew Ahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 879*3b2aab18SMatthew Ahrens boolean_t force, char *origin, dmu_recv_cookie_t *drc) 880efb80947Sahrens { 881*3b2aab18SMatthew Ahrens dmu_recv_begin_arg_t drba = { 0 }; 882*3b2aab18SMatthew Ahrens dmu_replay_record_t *drr; 883ab04eb8eStimh 8843cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 8853cb34c60Sahrens drc->drc_drrb = drrb; 8863cb34c60Sahrens drc->drc_tosnap = tosnap; 887*3b2aab18SMatthew Ahrens drc->drc_tofs = tofs; 8883cb34c60Sahrens drc->drc_force = force; 889efb80947Sahrens 890*3b2aab18SMatthew Ahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 891*3b2aab18SMatthew Ahrens drc->drc_byteswap = B_TRUE; 892*3b2aab18SMatthew Ahrens else if (drrb->drr_magic != DMU_BACKUP_MAGIC) 893*3b2aab18SMatthew Ahrens return (EINVAL); 894efb80947Sahrens 895*3b2aab18SMatthew Ahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 896*3b2aab18SMatthew Ahrens drr->drr_type = DRR_BEGIN; 897*3b2aab18SMatthew Ahrens drr->drr_u.drr_begin = *drc->drc_drrb; 898*3b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 899*3b2aab18SMatthew Ahrens fletcher_4_incremental_byteswap(drr, 900*3b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 901*3b2aab18SMatthew Ahrens } else { 902*3b2aab18SMatthew Ahrens fletcher_4_incremental_native(drr, 903*3b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 904*3b2aab18SMatthew Ahrens } 905*3b2aab18SMatthew Ahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 906dc7cd546SMark Shellenbaum 907*3b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 908*3b2aab18SMatthew Ahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 909*3b2aab18SMatthew Ahrens drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 910*3b2aab18SMatthew Ahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 911*3b2aab18SMatthew Ahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 912*3b2aab18SMatthew Ahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 913*3b2aab18SMatthew Ahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 9143cb34c60Sahrens } 9153cb34c60Sahrens 916*3b2aab18SMatthew Ahrens drba.drba_origin = origin; 917*3b2aab18SMatthew Ahrens drba.drba_cookie = drc; 918*3b2aab18SMatthew Ahrens drba.drba_cred = CRED(); 919*3b2aab18SMatthew Ahrens 920*3b2aab18SMatthew Ahrens return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync, 921*3b2aab18SMatthew Ahrens &drba, 5)); 922efb80947Sahrens } 923efb80947Sahrens 9243cb34c60Sahrens struct restorearg { 9253cb34c60Sahrens int err; 926*3b2aab18SMatthew Ahrens boolean_t byteswap; 9273cb34c60Sahrens vnode_t *vp; 9283cb34c60Sahrens char *buf; 9293cb34c60Sahrens uint64_t voff; 9303cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 9313cb34c60Sahrens zio_cksum_t cksum; 932c99e4bdcSChris Kirby avl_tree_t *guid_to_ds_map; 9333cb34c60Sahrens }; 9343cb34c60Sahrens 9359e69d7d0SLori Alt typedef struct guid_map_entry { 9369e69d7d0SLori Alt uint64_t guid; 9379e69d7d0SLori Alt dsl_dataset_t *gme_ds; 9389e69d7d0SLori Alt avl_node_t avlnode; 9399e69d7d0SLori Alt } guid_map_entry_t; 9409e69d7d0SLori Alt 9419e69d7d0SLori Alt static int 9429e69d7d0SLori Alt guid_compare(const void *arg1, const void *arg2) 9439e69d7d0SLori Alt { 9449e69d7d0SLori Alt const guid_map_entry_t *gmep1 = arg1; 9459e69d7d0SLori Alt const guid_map_entry_t *gmep2 = arg2; 9469e69d7d0SLori Alt 9479e69d7d0SLori Alt if (gmep1->guid < gmep2->guid) 9489e69d7d0SLori Alt return (-1); 9499e69d7d0SLori Alt else if (gmep1->guid > gmep2->guid) 9509e69d7d0SLori Alt return (1); 9519e69d7d0SLori Alt return (0); 9529e69d7d0SLori Alt } 9539e69d7d0SLori Alt 954c99e4bdcSChris Kirby static void 955c99e4bdcSChris Kirby free_guid_map_onexit(void *arg) 956c99e4bdcSChris Kirby { 957c99e4bdcSChris Kirby avl_tree_t *ca = arg; 958c99e4bdcSChris Kirby void *cookie = NULL; 959c99e4bdcSChris Kirby guid_map_entry_t *gmep; 960c99e4bdcSChris Kirby 961c99e4bdcSChris Kirby while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { 962*3b2aab18SMatthew Ahrens dsl_dataset_long_rele(gmep->gme_ds, gmep); 963c99e4bdcSChris Kirby kmem_free(gmep, sizeof (guid_map_entry_t)); 964c99e4bdcSChris Kirby } 965c99e4bdcSChris Kirby avl_destroy(ca); 966c99e4bdcSChris Kirby kmem_free(ca, sizeof (avl_tree_t)); 967c99e4bdcSChris Kirby } 968c99e4bdcSChris Kirby 969efb80947Sahrens static void * 970efb80947Sahrens restore_read(struct restorearg *ra, int len) 971efb80947Sahrens { 972efb80947Sahrens void *rv; 9733cb34c60Sahrens int done = 0; 974efb80947Sahrens 975efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 976fb09f5aaSMadhav Suresh ASSERT0(len % 8); 977efb80947Sahrens 9783cb34c60Sahrens while (done < len) { 979efb80947Sahrens ssize_t resid; 980efb80947Sahrens 981efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 9823cb34c60Sahrens (caddr_t)ra->buf + done, len - done, 983efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 984efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 985efb80947Sahrens 9863cb34c60Sahrens if (resid == len - done) 987efb80947Sahrens ra->err = EINVAL; 9883cb34c60Sahrens ra->voff += len - done - resid; 9893cb34c60Sahrens done = len - resid; 990*3b2aab18SMatthew Ahrens if (ra->err != 0) 991efb80947Sahrens return (NULL); 992efb80947Sahrens } 993efb80947Sahrens 9943cb34c60Sahrens ASSERT3U(done, ==, len); 9953cb34c60Sahrens rv = ra->buf; 996efb80947Sahrens if (ra->byteswap) 9973cb34c60Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 998efb80947Sahrens else 9993cb34c60Sahrens fletcher_4_incremental_native(rv, len, &ra->cksum); 1000efb80947Sahrens return (rv); 1001efb80947Sahrens } 1002efb80947Sahrens 1003efb80947Sahrens static void 1004efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 1005efb80947Sahrens { 1006efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 1007efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 1008efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 10093cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 1010efb80947Sahrens switch (drr->drr_type) { 1011efb80947Sahrens case DRR_BEGIN: 1012efb80947Sahrens DO64(drr_begin.drr_magic); 10139e69d7d0SLori Alt DO64(drr_begin.drr_versioninfo); 1014efb80947Sahrens DO64(drr_begin.drr_creation_time); 1015efb80947Sahrens DO32(drr_begin.drr_type); 10163cb34c60Sahrens DO32(drr_begin.drr_flags); 1017efb80947Sahrens DO64(drr_begin.drr_toguid); 1018efb80947Sahrens DO64(drr_begin.drr_fromguid); 1019efb80947Sahrens break; 1020efb80947Sahrens case DRR_OBJECT: 1021efb80947Sahrens DO64(drr_object.drr_object); 1022efb80947Sahrens /* DO64(drr_object.drr_allocation_txg); */ 1023efb80947Sahrens DO32(drr_object.drr_type); 1024efb80947Sahrens DO32(drr_object.drr_bonustype); 1025efb80947Sahrens DO32(drr_object.drr_blksz); 1026efb80947Sahrens DO32(drr_object.drr_bonuslen); 10279e69d7d0SLori Alt DO64(drr_object.drr_toguid); 1028efb80947Sahrens break; 1029efb80947Sahrens case DRR_FREEOBJECTS: 1030efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 1031efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 10329e69d7d0SLori Alt DO64(drr_freeobjects.drr_toguid); 1033efb80947Sahrens break; 1034efb80947Sahrens case DRR_WRITE: 1035efb80947Sahrens DO64(drr_write.drr_object); 1036efb80947Sahrens DO32(drr_write.drr_type); 1037efb80947Sahrens DO64(drr_write.drr_offset); 1038efb80947Sahrens DO64(drr_write.drr_length); 10399e69d7d0SLori Alt DO64(drr_write.drr_toguid); 10408e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[0]); 10418e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[1]); 10428e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[2]); 10438e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[3]); 10448e714474SLori Alt DO64(drr_write.drr_key.ddk_prop); 10459e69d7d0SLori Alt break; 10469e69d7d0SLori Alt case DRR_WRITE_BYREF: 10479e69d7d0SLori Alt DO64(drr_write_byref.drr_object); 10489e69d7d0SLori Alt DO64(drr_write_byref.drr_offset); 10499e69d7d0SLori Alt DO64(drr_write_byref.drr_length); 10509e69d7d0SLori Alt DO64(drr_write_byref.drr_toguid); 10519e69d7d0SLori Alt DO64(drr_write_byref.drr_refguid); 10529e69d7d0SLori Alt DO64(drr_write_byref.drr_refobject); 10539e69d7d0SLori Alt DO64(drr_write_byref.drr_refoffset); 10548e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[0]); 10558e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[1]); 10568e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[2]); 10578e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[3]); 10588e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_prop); 1059efb80947Sahrens break; 1060efb80947Sahrens case DRR_FREE: 1061efb80947Sahrens DO64(drr_free.drr_object); 1062efb80947Sahrens DO64(drr_free.drr_offset); 1063efb80947Sahrens DO64(drr_free.drr_length); 10649e69d7d0SLori Alt DO64(drr_free.drr_toguid); 1065efb80947Sahrens break; 10660a586ceaSMark Shellenbaum case DRR_SPILL: 10670a586ceaSMark Shellenbaum DO64(drr_spill.drr_object); 10680a586ceaSMark Shellenbaum DO64(drr_spill.drr_length); 10690a586ceaSMark Shellenbaum DO64(drr_spill.drr_toguid); 10700a586ceaSMark Shellenbaum break; 1071efb80947Sahrens case DRR_END: 1072efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 1073efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 1074efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 1075efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 10769e69d7d0SLori Alt DO64(drr_end.drr_toguid); 1077efb80947Sahrens break; 1078efb80947Sahrens } 1079efb80947Sahrens #undef DO64 1080efb80947Sahrens #undef DO32 1081efb80947Sahrens } 1082efb80947Sahrens 1083efb80947Sahrens static int 1084efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 1085efb80947Sahrens { 1086efb80947Sahrens int err; 1087efb80947Sahrens dmu_tx_t *tx; 1088adee0b6fSTim Haley void *data = NULL; 1089efb80947Sahrens 1090efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 1091ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_type) || 1092ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_bonustype) || 10939e69d7d0SLori Alt drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || 1094efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 1095efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 1096efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 1097efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 1098efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 1099efb80947Sahrens return (EINVAL); 1100efb80947Sahrens } 1101efb80947Sahrens 11022bf405a2SMark Maybee err = dmu_object_info(os, drro->drr_object, NULL); 11032bf405a2SMark Maybee 11042bf405a2SMark Maybee if (err != 0 && err != ENOENT) 11052bf405a2SMark Maybee return (EINVAL); 11062bf405a2SMark Maybee 1107adee0b6fSTim Haley if (drro->drr_bonuslen) { 1108adee0b6fSTim Haley data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 1109*3b2aab18SMatthew Ahrens if (ra->err != 0) 1110adee0b6fSTim Haley return (ra->err); 1111adee0b6fSTim Haley } 1112adee0b6fSTim Haley 1113efb80947Sahrens if (err == ENOENT) { 1114efb80947Sahrens /* currently free, want to be allocated */ 11152bf405a2SMark Maybee tx = dmu_tx_create(os); 1116efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1117efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 1118*3b2aab18SMatthew Ahrens if (err != 0) { 1119efb80947Sahrens dmu_tx_abort(tx); 1120efb80947Sahrens return (err); 1121efb80947Sahrens } 1122efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 1123efb80947Sahrens drro->drr_type, drro->drr_blksz, 1124efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 11252bf405a2SMark Maybee dmu_tx_commit(tx); 1126efb80947Sahrens } else { 1127efb80947Sahrens /* currently allocated, want to be allocated */ 1128efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 1129efb80947Sahrens drro->drr_type, drro->drr_blksz, 11302bf405a2SMark Maybee drro->drr_bonustype, drro->drr_bonuslen); 1131efb80947Sahrens } 1132*3b2aab18SMatthew Ahrens if (err != 0) { 1133efb80947Sahrens return (EINVAL); 11340a586ceaSMark Shellenbaum } 11352bf405a2SMark Maybee 11362bf405a2SMark Maybee tx = dmu_tx_create(os); 11372bf405a2SMark Maybee dmu_tx_hold_bonus(tx, drro->drr_object); 11382bf405a2SMark Maybee err = dmu_tx_assign(tx, TXG_WAIT); 1139*3b2aab18SMatthew Ahrens if (err != 0) { 11402bf405a2SMark Maybee dmu_tx_abort(tx); 11412bf405a2SMark Maybee return (err); 1142efb80947Sahrens } 1143efb80947Sahrens 11449e69d7d0SLori Alt dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 11459e69d7d0SLori Alt tx); 1146efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1147efb80947Sahrens 1148adee0b6fSTim Haley if (data != NULL) { 1149efb80947Sahrens dmu_buf_t *db; 1150adee0b6fSTim Haley 1151efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 1152efb80947Sahrens dmu_buf_will_dirty(db, tx); 1153efb80947Sahrens 11541934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 11551934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 1156efb80947Sahrens if (ra->byteswap) { 1157ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1158ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drro->drr_bonustype); 1159ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(db->db_data, 1160efb80947Sahrens drro->drr_bonuslen); 1161efb80947Sahrens } 1162efb80947Sahrens dmu_buf_rele(db, FTAG); 1163efb80947Sahrens } 1164efb80947Sahrens dmu_tx_commit(tx); 1165efb80947Sahrens return (0); 1166efb80947Sahrens } 1167efb80947Sahrens 1168efb80947Sahrens /* ARGSUSED */ 1169efb80947Sahrens static int 1170efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 1171efb80947Sahrens struct drr_freeobjects *drrfo) 1172efb80947Sahrens { 1173efb80947Sahrens uint64_t obj; 1174efb80947Sahrens 1175efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 1176efb80947Sahrens return (EINVAL); 1177efb80947Sahrens 1178efb80947Sahrens for (obj = drrfo->drr_firstobj; 1179432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1180432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 1181efb80947Sahrens int err; 1182efb80947Sahrens 1183efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 1184efb80947Sahrens continue; 1185efb80947Sahrens 1186cdb0ab79Smaybee err = dmu_free_object(os, obj); 1187*3b2aab18SMatthew Ahrens if (err != 0) 1188efb80947Sahrens return (err); 1189efb80947Sahrens } 1190efb80947Sahrens return (0); 1191efb80947Sahrens } 1192efb80947Sahrens 1193efb80947Sahrens static int 1194efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 1195efb80947Sahrens struct drr_write *drrw) 1196efb80947Sahrens { 1197efb80947Sahrens dmu_tx_t *tx; 1198efb80947Sahrens void *data; 1199efb80947Sahrens int err; 1200efb80947Sahrens 1201efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 1202ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drrw->drr_type)) 1203efb80947Sahrens return (EINVAL); 1204efb80947Sahrens 1205efb80947Sahrens data = restore_read(ra, drrw->drr_length); 1206efb80947Sahrens if (data == NULL) 1207efb80947Sahrens return (ra->err); 1208efb80947Sahrens 1209efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1210efb80947Sahrens return (EINVAL); 1211efb80947Sahrens 1212efb80947Sahrens tx = dmu_tx_create(os); 1213efb80947Sahrens 1214efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 1215efb80947Sahrens drrw->drr_offset, drrw->drr_length); 1216efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 1217*3b2aab18SMatthew Ahrens if (err != 0) { 1218efb80947Sahrens dmu_tx_abort(tx); 1219efb80947Sahrens return (err); 1220efb80947Sahrens } 1221ad135b5dSChristopher Siden if (ra->byteswap) { 1222ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1223ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drrw->drr_type); 1224ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1225ad135b5dSChristopher Siden } 1226efb80947Sahrens dmu_write(os, drrw->drr_object, 1227efb80947Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 1228efb80947Sahrens dmu_tx_commit(tx); 1229efb80947Sahrens return (0); 1230efb80947Sahrens } 1231efb80947Sahrens 12329e69d7d0SLori Alt /* 12339e69d7d0SLori Alt * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed 12349e69d7d0SLori Alt * streams to refer to a copy of the data that is already on the 12359e69d7d0SLori Alt * system because it came in earlier in the stream. This function 12369e69d7d0SLori Alt * finds the earlier copy of the data, and uses that copy instead of 12379e69d7d0SLori Alt * data from the stream to fulfill this write. 12389e69d7d0SLori Alt */ 12399e69d7d0SLori Alt static int 12409e69d7d0SLori Alt restore_write_byref(struct restorearg *ra, objset_t *os, 12419e69d7d0SLori Alt struct drr_write_byref *drrwbr) 12429e69d7d0SLori Alt { 12439e69d7d0SLori Alt dmu_tx_t *tx; 12449e69d7d0SLori Alt int err; 12459e69d7d0SLori Alt guid_map_entry_t gmesrch; 12469e69d7d0SLori Alt guid_map_entry_t *gmep; 12479e69d7d0SLori Alt avl_index_t where; 12489e69d7d0SLori Alt objset_t *ref_os = NULL; 12499e69d7d0SLori Alt dmu_buf_t *dbp; 12509e69d7d0SLori Alt 12519e69d7d0SLori Alt if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset) 12529e69d7d0SLori Alt return (EINVAL); 12539e69d7d0SLori Alt 12549e69d7d0SLori Alt /* 12559e69d7d0SLori Alt * If the GUID of the referenced dataset is different from the 12569e69d7d0SLori Alt * GUID of the target dataset, find the referenced dataset. 12579e69d7d0SLori Alt */ 12589e69d7d0SLori Alt if (drrwbr->drr_toguid != drrwbr->drr_refguid) { 12599e69d7d0SLori Alt gmesrch.guid = drrwbr->drr_refguid; 1260c99e4bdcSChris Kirby if ((gmep = avl_find(ra->guid_to_ds_map, &gmesrch, 12619e69d7d0SLori Alt &where)) == NULL) { 12629e69d7d0SLori Alt return (EINVAL); 12639e69d7d0SLori Alt } 12649e69d7d0SLori Alt if (dmu_objset_from_ds(gmep->gme_ds, &ref_os)) 12659e69d7d0SLori Alt return (EINVAL); 12669e69d7d0SLori Alt } else { 12679e69d7d0SLori Alt ref_os = os; 12689e69d7d0SLori Alt } 12699e69d7d0SLori Alt 12709e69d7d0SLori Alt if (err = dmu_buf_hold(ref_os, drrwbr->drr_refobject, 127147cb52daSJeff Bonwick drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH)) 12729e69d7d0SLori Alt return (err); 12739e69d7d0SLori Alt 12749e69d7d0SLori Alt tx = dmu_tx_create(os); 12759e69d7d0SLori Alt 12769e69d7d0SLori Alt dmu_tx_hold_write(tx, drrwbr->drr_object, 12779e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length); 12789e69d7d0SLori Alt err = dmu_tx_assign(tx, TXG_WAIT); 1279*3b2aab18SMatthew Ahrens if (err != 0) { 12809e69d7d0SLori Alt dmu_tx_abort(tx); 12819e69d7d0SLori Alt return (err); 12829e69d7d0SLori Alt } 12839e69d7d0SLori Alt dmu_write(os, drrwbr->drr_object, 12849e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 12859e69d7d0SLori Alt dmu_buf_rele(dbp, FTAG); 12869e69d7d0SLori Alt dmu_tx_commit(tx); 12879e69d7d0SLori Alt return (0); 12889e69d7d0SLori Alt } 12899e69d7d0SLori Alt 12900a586ceaSMark Shellenbaum static int 12910a586ceaSMark Shellenbaum restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs) 12920a586ceaSMark Shellenbaum { 12930a586ceaSMark Shellenbaum dmu_tx_t *tx; 12940a586ceaSMark Shellenbaum void *data; 12950a586ceaSMark Shellenbaum dmu_buf_t *db, *db_spill; 12960a586ceaSMark Shellenbaum int err; 12970a586ceaSMark Shellenbaum 12980a586ceaSMark Shellenbaum if (drrs->drr_length < SPA_MINBLOCKSIZE || 12990a586ceaSMark Shellenbaum drrs->drr_length > SPA_MAXBLOCKSIZE) 13000a586ceaSMark Shellenbaum return (EINVAL); 13010a586ceaSMark Shellenbaum 13020a586ceaSMark Shellenbaum data = restore_read(ra, drrs->drr_length); 13030a586ceaSMark Shellenbaum if (data == NULL) 13040a586ceaSMark Shellenbaum return (ra->err); 13050a586ceaSMark Shellenbaum 13060a586ceaSMark Shellenbaum if (dmu_object_info(os, drrs->drr_object, NULL) != 0) 13070a586ceaSMark Shellenbaum return (EINVAL); 13080a586ceaSMark Shellenbaum 13090a586ceaSMark Shellenbaum VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db)); 13100a586ceaSMark Shellenbaum if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) { 13110a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 13120a586ceaSMark Shellenbaum return (err); 13130a586ceaSMark Shellenbaum } 13140a586ceaSMark Shellenbaum 13150a586ceaSMark Shellenbaum tx = dmu_tx_create(os); 13160a586ceaSMark Shellenbaum 13170a586ceaSMark Shellenbaum dmu_tx_hold_spill(tx, db->db_object); 13180a586ceaSMark Shellenbaum 13190a586ceaSMark Shellenbaum err = dmu_tx_assign(tx, TXG_WAIT); 1320*3b2aab18SMatthew Ahrens if (err != 0) { 13210a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 13220a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 13230a586ceaSMark Shellenbaum dmu_tx_abort(tx); 13240a586ceaSMark Shellenbaum return (err); 13250a586ceaSMark Shellenbaum } 13260a586ceaSMark Shellenbaum dmu_buf_will_dirty(db_spill, tx); 13270a586ceaSMark Shellenbaum 13280a586ceaSMark Shellenbaum if (db_spill->db_size < drrs->drr_length) 13290a586ceaSMark Shellenbaum VERIFY(0 == dbuf_spill_set_blksz(db_spill, 13300a586ceaSMark Shellenbaum drrs->drr_length, tx)); 13310a586ceaSMark Shellenbaum bcopy(data, db_spill->db_data, drrs->drr_length); 13320a586ceaSMark Shellenbaum 13330a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 13340a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 13350a586ceaSMark Shellenbaum 13360a586ceaSMark Shellenbaum dmu_tx_commit(tx); 13370a586ceaSMark Shellenbaum return (0); 13380a586ceaSMark Shellenbaum } 13390a586ceaSMark Shellenbaum 1340efb80947Sahrens /* ARGSUSED */ 1341efb80947Sahrens static int 1342efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 1343efb80947Sahrens struct drr_free *drrf) 1344efb80947Sahrens { 1345efb80947Sahrens int err; 1346efb80947Sahrens 1347efb80947Sahrens if (drrf->drr_length != -1ULL && 1348efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 1349efb80947Sahrens return (EINVAL); 1350efb80947Sahrens 1351efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1352efb80947Sahrens return (EINVAL); 1353efb80947Sahrens 1354cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 1355efb80947Sahrens drrf->drr_offset, drrf->drr_length); 1356efb80947Sahrens return (err); 1357efb80947Sahrens } 1358efb80947Sahrens 1359*3b2aab18SMatthew Ahrens /* used to destroy the drc_ds on error */ 1360*3b2aab18SMatthew Ahrens static void 1361*3b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) 1362*3b2aab18SMatthew Ahrens { 1363*3b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 1364*3b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 1365*3b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 1366*3b2aab18SMatthew Ahrens (void) dsl_destroy_head(name); 1367*3b2aab18SMatthew Ahrens } 1368*3b2aab18SMatthew Ahrens 13693cb34c60Sahrens /* 13703cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 13713cb34c60Sahrens */ 1372efb80947Sahrens int 1373c99e4bdcSChris Kirby dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp, 1374c99e4bdcSChris Kirby int cleanup_fd, uint64_t *action_handlep) 1375efb80947Sahrens { 13763cb34c60Sahrens struct restorearg ra = { 0 }; 1377efb80947Sahrens dmu_replay_record_t *drr; 13783cb34c60Sahrens objset_t *os; 13793cb34c60Sahrens zio_cksum_t pcksum; 13809e69d7d0SLori Alt int featureflags; 1381efb80947Sahrens 1382*3b2aab18SMatthew Ahrens ra.byteswap = drc->drc_byteswap; 1383*3b2aab18SMatthew Ahrens ra.cksum = drc->drc_cksum; 13843cb34c60Sahrens ra.vp = vp; 13853cb34c60Sahrens ra.voff = *voffp; 13863cb34c60Sahrens ra.bufsize = 1<<20; 13873cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1388efb80947Sahrens 13893cb34c60Sahrens /* these were verified in dmu_recv_begin */ 1390*3b2aab18SMatthew Ahrens ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==, 13919e69d7d0SLori Alt DMU_SUBSTREAM); 1392*3b2aab18SMatthew Ahrens ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES); 1393efb80947Sahrens 1394efb80947Sahrens /* 1395efb80947Sahrens * Open the objset we are modifying. 1396efb80947Sahrens */ 1397*3b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os)); 1398efb80947Sahrens 1399*3b2aab18SMatthew Ahrens ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1400efb80947Sahrens 14019e69d7d0SLori Alt featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 14029e69d7d0SLori Alt 14039e69d7d0SLori Alt /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 14049e69d7d0SLori Alt if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1405a7f53a56SChris Kirby minor_t minor; 1406a7f53a56SChris Kirby 1407c99e4bdcSChris Kirby if (cleanup_fd == -1) { 1408c99e4bdcSChris Kirby ra.err = EBADF; 1409c99e4bdcSChris Kirby goto out; 1410c99e4bdcSChris Kirby } 1411a7f53a56SChris Kirby ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); 1412*3b2aab18SMatthew Ahrens if (ra.err != 0) { 1413a7f53a56SChris Kirby cleanup_fd = -1; 1414a7f53a56SChris Kirby goto out; 1415a7f53a56SChris Kirby } 1416a7f53a56SChris Kirby 1417c99e4bdcSChris Kirby if (*action_handlep == 0) { 1418c99e4bdcSChris Kirby ra.guid_to_ds_map = 1419c99e4bdcSChris Kirby kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1420c99e4bdcSChris Kirby avl_create(ra.guid_to_ds_map, guid_compare, 1421c99e4bdcSChris Kirby sizeof (guid_map_entry_t), 1422c99e4bdcSChris Kirby offsetof(guid_map_entry_t, avlnode)); 1423a7f53a56SChris Kirby ra.err = zfs_onexit_add_cb(minor, 1424c99e4bdcSChris Kirby free_guid_map_onexit, ra.guid_to_ds_map, 1425c99e4bdcSChris Kirby action_handlep); 1426*3b2aab18SMatthew Ahrens if (ra.err != 0) 1427c99e4bdcSChris Kirby goto out; 1428c99e4bdcSChris Kirby } else { 1429a7f53a56SChris Kirby ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1430c99e4bdcSChris Kirby (void **)&ra.guid_to_ds_map); 1431*3b2aab18SMatthew Ahrens if (ra.err != 0) 1432c99e4bdcSChris Kirby goto out; 1433c99e4bdcSChris Kirby } 1434ec5cf9d5SAlexander Stetsenko 1435ec5cf9d5SAlexander Stetsenko drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 14369e69d7d0SLori Alt } 14379e69d7d0SLori Alt 1438efb80947Sahrens /* 1439efb80947Sahrens * Read records and process them. 1440efb80947Sahrens */ 14413cb34c60Sahrens pcksum = ra.cksum; 1442efb80947Sahrens while (ra.err == 0 && 1443efb80947Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 1444efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 1445efb80947Sahrens ra.err = EINTR; 1446efb80947Sahrens goto out; 1447efb80947Sahrens } 1448efb80947Sahrens 1449efb80947Sahrens if (ra.byteswap) 1450efb80947Sahrens backup_byteswap(drr); 1451efb80947Sahrens 1452efb80947Sahrens switch (drr->drr_type) { 1453efb80947Sahrens case DRR_OBJECT: 1454efb80947Sahrens { 1455efb80947Sahrens /* 1456efb80947Sahrens * We need to make a copy of the record header, 1457efb80947Sahrens * because restore_{object,write} may need to 1458efb80947Sahrens * restore_read(), which will invalidate drr. 1459efb80947Sahrens */ 1460efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 1461efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 1462efb80947Sahrens break; 1463efb80947Sahrens } 1464efb80947Sahrens case DRR_FREEOBJECTS: 1465efb80947Sahrens { 1466efb80947Sahrens struct drr_freeobjects drrfo = 1467efb80947Sahrens drr->drr_u.drr_freeobjects; 1468efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 1469efb80947Sahrens break; 1470efb80947Sahrens } 1471efb80947Sahrens case DRR_WRITE: 1472efb80947Sahrens { 1473efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 1474efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 1475efb80947Sahrens break; 1476efb80947Sahrens } 14779e69d7d0SLori Alt case DRR_WRITE_BYREF: 14789e69d7d0SLori Alt { 14799e69d7d0SLori Alt struct drr_write_byref drrwbr = 14809e69d7d0SLori Alt drr->drr_u.drr_write_byref; 14819e69d7d0SLori Alt ra.err = restore_write_byref(&ra, os, &drrwbr); 14829e69d7d0SLori Alt break; 14839e69d7d0SLori Alt } 1484efb80947Sahrens case DRR_FREE: 1485efb80947Sahrens { 1486efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 1487efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 1488efb80947Sahrens break; 1489efb80947Sahrens } 1490efb80947Sahrens case DRR_END: 1491efb80947Sahrens { 1492efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1493efb80947Sahrens /* 1494efb80947Sahrens * We compare against the *previous* checksum 1495efb80947Sahrens * value, because the stored checksum is of 1496efb80947Sahrens * everything before the DRR_END record. 1497efb80947Sahrens */ 1498137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1499efb80947Sahrens ra.err = ECKSUM; 1500efb80947Sahrens goto out; 1501efb80947Sahrens } 15020a586ceaSMark Shellenbaum case DRR_SPILL: 15030a586ceaSMark Shellenbaum { 15040a586ceaSMark Shellenbaum struct drr_spill drrs = drr->drr_u.drr_spill; 15050a586ceaSMark Shellenbaum ra.err = restore_spill(&ra, os, &drrs); 15060a586ceaSMark Shellenbaum break; 15070a586ceaSMark Shellenbaum } 1508efb80947Sahrens default: 1509efb80947Sahrens ra.err = EINVAL; 1510efb80947Sahrens goto out; 1511efb80947Sahrens } 15123cb34c60Sahrens pcksum = ra.cksum; 1513efb80947Sahrens } 1514137fa067Sahrens ASSERT(ra.err != 0); 1515efb80947Sahrens 1516efb80947Sahrens out: 1517a7f53a56SChris Kirby if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1518a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 1519a7f53a56SChris Kirby 15203cb34c60Sahrens if (ra.err != 0) { 1521efb80947Sahrens /* 1522f4b94bdeSMatthew Ahrens * destroy what we created, so we don't leave it in the 1523f4b94bdeSMatthew Ahrens * inconsistent restoring state. 1524efb80947Sahrens */ 1525*3b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 1526efb80947Sahrens } 1527efb80947Sahrens 1528efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 15293cb34c60Sahrens *voffp = ra.voff; 1530efb80947Sahrens return (ra.err); 1531efb80947Sahrens } 1532f18faf3fSek 15333cb34c60Sahrens static int 1534*3b2aab18SMatthew Ahrens dmu_recv_end_check(void *arg, dmu_tx_t *tx) 15353cb34c60Sahrens { 1536*3b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 1537*3b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 1538*3b2aab18SMatthew Ahrens int error; 1539*3b2aab18SMatthew Ahrens 1540*3b2aab18SMatthew Ahrens ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag); 15413cb34c60Sahrens 1542*3b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 1543*3b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 1544*3b2aab18SMatthew Ahrens 1545*3b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head); 1546*3b2aab18SMatthew Ahrens if (error != 0) 1547*3b2aab18SMatthew Ahrens return (error); 1548*3b2aab18SMatthew Ahrens error = dsl_dataset_clone_swap_check_impl(drc->drc_ds, 1549*3b2aab18SMatthew Ahrens origin_head, drc->drc_force); 1550*3b2aab18SMatthew Ahrens if (error != 0) { 1551*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 1552*3b2aab18SMatthew Ahrens return (error); 1553*3b2aab18SMatthew Ahrens } 1554*3b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(origin_head, 1555*3b2aab18SMatthew Ahrens drc->drc_tosnap, tx); 1556*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 1557*3b2aab18SMatthew Ahrens if (error != 0) 1558*3b2aab18SMatthew Ahrens return (error); 1559*3b2aab18SMatthew Ahrens 1560*3b2aab18SMatthew Ahrens error = dsl_destroy_head_check_impl(drc->drc_ds, 1); 1561*3b2aab18SMatthew Ahrens } else { 1562*3b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(drc->drc_ds, 1563*3b2aab18SMatthew Ahrens drc->drc_tosnap, tx); 1564*3b2aab18SMatthew Ahrens } 1565*3b2aab18SMatthew Ahrens return (error); 15663cb34c60Sahrens } 15673cb34c60Sahrens 15683cb34c60Sahrens static void 1569*3b2aab18SMatthew Ahrens dmu_recv_end_sync(void *arg, dmu_tx_t *tx) 15703cb34c60Sahrens { 1571*3b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 1572*3b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 1573*3b2aab18SMatthew Ahrens 1574*3b2aab18SMatthew Ahrens spa_history_log_internal_ds(drc->drc_ds, "finish receiving", 1575*3b2aab18SMatthew Ahrens tx, "snap=%s", drc->drc_tosnap); 1576*3b2aab18SMatthew Ahrens 1577*3b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 1578*3b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 1579*3b2aab18SMatthew Ahrens 1580*3b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG, 1581*3b2aab18SMatthew Ahrens &origin_head)); 1582*3b2aab18SMatthew Ahrens dsl_dataset_clone_swap_sync_impl(drc->drc_ds, 1583*3b2aab18SMatthew Ahrens origin_head, tx); 1584*3b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(origin_head, 1585*3b2aab18SMatthew Ahrens drc->drc_tosnap, tx); 1586*3b2aab18SMatthew Ahrens 1587*3b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 1588*3b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx); 1589*3b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_creation_time = 1590*3b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 1591*3b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_guid = 1592*3b2aab18SMatthew Ahrens drc->drc_drrb->drr_toguid; 1593*3b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_flags &= 1594*3b2aab18SMatthew Ahrens ~DS_FLAG_INCONSISTENT; 1595*3b2aab18SMatthew Ahrens 1596*3b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_dbuf, tx); 1597*3b2aab18SMatthew Ahrens origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1598*3b2aab18SMatthew Ahrens 1599*3b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 1600*3b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(drc->drc_ds, tx); 1601*3b2aab18SMatthew Ahrens } else { 1602*3b2aab18SMatthew Ahrens dsl_dataset_t *ds = drc->drc_ds; 16033cb34c60Sahrens 1604*3b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx); 16053cb34c60Sahrens 1606*3b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 1607*3b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1608*3b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_creation_time = 1609*3b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 1610*3b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid; 1611*3b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 16123cb34c60Sahrens 1613*3b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1614*3b2aab18SMatthew Ahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1615*3b2aab18SMatthew Ahrens } 1616*3b2aab18SMatthew Ahrens drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj; 1617*3b2aab18SMatthew Ahrens /* 1618*3b2aab18SMatthew Ahrens * Release the hold from dmu_recv_begin. This must be done before 1619*3b2aab18SMatthew Ahrens * we return to open context, so that when we free the dataset's dnode, 1620*3b2aab18SMatthew Ahrens * we can evict its bonus buffer. 1621*3b2aab18SMatthew Ahrens */ 1622*3b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 1623*3b2aab18SMatthew Ahrens drc->drc_ds = NULL; 16243cb34c60Sahrens } 16253cb34c60Sahrens 1626ec5cf9d5SAlexander Stetsenko static int 1627*3b2aab18SMatthew Ahrens add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj) 1628ec5cf9d5SAlexander Stetsenko { 1629*3b2aab18SMatthew Ahrens dsl_pool_t *dp; 1630ec5cf9d5SAlexander Stetsenko dsl_dataset_t *snapds; 1631ec5cf9d5SAlexander Stetsenko guid_map_entry_t *gmep; 1632ec5cf9d5SAlexander Stetsenko int err; 1633ec5cf9d5SAlexander Stetsenko 1634ec5cf9d5SAlexander Stetsenko ASSERT(guid_map != NULL); 1635ec5cf9d5SAlexander Stetsenko 1636*3b2aab18SMatthew Ahrens err = dsl_pool_hold(name, FTAG, &dp); 1637*3b2aab18SMatthew Ahrens if (err != 0) 1638*3b2aab18SMatthew Ahrens return (err); 1639*3b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snapds); 1640ec5cf9d5SAlexander Stetsenko if (err == 0) { 1641ec5cf9d5SAlexander Stetsenko gmep = kmem_alloc(sizeof (guid_map_entry_t), KM_SLEEP); 1642ec5cf9d5SAlexander Stetsenko gmep->guid = snapds->ds_phys->ds_guid; 1643ec5cf9d5SAlexander Stetsenko gmep->gme_ds = snapds; 1644ec5cf9d5SAlexander Stetsenko avl_add(guid_map, gmep); 1645*3b2aab18SMatthew Ahrens dsl_dataset_long_hold(snapds, gmep); 1646*3b2aab18SMatthew Ahrens dsl_dataset_rele(snapds, FTAG); 1647ec5cf9d5SAlexander Stetsenko } 1648ec5cf9d5SAlexander Stetsenko 1649*3b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 1650ec5cf9d5SAlexander Stetsenko return (err); 1651ec5cf9d5SAlexander Stetsenko } 1652ec5cf9d5SAlexander Stetsenko 1653*3b2aab18SMatthew Ahrens static int dmu_recv_end_modified_blocks = 3; 1654*3b2aab18SMatthew Ahrens 1655ae46e4c7SMatthew Ahrens static int 1656ae46e4c7SMatthew Ahrens dmu_recv_existing_end(dmu_recv_cookie_t *drc) 1657f18faf3fSek { 1658*3b2aab18SMatthew Ahrens int error; 1659*3b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 16603cb34c60Sahrens 1661*3b2aab18SMatthew Ahrens #ifdef _KERNEL 1662*3b2aab18SMatthew Ahrens /* 1663*3b2aab18SMatthew Ahrens * We will be destroying the ds; make sure its origin is unmounted if 1664*3b2aab18SMatthew Ahrens * necessary. 1665*3b2aab18SMatthew Ahrens */ 1666*3b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 1667*3b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(name); 1668*3b2aab18SMatthew Ahrens #endif 16693cb34c60Sahrens 1670*3b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 1671*3b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 1672*3b2aab18SMatthew Ahrens dmu_recv_end_modified_blocks); 16733cb34c60Sahrens 1674*3b2aab18SMatthew Ahrens if (error != 0) 1675*3b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 1676*3b2aab18SMatthew Ahrens return (error); 1677f18faf3fSek } 1678ae46e4c7SMatthew Ahrens 1679ae46e4c7SMatthew Ahrens static int 1680ae46e4c7SMatthew Ahrens dmu_recv_new_end(dmu_recv_cookie_t *drc) 1681ae46e4c7SMatthew Ahrens { 1682*3b2aab18SMatthew Ahrens int error; 1683ae46e4c7SMatthew Ahrens 1684*3b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 1685*3b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 1686*3b2aab18SMatthew Ahrens dmu_recv_end_modified_blocks); 1687ae46e4c7SMatthew Ahrens 1688*3b2aab18SMatthew Ahrens if (error != 0) { 1689*3b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 1690*3b2aab18SMatthew Ahrens } else if (drc->drc_guid_to_ds_map != NULL) { 1691*3b2aab18SMatthew Ahrens (void) add_ds_to_guidmap(drc->drc_tofs, 1692*3b2aab18SMatthew Ahrens drc->drc_guid_to_ds_map, 1693*3b2aab18SMatthew Ahrens drc->drc_newsnapobj); 1694ae46e4c7SMatthew Ahrens } 1695*3b2aab18SMatthew Ahrens return (error); 1696ae46e4c7SMatthew Ahrens } 1697ae46e4c7SMatthew Ahrens 1698ae46e4c7SMatthew Ahrens int 1699ae46e4c7SMatthew Ahrens dmu_recv_end(dmu_recv_cookie_t *drc) 1700ae46e4c7SMatthew Ahrens { 1701*3b2aab18SMatthew Ahrens if (drc->drc_newfs) 1702ae46e4c7SMatthew Ahrens return (dmu_recv_new_end(drc)); 1703*3b2aab18SMatthew Ahrens else 1704*3b2aab18SMatthew Ahrens return (dmu_recv_existing_end(drc)); 1705ae46e4c7SMatthew Ahrens } 1706