12743Sahrens /* 22743Sahrens * CDDL HEADER START 32743Sahrens * 42743Sahrens * The contents of this file are subject to the terms of the 52743Sahrens * Common Development and Distribution License (the "License"). 62743Sahrens * You may not use this file except in compliance with the License. 72743Sahrens * 82743Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92743Sahrens * or http://www.opensolaris.org/os/licensing. 102743Sahrens * See the License for the specific language governing permissions 112743Sahrens * and limitations under the License. 122743Sahrens * 132743Sahrens * When distributing Covered Code, include this CDDL HEADER in each 142743Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152743Sahrens * If applicable, add the following below this CDDL HEADER, with the 162743Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 172743Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 182743Sahrens * 192743Sahrens * CDDL HEADER END 202743Sahrens */ 212743Sahrens /* 226083Sek110237 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 232743Sahrens * Use is subject to license terms. 242743Sahrens */ 252743Sahrens 262743Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 272743Sahrens 282743Sahrens #include <sys/dmu.h> 292743Sahrens #include <sys/dmu_impl.h> 302743Sahrens #include <sys/dmu_tx.h> 312743Sahrens #include <sys/dbuf.h> 322743Sahrens #include <sys/dnode.h> 332743Sahrens #include <sys/zfs_context.h> 342743Sahrens #include <sys/dmu_objset.h> 352743Sahrens #include <sys/dmu_traverse.h> 362743Sahrens #include <sys/dsl_dataset.h> 372743Sahrens #include <sys/dsl_dir.h> 382743Sahrens #include <sys/dsl_pool.h> 392743Sahrens #include <sys/dsl_synctask.h> 402743Sahrens #include <sys/zfs_ioctl.h> 412743Sahrens #include <sys/zap.h> 422743Sahrens #include <sys/zio_checksum.h> 432743Sahrens 445367Sahrens static char *dmu_recv_tag = "dmu_recv_tag"; 455367Sahrens 462743Sahrens struct backuparg { 472743Sahrens dmu_replay_record_t *drr; 482743Sahrens vnode_t *vp; 495367Sahrens offset_t *off; 502743Sahrens objset_t *os; 512743Sahrens zio_cksum_t zc; 522743Sahrens int err; 532743Sahrens }; 542743Sahrens 552743Sahrens static int 562743Sahrens dump_bytes(struct backuparg *ba, void *buf, int len) 572743Sahrens { 582743Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 592743Sahrens ASSERT3U(len % 8, ==, 0); 602743Sahrens 612743Sahrens fletcher_4_incremental_native(buf, len, &ba->zc); 622743Sahrens ba->err = vn_rdwr(UIO_WRITE, ba->vp, 632743Sahrens (caddr_t)buf, len, 642743Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 655367Sahrens *ba->off += len; 662743Sahrens return (ba->err); 672743Sahrens } 682743Sahrens 692743Sahrens static int 702743Sahrens dump_free(struct backuparg *ba, uint64_t object, uint64_t offset, 712743Sahrens uint64_t length) 722743Sahrens { 732743Sahrens /* write a FREE record */ 742743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 752743Sahrens ba->drr->drr_type = DRR_FREE; 762743Sahrens ba->drr->drr_u.drr_free.drr_object = object; 772743Sahrens ba->drr->drr_u.drr_free.drr_offset = offset; 782743Sahrens ba->drr->drr_u.drr_free.drr_length = length; 792743Sahrens 802743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 812743Sahrens return (EINTR); 822743Sahrens return (0); 832743Sahrens } 842743Sahrens 852743Sahrens static int 862743Sahrens dump_data(struct backuparg *ba, dmu_object_type_t type, 872743Sahrens uint64_t object, uint64_t offset, int blksz, void *data) 882743Sahrens { 892743Sahrens /* write a DATA record */ 902743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 912743Sahrens ba->drr->drr_type = DRR_WRITE; 922743Sahrens ba->drr->drr_u.drr_write.drr_object = object; 932743Sahrens ba->drr->drr_u.drr_write.drr_type = type; 942743Sahrens ba->drr->drr_u.drr_write.drr_offset = offset; 952743Sahrens ba->drr->drr_u.drr_write.drr_length = blksz; 962743Sahrens 972743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 982743Sahrens return (EINTR); 992743Sahrens if (dump_bytes(ba, data, blksz)) 1002743Sahrens return (EINTR); 1012743Sahrens return (0); 1022743Sahrens } 1032743Sahrens 1042743Sahrens static int 1052743Sahrens dump_freeobjects(struct backuparg *ba, uint64_t firstobj, uint64_t numobjs) 1062743Sahrens { 1072743Sahrens /* write a FREEOBJECTS record */ 1082743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 1092743Sahrens ba->drr->drr_type = DRR_FREEOBJECTS; 1102743Sahrens ba->drr->drr_u.drr_freeobjects.drr_firstobj = firstobj; 1112743Sahrens ba->drr->drr_u.drr_freeobjects.drr_numobjs = numobjs; 1122743Sahrens 1132743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 1142743Sahrens return (EINTR); 1152743Sahrens return (0); 1162743Sahrens } 1172743Sahrens 1182743Sahrens static int 1192743Sahrens dump_dnode(struct backuparg *ba, uint64_t object, dnode_phys_t *dnp) 1202743Sahrens { 1212743Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 1222743Sahrens return (dump_freeobjects(ba, object, 1)); 1232743Sahrens 1242743Sahrens /* write an OBJECT record */ 1252743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 1262743Sahrens ba->drr->drr_type = DRR_OBJECT; 1272743Sahrens ba->drr->drr_u.drr_object.drr_object = object; 1282743Sahrens ba->drr->drr_u.drr_object.drr_type = dnp->dn_type; 1292743Sahrens ba->drr->drr_u.drr_object.drr_bonustype = dnp->dn_bonustype; 1302743Sahrens ba->drr->drr_u.drr_object.drr_blksz = 1312743Sahrens dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 1322743Sahrens ba->drr->drr_u.drr_object.drr_bonuslen = dnp->dn_bonuslen; 1332743Sahrens ba->drr->drr_u.drr_object.drr_checksum = dnp->dn_checksum; 1342743Sahrens ba->drr->drr_u.drr_object.drr_compress = dnp->dn_compress; 1352743Sahrens 1362743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 1372743Sahrens return (EINTR); 1382743Sahrens 1392743Sahrens if (dump_bytes(ba, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8))) 1402743Sahrens return (EINTR); 1412743Sahrens 1422743Sahrens /* free anything past the end of the file */ 1432743Sahrens if (dump_free(ba, object, (dnp->dn_maxblkid + 1) * 1442743Sahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 1452743Sahrens return (EINTR); 1462743Sahrens if (ba->err) 1472743Sahrens return (EINTR); 1482743Sahrens return (0); 1492743Sahrens } 1502743Sahrens 1512743Sahrens #define BP_SPAN(dnp, level) \ 1522743Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 1532743Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 1542743Sahrens 1552743Sahrens static int 1562743Sahrens backup_cb(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 1572743Sahrens { 1582743Sahrens struct backuparg *ba = arg; 1592743Sahrens uint64_t object = bc->bc_bookmark.zb_object; 1602743Sahrens int level = bc->bc_bookmark.zb_level; 1612743Sahrens uint64_t blkid = bc->bc_bookmark.zb_blkid; 1622743Sahrens blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL; 1632743Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 1642743Sahrens void *data = bc->bc_data; 1652743Sahrens int err = 0; 1662743Sahrens 1672743Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 1682743Sahrens return (EINTR); 1692743Sahrens 1702743Sahrens ASSERT(data || bp == NULL); 1712743Sahrens 1722743Sahrens if (bp == NULL && object == 0) { 1732743Sahrens uint64_t span = BP_SPAN(bc->bc_dnode, level); 1742743Sahrens uint64_t dnobj = (blkid * span) >> DNODE_SHIFT; 1752743Sahrens err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT); 1762743Sahrens } else if (bp == NULL) { 1772743Sahrens uint64_t span = BP_SPAN(bc->bc_dnode, level); 1782743Sahrens err = dump_free(ba, object, blkid * span, span); 1792743Sahrens } else if (data && level == 0 && type == DMU_OT_DNODE) { 1802743Sahrens dnode_phys_t *blk = data; 1812743Sahrens int i; 1822743Sahrens int blksz = BP_GET_LSIZE(bp); 1832743Sahrens 1842743Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 1852743Sahrens uint64_t dnobj = 1862743Sahrens (blkid << (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 1872743Sahrens err = dump_dnode(ba, dnobj, blk+i); 1882743Sahrens if (err) 1892743Sahrens break; 1902743Sahrens } 1912743Sahrens } else if (level == 0 && 1922743Sahrens type != DMU_OT_DNODE && type != DMU_OT_OBJSET) { 1932743Sahrens int blksz = BP_GET_LSIZE(bp); 1942743Sahrens if (data == NULL) { 1952743Sahrens uint32_t aflags = ARC_WAIT; 1962743Sahrens arc_buf_t *abuf; 1972743Sahrens zbookmark_t zb; 1982743Sahrens 1992743Sahrens zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object; 2002743Sahrens zb.zb_object = object; 2012743Sahrens zb.zb_level = level; 2022743Sahrens zb.zb_blkid = blkid; 2032743Sahrens (void) arc_read(NULL, spa, bp, 2042743Sahrens dmu_ot[type].ot_byteswap, arc_getbuf_func, &abuf, 2052743Sahrens ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_MUSTSUCCEED, 2062743Sahrens &aflags, &zb); 2072743Sahrens 2082743Sahrens if (abuf) { 2092743Sahrens err = dump_data(ba, type, object, blkid * blksz, 2102743Sahrens blksz, abuf->b_data); 2112743Sahrens (void) arc_buf_remove_ref(abuf, &abuf); 2122743Sahrens } 2132743Sahrens } else { 2142743Sahrens err = dump_data(ba, type, object, blkid * blksz, 2152743Sahrens blksz, data); 2162743Sahrens } 2172743Sahrens } 2182743Sahrens 2192743Sahrens ASSERT(err == 0 || err == EINTR); 2202743Sahrens return (err); 2212743Sahrens } 2222743Sahrens 2232743Sahrens int 2245367Sahrens dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin, 2255367Sahrens vnode_t *vp, offset_t *off) 2262743Sahrens { 2272743Sahrens dsl_dataset_t *ds = tosnap->os->os_dsl_dataset; 2282743Sahrens dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL; 2292743Sahrens dmu_replay_record_t *drr; 2302743Sahrens struct backuparg ba; 2312743Sahrens int err; 2325367Sahrens uint64_t fromtxg = 0; 2332743Sahrens 2342743Sahrens /* tosnap must be a snapshot */ 2352743Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 2362743Sahrens return (EINVAL); 2372743Sahrens 2382743Sahrens /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 2392743Sahrens if (fromds && (ds->ds_dir != fromds->ds_dir || 2405367Sahrens fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg)) 2412743Sahrens return (EXDEV); 2422743Sahrens 2435367Sahrens if (fromorigin) { 2445367Sahrens if (fromsnap) 2455367Sahrens return (EINVAL); 2465367Sahrens 2475367Sahrens if (ds->ds_dir->dd_phys->dd_origin_obj != NULL) { 2485367Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 2495367Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 2506689Smaybee err = dsl_dataset_hold_obj(dp, 2516689Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds); 2525367Sahrens rw_exit(&dp->dp_config_rwlock); 2535367Sahrens if (err) 2545367Sahrens return (err); 2555367Sahrens } else { 2565367Sahrens fromorigin = B_FALSE; 2575367Sahrens } 2585367Sahrens } 2595367Sahrens 2605367Sahrens 2612743Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 2622743Sahrens drr->drr_type = DRR_BEGIN; 2632743Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 2645367Sahrens drr->drr_u.drr_begin.drr_version = DMU_BACKUP_STREAM_VERSION; 2652743Sahrens drr->drr_u.drr_begin.drr_creation_time = 2662743Sahrens ds->ds_phys->ds_creation_time; 2672743Sahrens drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type; 2685367Sahrens if (fromorigin) 2695367Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 2702743Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 2716492Stimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 2726492Stimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 2736492Stimh 2742743Sahrens if (fromds) 2752743Sahrens drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 2762743Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 2772743Sahrens 2785367Sahrens if (fromds) 2795367Sahrens fromtxg = fromds->ds_phys->ds_creation_txg; 2805367Sahrens if (fromorigin) 2816689Smaybee dsl_dataset_rele(fromds, FTAG); 2825367Sahrens 2832743Sahrens ba.drr = drr; 2842743Sahrens ba.vp = vp; 2852743Sahrens ba.os = tosnap; 2865367Sahrens ba.off = off; 2872743Sahrens ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); 2882743Sahrens 2892743Sahrens if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 2902743Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 2912743Sahrens return (ba.err); 2922743Sahrens } 2932743Sahrens 2945367Sahrens err = traverse_dsl_dataset(ds, fromtxg, 2952743Sahrens ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK, 2962743Sahrens backup_cb, &ba); 2972743Sahrens 2982743Sahrens if (err) { 2992743Sahrens if (err == EINTR && ba.err) 3002743Sahrens err = ba.err; 3013655Sgw25295 kmem_free(drr, sizeof (dmu_replay_record_t)); 3022743Sahrens return (err); 3032743Sahrens } 3042743Sahrens 3052743Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 3062743Sahrens drr->drr_type = DRR_END; 3072743Sahrens drr->drr_u.drr_end.drr_checksum = ba.zc; 3082743Sahrens 3093655Sgw25295 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 3103655Sgw25295 kmem_free(drr, sizeof (dmu_replay_record_t)); 3112743Sahrens return (ba.err); 3123655Sgw25295 } 3132743Sahrens 3142743Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 3152743Sahrens 3162743Sahrens return (0); 3172743Sahrens } 3182743Sahrens 3195367Sahrens struct recvbeginsyncarg { 3205367Sahrens const char *tofs; 3215367Sahrens const char *tosnap; 3225367Sahrens dsl_dataset_t *origin; 3235367Sahrens uint64_t fromguid; 3245367Sahrens dmu_objset_type_t type; 3255367Sahrens void *tag; 3265367Sahrens boolean_t force; 3276492Stimh uint64_t dsflags; 3285367Sahrens char clonelastname[MAXNAMELEN]; 3295367Sahrens dsl_dataset_t *ds; /* the ds to recv into; returned from the syncfunc */ 3302743Sahrens }; 3312743Sahrens 3325367Sahrens static dsl_dataset_t * 3335367Sahrens recv_full_sync_impl(dsl_pool_t *dp, uint64_t dsobj, dmu_objset_type_t type, 3345367Sahrens cred_t *cr, dmu_tx_t *tx) 3355367Sahrens { 3365367Sahrens dsl_dataset_t *ds; 3375367Sahrens 3386689Smaybee /* This should always work, since we just created it */ 3396689Smaybee /* XXX - create should return an owned ds */ 3406689Smaybee VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 3416689Smaybee DS_MODE_INCONSISTENT, dmu_recv_tag, &ds)); 3425367Sahrens 3435367Sahrens if (type != DMU_OST_NONE) { 3445367Sahrens (void) dmu_objset_create_impl(dp->dp_spa, 3455367Sahrens ds, &ds->ds_phys->ds_bp, type, tx); 3465367Sahrens } 3475367Sahrens 3485367Sahrens spa_history_internal_log(LOG_DS_REPLAY_FULL_SYNC, 3496689Smaybee dp->dp_spa, tx, cr, "dataset = %lld", dsobj); 3505367Sahrens 3515367Sahrens return (ds); 3525367Sahrens } 3535367Sahrens 3545367Sahrens /* ARGSUSED */ 3552743Sahrens static int 3565367Sahrens recv_full_check(void *arg1, void *arg2, dmu_tx_t *tx) 3575367Sahrens { 3585367Sahrens dsl_dir_t *dd = arg1; 3595367Sahrens struct recvbeginsyncarg *rbsa = arg2; 3605367Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 3615367Sahrens uint64_t val; 3625367Sahrens int err; 3635367Sahrens 3645367Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 3655367Sahrens strrchr(rbsa->tofs, '/') + 1, sizeof (uint64_t), 1, &val); 3665367Sahrens 3675367Sahrens if (err != ENOENT) 3685367Sahrens return (err ? err : EEXIST); 3695367Sahrens 3705367Sahrens if (rbsa->origin) { 3715367Sahrens /* make sure it's a snap in the same pool */ 3725367Sahrens if (rbsa->origin->ds_dir->dd_pool != dd->dd_pool) 3735367Sahrens return (EXDEV); 3745367Sahrens if (rbsa->origin->ds_phys->ds_num_children == 0) 3755367Sahrens return (EINVAL); 3765367Sahrens if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 3775367Sahrens return (ENODEV); 3785367Sahrens } 3795367Sahrens 3805367Sahrens return (0); 3815367Sahrens } 3825367Sahrens 3835367Sahrens static void 3845367Sahrens recv_full_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3855367Sahrens { 3865367Sahrens dsl_dir_t *dd = arg1; 3875367Sahrens struct recvbeginsyncarg *rbsa = arg2; 3886689Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 3895367Sahrens uint64_t dsobj; 3905367Sahrens 3915367Sahrens dsobj = dsl_dataset_create_sync(dd, strrchr(rbsa->tofs, '/') + 1, 3926492Stimh rbsa->origin, flags, cr, tx); 3935367Sahrens 3945367Sahrens rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj, 3955367Sahrens rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx); 3965367Sahrens } 3975367Sahrens 3985367Sahrens static int 3995367Sahrens recv_full_existing_check(void *arg1, void *arg2, dmu_tx_t *tx) 4002743Sahrens { 4015367Sahrens dsl_dataset_t *ds = arg1; 4025367Sahrens struct recvbeginsyncarg *rbsa = arg2; 4035367Sahrens int err; 4045367Sahrens 4055367Sahrens /* must be a head ds */ 4065367Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 4075367Sahrens return (EINVAL); 4085367Sahrens 4095367Sahrens /* must not be a clone ds */ 4105367Sahrens if (ds->ds_prev != NULL) 4115367Sahrens return (EINVAL); 4125367Sahrens 4135367Sahrens err = dsl_dataset_destroy_check(ds, rbsa->tag, tx); 4145367Sahrens if (err) 4155367Sahrens return (err); 4165367Sahrens 4175367Sahrens if (rbsa->origin) { 4185367Sahrens /* make sure it's a snap in the same pool */ 4195367Sahrens if (rbsa->origin->ds_dir->dd_pool != ds->ds_dir->dd_pool) 4205367Sahrens return (EXDEV); 4215367Sahrens if (rbsa->origin->ds_phys->ds_num_children == 0) 4225367Sahrens return (EINVAL); 4235367Sahrens if (rbsa->origin->ds_phys->ds_guid != rbsa->fromguid) 4245367Sahrens return (ENODEV); 4255367Sahrens } 4265367Sahrens 4275367Sahrens return (0); 4285367Sahrens } 4295367Sahrens 4305367Sahrens static void 4315367Sahrens recv_full_existing_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 4325367Sahrens { 4335367Sahrens dsl_dataset_t *ds = arg1; 4345367Sahrens struct recvbeginsyncarg *rbsa = arg2; 4355367Sahrens dsl_dir_t *dd = ds->ds_dir; 4366689Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 4375367Sahrens uint64_t dsobj; 4385367Sahrens 4395367Sahrens /* 4405367Sahrens * NB: caller must provide an extra hold on the dsl_dir_t, so it 4415367Sahrens * won't go away when dsl_dataset_destroy_sync() closes the 4425367Sahrens * dataset. 4435367Sahrens */ 4445367Sahrens dsl_dataset_destroy_sync(ds, rbsa->tag, cr, tx); 4455367Sahrens 4466492Stimh dsobj = dsl_dataset_create_sync_impl(dd, rbsa->origin, flags, tx); 4475367Sahrens 4485367Sahrens rbsa->ds = recv_full_sync_impl(dd->dd_pool, dsobj, 4495367Sahrens rbsa->origin ? DMU_OST_NONE : rbsa->type, cr, tx); 4505367Sahrens } 4515367Sahrens 4525367Sahrens /* ARGSUSED */ 4535367Sahrens static int 4545367Sahrens recv_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 4555367Sahrens { 4565367Sahrens dsl_dataset_t *ds = arg1; 4575367Sahrens struct recvbeginsyncarg *rbsa = arg2; 4582743Sahrens int err; 4592743Sahrens uint64_t val; 4602743Sahrens 4615367Sahrens /* must not have any changes since most recent snapshot */ 4625367Sahrens if (!rbsa->force && dsl_dataset_modified_since_lastsnap(ds)) 4635367Sahrens return (ETXTBSY); 4645367Sahrens 4652743Sahrens /* must already be a snapshot of this fs */ 4662743Sahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 4672743Sahrens return (ENODEV); 4682743Sahrens 4692743Sahrens /* most recent snapshot must match fromguid */ 4705367Sahrens if (ds->ds_prev->ds_phys->ds_guid != rbsa->fromguid) 4712743Sahrens return (ENODEV); 4722743Sahrens 4736083Sek110237 /* temporary clone name must not exist */ 4746083Sek110237 err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 4756083Sek110237 ds->ds_dir->dd_phys->dd_child_dir_zapobj, 4766083Sek110237 rbsa->clonelastname, 8, 1, &val); 4776083Sek110237 if (err == 0) 4786083Sek110237 return (EEXIST); 4796083Sek110237 if (err != ENOENT) 4806083Sek110237 return (err); 4816083Sek110237 4822743Sahrens /* new snapshot name must not exist */ 4835367Sahrens err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 4845367Sahrens ds->ds_phys->ds_snapnames_zapobj, rbsa->tosnap, 8, 1, &val); 4855367Sahrens if (err == 0) 4862743Sahrens return (EEXIST); 4872743Sahrens if (err != ENOENT) 4885367Sahrens return (err); 4892743Sahrens return (0); 4902743Sahrens } 4912743Sahrens 4922743Sahrens /* ARGSUSED */ 4935367Sahrens static void 4945367Sahrens recv_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 4955326Sek110237 { 4965367Sahrens dsl_dataset_t *ohds = arg1; 4975367Sahrens struct recvbeginsyncarg *rbsa = arg2; 4985367Sahrens dsl_pool_t *dp = ohds->ds_dir->dd_pool; 4995367Sahrens dsl_dataset_t *ods, *cds; 5006689Smaybee uint64_t flags = DS_FLAG_INCONSISTENT | rbsa->dsflags; 5015367Sahrens uint64_t dsobj; 5025326Sek110237 5035367Sahrens /* create the temporary clone */ 5046689Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, ohds->ds_phys->ds_prev_snap_obj, 5056689Smaybee FTAG, &ods)); 5065367Sahrens dsobj = dsl_dataset_create_sync(ohds->ds_dir, 5076492Stimh rbsa->clonelastname, ods, flags, cr, tx); 5086689Smaybee dsl_dataset_rele(ods, FTAG); 5095326Sek110237 5105367Sahrens /* open the temporary clone */ 5116689Smaybee VERIFY(0 == dsl_dataset_own_obj(dp, dsobj, 5126689Smaybee DS_MODE_INCONSISTENT, dmu_recv_tag, &cds)); 5135367Sahrens 5145378Sck153898 /* copy the refquota from the target fs to the clone */ 5155378Sck153898 if (ohds->ds_quota > 0) 5165378Sck153898 dsl_dataset_set_quota_sync(cds, &ohds->ds_quota, cr, tx); 5175378Sck153898 5185367Sahrens rbsa->ds = cds; 5195367Sahrens 5205367Sahrens spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 5216689Smaybee dp->dp_spa, tx, cr, "dataset = %lld", dsobj); 5225326Sek110237 } 5235326Sek110237 5245326Sek110237 /* ARGSUSED */ 5252743Sahrens static void 5265367Sahrens recv_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 5272743Sahrens { 5282743Sahrens dsl_dataset_t *ds = arg1; 5295378Sck153898 5302743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 5312743Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 5324543Smarks 5334543Smarks spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 5344543Smarks ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld", 5356689Smaybee ds->ds_object); 5362743Sahrens } 5372743Sahrens 5385367Sahrens /* 5395367Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 5405367Sahrens * succeeds; otherwise we will leak the holds on the datasets. 5415367Sahrens */ 5425367Sahrens int 5435367Sahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 5445367Sahrens boolean_t force, objset_t *origin, boolean_t online, dmu_recv_cookie_t *drc) 5452743Sahrens { 5465367Sahrens int err = 0; 5475367Sahrens boolean_t byteswap; 5485367Sahrens struct recvbeginsyncarg rbsa; 5495367Sahrens uint64_t version; 5505367Sahrens int flags; 5515367Sahrens dsl_dataset_t *ds; 5525367Sahrens 5535367Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) 5545367Sahrens byteswap = FALSE; 5555367Sahrens else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 5565367Sahrens byteswap = TRUE; 5575367Sahrens else 5585367Sahrens return (EINVAL); 5595367Sahrens 5605367Sahrens rbsa.tofs = tofs; 5615367Sahrens rbsa.tosnap = tosnap; 5625367Sahrens rbsa.origin = origin ? origin->os->os_dsl_dataset : NULL; 5635367Sahrens rbsa.fromguid = drrb->drr_fromguid; 5645367Sahrens rbsa.type = drrb->drr_type; 5655367Sahrens rbsa.tag = FTAG; 5666492Stimh rbsa.dsflags = 0; 5675367Sahrens version = drrb->drr_version; 5685367Sahrens flags = drrb->drr_flags; 5695367Sahrens 5705367Sahrens if (byteswap) { 5715367Sahrens rbsa.type = BSWAP_32(rbsa.type); 5725367Sahrens rbsa.fromguid = BSWAP_64(rbsa.fromguid); 5735367Sahrens version = BSWAP_64(version); 5745367Sahrens flags = BSWAP_32(flags); 5755367Sahrens } 5765367Sahrens 5775367Sahrens if (version != DMU_BACKUP_STREAM_VERSION || 5785367Sahrens rbsa.type >= DMU_OST_NUMTYPES || 5795367Sahrens ((flags & DRR_FLAG_CLONE) && origin == NULL)) 5805367Sahrens return (EINVAL); 5815367Sahrens 5826492Stimh if (flags & DRR_FLAG_CI_DATA) 5836492Stimh rbsa.dsflags = DS_FLAG_CI_DATASET; 5846492Stimh 5855367Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 5865367Sahrens drc->drc_drrb = drrb; 5875367Sahrens drc->drc_tosnap = tosnap; 5885367Sahrens drc->drc_force = force; 5895367Sahrens 5905367Sahrens /* 5915367Sahrens * Process the begin in syncing context. 5925367Sahrens */ 5935367Sahrens if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE) && !online) { 5945367Sahrens /* offline incremental receive */ 5956689Smaybee err = dsl_dataset_own(tofs, 0, dmu_recv_tag, &ds); 5965367Sahrens if (err) 5975367Sahrens return (err); 5982743Sahrens 5995367Sahrens /* 6005367Sahrens * Only do the rollback if the most recent snapshot 6015367Sahrens * matches the incremental source 6025367Sahrens */ 6035367Sahrens if (force) { 6045367Sahrens if (ds->ds_prev == NULL || 6055367Sahrens ds->ds_prev->ds_phys->ds_guid != 6065367Sahrens rbsa.fromguid) { 6076689Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 6085367Sahrens return (ENODEV); 6095367Sahrens } 6105367Sahrens (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 6115367Sahrens } 6125367Sahrens rbsa.force = B_FALSE; 6135367Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 6145367Sahrens recv_incremental_check, 6156689Smaybee recv_offline_incremental_sync, ds, &rbsa, 1); 6165367Sahrens if (err) { 6176689Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 6185367Sahrens return (err); 6195367Sahrens } 6205367Sahrens drc->drc_logical_ds = drc->drc_real_ds = ds; 6215367Sahrens } else if (rbsa.fromguid && !(flags & DRR_FLAG_CLONE)) { 6225367Sahrens /* online incremental receive */ 6235367Sahrens 6245367Sahrens /* tmp clone name is: tofs/%tosnap" */ 6255367Sahrens (void) snprintf(rbsa.clonelastname, sizeof (rbsa.clonelastname), 6265367Sahrens "%%%s", tosnap); 6275367Sahrens 6285367Sahrens /* open the dataset we are logically receiving into */ 6296689Smaybee err = dsl_dataset_hold(tofs, dmu_recv_tag, &ds); 6305367Sahrens if (err) 6315367Sahrens return (err); 6322743Sahrens 6335367Sahrens rbsa.force = force; 6345367Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 6355367Sahrens recv_incremental_check, 6365367Sahrens recv_online_incremental_sync, ds, &rbsa, 5); 6375367Sahrens if (err) { 6386689Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 6395367Sahrens return (err); 6405367Sahrens } 6415367Sahrens drc->drc_logical_ds = ds; 6425367Sahrens drc->drc_real_ds = rbsa.ds; 6435367Sahrens } else { 6445367Sahrens /* create new fs -- full backup or clone */ 6455367Sahrens dsl_dir_t *dd = NULL; 6465367Sahrens const char *tail; 6475367Sahrens 6485367Sahrens err = dsl_dir_open(tofs, FTAG, &dd, &tail); 6495367Sahrens if (err) 6505367Sahrens return (err); 6515367Sahrens if (tail == NULL) { 6525367Sahrens if (!force) { 6535367Sahrens dsl_dir_close(dd, FTAG); 6545367Sahrens return (EEXIST); 6555367Sahrens } 6565367Sahrens 6575367Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 6586689Smaybee err = dsl_dataset_own_obj(dd->dd_pool, 6596689Smaybee dd->dd_phys->dd_head_dataset_obj, 6606689Smaybee DS_MODE_INCONSISTENT, FTAG, &ds); 6615367Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 6625367Sahrens if (err) { 6635367Sahrens dsl_dir_close(dd, FTAG); 6645367Sahrens return (err); 6655367Sahrens } 6665367Sahrens 6676689Smaybee dsl_dataset_make_exclusive(ds, FTAG); 6685367Sahrens err = dsl_sync_task_do(dd->dd_pool, 6695367Sahrens recv_full_existing_check, 6705367Sahrens recv_full_existing_sync, ds, &rbsa, 5); 6716689Smaybee dsl_dataset_disown(ds, FTAG); 6725367Sahrens } else { 6735367Sahrens err = dsl_sync_task_do(dd->dd_pool, recv_full_check, 6745367Sahrens recv_full_sync, dd, &rbsa, 5); 6755367Sahrens } 6765367Sahrens dsl_dir_close(dd, FTAG); 6775367Sahrens if (err) 6785367Sahrens return (err); 6795367Sahrens drc->drc_logical_ds = drc->drc_real_ds = rbsa.ds; 6805367Sahrens drc->drc_newfs = B_TRUE; 6815367Sahrens } 6825367Sahrens 6832743Sahrens return (0); 6842743Sahrens } 6852743Sahrens 6865367Sahrens struct restorearg { 6875367Sahrens int err; 6885367Sahrens int byteswap; 6895367Sahrens vnode_t *vp; 6905367Sahrens char *buf; 6915367Sahrens uint64_t voff; 6925367Sahrens int bufsize; /* amount of memory allocated for buf */ 6935367Sahrens zio_cksum_t cksum; 6945326Sek110237 }; 6955326Sek110237 6962743Sahrens static void * 6972743Sahrens restore_read(struct restorearg *ra, int len) 6982743Sahrens { 6992743Sahrens void *rv; 7005367Sahrens int done = 0; 7012743Sahrens 7022743Sahrens /* some things will require 8-byte alignment, so everything must */ 7032743Sahrens ASSERT3U(len % 8, ==, 0); 7042743Sahrens 7055367Sahrens while (done < len) { 7062743Sahrens ssize_t resid; 7072743Sahrens 7082743Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 7095367Sahrens (caddr_t)ra->buf + done, len - done, 7102743Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 7112743Sahrens RLIM64_INFINITY, CRED(), &resid); 7122743Sahrens 7135367Sahrens if (resid == len - done) 7142743Sahrens ra->err = EINVAL; 7155367Sahrens ra->voff += len - done - resid; 7165367Sahrens done = len - resid; 7172743Sahrens if (ra->err) 7182743Sahrens return (NULL); 7192743Sahrens } 7202743Sahrens 7215367Sahrens ASSERT3U(done, ==, len); 7225367Sahrens rv = ra->buf; 7232743Sahrens if (ra->byteswap) 7245367Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 7252743Sahrens else 7265367Sahrens fletcher_4_incremental_native(rv, len, &ra->cksum); 7272743Sahrens return (rv); 7282743Sahrens } 7292743Sahrens 7302743Sahrens static void 7312743Sahrens backup_byteswap(dmu_replay_record_t *drr) 7322743Sahrens { 7332743Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 7342743Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 7352743Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 7365367Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 7372743Sahrens switch (drr->drr_type) { 7382743Sahrens case DRR_BEGIN: 7392743Sahrens DO64(drr_begin.drr_magic); 7402743Sahrens DO64(drr_begin.drr_version); 7412743Sahrens DO64(drr_begin.drr_creation_time); 7422743Sahrens DO32(drr_begin.drr_type); 7435367Sahrens DO32(drr_begin.drr_flags); 7442743Sahrens DO64(drr_begin.drr_toguid); 7452743Sahrens DO64(drr_begin.drr_fromguid); 7462743Sahrens break; 7472743Sahrens case DRR_OBJECT: 7482743Sahrens DO64(drr_object.drr_object); 7492743Sahrens /* DO64(drr_object.drr_allocation_txg); */ 7502743Sahrens DO32(drr_object.drr_type); 7512743Sahrens DO32(drr_object.drr_bonustype); 7522743Sahrens DO32(drr_object.drr_blksz); 7532743Sahrens DO32(drr_object.drr_bonuslen); 7542743Sahrens break; 7552743Sahrens case DRR_FREEOBJECTS: 7562743Sahrens DO64(drr_freeobjects.drr_firstobj); 7572743Sahrens DO64(drr_freeobjects.drr_numobjs); 7582743Sahrens break; 7592743Sahrens case DRR_WRITE: 7602743Sahrens DO64(drr_write.drr_object); 7612743Sahrens DO32(drr_write.drr_type); 7622743Sahrens DO64(drr_write.drr_offset); 7632743Sahrens DO64(drr_write.drr_length); 7642743Sahrens break; 7652743Sahrens case DRR_FREE: 7662743Sahrens DO64(drr_free.drr_object); 7672743Sahrens DO64(drr_free.drr_offset); 7682743Sahrens DO64(drr_free.drr_length); 7692743Sahrens break; 7702743Sahrens case DRR_END: 7712743Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 7722743Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 7732743Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 7742743Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 7752743Sahrens break; 7762743Sahrens } 7772743Sahrens #undef DO64 7782743Sahrens #undef DO32 7792743Sahrens } 7802743Sahrens 7812743Sahrens static int 7822743Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 7832743Sahrens { 7842743Sahrens int err; 7852743Sahrens dmu_tx_t *tx; 7862743Sahrens 7872743Sahrens err = dmu_object_info(os, drro->drr_object, NULL); 7882743Sahrens 7892743Sahrens if (err != 0 && err != ENOENT) 7902743Sahrens return (EINVAL); 7912743Sahrens 7922743Sahrens if (drro->drr_type == DMU_OT_NONE || 7932743Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 7942743Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 7952743Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 7962743Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 7972743Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 7982743Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 7992743Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 8002743Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 8012743Sahrens return (EINVAL); 8022743Sahrens } 8032743Sahrens 8042743Sahrens tx = dmu_tx_create(os); 8052743Sahrens 8062743Sahrens if (err == ENOENT) { 8072743Sahrens /* currently free, want to be allocated */ 8082743Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 8092743Sahrens dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 1); 8102743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 8112743Sahrens if (err) { 8122743Sahrens dmu_tx_abort(tx); 8132743Sahrens return (err); 8142743Sahrens } 8152743Sahrens err = dmu_object_claim(os, drro->drr_object, 8162743Sahrens drro->drr_type, drro->drr_blksz, 8172743Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 8182743Sahrens } else { 8192743Sahrens /* currently allocated, want to be allocated */ 8202743Sahrens dmu_tx_hold_bonus(tx, drro->drr_object); 8212743Sahrens /* 8222743Sahrens * We may change blocksize, so need to 8232743Sahrens * hold_write 8242743Sahrens */ 8252743Sahrens dmu_tx_hold_write(tx, drro->drr_object, 0, 1); 8262743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 8272743Sahrens if (err) { 8282743Sahrens dmu_tx_abort(tx); 8292743Sahrens return (err); 8302743Sahrens } 8312743Sahrens 8322743Sahrens err = dmu_object_reclaim(os, drro->drr_object, 8332743Sahrens drro->drr_type, drro->drr_blksz, 8342743Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 8352743Sahrens } 8362743Sahrens if (err) { 8372743Sahrens dmu_tx_commit(tx); 8382743Sahrens return (EINVAL); 8392743Sahrens } 8402743Sahrens 8412743Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 8422743Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 8432743Sahrens 8442743Sahrens if (drro->drr_bonuslen) { 8452743Sahrens dmu_buf_t *db; 8462743Sahrens void *data; 8472743Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 8482743Sahrens dmu_buf_will_dirty(db, tx); 8492743Sahrens 8504944Smaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 8514944Smaybee data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 8522743Sahrens if (data == NULL) { 8532743Sahrens dmu_tx_commit(tx); 8542743Sahrens return (ra->err); 8552743Sahrens } 8564944Smaybee bcopy(data, db->db_data, drro->drr_bonuslen); 8572743Sahrens if (ra->byteswap) { 8582743Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 8592743Sahrens drro->drr_bonuslen); 8602743Sahrens } 8612743Sahrens dmu_buf_rele(db, FTAG); 8622743Sahrens } 8632743Sahrens dmu_tx_commit(tx); 8642743Sahrens return (0); 8652743Sahrens } 8662743Sahrens 8672743Sahrens /* ARGSUSED */ 8682743Sahrens static int 8692743Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 8702743Sahrens struct drr_freeobjects *drrfo) 8712743Sahrens { 8722743Sahrens uint64_t obj; 8732743Sahrens 8742743Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 8752743Sahrens return (EINVAL); 8762743Sahrens 8772743Sahrens for (obj = drrfo->drr_firstobj; 8783087Sahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 8793087Sahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 8802743Sahrens int err; 8812743Sahrens 8822743Sahrens if (dmu_object_info(os, obj, NULL) != 0) 8832743Sahrens continue; 8842743Sahrens 885*6992Smaybee err = dmu_free_object(os, obj); 886*6992Smaybee if (err) 8872743Sahrens return (err); 8882743Sahrens } 8892743Sahrens return (0); 8902743Sahrens } 8912743Sahrens 8922743Sahrens static int 8932743Sahrens restore_write(struct restorearg *ra, objset_t *os, 8942743Sahrens struct drr_write *drrw) 8952743Sahrens { 8962743Sahrens dmu_tx_t *tx; 8972743Sahrens void *data; 8982743Sahrens int err; 8992743Sahrens 9002743Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 9012743Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 9022743Sahrens return (EINVAL); 9032743Sahrens 9042743Sahrens data = restore_read(ra, drrw->drr_length); 9052743Sahrens if (data == NULL) 9062743Sahrens return (ra->err); 9072743Sahrens 9082743Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 9092743Sahrens return (EINVAL); 9102743Sahrens 9112743Sahrens tx = dmu_tx_create(os); 9122743Sahrens 9132743Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 9142743Sahrens drrw->drr_offset, drrw->drr_length); 9152743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 9162743Sahrens if (err) { 9172743Sahrens dmu_tx_abort(tx); 9182743Sahrens return (err); 9192743Sahrens } 9202743Sahrens if (ra->byteswap) 9212743Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 9222743Sahrens dmu_write(os, drrw->drr_object, 9232743Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 9242743Sahrens dmu_tx_commit(tx); 9252743Sahrens return (0); 9262743Sahrens } 9272743Sahrens 9282743Sahrens /* ARGSUSED */ 9292743Sahrens static int 9302743Sahrens restore_free(struct restorearg *ra, objset_t *os, 9312743Sahrens struct drr_free *drrf) 9322743Sahrens { 9332743Sahrens int err; 9342743Sahrens 9352743Sahrens if (drrf->drr_length != -1ULL && 9362743Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 9372743Sahrens return (EINVAL); 9382743Sahrens 9392743Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 9402743Sahrens return (EINVAL); 9412743Sahrens 942*6992Smaybee err = dmu_free_long_range(os, drrf->drr_object, 9432743Sahrens drrf->drr_offset, drrf->drr_length); 9442743Sahrens return (err); 9452743Sahrens } 9462743Sahrens 9476083Sek110237 void 9486083Sek110237 dmu_recv_abort_cleanup(dmu_recv_cookie_t *drc) 9492743Sahrens { 9505367Sahrens if (drc->drc_newfs || drc->drc_real_ds != drc->drc_logical_ds) { 9515367Sahrens /* 9525367Sahrens * online incremental or new fs: destroy the fs (which 9535367Sahrens * may be a clone) that we created 9545367Sahrens */ 9555367Sahrens (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 9566689Smaybee if (drc->drc_real_ds != drc->drc_logical_ds) 9576689Smaybee dsl_dataset_rele(drc->drc_logical_ds, dmu_recv_tag); 9585367Sahrens } else { 9595367Sahrens /* 9605367Sahrens * offline incremental: rollback to most recent snapshot. 9615367Sahrens */ 9626689Smaybee (void) dsl_dataset_rollback(drc->drc_real_ds, DMU_OST_NONE); 9636689Smaybee dsl_dataset_disown(drc->drc_real_ds, dmu_recv_tag); 9645367Sahrens } 9655367Sahrens } 9662743Sahrens 9675367Sahrens /* 9685367Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 9695367Sahrens */ 9705367Sahrens int 9715367Sahrens dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp) 9725367Sahrens { 9735367Sahrens struct restorearg ra = { 0 }; 9745367Sahrens dmu_replay_record_t *drr; 9755367Sahrens objset_t *os; 9765367Sahrens zio_cksum_t pcksum; 9775367Sahrens 9785367Sahrens if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 9795367Sahrens ra.byteswap = TRUE; 9802743Sahrens 9815367Sahrens { 9825367Sahrens /* compute checksum of drr_begin record */ 9835367Sahrens dmu_replay_record_t *drr; 9845367Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 9855367Sahrens 9865367Sahrens drr->drr_type = DRR_BEGIN; 9875367Sahrens drr->drr_u.drr_begin = *drc->drc_drrb; 9885367Sahrens if (ra.byteswap) { 9895367Sahrens fletcher_4_incremental_byteswap(drr, 9905367Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9915367Sahrens } else { 9925367Sahrens fletcher_4_incremental_native(drr, 9935367Sahrens sizeof (dmu_replay_record_t), &ra.cksum); 9945367Sahrens } 9955367Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 9962743Sahrens } 9972743Sahrens 9982743Sahrens if (ra.byteswap) { 9995367Sahrens struct drr_begin *drrb = drc->drc_drrb; 10002743Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 10012743Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 10022743Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 10032743Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 10042743Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 10052743Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 10062743Sahrens } 10072743Sahrens 10085367Sahrens ra.vp = vp; 10095367Sahrens ra.voff = *voffp; 10105367Sahrens ra.bufsize = 1<<20; 10115367Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 10125326Sek110237 10135367Sahrens /* these were verified in dmu_recv_begin */ 10145367Sahrens ASSERT(drc->drc_drrb->drr_version == DMU_BACKUP_STREAM_VERSION); 10155367Sahrens ASSERT(drc->drc_drrb->drr_type < DMU_OST_NUMTYPES); 10162743Sahrens 10172743Sahrens /* 10182743Sahrens * Open the objset we are modifying. 10192743Sahrens */ 10205367Sahrens VERIFY(dmu_objset_open_ds(drc->drc_real_ds, DMU_OST_ANY, &os) == 0); 10212743Sahrens 10225367Sahrens ASSERT(drc->drc_real_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 10232743Sahrens 10242743Sahrens /* 10252743Sahrens * Read records and process them. 10262743Sahrens */ 10275367Sahrens pcksum = ra.cksum; 10282743Sahrens while (ra.err == 0 && 10292743Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 10302743Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 10312743Sahrens ra.err = EINTR; 10322743Sahrens goto out; 10332743Sahrens } 10342743Sahrens 10352743Sahrens if (ra.byteswap) 10362743Sahrens backup_byteswap(drr); 10372743Sahrens 10382743Sahrens switch (drr->drr_type) { 10392743Sahrens case DRR_OBJECT: 10402743Sahrens { 10412743Sahrens /* 10422743Sahrens * We need to make a copy of the record header, 10432743Sahrens * because restore_{object,write} may need to 10442743Sahrens * restore_read(), which will invalidate drr. 10452743Sahrens */ 10462743Sahrens struct drr_object drro = drr->drr_u.drr_object; 10472743Sahrens ra.err = restore_object(&ra, os, &drro); 10482743Sahrens break; 10492743Sahrens } 10502743Sahrens case DRR_FREEOBJECTS: 10512743Sahrens { 10522743Sahrens struct drr_freeobjects drrfo = 10532743Sahrens drr->drr_u.drr_freeobjects; 10542743Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 10552743Sahrens break; 10562743Sahrens } 10572743Sahrens case DRR_WRITE: 10582743Sahrens { 10592743Sahrens struct drr_write drrw = drr->drr_u.drr_write; 10602743Sahrens ra.err = restore_write(&ra, os, &drrw); 10612743Sahrens break; 10622743Sahrens } 10632743Sahrens case DRR_FREE: 10642743Sahrens { 10652743Sahrens struct drr_free drrf = drr->drr_u.drr_free; 10662743Sahrens ra.err = restore_free(&ra, os, &drrf); 10672743Sahrens break; 10682743Sahrens } 10692743Sahrens case DRR_END: 10702743Sahrens { 10712743Sahrens struct drr_end drre = drr->drr_u.drr_end; 10722743Sahrens /* 10732743Sahrens * We compare against the *previous* checksum 10742743Sahrens * value, because the stored checksum is of 10752743Sahrens * everything before the DRR_END record. 10762743Sahrens */ 10776479Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 10782743Sahrens ra.err = ECKSUM; 10792743Sahrens goto out; 10802743Sahrens } 10812743Sahrens default: 10822743Sahrens ra.err = EINVAL; 10832743Sahrens goto out; 10842743Sahrens } 10855367Sahrens pcksum = ra.cksum; 10862743Sahrens } 10876479Sahrens ASSERT(ra.err != 0); 10882743Sahrens 10892743Sahrens out: 10905367Sahrens dmu_objset_close(os); 10912743Sahrens 10925367Sahrens if (ra.err != 0) { 10932743Sahrens /* 10942743Sahrens * rollback or destroy what we created, so we don't 10952743Sahrens * leave it in the restoring state. 10962743Sahrens */ 10975367Sahrens txg_wait_synced(drc->drc_real_ds->ds_dir->dd_pool, 0); 10986083Sek110237 dmu_recv_abort_cleanup(drc); 10992743Sahrens } 11002743Sahrens 11012743Sahrens kmem_free(ra.buf, ra.bufsize); 11025367Sahrens *voffp = ra.voff; 11032743Sahrens return (ra.err); 11042743Sahrens } 11055326Sek110237 11065367Sahrens struct recvendsyncarg { 11075367Sahrens char *tosnap; 11085367Sahrens uint64_t creation_time; 11095367Sahrens uint64_t toguid; 11105367Sahrens }; 11115367Sahrens 11125367Sahrens static int 11135367Sahrens recv_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 11145367Sahrens { 11155367Sahrens dsl_dataset_t *ds = arg1; 11165367Sahrens struct recvendsyncarg *resa = arg2; 11175367Sahrens 11185367Sahrens return (dsl_dataset_snapshot_check(ds, resa->tosnap, tx)); 11195367Sahrens } 11205367Sahrens 11215367Sahrens static void 11225367Sahrens recv_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 11235326Sek110237 { 11245367Sahrens dsl_dataset_t *ds = arg1; 11255367Sahrens struct recvendsyncarg *resa = arg2; 11265367Sahrens 11275367Sahrens dsl_dataset_snapshot_sync(ds, resa->tosnap, cr, tx); 11285367Sahrens 11295367Sahrens /* set snapshot's creation time and guid */ 11305367Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 11315367Sahrens ds->ds_prev->ds_phys->ds_creation_time = resa->creation_time; 11325367Sahrens ds->ds_prev->ds_phys->ds_guid = resa->toguid; 11335367Sahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 11345367Sahrens 11355367Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 11365367Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 11375367Sahrens } 11385367Sahrens 11395367Sahrens int 11405367Sahrens dmu_recv_end(dmu_recv_cookie_t *drc) 11415367Sahrens { 11426689Smaybee struct recvendsyncarg resa; 11436689Smaybee dsl_dataset_t *ds = drc->drc_logical_ds; 11446689Smaybee int err; 11455367Sahrens 11465367Sahrens /* 11475367Sahrens * XXX hack; seems the ds is still dirty and 11486689Smaybee * dsl_pool_zil_clean() expects it to have a ds_user_ptr 11496689Smaybee * (and zil), but clone_swap() can close it. 11505367Sahrens */ 11516689Smaybee txg_wait_synced(ds->ds_dir->dd_pool, 0); 11525326Sek110237 11536689Smaybee if (ds != drc->drc_real_ds) { 11546689Smaybee /* we are doing an online recv */ 11556689Smaybee if (dsl_dataset_tryown(ds, FALSE, dmu_recv_tag)) { 11566689Smaybee err = dsl_dataset_clone_swap(drc->drc_real_ds, ds, 11576689Smaybee drc->drc_force); 11586689Smaybee if (err) 11596689Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 11606689Smaybee } else { 11616689Smaybee err = EBUSY; 11626689Smaybee dsl_dataset_rele(ds, dmu_recv_tag); 11636689Smaybee } 11646689Smaybee /* dsl_dataset_destroy() will disown the ds */ 11656689Smaybee (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag); 11666689Smaybee if (err) 11676689Smaybee return (err); 11685367Sahrens } 11695367Sahrens 11706689Smaybee resa.creation_time = drc->drc_drrb->drr_creation_time; 11716689Smaybee resa.toguid = drc->drc_drrb->drr_toguid; 11726689Smaybee resa.tosnap = drc->drc_tosnap; 11736689Smaybee 11746689Smaybee err = dsl_sync_task_do(ds->ds_dir->dd_pool, 11756689Smaybee recv_end_check, recv_end_sync, ds, &resa, 3); 11766689Smaybee if (err) { 11776689Smaybee if (drc->drc_newfs) { 11786689Smaybee ASSERT(ds == drc->drc_real_ds); 11796689Smaybee (void) dsl_dataset_destroy(ds, dmu_recv_tag); 11806689Smaybee return (err); 11815367Sahrens } else { 11826689Smaybee (void) dsl_dataset_rollback(ds, DMU_OST_NONE); 11835367Sahrens } 11845367Sahrens } 11855367Sahrens 11866689Smaybee /* release the hold from dmu_recv_begin */ 11876689Smaybee dsl_dataset_disown(ds, dmu_recv_tag); 11885326Sek110237 return (err); 11895326Sek110237 } 1190