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 /* 223547Smaybee * Copyright 2007 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 442743Sahrens struct backuparg { 452743Sahrens dmu_replay_record_t *drr; 462743Sahrens vnode_t *vp; 472743Sahrens objset_t *os; 482743Sahrens zio_cksum_t zc; 492743Sahrens int err; 502743Sahrens }; 512743Sahrens 522743Sahrens static int 532743Sahrens dump_bytes(struct backuparg *ba, void *buf, int len) 542743Sahrens { 552743Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 562743Sahrens ASSERT3U(len % 8, ==, 0); 572743Sahrens 582743Sahrens fletcher_4_incremental_native(buf, len, &ba->zc); 592743Sahrens ba->err = vn_rdwr(UIO_WRITE, ba->vp, 602743Sahrens (caddr_t)buf, len, 612743Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 622743Sahrens return (ba->err); 632743Sahrens } 642743Sahrens 652743Sahrens static int 662743Sahrens dump_free(struct backuparg *ba, uint64_t object, uint64_t offset, 672743Sahrens uint64_t length) 682743Sahrens { 692743Sahrens /* write a FREE record */ 702743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 712743Sahrens ba->drr->drr_type = DRR_FREE; 722743Sahrens ba->drr->drr_u.drr_free.drr_object = object; 732743Sahrens ba->drr->drr_u.drr_free.drr_offset = offset; 742743Sahrens ba->drr->drr_u.drr_free.drr_length = length; 752743Sahrens 762743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 772743Sahrens return (EINTR); 782743Sahrens return (0); 792743Sahrens } 802743Sahrens 812743Sahrens static int 822743Sahrens dump_data(struct backuparg *ba, dmu_object_type_t type, 832743Sahrens uint64_t object, uint64_t offset, int blksz, void *data) 842743Sahrens { 852743Sahrens /* write a DATA record */ 862743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 872743Sahrens ba->drr->drr_type = DRR_WRITE; 882743Sahrens ba->drr->drr_u.drr_write.drr_object = object; 892743Sahrens ba->drr->drr_u.drr_write.drr_type = type; 902743Sahrens ba->drr->drr_u.drr_write.drr_offset = offset; 912743Sahrens ba->drr->drr_u.drr_write.drr_length = blksz; 922743Sahrens 932743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 942743Sahrens return (EINTR); 952743Sahrens if (dump_bytes(ba, data, blksz)) 962743Sahrens return (EINTR); 972743Sahrens return (0); 982743Sahrens } 992743Sahrens 1002743Sahrens static int 1012743Sahrens dump_freeobjects(struct backuparg *ba, uint64_t firstobj, uint64_t numobjs) 1022743Sahrens { 1032743Sahrens /* write a FREEOBJECTS record */ 1042743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 1052743Sahrens ba->drr->drr_type = DRR_FREEOBJECTS; 1062743Sahrens ba->drr->drr_u.drr_freeobjects.drr_firstobj = firstobj; 1072743Sahrens ba->drr->drr_u.drr_freeobjects.drr_numobjs = numobjs; 1082743Sahrens 1092743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 1102743Sahrens return (EINTR); 1112743Sahrens return (0); 1122743Sahrens } 1132743Sahrens 1142743Sahrens static int 1152743Sahrens dump_dnode(struct backuparg *ba, uint64_t object, dnode_phys_t *dnp) 1162743Sahrens { 1172743Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 1182743Sahrens return (dump_freeobjects(ba, object, 1)); 1192743Sahrens 1202743Sahrens /* write an OBJECT record */ 1212743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 1222743Sahrens ba->drr->drr_type = DRR_OBJECT; 1232743Sahrens ba->drr->drr_u.drr_object.drr_object = object; 1242743Sahrens ba->drr->drr_u.drr_object.drr_type = dnp->dn_type; 1252743Sahrens ba->drr->drr_u.drr_object.drr_bonustype = dnp->dn_bonustype; 1262743Sahrens ba->drr->drr_u.drr_object.drr_blksz = 1272743Sahrens dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 1282743Sahrens ba->drr->drr_u.drr_object.drr_bonuslen = dnp->dn_bonuslen; 1292743Sahrens ba->drr->drr_u.drr_object.drr_checksum = dnp->dn_checksum; 1302743Sahrens ba->drr->drr_u.drr_object.drr_compress = dnp->dn_compress; 1312743Sahrens 1322743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 1332743Sahrens return (EINTR); 1342743Sahrens 1352743Sahrens if (dump_bytes(ba, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8))) 1362743Sahrens return (EINTR); 1372743Sahrens 1382743Sahrens /* free anything past the end of the file */ 1392743Sahrens if (dump_free(ba, object, (dnp->dn_maxblkid + 1) * 1402743Sahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 1412743Sahrens return (EINTR); 1422743Sahrens if (ba->err) 1432743Sahrens return (EINTR); 1442743Sahrens return (0); 1452743Sahrens } 1462743Sahrens 1472743Sahrens #define BP_SPAN(dnp, level) \ 1482743Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 1492743Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 1502743Sahrens 1512743Sahrens static int 1522743Sahrens backup_cb(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 1532743Sahrens { 1542743Sahrens struct backuparg *ba = arg; 1552743Sahrens uint64_t object = bc->bc_bookmark.zb_object; 1562743Sahrens int level = bc->bc_bookmark.zb_level; 1572743Sahrens uint64_t blkid = bc->bc_bookmark.zb_blkid; 1582743Sahrens blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL; 1592743Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 1602743Sahrens void *data = bc->bc_data; 1612743Sahrens int err = 0; 1622743Sahrens 1632743Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 1642743Sahrens return (EINTR); 1652743Sahrens 1662743Sahrens ASSERT(data || bp == NULL); 1672743Sahrens 1682743Sahrens if (bp == NULL && object == 0) { 1692743Sahrens uint64_t span = BP_SPAN(bc->bc_dnode, level); 1702743Sahrens uint64_t dnobj = (blkid * span) >> DNODE_SHIFT; 1712743Sahrens err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT); 1722743Sahrens } else if (bp == NULL) { 1732743Sahrens uint64_t span = BP_SPAN(bc->bc_dnode, level); 1742743Sahrens err = dump_free(ba, object, blkid * span, span); 1752743Sahrens } else if (data && level == 0 && type == DMU_OT_DNODE) { 1762743Sahrens dnode_phys_t *blk = data; 1772743Sahrens int i; 1782743Sahrens int blksz = BP_GET_LSIZE(bp); 1792743Sahrens 1802743Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 1812743Sahrens uint64_t dnobj = 1822743Sahrens (blkid << (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 1832743Sahrens err = dump_dnode(ba, dnobj, blk+i); 1842743Sahrens if (err) 1852743Sahrens break; 1862743Sahrens } 1872743Sahrens } else if (level == 0 && 1882743Sahrens type != DMU_OT_DNODE && type != DMU_OT_OBJSET) { 1892743Sahrens int blksz = BP_GET_LSIZE(bp); 1902743Sahrens if (data == NULL) { 1912743Sahrens uint32_t aflags = ARC_WAIT; 1922743Sahrens arc_buf_t *abuf; 1932743Sahrens zbookmark_t zb; 1942743Sahrens 1952743Sahrens zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object; 1962743Sahrens zb.zb_object = object; 1972743Sahrens zb.zb_level = level; 1982743Sahrens zb.zb_blkid = blkid; 1992743Sahrens (void) arc_read(NULL, spa, bp, 2002743Sahrens dmu_ot[type].ot_byteswap, arc_getbuf_func, &abuf, 2012743Sahrens ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_MUSTSUCCEED, 2022743Sahrens &aflags, &zb); 2032743Sahrens 2042743Sahrens if (abuf) { 2052743Sahrens err = dump_data(ba, type, object, blkid * blksz, 2062743Sahrens blksz, abuf->b_data); 2072743Sahrens (void) arc_buf_remove_ref(abuf, &abuf); 2082743Sahrens } 2092743Sahrens } else { 2102743Sahrens err = dump_data(ba, type, object, blkid * blksz, 2112743Sahrens blksz, data); 2122743Sahrens } 2132743Sahrens } 2142743Sahrens 2152743Sahrens ASSERT(err == 0 || err == EINTR); 2162743Sahrens return (err); 2172743Sahrens } 2182743Sahrens 2192743Sahrens int 2202743Sahrens dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, vnode_t *vp) 2212743Sahrens { 2222743Sahrens dsl_dataset_t *ds = tosnap->os->os_dsl_dataset; 2232743Sahrens dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL; 2242743Sahrens dmu_replay_record_t *drr; 2252743Sahrens struct backuparg ba; 2262743Sahrens int err; 2272743Sahrens 2282743Sahrens /* tosnap must be a snapshot */ 2292743Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 2302743Sahrens return (EINVAL); 2312743Sahrens 2322743Sahrens /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 2332743Sahrens if (fromds && (ds->ds_dir != fromds->ds_dir || 2342743Sahrens fromds->ds_phys->ds_creation_txg >= 2352743Sahrens ds->ds_phys->ds_creation_txg)) 2362743Sahrens return (EXDEV); 2372743Sahrens 2382743Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 2392743Sahrens drr->drr_type = DRR_BEGIN; 2402743Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 2412743Sahrens drr->drr_u.drr_begin.drr_version = DMU_BACKUP_VERSION; 2422743Sahrens drr->drr_u.drr_begin.drr_creation_time = 2432743Sahrens ds->ds_phys->ds_creation_time; 2442743Sahrens drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type; 2452743Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 2462743Sahrens if (fromds) 2472743Sahrens drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 2482743Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 2492743Sahrens 2502743Sahrens ba.drr = drr; 2512743Sahrens ba.vp = vp; 2522743Sahrens ba.os = tosnap; 2532743Sahrens ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); 2542743Sahrens 2552743Sahrens if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 2562743Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 2572743Sahrens return (ba.err); 2582743Sahrens } 2592743Sahrens 2602743Sahrens err = traverse_dsl_dataset(ds, 2612743Sahrens fromds ? fromds->ds_phys->ds_creation_txg : 0, 2622743Sahrens ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK, 2632743Sahrens backup_cb, &ba); 2642743Sahrens 2652743Sahrens if (err) { 2662743Sahrens if (err == EINTR && ba.err) 2672743Sahrens err = ba.err; 2683655Sgw25295 kmem_free(drr, sizeof (dmu_replay_record_t)); 2692743Sahrens return (err); 2702743Sahrens } 2712743Sahrens 2722743Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 2732743Sahrens drr->drr_type = DRR_END; 2742743Sahrens drr->drr_u.drr_end.drr_checksum = ba.zc; 2752743Sahrens 2763655Sgw25295 if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 2773655Sgw25295 kmem_free(drr, sizeof (dmu_replay_record_t)); 2782743Sahrens return (ba.err); 2793655Sgw25295 } 2802743Sahrens 2812743Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 2822743Sahrens 2832743Sahrens return (0); 2842743Sahrens } 2852743Sahrens 2862743Sahrens struct restorearg { 2872743Sahrens int err; 2882743Sahrens int byteswap; 2892743Sahrens vnode_t *vp; 2902743Sahrens char *buf; 2912743Sahrens uint64_t voff; 2922743Sahrens int buflen; /* number of valid bytes in buf */ 2932743Sahrens int bufoff; /* next offset to read */ 2942743Sahrens int bufsize; /* amount of memory allocated for buf */ 2952743Sahrens zio_cksum_t zc; 2962743Sahrens }; 2972743Sahrens 2982743Sahrens static int 299*5326Sek110237 replay_incremental_check(dsl_dataset_t *ds, struct drr_begin *drrb) 3002743Sahrens { 3012743Sahrens const char *snapname; 3022743Sahrens int err; 3032743Sahrens uint64_t val; 3042743Sahrens 3052743Sahrens /* must already be a snapshot of this fs */ 3062743Sahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 3072743Sahrens return (ENODEV); 3082743Sahrens 3092743Sahrens /* most recent snapshot must match fromguid */ 3102743Sahrens if (ds->ds_prev->ds_phys->ds_guid != drrb->drr_fromguid) 3112743Sahrens return (ENODEV); 3122743Sahrens 3132743Sahrens /* new snapshot name must not exist */ 3142743Sahrens snapname = strrchr(drrb->drr_toname, '@'); 3152743Sahrens if (snapname == NULL) 3162743Sahrens return (EEXIST); 3172743Sahrens 3182743Sahrens snapname++; 3192743Sahrens err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 3202743Sahrens ds->ds_phys->ds_snapnames_zapobj, snapname, 8, 1, &val); 3212743Sahrens if (err == 0) 322*5326Sek110237 return (EEXIST); 3232743Sahrens if (err != ENOENT) 324*5326Sek110237 return (err); 3252743Sahrens 3262743Sahrens return (0); 3272743Sahrens } 3282743Sahrens 3292743Sahrens /* ARGSUSED */ 330*5326Sek110237 static int 331*5326Sek110237 replay_offline_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 332*5326Sek110237 { 333*5326Sek110237 dsl_dataset_t *ds = arg1; 334*5326Sek110237 struct drr_begin *drrb = arg2; 335*5326Sek110237 336*5326Sek110237 /* must not have any changes since most recent snapshot */ 337*5326Sek110237 if (dsl_dataset_modified_since_lastsnap(ds)) 338*5326Sek110237 return (ETXTBSY); 339*5326Sek110237 340*5326Sek110237 return (replay_incremental_check(ds, drrb)); 341*5326Sek110237 } 342*5326Sek110237 343*5326Sek110237 /* ARGSUSED */ 3442743Sahrens static void 345*5326Sek110237 replay_offline_incremental_sync(void *arg1, void *arg2, cred_t *cr, 346*5326Sek110237 dmu_tx_t *tx) 3472743Sahrens { 3482743Sahrens dsl_dataset_t *ds = arg1; 3492743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 3502743Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 3514543Smarks 3524543Smarks spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 3534543Smarks ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld", 3544543Smarks ds->ds_phys->ds_dir_obj); 3552743Sahrens } 3562743Sahrens 3572743Sahrens /* ARGSUSED */ 3582743Sahrens static int 3592743Sahrens replay_full_check(void *arg1, void *arg2, dmu_tx_t *tx) 3602743Sahrens { 3612743Sahrens dsl_dir_t *dd = arg1; 3622743Sahrens struct drr_begin *drrb = arg2; 3632743Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 3642743Sahrens char *cp; 3652743Sahrens uint64_t val; 3662743Sahrens int err; 3672743Sahrens 3682743Sahrens cp = strchr(drrb->drr_toname, '@'); 3692743Sahrens *cp = '\0'; 3702743Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 3712743Sahrens strrchr(drrb->drr_toname, '/') + 1, 3722743Sahrens sizeof (uint64_t), 1, &val); 3732743Sahrens *cp = '@'; 3742743Sahrens 3752743Sahrens if (err != ENOENT) 3762743Sahrens return (err ? err : EEXIST); 3772743Sahrens 3782743Sahrens return (0); 3792743Sahrens } 3802743Sahrens 3812743Sahrens static void 3824543Smarks replay_full_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3832743Sahrens { 3842743Sahrens dsl_dir_t *dd = arg1; 3852743Sahrens struct drr_begin *drrb = arg2; 3862743Sahrens char *cp; 3872743Sahrens dsl_dataset_t *ds; 3882743Sahrens uint64_t dsobj; 3892743Sahrens 3902743Sahrens cp = strchr(drrb->drr_toname, '@'); 3912743Sahrens *cp = '\0'; 3922743Sahrens dsobj = dsl_dataset_create_sync(dd, strrchr(drrb->drr_toname, '/') + 1, 3932743Sahrens NULL, tx); 3942743Sahrens 3952743Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 3962743Sahrens DS_MODE_EXCLUSIVE, FTAG, &ds)); 3972743Sahrens 3982743Sahrens (void) dmu_objset_create_impl(dsl_dataset_get_spa(ds), 3993547Smaybee ds, &ds->ds_phys->ds_bp, drrb->drr_type, tx); 4002743Sahrens 4012743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 4022743Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 4032743Sahrens 4044543Smarks spa_history_internal_log(LOG_DS_REPLAY_FULL_SYNC, 4054543Smarks ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld", 4064543Smarks ds->ds_phys->ds_dir_obj); 4074543Smarks 4084543Smarks *cp = '@'; 4094543Smarks 4102743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 4112743Sahrens } 4122743Sahrens 413*5326Sek110237 struct onlineincarg { 414*5326Sek110237 dsl_dir_t *dd; 415*5326Sek110237 dsl_dataset_t *ohds; 416*5326Sek110237 boolean_t force; 417*5326Sek110237 const char *cosname; 418*5326Sek110237 }; 419*5326Sek110237 420*5326Sek110237 /* ARGSUSED */ 421*5326Sek110237 static int 422*5326Sek110237 replay_online_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 423*5326Sek110237 { 424*5326Sek110237 struct onlineincarg *oia = arg1; 425*5326Sek110237 426*5326Sek110237 if (dsl_dataset_modified_since_lastsnap(oia->ohds) && !oia->force) 427*5326Sek110237 return (ETXTBSY); 428*5326Sek110237 429*5326Sek110237 return (replay_incremental_check(oia->ohds, arg2)); 430*5326Sek110237 } 431*5326Sek110237 432*5326Sek110237 /* ARGSUSED */ 433*5326Sek110237 static void 434*5326Sek110237 replay_online_incremental_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 435*5326Sek110237 { 436*5326Sek110237 struct onlineincarg *oia = arg1; 437*5326Sek110237 dsl_dataset_t *ohds = oia->ohds; 438*5326Sek110237 dsl_dir_t *dd = oia->dd; 439*5326Sek110237 dsl_dataset_t *ods, *ds; 440*5326Sek110237 uint64_t dsobj; 441*5326Sek110237 442*5326Sek110237 VERIFY(0 == dsl_dataset_open_obj(ohds->ds_dir->dd_pool, 443*5326Sek110237 ohds->ds_phys->ds_prev_snap_obj, NULL, 444*5326Sek110237 DS_MODE_STANDARD, FTAG, &ods)); 445*5326Sek110237 446*5326Sek110237 dsobj = dsl_dataset_create_sync(dd, strrchr(oia->cosname, '/') + 1, 447*5326Sek110237 ods, tx); 448*5326Sek110237 449*5326Sek110237 /* open the temporary clone */ 450*5326Sek110237 VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 451*5326Sek110237 DS_MODE_EXCLUSIVE, FTAG, &ds)); 452*5326Sek110237 453*5326Sek110237 dmu_buf_will_dirty(ds->ds_dbuf, tx); 454*5326Sek110237 ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 455*5326Sek110237 456*5326Sek110237 spa_history_internal_log(LOG_DS_REPLAY_INC_SYNC, 457*5326Sek110237 ds->ds_dir->dd_pool->dp_spa, tx, cr, "dataset = %lld", 458*5326Sek110237 ds->ds_phys->ds_dir_obj); 459*5326Sek110237 460*5326Sek110237 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 461*5326Sek110237 dsl_dataset_close(ods, DS_MODE_STANDARD, FTAG); 462*5326Sek110237 } 463*5326Sek110237 4642743Sahrens static int 4652743Sahrens replay_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 4662743Sahrens { 4672743Sahrens objset_t *os = arg1; 4682743Sahrens struct drr_begin *drrb = arg2; 4692743Sahrens char *snapname; 4702743Sahrens 4712743Sahrens /* XXX verify that drr_toname is in dd */ 4722743Sahrens 4732743Sahrens snapname = strchr(drrb->drr_toname, '@'); 4742743Sahrens if (snapname == NULL) 4752743Sahrens return (EINVAL); 4762743Sahrens snapname++; 4772743Sahrens 4782743Sahrens return (dsl_dataset_snapshot_check(os, snapname, tx)); 4792743Sahrens } 4802743Sahrens 4812743Sahrens static void 4824543Smarks replay_end_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 4832743Sahrens { 4842743Sahrens objset_t *os = arg1; 4852743Sahrens struct drr_begin *drrb = arg2; 4862743Sahrens char *snapname; 4872743Sahrens dsl_dataset_t *ds, *hds; 4882743Sahrens 4892743Sahrens snapname = strchr(drrb->drr_toname, '@') + 1; 4902743Sahrens 4914543Smarks dsl_dataset_snapshot_sync(os, snapname, cr, tx); 4922743Sahrens 4932743Sahrens /* set snapshot's creation time and guid */ 4942743Sahrens hds = os->os->os_dsl_dataset; 4952743Sahrens VERIFY(0 == dsl_dataset_open_obj(hds->ds_dir->dd_pool, 4962743Sahrens hds->ds_phys->ds_prev_snap_obj, NULL, 4972743Sahrens DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 4982743Sahrens FTAG, &ds)); 4992743Sahrens 5002743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 5012743Sahrens ds->ds_phys->ds_creation_time = drrb->drr_creation_time; 5022743Sahrens ds->ds_phys->ds_guid = drrb->drr_toguid; 5032743Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 5042743Sahrens 5054543Smarks /* log the end of the receive */ 5064543Smarks spa_history_internal_log(LOG_DS_RECEIVE, ds->ds_dir->dd_pool->dp_spa, 5074543Smarks tx, cr, "dataset = %llu", ds->ds_phys->ds_dir_obj); 5084543Smarks 5092743Sahrens dsl_dataset_close(ds, DS_MODE_PRIMARY, FTAG); 5102743Sahrens 5112743Sahrens dmu_buf_will_dirty(hds->ds_dbuf, tx); 5122743Sahrens hds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 5132743Sahrens } 5142743Sahrens 5152743Sahrens static void * 5162743Sahrens restore_read(struct restorearg *ra, int len) 5172743Sahrens { 5182743Sahrens void *rv; 5192743Sahrens 5202743Sahrens /* some things will require 8-byte alignment, so everything must */ 5212743Sahrens ASSERT3U(len % 8, ==, 0); 5222743Sahrens 5232743Sahrens while (ra->buflen - ra->bufoff < len) { 5242743Sahrens ssize_t resid; 5252743Sahrens int leftover = ra->buflen - ra->bufoff; 5262743Sahrens 5272743Sahrens (void) memmove(ra->buf, ra->buf + ra->bufoff, leftover); 5282743Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 5292743Sahrens (caddr_t)ra->buf + leftover, ra->bufsize - leftover, 5302743Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 5312743Sahrens RLIM64_INFINITY, CRED(), &resid); 5322743Sahrens 5332743Sahrens ra->voff += ra->bufsize - leftover - resid; 5342743Sahrens ra->buflen = ra->bufsize - resid; 5352743Sahrens ra->bufoff = 0; 5362743Sahrens if (resid == ra->bufsize - leftover) 5372743Sahrens ra->err = EINVAL; 5382743Sahrens if (ra->err) 5392743Sahrens return (NULL); 5402743Sahrens /* Could compute checksum here? */ 5412743Sahrens } 5422743Sahrens 5432743Sahrens ASSERT3U(ra->bufoff % 8, ==, 0); 5442743Sahrens ASSERT3U(ra->buflen - ra->bufoff, >=, len); 5452743Sahrens rv = ra->buf + ra->bufoff; 5462743Sahrens ra->bufoff += len; 5472743Sahrens if (ra->byteswap) 5482743Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->zc); 5492743Sahrens else 5502743Sahrens fletcher_4_incremental_native(rv, len, &ra->zc); 5512743Sahrens return (rv); 5522743Sahrens } 5532743Sahrens 5542743Sahrens static void 5552743Sahrens backup_byteswap(dmu_replay_record_t *drr) 5562743Sahrens { 5572743Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 5582743Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 5592743Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 5602743Sahrens switch (drr->drr_type) { 5612743Sahrens case DRR_BEGIN: 5622743Sahrens DO64(drr_begin.drr_magic); 5632743Sahrens DO64(drr_begin.drr_version); 5642743Sahrens DO64(drr_begin.drr_creation_time); 5652743Sahrens DO32(drr_begin.drr_type); 5662743Sahrens DO64(drr_begin.drr_toguid); 5672743Sahrens DO64(drr_begin.drr_fromguid); 5682743Sahrens break; 5692743Sahrens case DRR_OBJECT: 5702743Sahrens DO64(drr_object.drr_object); 5712743Sahrens /* DO64(drr_object.drr_allocation_txg); */ 5722743Sahrens DO32(drr_object.drr_type); 5732743Sahrens DO32(drr_object.drr_bonustype); 5742743Sahrens DO32(drr_object.drr_blksz); 5752743Sahrens DO32(drr_object.drr_bonuslen); 5762743Sahrens break; 5772743Sahrens case DRR_FREEOBJECTS: 5782743Sahrens DO64(drr_freeobjects.drr_firstobj); 5792743Sahrens DO64(drr_freeobjects.drr_numobjs); 5802743Sahrens break; 5812743Sahrens case DRR_WRITE: 5822743Sahrens DO64(drr_write.drr_object); 5832743Sahrens DO32(drr_write.drr_type); 5842743Sahrens DO64(drr_write.drr_offset); 5852743Sahrens DO64(drr_write.drr_length); 5862743Sahrens break; 5872743Sahrens case DRR_FREE: 5882743Sahrens DO64(drr_free.drr_object); 5892743Sahrens DO64(drr_free.drr_offset); 5902743Sahrens DO64(drr_free.drr_length); 5912743Sahrens break; 5922743Sahrens case DRR_END: 5932743Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 5942743Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 5952743Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 5962743Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 5972743Sahrens break; 5982743Sahrens } 5992743Sahrens #undef DO64 6002743Sahrens #undef DO32 6012743Sahrens } 6022743Sahrens 6032743Sahrens static int 6042743Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 6052743Sahrens { 6062743Sahrens int err; 6072743Sahrens dmu_tx_t *tx; 6082743Sahrens 6092743Sahrens err = dmu_object_info(os, drro->drr_object, NULL); 6102743Sahrens 6112743Sahrens if (err != 0 && err != ENOENT) 6122743Sahrens return (EINVAL); 6132743Sahrens 6142743Sahrens if (drro->drr_type == DMU_OT_NONE || 6152743Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 6162743Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 6172743Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 6182743Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 6192743Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 6202743Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 6212743Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 6222743Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 6232743Sahrens return (EINVAL); 6242743Sahrens } 6252743Sahrens 6262743Sahrens tx = dmu_tx_create(os); 6272743Sahrens 6282743Sahrens if (err == ENOENT) { 6292743Sahrens /* currently free, want to be allocated */ 6302743Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 6312743Sahrens dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 1); 6322743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 6332743Sahrens if (err) { 6342743Sahrens dmu_tx_abort(tx); 6352743Sahrens return (err); 6362743Sahrens } 6372743Sahrens err = dmu_object_claim(os, drro->drr_object, 6382743Sahrens drro->drr_type, drro->drr_blksz, 6392743Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 6402743Sahrens } else { 6412743Sahrens /* currently allocated, want to be allocated */ 6422743Sahrens dmu_tx_hold_bonus(tx, drro->drr_object); 6432743Sahrens /* 6442743Sahrens * We may change blocksize, so need to 6452743Sahrens * hold_write 6462743Sahrens */ 6472743Sahrens dmu_tx_hold_write(tx, drro->drr_object, 0, 1); 6482743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 6492743Sahrens if (err) { 6502743Sahrens dmu_tx_abort(tx); 6512743Sahrens return (err); 6522743Sahrens } 6532743Sahrens 6542743Sahrens err = dmu_object_reclaim(os, drro->drr_object, 6552743Sahrens drro->drr_type, drro->drr_blksz, 6562743Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 6572743Sahrens } 6582743Sahrens if (err) { 6592743Sahrens dmu_tx_commit(tx); 6602743Sahrens return (EINVAL); 6612743Sahrens } 6622743Sahrens 6632743Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 6642743Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 6652743Sahrens 6662743Sahrens if (drro->drr_bonuslen) { 6672743Sahrens dmu_buf_t *db; 6682743Sahrens void *data; 6692743Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 6702743Sahrens dmu_buf_will_dirty(db, tx); 6712743Sahrens 6724944Smaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 6734944Smaybee data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 6742743Sahrens if (data == NULL) { 6752743Sahrens dmu_tx_commit(tx); 6762743Sahrens return (ra->err); 6772743Sahrens } 6784944Smaybee bcopy(data, db->db_data, drro->drr_bonuslen); 6792743Sahrens if (ra->byteswap) { 6802743Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 6812743Sahrens drro->drr_bonuslen); 6822743Sahrens } 6832743Sahrens dmu_buf_rele(db, FTAG); 6842743Sahrens } 6852743Sahrens dmu_tx_commit(tx); 6862743Sahrens return (0); 6872743Sahrens } 6882743Sahrens 6892743Sahrens /* ARGSUSED */ 6902743Sahrens static int 6912743Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 6922743Sahrens struct drr_freeobjects *drrfo) 6932743Sahrens { 6942743Sahrens uint64_t obj; 6952743Sahrens 6962743Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 6972743Sahrens return (EINVAL); 6982743Sahrens 6992743Sahrens for (obj = drrfo->drr_firstobj; 7003087Sahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 7013087Sahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 7022743Sahrens dmu_tx_t *tx; 7032743Sahrens int err; 7042743Sahrens 7052743Sahrens if (dmu_object_info(os, obj, NULL) != 0) 7062743Sahrens continue; 7072743Sahrens 7082743Sahrens tx = dmu_tx_create(os); 7092743Sahrens dmu_tx_hold_bonus(tx, obj); 7102743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 7112743Sahrens if (err) { 7122743Sahrens dmu_tx_abort(tx); 7132743Sahrens return (err); 7142743Sahrens } 7152743Sahrens err = dmu_object_free(os, obj, tx); 7162743Sahrens dmu_tx_commit(tx); 7172743Sahrens if (err && err != ENOENT) 7182743Sahrens return (EINVAL); 7192743Sahrens } 7202743Sahrens return (0); 7212743Sahrens } 7222743Sahrens 7232743Sahrens static int 7242743Sahrens restore_write(struct restorearg *ra, objset_t *os, 7252743Sahrens struct drr_write *drrw) 7262743Sahrens { 7272743Sahrens dmu_tx_t *tx; 7282743Sahrens void *data; 7292743Sahrens int err; 7302743Sahrens 7312743Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 7322743Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 7332743Sahrens return (EINVAL); 7342743Sahrens 7352743Sahrens data = restore_read(ra, drrw->drr_length); 7362743Sahrens if (data == NULL) 7372743Sahrens return (ra->err); 7382743Sahrens 7392743Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 7402743Sahrens return (EINVAL); 7412743Sahrens 7422743Sahrens tx = dmu_tx_create(os); 7432743Sahrens 7442743Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 7452743Sahrens drrw->drr_offset, drrw->drr_length); 7462743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 7472743Sahrens if (err) { 7482743Sahrens dmu_tx_abort(tx); 7492743Sahrens return (err); 7502743Sahrens } 7512743Sahrens if (ra->byteswap) 7522743Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 7532743Sahrens dmu_write(os, drrw->drr_object, 7542743Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 7552743Sahrens dmu_tx_commit(tx); 7562743Sahrens return (0); 7572743Sahrens } 7582743Sahrens 7592743Sahrens /* ARGSUSED */ 7602743Sahrens static int 7612743Sahrens restore_free(struct restorearg *ra, objset_t *os, 7622743Sahrens struct drr_free *drrf) 7632743Sahrens { 7642743Sahrens dmu_tx_t *tx; 7652743Sahrens int err; 7662743Sahrens 7672743Sahrens if (drrf->drr_length != -1ULL && 7682743Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 7692743Sahrens return (EINVAL); 7702743Sahrens 7712743Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 7722743Sahrens return (EINVAL); 7732743Sahrens 7742743Sahrens tx = dmu_tx_create(os); 7752743Sahrens 7762743Sahrens dmu_tx_hold_free(tx, drrf->drr_object, 7772743Sahrens drrf->drr_offset, drrf->drr_length); 7782743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 7792743Sahrens if (err) { 7802743Sahrens dmu_tx_abort(tx); 7812743Sahrens return (err); 7822743Sahrens } 7832743Sahrens err = dmu_free_range(os, drrf->drr_object, 7842743Sahrens drrf->drr_offset, drrf->drr_length, tx); 7852743Sahrens dmu_tx_commit(tx); 7862743Sahrens return (err); 7872743Sahrens } 7882743Sahrens 7892743Sahrens int 7902743Sahrens dmu_recvbackup(char *tosnap, struct drr_begin *drrb, uint64_t *sizep, 791*5326Sek110237 boolean_t force, boolean_t online, vnode_t *vp, uint64_t voffset, 792*5326Sek110237 char *cosname) 7932743Sahrens { 7942743Sahrens struct restorearg ra; 7952743Sahrens dmu_replay_record_t *drr; 7962743Sahrens char *cp; 7972743Sahrens objset_t *os = NULL; 7982743Sahrens zio_cksum_t pzc; 799*5326Sek110237 char *clonebuf = NULL; 800*5326Sek110237 size_t len; 8012743Sahrens 8022743Sahrens bzero(&ra, sizeof (ra)); 8032743Sahrens ra.vp = vp; 8042743Sahrens ra.voff = voffset; 8052743Sahrens ra.bufsize = 1<<20; 8062743Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 8072743Sahrens 8082743Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) { 8092743Sahrens ra.byteswap = FALSE; 8102743Sahrens } else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 8112743Sahrens ra.byteswap = TRUE; 8122743Sahrens } else { 8132743Sahrens ra.err = EINVAL; 8142743Sahrens goto out; 8152743Sahrens } 8162743Sahrens 8172743Sahrens /* 8182743Sahrens * NB: this assumes that struct drr_begin will be the largest in 8192743Sahrens * dmu_replay_record_t's drr_u, and thus we don't need to pad it 8202743Sahrens * with zeros to make it the same length as we wrote out. 8212743Sahrens */ 8222743Sahrens ((dmu_replay_record_t *)ra.buf)->drr_type = DRR_BEGIN; 8232743Sahrens ((dmu_replay_record_t *)ra.buf)->drr_pad = 0; 8242743Sahrens ((dmu_replay_record_t *)ra.buf)->drr_u.drr_begin = *drrb; 8252743Sahrens if (ra.byteswap) { 8262743Sahrens fletcher_4_incremental_byteswap(ra.buf, 8272743Sahrens sizeof (dmu_replay_record_t), &ra.zc); 8282743Sahrens } else { 8292743Sahrens fletcher_4_incremental_native(ra.buf, 8302743Sahrens sizeof (dmu_replay_record_t), &ra.zc); 8312743Sahrens } 8322743Sahrens (void) strcpy(drrb->drr_toname, tosnap); /* for the sync funcs */ 8332743Sahrens 8342743Sahrens if (ra.byteswap) { 8352743Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 8362743Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 8372743Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 8382743Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 8392743Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 8402743Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 8412743Sahrens } 8422743Sahrens 8432743Sahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 8442743Sahrens 8452743Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION || 8462743Sahrens drrb->drr_type >= DMU_OST_NUMTYPES || 8472743Sahrens strchr(drrb->drr_toname, '@') == NULL) { 8482743Sahrens ra.err = EINVAL; 8492743Sahrens goto out; 8502743Sahrens } 8512743Sahrens 8522743Sahrens /* 8532743Sahrens * Process the begin in syncing context. 8542743Sahrens */ 855*5326Sek110237 if (drrb->drr_fromguid && !online) { 856*5326Sek110237 /* offline incremental receive */ 857*5326Sek110237 8582743Sahrens dsl_dataset_t *ds = NULL; 8592743Sahrens 8602743Sahrens cp = strchr(tosnap, '@'); 8612743Sahrens *cp = '\0'; 8622743Sahrens ra.err = dsl_dataset_open(tosnap, DS_MODE_EXCLUSIVE, FTAG, &ds); 8632743Sahrens *cp = '@'; 8642743Sahrens if (ra.err) 8652743Sahrens goto out; 8662743Sahrens 8672743Sahrens /* 8682743Sahrens * Only do the rollback if the most recent snapshot 8692743Sahrens * matches the incremental source 8702743Sahrens */ 8712743Sahrens if (force) { 8722885Sahrens if (ds->ds_prev == NULL || 8732885Sahrens ds->ds_prev->ds_phys->ds_guid != 8742743Sahrens drrb->drr_fromguid) { 8752743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 8763655Sgw25295 kmem_free(ra.buf, ra.bufsize); 8772743Sahrens return (ENODEV); 8782743Sahrens } 8792743Sahrens (void) dsl_dataset_rollback(ds); 8802743Sahrens } 8812743Sahrens ra.err = dsl_sync_task_do(ds->ds_dir->dd_pool, 882*5326Sek110237 replay_offline_incremental_check, 883*5326Sek110237 replay_offline_incremental_sync, ds, drrb, 1); 8842743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 885*5326Sek110237 } else if (drrb->drr_fromguid && online) { 886*5326Sek110237 /* online incremental receive */ 887*5326Sek110237 888*5326Sek110237 const char *tail; 889*5326Sek110237 struct onlineincarg oia = { 0 }; 890*5326Sek110237 891*5326Sek110237 /* 892*5326Sek110237 * Get the dsl_dir for the parent of the 893*5326Sek110237 * temporary clone. 894*5326Sek110237 */ 895*5326Sek110237 cp = strchr(tosnap, '@'); 896*5326Sek110237 *cp = '\0'; 897*5326Sek110237 898*5326Sek110237 /* tmp clone is: tonsap + '/' + '%' + "snapX" */ 899*5326Sek110237 len = strlen(tosnap) + 2 + strlen(cp + 1) + 1; 900*5326Sek110237 clonebuf = kmem_alloc(len, KM_SLEEP); 901*5326Sek110237 (void) snprintf(clonebuf, len, "%s%c%c%s%c", 902*5326Sek110237 tosnap, '/', '%', cp + 1, '\0'); 903*5326Sek110237 ra.err = dsl_dir_open(tosnap, FTAG, &oia.dd, &tail); 904*5326Sek110237 *cp = '@'; 905*5326Sek110237 if (ra.err) 906*5326Sek110237 goto out; 907*5326Sek110237 908*5326Sek110237 /* open the dataset we are logically receiving into */ 909*5326Sek110237 *cp = '\0'; 910*5326Sek110237 ra.err = dsl_dataset_open(tosnap, DS_MODE_STANDARD, 911*5326Sek110237 FTAG, &oia.ohds); 912*5326Sek110237 *cp = '@'; 913*5326Sek110237 if (ra.err) { 914*5326Sek110237 dsl_dir_close(oia.dd, FTAG); 915*5326Sek110237 goto out; 916*5326Sek110237 } 917*5326Sek110237 918*5326Sek110237 oia.force = force; 919*5326Sek110237 oia.cosname = clonebuf; 920*5326Sek110237 ra.err = dsl_sync_task_do(oia.dd->dd_pool, 921*5326Sek110237 replay_online_incremental_check, 922*5326Sek110237 replay_online_incremental_sync, &oia, drrb, 5); 923*5326Sek110237 dsl_dataset_close(oia.ohds, DS_MODE_STANDARD, FTAG); 924*5326Sek110237 dsl_dir_close(oia.dd, FTAG); 9252743Sahrens } else { 9262743Sahrens /* full backup */ 927*5326Sek110237 9282743Sahrens dsl_dir_t *dd = NULL; 9292743Sahrens const char *tail; 9302743Sahrens 9312743Sahrens /* can't restore full backup into topmost fs, for now */ 9322743Sahrens if (strrchr(drrb->drr_toname, '/') == NULL) { 9332743Sahrens ra.err = EINVAL; 9342743Sahrens goto out; 9352743Sahrens } 9362743Sahrens 9372743Sahrens cp = strchr(tosnap, '@'); 9382743Sahrens *cp = '\0'; 9392743Sahrens ra.err = dsl_dir_open(tosnap, FTAG, &dd, &tail); 9402743Sahrens *cp = '@'; 9412743Sahrens if (ra.err) 9422743Sahrens goto out; 9432743Sahrens if (tail == NULL) { 9442743Sahrens ra.err = EEXIST; 9452743Sahrens goto out; 9462743Sahrens } 9472743Sahrens 9482743Sahrens ra.err = dsl_sync_task_do(dd->dd_pool, replay_full_check, 9492743Sahrens replay_full_sync, dd, drrb, 5); 9502743Sahrens dsl_dir_close(dd, FTAG); 9512743Sahrens } 9522743Sahrens if (ra.err) 9532743Sahrens goto out; 9542743Sahrens 9552743Sahrens /* 9562743Sahrens * Open the objset we are modifying. 9572743Sahrens */ 9582743Sahrens 9592743Sahrens cp = strchr(tosnap, '@'); 9602743Sahrens *cp = '\0'; 961*5326Sek110237 ra.err = dmu_objset_open(clonebuf == NULL ? tosnap : clonebuf, 962*5326Sek110237 DMU_OST_ANY, DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os); 9632743Sahrens *cp = '@'; 9642743Sahrens ASSERT3U(ra.err, ==, 0); 9652743Sahrens 9662743Sahrens /* 9672743Sahrens * Read records and process them. 9682743Sahrens */ 9692743Sahrens pzc = ra.zc; 9702743Sahrens while (ra.err == 0 && 9712743Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 9722743Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 9732743Sahrens ra.err = EINTR; 9742743Sahrens goto out; 9752743Sahrens } 9762743Sahrens 9772743Sahrens if (ra.byteswap) 9782743Sahrens backup_byteswap(drr); 9792743Sahrens 9802743Sahrens switch (drr->drr_type) { 9812743Sahrens case DRR_OBJECT: 9822743Sahrens { 9832743Sahrens /* 9842743Sahrens * We need to make a copy of the record header, 9852743Sahrens * because restore_{object,write} may need to 9862743Sahrens * restore_read(), which will invalidate drr. 9872743Sahrens */ 9882743Sahrens struct drr_object drro = drr->drr_u.drr_object; 9892743Sahrens ra.err = restore_object(&ra, os, &drro); 9902743Sahrens break; 9912743Sahrens } 9922743Sahrens case DRR_FREEOBJECTS: 9932743Sahrens { 9942743Sahrens struct drr_freeobjects drrfo = 9952743Sahrens drr->drr_u.drr_freeobjects; 9962743Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 9972743Sahrens break; 9982743Sahrens } 9992743Sahrens case DRR_WRITE: 10002743Sahrens { 10012743Sahrens struct drr_write drrw = drr->drr_u.drr_write; 10022743Sahrens ra.err = restore_write(&ra, os, &drrw); 10032743Sahrens break; 10042743Sahrens } 10052743Sahrens case DRR_FREE: 10062743Sahrens { 10072743Sahrens struct drr_free drrf = drr->drr_u.drr_free; 10082743Sahrens ra.err = restore_free(&ra, os, &drrf); 10092743Sahrens break; 10102743Sahrens } 10112743Sahrens case DRR_END: 10122743Sahrens { 10132743Sahrens struct drr_end drre = drr->drr_u.drr_end; 10142743Sahrens /* 10152743Sahrens * We compare against the *previous* checksum 10162743Sahrens * value, because the stored checksum is of 10172743Sahrens * everything before the DRR_END record. 10182743Sahrens */ 10192743Sahrens if (drre.drr_checksum.zc_word[0] != 0 && 10203093Sahrens !ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pzc)) { 10212743Sahrens ra.err = ECKSUM; 10222743Sahrens goto out; 10232743Sahrens } 10242743Sahrens 1025*5326Sek110237 if (clonebuf == NULL) { 1026*5326Sek110237 ra.err = dsl_sync_task_do(dmu_objset_ds(os)-> 1027*5326Sek110237 ds_dir->dd_pool, replay_end_check, 1028*5326Sek110237 replay_end_sync, os, drrb, 3); 1029*5326Sek110237 } 10302743Sahrens goto out; 10312743Sahrens } 10322743Sahrens default: 10332743Sahrens ra.err = EINVAL; 10342743Sahrens goto out; 10352743Sahrens } 10362743Sahrens pzc = ra.zc; 10372743Sahrens } 10382743Sahrens 10392743Sahrens out: 1040*5326Sek110237 if (os) { 1041*5326Sek110237 if (drrb->drr_fromguid && online && !ra.err) 1042*5326Sek110237 dmu_objset_name(os, cosname); 10432743Sahrens dmu_objset_close(os); 1044*5326Sek110237 } 10452743Sahrens 10462743Sahrens /* 10472743Sahrens * Make sure we don't rollback/destroy unless we actually 10482743Sahrens * processed the begin properly. 'os' will only be set if this 10492743Sahrens * is the case. 10502743Sahrens */ 10512743Sahrens if (ra.err && os && tosnap && strchr(tosnap, '@')) { 10522743Sahrens /* 10532743Sahrens * rollback or destroy what we created, so we don't 10542743Sahrens * leave it in the restoring state. 10552743Sahrens */ 10562743Sahrens dsl_dataset_t *ds; 10572743Sahrens int err; 10582743Sahrens 10592743Sahrens cp = strchr(tosnap, '@'); 10602743Sahrens *cp = '\0'; 1061*5326Sek110237 err = dsl_dataset_open(clonebuf == NULL ? tosnap : clonebuf, 10622743Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, 10632743Sahrens FTAG, &ds); 10642743Sahrens if (err == 0) { 10652743Sahrens txg_wait_synced(ds->ds_dir->dd_pool, 0); 10662743Sahrens if (drrb->drr_fromguid) { 1067*5326Sek110237 if (clonebuf != NULL) { 1068*5326Sek110237 /* 1069*5326Sek110237 * online incremental: destroy 1070*5326Sek110237 * the temporarily created clone. 1071*5326Sek110237 */ 1072*5326Sek110237 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, 1073*5326Sek110237 FTAG); 1074*5326Sek110237 (void) dmu_objset_destroy(clonebuf); 1075*5326Sek110237 } else { 1076*5326Sek110237 /* 1077*5326Sek110237 * offline incremental: rollback to 1078*5326Sek110237 * most recent snapshot. 1079*5326Sek110237 */ 1080*5326Sek110237 (void) dsl_dataset_rollback(ds); 1081*5326Sek110237 dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, 1082*5326Sek110237 FTAG); 1083*5326Sek110237 } 10842743Sahrens } else { 10852743Sahrens /* full: destroy whole fs */ 10862743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 10872743Sahrens (void) dsl_dataset_destroy(tosnap); 10882743Sahrens } 10892743Sahrens } 10902743Sahrens *cp = '@'; 10912743Sahrens } 10922743Sahrens 1093*5326Sek110237 if (clonebuf != NULL) 1094*5326Sek110237 kmem_free(clonebuf, len); 10952743Sahrens kmem_free(ra.buf, ra.bufsize); 10962743Sahrens if (sizep) 10972743Sahrens *sizep = ra.voff; 10982743Sahrens return (ra.err); 10992743Sahrens } 1100*5326Sek110237 1101*5326Sek110237 int 1102*5326Sek110237 dmu_replay_end_snapshot(char *name, struct drr_begin *drrb) 1103*5326Sek110237 { 1104*5326Sek110237 objset_t *os; 1105*5326Sek110237 int err; 1106*5326Sek110237 1107*5326Sek110237 err = dmu_objset_open(name, DMU_OST_ZFS, DS_MODE_STANDARD, &os); 1108*5326Sek110237 if (err) 1109*5326Sek110237 return (err); 1110*5326Sek110237 1111*5326Sek110237 err = dsl_sync_task_do(dmu_objset_ds(os)->ds_dir->dd_pool, 1112*5326Sek110237 replay_end_check, replay_end_sync, os, drrb, 3); 1113*5326Sek110237 dmu_objset_close(os); 1114*5326Sek110237 return (err); 1115*5326Sek110237 } 1116