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