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 /* 22da03de99SMark Maybee * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23efb80947Sahrens * Use is subject to license terms. 24efb80947Sahrens */ 25efb80947Sahrens 26efb80947Sahrens #include <sys/dmu.h> 27efb80947Sahrens #include <sys/dmu_impl.h> 28efb80947Sahrens #include <sys/dmu_tx.h> 29efb80947Sahrens #include <sys/dbuf.h> 30efb80947Sahrens #include <sys/dnode.h> 31efb80947Sahrens #include <sys/zfs_context.h> 32efb80947Sahrens #include <sys/dmu_objset.h> 33efb80947Sahrens #include <sys/dmu_traverse.h> 34efb80947Sahrens #include <sys/dsl_dataset.h> 35efb80947Sahrens #include <sys/dsl_dir.h> 36efb80947Sahrens #include <sys/dsl_pool.h> 37efb80947Sahrens #include <sys/dsl_synctask.h> 38efb80947Sahrens #include <sys/zfs_ioctl.h> 39efb80947Sahrens #include <sys/zap.h> 40efb80947Sahrens #include <sys/zio_checksum.h> 41efb80947Sahrens 423cb34c60Sahrens static char *dmu_recv_tag = "dmu_recv_tag"; 433cb34c60Sahrens 44efb80947Sahrens struct backuparg { 45efb80947Sahrens dmu_replay_record_t *drr; 46efb80947Sahrens vnode_t *vp; 473cb34c60Sahrens offset_t *off; 48efb80947Sahrens objset_t *os; 49efb80947Sahrens zio_cksum_t zc; 50efb80947Sahrens int err; 51efb80947Sahrens }; 52efb80947Sahrens 53efb80947Sahrens static int 54efb80947Sahrens dump_bytes(struct backuparg *ba, void *buf, int len) 55efb80947Sahrens { 56efb80947Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 57efb80947Sahrens ASSERT3U(len % 8, ==, 0); 58efb80947Sahrens 59efb80947Sahrens fletcher_4_incremental_native(buf, len, &ba->zc); 60efb80947Sahrens ba->err = vn_rdwr(UIO_WRITE, ba->vp, 61efb80947Sahrens (caddr_t)buf, len, 62efb80947Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 633cb34c60Sahrens *ba->off += len; 64efb80947Sahrens return (ba->err); 65efb80947Sahrens } 66efb80947Sahrens 67efb80947Sahrens static int 68efb80947Sahrens dump_free(struct backuparg *ba, uint64_t object, uint64_t offset, 69efb80947Sahrens uint64_t length) 70efb80947Sahrens { 71efb80947Sahrens /* write a FREE record */ 72efb80947Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 73efb80947Sahrens ba->drr->drr_type = DRR_FREE; 74efb80947Sahrens ba->drr->drr_u.drr_free.drr_object = object; 75efb80947Sahrens ba->drr->drr_u.drr_free.drr_offset = offset; 76efb80947Sahrens ba->drr->drr_u.drr_free.drr_length = length; 77efb80947Sahrens 78efb80947Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 79efb80947Sahrens return (EINTR); 80efb80947Sahrens return (0); 81efb80947Sahrens } 82efb80947Sahrens 83efb80947Sahrens static int 84efb80947Sahrens dump_data(struct backuparg *ba, dmu_object_type_t type, 85efb80947Sahrens uint64_t object, uint64_t offset, int blksz, void *data) 86efb80947Sahrens { 87efb80947Sahrens /* write a DATA record */ 88efb80947Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 89efb80947Sahrens ba->drr->drr_type = DRR_WRITE; 90efb80947Sahrens ba->drr->drr_u.drr_write.drr_object = object; 91efb80947Sahrens ba->drr->drr_u.drr_write.drr_type = type; 92efb80947Sahrens ba->drr->drr_u.drr_write.drr_offset = offset; 93efb80947Sahrens ba->drr->drr_u.drr_write.drr_length = blksz; 94efb80947Sahrens 95efb80947Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 96efb80947Sahrens return (EINTR); 97efb80947Sahrens if (dump_bytes(ba, data, blksz)) 98efb80947Sahrens return (EINTR); 99efb80947Sahrens return (0); 100efb80947Sahrens } 101efb80947Sahrens 102efb80947Sahrens static int 103efb80947Sahrens dump_freeobjects(struct backuparg *ba, uint64_t firstobj, uint64_t numobjs) 104efb80947Sahrens { 105efb80947Sahrens /* write a FREEOBJECTS record */ 106efb80947Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 107efb80947Sahrens ba->drr->drr_type = DRR_FREEOBJECTS; 108efb80947Sahrens ba->drr->drr_u.drr_freeobjects.drr_firstobj = firstobj; 109efb80947Sahrens ba->drr->drr_u.drr_freeobjects.drr_numobjs = numobjs; 110efb80947Sahrens 111efb80947Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 112efb80947Sahrens return (EINTR); 113efb80947Sahrens return (0); 114efb80947Sahrens } 115efb80947Sahrens 116efb80947Sahrens static int 117efb80947Sahrens dump_dnode(struct backuparg *ba, uint64_t object, dnode_phys_t *dnp) 118efb80947Sahrens { 119efb80947Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 120efb80947Sahrens return (dump_freeobjects(ba, object, 1)); 121efb80947Sahrens 122efb80947Sahrens /* write an OBJECT record */ 123efb80947Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 124efb80947Sahrens ba->drr->drr_type = DRR_OBJECT; 125efb80947Sahrens ba->drr->drr_u.drr_object.drr_object = object; 126efb80947Sahrens ba->drr->drr_u.drr_object.drr_type = dnp->dn_type; 127efb80947Sahrens ba->drr->drr_u.drr_object.drr_bonustype = dnp->dn_bonustype; 128efb80947Sahrens ba->drr->drr_u.drr_object.drr_blksz = 129efb80947Sahrens dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 130efb80947Sahrens ba->drr->drr_u.drr_object.drr_bonuslen = dnp->dn_bonuslen; 131efb80947Sahrens ba->drr->drr_u.drr_object.drr_checksum = dnp->dn_checksum; 132efb80947Sahrens ba->drr->drr_u.drr_object.drr_compress = dnp->dn_compress; 133efb80947Sahrens 134efb80947Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 135efb80947Sahrens return (EINTR); 136efb80947Sahrens 137efb80947Sahrens if (dump_bytes(ba, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8))) 138efb80947Sahrens return (EINTR); 139efb80947Sahrens 140efb80947Sahrens /* free anything past the end of the file */ 141efb80947Sahrens if (dump_free(ba, object, (dnp->dn_maxblkid + 1) * 142efb80947Sahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 143efb80947Sahrens return (EINTR); 144efb80947Sahrens if (ba->err) 145efb80947Sahrens return (EINTR); 146efb80947Sahrens return (0); 147efb80947Sahrens } 148efb80947Sahrens 149efb80947Sahrens #define BP_SPAN(dnp, level) \ 150efb80947Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 151efb80947Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 152efb80947Sahrens 153efb80947Sahrens static int 15488b7b0f2SMatthew Ahrens backup_cb(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb, 15588b7b0f2SMatthew Ahrens const dnode_phys_t *dnp, void *arg) 156efb80947Sahrens { 157efb80947Sahrens struct backuparg *ba = arg; 158efb80947Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 159efb80947Sahrens int err = 0; 160efb80947Sahrens 161efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 162efb80947Sahrens return (EINTR); 163efb80947Sahrens 16414843421SMatthew Ahrens if (zb->zb_object != 0 && DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 16514843421SMatthew Ahrens return (0); 16614843421SMatthew Ahrens } else if (bp == NULL && zb->zb_object == 0) { 16788b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 16888b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 169efb80947Sahrens err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT); 170efb80947Sahrens } else if (bp == NULL) { 17188b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 17288b7b0f2SMatthew Ahrens err = dump_free(ba, zb->zb_object, zb->zb_blkid * span, span); 17388b7b0f2SMatthew Ahrens } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 17488b7b0f2SMatthew Ahrens return (0); 17588b7b0f2SMatthew Ahrens } else if (type == DMU_OT_DNODE) { 17688b7b0f2SMatthew Ahrens dnode_phys_t *blk; 177efb80947Sahrens int i; 178efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 17988b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 18088b7b0f2SMatthew Ahrens arc_buf_t *abuf; 181efb80947Sahrens 18288b7b0f2SMatthew Ahrens if (arc_read_nolock(NULL, spa, bp, 18388b7b0f2SMatthew Ahrens arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ, 18488b7b0f2SMatthew Ahrens ZIO_FLAG_CANFAIL, &aflags, zb) != 0) 18588b7b0f2SMatthew Ahrens return (EIO); 18688b7b0f2SMatthew Ahrens 18788b7b0f2SMatthew Ahrens blk = abuf->b_data; 188efb80947Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 18988b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid << 19088b7b0f2SMatthew Ahrens (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 191efb80947Sahrens err = dump_dnode(ba, dnobj, blk+i); 192efb80947Sahrens if (err) 193efb80947Sahrens break; 194efb80947Sahrens } 19588b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 19688b7b0f2SMatthew Ahrens } else { /* it's a level-0 block of a regular object */ 19788b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 19888b7b0f2SMatthew Ahrens arc_buf_t *abuf; 199efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 20088b7b0f2SMatthew Ahrens 20188b7b0f2SMatthew Ahrens if (arc_read_nolock(NULL, spa, bp, 20288b7b0f2SMatthew Ahrens arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ, 20388b7b0f2SMatthew Ahrens ZIO_FLAG_CANFAIL, &aflags, zb) != 0) 20488b7b0f2SMatthew Ahrens return (EIO); 20588b7b0f2SMatthew Ahrens 20688b7b0f2SMatthew Ahrens err = dump_data(ba, type, zb->zb_object, zb->zb_blkid * blksz, 20788b7b0f2SMatthew Ahrens blksz, abuf->b_data); 20888b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 209efb80947Sahrens } 210efb80947Sahrens 211efb80947Sahrens ASSERT(err == 0 || err == EINTR); 212efb80947Sahrens return (err); 213efb80947Sahrens } 214efb80947Sahrens 215efb80947Sahrens int 2163cb34c60Sahrens dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, 2173cb34c60Sahrens vnode_t *vp, offset_t *off) 218efb80947Sahrens { 219efb80947Sahrens dsl_dataset_t *ds = tosnap->os->os_dsl_dataset; 220efb80947Sahrens dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL; 221efb80947Sahrens dmu_replay_record_t *drr; 222efb80947Sahrens struct backuparg ba; 223efb80947Sahrens int err; 2243cb34c60Sahrens uint64_t fromtxg = 0; 225efb80947Sahrens 226efb80947Sahrens /* tosnap must be a snapshot */ 227efb80947Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 228efb80947Sahrens return (EINVAL); 229efb80947Sahrens 230efb80947Sahrens /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 231efb80947Sahrens if (fromds && (ds->ds_dir != fromds->ds_dir || 2323cb34c60Sahrens fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg)) 233efb80947Sahrens return (EXDEV); 234efb80947Sahrens 2353cb34c60Sahrens if (fromorigin) { 236088f3894Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 237088f3894Sahrens 2383cb34c60Sahrens if (fromsnap) 2393cb34c60Sahrens return (EINVAL); 2403cb34c60Sahrens 241088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2423cb34c60Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 243745cd3c5Smaybee err = dsl_dataset_hold_obj(dp, 244745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds); 2453cb34c60Sahrens rw_exit(&dp->dp_config_rwlock); 2463cb34c60Sahrens if (err) 2473cb34c60Sahrens return (err); 2483cb34c60Sahrens } else { 2493cb34c60Sahrens fromorigin = B_FALSE; 2503cb34c60Sahrens } 2513cb34c60Sahrens } 2523cb34c60Sahrens 2533cb34c60Sahrens 254efb80947Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 255efb80947Sahrens drr->drr_type = DRR_BEGIN; 256efb80947Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 2573cb34c60Sahrens drr->drr_u.drr_begin.drr_version = DMU_BACKUP_STREAM_VERSION; 258efb80947Sahrens drr->drr_u.drr_begin.drr_creation_time = 259efb80947Sahrens ds->ds_phys->ds_creation_time; 260efb80947Sahrens drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type; 2613cb34c60Sahrens if (fromorigin) 2623cb34c60Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 263efb80947Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 264ab04eb8eStimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 265ab04eb8eStimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 266ab04eb8eStimh 267efb80947Sahrens if (fromds) 268efb80947Sahrens drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 269efb80947Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 270efb80947Sahrens 2713cb34c60Sahrens if (fromds) 2723cb34c60Sahrens fromtxg = fromds->ds_phys->ds_creation_txg; 2733cb34c60Sahrens if (fromorigin) 274745cd3c5Smaybee dsl_dataset_rele(fromds, FTAG); 2753cb34c60Sahrens 276efb80947Sahrens ba.drr = drr; 277efb80947Sahrens ba.vp = vp; 278efb80947Sahrens ba.os = tosnap; 2793cb34c60Sahrens ba.off = off; 280efb80947Sahrens ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); 281efb80947Sahrens 282efb80947Sahrens if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 283efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 284efb80947Sahrens return (ba.err); 285efb80947Sahrens } 286efb80947Sahrens 28788b7b0f2SMatthew Ahrens err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 288efb80947Sahrens backup_cb, &ba); 289efb80947Sahrens 290efb80947Sahrens if (err) { 291efb80947Sahrens if (err == EINTR && ba.err) 292efb80947Sahrens err = ba.err; 2937b5309bbSgw kmem_free(drr, sizeof (dmu_replay_record_t)); 294efb80947Sahrens return (err); 295efb80947Sahrens } 296efb80947Sahrens 297efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 298efb80947Sahrens drr->drr_type = DRR_END; 299efb80947Sahrens drr->drr_u.drr_end.drr_checksum = ba.zc; 300efb80947Sahrens 3017b5309bbSgw if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 3027b5309bbSgw kmem_free(drr, sizeof (dmu_replay_record_t)); 303efb80947Sahrens return (ba.err); 3047b5309bbSgw } 305efb80947Sahrens 306efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 307efb80947Sahrens 308efb80947Sahrens return (0); 309efb80947Sahrens } 310efb80947Sahrens 3113cb34c60Sahrens struct recvbeginsyncarg { 3123cb34c60Sahrens const char *tofs; 3133cb34c60Sahrens const char *tosnap; 3143cb34c60Sahrens dsl_dataset_t *origin; 3153cb34c60Sahrens uint64_t fromguid; 3163cb34c60Sahrens dmu_objset_type_t type; 3173cb34c60Sahrens void *tag; 3183cb34c60Sahrens boolean_t force; 319ab04eb8eStimh uint64_t dsflags; 3203cb34c60Sahrens char clonelastname[MAXNAMELEN]; 3213cb34c60Sahrens dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */ 322efb80947Sahrens }; 323efb80947Sahrens 3243cb34c60Sahrens static dsl_dataset_t * 3253cb34c60Sahrens recv_full_sync_impl(dsl_pool_t *dp, uint64_t dsobj, dmu_objset_type_t type, 3263cb34c60Sahrens cred_t *cr, dmu_tx_t *tx) 327f18faf3fSek { 3283cb34c60Sahrens dsl_dataset_t *ds; 329f18faf3fSek 330745cd3c5Smaybee /* This should always work, since we just created it */ 331745cd3c5Smaybee /* XXX - create should return an owned ds */ 332745cd3c5Smaybee VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 333745cd3c5Smaybee DS_MODE_INCONSISTENT, dmu_recv_tag, &ds)); 334f18faf3fSek 3353cb34c60Sahrens if (type != DMU_OST_NONE) { 3363cb34c60Sahrens (void) dmu_objset_create_impl(dp->dp_spa, 3373cb34c60Sahrens ds, &ds->ds_phys->ds_bp, type, tx); 3383cb34c60Sahrens } 339f18faf3fSek 3403cb34c60Sahrens spa_history_internal_log(LOG_DS_REPLAY_FULL_SYNC, 341745cd3c5Smaybee dp->dp_spa, tx, cr, "dataset = %lld", dsobj); 3423cb34c60Sahrens 3433cb34c60Sahrens return (ds); 344efb80947Sahrens } 345efb80947Sahrens 346efb80947Sahrens /* ARGSUSED */ 347efb80947Sahrens static int 3483cb34c60Sahrens recv_full_check(void *arg1, void *arg2, dmu_tx_t *tx) 349efb80947Sahrens { 350efb80947Sahrens dsl_dir_t *dd = arg1; 3513cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 352efb80947Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 353efb80947Sahrens uint64_t val; 354efb80947Sahrens int err; 355efb80947Sahrens 356efb80947Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 3573cb34c60Sahrens strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val); 358efb80947Sahrens 359efb80947Sahrens if (err != ENOENT) 360efb80947Sahrens return (err ? err : EEXIST); 361efb80947Sahrens 3623cb34c60Sahrens if (rbsa->origin) { 3633cb34c60Sahrens /* make sure it's a snap in the same pool */ 3643cb34c60Sahrens if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool) 3653cb34c60Sahrens return (EXDEV); 3663cb34c60Sahrens if (rbsa->origin->ds_phys->ds_num_children == 0) 3673cb34c60Sahrens return (EINVAL); 3683cb34c60Sahrens if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 3693cb34c60Sahrens return (ENODEV); 3703cb34c60Sahrens } 3713cb34c60Sahrens 372efb80947Sahrens return (0); 373efb80947Sahrens } 374efb80947Sahrens 375efb80947Sahrens static void 3763cb34c60Sahrens recv_full_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 377efb80947Sahrens { 378efb80947Sahrens dsl_dir_t *dd = arg1; 3793cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 380745cd3c5Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 381efb80947Sahrens uint64_t dsobj; 382efb80947Sahrens 3833cb34c60Sahrens dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1, 384ab04eb8eStimh rbsa->origin, flags, cr, tx); 385efb80947Sahrens 3863cb34c60Sahrens rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj, 3873cb34c60Sahrens rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx); 3883cb34c60Sahrens } 389efb80947Sahrens 3903cb34c60Sahrens static int 3913cb34c60Sahrens recv_full_existing_check(void *arg1, void *arg2, dmu_tx_t *tx) 3923cb34c60Sahrens { 3933cb34c60Sahrens dsl_dataset_t *ds = arg1; 3943cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 3953cb34c60Sahrens int err; 396efb80947Sahrens 3973cb34c60Sahrens /* must be a head ds */ 3983cb34c60Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 3993cb34c60Sahrens return (EINVAL); 400efb80947Sahrens 4013cb34c60Sahrens /* must not be a clone ds */ 402088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) 4033cb34c60Sahrens return (EINVAL); 4043cb34c60Sahrens 4053cb34c60Sahrens err = dsl_dataset_destroy_check(ds, rbsa->tag, tx); 4063cb34c60Sahrens if (err) 4073cb34c60Sahrens return (err); 408ecd6cf80Smarks 4093cb34c60Sahrens if (rbsa->origin) { 4103cb34c60Sahrens /* make sure it's a snap in the same pool */ 4113cb34c60Sahrens if (rbsa->origin->ds_dir->dd_pool != ds->ds_dir->dd_pool) 4123cb34c60Sahrens return (EXDEV); 4133cb34c60Sahrens if (rbsa->origin->ds_phys->ds_num_children == 0) 4143cb34c60Sahrens return (EINVAL); 4153cb34c60Sahrens if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 4163cb34c60Sahrens return (ENODEV); 4173cb34c60Sahrens } 418ecd6cf80Smarks 4193cb34c60Sahrens return (0); 420efb80947Sahrens } 421efb80947Sahrens 4223cb34c60Sahrens static void 4233cb34c60Sahrens recv_full_existing_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 4243cb34c60Sahrens { 4253cb34c60Sahrens dsl_dataset_t *ds = arg1; 4263cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 4273cb34c60Sahrens dsl_dir_t *dd = ds->ds_dir; 428745cd3c5Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 4293cb34c60Sahrens uint64_t dsobj; 4303cb34c60Sahrens 4313cb34c60Sahrens /* 4323cb34c60Sahrens * NB: caller must provide an extra hold on the dsl_dir_t, so it 4333cb34c60Sahrens * won't go away when dsl_dataset_destroy_sync() closes the 4343cb34c60Sahrens * dataset. 4353cb34c60Sahrens */ 4363cb34c60Sahrens dsl_dataset_destroy_sync(ds, rbsa->tag, cr, tx); 4373cb34c60Sahrens 438088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, rbsa->origin, flags, tx); 4393cb34c60Sahrens 4403cb34c60Sahrens rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj, 4413cb34c60Sahrens rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx); 4423cb34c60Sahrens } 443f18faf3fSek 444f18faf3fSek /* ARGSUSED */ 445f18faf3fSek static int 4463cb34c60Sahrens recv_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 447f18faf3fSek { 4483cb34c60Sahrens dsl_dataset_t *ds = arg1; 4493cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 4503cb34c60Sahrens int err; 4513cb34c60Sahrens uint64_t val; 452f18faf3fSek 4533cb34c60Sahrens /* must not have any changes since most recent snapshot */ 4543cb34c60Sahrens if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds)) 455f18faf3fSek return (ETXTBSY); 456f18faf3fSek 4573cb34c60Sahrens /* must already be a snapshot of this fs */ 4583cb34c60Sahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 4593cb34c60Sahrens return (ENODEV); 4603cb34c60Sahrens 4613cb34c60Sahrens /* most recent snapshot must match fromguid */ 4623cb34c60Sahrens if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid) 4633cb34c60Sahrens return (ENODEV); 4643cb34c60Sahrens 46547f263f4Sek /* temporary clone name must not exist */ 46647f263f4Sek err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 46747f263f4Sek ds->ds_dir->dd_phys->dd_child_dir_zapobj, 46847f263f4Sek rbsa->clonelastname, 8, 1, &val); 46947f263f4Sek if (err == 0) 47047f263f4Sek return (EEXIST); 47147f263f4Sek if (err != ENOENT) 47247f263f4Sek return (err); 47347f263f4Sek 4743cb34c60Sahrens /* new snapshot name must not exist */ 4753cb34c60Sahrens err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 4763cb34c60Sahrens ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val); 4773cb34c60Sahrens if (err == 0) 4783cb34c60Sahrens return (EEXIST); 4793cb34c60Sahrens if (err != ENOENT) 4803cb34c60Sahrens return (err); 4813cb34c60Sahrens return (0); 482f18faf3fSek } 483f18faf3fSek 484f18faf3fSek /* ARGSUSED */ 485f18faf3fSek static void 486*f4b94bdeSMatthew Ahrens recv_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 487f18faf3fSek { 4883cb34c60Sahrens dsl_dataset_t *ohds = arg1; 4893cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 4903cb34c60Sahrens dsl_pool_t *dp = ohds->ds_dir->dd_pool; 4913cb34c60Sahrens dsl_dataset_t *ods, *cds; 492745cd3c5Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 493f18faf3fSek uint64_t dsobj; 494f18faf3fSek 4953cb34c60Sahrens /* create the temporary clone */ 496745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, ohds->ds_phys->ds_prev_snap_obj, 497745cd3c5Smaybee FTAG, &ods)); 4983cb34c60Sahrens dsobj = dsl_dataset_create_sync(ohds->ds_dir, 499ab04eb8eStimh rbsa->clonelastname, ods, flags, cr, tx); 500745cd3c5Smaybee dsl_dataset_rele(ods, FTAG); 501f18faf3fSek 502f18faf3fSek /* open the temporary clone */ 503745cd3c5Smaybee VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 504745cd3c5Smaybee DS_MODE_INCONSISTENT, dmu_recv_tag, &cds)); 5053cb34c60Sahrens 506a9799022Sck /* copy the refquota from the target fs to the clone */ 507a9799022Sck if (ohds->ds_quota > 0) 508a9799022Sck dsl_dataset_set_quota_sync(cds, &ohds->ds_quota, cr, tx); 509a9799022Sck 5103cb34c60Sahrens rbsa->ds = cds; 5113cb34c60Sahrens 5123cb34c60Sahrens spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 513745cd3c5Smaybee dp->dp_spa, tx, cr, "dataset = %lld", dsobj); 5143cb34c60Sahrens } 5153cb34c60Sahrens 5163cb34c60Sahrens /* 5173cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 5183cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 5193cb34c60Sahrens */ 5203cb34c60Sahrens int 5213cb34c60Sahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 522*f4b94bdeSMatthew Ahrens boolean_t force, objset_t *origin, dmu_recv_cookie_t *drc) 523efb80947Sahrens { 5243cb34c60Sahrens int err = 0; 5253cb34c60Sahrens boolean_t byteswap; 5263cb34c60Sahrens struct recvbeginsyncarg rbsa; 5273cb34c60Sahrens uint64_t version; 5283cb34c60Sahrens int flags; 5293cb34c60Sahrens dsl_dataset_t *ds; 530efb80947Sahrens 5313cb34c60Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) 5323cb34c60Sahrens byteswap = FALSE; 5333cb34c60Sahrens else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 5343cb34c60Sahrens byteswap = TRUE; 5353cb34c60Sahrens else 5363cb34c60Sahrens return (EINVAL); 5373cb34c60Sahrens 5383cb34c60Sahrens rbsa.tofs = tofs; 5393cb34c60Sahrens rbsa.tosnap = tosnap; 5403cb34c60Sahrens rbsa.origin = origin ? origin->os->os_dsl_dataset : NULL; 5413cb34c60Sahrens rbsa.fromguid = drrb->drr_fromguid; 5423cb34c60Sahrens rbsa.type = drrb->drr_type; 5433cb34c60Sahrens rbsa.tag = FTAG; 544ab04eb8eStimh rbsa.dsflags = 0; 5453cb34c60Sahrens version = drrb->drr_version; 5463cb34c60Sahrens flags = drrb->drr_flags; 5473cb34c60Sahrens 5483cb34c60Sahrens if (byteswap) { 5493cb34c60Sahrens rbsa.type = BSWAP_32(rbsa.type); 5503cb34c60Sahrens rbsa.fromguid = BSWAP_64(rbsa.fromguid); 5513cb34c60Sahrens version = BSWAP_64(version); 5523cb34c60Sahrens flags = BSWAP_32(flags); 5533cb34c60Sahrens } 554efb80947Sahrens 5553cb34c60Sahrens if (version != DMU_BACKUP_STREAM_VERSION || 5563cb34c60Sahrens rbsa.type >= DMU_OST_NUMTYPES || 5573cb34c60Sahrens ((flags & DRR_FLAG_CLONE) && origin == NULL)) 558efb80947Sahrens return (EINVAL); 559efb80947Sahrens 560ab04eb8eStimh if (flags & DRR_FLAG_CI_DATA) 561ab04eb8eStimh rbsa.dsflags = DS_FLAG_CI_DATASET; 562ab04eb8eStimh 5633cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 5643cb34c60Sahrens drc->drc_drrb = drrb; 5653cb34c60Sahrens drc->drc_tosnap = tosnap; 5663cb34c60Sahrens drc->drc_force = force; 567efb80947Sahrens 5683cb34c60Sahrens /* 5693cb34c60Sahrens * Process the begin in syncing context. 5703cb34c60Sahrens */ 571*f4b94bdeSMatthew Ahrens if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) { 572*f4b94bdeSMatthew Ahrens /* incremental receive */ 573efb80947Sahrens 5743cb34c60Sahrens /* tmp clone name is: tofs/%tosnap" */ 5753cb34c60Sahrens (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname), 5763cb34c60Sahrens "%%%s", tosnap); 577efb80947Sahrens 5783cb34c60Sahrens /* open the dataset we are logically receiving into */ 579745cd3c5Smaybee err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds); 5803cb34c60Sahrens if (err) 5813cb34c60Sahrens return (err); 582efb80947Sahrens 583*f4b94bdeSMatthew Ahrens /* must not have an incremental recv already in progress */ 584*f4b94bdeSMatthew Ahrens if (!mutex_tryenter(&ds->ds_recvlock)) { 585*f4b94bdeSMatthew Ahrens dsl_dataset_rele(ds, dmu_recv_tag); 586*f4b94bdeSMatthew Ahrens return (EBUSY); 587*f4b94bdeSMatthew Ahrens } 588*f4b94bdeSMatthew Ahrens 5893cb34c60Sahrens rbsa.force = force; 5903cb34c60Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 5913cb34c60Sahrens recv_incremental_check, 592*f4b94bdeSMatthew Ahrens recv_incremental_sync, ds, &rbsa, 5); 5933cb34c60Sahrens if (err) { 594*f4b94bdeSMatthew Ahrens mutex_exit(&ds->ds_recvlock); 595745cd3c5Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 5963cb34c60Sahrens return (err); 5973cb34c60Sahrens } 5983cb34c60Sahrens drc->drc_logical_ds = ds; 5993cb34c60Sahrens drc->drc_real_ds = rbsa.ds; 6003cb34c60Sahrens } else { 6013cb34c60Sahrens /* create new fs -- full backup or clone */ 6023cb34c60Sahrens dsl_dir_t *dd = NULL; 6033cb34c60Sahrens const char *tail; 604efb80947Sahrens 6053cb34c60Sahrens err = dsl_dir_open(tofs, FTAG, &dd, &tail); 6063cb34c60Sahrens if (err) 6073cb34c60Sahrens return (err); 6083cb34c60Sahrens if (tail == NULL) { 6093cb34c60Sahrens if (!force) { 6103cb34c60Sahrens dsl_dir_close(dd, FTAG); 6113cb34c60Sahrens return (EEXIST); 6123cb34c60Sahrens } 613ecd6cf80Smarks 6143cb34c60Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 615745cd3c5Smaybee err = dsl_dataset_own_obj(dd->dd_pool, 616745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, 617745cd3c5Smaybee DS_MODE_INCONSISTENT, FTAG, &ds); 6183cb34c60Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 6193cb34c60Sahrens if (err) { 6203cb34c60Sahrens dsl_dir_close(dd, FTAG); 6213cb34c60Sahrens return (err); 6223cb34c60Sahrens } 623efb80947Sahrens 624745cd3c5Smaybee dsl_dataset_make_exclusive(ds, FTAG); 6253cb34c60Sahrens err = dsl_sync_task_do(dd->dd_pool, 6263cb34c60Sahrens recv_full_existing_check, 6273cb34c60Sahrens recv_full_existing_sync, ds, &rbsa, 5); 628745cd3c5Smaybee dsl_dataset_disown(ds, FTAG); 6293cb34c60Sahrens } else { 6303cb34c60Sahrens err = dsl_sync_task_do(dd->dd_pool, recv_full_check, 6313cb34c60Sahrens recv_full_sync, dd, &rbsa, 5); 6323cb34c60Sahrens } 6333cb34c60Sahrens dsl_dir_close(dd, FTAG); 6343cb34c60Sahrens if (err) 6353cb34c60Sahrens return (err); 6363cb34c60Sahrens drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds; 6373cb34c60Sahrens drc->drc_newfs = B_TRUE; 6383cb34c60Sahrens } 6393cb34c60Sahrens 6403cb34c60Sahrens return (0); 641efb80947Sahrens } 642efb80947Sahrens 6433cb34c60Sahrens struct restorearg { 6443cb34c60Sahrens int err; 6453cb34c60Sahrens int byteswap; 6463cb34c60Sahrens vnode_t *vp; 6473cb34c60Sahrens char *buf; 6483cb34c60Sahrens uint64_t voff; 6493cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 6503cb34c60Sahrens zio_cksum_t cksum; 6513cb34c60Sahrens }; 6523cb34c60Sahrens 653efb80947Sahrens static void * 654efb80947Sahrens restore_read(struct restorearg *ra, int len) 655efb80947Sahrens { 656efb80947Sahrens void *rv; 6573cb34c60Sahrens int done = 0; 658efb80947Sahrens 659efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 660efb80947Sahrens ASSERT3U(len % 8, ==, 0); 661efb80947Sahrens 6623cb34c60Sahrens while (done < len) { 663efb80947Sahrens ssize_t resid; 664efb80947Sahrens 665efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 6663cb34c60Sahrens (caddr_t)ra->buf + done, len - done, 667efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 668efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 669efb80947Sahrens 6703cb34c60Sahrens if (resid == len - done) 671efb80947Sahrens ra->err = EINVAL; 6723cb34c60Sahrens ra->voff += len - done - resid; 6733cb34c60Sahrens done = len - resid; 674efb80947Sahrens if (ra->err) 675efb80947Sahrens return (NULL); 676efb80947Sahrens } 677efb80947Sahrens 6783cb34c60Sahrens ASSERT3U(done, ==, len); 6793cb34c60Sahrens rv = ra->buf; 680efb80947Sahrens if (ra->byteswap) 6813cb34c60Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 682efb80947Sahrens else 6833cb34c60Sahrens fletcher_4_incremental_native(rv, len, &ra->cksum); 684efb80947Sahrens return (rv); 685efb80947Sahrens } 686efb80947Sahrens 687efb80947Sahrens static void 688efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 689efb80947Sahrens { 690efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 691efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 692efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 6933cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 694efb80947Sahrens switch (drr->drr_type) { 695efb80947Sahrens case DRR_BEGIN: 696efb80947Sahrens DO64(drr_begin.drr_magic); 697efb80947Sahrens DO64(drr_begin.drr_version); 698efb80947Sahrens DO64(drr_begin.drr_creation_time); 699efb80947Sahrens DO32(drr_begin.drr_type); 7003cb34c60Sahrens DO32(drr_begin.drr_flags); 701efb80947Sahrens DO64(drr_begin.drr_toguid); 702efb80947Sahrens DO64(drr_begin.drr_fromguid); 703efb80947Sahrens break; 704efb80947Sahrens case DRR_OBJECT: 705efb80947Sahrens DO64(drr_object.drr_object); 706efb80947Sahrens /* DO64(drr_object.drr_allocation_txg); */ 707efb80947Sahrens DO32(drr_object.drr_type); 708efb80947Sahrens DO32(drr_object.drr_bonustype); 709efb80947Sahrens DO32(drr_object.drr_blksz); 710efb80947Sahrens DO32(drr_object.drr_bonuslen); 711efb80947Sahrens break; 712efb80947Sahrens case DRR_FREEOBJECTS: 713efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 714efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 715efb80947Sahrens break; 716efb80947Sahrens case DRR_WRITE: 717efb80947Sahrens DO64(drr_write.drr_object); 718efb80947Sahrens DO32(drr_write.drr_type); 719efb80947Sahrens DO64(drr_write.drr_offset); 720efb80947Sahrens DO64(drr_write.drr_length); 721efb80947Sahrens break; 722efb80947Sahrens case DRR_FREE: 723efb80947Sahrens DO64(drr_free.drr_object); 724efb80947Sahrens DO64(drr_free.drr_offset); 725efb80947Sahrens DO64(drr_free.drr_length); 726efb80947Sahrens break; 727efb80947Sahrens case DRR_END: 728efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 729efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 730efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 731efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 732efb80947Sahrens break; 733efb80947Sahrens } 734efb80947Sahrens #undef DO64 735efb80947Sahrens #undef DO32 736efb80947Sahrens } 737efb80947Sahrens 738efb80947Sahrens static int 739efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 740efb80947Sahrens { 741efb80947Sahrens int err; 742efb80947Sahrens dmu_tx_t *tx; 743adee0b6fSTim Haley void *data = NULL; 744efb80947Sahrens 745efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 746efb80947Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 747efb80947Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 748efb80947Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 749efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 750efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 751efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 752efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 753efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 754efb80947Sahrens return (EINVAL); 755efb80947Sahrens } 756efb80947Sahrens 7572bf405a2SMark Maybee err = dmu_object_info(os, drro->drr_object, NULL); 7582bf405a2SMark Maybee 7592bf405a2SMark Maybee if (err != 0 && err != ENOENT) 7602bf405a2SMark Maybee return (EINVAL); 7612bf405a2SMark Maybee 762adee0b6fSTim Haley if (drro->drr_bonuslen) { 763adee0b6fSTim Haley data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 764adee0b6fSTim Haley if (ra->err) 765adee0b6fSTim Haley return (ra->err); 766adee0b6fSTim Haley } 767adee0b6fSTim Haley 768efb80947Sahrens if (err == ENOENT) { 769efb80947Sahrens /* currently free, want to be allocated */ 7702bf405a2SMark Maybee tx = dmu_tx_create(os); 771efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 772efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 773efb80947Sahrens if (err) { 774efb80947Sahrens dmu_tx_abort(tx); 775efb80947Sahrens return (err); 776efb80947Sahrens } 777efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 778efb80947Sahrens drro->drr_type, drro->drr_blksz, 779efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 7802bf405a2SMark Maybee dmu_tx_commit(tx); 781efb80947Sahrens } else { 782efb80947Sahrens /* currently allocated, want to be allocated */ 783efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 784efb80947Sahrens drro->drr_type, drro->drr_blksz, 7852bf405a2SMark Maybee drro->drr_bonustype, drro->drr_bonuslen); 786efb80947Sahrens } 7872bf405a2SMark Maybee if (err) 788efb80947Sahrens return (EINVAL); 7892bf405a2SMark Maybee 7902bf405a2SMark Maybee tx = dmu_tx_create(os); 7912bf405a2SMark Maybee dmu_tx_hold_bonus(tx, drro->drr_object); 7922bf405a2SMark Maybee err = dmu_tx_assign(tx, TXG_WAIT); 7932bf405a2SMark Maybee if (err) { 7942bf405a2SMark Maybee dmu_tx_abort(tx); 7952bf405a2SMark Maybee return (err); 796efb80947Sahrens } 797efb80947Sahrens 798efb80947Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 799efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 800efb80947Sahrens 801adee0b6fSTim Haley if (data != NULL) { 802efb80947Sahrens dmu_buf_t *db; 803adee0b6fSTim Haley 804efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 805efb80947Sahrens dmu_buf_will_dirty(db, tx); 806efb80947Sahrens 8071934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 8081934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 809efb80947Sahrens if (ra->byteswap) { 810efb80947Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 811efb80947Sahrens drro->drr_bonuslen); 812efb80947Sahrens } 813efb80947Sahrens dmu_buf_rele(db, FTAG); 814efb80947Sahrens } 815efb80947Sahrens dmu_tx_commit(tx); 816efb80947Sahrens return (0); 817efb80947Sahrens } 818efb80947Sahrens 819efb80947Sahrens /* ARGSUSED */ 820efb80947Sahrens static int 821efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 822efb80947Sahrens struct drr_freeobjects *drrfo) 823efb80947Sahrens { 824efb80947Sahrens uint64_t obj; 825efb80947Sahrens 826efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 827efb80947Sahrens return (EINVAL); 828efb80947Sahrens 829efb80947Sahrens for (obj = drrfo->drr_firstobj; 830432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 831432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 832efb80947Sahrens int err; 833efb80947Sahrens 834efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 835efb80947Sahrens continue; 836efb80947Sahrens 837cdb0ab79Smaybee err = dmu_free_object(os, obj); 838cdb0ab79Smaybee if (err) 839efb80947Sahrens return (err); 840efb80947Sahrens } 841efb80947Sahrens return (0); 842efb80947Sahrens } 843efb80947Sahrens 844efb80947Sahrens static int 845efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 846efb80947Sahrens struct drr_write *drrw) 847efb80947Sahrens { 848efb80947Sahrens dmu_tx_t *tx; 849efb80947Sahrens void *data; 850efb80947Sahrens int err; 851efb80947Sahrens 852efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 853efb80947Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 854efb80947Sahrens return (EINVAL); 855efb80947Sahrens 856efb80947Sahrens data = restore_read(ra, drrw->drr_length); 857efb80947Sahrens if (data == NULL) 858efb80947Sahrens return (ra->err); 859efb80947Sahrens 860efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 861efb80947Sahrens return (EINVAL); 862efb80947Sahrens 863efb80947Sahrens tx = dmu_tx_create(os); 864efb80947Sahrens 865efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 866efb80947Sahrens drrw->drr_offset, drrw->drr_length); 867efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 868efb80947Sahrens if (err) { 869efb80947Sahrens dmu_tx_abort(tx); 870efb80947Sahrens return (err); 871efb80947Sahrens } 872efb80947Sahrens if (ra->byteswap) 873efb80947Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 874efb80947Sahrens dmu_write(os, drrw->drr_object, 875efb80947Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 876efb80947Sahrens dmu_tx_commit(tx); 877efb80947Sahrens return (0); 878efb80947Sahrens } 879efb80947Sahrens 880efb80947Sahrens /* ARGSUSED */ 881efb80947Sahrens static int 882efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 883efb80947Sahrens struct drr_free *drrf) 884efb80947Sahrens { 885efb80947Sahrens int err; 886efb80947Sahrens 887efb80947Sahrens if (drrf->drr_length != -1ULL && 888efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 889efb80947Sahrens return (EINVAL); 890efb80947Sahrens 891efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 892efb80947Sahrens return (EINVAL); 893efb80947Sahrens 894cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 895efb80947Sahrens drrf->drr_offset, drrf->drr_length); 896efb80947Sahrens return (err); 897efb80947Sahrens } 898efb80947Sahrens 8993cb34c60Sahrens /* 9003cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 9013cb34c60Sahrens */ 902efb80947Sahrens int 9033cb34c60Sahrens dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp) 904efb80947Sahrens { 9053cb34c60Sahrens struct restorearg ra = { 0 }; 906efb80947Sahrens dmu_replay_record_t *drr; 9073cb34c60Sahrens objset_t *os; 9083cb34c60Sahrens zio_cksum_t pcksum; 909efb80947Sahrens 9103cb34c60Sahrens if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 911efb80947Sahrens ra.byteswap = TRUE; 912efb80947Sahrens 9133cb34c60Sahrens { 9143cb34c60Sahrens /* compute checksum of drr_begin record */ 9153cb34c60Sahrens dmu_replay_record_t *drr; 9163cb34c60Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 9173cb34c60Sahrens 9183cb34c60Sahrens drr->drr_type = DRR_BEGIN; 9193cb34c60Sahrens drr->drr_u.drr_begin = *drc->drc_drrb; 9203cb34c60Sahrens if (ra.byteswap) { 9213cb34c60Sahrens fletcher_4_incremental_byteswap(drr, 9223cb34c60Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9233cb34c60Sahrens } else { 9243cb34c60Sahrens fletcher_4_incremental_native(drr, 9253cb34c60Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9263cb34c60Sahrens } 9273cb34c60Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 928efb80947Sahrens } 929efb80947Sahrens 930efb80947Sahrens if (ra.byteswap) { 9313cb34c60Sahrens struct drr_begin *drrb = drc->drc_drrb; 932efb80947Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 933efb80947Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 934efb80947Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 935efb80947Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 936efb80947Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 937efb80947Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 938efb80947Sahrens } 939efb80947Sahrens 9403cb34c60Sahrens ra.vp = vp; 9413cb34c60Sahrens ra.voff = *voffp; 9423cb34c60Sahrens ra.bufsize = 1<<20; 9433cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 944efb80947Sahrens 9453cb34c60Sahrens /* these were verified in dmu_recv_begin */ 9463cb34c60Sahrens ASSERT(drc->drc_drrb->drr_version == DMU_BACKUP_STREAM_VERSION); 9473cb34c60Sahrens ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES); 948efb80947Sahrens 949efb80947Sahrens /* 950efb80947Sahrens * Open the objset we are modifying. 951efb80947Sahrens */ 9523cb34c60Sahrens VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0); 953efb80947Sahrens 9543cb34c60Sahrens ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 955efb80947Sahrens 956efb80947Sahrens /* 957efb80947Sahrens * Read records and process them. 958efb80947Sahrens */ 9593cb34c60Sahrens pcksum = ra.cksum; 960efb80947Sahrens while (ra.err == 0 && 961efb80947Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 962efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 963efb80947Sahrens ra.err = EINTR; 964efb80947Sahrens goto out; 965efb80947Sahrens } 966efb80947Sahrens 967efb80947Sahrens if (ra.byteswap) 968efb80947Sahrens backup_byteswap(drr); 969efb80947Sahrens 970efb80947Sahrens switch (drr->drr_type) { 971efb80947Sahrens case DRR_OBJECT: 972efb80947Sahrens { 973efb80947Sahrens /* 974efb80947Sahrens * We need to make a copy of the record header, 975efb80947Sahrens * because restore_{object,write} may need to 976efb80947Sahrens * restore_read(), which will invalidate drr. 977efb80947Sahrens */ 978efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 979efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 980efb80947Sahrens break; 981efb80947Sahrens } 982efb80947Sahrens case DRR_FREEOBJECTS: 983efb80947Sahrens { 984efb80947Sahrens struct drr_freeobjects drrfo = 985efb80947Sahrens drr->drr_u.drr_freeobjects; 986efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 987efb80947Sahrens break; 988efb80947Sahrens } 989efb80947Sahrens case DRR_WRITE: 990efb80947Sahrens { 991efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 992efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 993efb80947Sahrens break; 994efb80947Sahrens } 995efb80947Sahrens case DRR_FREE: 996efb80947Sahrens { 997efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 998efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 999efb80947Sahrens break; 1000efb80947Sahrens } 1001efb80947Sahrens case DRR_END: 1002efb80947Sahrens { 1003efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1004efb80947Sahrens /* 1005efb80947Sahrens * We compare against the *previous* checksum 1006efb80947Sahrens * value, because the stored checksum is of 1007efb80947Sahrens * everything before the DRR_END record. 1008efb80947Sahrens */ 1009137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1010efb80947Sahrens ra.err = ECKSUM; 1011efb80947Sahrens goto out; 1012efb80947Sahrens } 1013efb80947Sahrens default: 1014efb80947Sahrens ra.err = EINVAL; 1015efb80947Sahrens goto out; 1016efb80947Sahrens } 10173cb34c60Sahrens pcksum = ra.cksum; 1018efb80947Sahrens } 1019137fa067Sahrens ASSERT(ra.err != 0); 1020efb80947Sahrens 1021efb80947Sahrens out: 10223cb34c60Sahrens dmu_objset_close(os); 1023efb80947Sahrens 10243cb34c60Sahrens if (ra.err != 0) { 1025efb80947Sahrens /* 1026*f4b94bdeSMatthew Ahrens * destroy what we created, so we don't leave it in the 1027*f4b94bdeSMatthew Ahrens * inconsistent restoring state. 1028efb80947Sahrens */ 10293cb34c60Sahrens txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0); 1030*f4b94bdeSMatthew Ahrens 1031*f4b94bdeSMatthew Ahrens (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 1032*f4b94bdeSMatthew Ahrens if (drc->drc_real_ds != drc->drc_logical_ds) { 1033*f4b94bdeSMatthew Ahrens mutex_exit(&drc->drc_logical_ds->ds_recvlock); 1034*f4b94bdeSMatthew Ahrens dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag); 1035*f4b94bdeSMatthew Ahrens } 1036efb80947Sahrens } 1037efb80947Sahrens 1038efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 10393cb34c60Sahrens *voffp = ra.voff; 1040efb80947Sahrens return (ra.err); 1041efb80947Sahrens } 1042f18faf3fSek 10433cb34c60Sahrens struct recvendsyncarg { 10443cb34c60Sahrens char *tosnap; 10453cb34c60Sahrens uint64_t creation_time; 10463cb34c60Sahrens uint64_t toguid; 10473cb34c60Sahrens }; 10483cb34c60Sahrens 10493cb34c60Sahrens static int 10503cb34c60Sahrens recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 10513cb34c60Sahrens { 10523cb34c60Sahrens dsl_dataset_t *ds = arg1; 10533cb34c60Sahrens struct recvendsyncarg *resa = arg2; 10543cb34c60Sahrens 10553cb34c60Sahrens return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx)); 10563cb34c60Sahrens } 10573cb34c60Sahrens 10583cb34c60Sahrens static void 10593cb34c60Sahrens recv_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 10603cb34c60Sahrens { 10613cb34c60Sahrens dsl_dataset_t *ds = arg1; 10623cb34c60Sahrens struct recvendsyncarg *resa = arg2; 10633cb34c60Sahrens 10643cb34c60Sahrens dsl_dataset_snapshot_sync(ds, resa->tosnap, cr, tx); 10653cb34c60Sahrens 10663cb34c60Sahrens /* set snapshot's creation time and guid */ 10673cb34c60Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 10683cb34c60Sahrens ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time; 10693cb34c60Sahrens ds->ds_prev->ds_phys->ds_guid = resa->toguid; 10703cb34c60Sahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 10713cb34c60Sahrens 10723cb34c60Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10733cb34c60Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 10743cb34c60Sahrens } 10753cb34c60Sahrens 1076f18faf3fSek int 10773cb34c60Sahrens dmu_recv_end(dmu_recv_cookie_t *drc) 1078f18faf3fSek { 1079745cd3c5Smaybee struct recvendsyncarg resa; 1080745cd3c5Smaybee dsl_dataset_t *ds = drc->drc_logical_ds; 1081745cd3c5Smaybee int err; 1082f18faf3fSek 10833cb34c60Sahrens /* 10843cb34c60Sahrens * XXX hack; seems the ds is still dirty and 1085745cd3c5Smaybee * dsl_pool_zil_clean() expects it to have a ds_user_ptr 1086745cd3c5Smaybee * (and zil), but clone_swap() can close it. 10873cb34c60Sahrens */ 1088745cd3c5Smaybee txg_wait_synced(ds->ds_dir->dd_pool, 0); 10893cb34c60Sahrens 1090745cd3c5Smaybee if (ds != drc->drc_real_ds) { 1091745cd3c5Smaybee /* we are doing an online recv */ 1092745cd3c5Smaybee if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) { 1093745cd3c5Smaybee err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, 1094745cd3c5Smaybee drc->drc_force); 1095745cd3c5Smaybee if (err) 1096745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 10973cb34c60Sahrens } else { 10983cb34c60Sahrens err = EBUSY; 1099745cd3c5Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 11003cb34c60Sahrens } 1101745cd3c5Smaybee /* dsl_dataset_destroy() will disown the ds */ 1102745cd3c5Smaybee (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 1103*f4b94bdeSMatthew Ahrens mutex_exit(&drc->drc_logical_ds->ds_recvlock); 1104745cd3c5Smaybee if (err) 1105745cd3c5Smaybee return (err); 11063cb34c60Sahrens } 11073cb34c60Sahrens 1108745cd3c5Smaybee resa.creation_time = drc->drc_drrb->drr_creation_time; 1109745cd3c5Smaybee resa.toguid = drc->drc_drrb->drr_toguid; 1110745cd3c5Smaybee resa.tosnap = drc->drc_tosnap; 11113cb34c60Sahrens 1112745cd3c5Smaybee err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1113745cd3c5Smaybee recv_end_check, recv_end_sync, ds, &resa, 3); 1114745cd3c5Smaybee if (err) { 1115745cd3c5Smaybee if (drc->drc_newfs) { 1116745cd3c5Smaybee ASSERT(ds == drc->drc_real_ds); 1117745cd3c5Smaybee (void) dsl_dataset_destroy(ds, dmu_recv_tag); 1118745cd3c5Smaybee return (err); 1119745cd3c5Smaybee } else { 1120745cd3c5Smaybee (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 11213cb34c60Sahrens } 11223cb34c60Sahrens } 11233cb34c60Sahrens 1124745cd3c5Smaybee /* release the hold from dmu_recv_begin */ 1125745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 1126f18faf3fSek return (err); 1127f18faf3fSek } 1128