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 164*14843421SMatthew Ahrens if (zb->zb_object != 0 && DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 165*14843421SMatthew Ahrens return (0); 166*14843421SMatthew 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 4863cb34c60Sahrens recv_online_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 /* ARGSUSED */ 5173cb34c60Sahrens static void 5183cb34c60Sahrens recv_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 5193cb34c60Sahrens { 5203cb34c60Sahrens dsl_dataset_t *ds = arg1; 521a9799022Sck 522f18faf3fSek dmu_buf_will_dirty(ds->ds_dbuf, tx); 523f18faf3fSek ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 524f18faf3fSek 525f18faf3fSek spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 526f18faf3fSek ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld", 527745cd3c5Smaybee ds->ds_object); 528f18faf3fSek } 529f18faf3fSek 5303cb34c60Sahrens /* 5313cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 5323cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 5333cb34c60Sahrens */ 5343cb34c60Sahrens int 5353cb34c60Sahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 5363cb34c60Sahrens boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *drc) 537efb80947Sahrens { 5383cb34c60Sahrens int err = 0; 5393cb34c60Sahrens boolean_t byteswap; 5403cb34c60Sahrens struct recvbeginsyncarg rbsa; 5413cb34c60Sahrens uint64_t version; 5423cb34c60Sahrens int flags; 5433cb34c60Sahrens dsl_dataset_t *ds; 544efb80947Sahrens 5453cb34c60Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) 5463cb34c60Sahrens byteswap = FALSE; 5473cb34c60Sahrens else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 5483cb34c60Sahrens byteswap = TRUE; 5493cb34c60Sahrens else 5503cb34c60Sahrens return (EINVAL); 5513cb34c60Sahrens 5523cb34c60Sahrens rbsa.tofs = tofs; 5533cb34c60Sahrens rbsa.tosnap = tosnap; 5543cb34c60Sahrens rbsa.origin = origin ? origin->os->os_dsl_dataset : NULL; 5553cb34c60Sahrens rbsa.fromguid = drrb->drr_fromguid; 5563cb34c60Sahrens rbsa.type = drrb->drr_type; 5573cb34c60Sahrens rbsa.tag = FTAG; 558ab04eb8eStimh rbsa.dsflags = 0; 5593cb34c60Sahrens version = drrb->drr_version; 5603cb34c60Sahrens flags = drrb->drr_flags; 5613cb34c60Sahrens 5623cb34c60Sahrens if (byteswap) { 5633cb34c60Sahrens rbsa.type = BSWAP_32(rbsa.type); 5643cb34c60Sahrens rbsa.fromguid = BSWAP_64(rbsa.fromguid); 5653cb34c60Sahrens version = BSWAP_64(version); 5663cb34c60Sahrens flags = BSWAP_32(flags); 5673cb34c60Sahrens } 568efb80947Sahrens 5693cb34c60Sahrens if (version != DMU_BACKUP_STREAM_VERSION || 5703cb34c60Sahrens rbsa.type >= DMU_OST_NUMTYPES || 5713cb34c60Sahrens ((flags & DRR_FLAG_CLONE) && origin == NULL)) 572efb80947Sahrens return (EINVAL); 573efb80947Sahrens 574ab04eb8eStimh if (flags & DRR_FLAG_CI_DATA) 575ab04eb8eStimh rbsa.dsflags = DS_FLAG_CI_DATASET; 576ab04eb8eStimh 5773cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 5783cb34c60Sahrens drc->drc_drrb = drrb; 5793cb34c60Sahrens drc->drc_tosnap = tosnap; 5803cb34c60Sahrens drc->drc_force = force; 581efb80947Sahrens 5823cb34c60Sahrens /* 5833cb34c60Sahrens * Process the begin in syncing context. 5843cb34c60Sahrens */ 5853cb34c60Sahrens if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE) && !online) { 5863cb34c60Sahrens /* offline incremental receive */ 587745cd3c5Smaybee err = dsl_dataset_own(tofs, 0, dmu_recv_tag, &ds); 5883cb34c60Sahrens if (err) 5893cb34c60Sahrens return (err); 590efb80947Sahrens 5913cb34c60Sahrens /* 5923cb34c60Sahrens * Only do the rollback if the most recent snapshot 5933cb34c60Sahrens * matches the incremental source 5943cb34c60Sahrens */ 5953cb34c60Sahrens if (force) { 5963cb34c60Sahrens if (ds->ds_prev == NULL || 5973cb34c60Sahrens ds->ds_prev->ds_phys->ds_guid != 5983cb34c60Sahrens rbsa.fromguid) { 599745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 6003cb34c60Sahrens return (ENODEV); 6013cb34c60Sahrens } 6023cb34c60Sahrens (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 6033cb34c60Sahrens } 6043cb34c60Sahrens rbsa.force = B_FALSE; 6053cb34c60Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 6063cb34c60Sahrens recv_incremental_check, 607745cd3c5Smaybee recv_offline_incremental_sync, ds, &rbsa, 1); 6083cb34c60Sahrens if (err) { 609745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 6103cb34c60Sahrens return (err); 6113cb34c60Sahrens } 6123cb34c60Sahrens drc->drc_logical_ds = drc->drc_real_ds = ds; 6133cb34c60Sahrens } else if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) { 6143cb34c60Sahrens /* online incremental receive */ 615efb80947Sahrens 6163cb34c60Sahrens /* tmp clone name is: tofs/%tosnap" */ 6173cb34c60Sahrens (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname), 6183cb34c60Sahrens "%%%s", tosnap); 619efb80947Sahrens 6203cb34c60Sahrens /* open the dataset we are logically receiving into */ 621745cd3c5Smaybee err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds); 6223cb34c60Sahrens if (err) 6233cb34c60Sahrens return (err); 624efb80947Sahrens 6253cb34c60Sahrens rbsa.force = force; 6263cb34c60Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 6273cb34c60Sahrens recv_incremental_check, 6283cb34c60Sahrens recv_online_incremental_sync, ds, &rbsa, 5); 6293cb34c60Sahrens if (err) { 630745cd3c5Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 6313cb34c60Sahrens return (err); 6323cb34c60Sahrens } 6333cb34c60Sahrens drc->drc_logical_ds = ds; 6343cb34c60Sahrens drc->drc_real_ds = rbsa.ds; 6353cb34c60Sahrens } else { 6363cb34c60Sahrens /* create new fs -- full backup or clone */ 6373cb34c60Sahrens dsl_dir_t *dd = NULL; 6383cb34c60Sahrens const char *tail; 639efb80947Sahrens 6403cb34c60Sahrens err = dsl_dir_open(tofs, FTAG, &dd, &tail); 6413cb34c60Sahrens if (err) 6423cb34c60Sahrens return (err); 6433cb34c60Sahrens if (tail == NULL) { 6443cb34c60Sahrens if (!force) { 6453cb34c60Sahrens dsl_dir_close(dd, FTAG); 6463cb34c60Sahrens return (EEXIST); 6473cb34c60Sahrens } 648ecd6cf80Smarks 6493cb34c60Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 650745cd3c5Smaybee err = dsl_dataset_own_obj(dd->dd_pool, 651745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, 652745cd3c5Smaybee DS_MODE_INCONSISTENT, FTAG, &ds); 6533cb34c60Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 6543cb34c60Sahrens if (err) { 6553cb34c60Sahrens dsl_dir_close(dd, FTAG); 6563cb34c60Sahrens return (err); 6573cb34c60Sahrens } 658efb80947Sahrens 659745cd3c5Smaybee dsl_dataset_make_exclusive(ds, FTAG); 6603cb34c60Sahrens err = dsl_sync_task_do(dd->dd_pool, 6613cb34c60Sahrens recv_full_existing_check, 6623cb34c60Sahrens recv_full_existing_sync, ds, &rbsa, 5); 663745cd3c5Smaybee dsl_dataset_disown(ds, FTAG); 6643cb34c60Sahrens } else { 6653cb34c60Sahrens err = dsl_sync_task_do(dd->dd_pool, recv_full_check, 6663cb34c60Sahrens recv_full_sync, dd, &rbsa, 5); 6673cb34c60Sahrens } 6683cb34c60Sahrens dsl_dir_close(dd, FTAG); 6693cb34c60Sahrens if (err) 6703cb34c60Sahrens return (err); 6713cb34c60Sahrens drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds; 6723cb34c60Sahrens drc->drc_newfs = B_TRUE; 6733cb34c60Sahrens } 6743cb34c60Sahrens 6753cb34c60Sahrens return (0); 676efb80947Sahrens } 677efb80947Sahrens 6783cb34c60Sahrens struct restorearg { 6793cb34c60Sahrens int err; 6803cb34c60Sahrens int byteswap; 6813cb34c60Sahrens vnode_t *vp; 6823cb34c60Sahrens char *buf; 6833cb34c60Sahrens uint64_t voff; 6843cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 6853cb34c60Sahrens zio_cksum_t cksum; 6863cb34c60Sahrens }; 6873cb34c60Sahrens 688efb80947Sahrens static void * 689efb80947Sahrens restore_read(struct restorearg *ra, int len) 690efb80947Sahrens { 691efb80947Sahrens void *rv; 6923cb34c60Sahrens int done = 0; 693efb80947Sahrens 694efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 695efb80947Sahrens ASSERT3U(len % 8, ==, 0); 696efb80947Sahrens 6973cb34c60Sahrens while (done < len) { 698efb80947Sahrens ssize_t resid; 699efb80947Sahrens 700efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 7013cb34c60Sahrens (caddr_t)ra->buf + done, len - done, 702efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 703efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 704efb80947Sahrens 7053cb34c60Sahrens if (resid == len - done) 706efb80947Sahrens ra->err = EINVAL; 7073cb34c60Sahrens ra->voff += len - done - resid; 7083cb34c60Sahrens done = len - resid; 709efb80947Sahrens if (ra->err) 710efb80947Sahrens return (NULL); 711efb80947Sahrens } 712efb80947Sahrens 7133cb34c60Sahrens ASSERT3U(done, ==, len); 7143cb34c60Sahrens rv = ra->buf; 715efb80947Sahrens if (ra->byteswap) 7163cb34c60Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 717efb80947Sahrens else 7183cb34c60Sahrens fletcher_4_incremental_native(rv, len, &ra->cksum); 719efb80947Sahrens return (rv); 720efb80947Sahrens } 721efb80947Sahrens 722efb80947Sahrens static void 723efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 724efb80947Sahrens { 725efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 726efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 727efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 7283cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 729efb80947Sahrens switch (drr->drr_type) { 730efb80947Sahrens case DRR_BEGIN: 731efb80947Sahrens DO64(drr_begin.drr_magic); 732efb80947Sahrens DO64(drr_begin.drr_version); 733efb80947Sahrens DO64(drr_begin.drr_creation_time); 734efb80947Sahrens DO32(drr_begin.drr_type); 7353cb34c60Sahrens DO32(drr_begin.drr_flags); 736efb80947Sahrens DO64(drr_begin.drr_toguid); 737efb80947Sahrens DO64(drr_begin.drr_fromguid); 738efb80947Sahrens break; 739efb80947Sahrens case DRR_OBJECT: 740efb80947Sahrens DO64(drr_object.drr_object); 741efb80947Sahrens /* DO64(drr_object.drr_allocation_txg); */ 742efb80947Sahrens DO32(drr_object.drr_type); 743efb80947Sahrens DO32(drr_object.drr_bonustype); 744efb80947Sahrens DO32(drr_object.drr_blksz); 745efb80947Sahrens DO32(drr_object.drr_bonuslen); 746efb80947Sahrens break; 747efb80947Sahrens case DRR_FREEOBJECTS: 748efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 749efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 750efb80947Sahrens break; 751efb80947Sahrens case DRR_WRITE: 752efb80947Sahrens DO64(drr_write.drr_object); 753efb80947Sahrens DO32(drr_write.drr_type); 754efb80947Sahrens DO64(drr_write.drr_offset); 755efb80947Sahrens DO64(drr_write.drr_length); 756efb80947Sahrens break; 757efb80947Sahrens case DRR_FREE: 758efb80947Sahrens DO64(drr_free.drr_object); 759efb80947Sahrens DO64(drr_free.drr_offset); 760efb80947Sahrens DO64(drr_free.drr_length); 761efb80947Sahrens break; 762efb80947Sahrens case DRR_END: 763efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 764efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 765efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 766efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 767efb80947Sahrens break; 768efb80947Sahrens } 769efb80947Sahrens #undef DO64 770efb80947Sahrens #undef DO32 771efb80947Sahrens } 772efb80947Sahrens 773efb80947Sahrens static int 774efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 775efb80947Sahrens { 776efb80947Sahrens int err; 777efb80947Sahrens dmu_tx_t *tx; 778adee0b6fSTim Haley void *data = NULL; 779efb80947Sahrens 780efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 781efb80947Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 782efb80947Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 783efb80947Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 784efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 785efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 786efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 787efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 788efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 789efb80947Sahrens return (EINVAL); 790efb80947Sahrens } 791efb80947Sahrens 7922bf405a2SMark Maybee err = dmu_object_info(os, drro->drr_object, NULL); 7932bf405a2SMark Maybee 7942bf405a2SMark Maybee if (err != 0 && err != ENOENT) 7952bf405a2SMark Maybee return (EINVAL); 7962bf405a2SMark Maybee 797adee0b6fSTim Haley if (drro->drr_bonuslen) { 798adee0b6fSTim Haley data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 799adee0b6fSTim Haley if (ra->err) 800adee0b6fSTim Haley return (ra->err); 801adee0b6fSTim Haley } 802adee0b6fSTim Haley 803efb80947Sahrens if (err == ENOENT) { 804efb80947Sahrens /* currently free, want to be allocated */ 8052bf405a2SMark Maybee tx = dmu_tx_create(os); 806efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 807efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 808efb80947Sahrens if (err) { 809efb80947Sahrens dmu_tx_abort(tx); 810efb80947Sahrens return (err); 811efb80947Sahrens } 812efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 813efb80947Sahrens drro->drr_type, drro->drr_blksz, 814efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 8152bf405a2SMark Maybee dmu_tx_commit(tx); 816efb80947Sahrens } else { 817efb80947Sahrens /* currently allocated, want to be allocated */ 818efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 819efb80947Sahrens drro->drr_type, drro->drr_blksz, 8202bf405a2SMark Maybee drro->drr_bonustype, drro->drr_bonuslen); 821efb80947Sahrens } 8222bf405a2SMark Maybee if (err) 823efb80947Sahrens return (EINVAL); 8242bf405a2SMark Maybee 8252bf405a2SMark Maybee tx = dmu_tx_create(os); 8262bf405a2SMark Maybee dmu_tx_hold_bonus(tx, drro->drr_object); 8272bf405a2SMark Maybee err = dmu_tx_assign(tx, TXG_WAIT); 8282bf405a2SMark Maybee if (err) { 8292bf405a2SMark Maybee dmu_tx_abort(tx); 8302bf405a2SMark Maybee return (err); 831efb80947Sahrens } 832efb80947Sahrens 833efb80947Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 834efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 835efb80947Sahrens 836adee0b6fSTim Haley if (data != NULL) { 837efb80947Sahrens dmu_buf_t *db; 838adee0b6fSTim Haley 839efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 840efb80947Sahrens dmu_buf_will_dirty(db, tx); 841efb80947Sahrens 8421934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 8431934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 844efb80947Sahrens if (ra->byteswap) { 845efb80947Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 846efb80947Sahrens drro->drr_bonuslen); 847efb80947Sahrens } 848efb80947Sahrens dmu_buf_rele(db, FTAG); 849efb80947Sahrens } 850efb80947Sahrens dmu_tx_commit(tx); 851efb80947Sahrens return (0); 852efb80947Sahrens } 853efb80947Sahrens 854efb80947Sahrens /* ARGSUSED */ 855efb80947Sahrens static int 856efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 857efb80947Sahrens struct drr_freeobjects *drrfo) 858efb80947Sahrens { 859efb80947Sahrens uint64_t obj; 860efb80947Sahrens 861efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 862efb80947Sahrens return (EINVAL); 863efb80947Sahrens 864efb80947Sahrens for (obj = drrfo->drr_firstobj; 865432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 866432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 867efb80947Sahrens int err; 868efb80947Sahrens 869efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 870efb80947Sahrens continue; 871efb80947Sahrens 872cdb0ab79Smaybee err = dmu_free_object(os, obj); 873cdb0ab79Smaybee if (err) 874efb80947Sahrens return (err); 875efb80947Sahrens } 876efb80947Sahrens return (0); 877efb80947Sahrens } 878efb80947Sahrens 879efb80947Sahrens static int 880efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 881efb80947Sahrens struct drr_write *drrw) 882efb80947Sahrens { 883efb80947Sahrens dmu_tx_t *tx; 884efb80947Sahrens void *data; 885efb80947Sahrens int err; 886efb80947Sahrens 887efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 888efb80947Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 889efb80947Sahrens return (EINVAL); 890efb80947Sahrens 891efb80947Sahrens data = restore_read(ra, drrw->drr_length); 892efb80947Sahrens if (data == NULL) 893efb80947Sahrens return (ra->err); 894efb80947Sahrens 895efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 896efb80947Sahrens return (EINVAL); 897efb80947Sahrens 898efb80947Sahrens tx = dmu_tx_create(os); 899efb80947Sahrens 900efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 901efb80947Sahrens drrw->drr_offset, drrw->drr_length); 902efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 903efb80947Sahrens if (err) { 904efb80947Sahrens dmu_tx_abort(tx); 905efb80947Sahrens return (err); 906efb80947Sahrens } 907efb80947Sahrens if (ra->byteswap) 908efb80947Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 909efb80947Sahrens dmu_write(os, drrw->drr_object, 910efb80947Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 911efb80947Sahrens dmu_tx_commit(tx); 912efb80947Sahrens return (0); 913efb80947Sahrens } 914efb80947Sahrens 915efb80947Sahrens /* ARGSUSED */ 916efb80947Sahrens static int 917efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 918efb80947Sahrens struct drr_free *drrf) 919efb80947Sahrens { 920efb80947Sahrens int err; 921efb80947Sahrens 922efb80947Sahrens if (drrf->drr_length != -1ULL && 923efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 924efb80947Sahrens return (EINVAL); 925efb80947Sahrens 926efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 927efb80947Sahrens return (EINVAL); 928efb80947Sahrens 929cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 930efb80947Sahrens drrf->drr_offset, drrf->drr_length); 931efb80947Sahrens return (err); 932efb80947Sahrens } 933efb80947Sahrens 93447f263f4Sek void 93547f263f4Sek dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc) 9363cb34c60Sahrens { 9373cb34c60Sahrens if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) { 9383cb34c60Sahrens /* 9393cb34c60Sahrens * online incremental or new fs: destroy the fs (which 9403cb34c60Sahrens * may be a clone) that we created 9413cb34c60Sahrens */ 9423cb34c60Sahrens (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 943745cd3c5Smaybee if (drc->drc_real_ds != drc->drc_logical_ds) 944745cd3c5Smaybee dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag); 9453cb34c60Sahrens } else { 9463cb34c60Sahrens /* 9473cb34c60Sahrens * offline incremental: rollback to most recent snapshot. 9483cb34c60Sahrens */ 949745cd3c5Smaybee (void) dsl_dataset_rollback(drc->drc_real_ds, DMU_OST_NONE); 950745cd3c5Smaybee dsl_dataset_disown(drc->drc_real_ds, dmu_recv_tag); 9513cb34c60Sahrens } 9523cb34c60Sahrens } 9533cb34c60Sahrens 9543cb34c60Sahrens /* 9553cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 9563cb34c60Sahrens */ 957efb80947Sahrens int 9583cb34c60Sahrens dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp) 959efb80947Sahrens { 9603cb34c60Sahrens struct restorearg ra = { 0 }; 961efb80947Sahrens dmu_replay_record_t *drr; 9623cb34c60Sahrens objset_t *os; 9633cb34c60Sahrens zio_cksum_t pcksum; 964efb80947Sahrens 9653cb34c60Sahrens if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 966efb80947Sahrens ra.byteswap = TRUE; 967efb80947Sahrens 9683cb34c60Sahrens { 9693cb34c60Sahrens /* compute checksum of drr_begin record */ 9703cb34c60Sahrens dmu_replay_record_t *drr; 9713cb34c60Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 9723cb34c60Sahrens 9733cb34c60Sahrens drr->drr_type = DRR_BEGIN; 9743cb34c60Sahrens drr->drr_u.drr_begin = *drc->drc_drrb; 9753cb34c60Sahrens if (ra.byteswap) { 9763cb34c60Sahrens fletcher_4_incremental_byteswap(drr, 9773cb34c60Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9783cb34c60Sahrens } else { 9793cb34c60Sahrens fletcher_4_incremental_native(drr, 9803cb34c60Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9813cb34c60Sahrens } 9823cb34c60Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 983efb80947Sahrens } 984efb80947Sahrens 985efb80947Sahrens if (ra.byteswap) { 9863cb34c60Sahrens struct drr_begin *drrb = drc->drc_drrb; 987efb80947Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 988efb80947Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 989efb80947Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 990efb80947Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 991efb80947Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 992efb80947Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 993efb80947Sahrens } 994efb80947Sahrens 9953cb34c60Sahrens ra.vp = vp; 9963cb34c60Sahrens ra.voff = *voffp; 9973cb34c60Sahrens ra.bufsize = 1<<20; 9983cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 999efb80947Sahrens 10003cb34c60Sahrens /* these were verified in dmu_recv_begin */ 10013cb34c60Sahrens ASSERT(drc->drc_drrb->drr_version == DMU_BACKUP_STREAM_VERSION); 10023cb34c60Sahrens ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES); 1003efb80947Sahrens 1004efb80947Sahrens /* 1005efb80947Sahrens * Open the objset we are modifying. 1006efb80947Sahrens */ 10073cb34c60Sahrens VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0); 1008efb80947Sahrens 10093cb34c60Sahrens ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1010efb80947Sahrens 1011efb80947Sahrens /* 1012efb80947Sahrens * Read records and process them. 1013efb80947Sahrens */ 10143cb34c60Sahrens pcksum = ra.cksum; 1015efb80947Sahrens while (ra.err == 0 && 1016efb80947Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 1017efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 1018efb80947Sahrens ra.err = EINTR; 1019efb80947Sahrens goto out; 1020efb80947Sahrens } 1021efb80947Sahrens 1022efb80947Sahrens if (ra.byteswap) 1023efb80947Sahrens backup_byteswap(drr); 1024efb80947Sahrens 1025efb80947Sahrens switch (drr->drr_type) { 1026efb80947Sahrens case DRR_OBJECT: 1027efb80947Sahrens { 1028efb80947Sahrens /* 1029efb80947Sahrens * We need to make a copy of the record header, 1030efb80947Sahrens * because restore_{object,write} may need to 1031efb80947Sahrens * restore_read(), which will invalidate drr. 1032efb80947Sahrens */ 1033efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 1034efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 1035efb80947Sahrens break; 1036efb80947Sahrens } 1037efb80947Sahrens case DRR_FREEOBJECTS: 1038efb80947Sahrens { 1039efb80947Sahrens struct drr_freeobjects drrfo = 1040efb80947Sahrens drr->drr_u.drr_freeobjects; 1041efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 1042efb80947Sahrens break; 1043efb80947Sahrens } 1044efb80947Sahrens case DRR_WRITE: 1045efb80947Sahrens { 1046efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 1047efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 1048efb80947Sahrens break; 1049efb80947Sahrens } 1050efb80947Sahrens case DRR_FREE: 1051efb80947Sahrens { 1052efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 1053efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 1054efb80947Sahrens break; 1055efb80947Sahrens } 1056efb80947Sahrens case DRR_END: 1057efb80947Sahrens { 1058efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1059efb80947Sahrens /* 1060efb80947Sahrens * We compare against the *previous* checksum 1061efb80947Sahrens * value, because the stored checksum is of 1062efb80947Sahrens * everything before the DRR_END record. 1063efb80947Sahrens */ 1064137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1065efb80947Sahrens ra.err = ECKSUM; 1066efb80947Sahrens goto out; 1067efb80947Sahrens } 1068efb80947Sahrens default: 1069efb80947Sahrens ra.err = EINVAL; 1070efb80947Sahrens goto out; 1071efb80947Sahrens } 10723cb34c60Sahrens pcksum = ra.cksum; 1073efb80947Sahrens } 1074137fa067Sahrens ASSERT(ra.err != 0); 1075efb80947Sahrens 1076efb80947Sahrens out: 10773cb34c60Sahrens dmu_objset_close(os); 1078efb80947Sahrens 10793cb34c60Sahrens if (ra.err != 0) { 1080efb80947Sahrens /* 1081efb80947Sahrens * rollback or destroy what we created, so we don't 1082efb80947Sahrens * leave it in the restoring state. 1083efb80947Sahrens */ 10843cb34c60Sahrens txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0); 108547f263f4Sek dmu_recv_abort_cleanup(drc); 1086efb80947Sahrens } 1087efb80947Sahrens 1088efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 10893cb34c60Sahrens *voffp = ra.voff; 1090efb80947Sahrens return (ra.err); 1091efb80947Sahrens } 1092f18faf3fSek 10933cb34c60Sahrens struct recvendsyncarg { 10943cb34c60Sahrens char *tosnap; 10953cb34c60Sahrens uint64_t creation_time; 10963cb34c60Sahrens uint64_t toguid; 10973cb34c60Sahrens }; 10983cb34c60Sahrens 10993cb34c60Sahrens static int 11003cb34c60Sahrens recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 11013cb34c60Sahrens { 11023cb34c60Sahrens dsl_dataset_t *ds = arg1; 11033cb34c60Sahrens struct recvendsyncarg *resa = arg2; 11043cb34c60Sahrens 11053cb34c60Sahrens return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx)); 11063cb34c60Sahrens } 11073cb34c60Sahrens 11083cb34c60Sahrens static void 11093cb34c60Sahrens recv_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 11103cb34c60Sahrens { 11113cb34c60Sahrens dsl_dataset_t *ds = arg1; 11123cb34c60Sahrens struct recvendsyncarg *resa = arg2; 11133cb34c60Sahrens 11143cb34c60Sahrens dsl_dataset_snapshot_sync(ds, resa->tosnap, cr, tx); 11153cb34c60Sahrens 11163cb34c60Sahrens /* set snapshot's creation time and guid */ 11173cb34c60Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 11183cb34c60Sahrens ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time; 11193cb34c60Sahrens ds->ds_prev->ds_phys->ds_guid = resa->toguid; 11203cb34c60Sahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 11213cb34c60Sahrens 11223cb34c60Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 11233cb34c60Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 11243cb34c60Sahrens } 11253cb34c60Sahrens 1126f18faf3fSek int 11273cb34c60Sahrens dmu_recv_end(dmu_recv_cookie_t *drc) 1128f18faf3fSek { 1129745cd3c5Smaybee struct recvendsyncarg resa; 1130745cd3c5Smaybee dsl_dataset_t *ds = drc->drc_logical_ds; 1131745cd3c5Smaybee int err; 1132f18faf3fSek 11333cb34c60Sahrens /* 11343cb34c60Sahrens * XXX hack; seems the ds is still dirty and 1135745cd3c5Smaybee * dsl_pool_zil_clean() expects it to have a ds_user_ptr 1136745cd3c5Smaybee * (and zil), but clone_swap() can close it. 11373cb34c60Sahrens */ 1138745cd3c5Smaybee txg_wait_synced(ds->ds_dir->dd_pool, 0); 11393cb34c60Sahrens 1140745cd3c5Smaybee if (ds != drc->drc_real_ds) { 1141745cd3c5Smaybee /* we are doing an online recv */ 1142745cd3c5Smaybee if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) { 1143745cd3c5Smaybee err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, 1144745cd3c5Smaybee drc->drc_force); 1145745cd3c5Smaybee if (err) 1146745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 11473cb34c60Sahrens } else { 11483cb34c60Sahrens err = EBUSY; 1149745cd3c5Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 11503cb34c60Sahrens } 1151745cd3c5Smaybee /* dsl_dataset_destroy() will disown the ds */ 1152745cd3c5Smaybee (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 1153745cd3c5Smaybee if (err) 1154745cd3c5Smaybee return (err); 11553cb34c60Sahrens } 11563cb34c60Sahrens 1157745cd3c5Smaybee resa.creation_time = drc->drc_drrb->drr_creation_time; 1158745cd3c5Smaybee resa.toguid = drc->drc_drrb->drr_toguid; 1159745cd3c5Smaybee resa.tosnap = drc->drc_tosnap; 11603cb34c60Sahrens 1161745cd3c5Smaybee err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1162745cd3c5Smaybee recv_end_check, recv_end_sync, ds, &resa, 3); 1163745cd3c5Smaybee if (err) { 1164745cd3c5Smaybee if (drc->drc_newfs) { 1165745cd3c5Smaybee ASSERT(ds == drc->drc_real_ds); 1166745cd3c5Smaybee (void) dsl_dataset_destroy(ds, dmu_recv_tag); 1167745cd3c5Smaybee return (err); 1168745cd3c5Smaybee } else { 1169745cd3c5Smaybee (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 11703cb34c60Sahrens } 11713cb34c60Sahrens } 11723cb34c60Sahrens 1173745cd3c5Smaybee /* release the hold from dmu_recv_begin */ 1174745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 1175f18faf3fSek return (err); 1176f18faf3fSek } 1177