dmu_send.c revision 260150
1168404Spjd/* 2168404Spjd * CDDL HEADER START 3168404Spjd * 4168404Spjd * The contents of this file are subject to the terms of the 5168404Spjd * Common Development and Distribution License (the "License"). 6168404Spjd * You may not use this file except in compliance with the License. 7168404Spjd * 8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9168404Spjd * or http://www.opensolaris.org/os/licensing. 10168404Spjd * See the License for the specific language governing permissions 11168404Spjd * and limitations under the License. 12168404Spjd * 13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each 14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15168404Spjd * If applicable, add the following below this CDDL HEADER, with the 16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18168404Spjd * 19168404Spjd * CDDL HEADER END 20168404Spjd */ 21168404Spjd/* 22219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23221263Smm * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24249195Smm * Copyright (c) 2013 by Delphix. All rights reserved. 25235222Smm * Copyright (c) 2012, Joyent, Inc. All rights reserved. 26235222Smm * Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>. All rights reserved. 27221263Smm */ 28168404Spjd 29168404Spjd#include <sys/dmu.h> 30168404Spjd#include <sys/dmu_impl.h> 31168404Spjd#include <sys/dmu_tx.h> 32168404Spjd#include <sys/dbuf.h> 33168404Spjd#include <sys/dnode.h> 34168404Spjd#include <sys/zfs_context.h> 35168404Spjd#include <sys/dmu_objset.h> 36168404Spjd#include <sys/dmu_traverse.h> 37168404Spjd#include <sys/dsl_dataset.h> 38168404Spjd#include <sys/dsl_dir.h> 39219089Spjd#include <sys/dsl_prop.h> 40168404Spjd#include <sys/dsl_pool.h> 41168404Spjd#include <sys/dsl_synctask.h> 42168404Spjd#include <sys/zfs_ioctl.h> 43168404Spjd#include <sys/zap.h> 44168404Spjd#include <sys/zio_checksum.h> 45219089Spjd#include <sys/zfs_znode.h> 46219089Spjd#include <zfs_fletcher.h> 47219089Spjd#include <sys/avl.h> 48219089Spjd#include <sys/ddt.h> 49219089Spjd#include <sys/zfs_onexit.h> 50248571Smm#include <sys/dmu_send.h> 51248571Smm#include <sys/dsl_destroy.h> 52168404Spjd 53228103Smm/* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 54228103Smmint zfs_send_corrupt_data = B_FALSE; 55228103Smm 56185029Spjdstatic char *dmu_recv_tag = "dmu_recv_tag"; 57248571Smmstatic const char *recv_clone_name = "%recv"; 58185029Spjd 59168404Spjdstatic int 60235222Smmdump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 61168404Spjd{ 62235222Smm dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 63168404Spjd struct uio auio; 64168404Spjd struct iovec aiov; 65240415Smm ASSERT0(len % 8); 66168404Spjd 67235222Smm fletcher_4_incremental_native(buf, len, &dsp->dsa_zc); 68168404Spjd aiov.iov_base = buf; 69168404Spjd aiov.iov_len = len; 70168404Spjd auio.uio_iov = &aiov; 71168404Spjd auio.uio_iovcnt = 1; 72168404Spjd auio.uio_resid = len; 73169170Spjd auio.uio_segflg = UIO_SYSSPACE; 74168404Spjd auio.uio_rw = UIO_WRITE; 75168404Spjd auio.uio_offset = (off_t)-1; 76235222Smm auio.uio_td = dsp->dsa_td; 77168404Spjd#ifdef _KERNEL 78235222Smm if (dsp->dsa_fp->f_type == DTYPE_VNODE) 79168404Spjd bwillwrite(); 80235222Smm dsp->dsa_err = fo_write(dsp->dsa_fp, &auio, dsp->dsa_td->td_ucred, 0, 81235222Smm dsp->dsa_td); 82168404Spjd#else 83168404Spjd fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__); 84235222Smm dsp->dsa_err = EOPNOTSUPP; 85168404Spjd#endif 86235222Smm mutex_enter(&ds->ds_sendstream_lock); 87235222Smm *dsp->dsa_off += len; 88235222Smm mutex_exit(&ds->ds_sendstream_lock); 89235222Smm 90235222Smm return (dsp->dsa_err); 91168404Spjd} 92168404Spjd 93168404Spjdstatic int 94235222Smmdump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 95168404Spjd uint64_t length) 96168404Spjd{ 97235222Smm struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free); 98219089Spjd 99253821Sdelphij /* 100253821Sdelphij * When we receive a free record, dbuf_free_range() assumes 101253821Sdelphij * that the receiving system doesn't have any dbufs in the range 102253821Sdelphij * being freed. This is always true because there is a one-record 103253821Sdelphij * constraint: we only send one WRITE record for any given 104253821Sdelphij * object+offset. We know that the one-record constraint is 105253821Sdelphij * true because we always send data in increasing order by 106253821Sdelphij * object,offset. 107253821Sdelphij * 108253821Sdelphij * If the increasing-order constraint ever changes, we should find 109253821Sdelphij * another way to assert that the one-record constraint is still 110253821Sdelphij * satisfied. 111253821Sdelphij */ 112253821Sdelphij ASSERT(object > dsp->dsa_last_data_object || 113253821Sdelphij (object == dsp->dsa_last_data_object && 114253821Sdelphij offset > dsp->dsa_last_data_offset)); 115253821Sdelphij 116253821Sdelphij /* 117253821Sdelphij * If we are doing a non-incremental send, then there can't 118253821Sdelphij * be any data in the dataset we're receiving into. Therefore 119253821Sdelphij * a free record would simply be a no-op. Save space by not 120253821Sdelphij * sending it to begin with. 121253821Sdelphij */ 122253821Sdelphij if (!dsp->dsa_incremental) 123253821Sdelphij return (0); 124253821Sdelphij 125237458Smm if (length != -1ULL && offset + length < offset) 126237458Smm length = -1ULL; 127237458Smm 128219089Spjd /* 129219089Spjd * If there is a pending op, but it's not PENDING_FREE, push it out, 130219089Spjd * since free block aggregation can only be done for blocks of the 131219089Spjd * same type (i.e., DRR_FREE records can only be aggregated with 132219089Spjd * other DRR_FREE records. DRR_FREEOBJECTS records can only be 133219089Spjd * aggregated with other DRR_FREEOBJECTS records. 134219089Spjd */ 135235222Smm if (dsp->dsa_pending_op != PENDING_NONE && 136235222Smm dsp->dsa_pending_op != PENDING_FREE) { 137235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 138235222Smm sizeof (dmu_replay_record_t)) != 0) 139249195Smm return (SET_ERROR(EINTR)); 140235222Smm dsp->dsa_pending_op = PENDING_NONE; 141219089Spjd } 142219089Spjd 143235222Smm if (dsp->dsa_pending_op == PENDING_FREE) { 144219089Spjd /* 145219089Spjd * There should never be a PENDING_FREE if length is -1 146219089Spjd * (because dump_dnode is the only place where this 147219089Spjd * function is called with a -1, and only after flushing 148219089Spjd * any pending record). 149219089Spjd */ 150219089Spjd ASSERT(length != -1ULL); 151219089Spjd /* 152219089Spjd * Check to see whether this free block can be aggregated 153219089Spjd * with pending one. 154219089Spjd */ 155219089Spjd if (drrf->drr_object == object && drrf->drr_offset + 156219089Spjd drrf->drr_length == offset) { 157219089Spjd drrf->drr_length += length; 158219089Spjd return (0); 159219089Spjd } else { 160219089Spjd /* not a continuation. Push out pending record */ 161235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 162219089Spjd sizeof (dmu_replay_record_t)) != 0) 163249195Smm return (SET_ERROR(EINTR)); 164235222Smm dsp->dsa_pending_op = PENDING_NONE; 165219089Spjd } 166219089Spjd } 167219089Spjd /* create a FREE record and make it pending */ 168235222Smm bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 169235222Smm dsp->dsa_drr->drr_type = DRR_FREE; 170219089Spjd drrf->drr_object = object; 171219089Spjd drrf->drr_offset = offset; 172219089Spjd drrf->drr_length = length; 173235222Smm drrf->drr_toguid = dsp->dsa_toguid; 174219089Spjd if (length == -1ULL) { 175235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 176235222Smm sizeof (dmu_replay_record_t)) != 0) 177249195Smm return (SET_ERROR(EINTR)); 178219089Spjd } else { 179235222Smm dsp->dsa_pending_op = PENDING_FREE; 180219089Spjd } 181168404Spjd 182168404Spjd return (0); 183168404Spjd} 184168404Spjd 185168404Spjdstatic int 186235222Smmdump_data(dmu_sendarg_t *dsp, dmu_object_type_t type, 187219089Spjd uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) 188168404Spjd{ 189235222Smm struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write); 190219089Spjd 191253821Sdelphij /* 192253821Sdelphij * We send data in increasing object, offset order. 193253821Sdelphij * See comment in dump_free() for details. 194253821Sdelphij */ 195253821Sdelphij ASSERT(object > dsp->dsa_last_data_object || 196253821Sdelphij (object == dsp->dsa_last_data_object && 197253821Sdelphij offset > dsp->dsa_last_data_offset)); 198253821Sdelphij dsp->dsa_last_data_object = object; 199253821Sdelphij dsp->dsa_last_data_offset = offset + blksz - 1; 200219089Spjd 201219089Spjd /* 202219089Spjd * If there is any kind of pending aggregation (currently either 203219089Spjd * a grouping of free objects or free blocks), push it out to 204219089Spjd * the stream, since aggregation can't be done across operations 205219089Spjd * of different types. 206219089Spjd */ 207235222Smm if (dsp->dsa_pending_op != PENDING_NONE) { 208235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 209235222Smm sizeof (dmu_replay_record_t)) != 0) 210249195Smm return (SET_ERROR(EINTR)); 211235222Smm dsp->dsa_pending_op = PENDING_NONE; 212219089Spjd } 213168404Spjd /* write a DATA record */ 214235222Smm bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 215235222Smm dsp->dsa_drr->drr_type = DRR_WRITE; 216219089Spjd drrw->drr_object = object; 217219089Spjd drrw->drr_type = type; 218219089Spjd drrw->drr_offset = offset; 219219089Spjd drrw->drr_length = blksz; 220235222Smm drrw->drr_toguid = dsp->dsa_toguid; 221219089Spjd drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); 222219089Spjd if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) 223219089Spjd drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; 224219089Spjd DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); 225219089Spjd DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); 226219089Spjd DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); 227219089Spjd drrw->drr_key.ddk_cksum = bp->blk_cksum; 228168404Spjd 229235222Smm if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 230249195Smm return (SET_ERROR(EINTR)); 231235222Smm if (dump_bytes(dsp, data, blksz) != 0) 232249195Smm return (SET_ERROR(EINTR)); 233219089Spjd return (0); 234219089Spjd} 235219089Spjd 236219089Spjdstatic int 237235222Smmdump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data) 238219089Spjd{ 239235222Smm struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill); 240219089Spjd 241235222Smm if (dsp->dsa_pending_op != PENDING_NONE) { 242235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 243235222Smm sizeof (dmu_replay_record_t)) != 0) 244249195Smm return (SET_ERROR(EINTR)); 245235222Smm dsp->dsa_pending_op = PENDING_NONE; 246219089Spjd } 247219089Spjd 248219089Spjd /* write a SPILL record */ 249235222Smm bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 250235222Smm dsp->dsa_drr->drr_type = DRR_SPILL; 251219089Spjd drrs->drr_object = object; 252219089Spjd drrs->drr_length = blksz; 253235222Smm drrs->drr_toguid = dsp->dsa_toguid; 254219089Spjd 255235222Smm if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t))) 256249195Smm return (SET_ERROR(EINTR)); 257235222Smm if (dump_bytes(dsp, data, blksz)) 258249195Smm return (SET_ERROR(EINTR)); 259168404Spjd return (0); 260168404Spjd} 261168404Spjd 262168404Spjdstatic int 263235222Smmdump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs) 264168404Spjd{ 265235222Smm struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects); 266219089Spjd 267253821Sdelphij /* See comment in dump_free(). */ 268253821Sdelphij if (!dsp->dsa_incremental) 269253821Sdelphij return (0); 270253821Sdelphij 271219089Spjd /* 272219089Spjd * If there is a pending op, but it's not PENDING_FREEOBJECTS, 273219089Spjd * push it out, since free block aggregation can only be done for 274219089Spjd * blocks of the same type (i.e., DRR_FREE records can only be 275219089Spjd * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records 276219089Spjd * can only be aggregated with other DRR_FREEOBJECTS records. 277219089Spjd */ 278235222Smm if (dsp->dsa_pending_op != PENDING_NONE && 279235222Smm dsp->dsa_pending_op != PENDING_FREEOBJECTS) { 280235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 281235222Smm sizeof (dmu_replay_record_t)) != 0) 282249195Smm return (SET_ERROR(EINTR)); 283235222Smm dsp->dsa_pending_op = PENDING_NONE; 284219089Spjd } 285235222Smm if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) { 286219089Spjd /* 287219089Spjd * See whether this free object array can be aggregated 288219089Spjd * with pending one 289219089Spjd */ 290219089Spjd if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { 291219089Spjd drrfo->drr_numobjs += numobjs; 292219089Spjd return (0); 293219089Spjd } else { 294219089Spjd /* can't be aggregated. Push out pending record */ 295235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 296219089Spjd sizeof (dmu_replay_record_t)) != 0) 297249195Smm return (SET_ERROR(EINTR)); 298235222Smm dsp->dsa_pending_op = PENDING_NONE; 299219089Spjd } 300219089Spjd } 301219089Spjd 302168404Spjd /* write a FREEOBJECTS record */ 303235222Smm bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 304235222Smm dsp->dsa_drr->drr_type = DRR_FREEOBJECTS; 305219089Spjd drrfo->drr_firstobj = firstobj; 306219089Spjd drrfo->drr_numobjs = numobjs; 307235222Smm drrfo->drr_toguid = dsp->dsa_toguid; 308168404Spjd 309235222Smm dsp->dsa_pending_op = PENDING_FREEOBJECTS; 310219089Spjd 311168404Spjd return (0); 312168404Spjd} 313168404Spjd 314168404Spjdstatic int 315235222Smmdump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp) 316168404Spjd{ 317235222Smm struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object); 318219089Spjd 319168404Spjd if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 320235222Smm return (dump_freeobjects(dsp, object, 1)); 321168404Spjd 322235222Smm if (dsp->dsa_pending_op != PENDING_NONE) { 323235222Smm if (dump_bytes(dsp, dsp->dsa_drr, 324235222Smm sizeof (dmu_replay_record_t)) != 0) 325249195Smm return (SET_ERROR(EINTR)); 326235222Smm dsp->dsa_pending_op = PENDING_NONE; 327219089Spjd } 328219089Spjd 329168404Spjd /* write an OBJECT record */ 330235222Smm bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 331235222Smm dsp->dsa_drr->drr_type = DRR_OBJECT; 332219089Spjd drro->drr_object = object; 333219089Spjd drro->drr_type = dnp->dn_type; 334219089Spjd drro->drr_bonustype = dnp->dn_bonustype; 335219089Spjd drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 336219089Spjd drro->drr_bonuslen = dnp->dn_bonuslen; 337219089Spjd drro->drr_checksumtype = dnp->dn_checksum; 338219089Spjd drro->drr_compress = dnp->dn_compress; 339235222Smm drro->drr_toguid = dsp->dsa_toguid; 340168404Spjd 341235222Smm if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 342249195Smm return (SET_ERROR(EINTR)); 343168404Spjd 344235222Smm if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 345249195Smm return (SET_ERROR(EINTR)); 346168404Spjd 347253821Sdelphij /* Free anything past the end of the file. */ 348235222Smm if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 349253821Sdelphij (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL) != 0) 350249195Smm return (SET_ERROR(EINTR)); 351248571Smm if (dsp->dsa_err != 0) 352249195Smm return (SET_ERROR(EINTR)); 353168404Spjd return (0); 354168404Spjd} 355168404Spjd 356168404Spjd#define BP_SPAN(dnp, level) \ 357168404Spjd (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 358168404Spjd (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 359168404Spjd 360219089Spjd/* ARGSUSED */ 361168404Spjdstatic int 362246666Smmbackup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 363219089Spjd const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 364168404Spjd{ 365235222Smm dmu_sendarg_t *dsp = arg; 366168404Spjd dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 367168404Spjd int err = 0; 368168404Spjd 369185029Spjd if (issig(JUSTLOOKING) && issig(FORREAL)) 370249195Smm return (SET_ERROR(EINTR)); 371168404Spjd 372219089Spjd if (zb->zb_object != DMU_META_DNODE_OBJECT && 373219089Spjd DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 374209962Smm return (0); 375260150Sdelphij } else if (BP_IS_HOLE(bp) && 376260150Sdelphij zb->zb_object == DMU_META_DNODE_OBJECT) { 377208047Smm uint64_t span = BP_SPAN(dnp, zb->zb_level); 378208047Smm uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 379235222Smm err = dump_freeobjects(dsp, dnobj, span >> DNODE_SHIFT); 380260150Sdelphij } else if (BP_IS_HOLE(bp)) { 381208047Smm uint64_t span = BP_SPAN(dnp, zb->zb_level); 382235222Smm err = dump_free(dsp, zb->zb_object, zb->zb_blkid * span, span); 383208047Smm } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 384208047Smm return (0); 385208047Smm } else if (type == DMU_OT_DNODE) { 386208047Smm dnode_phys_t *blk; 387168404Spjd int i; 388168404Spjd int blksz = BP_GET_LSIZE(bp); 389208047Smm uint32_t aflags = ARC_WAIT; 390208047Smm arc_buf_t *abuf; 391168404Spjd 392246666Smm if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 393246666Smm ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 394246666Smm &aflags, zb) != 0) 395249195Smm return (SET_ERROR(EIO)); 396208047Smm 397208047Smm blk = abuf->b_data; 398168404Spjd for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 399208047Smm uint64_t dnobj = (zb->zb_blkid << 400208047Smm (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 401235222Smm err = dump_dnode(dsp, dnobj, blk+i); 402248571Smm if (err != 0) 403168404Spjd break; 404168404Spjd } 405208047Smm (void) arc_buf_remove_ref(abuf, &abuf); 406219089Spjd } else if (type == DMU_OT_SA) { 407208047Smm uint32_t aflags = ARC_WAIT; 408208047Smm arc_buf_t *abuf; 409168404Spjd int blksz = BP_GET_LSIZE(bp); 410168404Spjd 411246666Smm if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 412246666Smm ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 413246666Smm &aflags, zb) != 0) 414249195Smm return (SET_ERROR(EIO)); 415168404Spjd 416235222Smm err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data); 417219089Spjd (void) arc_buf_remove_ref(abuf, &abuf); 418219089Spjd } else { /* it's a level-0 block of a regular object */ 419219089Spjd uint32_t aflags = ARC_WAIT; 420219089Spjd arc_buf_t *abuf; 421219089Spjd int blksz = BP_GET_LSIZE(bp); 422219089Spjd 423246666Smm if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 424246666Smm ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 425246666Smm &aflags, zb) != 0) { 426228103Smm if (zfs_send_corrupt_data) { 427228103Smm /* Send a block filled with 0x"zfs badd bloc" */ 428228103Smm abuf = arc_buf_alloc(spa, blksz, &abuf, 429228103Smm ARC_BUFC_DATA); 430228103Smm uint64_t *ptr; 431228103Smm for (ptr = abuf->b_data; 432228103Smm (char *)ptr < (char *)abuf->b_data + blksz; 433228103Smm ptr++) 434228103Smm *ptr = 0x2f5baddb10c; 435228103Smm } else { 436249195Smm return (SET_ERROR(EIO)); 437228103Smm } 438228103Smm } 439219089Spjd 440235222Smm err = dump_data(dsp, type, zb->zb_object, zb->zb_blkid * blksz, 441219089Spjd blksz, bp, abuf->b_data); 442208047Smm (void) arc_buf_remove_ref(abuf, &abuf); 443168404Spjd } 444168404Spjd 445168404Spjd ASSERT(err == 0 || err == EINTR); 446168404Spjd return (err); 447168404Spjd} 448168404Spjd 449248571Smm/* 450248571Smm * Releases dp, ds, and fromds, using the specified tag. 451248571Smm */ 452248571Smmstatic int 453248571Smmdmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds, 454248571Smm#ifdef illumos 455248571Smm dsl_dataset_t *fromds, int outfd, vnode_t *vp, offset_t *off) 456248571Smm#else 457248571Smm dsl_dataset_t *fromds, int outfd, struct file *fp, offset_t *off) 458248571Smm#endif 459168404Spjd{ 460248571Smm objset_t *os; 461168404Spjd dmu_replay_record_t *drr; 462235222Smm dmu_sendarg_t *dsp; 463168404Spjd int err; 464185029Spjd uint64_t fromtxg = 0; 465168404Spjd 466248571Smm if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) { 467248571Smm dsl_dataset_rele(fromds, tag); 468248571Smm dsl_dataset_rele(ds, tag); 469248571Smm dsl_pool_rele(dp, tag); 470249195Smm return (SET_ERROR(EXDEV)); 471248571Smm } 472168404Spjd 473248571Smm err = dmu_objset_from_ds(ds, &os); 474248571Smm if (err != 0) { 475248571Smm if (fromds != NULL) 476248571Smm dsl_dataset_rele(fromds, tag); 477248571Smm dsl_dataset_rele(ds, tag); 478248571Smm dsl_pool_rele(dp, tag); 479248571Smm return (err); 480185029Spjd } 481185029Spjd 482168404Spjd drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 483168404Spjd drr->drr_type = DRR_BEGIN; 484168404Spjd drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 485219089Spjd DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 486219089Spjd DMU_SUBSTREAM); 487219089Spjd 488219089Spjd#ifdef _KERNEL 489248571Smm if (dmu_objset_type(os) == DMU_OST_ZFS) { 490219089Spjd uint64_t version; 491248571Smm if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) { 492235222Smm kmem_free(drr, sizeof (dmu_replay_record_t)); 493248571Smm if (fromds != NULL) 494248571Smm dsl_dataset_rele(fromds, tag); 495248571Smm dsl_dataset_rele(ds, tag); 496248571Smm dsl_pool_rele(dp, tag); 497249195Smm return (SET_ERROR(EINVAL)); 498235222Smm } 499248571Smm if (version >= ZPL_VERSION_SA) { 500219089Spjd DMU_SET_FEATUREFLAGS( 501219089Spjd drr->drr_u.drr_begin.drr_versioninfo, 502219089Spjd DMU_BACKUP_FEATURE_SA_SPILL); 503219089Spjd } 504219089Spjd } 505219089Spjd#endif 506219089Spjd 507168404Spjd drr->drr_u.drr_begin.drr_creation_time = 508168404Spjd ds->ds_phys->ds_creation_time; 509248571Smm drr->drr_u.drr_begin.drr_type = dmu_objset_type(os); 510248571Smm if (fromds != NULL && ds->ds_dir != fromds->ds_dir) 511185029Spjd drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 512168404Spjd drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 513185029Spjd if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 514185029Spjd drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 515185029Spjd 516248571Smm if (fromds != NULL) 517168404Spjd drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 518168404Spjd dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 519168404Spjd 520248571Smm if (fromds != NULL) { 521185029Spjd fromtxg = fromds->ds_phys->ds_creation_txg; 522248571Smm dsl_dataset_rele(fromds, tag); 523248571Smm fromds = NULL; 524248571Smm } 525185029Spjd 526235222Smm dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 527168404Spjd 528235222Smm dsp->dsa_drr = drr; 529235222Smm dsp->dsa_outfd = outfd; 530235222Smm dsp->dsa_proc = curproc; 531235222Smm dsp->dsa_td = curthread; 532235222Smm dsp->dsa_fp = fp; 533248571Smm dsp->dsa_os = os; 534235222Smm dsp->dsa_off = off; 535235222Smm dsp->dsa_toguid = ds->ds_phys->ds_guid; 536235222Smm ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 537235222Smm dsp->dsa_pending_op = PENDING_NONE; 538253821Sdelphij dsp->dsa_incremental = (fromtxg != 0); 539235222Smm 540235222Smm mutex_enter(&ds->ds_sendstream_lock); 541235222Smm list_insert_head(&ds->ds_sendstreams, dsp); 542235222Smm mutex_exit(&ds->ds_sendstream_lock); 543235222Smm 544249042Smm dsl_dataset_long_hold(ds, FTAG); 545249042Smm dsl_pool_rele(dp, tag); 546249042Smm 547235222Smm if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 548235222Smm err = dsp->dsa_err; 549235222Smm goto out; 550168404Spjd } 551168404Spjd 552208047Smm err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 553235222Smm backup_cb, dsp); 554168404Spjd 555235222Smm if (dsp->dsa_pending_op != PENDING_NONE) 556235222Smm if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 557249195Smm err = SET_ERROR(EINTR); 558219089Spjd 559248571Smm if (err != 0) { 560248571Smm if (err == EINTR && dsp->dsa_err != 0) 561235222Smm err = dsp->dsa_err; 562235222Smm goto out; 563168404Spjd } 564168404Spjd 565168404Spjd bzero(drr, sizeof (dmu_replay_record_t)); 566168404Spjd drr->drr_type = DRR_END; 567235222Smm drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 568235222Smm drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; 569168404Spjd 570235222Smm if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 571235222Smm err = dsp->dsa_err; 572235222Smm goto out; 573168404Spjd } 574168404Spjd 575235222Smmout: 576235222Smm mutex_enter(&ds->ds_sendstream_lock); 577235222Smm list_remove(&ds->ds_sendstreams, dsp); 578235222Smm mutex_exit(&ds->ds_sendstream_lock); 579235222Smm 580168404Spjd kmem_free(drr, sizeof (dmu_replay_record_t)); 581235222Smm kmem_free(dsp, sizeof (dmu_sendarg_t)); 582168404Spjd 583248571Smm dsl_dataset_long_rele(ds, FTAG); 584248571Smm dsl_dataset_rele(ds, tag); 585248571Smm 586235222Smm return (err); 587168404Spjd} 588168404Spjd 589228103Smmint 590248571Smmdmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, 591248571Smm#ifdef illumos 592248571Smm int outfd, vnode_t *vp, offset_t *off) 593248571Smm#else 594248571Smm int outfd, struct file *fp, offset_t *off) 595248571Smm#endif 596228103Smm{ 597248571Smm dsl_pool_t *dp; 598248571Smm dsl_dataset_t *ds; 599248571Smm dsl_dataset_t *fromds = NULL; 600248571Smm int err; 601248571Smm 602248571Smm err = dsl_pool_hold(pool, FTAG, &dp); 603248571Smm if (err != 0) 604248571Smm return (err); 605248571Smm 606248571Smm err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds); 607248571Smm if (err != 0) { 608248571Smm dsl_pool_rele(dp, FTAG); 609248571Smm return (err); 610248571Smm } 611248571Smm 612248571Smm if (fromsnap != 0) { 613248571Smm err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds); 614248571Smm if (err != 0) { 615248571Smm dsl_dataset_rele(ds, FTAG); 616248571Smm dsl_pool_rele(dp, FTAG); 617248571Smm return (err); 618248571Smm } 619248571Smm } 620248571Smm 621248571Smm return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, fp, off)); 622248571Smm} 623248571Smm 624248571Smmint 625248571Smmdmu_send(const char *tosnap, const char *fromsnap, 626248571Smm#ifdef illumos 627248571Smm int outfd, vnode_t *vp, offset_t *off) 628248571Smm#else 629248571Smm int outfd, struct file *fp, offset_t *off) 630248571Smm#endif 631248571Smm{ 632248571Smm dsl_pool_t *dp; 633248571Smm dsl_dataset_t *ds; 634248571Smm dsl_dataset_t *fromds = NULL; 635248571Smm int err; 636248571Smm 637248571Smm if (strchr(tosnap, '@') == NULL) 638249195Smm return (SET_ERROR(EINVAL)); 639248571Smm if (fromsnap != NULL && strchr(fromsnap, '@') == NULL) 640249195Smm return (SET_ERROR(EINVAL)); 641248571Smm 642248571Smm err = dsl_pool_hold(tosnap, FTAG, &dp); 643248571Smm if (err != 0) 644248571Smm return (err); 645248571Smm 646248571Smm err = dsl_dataset_hold(dp, tosnap, FTAG, &ds); 647248571Smm if (err != 0) { 648248571Smm dsl_pool_rele(dp, FTAG); 649248571Smm return (err); 650248571Smm } 651248571Smm 652248571Smm if (fromsnap != NULL) { 653248571Smm err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds); 654248571Smm if (err != 0) { 655248571Smm dsl_dataset_rele(ds, FTAG); 656248571Smm dsl_pool_rele(dp, FTAG); 657248571Smm return (err); 658248571Smm } 659248571Smm } 660248571Smm return (dmu_send_impl(FTAG, dp, ds, fromds, outfd, fp, off)); 661248571Smm} 662248571Smm 663248571Smmint 664248571Smmdmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep) 665248571Smm{ 666228103Smm dsl_pool_t *dp = ds->ds_dir->dd_pool; 667228103Smm int err; 668228103Smm uint64_t size; 669228103Smm 670248571Smm ASSERT(dsl_pool_config_held(dp)); 671248571Smm 672228103Smm /* tosnap must be a snapshot */ 673248571Smm if (!dsl_dataset_is_snapshot(ds)) 674249195Smm return (SET_ERROR(EINVAL)); 675228103Smm 676248571Smm /* 677248571Smm * fromsnap must be an earlier snapshot from the same fs as tosnap, 678248571Smm * or the origin's fs. 679248571Smm */ 680248571Smm if (fromds != NULL && !dsl_dataset_is_before(ds, fromds)) 681249195Smm return (SET_ERROR(EXDEV)); 682228103Smm 683228103Smm /* Get uncompressed size estimate of changed data. */ 684228103Smm if (fromds == NULL) { 685228103Smm size = ds->ds_phys->ds_uncompressed_bytes; 686228103Smm } else { 687228103Smm uint64_t used, comp; 688228103Smm err = dsl_dataset_space_written(fromds, ds, 689228103Smm &used, &comp, &size); 690248571Smm if (err != 0) 691228103Smm return (err); 692228103Smm } 693228103Smm 694228103Smm /* 695228103Smm * Assume that space (both on-disk and in-stream) is dominated by 696228103Smm * data. We will adjust for indirect blocks and the copies property, 697228103Smm * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 698228103Smm */ 699228103Smm 700228103Smm /* 701228103Smm * Subtract out approximate space used by indirect blocks. 702228103Smm * Assume most space is used by data blocks (non-indirect, non-dnode). 703228103Smm * Assume all blocks are recordsize. Assume ditto blocks and 704228103Smm * internal fragmentation counter out compression. 705228103Smm * 706228103Smm * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 707228103Smm * block, which we observe in practice. 708228103Smm */ 709228103Smm uint64_t recordsize; 710248571Smm err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize); 711248571Smm if (err != 0) 712228103Smm return (err); 713228103Smm size -= size / recordsize * sizeof (blkptr_t); 714228103Smm 715228103Smm /* Add in the space for the record associated with each block. */ 716228103Smm size += size / recordsize * sizeof (dmu_replay_record_t); 717228103Smm 718228103Smm *sizep = size; 719228103Smm 720228103Smm return (0); 721228103Smm} 722228103Smm 723248571Smmtypedef struct dmu_recv_begin_arg { 724248571Smm const char *drba_origin; 725248571Smm dmu_recv_cookie_t *drba_cookie; 726248571Smm cred_t *drba_cred; 727253820Sdelphij uint64_t drba_snapobj; 728248571Smm} dmu_recv_begin_arg_t; 729168404Spjd 730168404Spjdstatic int 731248571Smmrecv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds, 732248571Smm uint64_t fromguid) 733168404Spjd{ 734185029Spjd uint64_t val; 735248571Smm int error; 736248571Smm dsl_pool_t *dp = ds->ds_dir->dd_pool; 737185029Spjd 738248571Smm /* temporary clone name must not exist */ 739248571Smm error = zap_lookup(dp->dp_meta_objset, 740248571Smm ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name, 741248571Smm 8, 1, &val); 742248571Smm if (error != ENOENT) 743248571Smm return (error == 0 ? EBUSY : error); 744248571Smm 745219089Spjd /* new snapshot name must not exist */ 746248571Smm error = zap_lookup(dp->dp_meta_objset, 747248571Smm ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap, 748248571Smm 8, 1, &val); 749248571Smm if (error != ENOENT) 750248571Smm return (error == 0 ? EEXIST : error); 751168404Spjd 752248571Smm if (fromguid != 0) { 753253820Sdelphij dsl_dataset_t *snap; 754253820Sdelphij uint64_t obj = ds->ds_phys->ds_prev_snap_obj; 755253820Sdelphij 756253820Sdelphij /* Find snapshot in this dir that matches fromguid. */ 757253820Sdelphij while (obj != 0) { 758253820Sdelphij error = dsl_dataset_hold_obj(dp, obj, FTAG, 759253820Sdelphij &snap); 760253820Sdelphij if (error != 0) 761253820Sdelphij return (SET_ERROR(ENODEV)); 762253820Sdelphij if (snap->ds_dir != ds->ds_dir) { 763253820Sdelphij dsl_dataset_rele(snap, FTAG); 764253820Sdelphij return (SET_ERROR(ENODEV)); 765253820Sdelphij } 766253820Sdelphij if (snap->ds_phys->ds_guid == fromguid) 767253820Sdelphij break; 768253820Sdelphij obj = snap->ds_phys->ds_prev_snap_obj; 769253820Sdelphij dsl_dataset_rele(snap, FTAG); 770253820Sdelphij } 771253820Sdelphij if (obj == 0) 772249195Smm return (SET_ERROR(ENODEV)); 773168404Spjd 774253820Sdelphij if (drba->drba_cookie->drc_force) { 775253820Sdelphij drba->drba_snapobj = obj; 776253820Sdelphij } else { 777253820Sdelphij /* 778253820Sdelphij * If we are not forcing, there must be no 779253820Sdelphij * changes since fromsnap. 780253820Sdelphij */ 781253820Sdelphij if (dsl_dataset_modified_since_snap(ds, snap)) { 782219089Spjd dsl_dataset_rele(snap, FTAG); 783253820Sdelphij return (SET_ERROR(ETXTBSY)); 784219089Spjd } 785253820Sdelphij drba->drba_snapobj = ds->ds_prev->ds_object; 786219089Spjd } 787253820Sdelphij 788253820Sdelphij dsl_dataset_rele(snap, FTAG); 789219089Spjd } else { 790219089Spjd /* if full, most recent snapshot must be $ORIGIN */ 791219089Spjd if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 792249195Smm return (SET_ERROR(ENODEV)); 793253820Sdelphij drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj; 794219089Spjd } 795219089Spjd 796248571Smm return (0); 797168404Spjd 798168404Spjd} 799168404Spjd 800248571Smmstatic int 801248571Smmdmu_recv_begin_check(void *arg, dmu_tx_t *tx) 802248571Smm{ 803248571Smm dmu_recv_begin_arg_t *drba = arg; 804248571Smm dsl_pool_t *dp = dmu_tx_pool(tx); 805248571Smm struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 806248571Smm uint64_t fromguid = drrb->drr_fromguid; 807248571Smm int flags = drrb->drr_flags; 808248571Smm int error; 809248571Smm dsl_dataset_t *ds; 810248571Smm const char *tofs = drba->drba_cookie->drc_tofs; 811248571Smm 812248571Smm /* already checked */ 813248571Smm ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 814248571Smm 815248571Smm if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == 816248571Smm DMU_COMPOUNDSTREAM || 817248571Smm drrb->drr_type >= DMU_OST_NUMTYPES || 818248571Smm ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) 819249195Smm return (SET_ERROR(EINVAL)); 820248571Smm 821248571Smm /* Verify pool version supports SA if SA_SPILL feature set */ 822248571Smm if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) & 823248571Smm DMU_BACKUP_FEATURE_SA_SPILL) && 824248571Smm spa_version(dp->dp_spa) < SPA_VERSION_SA) { 825249195Smm return (SET_ERROR(ENOTSUP)); 826248571Smm } 827248571Smm 828248571Smm error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 829248571Smm if (error == 0) { 830248571Smm /* target fs already exists; recv into temp clone */ 831248571Smm 832248571Smm /* Can't recv a clone into an existing fs */ 833248571Smm if (flags & DRR_FLAG_CLONE) { 834248571Smm dsl_dataset_rele(ds, FTAG); 835249195Smm return (SET_ERROR(EINVAL)); 836248571Smm } 837248571Smm 838248571Smm error = recv_begin_check_existing_impl(drba, ds, fromguid); 839248571Smm dsl_dataset_rele(ds, FTAG); 840248571Smm } else if (error == ENOENT) { 841248571Smm /* target fs does not exist; must be a full backup or clone */ 842248571Smm char buf[MAXNAMELEN]; 843248571Smm 844248571Smm /* 845248571Smm * If it's a non-clone incremental, we are missing the 846248571Smm * target fs, so fail the recv. 847248571Smm */ 848248571Smm if (fromguid != 0 && !(flags & DRR_FLAG_CLONE)) 849249195Smm return (SET_ERROR(ENOENT)); 850248571Smm 851248571Smm /* Open the parent of tofs */ 852248571Smm ASSERT3U(strlen(tofs), <, MAXNAMELEN); 853248571Smm (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1); 854248571Smm error = dsl_dataset_hold(dp, buf, FTAG, &ds); 855248571Smm if (error != 0) 856248571Smm return (error); 857248571Smm 858248571Smm if (drba->drba_origin != NULL) { 859248571Smm dsl_dataset_t *origin; 860248571Smm error = dsl_dataset_hold(dp, drba->drba_origin, 861248571Smm FTAG, &origin); 862248571Smm if (error != 0) { 863248571Smm dsl_dataset_rele(ds, FTAG); 864248571Smm return (error); 865248571Smm } 866248571Smm if (!dsl_dataset_is_snapshot(origin)) { 867248571Smm dsl_dataset_rele(origin, FTAG); 868248571Smm dsl_dataset_rele(ds, FTAG); 869249195Smm return (SET_ERROR(EINVAL)); 870248571Smm } 871248571Smm if (origin->ds_phys->ds_guid != fromguid) { 872248571Smm dsl_dataset_rele(origin, FTAG); 873248571Smm dsl_dataset_rele(ds, FTAG); 874249195Smm return (SET_ERROR(ENODEV)); 875248571Smm } 876248571Smm dsl_dataset_rele(origin, FTAG); 877248571Smm } 878248571Smm dsl_dataset_rele(ds, FTAG); 879248571Smm error = 0; 880248571Smm } 881248571Smm return (error); 882248571Smm} 883248571Smm 884168404Spjdstatic void 885248571Smmdmu_recv_begin_sync(void *arg, dmu_tx_t *tx) 886168404Spjd{ 887248571Smm dmu_recv_begin_arg_t *drba = arg; 888248571Smm dsl_pool_t *dp = dmu_tx_pool(tx); 889248571Smm struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 890248571Smm const char *tofs = drba->drba_cookie->drc_tofs; 891248571Smm dsl_dataset_t *ds, *newds; 892185029Spjd uint64_t dsobj; 893248571Smm int error; 894248571Smm uint64_t crflags; 895168404Spjd 896248571Smm crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ? 897248571Smm DS_FLAG_CI_DATASET : 0; 898168404Spjd 899248571Smm error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 900248571Smm if (error == 0) { 901248571Smm /* create temporary clone */ 902253820Sdelphij dsl_dataset_t *snap = NULL; 903253820Sdelphij if (drba->drba_snapobj != 0) { 904253820Sdelphij VERIFY0(dsl_dataset_hold_obj(dp, 905253820Sdelphij drba->drba_snapobj, FTAG, &snap)); 906253820Sdelphij } 907248571Smm dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name, 908253820Sdelphij snap, crflags, drba->drba_cred, tx); 909253820Sdelphij dsl_dataset_rele(snap, FTAG); 910248571Smm dsl_dataset_rele(ds, FTAG); 911248571Smm } else { 912248571Smm dsl_dir_t *dd; 913248571Smm const char *tail; 914248571Smm dsl_dataset_t *origin = NULL; 915248571Smm 916248571Smm VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail)); 917248571Smm 918248571Smm if (drba->drba_origin != NULL) { 919248571Smm VERIFY0(dsl_dataset_hold(dp, drba->drba_origin, 920248571Smm FTAG, &origin)); 921248571Smm } 922248571Smm 923248571Smm /* Create new dataset. */ 924248571Smm dsobj = dsl_dataset_create_sync(dd, 925248571Smm strrchr(tofs, '/') + 1, 926248571Smm origin, crflags, drba->drba_cred, tx); 927248571Smm if (origin != NULL) 928248571Smm dsl_dataset_rele(origin, FTAG); 929248571Smm dsl_dir_rele(dd, FTAG); 930248571Smm drba->drba_cookie->drc_newfs = B_TRUE; 931248571Smm } 932248571Smm VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds)); 933248571Smm 934248571Smm dmu_buf_will_dirty(newds->ds_dbuf, tx); 935248571Smm newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 936248571Smm 937219089Spjd /* 938219089Spjd * If we actually created a non-clone, we need to create the 939219089Spjd * objset in our new dataset. 940219089Spjd */ 941248571Smm if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) { 942219089Spjd (void) dmu_objset_create_impl(dp->dp_spa, 943248571Smm newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx); 944219089Spjd } 945168404Spjd 946248571Smm drba->drba_cookie->drc_ds = newds; 947185029Spjd 948248571Smm spa_history_log_internal_ds(newds, "receive", tx, ""); 949168404Spjd} 950168404Spjd 951185029Spjd/* 952185029Spjd * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 953185029Spjd * succeeds; otherwise we will leak the holds on the datasets. 954185029Spjd */ 955185029Spjdint 956248571Smmdmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 957248571Smm boolean_t force, char *origin, dmu_recv_cookie_t *drc) 958168404Spjd{ 959248571Smm dmu_recv_begin_arg_t drba = { 0 }; 960248571Smm dmu_replay_record_t *drr; 961168404Spjd 962185029Spjd bzero(drc, sizeof (dmu_recv_cookie_t)); 963185029Spjd drc->drc_drrb = drrb; 964185029Spjd drc->drc_tosnap = tosnap; 965248571Smm drc->drc_tofs = tofs; 966185029Spjd drc->drc_force = force; 967168404Spjd 968248571Smm if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 969248571Smm drc->drc_byteswap = B_TRUE; 970248571Smm else if (drrb->drr_magic != DMU_BACKUP_MAGIC) 971249195Smm return (SET_ERROR(EINVAL)); 972168404Spjd 973248571Smm drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 974248571Smm drr->drr_type = DRR_BEGIN; 975248571Smm drr->drr_u.drr_begin = *drc->drc_drrb; 976248571Smm if (drc->drc_byteswap) { 977248571Smm fletcher_4_incremental_byteswap(drr, 978248571Smm sizeof (dmu_replay_record_t), &drc->drc_cksum); 979248571Smm } else { 980248571Smm fletcher_4_incremental_native(drr, 981248571Smm sizeof (dmu_replay_record_t), &drc->drc_cksum); 982248571Smm } 983248571Smm kmem_free(drr, sizeof (dmu_replay_record_t)); 984219089Spjd 985248571Smm if (drc->drc_byteswap) { 986248571Smm drrb->drr_magic = BSWAP_64(drrb->drr_magic); 987248571Smm drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 988248571Smm drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 989248571Smm drrb->drr_type = BSWAP_32(drrb->drr_type); 990248571Smm drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 991248571Smm drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 992248571Smm } 993168404Spjd 994248571Smm drba.drba_origin = origin; 995248571Smm drba.drba_cookie = drc; 996248571Smm drba.drba_cred = CRED(); 997219089Spjd 998248571Smm return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync, 999248571Smm &drba, 5)); 1000168404Spjd} 1001168404Spjd 1002185029Spjdstruct restorearg { 1003185029Spjd int err; 1004248571Smm boolean_t byteswap; 1005185029Spjd kthread_t *td; 1006185029Spjd struct file *fp; 1007185029Spjd char *buf; 1008185029Spjd uint64_t voff; 1009185029Spjd int bufsize; /* amount of memory allocated for buf */ 1010185029Spjd zio_cksum_t cksum; 1011219089Spjd avl_tree_t *guid_to_ds_map; 1012185029Spjd}; 1013185029Spjd 1014219089Spjdtypedef struct guid_map_entry { 1015219089Spjd uint64_t guid; 1016219089Spjd dsl_dataset_t *gme_ds; 1017219089Spjd avl_node_t avlnode; 1018219089Spjd} guid_map_entry_t; 1019219089Spjd 1020168404Spjdstatic int 1021219089Spjdguid_compare(const void *arg1, const void *arg2) 1022168404Spjd{ 1023219089Spjd const guid_map_entry_t *gmep1 = arg1; 1024219089Spjd const guid_map_entry_t *gmep2 = arg2; 1025219089Spjd 1026219089Spjd if (gmep1->guid < gmep2->guid) 1027219089Spjd return (-1); 1028219089Spjd else if (gmep1->guid > gmep2->guid) 1029219089Spjd return (1); 1030219089Spjd return (0); 1031219089Spjd} 1032219089Spjd 1033219089Spjdstatic void 1034219089Spjdfree_guid_map_onexit(void *arg) 1035219089Spjd{ 1036219089Spjd avl_tree_t *ca = arg; 1037219089Spjd void *cookie = NULL; 1038219089Spjd guid_map_entry_t *gmep; 1039219089Spjd 1040219089Spjd while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { 1041248571Smm dsl_dataset_long_rele(gmep->gme_ds, gmep); 1042249196Smm dsl_dataset_rele(gmep->gme_ds, gmep); 1043219089Spjd kmem_free(gmep, sizeof (guid_map_entry_t)); 1044219089Spjd } 1045219089Spjd avl_destroy(ca); 1046219089Spjd kmem_free(ca, sizeof (avl_tree_t)); 1047219089Spjd} 1048219089Spjd 1049219089Spjdstatic int 1050219089Spjdrestore_bytes(struct restorearg *ra, void *buf, int len, off_t off, ssize_t *resid) 1051219089Spjd{ 1052168404Spjd struct uio auio; 1053168404Spjd struct iovec aiov; 1054168404Spjd int error; 1055168404Spjd 1056168404Spjd aiov.iov_base = buf; 1057168404Spjd aiov.iov_len = len; 1058168404Spjd auio.uio_iov = &aiov; 1059168404Spjd auio.uio_iovcnt = 1; 1060168404Spjd auio.uio_resid = len; 1061169170Spjd auio.uio_segflg = UIO_SYSSPACE; 1062168404Spjd auio.uio_rw = UIO_READ; 1063168404Spjd auio.uio_offset = off; 1064168404Spjd auio.uio_td = ra->td; 1065168404Spjd#ifdef _KERNEL 1066168404Spjd error = fo_read(ra->fp, &auio, ra->td->td_ucred, FOF_OFFSET, ra->td); 1067168404Spjd#else 1068168404Spjd fprintf(stderr, "%s: returning EOPNOTSUPP\n", __func__); 1069168404Spjd error = EOPNOTSUPP; 1070168404Spjd#endif 1071168404Spjd *resid = auio.uio_resid; 1072168404Spjd return (error); 1073168404Spjd} 1074168404Spjd 1075168404Spjdstatic void * 1076168404Spjdrestore_read(struct restorearg *ra, int len) 1077168404Spjd{ 1078168404Spjd void *rv; 1079185029Spjd int done = 0; 1080168404Spjd 1081168404Spjd /* some things will require 8-byte alignment, so everything must */ 1082240415Smm ASSERT0(len % 8); 1083168404Spjd 1084185029Spjd while (done < len) { 1085219089Spjd ssize_t resid; 1086168404Spjd 1087185029Spjd ra->err = restore_bytes(ra, (caddr_t)ra->buf + done, 1088185029Spjd len - done, ra->voff, &resid); 1089168404Spjd 1090185029Spjd if (resid == len - done) 1091249195Smm ra->err = SET_ERROR(EINVAL); 1092185029Spjd ra->voff += len - done - resid; 1093185029Spjd done = len - resid; 1094248571Smm if (ra->err != 0) 1095168404Spjd return (NULL); 1096168404Spjd } 1097168404Spjd 1098185029Spjd ASSERT3U(done, ==, len); 1099185029Spjd rv = ra->buf; 1100168404Spjd if (ra->byteswap) 1101185029Spjd fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 1102168404Spjd else 1103185029Spjd fletcher_4_incremental_native(rv, len, &ra->cksum); 1104168404Spjd return (rv); 1105168404Spjd} 1106168404Spjd 1107168404Spjdstatic void 1108168404Spjdbackup_byteswap(dmu_replay_record_t *drr) 1109168404Spjd{ 1110168404Spjd#define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 1111168404Spjd#define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 1112168404Spjd drr->drr_type = BSWAP_32(drr->drr_type); 1113185029Spjd drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 1114168404Spjd switch (drr->drr_type) { 1115168404Spjd case DRR_BEGIN: 1116168404Spjd DO64(drr_begin.drr_magic); 1117219089Spjd DO64(drr_begin.drr_versioninfo); 1118168404Spjd DO64(drr_begin.drr_creation_time); 1119168404Spjd DO32(drr_begin.drr_type); 1120185029Spjd DO32(drr_begin.drr_flags); 1121168404Spjd DO64(drr_begin.drr_toguid); 1122168404Spjd DO64(drr_begin.drr_fromguid); 1123168404Spjd break; 1124168404Spjd case DRR_OBJECT: 1125168404Spjd DO64(drr_object.drr_object); 1126168404Spjd /* DO64(drr_object.drr_allocation_txg); */ 1127168404Spjd DO32(drr_object.drr_type); 1128168404Spjd DO32(drr_object.drr_bonustype); 1129168404Spjd DO32(drr_object.drr_blksz); 1130168404Spjd DO32(drr_object.drr_bonuslen); 1131219089Spjd DO64(drr_object.drr_toguid); 1132168404Spjd break; 1133168404Spjd case DRR_FREEOBJECTS: 1134168404Spjd DO64(drr_freeobjects.drr_firstobj); 1135168404Spjd DO64(drr_freeobjects.drr_numobjs); 1136219089Spjd DO64(drr_freeobjects.drr_toguid); 1137168404Spjd break; 1138168404Spjd case DRR_WRITE: 1139168404Spjd DO64(drr_write.drr_object); 1140168404Spjd DO32(drr_write.drr_type); 1141168404Spjd DO64(drr_write.drr_offset); 1142168404Spjd DO64(drr_write.drr_length); 1143219089Spjd DO64(drr_write.drr_toguid); 1144219089Spjd DO64(drr_write.drr_key.ddk_cksum.zc_word[0]); 1145219089Spjd DO64(drr_write.drr_key.ddk_cksum.zc_word[1]); 1146219089Spjd DO64(drr_write.drr_key.ddk_cksum.zc_word[2]); 1147219089Spjd DO64(drr_write.drr_key.ddk_cksum.zc_word[3]); 1148219089Spjd DO64(drr_write.drr_key.ddk_prop); 1149168404Spjd break; 1150219089Spjd case DRR_WRITE_BYREF: 1151219089Spjd DO64(drr_write_byref.drr_object); 1152219089Spjd DO64(drr_write_byref.drr_offset); 1153219089Spjd DO64(drr_write_byref.drr_length); 1154219089Spjd DO64(drr_write_byref.drr_toguid); 1155219089Spjd DO64(drr_write_byref.drr_refguid); 1156219089Spjd DO64(drr_write_byref.drr_refobject); 1157219089Spjd DO64(drr_write_byref.drr_refoffset); 1158219089Spjd DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[0]); 1159219089Spjd DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[1]); 1160219089Spjd DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[2]); 1161219089Spjd DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[3]); 1162219089Spjd DO64(drr_write_byref.drr_key.ddk_prop); 1163219089Spjd break; 1164168404Spjd case DRR_FREE: 1165168404Spjd DO64(drr_free.drr_object); 1166168404Spjd DO64(drr_free.drr_offset); 1167168404Spjd DO64(drr_free.drr_length); 1168219089Spjd DO64(drr_free.drr_toguid); 1169168404Spjd break; 1170219089Spjd case DRR_SPILL: 1171219089Spjd DO64(drr_spill.drr_object); 1172219089Spjd DO64(drr_spill.drr_length); 1173219089Spjd DO64(drr_spill.drr_toguid); 1174219089Spjd break; 1175168404Spjd case DRR_END: 1176168404Spjd DO64(drr_end.drr_checksum.zc_word[0]); 1177168404Spjd DO64(drr_end.drr_checksum.zc_word[1]); 1178168404Spjd DO64(drr_end.drr_checksum.zc_word[2]); 1179168404Spjd DO64(drr_end.drr_checksum.zc_word[3]); 1180219089Spjd DO64(drr_end.drr_toguid); 1181168404Spjd break; 1182168404Spjd } 1183168404Spjd#undef DO64 1184168404Spjd#undef DO32 1185168404Spjd} 1186168404Spjd 1187168404Spjdstatic int 1188168404Spjdrestore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 1189168404Spjd{ 1190168404Spjd int err; 1191168404Spjd dmu_tx_t *tx; 1192200727Sdelphij void *data = NULL; 1193168404Spjd 1194168404Spjd if (drro->drr_type == DMU_OT_NONE || 1195236884Smm !DMU_OT_IS_VALID(drro->drr_type) || 1196236884Smm !DMU_OT_IS_VALID(drro->drr_bonustype) || 1197219089Spjd drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || 1198168404Spjd drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 1199168404Spjd P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 1200168404Spjd drro->drr_blksz < SPA_MINBLOCKSIZE || 1201168404Spjd drro->drr_blksz > SPA_MAXBLOCKSIZE || 1202168404Spjd drro->drr_bonuslen > DN_MAX_BONUSLEN) { 1203249195Smm return (SET_ERROR(EINVAL)); 1204168404Spjd } 1205168404Spjd 1206200726Sdelphij err = dmu_object_info(os, drro->drr_object, NULL); 1207168404Spjd 1208200726Sdelphij if (err != 0 && err != ENOENT) 1209249195Smm return (SET_ERROR(EINVAL)); 1210200726Sdelphij 1211201756Sdelphij if (drro->drr_bonuslen) { 1212201756Sdelphij data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 1213248571Smm if (ra->err != 0) 1214201756Sdelphij return (ra->err); 1215201756Sdelphij } 1216201756Sdelphij 1217168404Spjd if (err == ENOENT) { 1218168404Spjd /* currently free, want to be allocated */ 1219200726Sdelphij tx = dmu_tx_create(os); 1220168404Spjd dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1221168404Spjd err = dmu_tx_assign(tx, TXG_WAIT); 1222248571Smm if (err != 0) { 1223168404Spjd dmu_tx_abort(tx); 1224168404Spjd return (err); 1225168404Spjd } 1226168404Spjd err = dmu_object_claim(os, drro->drr_object, 1227168404Spjd drro->drr_type, drro->drr_blksz, 1228168404Spjd drro->drr_bonustype, drro->drr_bonuslen, tx); 1229200726Sdelphij dmu_tx_commit(tx); 1230168404Spjd } else { 1231168404Spjd /* currently allocated, want to be allocated */ 1232168404Spjd err = dmu_object_reclaim(os, drro->drr_object, 1233168404Spjd drro->drr_type, drro->drr_blksz, 1234200726Sdelphij drro->drr_bonustype, drro->drr_bonuslen); 1235168404Spjd } 1236248571Smm if (err != 0) { 1237249195Smm return (SET_ERROR(EINVAL)); 1238219089Spjd } 1239200726Sdelphij 1240200726Sdelphij tx = dmu_tx_create(os); 1241200726Sdelphij dmu_tx_hold_bonus(tx, drro->drr_object); 1242200726Sdelphij err = dmu_tx_assign(tx, TXG_WAIT); 1243248571Smm if (err != 0) { 1244200726Sdelphij dmu_tx_abort(tx); 1245200726Sdelphij return (err); 1246168404Spjd } 1247168404Spjd 1248219089Spjd dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 1249219089Spjd tx); 1250168404Spjd dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1251168404Spjd 1252200727Sdelphij if (data != NULL) { 1253168404Spjd dmu_buf_t *db; 1254200727Sdelphij 1255168404Spjd VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 1256168404Spjd dmu_buf_will_dirty(db, tx); 1257168404Spjd 1258185029Spjd ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 1259185029Spjd bcopy(data, db->db_data, drro->drr_bonuslen); 1260168404Spjd if (ra->byteswap) { 1261236884Smm dmu_object_byteswap_t byteswap = 1262236884Smm DMU_OT_BYTESWAP(drro->drr_bonustype); 1263236884Smm dmu_ot_byteswap[byteswap].ob_func(db->db_data, 1264168404Spjd drro->drr_bonuslen); 1265168404Spjd } 1266168404Spjd dmu_buf_rele(db, FTAG); 1267168404Spjd } 1268168404Spjd dmu_tx_commit(tx); 1269168404Spjd return (0); 1270168404Spjd} 1271168404Spjd 1272168404Spjd/* ARGSUSED */ 1273168404Spjdstatic int 1274168404Spjdrestore_freeobjects(struct restorearg *ra, objset_t *os, 1275168404Spjd struct drr_freeobjects *drrfo) 1276168404Spjd{ 1277168404Spjd uint64_t obj; 1278168404Spjd 1279168404Spjd if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 1280249195Smm return (SET_ERROR(EINVAL)); 1281168404Spjd 1282168404Spjd for (obj = drrfo->drr_firstobj; 1283168404Spjd obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1284168404Spjd (void) dmu_object_next(os, &obj, FALSE, 0)) { 1285168404Spjd int err; 1286168404Spjd 1287168404Spjd if (dmu_object_info(os, obj, NULL) != 0) 1288168404Spjd continue; 1289168404Spjd 1290254753Sdelphij err = dmu_free_long_object(os, obj); 1291248571Smm if (err != 0) 1292168404Spjd return (err); 1293168404Spjd } 1294168404Spjd return (0); 1295168404Spjd} 1296168404Spjd 1297168404Spjdstatic int 1298168404Spjdrestore_write(struct restorearg *ra, objset_t *os, 1299168404Spjd struct drr_write *drrw) 1300168404Spjd{ 1301168404Spjd dmu_tx_t *tx; 1302168404Spjd void *data; 1303168404Spjd int err; 1304168404Spjd 1305168404Spjd if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 1306236884Smm !DMU_OT_IS_VALID(drrw->drr_type)) 1307249195Smm return (SET_ERROR(EINVAL)); 1308168404Spjd 1309168404Spjd data = restore_read(ra, drrw->drr_length); 1310168404Spjd if (data == NULL) 1311168404Spjd return (ra->err); 1312168404Spjd 1313168404Spjd if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1314249195Smm return (SET_ERROR(EINVAL)); 1315168404Spjd 1316168404Spjd tx = dmu_tx_create(os); 1317168404Spjd 1318168404Spjd dmu_tx_hold_write(tx, drrw->drr_object, 1319168404Spjd drrw->drr_offset, drrw->drr_length); 1320168404Spjd err = dmu_tx_assign(tx, TXG_WAIT); 1321248571Smm if (err != 0) { 1322168404Spjd dmu_tx_abort(tx); 1323168404Spjd return (err); 1324168404Spjd } 1325236884Smm if (ra->byteswap) { 1326236884Smm dmu_object_byteswap_t byteswap = 1327236884Smm DMU_OT_BYTESWAP(drrw->drr_type); 1328236884Smm dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1329236884Smm } 1330168404Spjd dmu_write(os, drrw->drr_object, 1331168404Spjd drrw->drr_offset, drrw->drr_length, data, tx); 1332168404Spjd dmu_tx_commit(tx); 1333168404Spjd return (0); 1334168404Spjd} 1335168404Spjd 1336219089Spjd/* 1337219089Spjd * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed 1338219089Spjd * streams to refer to a copy of the data that is already on the 1339219089Spjd * system because it came in earlier in the stream. This function 1340219089Spjd * finds the earlier copy of the data, and uses that copy instead of 1341219089Spjd * data from the stream to fulfill this write. 1342219089Spjd */ 1343219089Spjdstatic int 1344219089Spjdrestore_write_byref(struct restorearg *ra, objset_t *os, 1345219089Spjd struct drr_write_byref *drrwbr) 1346219089Spjd{ 1347219089Spjd dmu_tx_t *tx; 1348219089Spjd int err; 1349219089Spjd guid_map_entry_t gmesrch; 1350219089Spjd guid_map_entry_t *gmep; 1351219089Spjd avl_index_t where; 1352219089Spjd objset_t *ref_os = NULL; 1353219089Spjd dmu_buf_t *dbp; 1354219089Spjd 1355219089Spjd if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset) 1356249195Smm return (SET_ERROR(EINVAL)); 1357219089Spjd 1358219089Spjd /* 1359219089Spjd * If the GUID of the referenced dataset is different from the 1360219089Spjd * GUID of the target dataset, find the referenced dataset. 1361219089Spjd */ 1362219089Spjd if (drrwbr->drr_toguid != drrwbr->drr_refguid) { 1363219089Spjd gmesrch.guid = drrwbr->drr_refguid; 1364219089Spjd if ((gmep = avl_find(ra->guid_to_ds_map, &gmesrch, 1365219089Spjd &where)) == NULL) { 1366249195Smm return (SET_ERROR(EINVAL)); 1367219089Spjd } 1368219089Spjd if (dmu_objset_from_ds(gmep->gme_ds, &ref_os)) 1369249195Smm return (SET_ERROR(EINVAL)); 1370219089Spjd } else { 1371219089Spjd ref_os = os; 1372219089Spjd } 1373219089Spjd 1374219089Spjd if (err = dmu_buf_hold(ref_os, drrwbr->drr_refobject, 1375219089Spjd drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH)) 1376219089Spjd return (err); 1377219089Spjd 1378219089Spjd tx = dmu_tx_create(os); 1379219089Spjd 1380219089Spjd dmu_tx_hold_write(tx, drrwbr->drr_object, 1381219089Spjd drrwbr->drr_offset, drrwbr->drr_length); 1382219089Spjd err = dmu_tx_assign(tx, TXG_WAIT); 1383248571Smm if (err != 0) { 1384219089Spjd dmu_tx_abort(tx); 1385219089Spjd return (err); 1386219089Spjd } 1387219089Spjd dmu_write(os, drrwbr->drr_object, 1388219089Spjd drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 1389219089Spjd dmu_buf_rele(dbp, FTAG); 1390219089Spjd dmu_tx_commit(tx); 1391219089Spjd return (0); 1392219089Spjd} 1393219089Spjd 1394219089Spjdstatic int 1395219089Spjdrestore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs) 1396219089Spjd{ 1397219089Spjd dmu_tx_t *tx; 1398219089Spjd void *data; 1399219089Spjd dmu_buf_t *db, *db_spill; 1400219089Spjd int err; 1401219089Spjd 1402219089Spjd if (drrs->drr_length < SPA_MINBLOCKSIZE || 1403219089Spjd drrs->drr_length > SPA_MAXBLOCKSIZE) 1404249195Smm return (SET_ERROR(EINVAL)); 1405219089Spjd 1406219089Spjd data = restore_read(ra, drrs->drr_length); 1407219089Spjd if (data == NULL) 1408219089Spjd return (ra->err); 1409219089Spjd 1410219089Spjd if (dmu_object_info(os, drrs->drr_object, NULL) != 0) 1411249195Smm return (SET_ERROR(EINVAL)); 1412219089Spjd 1413219089Spjd VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db)); 1414219089Spjd if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) { 1415219089Spjd dmu_buf_rele(db, FTAG); 1416219089Spjd return (err); 1417219089Spjd } 1418219089Spjd 1419219089Spjd tx = dmu_tx_create(os); 1420219089Spjd 1421219089Spjd dmu_tx_hold_spill(tx, db->db_object); 1422219089Spjd 1423219089Spjd err = dmu_tx_assign(tx, TXG_WAIT); 1424248571Smm if (err != 0) { 1425219089Spjd dmu_buf_rele(db, FTAG); 1426219089Spjd dmu_buf_rele(db_spill, FTAG); 1427219089Spjd dmu_tx_abort(tx); 1428219089Spjd return (err); 1429219089Spjd } 1430219089Spjd dmu_buf_will_dirty(db_spill, tx); 1431219089Spjd 1432219089Spjd if (db_spill->db_size < drrs->drr_length) 1433219089Spjd VERIFY(0 == dbuf_spill_set_blksz(db_spill, 1434219089Spjd drrs->drr_length, tx)); 1435219089Spjd bcopy(data, db_spill->db_data, drrs->drr_length); 1436219089Spjd 1437219089Spjd dmu_buf_rele(db, FTAG); 1438219089Spjd dmu_buf_rele(db_spill, FTAG); 1439219089Spjd 1440219089Spjd dmu_tx_commit(tx); 1441219089Spjd return (0); 1442219089Spjd} 1443219089Spjd 1444168404Spjd/* ARGSUSED */ 1445168404Spjdstatic int 1446168404Spjdrestore_free(struct restorearg *ra, objset_t *os, 1447168404Spjd struct drr_free *drrf) 1448168404Spjd{ 1449168404Spjd int err; 1450168404Spjd 1451168404Spjd if (drrf->drr_length != -1ULL && 1452168404Spjd drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 1453249195Smm return (SET_ERROR(EINVAL)); 1454168404Spjd 1455168404Spjd if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1456249195Smm return (SET_ERROR(EINVAL)); 1457168404Spjd 1458185029Spjd err = dmu_free_long_range(os, drrf->drr_object, 1459168404Spjd drrf->drr_offset, drrf->drr_length); 1460168404Spjd return (err); 1461168404Spjd} 1462168404Spjd 1463248571Smm/* used to destroy the drc_ds on error */ 1464248571Smmstatic void 1465248571Smmdmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) 1466248571Smm{ 1467248571Smm char name[MAXNAMELEN]; 1468248571Smm dsl_dataset_name(drc->drc_ds, name); 1469248571Smm dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 1470248571Smm (void) dsl_destroy_head(name); 1471248571Smm} 1472248571Smm 1473185029Spjd/* 1474185029Spjd * NB: callers *must* call dmu_recv_end() if this succeeds. 1475185029Spjd */ 1476168404Spjdint 1477219089Spjddmu_recv_stream(dmu_recv_cookie_t *drc, struct file *fp, offset_t *voffp, 1478219089Spjd int cleanup_fd, uint64_t *action_handlep) 1479168404Spjd{ 1480185029Spjd struct restorearg ra = { 0 }; 1481168404Spjd dmu_replay_record_t *drr; 1482185029Spjd objset_t *os; 1483185029Spjd zio_cksum_t pcksum; 1484219089Spjd int featureflags; 1485168404Spjd 1486248571Smm ra.byteswap = drc->drc_byteswap; 1487248571Smm ra.cksum = drc->drc_cksum; 1488219089Spjd ra.td = curthread; 1489185029Spjd ra.fp = fp; 1490185029Spjd ra.voff = *voffp; 1491185029Spjd ra.bufsize = 1<<20; 1492185029Spjd ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1493168404Spjd 1494185029Spjd /* these were verified in dmu_recv_begin */ 1495248571Smm ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==, 1496219089Spjd DMU_SUBSTREAM); 1497248571Smm ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES); 1498168404Spjd 1499168404Spjd /* 1500168404Spjd * Open the objset we are modifying. 1501168404Spjd */ 1502248571Smm VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os)); 1503168404Spjd 1504248571Smm ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1505168404Spjd 1506219089Spjd featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 1507219089Spjd 1508219089Spjd /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 1509219089Spjd if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1510219089Spjd minor_t minor; 1511219089Spjd 1512219089Spjd if (cleanup_fd == -1) { 1513249195Smm ra.err = SET_ERROR(EBADF); 1514219089Spjd goto out; 1515219089Spjd } 1516219089Spjd ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); 1517248571Smm if (ra.err != 0) { 1518219089Spjd cleanup_fd = -1; 1519219089Spjd goto out; 1520219089Spjd } 1521219089Spjd 1522219089Spjd if (*action_handlep == 0) { 1523219089Spjd ra.guid_to_ds_map = 1524219089Spjd kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1525219089Spjd avl_create(ra.guid_to_ds_map, guid_compare, 1526219089Spjd sizeof (guid_map_entry_t), 1527219089Spjd offsetof(guid_map_entry_t, avlnode)); 1528219089Spjd ra.err = zfs_onexit_add_cb(minor, 1529219089Spjd free_guid_map_onexit, ra.guid_to_ds_map, 1530219089Spjd action_handlep); 1531248571Smm if (ra.err != 0) 1532219089Spjd goto out; 1533219089Spjd } else { 1534219089Spjd ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1535219089Spjd (void **)&ra.guid_to_ds_map); 1536248571Smm if (ra.err != 0) 1537219089Spjd goto out; 1538219089Spjd } 1539221263Smm 1540221263Smm drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 1541219089Spjd } 1542219089Spjd 1543168404Spjd /* 1544168404Spjd * Read records and process them. 1545168404Spjd */ 1546185029Spjd pcksum = ra.cksum; 1547168404Spjd while (ra.err == 0 && 1548168404Spjd NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 1549185029Spjd if (issig(JUSTLOOKING) && issig(FORREAL)) { 1550249195Smm ra.err = SET_ERROR(EINTR); 1551168404Spjd goto out; 1552168404Spjd } 1553168404Spjd 1554168404Spjd if (ra.byteswap) 1555168404Spjd backup_byteswap(drr); 1556168404Spjd 1557168404Spjd switch (drr->drr_type) { 1558168404Spjd case DRR_OBJECT: 1559168404Spjd { 1560168404Spjd /* 1561168404Spjd * We need to make a copy of the record header, 1562168404Spjd * because restore_{object,write} may need to 1563168404Spjd * restore_read(), which will invalidate drr. 1564168404Spjd */ 1565168404Spjd struct drr_object drro = drr->drr_u.drr_object; 1566168404Spjd ra.err = restore_object(&ra, os, &drro); 1567168404Spjd break; 1568168404Spjd } 1569168404Spjd case DRR_FREEOBJECTS: 1570168404Spjd { 1571168404Spjd struct drr_freeobjects drrfo = 1572168404Spjd drr->drr_u.drr_freeobjects; 1573168404Spjd ra.err = restore_freeobjects(&ra, os, &drrfo); 1574168404Spjd break; 1575168404Spjd } 1576168404Spjd case DRR_WRITE: 1577168404Spjd { 1578168404Spjd struct drr_write drrw = drr->drr_u.drr_write; 1579168404Spjd ra.err = restore_write(&ra, os, &drrw); 1580168404Spjd break; 1581168404Spjd } 1582219089Spjd case DRR_WRITE_BYREF: 1583219089Spjd { 1584219089Spjd struct drr_write_byref drrwbr = 1585219089Spjd drr->drr_u.drr_write_byref; 1586219089Spjd ra.err = restore_write_byref(&ra, os, &drrwbr); 1587219089Spjd break; 1588219089Spjd } 1589168404Spjd case DRR_FREE: 1590168404Spjd { 1591168404Spjd struct drr_free drrf = drr->drr_u.drr_free; 1592168404Spjd ra.err = restore_free(&ra, os, &drrf); 1593168404Spjd break; 1594168404Spjd } 1595168404Spjd case DRR_END: 1596168404Spjd { 1597168404Spjd struct drr_end drre = drr->drr_u.drr_end; 1598168404Spjd /* 1599168404Spjd * We compare against the *previous* checksum 1600168404Spjd * value, because the stored checksum is of 1601168404Spjd * everything before the DRR_END record. 1602168404Spjd */ 1603185029Spjd if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1604249195Smm ra.err = SET_ERROR(ECKSUM); 1605168404Spjd goto out; 1606168404Spjd } 1607219089Spjd case DRR_SPILL: 1608219089Spjd { 1609219089Spjd struct drr_spill drrs = drr->drr_u.drr_spill; 1610219089Spjd ra.err = restore_spill(&ra, os, &drrs); 1611219089Spjd break; 1612219089Spjd } 1613168404Spjd default: 1614249195Smm ra.err = SET_ERROR(EINVAL); 1615168404Spjd goto out; 1616168404Spjd } 1617185029Spjd pcksum = ra.cksum; 1618168404Spjd } 1619185029Spjd ASSERT(ra.err != 0); 1620168404Spjd 1621168404Spjdout: 1622219089Spjd if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1623219089Spjd zfs_onexit_fd_rele(cleanup_fd); 1624168404Spjd 1625185029Spjd if (ra.err != 0) { 1626168404Spjd /* 1627219089Spjd * destroy what we created, so we don't leave it in the 1628219089Spjd * inconsistent restoring state. 1629168404Spjd */ 1630248571Smm dmu_recv_cleanup_ds(drc); 1631168404Spjd } 1632168404Spjd 1633168404Spjd kmem_free(ra.buf, ra.bufsize); 1634185029Spjd *voffp = ra.voff; 1635168404Spjd return (ra.err); 1636168404Spjd} 1637185029Spjd 1638185029Spjdstatic int 1639248571Smmdmu_recv_end_check(void *arg, dmu_tx_t *tx) 1640185029Spjd{ 1641248571Smm dmu_recv_cookie_t *drc = arg; 1642248571Smm dsl_pool_t *dp = dmu_tx_pool(tx); 1643248571Smm int error; 1644185029Spjd 1645248571Smm ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag); 1646248571Smm 1647248571Smm if (!drc->drc_newfs) { 1648248571Smm dsl_dataset_t *origin_head; 1649248571Smm 1650248571Smm error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head); 1651248571Smm if (error != 0) 1652248571Smm return (error); 1653253820Sdelphij if (drc->drc_force) { 1654253820Sdelphij /* 1655253820Sdelphij * We will destroy any snapshots in tofs (i.e. before 1656253820Sdelphij * origin_head) that are after the origin (which is 1657253820Sdelphij * the snap before drc_ds, because drc_ds can not 1658253820Sdelphij * have any snaps of its own). 1659253820Sdelphij */ 1660253820Sdelphij uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 1661253820Sdelphij while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 1662253820Sdelphij dsl_dataset_t *snap; 1663253820Sdelphij error = dsl_dataset_hold_obj(dp, obj, FTAG, 1664253820Sdelphij &snap); 1665253820Sdelphij if (error != 0) 1666253820Sdelphij return (error); 1667253820Sdelphij if (snap->ds_dir != origin_head->ds_dir) 1668253820Sdelphij error = SET_ERROR(EINVAL); 1669253820Sdelphij if (error == 0) { 1670253820Sdelphij error = dsl_destroy_snapshot_check_impl( 1671253820Sdelphij snap, B_FALSE); 1672253820Sdelphij } 1673253820Sdelphij obj = snap->ds_phys->ds_prev_snap_obj; 1674253820Sdelphij dsl_dataset_rele(snap, FTAG); 1675253820Sdelphij if (error != 0) 1676253820Sdelphij return (error); 1677253820Sdelphij } 1678253820Sdelphij } 1679248571Smm error = dsl_dataset_clone_swap_check_impl(drc->drc_ds, 1680253816Sdelphij origin_head, drc->drc_force, drc->drc_owner, tx); 1681248571Smm if (error != 0) { 1682248571Smm dsl_dataset_rele(origin_head, FTAG); 1683248571Smm return (error); 1684248571Smm } 1685248571Smm error = dsl_dataset_snapshot_check_impl(origin_head, 1686253819Sdelphij drc->drc_tosnap, tx, B_TRUE); 1687248571Smm dsl_dataset_rele(origin_head, FTAG); 1688248571Smm if (error != 0) 1689248571Smm return (error); 1690248571Smm 1691248571Smm error = dsl_destroy_head_check_impl(drc->drc_ds, 1); 1692248571Smm } else { 1693248571Smm error = dsl_dataset_snapshot_check_impl(drc->drc_ds, 1694253819Sdelphij drc->drc_tosnap, tx, B_TRUE); 1695248571Smm } 1696248571Smm return (error); 1697185029Spjd} 1698185029Spjd 1699185029Spjdstatic void 1700248571Smmdmu_recv_end_sync(void *arg, dmu_tx_t *tx) 1701185029Spjd{ 1702248571Smm dmu_recv_cookie_t *drc = arg; 1703248571Smm dsl_pool_t *dp = dmu_tx_pool(tx); 1704185029Spjd 1705248571Smm spa_history_log_internal_ds(drc->drc_ds, "finish receiving", 1706248571Smm tx, "snap=%s", drc->drc_tosnap); 1707185029Spjd 1708248571Smm if (!drc->drc_newfs) { 1709248571Smm dsl_dataset_t *origin_head; 1710185029Spjd 1711248571Smm VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG, 1712248571Smm &origin_head)); 1713253820Sdelphij 1714253820Sdelphij if (drc->drc_force) { 1715253820Sdelphij /* 1716253820Sdelphij * Destroy any snapshots of drc_tofs (origin_head) 1717253820Sdelphij * after the origin (the snap before drc_ds). 1718253820Sdelphij */ 1719253820Sdelphij uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 1720253820Sdelphij while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 1721253820Sdelphij dsl_dataset_t *snap; 1722253820Sdelphij VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG, 1723253820Sdelphij &snap)); 1724253820Sdelphij ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir); 1725253820Sdelphij obj = snap->ds_phys->ds_prev_snap_obj; 1726253820Sdelphij dsl_destroy_snapshot_sync_impl(snap, 1727253820Sdelphij B_FALSE, tx); 1728253820Sdelphij dsl_dataset_rele(snap, FTAG); 1729253820Sdelphij } 1730253820Sdelphij } 1731253820Sdelphij VERIFY3P(drc->drc_ds->ds_prev, ==, 1732253820Sdelphij origin_head->ds_prev); 1733253820Sdelphij 1734248571Smm dsl_dataset_clone_swap_sync_impl(drc->drc_ds, 1735248571Smm origin_head, tx); 1736248571Smm dsl_dataset_snapshot_sync_impl(origin_head, 1737248571Smm drc->drc_tosnap, tx); 1738248571Smm 1739248571Smm /* set snapshot's creation time and guid */ 1740248571Smm dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx); 1741248571Smm origin_head->ds_prev->ds_phys->ds_creation_time = 1742248571Smm drc->drc_drrb->drr_creation_time; 1743248571Smm origin_head->ds_prev->ds_phys->ds_guid = 1744248571Smm drc->drc_drrb->drr_toguid; 1745248571Smm origin_head->ds_prev->ds_phys->ds_flags &= 1746248571Smm ~DS_FLAG_INCONSISTENT; 1747248571Smm 1748248571Smm dmu_buf_will_dirty(origin_head->ds_dbuf, tx); 1749248571Smm origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1750248571Smm 1751248571Smm dsl_dataset_rele(origin_head, FTAG); 1752248571Smm dsl_destroy_head_sync_impl(drc->drc_ds, tx); 1753253816Sdelphij 1754253816Sdelphij if (drc->drc_owner != NULL) 1755253816Sdelphij VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner); 1756248571Smm } else { 1757248571Smm dsl_dataset_t *ds = drc->drc_ds; 1758248571Smm 1759248571Smm dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx); 1760248571Smm 1761248571Smm /* set snapshot's creation time and guid */ 1762248571Smm dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1763248571Smm ds->ds_prev->ds_phys->ds_creation_time = 1764248571Smm drc->drc_drrb->drr_creation_time; 1765248571Smm ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid; 1766248571Smm ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1767248571Smm 1768248571Smm dmu_buf_will_dirty(ds->ds_dbuf, tx); 1769248571Smm ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 1770248571Smm } 1771248571Smm drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj; 1772248571Smm /* 1773248571Smm * Release the hold from dmu_recv_begin. This must be done before 1774248571Smm * we return to open context, so that when we free the dataset's dnode, 1775248571Smm * we can evict its bonus buffer. 1776248571Smm */ 1777248571Smm dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 1778248571Smm drc->drc_ds = NULL; 1779185029Spjd} 1780185029Spjd 1781219089Spjdstatic int 1782248571Smmadd_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj) 1783221263Smm{ 1784248571Smm dsl_pool_t *dp; 1785221263Smm dsl_dataset_t *snapds; 1786221263Smm guid_map_entry_t *gmep; 1787221263Smm int err; 1788221263Smm 1789221263Smm ASSERT(guid_map != NULL); 1790221263Smm 1791248571Smm err = dsl_pool_hold(name, FTAG, &dp); 1792248571Smm if (err != 0) 1793248571Smm return (err); 1794249356Smm gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP); 1795249196Smm err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds); 1796221263Smm if (err == 0) { 1797221263Smm gmep->guid = snapds->ds_phys->ds_guid; 1798221263Smm gmep->gme_ds = snapds; 1799221263Smm avl_add(guid_map, gmep); 1800248571Smm dsl_dataset_long_hold(snapds, gmep); 1801249196Smm } else 1802249356Smm kmem_free(gmep, sizeof (*gmep)); 1803221263Smm 1804248571Smm dsl_pool_rele(dp, FTAG); 1805221263Smm return (err); 1806221263Smm} 1807221263Smm 1808248571Smmstatic int dmu_recv_end_modified_blocks = 3; 1809248571Smm 1810221263Smmstatic int 1811219089Spjddmu_recv_existing_end(dmu_recv_cookie_t *drc) 1812185029Spjd{ 1813248571Smm int error; 1814248571Smm char name[MAXNAMELEN]; 1815185029Spjd 1816248571Smm#ifdef _KERNEL 1817248571Smm /* 1818248571Smm * We will be destroying the ds; make sure its origin is unmounted if 1819248571Smm * necessary. 1820248571Smm */ 1821248571Smm dsl_dataset_name(drc->drc_ds, name); 1822248571Smm zfs_destroy_unmount_origin(name); 1823248571Smm#endif 1824185029Spjd 1825248571Smm error = dsl_sync_task(drc->drc_tofs, 1826248571Smm dmu_recv_end_check, dmu_recv_end_sync, drc, 1827248571Smm dmu_recv_end_modified_blocks); 1828185029Spjd 1829248571Smm if (error != 0) 1830248571Smm dmu_recv_cleanup_ds(drc); 1831248571Smm return (error); 1832185029Spjd} 1833219089Spjd 1834219089Spjdstatic int 1835219089Spjddmu_recv_new_end(dmu_recv_cookie_t *drc) 1836219089Spjd{ 1837248571Smm int error; 1838219089Spjd 1839248571Smm error = dsl_sync_task(drc->drc_tofs, 1840248571Smm dmu_recv_end_check, dmu_recv_end_sync, drc, 1841248571Smm dmu_recv_end_modified_blocks); 1842219089Spjd 1843248571Smm if (error != 0) { 1844248571Smm dmu_recv_cleanup_ds(drc); 1845248571Smm } else if (drc->drc_guid_to_ds_map != NULL) { 1846248571Smm (void) add_ds_to_guidmap(drc->drc_tofs, 1847248571Smm drc->drc_guid_to_ds_map, 1848248571Smm drc->drc_newsnapobj); 1849219089Spjd } 1850248571Smm return (error); 1851219089Spjd} 1852219089Spjd 1853219089Spjdint 1854253816Sdelphijdmu_recv_end(dmu_recv_cookie_t *drc, void *owner) 1855219089Spjd{ 1856253816Sdelphij drc->drc_owner = owner; 1857253816Sdelphij 1858248571Smm if (drc->drc_newfs) 1859248571Smm return (dmu_recv_new_end(drc)); 1860248571Smm else 1861219089Spjd return (dmu_recv_existing_end(drc)); 1862219089Spjd} 1863253821Sdelphij 1864253821Sdelphij/* 1865253821Sdelphij * Return TRUE if this objset is currently being received into. 1866253821Sdelphij */ 1867253821Sdelphijboolean_t 1868253821Sdelphijdmu_objset_is_receiving(objset_t *os) 1869253821Sdelphij{ 1870253821Sdelphij return (os->os_dsl_dataset != NULL && 1871253821Sdelphij os->os_dsl_dataset->ds_owner == dmu_recv_tag); 1872253821Sdelphij} 1873