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