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