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 /* 2247f263f4Sek * Copyright 2008 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 154*88b7b0f2SMatthew Ahrens backup_cb(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb, 155*88b7b0f2SMatthew 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*88b7b0f2SMatthew Ahrens if (bp == NULL && zb->zb_object == 0) { 165*88b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 166*88b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 167efb80947Sahrens err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT); 168efb80947Sahrens } else if (bp == NULL) { 169*88b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 170*88b7b0f2SMatthew Ahrens err = dump_free(ba, zb->zb_object, zb->zb_blkid * span, span); 171*88b7b0f2SMatthew Ahrens } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 172*88b7b0f2SMatthew Ahrens return (0); 173*88b7b0f2SMatthew Ahrens } else if (type == DMU_OT_DNODE) { 174*88b7b0f2SMatthew Ahrens dnode_phys_t *blk; 175efb80947Sahrens int i; 176efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 177*88b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 178*88b7b0f2SMatthew Ahrens arc_buf_t *abuf; 179efb80947Sahrens 180*88b7b0f2SMatthew Ahrens if (arc_read_nolock(NULL, spa, bp, 181*88b7b0f2SMatthew Ahrens arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ, 182*88b7b0f2SMatthew Ahrens ZIO_FLAG_CANFAIL, &aflags, zb) != 0) 183*88b7b0f2SMatthew Ahrens return (EIO); 184*88b7b0f2SMatthew Ahrens 185*88b7b0f2SMatthew Ahrens blk = abuf->b_data; 186efb80947Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 187*88b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid << 188*88b7b0f2SMatthew Ahrens (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 189efb80947Sahrens err = dump_dnode(ba, dnobj, blk+i); 190efb80947Sahrens if (err) 191efb80947Sahrens break; 192efb80947Sahrens } 193*88b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 194*88b7b0f2SMatthew Ahrens } else { /* it's a level-0 block of a regular object */ 195*88b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 196*88b7b0f2SMatthew Ahrens arc_buf_t *abuf; 197efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 198*88b7b0f2SMatthew Ahrens 199*88b7b0f2SMatthew Ahrens if (arc_read_nolock(NULL, spa, bp, 200*88b7b0f2SMatthew Ahrens arc_getbuf_func, &abuf, ZIO_PRIORITY_ASYNC_READ, 201*88b7b0f2SMatthew Ahrens ZIO_FLAG_CANFAIL, &aflags, zb) != 0) 202*88b7b0f2SMatthew Ahrens return (EIO); 203*88b7b0f2SMatthew Ahrens 204*88b7b0f2SMatthew Ahrens err = dump_data(ba, type, zb->zb_object, zb->zb_blkid * blksz, 205*88b7b0f2SMatthew Ahrens blksz, abuf->b_data); 206*88b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 207efb80947Sahrens } 208efb80947Sahrens 209efb80947Sahrens ASSERT(err == 0 || err == EINTR); 210efb80947Sahrens return (err); 211efb80947Sahrens } 212efb80947Sahrens 213efb80947Sahrens int 2143cb34c60Sahrens dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, 2153cb34c60Sahrens vnode_t *vp, offset_t *off) 216efb80947Sahrens { 217efb80947Sahrens dsl_dataset_t *ds = tosnap->os->os_dsl_dataset; 218efb80947Sahrens dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL; 219efb80947Sahrens dmu_replay_record_t *drr; 220efb80947Sahrens struct backuparg ba; 221efb80947Sahrens int err; 2223cb34c60Sahrens uint64_t fromtxg = 0; 223efb80947Sahrens 224efb80947Sahrens /* tosnap must be a snapshot */ 225efb80947Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 226efb80947Sahrens return (EINVAL); 227efb80947Sahrens 228efb80947Sahrens /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 229efb80947Sahrens if (fromds && (ds->ds_dir != fromds->ds_dir || 2303cb34c60Sahrens fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg)) 231efb80947Sahrens return (EXDEV); 232efb80947Sahrens 2333cb34c60Sahrens if (fromorigin) { 234088f3894Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 235088f3894Sahrens 2363cb34c60Sahrens if (fromsnap) 2373cb34c60Sahrens return (EINVAL); 2383cb34c60Sahrens 239088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2403cb34c60Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 241745cd3c5Smaybee err = dsl_dataset_hold_obj(dp, 242745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds); 2433cb34c60Sahrens rw_exit(&dp->dp_config_rwlock); 2443cb34c60Sahrens if (err) 2453cb34c60Sahrens return (err); 2463cb34c60Sahrens } else { 2473cb34c60Sahrens fromorigin = B_FALSE; 2483cb34c60Sahrens } 2493cb34c60Sahrens } 2503cb34c60Sahrens 2513cb34c60Sahrens 252efb80947Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 253efb80947Sahrens drr->drr_type = DRR_BEGIN; 254efb80947Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 2553cb34c60Sahrens drr->drr_u.drr_begin.drr_version = DMU_BACKUP_STREAM_VERSION; 256efb80947Sahrens drr->drr_u.drr_begin.drr_creation_time = 257efb80947Sahrens ds->ds_phys->ds_creation_time; 258efb80947Sahrens drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type; 2593cb34c60Sahrens if (fromorigin) 2603cb34c60Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 261efb80947Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 262ab04eb8eStimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 263ab04eb8eStimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 264ab04eb8eStimh 265efb80947Sahrens if (fromds) 266efb80947Sahrens drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 267efb80947Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 268efb80947Sahrens 2693cb34c60Sahrens if (fromds) 2703cb34c60Sahrens fromtxg = fromds->ds_phys->ds_creation_txg; 2713cb34c60Sahrens if (fromorigin) 272745cd3c5Smaybee dsl_dataset_rele(fromds, FTAG); 2733cb34c60Sahrens 274efb80947Sahrens ba.drr = drr; 275efb80947Sahrens ba.vp = vp; 276efb80947Sahrens ba.os = tosnap; 2773cb34c60Sahrens ba.off = off; 278efb80947Sahrens ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); 279efb80947Sahrens 280efb80947Sahrens if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 281efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 282efb80947Sahrens return (ba.err); 283efb80947Sahrens } 284efb80947Sahrens 285*88b7b0f2SMatthew Ahrens err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 286efb80947Sahrens backup_cb, &ba); 287efb80947Sahrens 288efb80947Sahrens if (err) { 289efb80947Sahrens if (err == EINTR && ba.err) 290efb80947Sahrens err = ba.err; 2917b5309bbSgw kmem_free(drr, sizeof (dmu_replay_record_t)); 292efb80947Sahrens return (err); 293efb80947Sahrens } 294efb80947Sahrens 295efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 296efb80947Sahrens drr->drr_type = DRR_END; 297efb80947Sahrens drr->drr_u.drr_end.drr_checksum = ba.zc; 298efb80947Sahrens 2997b5309bbSgw if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 3007b5309bbSgw kmem_free(drr, sizeof (dmu_replay_record_t)); 301efb80947Sahrens return (ba.err); 3027b5309bbSgw } 303efb80947Sahrens 304efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 305efb80947Sahrens 306efb80947Sahrens return (0); 307efb80947Sahrens } 308efb80947Sahrens 3093cb34c60Sahrens struct recvbeginsyncarg { 3103cb34c60Sahrens const char *tofs; 3113cb34c60Sahrens const char *tosnap; 3123cb34c60Sahrens dsl_dataset_t *origin; 3133cb34c60Sahrens uint64_t fromguid; 3143cb34c60Sahrens dmu_objset_type_t type; 3153cb34c60Sahrens void *tag; 3163cb34c60Sahrens boolean_t force; 317ab04eb8eStimh uint64_t dsflags; 3183cb34c60Sahrens char clonelastname[MAXNAMELEN]; 3193cb34c60Sahrens dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */ 320efb80947Sahrens }; 321efb80947Sahrens 3223cb34c60Sahrens static dsl_dataset_t * 3233cb34c60Sahrens recv_full_sync_impl(dsl_pool_t *dp, uint64_t dsobj, dmu_objset_type_t type, 3243cb34c60Sahrens cred_t *cr, dmu_tx_t *tx) 325f18faf3fSek { 3263cb34c60Sahrens dsl_dataset_t *ds; 327f18faf3fSek 328745cd3c5Smaybee /* This should always work, since we just created it */ 329745cd3c5Smaybee /* XXX - create should return an owned ds */ 330745cd3c5Smaybee VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 331745cd3c5Smaybee DS_MODE_INCONSISTENT, dmu_recv_tag, &ds)); 332f18faf3fSek 3333cb34c60Sahrens if (type != DMU_OST_NONE) { 3343cb34c60Sahrens (void) dmu_objset_create_impl(dp->dp_spa, 3353cb34c60Sahrens ds, &ds->ds_phys->ds_bp, type, tx); 3363cb34c60Sahrens } 337f18faf3fSek 3383cb34c60Sahrens spa_history_internal_log(LOG_DS_REPLAY_FULL_SYNC, 339745cd3c5Smaybee dp->dp_spa, tx, cr, "dataset = %lld", dsobj); 3403cb34c60Sahrens 3413cb34c60Sahrens return (ds); 342efb80947Sahrens } 343efb80947Sahrens 344efb80947Sahrens /* ARGSUSED */ 345efb80947Sahrens static int 3463cb34c60Sahrens recv_full_check(void *arg1, void *arg2, dmu_tx_t *tx) 347efb80947Sahrens { 348efb80947Sahrens dsl_dir_t *dd = arg1; 3493cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 350efb80947Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 351efb80947Sahrens uint64_t val; 352efb80947Sahrens int err; 353efb80947Sahrens 354efb80947Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 3553cb34c60Sahrens strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val); 356efb80947Sahrens 357efb80947Sahrens if (err != ENOENT) 358efb80947Sahrens return (err ? err : EEXIST); 359efb80947Sahrens 3603cb34c60Sahrens if (rbsa->origin) { 3613cb34c60Sahrens /* make sure it's a snap in the same pool */ 3623cb34c60Sahrens if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool) 3633cb34c60Sahrens return (EXDEV); 3643cb34c60Sahrens if (rbsa->origin->ds_phys->ds_num_children == 0) 3653cb34c60Sahrens return (EINVAL); 3663cb34c60Sahrens if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 3673cb34c60Sahrens return (ENODEV); 3683cb34c60Sahrens } 3693cb34c60Sahrens 370efb80947Sahrens return (0); 371efb80947Sahrens } 372efb80947Sahrens 373efb80947Sahrens static void 3743cb34c60Sahrens recv_full_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 375efb80947Sahrens { 376efb80947Sahrens dsl_dir_t *dd = arg1; 3773cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 378745cd3c5Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 379efb80947Sahrens uint64_t dsobj; 380efb80947Sahrens 3813cb34c60Sahrens dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1, 382ab04eb8eStimh rbsa->origin, flags, cr, tx); 383efb80947Sahrens 3843cb34c60Sahrens rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj, 3853cb34c60Sahrens rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx); 3863cb34c60Sahrens } 387efb80947Sahrens 3883cb34c60Sahrens static int 3893cb34c60Sahrens recv_full_existing_check(void *arg1, void *arg2, dmu_tx_t *tx) 3903cb34c60Sahrens { 3913cb34c60Sahrens dsl_dataset_t *ds = arg1; 3923cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 3933cb34c60Sahrens int err; 394efb80947Sahrens 3953cb34c60Sahrens /* must be a head ds */ 3963cb34c60Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 3973cb34c60Sahrens return (EINVAL); 398efb80947Sahrens 3993cb34c60Sahrens /* must not be a clone ds */ 400088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) 4013cb34c60Sahrens return (EINVAL); 4023cb34c60Sahrens 4033cb34c60Sahrens err = dsl_dataset_destroy_check(ds, rbsa->tag, tx); 4043cb34c60Sahrens if (err) 4053cb34c60Sahrens return (err); 406ecd6cf80Smarks 4073cb34c60Sahrens if (rbsa->origin) { 4083cb34c60Sahrens /* make sure it's a snap in the same pool */ 4093cb34c60Sahrens if (rbsa->origin->ds_dir->dd_pool != ds->ds_dir->dd_pool) 4103cb34c60Sahrens return (EXDEV); 4113cb34c60Sahrens if (rbsa->origin->ds_phys->ds_num_children == 0) 4123cb34c60Sahrens return (EINVAL); 4133cb34c60Sahrens if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 4143cb34c60Sahrens return (ENODEV); 4153cb34c60Sahrens } 416ecd6cf80Smarks 4173cb34c60Sahrens return (0); 418efb80947Sahrens } 419efb80947Sahrens 4203cb34c60Sahrens static void 4213cb34c60Sahrens recv_full_existing_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 4223cb34c60Sahrens { 4233cb34c60Sahrens dsl_dataset_t *ds = arg1; 4243cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 4253cb34c60Sahrens dsl_dir_t *dd = ds->ds_dir; 426745cd3c5Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 4273cb34c60Sahrens uint64_t dsobj; 4283cb34c60Sahrens 4293cb34c60Sahrens /* 4303cb34c60Sahrens * NB: caller must provide an extra hold on the dsl_dir_t, so it 4313cb34c60Sahrens * won't go away when dsl_dataset_destroy_sync() closes the 4323cb34c60Sahrens * dataset. 4333cb34c60Sahrens */ 4343cb34c60Sahrens dsl_dataset_destroy_sync(ds, rbsa->tag, cr, tx); 4353cb34c60Sahrens 436088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, rbsa->origin, flags, tx); 4373cb34c60Sahrens 4383cb34c60Sahrens rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj, 4393cb34c60Sahrens rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx); 4403cb34c60Sahrens } 441f18faf3fSek 442f18faf3fSek /* ARGSUSED */ 443f18faf3fSek static int 4443cb34c60Sahrens recv_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 445f18faf3fSek { 4463cb34c60Sahrens dsl_dataset_t *ds = arg1; 4473cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 4483cb34c60Sahrens int err; 4493cb34c60Sahrens uint64_t val; 450f18faf3fSek 4513cb34c60Sahrens /* must not have any changes since most recent snapshot */ 4523cb34c60Sahrens if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds)) 453f18faf3fSek return (ETXTBSY); 454f18faf3fSek 4553cb34c60Sahrens /* must already be a snapshot of this fs */ 4563cb34c60Sahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 4573cb34c60Sahrens return (ENODEV); 4583cb34c60Sahrens 4593cb34c60Sahrens /* most recent snapshot must match fromguid */ 4603cb34c60Sahrens if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid) 4613cb34c60Sahrens return (ENODEV); 4623cb34c60Sahrens 46347f263f4Sek /* temporary clone name must not exist */ 46447f263f4Sek err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 46547f263f4Sek ds->ds_dir->dd_phys->dd_child_dir_zapobj, 46647f263f4Sek rbsa->clonelastname, 8, 1, &val); 46747f263f4Sek if (err == 0) 46847f263f4Sek return (EEXIST); 46947f263f4Sek if (err != ENOENT) 47047f263f4Sek return (err); 47147f263f4Sek 4723cb34c60Sahrens /* new snapshot name must not exist */ 4733cb34c60Sahrens err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 4743cb34c60Sahrens ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val); 4753cb34c60Sahrens if (err == 0) 4763cb34c60Sahrens return (EEXIST); 4773cb34c60Sahrens if (err != ENOENT) 4783cb34c60Sahrens return (err); 4793cb34c60Sahrens return (0); 480f18faf3fSek } 481f18faf3fSek 482f18faf3fSek /* ARGSUSED */ 483f18faf3fSek static void 4843cb34c60Sahrens recv_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 485f18faf3fSek { 4863cb34c60Sahrens dsl_dataset_t *ohds = arg1; 4873cb34c60Sahrens struct recvbeginsyncarg *rbsa = arg2; 4883cb34c60Sahrens dsl_pool_t *dp = ohds->ds_dir->dd_pool; 4893cb34c60Sahrens dsl_dataset_t *ods, *cds; 490745cd3c5Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 491f18faf3fSek uint64_t dsobj; 492f18faf3fSek 4933cb34c60Sahrens /* create the temporary clone */ 494745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, ohds->ds_phys->ds_prev_snap_obj, 495745cd3c5Smaybee FTAG, &ods)); 4963cb34c60Sahrens dsobj = dsl_dataset_create_sync(ohds->ds_dir, 497ab04eb8eStimh rbsa->clonelastname, ods, flags, cr, tx); 498745cd3c5Smaybee dsl_dataset_rele(ods, FTAG); 499f18faf3fSek 500f18faf3fSek /* open the temporary clone */ 501745cd3c5Smaybee VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 502745cd3c5Smaybee DS_MODE_INCONSISTENT, dmu_recv_tag, &cds)); 5033cb34c60Sahrens 504a9799022Sck /* copy the refquota from the target fs to the clone */ 505a9799022Sck if (ohds->ds_quota > 0) 506a9799022Sck dsl_dataset_set_quota_sync(cds, &ohds->ds_quota, cr, tx); 507a9799022Sck 5083cb34c60Sahrens rbsa->ds = cds; 5093cb34c60Sahrens 5103cb34c60Sahrens spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 511745cd3c5Smaybee dp->dp_spa, tx, cr, "dataset = %lld", dsobj); 5123cb34c60Sahrens } 5133cb34c60Sahrens 5143cb34c60Sahrens /* ARGSUSED */ 5153cb34c60Sahrens static void 5163cb34c60Sahrens recv_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 5173cb34c60Sahrens { 5183cb34c60Sahrens dsl_dataset_t *ds = arg1; 519a9799022Sck 520f18faf3fSek dmu_buf_will_dirty(ds->ds_dbuf, tx); 521f18faf3fSek ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 522f18faf3fSek 523f18faf3fSek spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 524f18faf3fSek ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld", 525745cd3c5Smaybee ds->ds_object); 526f18faf3fSek } 527f18faf3fSek 5283cb34c60Sahrens /* 5293cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 5303cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 5313cb34c60Sahrens */ 5323cb34c60Sahrens int 5333cb34c60Sahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 5343cb34c60Sahrens boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *drc) 535efb80947Sahrens { 5363cb34c60Sahrens int err = 0; 5373cb34c60Sahrens boolean_t byteswap; 5383cb34c60Sahrens struct recvbeginsyncarg rbsa; 5393cb34c60Sahrens uint64_t version; 5403cb34c60Sahrens int flags; 5413cb34c60Sahrens dsl_dataset_t *ds; 542efb80947Sahrens 5433cb34c60Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) 5443cb34c60Sahrens byteswap = FALSE; 5453cb34c60Sahrens else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 5463cb34c60Sahrens byteswap = TRUE; 5473cb34c60Sahrens else 5483cb34c60Sahrens return (EINVAL); 5493cb34c60Sahrens 5503cb34c60Sahrens rbsa.tofs = tofs; 5513cb34c60Sahrens rbsa.tosnap = tosnap; 5523cb34c60Sahrens rbsa.origin = origin ? origin->os->os_dsl_dataset : NULL; 5533cb34c60Sahrens rbsa.fromguid = drrb->drr_fromguid; 5543cb34c60Sahrens rbsa.type = drrb->drr_type; 5553cb34c60Sahrens rbsa.tag = FTAG; 556ab04eb8eStimh rbsa.dsflags = 0; 5573cb34c60Sahrens version = drrb->drr_version; 5583cb34c60Sahrens flags = drrb->drr_flags; 5593cb34c60Sahrens 5603cb34c60Sahrens if (byteswap) { 5613cb34c60Sahrens rbsa.type = BSWAP_32(rbsa.type); 5623cb34c60Sahrens rbsa.fromguid = BSWAP_64(rbsa.fromguid); 5633cb34c60Sahrens version = BSWAP_64(version); 5643cb34c60Sahrens flags = BSWAP_32(flags); 5653cb34c60Sahrens } 566efb80947Sahrens 5673cb34c60Sahrens if (version != DMU_BACKUP_STREAM_VERSION || 5683cb34c60Sahrens rbsa.type >= DMU_OST_NUMTYPES || 5693cb34c60Sahrens ((flags & DRR_FLAG_CLONE) && origin == NULL)) 570efb80947Sahrens return (EINVAL); 571efb80947Sahrens 572ab04eb8eStimh if (flags & DRR_FLAG_CI_DATA) 573ab04eb8eStimh rbsa.dsflags = DS_FLAG_CI_DATASET; 574ab04eb8eStimh 5753cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 5763cb34c60Sahrens drc->drc_drrb = drrb; 5773cb34c60Sahrens drc->drc_tosnap = tosnap; 5783cb34c60Sahrens drc->drc_force = force; 579efb80947Sahrens 5803cb34c60Sahrens /* 5813cb34c60Sahrens * Process the begin in syncing context. 5823cb34c60Sahrens */ 5833cb34c60Sahrens if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE) && !online) { 5843cb34c60Sahrens /* offline incremental receive */ 585745cd3c5Smaybee err = dsl_dataset_own(tofs, 0, dmu_recv_tag, &ds); 5863cb34c60Sahrens if (err) 5873cb34c60Sahrens return (err); 588efb80947Sahrens 5893cb34c60Sahrens /* 5903cb34c60Sahrens * Only do the rollback if the most recent snapshot 5913cb34c60Sahrens * matches the incremental source 5923cb34c60Sahrens */ 5933cb34c60Sahrens if (force) { 5943cb34c60Sahrens if (ds->ds_prev == NULL || 5953cb34c60Sahrens ds->ds_prev->ds_phys->ds_guid != 5963cb34c60Sahrens rbsa.fromguid) { 597745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 5983cb34c60Sahrens return (ENODEV); 5993cb34c60Sahrens } 6003cb34c60Sahrens (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 6013cb34c60Sahrens } 6023cb34c60Sahrens rbsa.force = B_FALSE; 6033cb34c60Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 6043cb34c60Sahrens recv_incremental_check, 605745cd3c5Smaybee recv_offline_incremental_sync, ds, &rbsa, 1); 6063cb34c60Sahrens if (err) { 607745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 6083cb34c60Sahrens return (err); 6093cb34c60Sahrens } 6103cb34c60Sahrens drc->drc_logical_ds = drc->drc_real_ds = ds; 6113cb34c60Sahrens } else if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) { 6123cb34c60Sahrens /* online incremental receive */ 613efb80947Sahrens 6143cb34c60Sahrens /* tmp clone name is: tofs/%tosnap" */ 6153cb34c60Sahrens (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname), 6163cb34c60Sahrens "%%%s", tosnap); 617efb80947Sahrens 6183cb34c60Sahrens /* open the dataset we are logically receiving into */ 619745cd3c5Smaybee err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds); 6203cb34c60Sahrens if (err) 6213cb34c60Sahrens return (err); 622efb80947Sahrens 6233cb34c60Sahrens rbsa.force = force; 6243cb34c60Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 6253cb34c60Sahrens recv_incremental_check, 6263cb34c60Sahrens recv_online_incremental_sync, ds, &rbsa, 5); 6273cb34c60Sahrens if (err) { 628745cd3c5Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 6293cb34c60Sahrens return (err); 6303cb34c60Sahrens } 6313cb34c60Sahrens drc->drc_logical_ds = ds; 6323cb34c60Sahrens drc->drc_real_ds = rbsa.ds; 6333cb34c60Sahrens } else { 6343cb34c60Sahrens /* create new fs -- full backup or clone */ 6353cb34c60Sahrens dsl_dir_t *dd = NULL; 6363cb34c60Sahrens const char *tail; 637efb80947Sahrens 6383cb34c60Sahrens err = dsl_dir_open(tofs, FTAG, &dd, &tail); 6393cb34c60Sahrens if (err) 6403cb34c60Sahrens return (err); 6413cb34c60Sahrens if (tail == NULL) { 6423cb34c60Sahrens if (!force) { 6433cb34c60Sahrens dsl_dir_close(dd, FTAG); 6443cb34c60Sahrens return (EEXIST); 6453cb34c60Sahrens } 646ecd6cf80Smarks 6473cb34c60Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 648745cd3c5Smaybee err = dsl_dataset_own_obj(dd->dd_pool, 649745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, 650745cd3c5Smaybee DS_MODE_INCONSISTENT, FTAG, &ds); 6513cb34c60Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 6523cb34c60Sahrens if (err) { 6533cb34c60Sahrens dsl_dir_close(dd, FTAG); 6543cb34c60Sahrens return (err); 6553cb34c60Sahrens } 656efb80947Sahrens 657745cd3c5Smaybee dsl_dataset_make_exclusive(ds, FTAG); 6583cb34c60Sahrens err = dsl_sync_task_do(dd->dd_pool, 6593cb34c60Sahrens recv_full_existing_check, 6603cb34c60Sahrens recv_full_existing_sync, ds, &rbsa, 5); 661745cd3c5Smaybee dsl_dataset_disown(ds, FTAG); 6623cb34c60Sahrens } else { 6633cb34c60Sahrens err = dsl_sync_task_do(dd->dd_pool, recv_full_check, 6643cb34c60Sahrens recv_full_sync, dd, &rbsa, 5); 6653cb34c60Sahrens } 6663cb34c60Sahrens dsl_dir_close(dd, FTAG); 6673cb34c60Sahrens if (err) 6683cb34c60Sahrens return (err); 6693cb34c60Sahrens drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds; 6703cb34c60Sahrens drc->drc_newfs = B_TRUE; 6713cb34c60Sahrens } 6723cb34c60Sahrens 6733cb34c60Sahrens return (0); 674efb80947Sahrens } 675efb80947Sahrens 6763cb34c60Sahrens struct restorearg { 6773cb34c60Sahrens int err; 6783cb34c60Sahrens int byteswap; 6793cb34c60Sahrens vnode_t *vp; 6803cb34c60Sahrens char *buf; 6813cb34c60Sahrens uint64_t voff; 6823cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 6833cb34c60Sahrens zio_cksum_t cksum; 6843cb34c60Sahrens }; 6853cb34c60Sahrens 686efb80947Sahrens static void * 687efb80947Sahrens restore_read(struct restorearg *ra, int len) 688efb80947Sahrens { 689efb80947Sahrens void *rv; 6903cb34c60Sahrens int done = 0; 691efb80947Sahrens 692efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 693efb80947Sahrens ASSERT3U(len % 8, ==, 0); 694efb80947Sahrens 6953cb34c60Sahrens while (done < len) { 696efb80947Sahrens ssize_t resid; 697efb80947Sahrens 698efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 6993cb34c60Sahrens (caddr_t)ra->buf + done, len - done, 700efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 701efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 702efb80947Sahrens 7033cb34c60Sahrens if (resid == len - done) 704efb80947Sahrens ra->err = EINVAL; 7053cb34c60Sahrens ra->voff += len - done - resid; 7063cb34c60Sahrens done = len - resid; 707efb80947Sahrens if (ra->err) 708efb80947Sahrens return (NULL); 709efb80947Sahrens } 710efb80947Sahrens 7113cb34c60Sahrens ASSERT3U(done, ==, len); 7123cb34c60Sahrens rv = ra->buf; 713efb80947Sahrens if (ra->byteswap) 7143cb34c60Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 715efb80947Sahrens else 7163cb34c60Sahrens fletcher_4_incremental_native(rv, len, &ra->cksum); 717efb80947Sahrens return (rv); 718efb80947Sahrens } 719efb80947Sahrens 720efb80947Sahrens static void 721efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 722efb80947Sahrens { 723efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 724efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 725efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 7263cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 727efb80947Sahrens switch (drr->drr_type) { 728efb80947Sahrens case DRR_BEGIN: 729efb80947Sahrens DO64(drr_begin.drr_magic); 730efb80947Sahrens DO64(drr_begin.drr_version); 731efb80947Sahrens DO64(drr_begin.drr_creation_time); 732efb80947Sahrens DO32(drr_begin.drr_type); 7333cb34c60Sahrens DO32(drr_begin.drr_flags); 734efb80947Sahrens DO64(drr_begin.drr_toguid); 735efb80947Sahrens DO64(drr_begin.drr_fromguid); 736efb80947Sahrens break; 737efb80947Sahrens case DRR_OBJECT: 738efb80947Sahrens DO64(drr_object.drr_object); 739efb80947Sahrens /* DO64(drr_object.drr_allocation_txg); */ 740efb80947Sahrens DO32(drr_object.drr_type); 741efb80947Sahrens DO32(drr_object.drr_bonustype); 742efb80947Sahrens DO32(drr_object.drr_blksz); 743efb80947Sahrens DO32(drr_object.drr_bonuslen); 744efb80947Sahrens break; 745efb80947Sahrens case DRR_FREEOBJECTS: 746efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 747efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 748efb80947Sahrens break; 749efb80947Sahrens case DRR_WRITE: 750efb80947Sahrens DO64(drr_write.drr_object); 751efb80947Sahrens DO32(drr_write.drr_type); 752efb80947Sahrens DO64(drr_write.drr_offset); 753efb80947Sahrens DO64(drr_write.drr_length); 754efb80947Sahrens break; 755efb80947Sahrens case DRR_FREE: 756efb80947Sahrens DO64(drr_free.drr_object); 757efb80947Sahrens DO64(drr_free.drr_offset); 758efb80947Sahrens DO64(drr_free.drr_length); 759efb80947Sahrens break; 760efb80947Sahrens case DRR_END: 761efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 762efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 763efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 764efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 765efb80947Sahrens break; 766efb80947Sahrens } 767efb80947Sahrens #undef DO64 768efb80947Sahrens #undef DO32 769efb80947Sahrens } 770efb80947Sahrens 771efb80947Sahrens static int 772efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 773efb80947Sahrens { 774efb80947Sahrens int err; 775efb80947Sahrens dmu_tx_t *tx; 776efb80947Sahrens 777efb80947Sahrens err = dmu_object_info(os, drro->drr_object, NULL); 778efb80947Sahrens 779efb80947Sahrens if (err != 0 && err != ENOENT) 780efb80947Sahrens return (EINVAL); 781efb80947Sahrens 782efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 783efb80947Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 784efb80947Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 785efb80947Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 786efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 787efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 788efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 789efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 790efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 791efb80947Sahrens return (EINVAL); 792efb80947Sahrens } 793efb80947Sahrens 794efb80947Sahrens tx = dmu_tx_create(os); 795efb80947Sahrens 796efb80947Sahrens if (err == ENOENT) { 797efb80947Sahrens /* currently free, want to be allocated */ 798efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 799efb80947Sahrens dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 1); 800efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 801efb80947Sahrens if (err) { 802efb80947Sahrens dmu_tx_abort(tx); 803efb80947Sahrens return (err); 804efb80947Sahrens } 805efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 806efb80947Sahrens drro->drr_type, drro->drr_blksz, 807efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 808efb80947Sahrens } else { 809efb80947Sahrens /* currently allocated, want to be allocated */ 810efb80947Sahrens dmu_tx_hold_bonus(tx, drro->drr_object); 811efb80947Sahrens /* 812efb80947Sahrens * We may change blocksize, so need to 813efb80947Sahrens * hold_write 814efb80947Sahrens */ 815efb80947Sahrens dmu_tx_hold_write(tx, drro->drr_object, 0, 1); 816efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 817efb80947Sahrens if (err) { 818efb80947Sahrens dmu_tx_abort(tx); 819efb80947Sahrens return (err); 820efb80947Sahrens } 821efb80947Sahrens 822efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 823efb80947Sahrens drro->drr_type, drro->drr_blksz, 824efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 825efb80947Sahrens } 826efb80947Sahrens if (err) { 827efb80947Sahrens dmu_tx_commit(tx); 828efb80947Sahrens return (EINVAL); 829efb80947Sahrens } 830efb80947Sahrens 831efb80947Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 832efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 833efb80947Sahrens 834efb80947Sahrens if (drro->drr_bonuslen) { 835efb80947Sahrens dmu_buf_t *db; 836efb80947Sahrens void *data; 837efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 838efb80947Sahrens dmu_buf_will_dirty(db, tx); 839efb80947Sahrens 8401934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 8411934e92fSmaybee data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 842efb80947Sahrens if (data == NULL) { 843efb80947Sahrens dmu_tx_commit(tx); 844efb80947Sahrens return (ra->err); 845efb80947Sahrens } 8461934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 847efb80947Sahrens if (ra->byteswap) { 848efb80947Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 849efb80947Sahrens drro->drr_bonuslen); 850efb80947Sahrens } 851efb80947Sahrens dmu_buf_rele(db, FTAG); 852efb80947Sahrens } 853efb80947Sahrens dmu_tx_commit(tx); 854efb80947Sahrens return (0); 855efb80947Sahrens } 856efb80947Sahrens 857efb80947Sahrens /* ARGSUSED */ 858efb80947Sahrens static int 859efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 860efb80947Sahrens struct drr_freeobjects *drrfo) 861efb80947Sahrens { 862efb80947Sahrens uint64_t obj; 863efb80947Sahrens 864efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 865efb80947Sahrens return (EINVAL); 866efb80947Sahrens 867efb80947Sahrens for (obj = drrfo->drr_firstobj; 868432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 869432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 870efb80947Sahrens int err; 871efb80947Sahrens 872efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 873efb80947Sahrens continue; 874efb80947Sahrens 875cdb0ab79Smaybee err = dmu_free_object(os, obj); 876cdb0ab79Smaybee if (err) 877efb80947Sahrens return (err); 878efb80947Sahrens } 879efb80947Sahrens return (0); 880efb80947Sahrens } 881efb80947Sahrens 882efb80947Sahrens static int 883efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 884efb80947Sahrens struct drr_write *drrw) 885efb80947Sahrens { 886efb80947Sahrens dmu_tx_t *tx; 887efb80947Sahrens void *data; 888efb80947Sahrens int err; 889efb80947Sahrens 890efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 891efb80947Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 892efb80947Sahrens return (EINVAL); 893efb80947Sahrens 894efb80947Sahrens data = restore_read(ra, drrw->drr_length); 895efb80947Sahrens if (data == NULL) 896efb80947Sahrens return (ra->err); 897efb80947Sahrens 898efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 899efb80947Sahrens return (EINVAL); 900efb80947Sahrens 901efb80947Sahrens tx = dmu_tx_create(os); 902efb80947Sahrens 903efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 904efb80947Sahrens drrw->drr_offset, drrw->drr_length); 905efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 906efb80947Sahrens if (err) { 907efb80947Sahrens dmu_tx_abort(tx); 908efb80947Sahrens return (err); 909efb80947Sahrens } 910efb80947Sahrens if (ra->byteswap) 911efb80947Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 912efb80947Sahrens dmu_write(os, drrw->drr_object, 913efb80947Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 914efb80947Sahrens dmu_tx_commit(tx); 915efb80947Sahrens return (0); 916efb80947Sahrens } 917efb80947Sahrens 918efb80947Sahrens /* ARGSUSED */ 919efb80947Sahrens static int 920efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 921efb80947Sahrens struct drr_free *drrf) 922efb80947Sahrens { 923efb80947Sahrens int err; 924efb80947Sahrens 925efb80947Sahrens if (drrf->drr_length != -1ULL && 926efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 927efb80947Sahrens return (EINVAL); 928efb80947Sahrens 929efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 930efb80947Sahrens return (EINVAL); 931efb80947Sahrens 932cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 933efb80947Sahrens drrf->drr_offset, drrf->drr_length); 934efb80947Sahrens return (err); 935efb80947Sahrens } 936efb80947Sahrens 93747f263f4Sek void 93847f263f4Sek dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc) 9393cb34c60Sahrens { 9403cb34c60Sahrens if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) { 9413cb34c60Sahrens /* 9423cb34c60Sahrens * online incremental or new fs: destroy the fs (which 9433cb34c60Sahrens * may be a clone) that we created 9443cb34c60Sahrens */ 9453cb34c60Sahrens (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 946745cd3c5Smaybee if (drc->drc_real_ds != drc->drc_logical_ds) 947745cd3c5Smaybee dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag); 9483cb34c60Sahrens } else { 9493cb34c60Sahrens /* 9503cb34c60Sahrens * offline incremental: rollback to most recent snapshot. 9513cb34c60Sahrens */ 952745cd3c5Smaybee (void) dsl_dataset_rollback(drc->drc_real_ds, DMU_OST_NONE); 953745cd3c5Smaybee dsl_dataset_disown(drc->drc_real_ds, dmu_recv_tag); 9543cb34c60Sahrens } 9553cb34c60Sahrens } 9563cb34c60Sahrens 9573cb34c60Sahrens /* 9583cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 9593cb34c60Sahrens */ 960efb80947Sahrens int 9613cb34c60Sahrens dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp) 962efb80947Sahrens { 9633cb34c60Sahrens struct restorearg ra = { 0 }; 964efb80947Sahrens dmu_replay_record_t *drr; 9653cb34c60Sahrens objset_t *os; 9663cb34c60Sahrens zio_cksum_t pcksum; 967efb80947Sahrens 9683cb34c60Sahrens if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 969efb80947Sahrens ra.byteswap = TRUE; 970efb80947Sahrens 9713cb34c60Sahrens { 9723cb34c60Sahrens /* compute checksum of drr_begin record */ 9733cb34c60Sahrens dmu_replay_record_t *drr; 9743cb34c60Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 9753cb34c60Sahrens 9763cb34c60Sahrens drr->drr_type = DRR_BEGIN; 9773cb34c60Sahrens drr->drr_u.drr_begin = *drc->drc_drrb; 9783cb34c60Sahrens if (ra.byteswap) { 9793cb34c60Sahrens fletcher_4_incremental_byteswap(drr, 9803cb34c60Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9813cb34c60Sahrens } else { 9823cb34c60Sahrens fletcher_4_incremental_native(drr, 9833cb34c60Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9843cb34c60Sahrens } 9853cb34c60Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 986efb80947Sahrens } 987efb80947Sahrens 988efb80947Sahrens if (ra.byteswap) { 9893cb34c60Sahrens struct drr_begin *drrb = drc->drc_drrb; 990efb80947Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 991efb80947Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 992efb80947Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 993efb80947Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 994efb80947Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 995efb80947Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 996efb80947Sahrens } 997efb80947Sahrens 9983cb34c60Sahrens ra.vp = vp; 9993cb34c60Sahrens ra.voff = *voffp; 10003cb34c60Sahrens ra.bufsize = 1<<20; 10013cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1002efb80947Sahrens 10033cb34c60Sahrens /* these were verified in dmu_recv_begin */ 10043cb34c60Sahrens ASSERT(drc->drc_drrb->drr_version == DMU_BACKUP_STREAM_VERSION); 10053cb34c60Sahrens ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES); 1006efb80947Sahrens 1007efb80947Sahrens /* 1008efb80947Sahrens * Open the objset we are modifying. 1009efb80947Sahrens */ 10103cb34c60Sahrens VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0); 1011efb80947Sahrens 10123cb34c60Sahrens ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1013efb80947Sahrens 1014efb80947Sahrens /* 1015efb80947Sahrens * Read records and process them. 1016efb80947Sahrens */ 10173cb34c60Sahrens pcksum = ra.cksum; 1018efb80947Sahrens while (ra.err == 0 && 1019efb80947Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 1020efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 1021efb80947Sahrens ra.err = EINTR; 1022efb80947Sahrens goto out; 1023efb80947Sahrens } 1024efb80947Sahrens 1025efb80947Sahrens if (ra.byteswap) 1026efb80947Sahrens backup_byteswap(drr); 1027efb80947Sahrens 1028efb80947Sahrens switch (drr->drr_type) { 1029efb80947Sahrens case DRR_OBJECT: 1030efb80947Sahrens { 1031efb80947Sahrens /* 1032efb80947Sahrens * We need to make a copy of the record header, 1033efb80947Sahrens * because restore_{object,write} may need to 1034efb80947Sahrens * restore_read(), which will invalidate drr. 1035efb80947Sahrens */ 1036efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 1037efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 1038efb80947Sahrens break; 1039efb80947Sahrens } 1040efb80947Sahrens case DRR_FREEOBJECTS: 1041efb80947Sahrens { 1042efb80947Sahrens struct drr_freeobjects drrfo = 1043efb80947Sahrens drr->drr_u.drr_freeobjects; 1044efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 1045efb80947Sahrens break; 1046efb80947Sahrens } 1047efb80947Sahrens case DRR_WRITE: 1048efb80947Sahrens { 1049efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 1050efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 1051efb80947Sahrens break; 1052efb80947Sahrens } 1053efb80947Sahrens case DRR_FREE: 1054efb80947Sahrens { 1055efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 1056efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 1057efb80947Sahrens break; 1058efb80947Sahrens } 1059efb80947Sahrens case DRR_END: 1060efb80947Sahrens { 1061efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1062efb80947Sahrens /* 1063efb80947Sahrens * We compare against the *previous* checksum 1064efb80947Sahrens * value, because the stored checksum is of 1065efb80947Sahrens * everything before the DRR_END record. 1066efb80947Sahrens */ 1067137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1068efb80947Sahrens ra.err = ECKSUM; 1069efb80947Sahrens goto out; 1070efb80947Sahrens } 1071efb80947Sahrens default: 1072efb80947Sahrens ra.err = EINVAL; 1073efb80947Sahrens goto out; 1074efb80947Sahrens } 10753cb34c60Sahrens pcksum = ra.cksum; 1076efb80947Sahrens } 1077137fa067Sahrens ASSERT(ra.err != 0); 1078efb80947Sahrens 1079efb80947Sahrens out: 10803cb34c60Sahrens dmu_objset_close(os); 1081efb80947Sahrens 10823cb34c60Sahrens if (ra.err != 0) { 1083efb80947Sahrens /* 1084efb80947Sahrens * rollback or destroy what we created, so we don't 1085efb80947Sahrens * leave it in the restoring state. 1086efb80947Sahrens */ 10873cb34c60Sahrens txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0); 108847f263f4Sek dmu_recv_abort_cleanup(drc); 1089efb80947Sahrens } 1090efb80947Sahrens 1091efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 10923cb34c60Sahrens *voffp = ra.voff; 1093efb80947Sahrens return (ra.err); 1094efb80947Sahrens } 1095f18faf3fSek 10963cb34c60Sahrens struct recvendsyncarg { 10973cb34c60Sahrens char *tosnap; 10983cb34c60Sahrens uint64_t creation_time; 10993cb34c60Sahrens uint64_t toguid; 11003cb34c60Sahrens }; 11013cb34c60Sahrens 11023cb34c60Sahrens static int 11033cb34c60Sahrens recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 11043cb34c60Sahrens { 11053cb34c60Sahrens dsl_dataset_t *ds = arg1; 11063cb34c60Sahrens struct recvendsyncarg *resa = arg2; 11073cb34c60Sahrens 11083cb34c60Sahrens return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx)); 11093cb34c60Sahrens } 11103cb34c60Sahrens 11113cb34c60Sahrens static void 11123cb34c60Sahrens recv_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 11133cb34c60Sahrens { 11143cb34c60Sahrens dsl_dataset_t *ds = arg1; 11153cb34c60Sahrens struct recvendsyncarg *resa = arg2; 11163cb34c60Sahrens 11173cb34c60Sahrens dsl_dataset_snapshot_sync(ds, resa->tosnap, cr, tx); 11183cb34c60Sahrens 11193cb34c60Sahrens /* set snapshot's creation time and guid */ 11203cb34c60Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 11213cb34c60Sahrens ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time; 11223cb34c60Sahrens ds->ds_prev->ds_phys->ds_guid = resa->toguid; 11233cb34c60Sahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 11243cb34c60Sahrens 11253cb34c60Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 11263cb34c60Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 11273cb34c60Sahrens } 11283cb34c60Sahrens 1129f18faf3fSek int 11303cb34c60Sahrens dmu_recv_end(dmu_recv_cookie_t *drc) 1131f18faf3fSek { 1132745cd3c5Smaybee struct recvendsyncarg resa; 1133745cd3c5Smaybee dsl_dataset_t *ds = drc->drc_logical_ds; 1134745cd3c5Smaybee int err; 1135f18faf3fSek 11363cb34c60Sahrens /* 11373cb34c60Sahrens * XXX hack; seems the ds is still dirty and 1138745cd3c5Smaybee * dsl_pool_zil_clean() expects it to have a ds_user_ptr 1139745cd3c5Smaybee * (and zil), but clone_swap() can close it. 11403cb34c60Sahrens */ 1141745cd3c5Smaybee txg_wait_synced(ds->ds_dir->dd_pool, 0); 11423cb34c60Sahrens 1143745cd3c5Smaybee if (ds != drc->drc_real_ds) { 1144745cd3c5Smaybee /* we are doing an online recv */ 1145745cd3c5Smaybee if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) { 1146745cd3c5Smaybee err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, 1147745cd3c5Smaybee drc->drc_force); 1148745cd3c5Smaybee if (err) 1149745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 11503cb34c60Sahrens } else { 11513cb34c60Sahrens err = EBUSY; 1152745cd3c5Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 11533cb34c60Sahrens } 1154745cd3c5Smaybee /* dsl_dataset_destroy() will disown the ds */ 1155745cd3c5Smaybee (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 1156745cd3c5Smaybee if (err) 1157745cd3c5Smaybee return (err); 11583cb34c60Sahrens } 11593cb34c60Sahrens 1160745cd3c5Smaybee resa.creation_time = drc->drc_drrb->drr_creation_time; 1161745cd3c5Smaybee resa.toguid = drc->drc_drrb->drr_toguid; 1162745cd3c5Smaybee resa.tosnap = drc->drc_tosnap; 11633cb34c60Sahrens 1164745cd3c5Smaybee err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1165745cd3c5Smaybee recv_end_check, recv_end_sync, ds, &resa, 3); 1166745cd3c5Smaybee if (err) { 1167745cd3c5Smaybee if (drc->drc_newfs) { 1168745cd3c5Smaybee ASSERT(ds == drc->drc_real_ds); 1169745cd3c5Smaybee (void) dsl_dataset_destroy(ds, dmu_recv_tag); 1170745cd3c5Smaybee return (err); 1171745cd3c5Smaybee } else { 1172745cd3c5Smaybee (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 11733cb34c60Sahrens } 11743cb34c60Sahrens } 11753cb34c60Sahrens 1176745cd3c5Smaybee /* release the hold from dmu_recv_begin */ 1177745cd3c5Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 1178f18faf3fSek return (err); 1179f18faf3fSek } 1180