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 /* 22c717a561Smaybee * Copyright 2007 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; 268*7b5309bbSgw kmem_free(drr, sizeof (dmu_replay_record_t)); 269efb80947Sahrens return (err); 270efb80947Sahrens } 271efb80947Sahrens 272efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 273efb80947Sahrens drr->drr_type = DRR_END; 274efb80947Sahrens drr->drr_u.drr_end.drr_checksum = ba.zc; 275efb80947Sahrens 276*7b5309bbSgw if (dump_bytes(&ba, drr, sizeof (dmu_replay_record_t))) { 277*7b5309bbSgw kmem_free(drr, sizeof (dmu_replay_record_t)); 278efb80947Sahrens return (ba.err); 279*7b5309bbSgw } 280efb80947Sahrens 281efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 282efb80947Sahrens 283efb80947Sahrens return (0); 284efb80947Sahrens } 285efb80947Sahrens 286efb80947Sahrens struct restorearg { 287efb80947Sahrens int err; 288efb80947Sahrens int byteswap; 289efb80947Sahrens vnode_t *vp; 290efb80947Sahrens char *buf; 291efb80947Sahrens uint64_t voff; 292efb80947Sahrens int buflen; /* number of valid bytes in buf */ 293efb80947Sahrens int bufoff; /* next offset to read */ 294efb80947Sahrens int bufsize; /* amount of memory allocated for buf */ 295efb80947Sahrens zio_cksum_t zc; 296efb80947Sahrens }; 297efb80947Sahrens 298efb80947Sahrens /* ARGSUSED */ 299efb80947Sahrens static int 300efb80947Sahrens replay_incremental_check(void *arg1, void *arg2, dmu_tx_t *tx) 301efb80947Sahrens { 302efb80947Sahrens dsl_dataset_t *ds = arg1; 303efb80947Sahrens struct drr_begin *drrb = arg2; 304efb80947Sahrens const char *snapname; 305efb80947Sahrens int err; 306efb80947Sahrens uint64_t val; 307efb80947Sahrens 308efb80947Sahrens /* must already be a snapshot of this fs */ 309efb80947Sahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 310efb80947Sahrens return (ENODEV); 311efb80947Sahrens 312efb80947Sahrens /* most recent snapshot must match fromguid */ 313efb80947Sahrens if (ds->ds_prev->ds_phys->ds_guid != drrb->drr_fromguid) 314efb80947Sahrens return (ENODEV); 315efb80947Sahrens /* must not have any changes since most recent snapshot */ 316efb80947Sahrens if (ds->ds_phys->ds_bp.blk_birth > 317efb80947Sahrens ds->ds_prev->ds_phys->ds_creation_txg) 318efb80947Sahrens return (ETXTBSY); 319efb80947Sahrens 320efb80947Sahrens /* new snapshot name must not exist */ 321efb80947Sahrens snapname = strrchr(drrb->drr_toname, '@'); 322efb80947Sahrens if (snapname == NULL) 323efb80947Sahrens return (EEXIST); 324efb80947Sahrens 325efb80947Sahrens snapname++; 326efb80947Sahrens err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, 327efb80947Sahrens ds->ds_phys->ds_snapnames_zapobj, snapname, 8, 1, &val); 328efb80947Sahrens if (err == 0) 329efb80947Sahrens return (EEXIST); 330efb80947Sahrens if (err != ENOENT) 331efb80947Sahrens return (err); 332efb80947Sahrens 333efb80947Sahrens return (0); 334efb80947Sahrens } 335efb80947Sahrens 336efb80947Sahrens /* ARGSUSED */ 337efb80947Sahrens static void 338efb80947Sahrens replay_incremental_sync(void *arg1, void *arg2, dmu_tx_t *tx) 339efb80947Sahrens { 340efb80947Sahrens dsl_dataset_t *ds = arg1; 341efb80947Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 342efb80947Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 343efb80947Sahrens } 344efb80947Sahrens 345efb80947Sahrens /* ARGSUSED */ 346efb80947Sahrens static int 347efb80947Sahrens replay_full_check(void *arg1, void *arg2, dmu_tx_t *tx) 348efb80947Sahrens { 349efb80947Sahrens dsl_dir_t *dd = arg1; 350efb80947Sahrens struct drr_begin *drrb = arg2; 351efb80947Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 352efb80947Sahrens char *cp; 353efb80947Sahrens uint64_t val; 354efb80947Sahrens int err; 355efb80947Sahrens 356efb80947Sahrens cp = strchr(drrb->drr_toname, '@'); 357efb80947Sahrens *cp = '\0'; 358efb80947Sahrens err = zap_lookup(mos, dd->dd_phys->dd_child_dir_zapobj, 359efb80947Sahrens strrchr(drrb->drr_toname, '/') + 1, 360efb80947Sahrens sizeof (uint64_t), 1, &val); 361efb80947Sahrens *cp = '@'; 362efb80947Sahrens 363efb80947Sahrens if (err != ENOENT) 364efb80947Sahrens return (err ? err : EEXIST); 365efb80947Sahrens 366efb80947Sahrens return (0); 367efb80947Sahrens } 368efb80947Sahrens 369efb80947Sahrens static void 370efb80947Sahrens replay_full_sync(void *arg1, void *arg2, dmu_tx_t *tx) 371efb80947Sahrens { 372efb80947Sahrens dsl_dir_t *dd = arg1; 373efb80947Sahrens struct drr_begin *drrb = arg2; 374efb80947Sahrens char *cp; 375efb80947Sahrens dsl_dataset_t *ds; 376efb80947Sahrens uint64_t dsobj; 377efb80947Sahrens 378efb80947Sahrens cp = strchr(drrb->drr_toname, '@'); 379efb80947Sahrens *cp = '\0'; 380efb80947Sahrens dsobj = dsl_dataset_create_sync(dd, strrchr(drrb->drr_toname, '/') + 1, 381efb80947Sahrens NULL, tx); 382efb80947Sahrens *cp = '@'; 383efb80947Sahrens 384efb80947Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, dsobj, NULL, 385efb80947Sahrens DS_MODE_EXCLUSIVE, FTAG, &ds)); 386efb80947Sahrens 387efb80947Sahrens (void) dmu_objset_create_impl(dsl_dataset_get_spa(ds), 388c717a561Smaybee ds, &ds->ds_phys->ds_bp, drrb->drr_type, tx); 389efb80947Sahrens 390efb80947Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 391efb80947Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 392efb80947Sahrens 393efb80947Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 394efb80947Sahrens } 395efb80947Sahrens 396efb80947Sahrens static int 397efb80947Sahrens replay_end_check(void *arg1, void *arg2, dmu_tx_t *tx) 398efb80947Sahrens { 399efb80947Sahrens objset_t *os = arg1; 400efb80947Sahrens struct drr_begin *drrb = arg2; 401efb80947Sahrens char *snapname; 402efb80947Sahrens 403efb80947Sahrens /* XXX verify that drr_toname is in dd */ 404efb80947Sahrens 405efb80947Sahrens snapname = strchr(drrb->drr_toname, '@'); 406efb80947Sahrens if (snapname == NULL) 407efb80947Sahrens return (EINVAL); 408efb80947Sahrens snapname++; 409efb80947Sahrens 410efb80947Sahrens return (dsl_dataset_snapshot_check(os, snapname, tx)); 411efb80947Sahrens } 412efb80947Sahrens 413efb80947Sahrens static void 414efb80947Sahrens replay_end_sync(void *arg1, void *arg2, dmu_tx_t *tx) 415efb80947Sahrens { 416efb80947Sahrens objset_t *os = arg1; 417efb80947Sahrens struct drr_begin *drrb = arg2; 418efb80947Sahrens char *snapname; 419efb80947Sahrens dsl_dataset_t *ds, *hds; 420efb80947Sahrens 421efb80947Sahrens snapname = strchr(drrb->drr_toname, '@') + 1; 422efb80947Sahrens 423efb80947Sahrens dsl_dataset_snapshot_sync(os, snapname, tx); 424efb80947Sahrens 425efb80947Sahrens /* set snapshot's creation time and guid */ 426efb80947Sahrens hds = os->os->os_dsl_dataset; 427efb80947Sahrens VERIFY(0 == dsl_dataset_open_obj(hds->ds_dir->dd_pool, 428efb80947Sahrens hds->ds_phys->ds_prev_snap_obj, NULL, 429efb80947Sahrens DS_MODE_PRIMARY | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 430efb80947Sahrens FTAG, &ds)); 431efb80947Sahrens 432efb80947Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 433efb80947Sahrens ds->ds_phys->ds_creation_time = drrb->drr_creation_time; 434efb80947Sahrens ds->ds_phys->ds_guid = drrb->drr_toguid; 435efb80947Sahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 436efb80947Sahrens 437efb80947Sahrens dsl_dataset_close(ds, DS_MODE_PRIMARY, FTAG); 438efb80947Sahrens 439efb80947Sahrens dmu_buf_will_dirty(hds->ds_dbuf, tx); 440efb80947Sahrens hds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 441efb80947Sahrens } 442efb80947Sahrens 443efb80947Sahrens static void * 444efb80947Sahrens restore_read(struct restorearg *ra, int len) 445efb80947Sahrens { 446efb80947Sahrens void *rv; 447efb80947Sahrens 448efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 449efb80947Sahrens ASSERT3U(len % 8, ==, 0); 450efb80947Sahrens 451efb80947Sahrens while (ra->buflen - ra->bufoff < len) { 452efb80947Sahrens ssize_t resid; 453efb80947Sahrens int leftover = ra->buflen - ra->bufoff; 454efb80947Sahrens 455efb80947Sahrens (void) memmove(ra->buf, ra->buf + ra->bufoff, leftover); 456efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 457efb80947Sahrens (caddr_t)ra->buf + leftover, ra->bufsize - leftover, 458efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 459efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 460efb80947Sahrens 461efb80947Sahrens ra->voff += ra->bufsize - leftover - resid; 462efb80947Sahrens ra->buflen = ra->bufsize - resid; 463efb80947Sahrens ra->bufoff = 0; 464efb80947Sahrens if (resid == ra->bufsize - leftover) 465efb80947Sahrens ra->err = EINVAL; 466efb80947Sahrens if (ra->err) 467efb80947Sahrens return (NULL); 468efb80947Sahrens /* Could compute checksum here? */ 469efb80947Sahrens } 470efb80947Sahrens 471efb80947Sahrens ASSERT3U(ra->bufoff % 8, ==, 0); 472efb80947Sahrens ASSERT3U(ra->buflen - ra->bufoff, >=, len); 473efb80947Sahrens rv = ra->buf + ra->bufoff; 474efb80947Sahrens ra->bufoff += len; 475efb80947Sahrens if (ra->byteswap) 476efb80947Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->zc); 477efb80947Sahrens else 478efb80947Sahrens fletcher_4_incremental_native(rv, len, &ra->zc); 479efb80947Sahrens return (rv); 480efb80947Sahrens } 481efb80947Sahrens 482efb80947Sahrens static void 483efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 484efb80947Sahrens { 485efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 486efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 487efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 488efb80947Sahrens switch (drr->drr_type) { 489efb80947Sahrens case DRR_BEGIN: 490efb80947Sahrens DO64(drr_begin.drr_magic); 491efb80947Sahrens DO64(drr_begin.drr_version); 492efb80947Sahrens DO64(drr_begin.drr_creation_time); 493efb80947Sahrens DO32(drr_begin.drr_type); 494efb80947Sahrens DO64(drr_begin.drr_toguid); 495efb80947Sahrens DO64(drr_begin.drr_fromguid); 496efb80947Sahrens break; 497efb80947Sahrens case DRR_OBJECT: 498efb80947Sahrens DO64(drr_object.drr_object); 499efb80947Sahrens /* DO64(drr_object.drr_allocation_txg); */ 500efb80947Sahrens DO32(drr_object.drr_type); 501efb80947Sahrens DO32(drr_object.drr_bonustype); 502efb80947Sahrens DO32(drr_object.drr_blksz); 503efb80947Sahrens DO32(drr_object.drr_bonuslen); 504efb80947Sahrens break; 505efb80947Sahrens case DRR_FREEOBJECTS: 506efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 507efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 508efb80947Sahrens break; 509efb80947Sahrens case DRR_WRITE: 510efb80947Sahrens DO64(drr_write.drr_object); 511efb80947Sahrens DO32(drr_write.drr_type); 512efb80947Sahrens DO64(drr_write.drr_offset); 513efb80947Sahrens DO64(drr_write.drr_length); 514efb80947Sahrens break; 515efb80947Sahrens case DRR_FREE: 516efb80947Sahrens DO64(drr_free.drr_object); 517efb80947Sahrens DO64(drr_free.drr_offset); 518efb80947Sahrens DO64(drr_free.drr_length); 519efb80947Sahrens break; 520efb80947Sahrens case DRR_END: 521efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 522efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 523efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 524efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 525efb80947Sahrens break; 526efb80947Sahrens } 527efb80947Sahrens #undef DO64 528efb80947Sahrens #undef DO32 529efb80947Sahrens } 530efb80947Sahrens 531efb80947Sahrens static int 532efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 533efb80947Sahrens { 534efb80947Sahrens int err; 535efb80947Sahrens dmu_tx_t *tx; 536efb80947Sahrens 537efb80947Sahrens err = dmu_object_info(os, drro->drr_object, NULL); 538efb80947Sahrens 539efb80947Sahrens if (err != 0 && err != ENOENT) 540efb80947Sahrens return (EINVAL); 541efb80947Sahrens 542efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 543efb80947Sahrens drro->drr_type >= DMU_OT_NUMTYPES || 544efb80947Sahrens drro->drr_bonustype >= DMU_OT_NUMTYPES || 545efb80947Sahrens drro->drr_checksum >= ZIO_CHECKSUM_FUNCTIONS || 546efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 547efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 548efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 549efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 550efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 551efb80947Sahrens return (EINVAL); 552efb80947Sahrens } 553efb80947Sahrens 554efb80947Sahrens tx = dmu_tx_create(os); 555efb80947Sahrens 556efb80947Sahrens if (err == ENOENT) { 557efb80947Sahrens /* currently free, want to be allocated */ 558efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 559efb80947Sahrens dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, 1); 560efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 561efb80947Sahrens if (err) { 562efb80947Sahrens dmu_tx_abort(tx); 563efb80947Sahrens return (err); 564efb80947Sahrens } 565efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 566efb80947Sahrens drro->drr_type, drro->drr_blksz, 567efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 568efb80947Sahrens } else { 569efb80947Sahrens /* currently allocated, want to be allocated */ 570efb80947Sahrens dmu_tx_hold_bonus(tx, drro->drr_object); 571efb80947Sahrens /* 572efb80947Sahrens * We may change blocksize, so need to 573efb80947Sahrens * hold_write 574efb80947Sahrens */ 575efb80947Sahrens dmu_tx_hold_write(tx, drro->drr_object, 0, 1); 576efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 577efb80947Sahrens if (err) { 578efb80947Sahrens dmu_tx_abort(tx); 579efb80947Sahrens return (err); 580efb80947Sahrens } 581efb80947Sahrens 582efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 583efb80947Sahrens drro->drr_type, drro->drr_blksz, 584efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 585efb80947Sahrens } 586efb80947Sahrens if (err) { 587efb80947Sahrens dmu_tx_commit(tx); 588efb80947Sahrens return (EINVAL); 589efb80947Sahrens } 590efb80947Sahrens 591efb80947Sahrens dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksum, tx); 592efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 593efb80947Sahrens 594efb80947Sahrens if (drro->drr_bonuslen) { 595efb80947Sahrens dmu_buf_t *db; 596efb80947Sahrens void *data; 597efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 598efb80947Sahrens dmu_buf_will_dirty(db, tx); 599efb80947Sahrens 600efb80947Sahrens ASSERT3U(db->db_size, ==, drro->drr_bonuslen); 601efb80947Sahrens data = restore_read(ra, P2ROUNDUP(db->db_size, 8)); 602efb80947Sahrens if (data == NULL) { 603efb80947Sahrens dmu_tx_commit(tx); 604efb80947Sahrens return (ra->err); 605efb80947Sahrens } 606efb80947Sahrens bcopy(data, db->db_data, db->db_size); 607efb80947Sahrens if (ra->byteswap) { 608efb80947Sahrens dmu_ot[drro->drr_bonustype].ot_byteswap(db->db_data, 609efb80947Sahrens drro->drr_bonuslen); 610efb80947Sahrens } 611efb80947Sahrens dmu_buf_rele(db, FTAG); 612efb80947Sahrens } 613efb80947Sahrens dmu_tx_commit(tx); 614efb80947Sahrens return (0); 615efb80947Sahrens } 616efb80947Sahrens 617efb80947Sahrens /* ARGSUSED */ 618efb80947Sahrens static int 619efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 620efb80947Sahrens struct drr_freeobjects *drrfo) 621efb80947Sahrens { 622efb80947Sahrens uint64_t obj; 623efb80947Sahrens 624efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 625efb80947Sahrens return (EINVAL); 626efb80947Sahrens 627efb80947Sahrens for (obj = drrfo->drr_firstobj; 628432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 629432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 630efb80947Sahrens dmu_tx_t *tx; 631efb80947Sahrens int err; 632efb80947Sahrens 633efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 634efb80947Sahrens continue; 635efb80947Sahrens 636efb80947Sahrens tx = dmu_tx_create(os); 637efb80947Sahrens dmu_tx_hold_bonus(tx, obj); 638efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 639efb80947Sahrens if (err) { 640efb80947Sahrens dmu_tx_abort(tx); 641efb80947Sahrens return (err); 642efb80947Sahrens } 643efb80947Sahrens err = dmu_object_free(os, obj, tx); 644efb80947Sahrens dmu_tx_commit(tx); 645efb80947Sahrens if (err && err != ENOENT) 646efb80947Sahrens return (EINVAL); 647efb80947Sahrens } 648efb80947Sahrens return (0); 649efb80947Sahrens } 650efb80947Sahrens 651efb80947Sahrens static int 652efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 653efb80947Sahrens struct drr_write *drrw) 654efb80947Sahrens { 655efb80947Sahrens dmu_tx_t *tx; 656efb80947Sahrens void *data; 657efb80947Sahrens int err; 658efb80947Sahrens 659efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 660efb80947Sahrens drrw->drr_type >= DMU_OT_NUMTYPES) 661efb80947Sahrens return (EINVAL); 662efb80947Sahrens 663efb80947Sahrens data = restore_read(ra, drrw->drr_length); 664efb80947Sahrens if (data == NULL) 665efb80947Sahrens return (ra->err); 666efb80947Sahrens 667efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 668efb80947Sahrens return (EINVAL); 669efb80947Sahrens 670efb80947Sahrens tx = dmu_tx_create(os); 671efb80947Sahrens 672efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 673efb80947Sahrens drrw->drr_offset, drrw->drr_length); 674efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 675efb80947Sahrens if (err) { 676efb80947Sahrens dmu_tx_abort(tx); 677efb80947Sahrens return (err); 678efb80947Sahrens } 679efb80947Sahrens if (ra->byteswap) 680efb80947Sahrens dmu_ot[drrw->drr_type].ot_byteswap(data, drrw->drr_length); 681efb80947Sahrens dmu_write(os, drrw->drr_object, 682efb80947Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 683efb80947Sahrens dmu_tx_commit(tx); 684efb80947Sahrens return (0); 685efb80947Sahrens } 686efb80947Sahrens 687efb80947Sahrens /* ARGSUSED */ 688efb80947Sahrens static int 689efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 690efb80947Sahrens struct drr_free *drrf) 691efb80947Sahrens { 692efb80947Sahrens dmu_tx_t *tx; 693efb80947Sahrens int err; 694efb80947Sahrens 695efb80947Sahrens if (drrf->drr_length != -1ULL && 696efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 697efb80947Sahrens return (EINVAL); 698efb80947Sahrens 699efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 700efb80947Sahrens return (EINVAL); 701efb80947Sahrens 702efb80947Sahrens tx = dmu_tx_create(os); 703efb80947Sahrens 704efb80947Sahrens dmu_tx_hold_free(tx, drrf->drr_object, 705efb80947Sahrens drrf->drr_offset, drrf->drr_length); 706efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 707efb80947Sahrens if (err) { 708efb80947Sahrens dmu_tx_abort(tx); 709efb80947Sahrens return (err); 710efb80947Sahrens } 711efb80947Sahrens err = dmu_free_range(os, drrf->drr_object, 712efb80947Sahrens drrf->drr_offset, drrf->drr_length, tx); 713efb80947Sahrens dmu_tx_commit(tx); 714efb80947Sahrens return (err); 715efb80947Sahrens } 716efb80947Sahrens 717efb80947Sahrens int 718efb80947Sahrens dmu_recvbackup(char *tosnap, struct drr_begin *drrb, uint64_t *sizep, 719efb80947Sahrens boolean_t force, vnode_t *vp, uint64_t voffset) 720efb80947Sahrens { 721efb80947Sahrens struct restorearg ra; 722efb80947Sahrens dmu_replay_record_t *drr; 723efb80947Sahrens char *cp; 724efb80947Sahrens objset_t *os = NULL; 725efb80947Sahrens zio_cksum_t pzc; 726efb80947Sahrens 727efb80947Sahrens bzero(&ra, sizeof (ra)); 728efb80947Sahrens ra.vp = vp; 729efb80947Sahrens ra.voff = voffset; 730efb80947Sahrens ra.bufsize = 1<<20; 731efb80947Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 732efb80947Sahrens 733efb80947Sahrens if (drrb->drr_magic == DMU_BACKUP_MAGIC) { 734efb80947Sahrens ra.byteswap = FALSE; 735efb80947Sahrens } else if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) { 736efb80947Sahrens ra.byteswap = TRUE; 737efb80947Sahrens } else { 738efb80947Sahrens ra.err = EINVAL; 739efb80947Sahrens goto out; 740efb80947Sahrens } 741efb80947Sahrens 742efb80947Sahrens /* 743efb80947Sahrens * NB: this assumes that struct drr_begin will be the largest in 744efb80947Sahrens * dmu_replay_record_t's drr_u, and thus we don't need to pad it 745efb80947Sahrens * with zeros to make it the same length as we wrote out. 746efb80947Sahrens */ 747efb80947Sahrens ((dmu_replay_record_t *)ra.buf)->drr_type = DRR_BEGIN; 748efb80947Sahrens ((dmu_replay_record_t *)ra.buf)->drr_pad = 0; 749efb80947Sahrens ((dmu_replay_record_t *)ra.buf)->drr_u.drr_begin = *drrb; 750efb80947Sahrens if (ra.byteswap) { 751efb80947Sahrens fletcher_4_incremental_byteswap(ra.buf, 752efb80947Sahrens sizeof (dmu_replay_record_t), &ra.zc); 753efb80947Sahrens } else { 754efb80947Sahrens fletcher_4_incremental_native(ra.buf, 755efb80947Sahrens sizeof (dmu_replay_record_t), &ra.zc); 756efb80947Sahrens } 757efb80947Sahrens (void) strcpy(drrb->drr_toname, tosnap); /* for the sync funcs */ 758efb80947Sahrens 759efb80947Sahrens if (ra.byteswap) { 760efb80947Sahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 761efb80947Sahrens drrb->drr_version = BSWAP_64(drrb->drr_version); 762efb80947Sahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 763efb80947Sahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 764efb80947Sahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 765efb80947Sahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 766efb80947Sahrens } 767efb80947Sahrens 768efb80947Sahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 769efb80947Sahrens 770efb80947Sahrens if (drrb->drr_version != DMU_BACKUP_VERSION || 771efb80947Sahrens drrb->drr_type >= DMU_OST_NUMTYPES || 772efb80947Sahrens strchr(drrb->drr_toname, '@') == NULL) { 773efb80947Sahrens ra.err = EINVAL; 774efb80947Sahrens goto out; 775efb80947Sahrens } 776efb80947Sahrens 777efb80947Sahrens /* 778efb80947Sahrens * Process the begin in syncing context. 779efb80947Sahrens */ 780efb80947Sahrens if (drrb->drr_fromguid) { 781efb80947Sahrens /* incremental backup */ 782efb80947Sahrens dsl_dataset_t *ds = NULL; 783efb80947Sahrens 784efb80947Sahrens cp = strchr(tosnap, '@'); 785efb80947Sahrens *cp = '\0'; 786efb80947Sahrens ra.err = dsl_dataset_open(tosnap, DS_MODE_EXCLUSIVE, FTAG, &ds); 787efb80947Sahrens *cp = '@'; 788efb80947Sahrens if (ra.err) 789efb80947Sahrens goto out; 790efb80947Sahrens 791efb80947Sahrens /* 792efb80947Sahrens * Only do the rollback if the most recent snapshot 793efb80947Sahrens * matches the incremental source 794efb80947Sahrens */ 795efb80947Sahrens if (force) { 796a2eea2e1Sahrens if (ds->ds_prev == NULL || 797a2eea2e1Sahrens ds->ds_prev->ds_phys->ds_guid != 798efb80947Sahrens drrb->drr_fromguid) { 799efb80947Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 800*7b5309bbSgw kmem_free(ra.buf, ra.bufsize); 801efb80947Sahrens return (ENODEV); 802efb80947Sahrens } 803efb80947Sahrens (void) dsl_dataset_rollback(ds); 804efb80947Sahrens } 805efb80947Sahrens ra.err = dsl_sync_task_do(ds->ds_dir->dd_pool, 806efb80947Sahrens replay_incremental_check, replay_incremental_sync, 807efb80947Sahrens ds, drrb, 1); 808efb80947Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 809efb80947Sahrens } else { 810efb80947Sahrens /* full backup */ 811efb80947Sahrens dsl_dir_t *dd = NULL; 812efb80947Sahrens const char *tail; 813efb80947Sahrens 814efb80947Sahrens /* can't restore full backup into topmost fs, for now */ 815efb80947Sahrens if (strrchr(drrb->drr_toname, '/') == NULL) { 816efb80947Sahrens ra.err = EINVAL; 817efb80947Sahrens goto out; 818efb80947Sahrens } 819efb80947Sahrens 820efb80947Sahrens cp = strchr(tosnap, '@'); 821efb80947Sahrens *cp = '\0'; 822efb80947Sahrens ra.err = dsl_dir_open(tosnap, FTAG, &dd, &tail); 823efb80947Sahrens *cp = '@'; 824efb80947Sahrens if (ra.err) 825efb80947Sahrens goto out; 826efb80947Sahrens if (tail == NULL) { 827efb80947Sahrens ra.err = EEXIST; 828efb80947Sahrens goto out; 829efb80947Sahrens } 830efb80947Sahrens 831efb80947Sahrens ra.err = dsl_sync_task_do(dd->dd_pool, replay_full_check, 832efb80947Sahrens replay_full_sync, dd, drrb, 5); 833efb80947Sahrens dsl_dir_close(dd, FTAG); 834efb80947Sahrens } 835efb80947Sahrens if (ra.err) 836efb80947Sahrens goto out; 837efb80947Sahrens 838efb80947Sahrens /* 839efb80947Sahrens * Open the objset we are modifying. 840efb80947Sahrens */ 841efb80947Sahrens 842efb80947Sahrens cp = strchr(tosnap, '@'); 843efb80947Sahrens *cp = '\0'; 844efb80947Sahrens ra.err = dmu_objset_open(tosnap, DMU_OST_ANY, 845efb80947Sahrens DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os); 846efb80947Sahrens *cp = '@'; 847efb80947Sahrens ASSERT3U(ra.err, ==, 0); 848efb80947Sahrens 849efb80947Sahrens /* 850efb80947Sahrens * Read records and process them. 851efb80947Sahrens */ 852efb80947Sahrens pzc = ra.zc; 853efb80947Sahrens while (ra.err == 0 && 854efb80947Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 855efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 856efb80947Sahrens ra.err = EINTR; 857efb80947Sahrens goto out; 858efb80947Sahrens } 859efb80947Sahrens 860efb80947Sahrens if (ra.byteswap) 861efb80947Sahrens backup_byteswap(drr); 862efb80947Sahrens 863efb80947Sahrens switch (drr->drr_type) { 864efb80947Sahrens case DRR_OBJECT: 865efb80947Sahrens { 866efb80947Sahrens /* 867efb80947Sahrens * We need to make a copy of the record header, 868efb80947Sahrens * because restore_{object,write} may need to 869efb80947Sahrens * restore_read(), which will invalidate drr. 870efb80947Sahrens */ 871efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 872efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 873efb80947Sahrens break; 874efb80947Sahrens } 875efb80947Sahrens case DRR_FREEOBJECTS: 876efb80947Sahrens { 877efb80947Sahrens struct drr_freeobjects drrfo = 878efb80947Sahrens drr->drr_u.drr_freeobjects; 879efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 880efb80947Sahrens break; 881efb80947Sahrens } 882efb80947Sahrens case DRR_WRITE: 883efb80947Sahrens { 884efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 885efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 886efb80947Sahrens break; 887efb80947Sahrens } 888efb80947Sahrens case DRR_FREE: 889efb80947Sahrens { 890efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 891efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 892efb80947Sahrens break; 893efb80947Sahrens } 894efb80947Sahrens case DRR_END: 895efb80947Sahrens { 896efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 897efb80947Sahrens /* 898efb80947Sahrens * We compare against the *previous* checksum 899efb80947Sahrens * value, because the stored checksum is of 900efb80947Sahrens * everything before the DRR_END record. 901efb80947Sahrens */ 902efb80947Sahrens if (drre.drr_checksum.zc_word[0] != 0 && 9036b4acc8bSahrens !ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pzc)) { 904efb80947Sahrens ra.err = ECKSUM; 905efb80947Sahrens goto out; 906efb80947Sahrens } 907efb80947Sahrens 908efb80947Sahrens ra.err = dsl_sync_task_do(dmu_objset_ds(os)-> 909efb80947Sahrens ds_dir->dd_pool, replay_end_check, replay_end_sync, 910efb80947Sahrens os, drrb, 3); 911efb80947Sahrens goto out; 912efb80947Sahrens } 913efb80947Sahrens default: 914efb80947Sahrens ra.err = EINVAL; 915efb80947Sahrens goto out; 916efb80947Sahrens } 917efb80947Sahrens pzc = ra.zc; 918efb80947Sahrens } 919efb80947Sahrens 920efb80947Sahrens out: 921efb80947Sahrens if (os) 922efb80947Sahrens dmu_objset_close(os); 923efb80947Sahrens 924efb80947Sahrens /* 925efb80947Sahrens * Make sure we don't rollback/destroy unless we actually 926efb80947Sahrens * processed the begin properly. 'os' will only be set if this 927efb80947Sahrens * is the case. 928efb80947Sahrens */ 929efb80947Sahrens if (ra.err && os && tosnap && strchr(tosnap, '@')) { 930efb80947Sahrens /* 931efb80947Sahrens * rollback or destroy what we created, so we don't 932efb80947Sahrens * leave it in the restoring state. 933efb80947Sahrens */ 934efb80947Sahrens dsl_dataset_t *ds; 935efb80947Sahrens int err; 936efb80947Sahrens 937efb80947Sahrens cp = strchr(tosnap, '@'); 938efb80947Sahrens *cp = '\0'; 939efb80947Sahrens err = dsl_dataset_open(tosnap, 940efb80947Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, 941efb80947Sahrens FTAG, &ds); 942efb80947Sahrens if (err == 0) { 943efb80947Sahrens txg_wait_synced(ds->ds_dir->dd_pool, 0); 944efb80947Sahrens if (drrb->drr_fromguid) { 945efb80947Sahrens /* incremental: rollback to most recent snap */ 946efb80947Sahrens (void) dsl_dataset_rollback(ds); 947efb80947Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 948efb80947Sahrens } else { 949efb80947Sahrens /* full: destroy whole fs */ 950efb80947Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 951efb80947Sahrens (void) dsl_dataset_destroy(tosnap); 952efb80947Sahrens } 953efb80947Sahrens } 954efb80947Sahrens *cp = '@'; 955efb80947Sahrens } 956efb80947Sahrens 957efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 958efb80947Sahrens if (sizep) 959efb80947Sahrens *sizep = ra.voff; 960efb80947Sahrens return (ra.err); 961efb80947Sahrens } 962