1*2743Sahrens /* 2*2743Sahrens * CDDL HEADER START 3*2743Sahrens * 4*2743Sahrens * The contents of this file are subject to the terms of the 5*2743Sahrens * Common Development and Distribution License (the "License"). 6*2743Sahrens * You may not use this file except in compliance with the License. 7*2743Sahrens * 8*2743Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2743Sahrens * or http://www.opensolaris.org/os/licensing. 10*2743Sahrens * See the License for the specific language governing permissions 11*2743Sahrens * and limitations under the License. 12*2743Sahrens * 13*2743Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14*2743Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2743Sahrens * If applicable, add the following below this CDDL HEADER, with the 16*2743Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17*2743Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18*2743Sahrens * 19*2743Sahrens * CDDL HEADER END 20*2743Sahrens */ 21*2743Sahrens /* 22*2743Sahrens * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*2743Sahrens * Use is subject to license terms. 24*2743Sahrens */ 25*2743Sahrens 26*2743Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27*2743Sahrens 28*2743Sahrens #include <sys/dmu.h> 29*2743Sahrens #include <sys/dmu_impl.h> 30*2743Sahrens #include <sys/dmu_tx.h> 31*2743Sahrens #include <sys/dbuf.h> 32*2743Sahrens #include <sys/dnode.h> 33*2743Sahrens #include <sys/zfs_context.h> 34*2743Sahrens #include <sys/dmu_objset.h> 35*2743Sahrens #include <sys/dmu_traverse.h> 36*2743Sahrens #include <sys/dsl_dataset.h> 37*2743Sahrens #include <sys/dsl_dir.h> 38*2743Sahrens #include <sys/dsl_pool.h> 39*2743Sahrens #include <sys/dsl_synctask.h> 40*2743Sahrens #include <sys/zfs_ioctl.h> 41*2743Sahrens #include <sys/zap.h> 42*2743Sahrens #include <sys/zio_checksum.h> 43*2743Sahrens 44*2743Sahrens struct backuparg { 45*2743Sahrens dmu_replay_record_t *drr; 46*2743Sahrens vnode_t *vp; 47*2743Sahrens objset_t *os; 48*2743Sahrens zio_cksum_t zc; 49*2743Sahrens int err; 50*2743Sahrens }; 51*2743Sahrens 52*2743Sahrens static int 53*2743Sahrens dump_bytes(struct backuparg *ba, void *buf, int len) 54*2743Sahrens { 55*2743Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 56*2743Sahrens ASSERT3U(len % 8, ==, 0); 57*2743Sahrens 58*2743Sahrens fletcher_4_incremental_native(buf, len, &ba->zc); 59*2743Sahrens ba->err = vn_rdwr(UIO_WRITE, ba->vp, 60*2743Sahrens (caddr_t)buf, len, 61*2743Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 62*2743Sahrens return (ba->err); 63*2743Sahrens } 64*2743Sahrens 65*2743Sahrens static int 66*2743Sahrens dump_free(struct backuparg *ba, uint64_t object, uint64_t offset, 67*2743Sahrens uint64_t length) 68*2743Sahrens { 69*2743Sahrens /* write a FREE record */ 70*2743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 71*2743Sahrens ba->drr->drr_type = DRR_FREE; 72*2743Sahrens ba->drr->drr_u.drr_free.drr_object = object; 73*2743Sahrens ba->drr->drr_u.drr_free.drr_offset = offset; 74*2743Sahrens ba->drr->drr_u.drr_free.drr_length = length; 75*2743Sahrens 76*2743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 77*2743Sahrens return (EINTR); 78*2743Sahrens return (0); 79*2743Sahrens } 80*2743Sahrens 81*2743Sahrens static int 82*2743Sahrens dump_data(struct backuparg *ba, dmu_object_type_t type, 83*2743Sahrens uint64_t object, uint64_t offset, int blksz, void *data) 84*2743Sahrens { 85*2743Sahrens /* write a DATA record */ 86*2743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 87*2743Sahrens ba->drr->drr_type = DRR_WRITE; 88*2743Sahrens ba->drr->drr_u.drr_write.drr_object = object; 89*2743Sahrens ba->drr->drr_u.drr_write.drr_type = type; 90*2743Sahrens ba->drr->drr_u.drr_write.drr_offset = offset; 91*2743Sahrens ba->drr->drr_u.drr_write.drr_length = blksz; 92*2743Sahrens 93*2743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 94*2743Sahrens return (EINTR); 95*2743Sahrens if (dump_bytes(ba, data, blksz)) 96*2743Sahrens return (EINTR); 97*2743Sahrens return (0); 98*2743Sahrens } 99*2743Sahrens 100*2743Sahrens static int 101*2743Sahrens dump_freeobjects(struct backuparg *ba, uint64_t firstobj, uint64_t numobjs) 102*2743Sahrens { 103*2743Sahrens /* write a FREEOBJECTS record */ 104*2743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 105*2743Sahrens ba->drr->drr_type = DRR_FREEOBJECTS; 106*2743Sahrens ba->drr->drr_u.drr_freeobjects.drr_firstobj = firstobj; 107*2743Sahrens ba->drr->drr_u.drr_freeobjects.drr_numobjs = numobjs; 108*2743Sahrens 109*2743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 110*2743Sahrens return (EINTR); 111*2743Sahrens return (0); 112*2743Sahrens } 113*2743Sahrens 114*2743Sahrens static int 115*2743Sahrens dump_dnode(struct backuparg *ba, uint64_t object, dnode_phys_t *dnp) 116*2743Sahrens { 117*2743Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 118*2743Sahrens return (dump_freeobjects(ba, object, 1)); 119*2743Sahrens 120*2743Sahrens /* write an OBJECT record */ 121*2743Sahrens bzero(ba->drr, sizeof (dmu_replay_record_t)); 122*2743Sahrens ba->drr->drr_type = DRR_OBJECT; 123*2743Sahrens ba->drr->drr_u.drr_object.drr_object = object; 124*2743Sahrens ba->drr->drr_u.drr_object.drr_type = dnp->dn_type; 125*2743Sahrens ba->drr->drr_u.drr_object.drr_bonustype = dnp->dn_bonustype; 126*2743Sahrens ba->drr->drr_u.drr_object.drr_blksz = 127*2743Sahrens dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 128*2743Sahrens ba->drr->drr_u.drr_object.drr_bonuslen = dnp->dn_bonuslen; 129*2743Sahrens ba->drr->drr_u.drr_object.drr_checksum = dnp->dn_checksum; 130*2743Sahrens ba->drr->drr_u.drr_object.drr_compress = dnp->dn_compress; 131*2743Sahrens 132*2743Sahrens if (dump_bytes(ba, ba->drr, sizeof (dmu_replay_record_t))) 133*2743Sahrens return (EINTR); 134*2743Sahrens 135*2743Sahrens if (dump_bytes(ba, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8))) 136*2743Sahrens return (EINTR); 137*2743Sahrens 138*2743Sahrens /* free anything past the end of the file */ 139*2743Sahrens if (dump_free(ba, object, (dnp->dn_maxblkid + 1) * 140*2743Sahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL)) 141*2743Sahrens return (EINTR); 142*2743Sahrens if (ba->err) 143*2743Sahrens return (EINTR); 144*2743Sahrens return (0); 145*2743Sahrens } 146*2743Sahrens 147*2743Sahrens #define BP_SPAN(dnp, level) \ 148*2743Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 149*2743Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 150*2743Sahrens 151*2743Sahrens static int 152*2743Sahrens backup_cb(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 153*2743Sahrens { 154*2743Sahrens struct backuparg *ba = arg; 155*2743Sahrens uint64_t object = bc->bc_bookmark.zb_object; 156*2743Sahrens int level = bc->bc_bookmark.zb_level; 157*2743Sahrens uint64_t blkid = bc->bc_bookmark.zb_blkid; 158*2743Sahrens blkptr_t *bp = bc->bc_blkptr.blk_birth ? &bc->bc_blkptr : NULL; 159*2743Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 160*2743Sahrens void *data = bc->bc_data; 161*2743Sahrens int err = 0; 162*2743Sahrens 163*2743Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 164*2743Sahrens return (EINTR); 165*2743Sahrens 166*2743Sahrens ASSERT(data || bp == NULL); 167*2743Sahrens 168*2743Sahrens if (bp == NULL && object == 0) { 169*2743Sahrens uint64_t span = BP_SPAN(bc->bc_dnode, level); 170*2743Sahrens uint64_t dnobj = (blkid * span) >> DNODE_SHIFT; 171*2743Sahrens err = dump_freeobjects(ba, dnobj, span >> DNODE_SHIFT); 172*2743Sahrens } else if (bp == NULL) { 173*2743Sahrens uint64_t span = BP_SPAN(bc->bc_dnode, level); 174*2743Sahrens err = dump_free(ba, object, blkid * span, span); 175*2743Sahrens } else if (data && level == 0 && type == DMU_OT_DNODE) { 176*2743Sahrens dnode_phys_t *blk = data; 177*2743Sahrens int i; 178*2743Sahrens int blksz = BP_GET_LSIZE(bp); 179*2743Sahrens 180*2743Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 181*2743Sahrens uint64_t dnobj = 182*2743Sahrens (blkid << (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 183*2743Sahrens err = dump_dnode(ba, dnobj, blk+i); 184*2743Sahrens if (err) 185*2743Sahrens break; 186*2743Sahrens } 187*2743Sahrens } else if (level == 0 && 188*2743Sahrens type != DMU_OT_DNODE && type != DMU_OT_OBJSET) { 189*2743Sahrens int blksz = BP_GET_LSIZE(bp); 190*2743Sahrens if (data == NULL) { 191*2743Sahrens uint32_t aflags = ARC_WAIT; 192*2743Sahrens arc_buf_t *abuf; 193*2743Sahrens zbookmark_t zb; 194*2743Sahrens 195*2743Sahrens zb.zb_objset = ba->os->os->os_dsl_dataset->ds_object; 196*2743Sahrens zb.zb_object = object; 197*2743Sahrens zb.zb_level = level; 198*2743Sahrens zb.zb_blkid = blkid; 199*2743Sahrens (void) arc_read(NULL, spa, bp, 200*2743Sahrens dmu_ot[type].ot_byteswap, arc_getbuf_func, &abuf, 201*2743Sahrens ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_MUSTSUCCEED, 202*2743Sahrens &aflags, &zb); 203*2743Sahrens 204*2743Sahrens if (abuf) { 205*2743Sahrens err = dump_data(ba, type, object, blkid * blksz, 206*2743Sahrens blksz, abuf->b_data); 207*2743Sahrens (void) arc_buf_remove_ref(abuf, &abuf); 208*2743Sahrens } 209*2743Sahrens } else { 210*2743Sahrens err = dump_data(ba, type, object, blkid * blksz, 211*2743Sahrens blksz, data); 212*2743Sahrens } 213*2743Sahrens } 214*2743Sahrens 215*2743Sahrens ASSERT(err == 0 || err == EINTR); 216*2743Sahrens return (err); 217*2743Sahrens } 218*2743Sahrens 219*2743Sahrens int 220*2743Sahrens dmu_sendbackup(objset_t *tosnap, objset_t *fromsnap, vnode_t *vp) 221*2743Sahrens { 222*2743Sahrens dsl_dataset_t *ds = tosnap->os->os_dsl_dataset; 223*2743Sahrens dsl_dataset_t *fromds = fromsnap ? fromsnap->os->os_dsl_dataset : NULL; 224*2743Sahrens dmu_replay_record_t *drr; 225*2743Sahrens struct backuparg ba; 226*2743Sahrens int err; 227*2743Sahrens 228*2743Sahrens /* tosnap must be a snapshot */ 229*2743Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 230*2743Sahrens return (EINVAL); 231*2743Sahrens 232*2743Sahrens /* fromsnap must be an earlier snapshot from the same fs as tosnap */ 233*2743Sahrens if (fromds && (ds->ds_dir != fromds->ds_dir || 234*2743Sahrens fromds->ds_phys->ds_creation_txg >= 235*2743Sahrens ds->ds_phys->ds_creation_txg)) 236*2743Sahrens return (EXDEV); 237*2743Sahrens 238*2743Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 239*2743Sahrens drr->drr_type = DRR_BEGIN; 240*2743Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 241*2743Sahrens drr->drr_u.drr_begin.drr_version = DMU_BACKUP_VERSION; 242*2743Sahrens drr->drr_u.drr_begin.drr_creation_time = 243*2743Sahrens ds->ds_phys->ds_creation_time; 244*2743Sahrens drr->drr_u.drr_begin.drr_type = tosnap->os->os_phys->os_type; 245*2743Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 246*2743Sahrens if (fromds) 247*2743Sahrens drr->drr_u.drr_begin.drr_fromguid = fromds->ds_phys->ds_guid; 248*2743Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 249*2743Sahrens 250*2743Sahrens ba.drr = drr; 251*2743Sahrens ba.vp = vp; 252*2743Sahrens ba.os = tosnap; 253*2743Sahrens ZIO_SET_CHECKSUM(&ba.zc, 0, 0, 0, 0); 254*2743Sahrens 255*2743Sahrens if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 256*2743Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 257*2743Sahrens return (ba.err); 258*2743Sahrens } 259*2743Sahrens 260*2743Sahrens err = traverse_dsl_dataset(ds, 261*2743Sahrens fromds ? fromds->ds_phys->ds_creation_txg : 0, 262*2743Sahrens ADVANCE_PRE | ADVANCE_HOLES | ADVANCE_DATA | ADVANCE_NOLOCK, 263*2743Sahrens backup_cb, &ba); 264*2743Sahrens 265*2743Sahrens if (err) { 266*2743Sahrens if (err == EINTR && ba.err) 267*2743Sahrens err = ba.err; 268*2743Sahrens return (err); 269*2743Sahrens } 270*2743Sahrens 271*2743Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 272*2743Sahrens drr->drr_type = DRR_END; 273*2743Sahrens drr->drr_u.drr_end.drr_checksum = ba.zc; 274*2743Sahrens 275*2743Sahrens if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) 276*2743Sahrens return (ba.err); 277*2743Sahrens 278*2743Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 279*2743Sahrens 280*2743Sahrens return (0); 281*2743Sahrens } 282*2743Sahrens 283*2743Sahrens struct restorearg { 284*2743Sahrens int err; 285*2743Sahrens int byteswap; 286*2743Sahrens vnode_t *vp; 287*2743Sahrens char *buf; 288*2743Sahrens uint64_t voff; 289*2743Sahrens int buflen; /* number of valid bytes in buf */ 290*2743Sahrens int bufoff; /* next offset to read */ 291*2743Sahrens int bufsize; /* amount of memory allocated for buf */ 292*2743Sahrens zio_cksum_t zc; 293*2743Sahrens }; 294*2743Sahrens 295*2743Sahrens /* ARGSUSED */ 296*2743Sahrens static int 297*2743Sahrens replay_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 298*2743Sahrens { 299*2743Sahrens dsl_dataset_t *ds = arg1; 300*2743Sahrens struct drr_begin *drrb = arg2; 301*2743Sahrens const char *snapname; 302*2743Sahrens int err; 303*2743Sahrens uint64_t val; 304*2743Sahrens 305*2743Sahrens /* must already be a snapshot of this fs */ 306*2743Sahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 307*2743Sahrens return (ENODEV); 308*2743Sahrens 309*2743Sahrens /* most recent snapshot must match fromguid */ 310*2743Sahrens if (ds->ds_prev->ds_phys->ds_guid != drrb->drr_fromguid) 311*2743Sahrens return (ENODEV); 312*2743Sahrens /* must not have any changes since most recent snapshot */ 313*2743Sahrens if (ds->ds_phys->ds_bp.blk_birth > 314*2743Sahrens ds->ds_prev->ds_phys->ds_creation_txg) 315*2743Sahrens return (ETXTBSY); 316*2743Sahrens 317*2743Sahrens /* new snapshot name must not exist */ 318*2743Sahrens snapname = strrchr(drrb->drr_toname, '@'); 319*2743Sahrens if (snapname == NULL) 320*2743Sahrens return (EEXIST); 321*2743Sahrens 322*2743Sahrens snapname++; 323*2743Sahrens err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 324*2743Sahrens ds->ds_phys->ds_snapnames_zapobj, snapname, 8, 1, &val); 325*2743Sahrens if (err == 0) 326*2743Sahrens return (EEXIST); 327*2743Sahrens if (err != ENOENT) 328*2743Sahrens return (err); 329*2743Sahrens 330*2743Sahrens return (0); 331*2743Sahrens } 332*2743Sahrens 333*2743Sahrens /* ARGSUSED */ 334*2743Sahrens static void 335*2743Sahrens replay_incremental_sync(void *arg1, void *arg2, dmu_tx_t *tx) 336*2743Sahrens { 337*2743Sahrens dsl_dataset_t *ds = arg1; 338*2743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 339*2743Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 340*2743Sahrens } 341*2743Sahrens 342*2743Sahrens /* ARGSUSED */ 343*2743Sahrens static int 344*2743Sahrens replay_full_check(void *arg1, void *arg2, dmu_tx_t *tx) 345*2743Sahrens { 346*2743Sahrens dsl_dir_t *dd = arg1; 347*2743Sahrens struct drr_begin *drrb = arg2; 348*2743Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 349*2743Sahrens char *cp; 350*2743Sahrens uint64_t val; 351*2743Sahrens int err; 352*2743Sahrens 353*2743Sahrens cp = strchr(drrb->drr_toname, '@'); 354*2743Sahrens *cp = '\0'; 355*2743Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 356*2743Sahrens strrchr(drrb->drr_toname, '/') + 1, 357*2743Sahrens sizeof (uint64_t), 1, &val); 358*2743Sahrens *cp = '@'; 359*2743Sahrens 360*2743Sahrens if (err != ENOENT) 361*2743Sahrens return (err ? err : EEXIST); 362*2743Sahrens 363*2743Sahrens return (0); 364*2743Sahrens } 365*2743Sahrens 366*2743Sahrens static void 367*2743Sahrens replay_full_sync(void *arg1, void *arg2, dmu_tx_t *tx) 368*2743Sahrens { 369*2743Sahrens dsl_dir_t *dd = arg1; 370*2743Sahrens struct drr_begin *drrb = arg2; 371*2743Sahrens char *cp; 372*2743Sahrens dsl_dataset_t *ds; 373*2743Sahrens uint64_t dsobj; 374*2743Sahrens 375*2743Sahrens cp = strchr(drrb->drr_toname, '@'); 376*2743Sahrens *cp = '\0'; 377*2743Sahrens dsobj = dsl_dataset_create_sync(dd, strrchr(drrb->drr_toname, '/') + 1, 378*2743Sahrens NULL, tx); 379*2743Sahrens *cp = '@'; 380*2743Sahrens 381*2743Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 382*2743Sahrens DS_MODE_EXCLUSIVE, FTAG, &ds)); 383*2743Sahrens 384*2743Sahrens (void) dmu_objset_create_impl(dsl_dataset_get_spa(ds), 385*2743Sahrens ds, drrb->drr_type, tx); 386*2743Sahrens 387*2743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 388*2743Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 389*2743Sahrens 390*2743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 391*2743Sahrens } 392*2743Sahrens 393*2743Sahrens static int 394*2743Sahrens replay_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 395*2743Sahrens { 396*2743Sahrens objset_t *os = arg1; 397*2743Sahrens struct drr_begin *drrb = arg2; 398*2743Sahrens char *snapname; 399*2743Sahrens 400*2743Sahrens /* XXX verify that drr_toname is in dd */ 401*2743Sahrens 402*2743Sahrens snapname = strchr(drrb->drr_toname, '@'); 403*2743Sahrens if (snapname == NULL) 404*2743Sahrens return (EINVAL); 405*2743Sahrens snapname++; 406*2743Sahrens 407*2743Sahrens return (dsl_dataset_snapshot_check(os, snapname, tx)); 408*2743Sahrens } 409*2743Sahrens 410*2743Sahrens static void 411*2743Sahrens replay_end_sync(void *arg1, void *arg2, dmu_tx_t *tx) 412*2743Sahrens { 413*2743Sahrens objset_t *os = arg1; 414*2743Sahrens struct drr_begin *drrb = arg2; 415*2743Sahrens char *snapname; 416*2743Sahrens dsl_dataset_t *ds, *hds; 417*2743Sahrens 418*2743Sahrens snapname = strchr(drrb->drr_toname, '@') + 1; 419*2743Sahrens 420*2743Sahrens dsl_dataset_snapshot_sync(os, snapname, tx); 421*2743Sahrens 422*2743Sahrens /* set snapshot's creation time and guid */ 423*2743Sahrens hds = os->os->os_dsl_dataset; 424*2743Sahrens VERIFY(0 == dsl_dataset_open_obj(hds->ds_dir->dd_pool, 425*2743Sahrens hds->ds_phys->ds_prev_snap_obj, NULL, 426*2743Sahrens DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 427*2743Sahrens FTAG, &ds)); 428*2743Sahrens 429*2743Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 430*2743Sahrens ds->ds_phys->ds_creation_time = drrb->drr_creation_time; 431*2743Sahrens ds->ds_phys->ds_guid = drrb->drr_toguid; 432*2743Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 433*2743Sahrens 434*2743Sahrens dsl_dataset_close(ds, DS_MODE_PRIMARY, FTAG); 435*2743Sahrens 436*2743Sahrens dmu_buf_will_dirty(hds->ds_dbuf, tx); 437*2743Sahrens hds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 438*2743Sahrens } 439*2743Sahrens 440*2743Sahrens static void * 441*2743Sahrens restore_read(struct restorearg *ra, int len) 442*2743Sahrens { 443*2743Sahrens void *rv; 444*2743Sahrens 445*2743Sahrens /* some things will require 8-byte alignment, so everything must */ 446*2743Sahrens ASSERT3U(len % 8, ==, 0); 447*2743Sahrens 448*2743Sahrens while (ra->buflen - ra->bufoff < len) { 449*2743Sahrens ssize_t resid; 450*2743Sahrens int leftover = ra->buflen - ra->bufoff; 451*2743Sahrens 452*2743Sahrens (void) memmove(ra->buf, ra->buf + ra->bufoff, leftover); 453*2743Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 454*2743Sahrens (caddr_t)ra->buf + leftover, ra->bufsize - leftover, 455*2743Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 456*2743Sahrens RLIM64_INFINITY, CRED(), &resid); 457*2743Sahrens 458*2743Sahrens ra->voff += ra->bufsize - leftover - resid; 459*2743Sahrens ra->buflen = ra->bufsize - resid; 460*2743Sahrens ra->bufoff = 0; 461*2743Sahrens if (resid == ra->bufsize - leftover) 462*2743Sahrens ra->err = EINVAL; 463*2743Sahrens if (ra->err) 464*2743Sahrens return (NULL); 465*2743Sahrens /* Could compute checksum here? */ 466*2743Sahrens } 467*2743Sahrens 468*2743Sahrens ASSERT3U(ra->bufoff % 8, ==, 0); 469*2743Sahrens ASSERT3U(ra->buflen - ra->bufoff, >=, len); 470*2743Sahrens rv = ra->buf + ra->bufoff; 471*2743Sahrens ra->bufoff += len; 472*2743Sahrens if (ra->byteswap) 473*2743Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->zc); 474*2743Sahrens else 475*2743Sahrens fletcher_4_incremental_native(rv, len, &ra->zc); 476*2743Sahrens return (rv); 477*2743Sahrens } 478*2743Sahrens 479*2743Sahrens static void 480*2743Sahrens backup_byteswap(dmu_replay_record_t *drr) 481*2743Sahrens { 482*2743Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 483*2743Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 484*2743Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 485*2743Sahrens switch (drr->drr_type) { 486*2743Sahrens case DRR_BEGIN: 487*2743Sahrens DO64(drr_begin.drr_magic); 488*2743Sahrens DO64(drr_begin.drr_version); 489*2743Sahrens DO64(drr_begin.drr_creation_time); 490*2743Sahrens DO32(drr_begin.drr_type); 491*2743Sahrens DO64(drr_begin.drr_toguid); 492*2743Sahrens DO64(drr_begin.drr_fromguid); 493*2743Sahrens break; 494*2743Sahrens case DRR_OBJECT: 495*2743Sahrens DO64(drr_object.drr_object); 496*2743Sahrens /* DO64(drr_object.drr_allocation_txg); */ 497*2743Sahrens DO32(drr_object.drr_type); 498*2743Sahrens DO32(drr_object.drr_bonustype); 499*2743Sahrens DO32(drr_object.drr_blksz); 500*2743Sahrens DO32(drr_object.drr_bonuslen); 501*2743Sahrens break; 502*2743Sahrens case DRR_FREEOBJECTS: 503*2743Sahrens DO64(drr_freeobjects.drr_firstobj); 504*2743Sahrens DO64(drr_freeobjects.drr_numobjs); 505*2743Sahrens break; 506*2743Sahrens case DRR_WRITE: 507*2743Sahrens DO64(drr_write.drr_object); 508*2743Sahrens DO32(drr_write.drr_type); 509*2743Sahrens DO64(drr_write.drr_offset); 510*2743Sahrens DO64(drr_write.drr_length); 511*2743Sahrens break; 512*2743Sahrens case DRR_FREE: 513*2743Sahrens DO64(drr_free.drr_object); 514*2743Sahrens DO64(drr_free.drr_offset); 515*2743Sahrens DO64(drr_free.drr_length); 516*2743Sahrens break; 517*2743Sahrens case DRR_END: 518*2743Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 519*2743Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 520*2743Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 521*2743Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 522*2743Sahrens break; 523*2743Sahrens } 524*2743Sahrens #undef DO64 525*2743Sahrens #undef DO32 526*2743Sahrens } 527*2743Sahrens 528*2743Sahrens static int 529*2743Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 530*2743Sahrens { 531*2743Sahrens int err; 532*2743Sahrens dmu_tx_t *tx; 533*2743Sahrens 534*2743Sahrens err = dmu_object_info(os, drro->drr_object, NULL); 535*2743Sahrens 536*2743Sahrens if (err != 0 && err != ENOENT) 537*2743Sahrens return (EINVAL); 538*2743Sahrens 539*2743Sahrens if (drro->drr_type == DMU_OT_NONE || 540*2743Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 541*2743Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 542*2743Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 543*2743Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 544*2743Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 545*2743Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 546*2743Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 547*2743Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 548*2743Sahrens return (EINVAL); 549*2743Sahrens } 550*2743Sahrens 551*2743Sahrens tx = dmu_tx_create(os); 552*2743Sahrens 553*2743Sahrens if (err == ENOENT) { 554*2743Sahrens /* currently free, want to be allocated */ 555*2743Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 556*2743Sahrens dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 1); 557*2743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 558*2743Sahrens if (err) { 559*2743Sahrens dmu_tx_abort(tx); 560*2743Sahrens return (err); 561*2743Sahrens } 562*2743Sahrens err = dmu_object_claim(os, drro->drr_object, 563*2743Sahrens drro->drr_type, drro->drr_blksz, 564*2743Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 565*2743Sahrens } else { 566*2743Sahrens /* currently allocated, want to be allocated */ 567*2743Sahrens dmu_tx_hold_bonus(tx, drro->drr_object); 568*2743Sahrens /* 569*2743Sahrens * We may change blocksize, so need to 570*2743Sahrens * hold_write 571*2743Sahrens */ 572*2743Sahrens dmu_tx_hold_write(tx, drro->drr_object, 0, 1); 573*2743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 574*2743Sahrens if (err) { 575*2743Sahrens dmu_tx_abort(tx); 576*2743Sahrens return (err); 577*2743Sahrens } 578*2743Sahrens 579*2743Sahrens err = dmu_object_reclaim(os, drro->drr_object, 580*2743Sahrens drro->drr_type, drro->drr_blksz, 581*2743Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 582*2743Sahrens } 583*2743Sahrens if (err) { 584*2743Sahrens dmu_tx_commit(tx); 585*2743Sahrens return (EINVAL); 586*2743Sahrens } 587*2743Sahrens 588*2743Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 589*2743Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 590*2743Sahrens 591*2743Sahrens if (drro->drr_bonuslen) { 592*2743Sahrens dmu_buf_t *db; 593*2743Sahrens void *data; 594*2743Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 595*2743Sahrens dmu_buf_will_dirty(db, tx); 596*2743Sahrens 597*2743Sahrens ASSERT3U(db->db_size, ==, drro->drr_bonuslen); 598*2743Sahrens data = restore_read(ra, P2ROUNDUP(db->db_size, 8)); 599*2743Sahrens if (data == NULL) { 600*2743Sahrens dmu_tx_commit(tx); 601*2743Sahrens return (ra->err); 602*2743Sahrens } 603*2743Sahrens bcopy(data, db->db_data, db->db_size); 604*2743Sahrens if (ra->byteswap) { 605*2743Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 606*2743Sahrens drro->drr_bonuslen); 607*2743Sahrens } 608*2743Sahrens dmu_buf_rele(db, FTAG); 609*2743Sahrens } 610*2743Sahrens dmu_tx_commit(tx); 611*2743Sahrens return (0); 612*2743Sahrens } 613*2743Sahrens 614*2743Sahrens /* ARGSUSED */ 615*2743Sahrens static int 616*2743Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 617*2743Sahrens struct drr_freeobjects *drrfo) 618*2743Sahrens { 619*2743Sahrens uint64_t obj; 620*2743Sahrens 621*2743Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 622*2743Sahrens return (EINVAL); 623*2743Sahrens 624*2743Sahrens for (obj = drrfo->drr_firstobj; 625*2743Sahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; obj++) { 626*2743Sahrens dmu_tx_t *tx; 627*2743Sahrens int err; 628*2743Sahrens 629*2743Sahrens if (dmu_object_info(os, obj, NULL) != 0) 630*2743Sahrens continue; 631*2743Sahrens 632*2743Sahrens tx = dmu_tx_create(os); 633*2743Sahrens dmu_tx_hold_bonus(tx, obj); 634*2743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 635*2743Sahrens if (err) { 636*2743Sahrens dmu_tx_abort(tx); 637*2743Sahrens return (err); 638*2743Sahrens } 639*2743Sahrens err = dmu_object_free(os, obj, tx); 640*2743Sahrens dmu_tx_commit(tx); 641*2743Sahrens if (err && err != ENOENT) 642*2743Sahrens return (EINVAL); 643*2743Sahrens } 644*2743Sahrens return (0); 645*2743Sahrens } 646*2743Sahrens 647*2743Sahrens static int 648*2743Sahrens restore_write(struct restorearg *ra, objset_t *os, 649*2743Sahrens struct drr_write *drrw) 650*2743Sahrens { 651*2743Sahrens dmu_tx_t *tx; 652*2743Sahrens void *data; 653*2743Sahrens int err; 654*2743Sahrens 655*2743Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 656*2743Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 657*2743Sahrens return (EINVAL); 658*2743Sahrens 659*2743Sahrens data = restore_read(ra, drrw->drr_length); 660*2743Sahrens if (data == NULL) 661*2743Sahrens return (ra->err); 662*2743Sahrens 663*2743Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 664*2743Sahrens return (EINVAL); 665*2743Sahrens 666*2743Sahrens tx = dmu_tx_create(os); 667*2743Sahrens 668*2743Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 669*2743Sahrens drrw->drr_offset, drrw->drr_length); 670*2743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 671*2743Sahrens if (err) { 672*2743Sahrens dmu_tx_abort(tx); 673*2743Sahrens return (err); 674*2743Sahrens } 675*2743Sahrens if (ra->byteswap) 676*2743Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 677*2743Sahrens dmu_write(os, drrw->drr_object, 678*2743Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 679*2743Sahrens dmu_tx_commit(tx); 680*2743Sahrens return (0); 681*2743Sahrens } 682*2743Sahrens 683*2743Sahrens /* ARGSUSED */ 684*2743Sahrens static int 685*2743Sahrens restore_free(struct restorearg *ra, objset_t *os, 686*2743Sahrens struct drr_free *drrf) 687*2743Sahrens { 688*2743Sahrens dmu_tx_t *tx; 689*2743Sahrens int err; 690*2743Sahrens 691*2743Sahrens if (drrf->drr_length != -1ULL && 692*2743Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 693*2743Sahrens return (EINVAL); 694*2743Sahrens 695*2743Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 696*2743Sahrens return (EINVAL); 697*2743Sahrens 698*2743Sahrens tx = dmu_tx_create(os); 699*2743Sahrens 700*2743Sahrens dmu_tx_hold_free(tx, drrf->drr_object, 701*2743Sahrens drrf->drr_offset, drrf->drr_length); 702*2743Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 703*2743Sahrens if (err) { 704*2743Sahrens dmu_tx_abort(tx); 705*2743Sahrens return (err); 706*2743Sahrens } 707*2743Sahrens err = dmu_free_range(os, drrf->drr_object, 708*2743Sahrens drrf->drr_offset, drrf->drr_length, tx); 709*2743Sahrens dmu_tx_commit(tx); 710*2743Sahrens return (err); 711*2743Sahrens } 712*2743Sahrens 713*2743Sahrens int 714*2743Sahrens dmu_recvbackup(char *tosnap, struct drr_begin *drrb, uint64_t *sizep, 715*2743Sahrens boolean_t force, vnode_t *vp, uint64_t voffset) 716*2743Sahrens { 717*2743Sahrens struct restorearg ra; 718*2743Sahrens dmu_replay_record_t *drr; 719*2743Sahrens char *cp; 720*2743Sahrens objset_t *os = NULL; 721*2743Sahrens zio_cksum_t pzc; 722*2743Sahrens 723*2743Sahrens bzero(&ra, sizeof (ra)); 724*2743Sahrens ra.vp = vp; 725*2743Sahrens ra.voff = voffset; 726*2743Sahrens ra.bufsize = 1<<20; 727*2743Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 728*2743Sahrens 729*2743Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) { 730*2743Sahrens ra.byteswap = FALSE; 731*2743Sahrens } else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 732*2743Sahrens ra.byteswap = TRUE; 733*2743Sahrens } else { 734*2743Sahrens ra.err = EINVAL; 735*2743Sahrens goto out; 736*2743Sahrens } 737*2743Sahrens 738*2743Sahrens /* 739*2743Sahrens * NB: this assumes that struct drr_begin will be the largest in 740*2743Sahrens * dmu_replay_record_t's drr_u, and thus we don't need to pad it 741*2743Sahrens * with zeros to make it the same length as we wrote out. 742*2743Sahrens */ 743*2743Sahrens ((dmu_replay_record_t *)ra.buf)->drr_type = DRR_BEGIN; 744*2743Sahrens ((dmu_replay_record_t *)ra.buf)->drr_pad = 0; 745*2743Sahrens ((dmu_replay_record_t *)ra.buf)->drr_u.drr_begin = *drrb; 746*2743Sahrens if (ra.byteswap) { 747*2743Sahrens fletcher_4_incremental_byteswap(ra.buf, 748*2743Sahrens sizeof (dmu_replay_record_t), &ra.zc); 749*2743Sahrens } else { 750*2743Sahrens fletcher_4_incremental_native(ra.buf, 751*2743Sahrens sizeof (dmu_replay_record_t), &ra.zc); 752*2743Sahrens } 753*2743Sahrens (void) strcpy(drrb->drr_toname, tosnap); /* for the sync funcs */ 754*2743Sahrens 755*2743Sahrens if (ra.byteswap) { 756*2743Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 757*2743Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 758*2743Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 759*2743Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 760*2743Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 761*2743Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 762*2743Sahrens } 763*2743Sahrens 764*2743Sahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 765*2743Sahrens 766*2743Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION || 767*2743Sahrens drrb->drr_type >= DMU_OST_NUMTYPES || 768*2743Sahrens strchr(drrb->drr_toname, '@') == NULL) { 769*2743Sahrens ra.err = EINVAL; 770*2743Sahrens goto out; 771*2743Sahrens } 772*2743Sahrens 773*2743Sahrens /* 774*2743Sahrens * Process the begin in syncing context. 775*2743Sahrens */ 776*2743Sahrens if (drrb->drr_fromguid) { 777*2743Sahrens /* incremental backup */ 778*2743Sahrens dsl_dataset_t *ds = NULL; 779*2743Sahrens 780*2743Sahrens cp = strchr(tosnap, '@'); 781*2743Sahrens *cp = '\0'; 782*2743Sahrens ra.err = dsl_dataset_open(tosnap, DS_MODE_EXCLUSIVE, FTAG, &ds); 783*2743Sahrens *cp = '@'; 784*2743Sahrens if (ra.err) 785*2743Sahrens goto out; 786*2743Sahrens 787*2743Sahrens /* 788*2743Sahrens * Only do the rollback if the most recent snapshot 789*2743Sahrens * matches the incremental source 790*2743Sahrens */ 791*2743Sahrens if (force) { 792*2743Sahrens if (ds->ds_prev->ds_phys->ds_guid != 793*2743Sahrens drrb->drr_fromguid) { 794*2743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 795*2743Sahrens return (ENODEV); 796*2743Sahrens } 797*2743Sahrens (void) dsl_dataset_rollback(ds); 798*2743Sahrens } 799*2743Sahrens ra.err = dsl_sync_task_do(ds->ds_dir->dd_pool, 800*2743Sahrens replay_incremental_check, replay_incremental_sync, 801*2743Sahrens ds, drrb, 1); 802*2743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 803*2743Sahrens } else { 804*2743Sahrens /* full backup */ 805*2743Sahrens dsl_dir_t *dd = NULL; 806*2743Sahrens const char *tail; 807*2743Sahrens 808*2743Sahrens /* can't restore full backup into topmost fs, for now */ 809*2743Sahrens if (strrchr(drrb->drr_toname, '/') == NULL) { 810*2743Sahrens ra.err = EINVAL; 811*2743Sahrens goto out; 812*2743Sahrens } 813*2743Sahrens 814*2743Sahrens cp = strchr(tosnap, '@'); 815*2743Sahrens *cp = '\0'; 816*2743Sahrens ra.err = dsl_dir_open(tosnap, FTAG, &dd, &tail); 817*2743Sahrens *cp = '@'; 818*2743Sahrens if (ra.err) 819*2743Sahrens goto out; 820*2743Sahrens if (tail == NULL) { 821*2743Sahrens ra.err = EEXIST; 822*2743Sahrens goto out; 823*2743Sahrens } 824*2743Sahrens 825*2743Sahrens ra.err = dsl_sync_task_do(dd->dd_pool, replay_full_check, 826*2743Sahrens replay_full_sync, dd, drrb, 5); 827*2743Sahrens dsl_dir_close(dd, FTAG); 828*2743Sahrens } 829*2743Sahrens if (ra.err) 830*2743Sahrens goto out; 831*2743Sahrens 832*2743Sahrens /* 833*2743Sahrens * Open the objset we are modifying. 834*2743Sahrens */ 835*2743Sahrens 836*2743Sahrens cp = strchr(tosnap, '@'); 837*2743Sahrens *cp = '\0'; 838*2743Sahrens ra.err = dmu_objset_open(tosnap, DMU_OST_ANY, 839*2743Sahrens DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os); 840*2743Sahrens *cp = '@'; 841*2743Sahrens ASSERT3U(ra.err, ==, 0); 842*2743Sahrens 843*2743Sahrens /* 844*2743Sahrens * Read records and process them. 845*2743Sahrens */ 846*2743Sahrens pzc = ra.zc; 847*2743Sahrens while (ra.err == 0 && 848*2743Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 849*2743Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 850*2743Sahrens ra.err = EINTR; 851*2743Sahrens goto out; 852*2743Sahrens } 853*2743Sahrens 854*2743Sahrens if (ra.byteswap) 855*2743Sahrens backup_byteswap(drr); 856*2743Sahrens 857*2743Sahrens switch (drr->drr_type) { 858*2743Sahrens case DRR_OBJECT: 859*2743Sahrens { 860*2743Sahrens /* 861*2743Sahrens * We need to make a copy of the record header, 862*2743Sahrens * because restore_{object,write} may need to 863*2743Sahrens * restore_read(), which will invalidate drr. 864*2743Sahrens */ 865*2743Sahrens struct drr_object drro = drr->drr_u.drr_object; 866*2743Sahrens ra.err = restore_object(&ra, os, &drro); 867*2743Sahrens break; 868*2743Sahrens } 869*2743Sahrens case DRR_FREEOBJECTS: 870*2743Sahrens { 871*2743Sahrens struct drr_freeobjects drrfo = 872*2743Sahrens drr->drr_u.drr_freeobjects; 873*2743Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 874*2743Sahrens break; 875*2743Sahrens } 876*2743Sahrens case DRR_WRITE: 877*2743Sahrens { 878*2743Sahrens struct drr_write drrw = drr->drr_u.drr_write; 879*2743Sahrens ra.err = restore_write(&ra, os, &drrw); 880*2743Sahrens break; 881*2743Sahrens } 882*2743Sahrens case DRR_FREE: 883*2743Sahrens { 884*2743Sahrens struct drr_free drrf = drr->drr_u.drr_free; 885*2743Sahrens ra.err = restore_free(&ra, os, &drrf); 886*2743Sahrens break; 887*2743Sahrens } 888*2743Sahrens case DRR_END: 889*2743Sahrens { 890*2743Sahrens struct drr_end drre = drr->drr_u.drr_end; 891*2743Sahrens /* 892*2743Sahrens * We compare against the *previous* checksum 893*2743Sahrens * value, because the stored checksum is of 894*2743Sahrens * everything before the DRR_END record. 895*2743Sahrens */ 896*2743Sahrens if (drre.drr_checksum.zc_word[0] != 0 && 897*2743Sahrens ((drre.drr_checksum.zc_word[0] - pzc.zc_word[0]) | 898*2743Sahrens (drre.drr_checksum.zc_word[1] - pzc.zc_word[1]) | 899*2743Sahrens (drre.drr_checksum.zc_word[2] - pzc.zc_word[2]) | 900*2743Sahrens (drre.drr_checksum.zc_word[3] - pzc.zc_word[3]))) { 901*2743Sahrens ra.err = ECKSUM; 902*2743Sahrens goto out; 903*2743Sahrens } 904*2743Sahrens 905*2743Sahrens ra.err = dsl_sync_task_do(dmu_objset_ds(os)-> 906*2743Sahrens ds_dir->dd_pool, replay_end_check, replay_end_sync, 907*2743Sahrens os, drrb, 3); 908*2743Sahrens goto out; 909*2743Sahrens } 910*2743Sahrens default: 911*2743Sahrens ra.err = EINVAL; 912*2743Sahrens goto out; 913*2743Sahrens } 914*2743Sahrens pzc = ra.zc; 915*2743Sahrens } 916*2743Sahrens 917*2743Sahrens out: 918*2743Sahrens if (os) 919*2743Sahrens dmu_objset_close(os); 920*2743Sahrens 921*2743Sahrens /* 922*2743Sahrens * Make sure we don't rollback/destroy unless we actually 923*2743Sahrens * processed the begin properly. 'os' will only be set if this 924*2743Sahrens * is the case. 925*2743Sahrens */ 926*2743Sahrens if (ra.err && os && tosnap && strchr(tosnap, '@')) { 927*2743Sahrens /* 928*2743Sahrens * rollback or destroy what we created, so we don't 929*2743Sahrens * leave it in the restoring state. 930*2743Sahrens */ 931*2743Sahrens dsl_dataset_t *ds; 932*2743Sahrens int err; 933*2743Sahrens 934*2743Sahrens cp = strchr(tosnap, '@'); 935*2743Sahrens *cp = '\0'; 936*2743Sahrens err = dsl_dataset_open(tosnap, 937*2743Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, 938*2743Sahrens FTAG, &ds); 939*2743Sahrens if (err == 0) { 940*2743Sahrens txg_wait_synced(ds->ds_dir->dd_pool, 0); 941*2743Sahrens if (drrb->drr_fromguid) { 942*2743Sahrens /* incremental: rollback to most recent snap */ 943*2743Sahrens (void) dsl_dataset_rollback(ds); 944*2743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 945*2743Sahrens } else { 946*2743Sahrens /* full: destroy whole fs */ 947*2743Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 948*2743Sahrens (void) dsl_dataset_destroy(tosnap); 949*2743Sahrens } 950*2743Sahrens } 951*2743Sahrens *cp = '@'; 952*2743Sahrens } 953*2743Sahrens 954*2743Sahrens kmem_free(ra.buf, ra.bufsize); 955*2743Sahrens if (sizep) 956*2743Sahrens *sizep = ra.voff; 957*2743Sahrens return (ra.err); 958*2743Sahrens } 959