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 /* 22dc7cd546SMark Shellenbaum * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23ec5cf9d5SAlexander Stetsenko * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24be6fd75aSMatthew Ahrens * Copyright (c) 2013 by Delphix. All rights reserved. 25*a2afb611SJerry Jelinek * Copyright (c) 2014, Joyent, Inc. All rights reserved. 26ec5cf9d5SAlexander Stetsenko */ 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> 3892241e0bSTom Erickson #include <sys/dsl_prop.h> 39efb80947Sahrens #include <sys/dsl_pool.h> 40efb80947Sahrens #include <sys/dsl_synctask.h> 41efb80947Sahrens #include <sys/zfs_ioctl.h> 42efb80947Sahrens #include <sys/zap.h> 43efb80947Sahrens #include <sys/zio_checksum.h> 44dc7cd546SMark Shellenbaum #include <sys/zfs_znode.h> 45cde58dbcSMatthew Ahrens #include <zfs_fletcher.h> 469e69d7d0SLori Alt #include <sys/avl.h> 478e714474SLori Alt #include <sys/ddt.h> 48c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 493b2aab18SMatthew Ahrens #include <sys/dmu_send.h> 503b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 5178f17100SMatthew Ahrens #include <sys/dsl_bookmark.h> 52efb80947Sahrens 5319b94df9SMatthew Ahrens /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 5419b94df9SMatthew Ahrens int zfs_send_corrupt_data = B_FALSE; 5519b94df9SMatthew Ahrens 563cb34c60Sahrens static char *dmu_recv_tag = "dmu_recv_tag"; 573b2aab18SMatthew Ahrens static const char *recv_clone_name = "%recv"; 583cb34c60Sahrens 59efb80947Sahrens static int 604e3c9f44SBill Pijewski dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 61efb80947Sahrens { 624e3c9f44SBill Pijewski dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 63efb80947Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 64fb09f5aaSMadhav Suresh ASSERT0(len % 8); 65efb80947Sahrens 664e3c9f44SBill Pijewski fletcher_4_incremental_native(buf, len, &dsp->dsa_zc); 674e3c9f44SBill Pijewski dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp, 68efb80947Sahrens (caddr_t)buf, len, 69efb80947Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 704e3c9f44SBill Pijewski 714e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 724e3c9f44SBill Pijewski *dsp->dsa_off += len; 734e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 744e3c9f44SBill Pijewski 754e3c9f44SBill Pijewski return (dsp->dsa_err); 76efb80947Sahrens } 77efb80947Sahrens 78efb80947Sahrens static int 794e3c9f44SBill Pijewski dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 80efb80947Sahrens uint64_t length) 81efb80947Sahrens { 824e3c9f44SBill Pijewski struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free); 839e69d7d0SLori Alt 842f3d8780SMatthew Ahrens /* 852f3d8780SMatthew Ahrens * When we receive a free record, dbuf_free_range() assumes 862f3d8780SMatthew Ahrens * that the receiving system doesn't have any dbufs in the range 872f3d8780SMatthew Ahrens * being freed. This is always true because there is a one-record 882f3d8780SMatthew Ahrens * constraint: we only send one WRITE record for any given 892f3d8780SMatthew Ahrens * object+offset. We know that the one-record constraint is 902f3d8780SMatthew Ahrens * true because we always send data in increasing order by 912f3d8780SMatthew Ahrens * object,offset. 922f3d8780SMatthew Ahrens * 932f3d8780SMatthew Ahrens * If the increasing-order constraint ever changes, we should find 942f3d8780SMatthew Ahrens * another way to assert that the one-record constraint is still 952f3d8780SMatthew Ahrens * satisfied. 962f3d8780SMatthew Ahrens */ 972f3d8780SMatthew Ahrens ASSERT(object > dsp->dsa_last_data_object || 982f3d8780SMatthew Ahrens (object == dsp->dsa_last_data_object && 992f3d8780SMatthew Ahrens offset > dsp->dsa_last_data_offset)); 1002f3d8780SMatthew Ahrens 1012f3d8780SMatthew Ahrens /* 1022f3d8780SMatthew Ahrens * If we are doing a non-incremental send, then there can't 1032f3d8780SMatthew Ahrens * be any data in the dataset we're receiving into. Therefore 1042f3d8780SMatthew Ahrens * a free record would simply be a no-op. Save space by not 1052f3d8780SMatthew Ahrens * sending it to begin with. 1062f3d8780SMatthew Ahrens */ 1072f3d8780SMatthew Ahrens if (!dsp->dsa_incremental) 1082f3d8780SMatthew Ahrens return (0); 1092f3d8780SMatthew Ahrens 110534029e5SSimon Klinkert if (length != -1ULL && offset + length < offset) 111534029e5SSimon Klinkert length = -1ULL; 112534029e5SSimon Klinkert 1139e69d7d0SLori Alt /* 1149e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREE, push it out, 1159e69d7d0SLori Alt * since free block aggregation can only be done for blocks of the 1169e69d7d0SLori Alt * same type (i.e., DRR_FREE records can only be aggregated with 1179e69d7d0SLori Alt * other DRR_FREE records. DRR_FREEOBJECTS records can only be 1189e69d7d0SLori Alt * aggregated with other DRR_FREEOBJECTS records. 1199e69d7d0SLori Alt */ 1204e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 1214e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREE) { 1224e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1234e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 124be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1254e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1269e69d7d0SLori Alt } 1279e69d7d0SLori Alt 1284e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREE) { 1299e69d7d0SLori Alt /* 1309e69d7d0SLori Alt * There should never be a PENDING_FREE if length is -1 1319e69d7d0SLori Alt * (because dump_dnode is the only place where this 1329e69d7d0SLori Alt * function is called with a -1, and only after flushing 1339e69d7d0SLori Alt * any pending record). 1349e69d7d0SLori Alt */ 1359e69d7d0SLori Alt ASSERT(length != -1ULL); 1369e69d7d0SLori Alt /* 1379e69d7d0SLori Alt * Check to see whether this free block can be aggregated 1389e69d7d0SLori Alt * with pending one. 1399e69d7d0SLori Alt */ 1409e69d7d0SLori Alt if (drrf->drr_object == object && drrf->drr_offset + 1419e69d7d0SLori Alt drrf->drr_length == offset) { 1429e69d7d0SLori Alt drrf->drr_length += length; 1439e69d7d0SLori Alt return (0); 1449e69d7d0SLori Alt } else { 1459e69d7d0SLori Alt /* not a continuation. Push out pending record */ 1464e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1479e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 148be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1494e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1509e69d7d0SLori Alt } 1519e69d7d0SLori Alt } 1529e69d7d0SLori Alt /* create a FREE record and make it pending */ 1534e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 1544e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREE; 1559e69d7d0SLori Alt drrf->drr_object = object; 1569e69d7d0SLori Alt drrf->drr_offset = offset; 1579e69d7d0SLori Alt drrf->drr_length = length; 1584e3c9f44SBill Pijewski drrf->drr_toguid = dsp->dsa_toguid; 1599e69d7d0SLori Alt if (length == -1ULL) { 1604e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1614e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 162be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1639e69d7d0SLori Alt } else { 1644e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREE; 1659e69d7d0SLori Alt } 166efb80947Sahrens 167efb80947Sahrens return (0); 168efb80947Sahrens } 169efb80947Sahrens 170efb80947Sahrens static int 1714e3c9f44SBill Pijewski dump_data(dmu_sendarg_t *dsp, dmu_object_type_t type, 1728e714474SLori Alt uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) 173efb80947Sahrens { 1744e3c9f44SBill Pijewski struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write); 1759e69d7d0SLori Alt 1762f3d8780SMatthew Ahrens /* 1772f3d8780SMatthew Ahrens * We send data in increasing object, offset order. 1782f3d8780SMatthew Ahrens * See comment in dump_free() for details. 1792f3d8780SMatthew Ahrens */ 1802f3d8780SMatthew Ahrens ASSERT(object > dsp->dsa_last_data_object || 1812f3d8780SMatthew Ahrens (object == dsp->dsa_last_data_object && 1822f3d8780SMatthew Ahrens offset > dsp->dsa_last_data_offset)); 1832f3d8780SMatthew Ahrens dsp->dsa_last_data_object = object; 1842f3d8780SMatthew Ahrens dsp->dsa_last_data_offset = offset + blksz - 1; 1858e714474SLori Alt 1869e69d7d0SLori Alt /* 1879e69d7d0SLori Alt * If there is any kind of pending aggregation (currently either 1889e69d7d0SLori Alt * a grouping of free objects or free blocks), push it out to 1899e69d7d0SLori Alt * the stream, since aggregation can't be done across operations 1909e69d7d0SLori Alt * of different types. 1919e69d7d0SLori Alt */ 1924e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 1934e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1944e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 195be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1964e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1979e69d7d0SLori Alt } 198efb80947Sahrens /* write a DATA record */ 1994e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2004e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_WRITE; 2019e69d7d0SLori Alt drrw->drr_object = object; 2029e69d7d0SLori Alt drrw->drr_type = type; 2039e69d7d0SLori Alt drrw->drr_offset = offset; 2049e69d7d0SLori Alt drrw->drr_length = blksz; 2054e3c9f44SBill Pijewski drrw->drr_toguid = dsp->dsa_toguid; 2068e714474SLori Alt drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); 2078e714474SLori Alt if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) 2088e714474SLori Alt drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; 2098e714474SLori Alt DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); 2108e714474SLori Alt DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); 2118e714474SLori Alt DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); 2128e714474SLori Alt drrw->drr_key.ddk_cksum = bp->blk_cksum; 213efb80947Sahrens 2144e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 215be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2164e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz) != 0) 217be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 218efb80947Sahrens return (0); 219efb80947Sahrens } 220efb80947Sahrens 2210a586ceaSMark Shellenbaum static int 2224e3c9f44SBill Pijewski dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data) 2230a586ceaSMark Shellenbaum { 2244e3c9f44SBill Pijewski struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill); 2250a586ceaSMark Shellenbaum 2264e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 2274e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2284e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 229be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2304e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2310a586ceaSMark Shellenbaum } 2320a586ceaSMark Shellenbaum 2330a586ceaSMark Shellenbaum /* write a SPILL record */ 2344e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2354e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_SPILL; 2360a586ceaSMark Shellenbaum drrs->drr_object = object; 2370a586ceaSMark Shellenbaum drrs->drr_length = blksz; 2384e3c9f44SBill Pijewski drrs->drr_toguid = dsp->dsa_toguid; 2390a586ceaSMark Shellenbaum 2404e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t))) 241be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2424e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz)) 243be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2440a586ceaSMark Shellenbaum return (0); 2450a586ceaSMark Shellenbaum } 2460a586ceaSMark Shellenbaum 247efb80947Sahrens static int 2484e3c9f44SBill Pijewski dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs) 249efb80947Sahrens { 2504e3c9f44SBill Pijewski struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects); 2519e69d7d0SLori Alt 2522f3d8780SMatthew Ahrens /* See comment in dump_free(). */ 2532f3d8780SMatthew Ahrens if (!dsp->dsa_incremental) 2542f3d8780SMatthew Ahrens return (0); 2552f3d8780SMatthew Ahrens 2569e69d7d0SLori Alt /* 2579e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREEOBJECTS, 2589e69d7d0SLori Alt * push it out, since free block aggregation can only be done for 2599e69d7d0SLori Alt * blocks of the same type (i.e., DRR_FREE records can only be 2609e69d7d0SLori Alt * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records 2619e69d7d0SLori Alt * can only be aggregated with other DRR_FREEOBJECTS records. 2629e69d7d0SLori Alt */ 2634e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 2644e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREEOBJECTS) { 2654e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2664e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 267be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2684e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2699e69d7d0SLori Alt } 2704e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) { 2719e69d7d0SLori Alt /* 2729e69d7d0SLori Alt * See whether this free object array can be aggregated 2739e69d7d0SLori Alt * with pending one 2749e69d7d0SLori Alt */ 2759e69d7d0SLori Alt if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { 2769e69d7d0SLori Alt drrfo->drr_numobjs += numobjs; 2779e69d7d0SLori Alt return (0); 2789e69d7d0SLori Alt } else { 2799e69d7d0SLori Alt /* can't be aggregated. Push out pending record */ 2804e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2819e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 282be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2834e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2849e69d7d0SLori Alt } 2859e69d7d0SLori Alt } 2869e69d7d0SLori Alt 287efb80947Sahrens /* write a FREEOBJECTS record */ 2884e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2894e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREEOBJECTS; 2909e69d7d0SLori Alt drrfo->drr_firstobj = firstobj; 2919e69d7d0SLori Alt drrfo->drr_numobjs = numobjs; 2924e3c9f44SBill Pijewski drrfo->drr_toguid = dsp->dsa_toguid; 2939e69d7d0SLori Alt 2944e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREEOBJECTS; 295efb80947Sahrens 296efb80947Sahrens return (0); 297efb80947Sahrens } 298efb80947Sahrens 299efb80947Sahrens static int 3004e3c9f44SBill Pijewski dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp) 301efb80947Sahrens { 3024e3c9f44SBill Pijewski struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object); 3039e69d7d0SLori Alt 304efb80947Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 3054e3c9f44SBill Pijewski return (dump_freeobjects(dsp, object, 1)); 306efb80947Sahrens 3074e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 3084e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3094e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 310be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3114e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3129e69d7d0SLori Alt } 3139e69d7d0SLori Alt 314efb80947Sahrens /* write an OBJECT record */ 3154e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 3164e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_OBJECT; 3179e69d7d0SLori Alt drro->drr_object = object; 3189e69d7d0SLori Alt drro->drr_type = dnp->dn_type; 3199e69d7d0SLori Alt drro->drr_bonustype = dnp->dn_bonustype; 3209e69d7d0SLori Alt drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 3219e69d7d0SLori Alt drro->drr_bonuslen = dnp->dn_bonuslen; 3229e69d7d0SLori Alt drro->drr_checksumtype = dnp->dn_checksum; 3239e69d7d0SLori Alt drro->drr_compress = dnp->dn_compress; 3244e3c9f44SBill Pijewski drro->drr_toguid = dsp->dsa_toguid; 3259e69d7d0SLori Alt 3264e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 327be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 328efb80947Sahrens 3294e3c9f44SBill Pijewski if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 330be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 331efb80947Sahrens 3322f3d8780SMatthew Ahrens /* Free anything past the end of the file. */ 3334e3c9f44SBill Pijewski if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 3342f3d8780SMatthew Ahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL) != 0) 335be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3363b2aab18SMatthew Ahrens if (dsp->dsa_err != 0) 337be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 338efb80947Sahrens return (0); 339efb80947Sahrens } 340efb80947Sahrens 341efb80947Sahrens #define BP_SPAN(dnp, level) \ 342efb80947Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 343efb80947Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 344efb80947Sahrens 345b24ab676SJeff Bonwick /* ARGSUSED */ 346efb80947Sahrens static int 3471b912ec7SGeorge Wilson backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 348b24ab676SJeff Bonwick const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 349efb80947Sahrens { 3504e3c9f44SBill Pijewski dmu_sendarg_t *dsp = arg; 351efb80947Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 352efb80947Sahrens int err = 0; 353efb80947Sahrens 354efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 355be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 356efb80947Sahrens 357b24ab676SJeff Bonwick if (zb->zb_object != DMU_META_DNODE_OBJECT && 358b24ab676SJeff Bonwick DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 35914843421SMatthew Ahrens return (0); 36078f17100SMatthew Ahrens } else if (zb->zb_level == ZB_ZIL_LEVEL) { 36178f17100SMatthew Ahrens /* 36278f17100SMatthew Ahrens * If we are sending a non-snapshot (which is allowed on 36378f17100SMatthew Ahrens * read-only pools), it may have a ZIL, which must be ignored. 36478f17100SMatthew Ahrens */ 36578f17100SMatthew Ahrens return (0); 36643466aaeSMax Grossman } else if (BP_IS_HOLE(bp) && 36743466aaeSMax Grossman zb->zb_object == DMU_META_DNODE_OBJECT) { 36888b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 36988b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 3704e3c9f44SBill Pijewski err = dump_freeobjects(dsp, dnobj, span >> DNODE_SHIFT); 37143466aaeSMax Grossman } else if (BP_IS_HOLE(bp)) { 37288b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 3734e3c9f44SBill Pijewski err = dump_free(dsp, zb->zb_object, zb->zb_blkid * span, span); 37488b7b0f2SMatthew Ahrens } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 37588b7b0f2SMatthew Ahrens return (0); 37688b7b0f2SMatthew Ahrens } else if (type == DMU_OT_DNODE) { 37788b7b0f2SMatthew Ahrens dnode_phys_t *blk; 378efb80947Sahrens int i; 379efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 38088b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 38188b7b0f2SMatthew Ahrens arc_buf_t *abuf; 382efb80947Sahrens 3831b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 3841b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 3851b912ec7SGeorge Wilson &aflags, zb) != 0) 386be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 38788b7b0f2SMatthew Ahrens 38888b7b0f2SMatthew Ahrens blk = abuf->b_data; 389efb80947Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 39088b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid << 39188b7b0f2SMatthew Ahrens (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 3924e3c9f44SBill Pijewski err = dump_dnode(dsp, dnobj, blk+i); 3933b2aab18SMatthew Ahrens if (err != 0) 394efb80947Sahrens break; 395efb80947Sahrens } 39688b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 3970a586ceaSMark Shellenbaum } else if (type == DMU_OT_SA) { 3980a586ceaSMark Shellenbaum uint32_t aflags = ARC_WAIT; 3990a586ceaSMark Shellenbaum arc_buf_t *abuf; 4000a586ceaSMark Shellenbaum int blksz = BP_GET_LSIZE(bp); 4010a586ceaSMark Shellenbaum 4021b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4031b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4041b912ec7SGeorge Wilson &aflags, zb) != 0) 405be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 4060a586ceaSMark Shellenbaum 4074e3c9f44SBill Pijewski err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data); 4080a586ceaSMark Shellenbaum (void) arc_buf_remove_ref(abuf, &abuf); 40988b7b0f2SMatthew Ahrens } else { /* it's a level-0 block of a regular object */ 41088b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 41188b7b0f2SMatthew Ahrens arc_buf_t *abuf; 412efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 41388b7b0f2SMatthew Ahrens 41478f17100SMatthew Ahrens ASSERT0(zb->zb_level); 4151b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4161b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4171b912ec7SGeorge Wilson &aflags, zb) != 0) { 41819b94df9SMatthew Ahrens if (zfs_send_corrupt_data) { 41919b94df9SMatthew Ahrens /* Send a block filled with 0x"zfs badd bloc" */ 42019b94df9SMatthew Ahrens abuf = arc_buf_alloc(spa, blksz, &abuf, 42119b94df9SMatthew Ahrens ARC_BUFC_DATA); 42219b94df9SMatthew Ahrens uint64_t *ptr; 42319b94df9SMatthew Ahrens for (ptr = abuf->b_data; 42419b94df9SMatthew Ahrens (char *)ptr < (char *)abuf->b_data + blksz; 42519b94df9SMatthew Ahrens ptr++) 42619b94df9SMatthew Ahrens *ptr = 0x2f5baddb10c; 42719b94df9SMatthew Ahrens } else { 428be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 42919b94df9SMatthew Ahrens } 43019b94df9SMatthew Ahrens } 43188b7b0f2SMatthew Ahrens 4324e3c9f44SBill Pijewski err = dump_data(dsp, type, zb->zb_object, zb->zb_blkid * blksz, 4338e714474SLori Alt blksz, bp, abuf->b_data); 43488b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 435efb80947Sahrens } 436efb80947Sahrens 437efb80947Sahrens ASSERT(err == 0 || err == EINTR); 438efb80947Sahrens return (err); 439efb80947Sahrens } 440efb80947Sahrens 4414445fffbSMatthew Ahrens /* 44278f17100SMatthew Ahrens * Releases dp using the specified tag. 4434445fffbSMatthew Ahrens */ 4443b2aab18SMatthew Ahrens static int 4453b2aab18SMatthew Ahrens dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds, 44678f17100SMatthew Ahrens zfs_bookmark_phys_t *fromzb, boolean_t is_clone, int outfd, 44778f17100SMatthew Ahrens vnode_t *vp, offset_t *off) 448efb80947Sahrens { 4493b2aab18SMatthew Ahrens objset_t *os; 450efb80947Sahrens dmu_replay_record_t *drr; 4514e3c9f44SBill Pijewski dmu_sendarg_t *dsp; 452efb80947Sahrens int err; 4533cb34c60Sahrens uint64_t fromtxg = 0; 454efb80947Sahrens 4553b2aab18SMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 4563b2aab18SMatthew Ahrens if (err != 0) { 4573b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 4583b2aab18SMatthew Ahrens return (err); 4593b2aab18SMatthew Ahrens } 460efb80947Sahrens 461efb80947Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 462efb80947Sahrens drr->drr_type = DRR_BEGIN; 463efb80947Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 4649e69d7d0SLori Alt DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 4659e69d7d0SLori Alt DMU_SUBSTREAM); 466dc7cd546SMark Shellenbaum 467dc7cd546SMark Shellenbaum #ifdef _KERNEL 4683b2aab18SMatthew Ahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 469dc7cd546SMark Shellenbaum uint64_t version; 4703b2aab18SMatthew Ahrens if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) { 4714e3c9f44SBill Pijewski kmem_free(drr, sizeof (dmu_replay_record_t)); 4723b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 473be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 4744e3c9f44SBill Pijewski } 4753b2aab18SMatthew Ahrens if (version >= ZPL_VERSION_SA) { 476dc7cd546SMark Shellenbaum DMU_SET_FEATUREFLAGS( 477dc7cd546SMark Shellenbaum drr->drr_u.drr_begin.drr_versioninfo, 478dc7cd546SMark Shellenbaum DMU_BACKUP_FEATURE_SA_SPILL); 479dc7cd546SMark Shellenbaum } 480dc7cd546SMark Shellenbaum } 481dc7cd546SMark Shellenbaum #endif 482dc7cd546SMark Shellenbaum 483efb80947Sahrens drr->drr_u.drr_begin.drr_creation_time = 484efb80947Sahrens ds->ds_phys->ds_creation_time; 4853b2aab18SMatthew Ahrens drr->drr_u.drr_begin.drr_type = dmu_objset_type(os); 48678f17100SMatthew Ahrens if (is_clone) 4873cb34c60Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 488efb80947Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 489ab04eb8eStimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 490ab04eb8eStimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 491ab04eb8eStimh 49278f17100SMatthew Ahrens if (fromzb != NULL) { 49378f17100SMatthew Ahrens drr->drr_u.drr_begin.drr_fromguid = fromzb->zbm_guid; 49478f17100SMatthew Ahrens fromtxg = fromzb->zbm_creation_txg; 49578f17100SMatthew Ahrens } 496efb80947Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 49778f17100SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 49878f17100SMatthew Ahrens (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--", 49978f17100SMatthew Ahrens sizeof (drr->drr_u.drr_begin.drr_toname)); 5003b2aab18SMatthew Ahrens } 5013cb34c60Sahrens 5024e3c9f44SBill Pijewski dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 5034e3c9f44SBill Pijewski 5044e3c9f44SBill Pijewski dsp->dsa_drr = drr; 5054e3c9f44SBill Pijewski dsp->dsa_vp = vp; 5064e3c9f44SBill Pijewski dsp->dsa_outfd = outfd; 5074e3c9f44SBill Pijewski dsp->dsa_proc = curproc; 5083b2aab18SMatthew Ahrens dsp->dsa_os = os; 5094e3c9f44SBill Pijewski dsp->dsa_off = off; 5104e3c9f44SBill Pijewski dsp->dsa_toguid = ds->ds_phys->ds_guid; 5114e3c9f44SBill Pijewski ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 5124e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 51378f17100SMatthew Ahrens dsp->dsa_incremental = (fromzb != NULL); 5144e3c9f44SBill Pijewski 5154e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 5164e3c9f44SBill Pijewski list_insert_head(&ds->ds_sendstreams, dsp); 5174e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 5184e3c9f44SBill Pijewski 519de8d9cffSMatthew Ahrens dsl_dataset_long_hold(ds, FTAG); 520de8d9cffSMatthew Ahrens dsl_pool_rele(dp, tag); 521de8d9cffSMatthew Ahrens 5224e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 5234e3c9f44SBill Pijewski err = dsp->dsa_err; 5244e3c9f44SBill Pijewski goto out; 525efb80947Sahrens } 526efb80947Sahrens 52788b7b0f2SMatthew Ahrens err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 5284e3c9f44SBill Pijewski backup_cb, dsp); 529efb80947Sahrens 5304e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) 5314e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 532be6fd75aSMatthew Ahrens err = SET_ERROR(EINTR); 5339e69d7d0SLori Alt 5343b2aab18SMatthew Ahrens if (err != 0) { 5353b2aab18SMatthew Ahrens if (err == EINTR && dsp->dsa_err != 0) 5364e3c9f44SBill Pijewski err = dsp->dsa_err; 5374e3c9f44SBill Pijewski goto out; 538efb80947Sahrens } 539efb80947Sahrens 540efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 541efb80947Sahrens drr->drr_type = DRR_END; 5424e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 5434e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; 544efb80947Sahrens 5454e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 5464e3c9f44SBill Pijewski err = dsp->dsa_err; 5474e3c9f44SBill Pijewski goto out; 5487b5309bbSgw } 549efb80947Sahrens 5504e3c9f44SBill Pijewski out: 5514e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 5524e3c9f44SBill Pijewski list_remove(&ds->ds_sendstreams, dsp); 5534e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 5544e3c9f44SBill Pijewski 555efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 5564e3c9f44SBill Pijewski kmem_free(dsp, sizeof (dmu_sendarg_t)); 557efb80947Sahrens 5583b2aab18SMatthew Ahrens dsl_dataset_long_rele(ds, FTAG); 5593b2aab18SMatthew Ahrens 5604e3c9f44SBill Pijewski return (err); 561efb80947Sahrens } 562efb80947Sahrens 56319b94df9SMatthew Ahrens int 5643b2aab18SMatthew Ahrens dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, 5653b2aab18SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 5663b2aab18SMatthew Ahrens { 5673b2aab18SMatthew Ahrens dsl_pool_t *dp; 5683b2aab18SMatthew Ahrens dsl_dataset_t *ds; 5693b2aab18SMatthew Ahrens dsl_dataset_t *fromds = NULL; 5703b2aab18SMatthew Ahrens int err; 5713b2aab18SMatthew Ahrens 5723b2aab18SMatthew Ahrens err = dsl_pool_hold(pool, FTAG, &dp); 5733b2aab18SMatthew Ahrens if (err != 0) 5743b2aab18SMatthew Ahrens return (err); 5753b2aab18SMatthew Ahrens 5763b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds); 5773b2aab18SMatthew Ahrens if (err != 0) { 5783b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 5793b2aab18SMatthew Ahrens return (err); 5803b2aab18SMatthew Ahrens } 5813b2aab18SMatthew Ahrens 5823b2aab18SMatthew Ahrens if (fromsnap != 0) { 58378f17100SMatthew Ahrens zfs_bookmark_phys_t zb; 58478f17100SMatthew Ahrens boolean_t is_clone; 58578f17100SMatthew Ahrens 5863b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds); 5873b2aab18SMatthew Ahrens if (err != 0) { 5883b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 5893b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 5903b2aab18SMatthew Ahrens return (err); 5913b2aab18SMatthew Ahrens } 59278f17100SMatthew Ahrens if (!dsl_dataset_is_before(ds, fromds, 0)) 59378f17100SMatthew Ahrens err = SET_ERROR(EXDEV); 59478f17100SMatthew Ahrens zb.zbm_creation_time = fromds->ds_phys->ds_creation_time; 59578f17100SMatthew Ahrens zb.zbm_creation_txg = fromds->ds_phys->ds_creation_txg; 59678f17100SMatthew Ahrens zb.zbm_guid = fromds->ds_phys->ds_guid; 59778f17100SMatthew Ahrens is_clone = (fromds->ds_dir != ds->ds_dir); 59878f17100SMatthew Ahrens dsl_dataset_rele(fromds, FTAG); 59978f17100SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone, 60078f17100SMatthew Ahrens outfd, vp, off); 60178f17100SMatthew Ahrens } else { 60278f17100SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE, 60378f17100SMatthew Ahrens outfd, vp, off); 6043b2aab18SMatthew Ahrens } 60578f17100SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 60678f17100SMatthew Ahrens return (err); 6073b2aab18SMatthew Ahrens } 6083b2aab18SMatthew Ahrens 6093b2aab18SMatthew Ahrens int 6103b2aab18SMatthew Ahrens dmu_send(const char *tosnap, const char *fromsnap, 6113b2aab18SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 6123b2aab18SMatthew Ahrens { 6133b2aab18SMatthew Ahrens dsl_pool_t *dp; 6143b2aab18SMatthew Ahrens dsl_dataset_t *ds; 6153b2aab18SMatthew Ahrens int err; 61678f17100SMatthew Ahrens boolean_t owned = B_FALSE; 6173b2aab18SMatthew Ahrens 61878f17100SMatthew Ahrens if (fromsnap != NULL && strpbrk(fromsnap, "@#") == NULL) 619be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 6203b2aab18SMatthew Ahrens 6213b2aab18SMatthew Ahrens err = dsl_pool_hold(tosnap, FTAG, &dp); 6223b2aab18SMatthew Ahrens if (err != 0) 6233b2aab18SMatthew Ahrens return (err); 6243b2aab18SMatthew Ahrens 62578f17100SMatthew Ahrens if (strchr(tosnap, '@') == NULL && spa_writeable(dp->dp_spa)) { 62678f17100SMatthew Ahrens /* 62778f17100SMatthew Ahrens * We are sending a filesystem or volume. Ensure 62878f17100SMatthew Ahrens * that it doesn't change by owning the dataset. 62978f17100SMatthew Ahrens */ 63078f17100SMatthew Ahrens err = dsl_dataset_own(dp, tosnap, FTAG, &ds); 63178f17100SMatthew Ahrens owned = B_TRUE; 63278f17100SMatthew Ahrens } else { 63378f17100SMatthew Ahrens err = dsl_dataset_hold(dp, tosnap, FTAG, &ds); 63478f17100SMatthew Ahrens } 6353b2aab18SMatthew Ahrens if (err != 0) { 6363b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 6373b2aab18SMatthew Ahrens return (err); 6383b2aab18SMatthew Ahrens } 6393b2aab18SMatthew Ahrens 6403b2aab18SMatthew Ahrens if (fromsnap != NULL) { 64178f17100SMatthew Ahrens zfs_bookmark_phys_t zb; 64278f17100SMatthew Ahrens boolean_t is_clone = B_FALSE; 64378f17100SMatthew Ahrens int fsnamelen = strchr(tosnap, '@') - tosnap; 64478f17100SMatthew Ahrens 64578f17100SMatthew Ahrens /* 64678f17100SMatthew Ahrens * If the fromsnap is in a different filesystem, then 64778f17100SMatthew Ahrens * mark the send stream as a clone. 64878f17100SMatthew Ahrens */ 64978f17100SMatthew Ahrens if (strncmp(tosnap, fromsnap, fsnamelen) != 0 || 65078f17100SMatthew Ahrens (fromsnap[fsnamelen] != '@' && 65178f17100SMatthew Ahrens fromsnap[fsnamelen] != '#')) { 65278f17100SMatthew Ahrens is_clone = B_TRUE; 65378f17100SMatthew Ahrens } 65478f17100SMatthew Ahrens 65578f17100SMatthew Ahrens if (strchr(fromsnap, '@')) { 65678f17100SMatthew Ahrens dsl_dataset_t *fromds; 65778f17100SMatthew Ahrens err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds); 65878f17100SMatthew Ahrens if (err == 0) { 65978f17100SMatthew Ahrens if (!dsl_dataset_is_before(ds, fromds, 0)) 66078f17100SMatthew Ahrens err = SET_ERROR(EXDEV); 66178f17100SMatthew Ahrens zb.zbm_creation_time = 66278f17100SMatthew Ahrens fromds->ds_phys->ds_creation_time; 66378f17100SMatthew Ahrens zb.zbm_creation_txg = 66478f17100SMatthew Ahrens fromds->ds_phys->ds_creation_txg; 66578f17100SMatthew Ahrens zb.zbm_guid = fromds->ds_phys->ds_guid; 66678f17100SMatthew Ahrens is_clone = (ds->ds_dir != fromds->ds_dir); 66778f17100SMatthew Ahrens dsl_dataset_rele(fromds, FTAG); 66878f17100SMatthew Ahrens } 66978f17100SMatthew Ahrens } else { 67078f17100SMatthew Ahrens err = dsl_bookmark_lookup(dp, fromsnap, ds, &zb); 67178f17100SMatthew Ahrens } 6723b2aab18SMatthew Ahrens if (err != 0) { 6733b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 6743b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 6753b2aab18SMatthew Ahrens return (err); 6763b2aab18SMatthew Ahrens } 67778f17100SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone, 67878f17100SMatthew Ahrens outfd, vp, off); 67978f17100SMatthew Ahrens } else { 68078f17100SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE, 68178f17100SMatthew Ahrens outfd, vp, off); 6823b2aab18SMatthew Ahrens } 68378f17100SMatthew Ahrens if (owned) 68478f17100SMatthew Ahrens dsl_dataset_disown(ds, FTAG); 68578f17100SMatthew Ahrens else 68678f17100SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 68778f17100SMatthew Ahrens return (err); 6883b2aab18SMatthew Ahrens } 6893b2aab18SMatthew Ahrens 6903b2aab18SMatthew Ahrens int 6913b2aab18SMatthew Ahrens dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep) 69219b94df9SMatthew Ahrens { 69319b94df9SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 69419b94df9SMatthew Ahrens int err; 69519b94df9SMatthew Ahrens uint64_t size; 69619b94df9SMatthew Ahrens 6973b2aab18SMatthew Ahrens ASSERT(dsl_pool_config_held(dp)); 6983b2aab18SMatthew Ahrens 69919b94df9SMatthew Ahrens /* tosnap must be a snapshot */ 7003b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) 701be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 70219b94df9SMatthew Ahrens 7034445fffbSMatthew Ahrens /* 7044445fffbSMatthew Ahrens * fromsnap must be an earlier snapshot from the same fs as tosnap, 7054445fffbSMatthew Ahrens * or the origin's fs. 7064445fffbSMatthew Ahrens */ 70778f17100SMatthew Ahrens if (fromds != NULL && !dsl_dataset_is_before(ds, fromds, 0)) 708be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 70919b94df9SMatthew Ahrens 71019b94df9SMatthew Ahrens /* Get uncompressed size estimate of changed data. */ 71119b94df9SMatthew Ahrens if (fromds == NULL) { 71219b94df9SMatthew Ahrens size = ds->ds_phys->ds_uncompressed_bytes; 71319b94df9SMatthew Ahrens } else { 71419b94df9SMatthew Ahrens uint64_t used, comp; 71519b94df9SMatthew Ahrens err = dsl_dataset_space_written(fromds, ds, 71619b94df9SMatthew Ahrens &used, &comp, &size); 7173b2aab18SMatthew Ahrens if (err != 0) 71819b94df9SMatthew Ahrens return (err); 71919b94df9SMatthew Ahrens } 72019b94df9SMatthew Ahrens 72119b94df9SMatthew Ahrens /* 72219b94df9SMatthew Ahrens * Assume that space (both on-disk and in-stream) is dominated by 72319b94df9SMatthew Ahrens * data. We will adjust for indirect blocks and the copies property, 72419b94df9SMatthew Ahrens * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 72519b94df9SMatthew Ahrens */ 72619b94df9SMatthew Ahrens 72719b94df9SMatthew Ahrens /* 72819b94df9SMatthew Ahrens * Subtract out approximate space used by indirect blocks. 72919b94df9SMatthew Ahrens * Assume most space is used by data blocks (non-indirect, non-dnode). 73019b94df9SMatthew Ahrens * Assume all blocks are recordsize. Assume ditto blocks and 73119b94df9SMatthew Ahrens * internal fragmentation counter out compression. 73219b94df9SMatthew Ahrens * 73319b94df9SMatthew Ahrens * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 73419b94df9SMatthew Ahrens * block, which we observe in practice. 73519b94df9SMatthew Ahrens */ 73619b94df9SMatthew Ahrens uint64_t recordsize; 7373b2aab18SMatthew Ahrens err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize); 7383b2aab18SMatthew Ahrens if (err != 0) 73919b94df9SMatthew Ahrens return (err); 74019b94df9SMatthew Ahrens size -= size / recordsize * sizeof (blkptr_t); 74119b94df9SMatthew Ahrens 74219b94df9SMatthew Ahrens /* Add in the space for the record associated with each block. */ 74319b94df9SMatthew Ahrens size += size / recordsize * sizeof (dmu_replay_record_t); 74419b94df9SMatthew Ahrens 74519b94df9SMatthew Ahrens *sizep = size; 74619b94df9SMatthew Ahrens 74719b94df9SMatthew Ahrens return (0); 74819b94df9SMatthew Ahrens } 74919b94df9SMatthew Ahrens 7503b2aab18SMatthew Ahrens typedef struct dmu_recv_begin_arg { 7513b2aab18SMatthew Ahrens const char *drba_origin; 7523b2aab18SMatthew Ahrens dmu_recv_cookie_t *drba_cookie; 7533b2aab18SMatthew Ahrens cred_t *drba_cred; 75434f2f8cfSMatthew Ahrens uint64_t drba_snapobj; 7553b2aab18SMatthew Ahrens } dmu_recv_begin_arg_t; 756f18faf3fSek 757f18faf3fSek static int 7583b2aab18SMatthew Ahrens recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds, 7593b2aab18SMatthew Ahrens uint64_t fromguid) 760f18faf3fSek { 7613cb34c60Sahrens uint64_t val; 7623b2aab18SMatthew Ahrens int error; 7633b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 764f18faf3fSek 7653b2aab18SMatthew Ahrens /* temporary clone name must not exist */ 7663b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 7673b2aab18SMatthew Ahrens ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name, 7683b2aab18SMatthew Ahrens 8, 1, &val); 7693b2aab18SMatthew Ahrens if (error != ENOENT) 7703b2aab18SMatthew Ahrens return (error == 0 ? EBUSY : error); 7713b2aab18SMatthew Ahrens 772feaa74e4SMark Maybee /* new snapshot name must not exist */ 7733b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 7743b2aab18SMatthew Ahrens ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap, 7753b2aab18SMatthew Ahrens 8, 1, &val); 7763b2aab18SMatthew Ahrens if (error != ENOENT) 7773b2aab18SMatthew Ahrens return (error == 0 ? EEXIST : error); 778feaa74e4SMark Maybee 779*a2afb611SJerry Jelinek /* 780*a2afb611SJerry Jelinek * Check snapshot limit before receiving. We'll recheck again at the 781*a2afb611SJerry Jelinek * end, but might as well abort before receiving if we're already over 782*a2afb611SJerry Jelinek * the limit. 783*a2afb611SJerry Jelinek * 784*a2afb611SJerry Jelinek * Note that we do not check the file system limit with 785*a2afb611SJerry Jelinek * dsl_dir_fscount_check because the temporary %clones don't count 786*a2afb611SJerry Jelinek * against that limit. 787*a2afb611SJerry Jelinek */ 788*a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT, 789*a2afb611SJerry Jelinek NULL, drba->drba_cred); 790*a2afb611SJerry Jelinek if (error != 0) 791*a2afb611SJerry Jelinek return (error); 792*a2afb611SJerry Jelinek 7933b2aab18SMatthew Ahrens if (fromguid != 0) { 79434f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 79534f2f8cfSMatthew Ahrens uint64_t obj = ds->ds_phys->ds_prev_snap_obj; 79634f2f8cfSMatthew Ahrens 79734f2f8cfSMatthew Ahrens /* Find snapshot in this dir that matches fromguid. */ 79834f2f8cfSMatthew Ahrens while (obj != 0) { 79934f2f8cfSMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 80034f2f8cfSMatthew Ahrens &snap); 80134f2f8cfSMatthew Ahrens if (error != 0) 80234f2f8cfSMatthew Ahrens return (SET_ERROR(ENODEV)); 80334f2f8cfSMatthew Ahrens if (snap->ds_dir != ds->ds_dir) { 80434f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 80534f2f8cfSMatthew Ahrens return (SET_ERROR(ENODEV)); 80634f2f8cfSMatthew Ahrens } 80734f2f8cfSMatthew Ahrens if (snap->ds_phys->ds_guid == fromguid) 80834f2f8cfSMatthew Ahrens break; 80934f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 81034f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 81134f2f8cfSMatthew Ahrens } 81234f2f8cfSMatthew Ahrens if (obj == 0) 813be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 81492241e0bSTom Erickson 81534f2f8cfSMatthew Ahrens if (drba->drba_cookie->drc_force) { 81634f2f8cfSMatthew Ahrens drba->drba_snapobj = obj; 81734f2f8cfSMatthew Ahrens } else { 81834f2f8cfSMatthew Ahrens /* 81934f2f8cfSMatthew Ahrens * If we are not forcing, there must be no 82034f2f8cfSMatthew Ahrens * changes since fromsnap. 82134f2f8cfSMatthew Ahrens */ 82234f2f8cfSMatthew Ahrens if (dsl_dataset_modified_since_snap(ds, snap)) { 82392241e0bSTom Erickson dsl_dataset_rele(snap, FTAG); 82434f2f8cfSMatthew Ahrens return (SET_ERROR(ETXTBSY)); 82592241e0bSTom Erickson } 82634f2f8cfSMatthew Ahrens drba->drba_snapobj = ds->ds_prev->ds_object; 82792241e0bSTom Erickson } 82834f2f8cfSMatthew Ahrens 82934f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 830ae46e4c7SMatthew Ahrens } else { 831ae46e4c7SMatthew Ahrens /* if full, most recent snapshot must be $ORIGIN */ 832ae46e4c7SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 833be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 83434f2f8cfSMatthew Ahrens drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj; 835ae46e4c7SMatthew Ahrens } 8363cb34c60Sahrens 8373cb34c60Sahrens return (0); 8383b2aab18SMatthew Ahrens 8393b2aab18SMatthew Ahrens } 8403b2aab18SMatthew Ahrens 8413b2aab18SMatthew Ahrens static int 8423b2aab18SMatthew Ahrens dmu_recv_begin_check(void *arg, dmu_tx_t *tx) 8433b2aab18SMatthew Ahrens { 8443b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 8453b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 8463b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 8473b2aab18SMatthew Ahrens uint64_t fromguid = drrb->drr_fromguid; 8483b2aab18SMatthew Ahrens int flags = drrb->drr_flags; 8493b2aab18SMatthew Ahrens int error; 8503b2aab18SMatthew Ahrens dsl_dataset_t *ds; 8513b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 8523b2aab18SMatthew Ahrens 8533b2aab18SMatthew Ahrens /* already checked */ 8543b2aab18SMatthew Ahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 8553b2aab18SMatthew Ahrens 8563b2aab18SMatthew Ahrens if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == 8573b2aab18SMatthew Ahrens DMU_COMPOUNDSTREAM || 8583b2aab18SMatthew Ahrens drrb->drr_type >= DMU_OST_NUMTYPES || 8593b2aab18SMatthew Ahrens ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) 860be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 8613b2aab18SMatthew Ahrens 8623b2aab18SMatthew Ahrens /* Verify pool version supports SA if SA_SPILL feature set */ 8633b2aab18SMatthew Ahrens if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) & 8643b2aab18SMatthew Ahrens DMU_BACKUP_FEATURE_SA_SPILL) && 8653b2aab18SMatthew Ahrens spa_version(dp->dp_spa) < SPA_VERSION_SA) { 866be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 8673b2aab18SMatthew Ahrens } 8683b2aab18SMatthew Ahrens 8693b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 8703b2aab18SMatthew Ahrens if (error == 0) { 8713b2aab18SMatthew Ahrens /* target fs already exists; recv into temp clone */ 8723b2aab18SMatthew Ahrens 8733b2aab18SMatthew Ahrens /* Can't recv a clone into an existing fs */ 8743b2aab18SMatthew Ahrens if (flags & DRR_FLAG_CLONE) { 8753b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 876be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 8773b2aab18SMatthew Ahrens } 8783b2aab18SMatthew Ahrens 8793b2aab18SMatthew Ahrens error = recv_begin_check_existing_impl(drba, ds, fromguid); 8803b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 8813b2aab18SMatthew Ahrens } else if (error == ENOENT) { 8823b2aab18SMatthew Ahrens /* target fs does not exist; must be a full backup or clone */ 8833b2aab18SMatthew Ahrens char buf[MAXNAMELEN]; 8843b2aab18SMatthew Ahrens 8853b2aab18SMatthew Ahrens /* 8863b2aab18SMatthew Ahrens * If it's a non-clone incremental, we are missing the 8873b2aab18SMatthew Ahrens * target fs, so fail the recv. 8883b2aab18SMatthew Ahrens */ 8893b2aab18SMatthew Ahrens if (fromguid != 0 && !(flags & DRR_FLAG_CLONE)) 890be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 8913b2aab18SMatthew Ahrens 8923b2aab18SMatthew Ahrens /* Open the parent of tofs */ 8933b2aab18SMatthew Ahrens ASSERT3U(strlen(tofs), <, MAXNAMELEN); 8943b2aab18SMatthew Ahrens (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1); 8953b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, buf, FTAG, &ds); 8963b2aab18SMatthew Ahrens if (error != 0) 8973b2aab18SMatthew Ahrens return (error); 8983b2aab18SMatthew Ahrens 899*a2afb611SJerry Jelinek /* 900*a2afb611SJerry Jelinek * Check filesystem and snapshot limits before receiving. We'll 901*a2afb611SJerry Jelinek * recheck snapshot limits again at the end (we create the 902*a2afb611SJerry Jelinek * filesystems and increment those counts during begin_sync). 903*a2afb611SJerry Jelinek */ 904*a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, 905*a2afb611SJerry Jelinek ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred); 906*a2afb611SJerry Jelinek if (error != 0) { 907*a2afb611SJerry Jelinek dsl_dataset_rele(ds, FTAG); 908*a2afb611SJerry Jelinek return (error); 909*a2afb611SJerry Jelinek } 910*a2afb611SJerry Jelinek 911*a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, 912*a2afb611SJerry Jelinek ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred); 913*a2afb611SJerry Jelinek if (error != 0) { 914*a2afb611SJerry Jelinek dsl_dataset_rele(ds, FTAG); 915*a2afb611SJerry Jelinek return (error); 916*a2afb611SJerry Jelinek } 917*a2afb611SJerry Jelinek 9183b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 9193b2aab18SMatthew Ahrens dsl_dataset_t *origin; 9203b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drba->drba_origin, 9213b2aab18SMatthew Ahrens FTAG, &origin); 9223b2aab18SMatthew Ahrens if (error != 0) { 9233b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9243b2aab18SMatthew Ahrens return (error); 9253b2aab18SMatthew Ahrens } 9263b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(origin)) { 9273b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 9283b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 929be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 9303b2aab18SMatthew Ahrens } 9313b2aab18SMatthew Ahrens if (origin->ds_phys->ds_guid != fromguid) { 9323b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 9333b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 934be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 9353b2aab18SMatthew Ahrens } 9363b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 9373b2aab18SMatthew Ahrens } 9383b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9393b2aab18SMatthew Ahrens error = 0; 9403b2aab18SMatthew Ahrens } 9413b2aab18SMatthew Ahrens return (error); 942f18faf3fSek } 943f18faf3fSek 944f18faf3fSek static void 9453b2aab18SMatthew Ahrens dmu_recv_begin_sync(void *arg, dmu_tx_t *tx) 946f18faf3fSek { 9473b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 9483b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 9493b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 9503b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 9513b2aab18SMatthew Ahrens dsl_dataset_t *ds, *newds; 952f18faf3fSek uint64_t dsobj; 9533b2aab18SMatthew Ahrens int error; 9543b2aab18SMatthew Ahrens uint64_t crflags; 9553b2aab18SMatthew Ahrens 9563b2aab18SMatthew Ahrens crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ? 9573b2aab18SMatthew Ahrens DS_FLAG_CI_DATASET : 0; 958f18faf3fSek 9593b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 9603b2aab18SMatthew Ahrens if (error == 0) { 9613b2aab18SMatthew Ahrens /* create temporary clone */ 96234f2f8cfSMatthew Ahrens dsl_dataset_t *snap = NULL; 96334f2f8cfSMatthew Ahrens if (drba->drba_snapobj != 0) { 96434f2f8cfSMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 96534f2f8cfSMatthew Ahrens drba->drba_snapobj, FTAG, &snap)); 96634f2f8cfSMatthew Ahrens } 9673b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name, 96834f2f8cfSMatthew Ahrens snap, crflags, drba->drba_cred, tx); 96934f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 9703b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9713b2aab18SMatthew Ahrens } else { 9723b2aab18SMatthew Ahrens dsl_dir_t *dd; 9733b2aab18SMatthew Ahrens const char *tail; 9743b2aab18SMatthew Ahrens dsl_dataset_t *origin = NULL; 9753b2aab18SMatthew Ahrens 9763b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail)); 9773b2aab18SMatthew Ahrens 9783b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 9793b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drba->drba_origin, 9803b2aab18SMatthew Ahrens FTAG, &origin)); 9813b2aab18SMatthew Ahrens } 9823b2aab18SMatthew Ahrens 9833b2aab18SMatthew Ahrens /* Create new dataset. */ 9843b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(dd, 9853b2aab18SMatthew Ahrens strrchr(tofs, '/') + 1, 9863b2aab18SMatthew Ahrens origin, crflags, drba->drba_cred, tx); 9873b2aab18SMatthew Ahrens if (origin != NULL) 9883b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 9893b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 9903b2aab18SMatthew Ahrens drba->drba_cookie->drc_newfs = B_TRUE; 9913b2aab18SMatthew Ahrens } 9923b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds)); 9933b2aab18SMatthew Ahrens 9943b2aab18SMatthew Ahrens dmu_buf_will_dirty(newds->ds_dbuf, tx); 9953b2aab18SMatthew Ahrens newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 9963cb34c60Sahrens 997ae46e4c7SMatthew Ahrens /* 998ae46e4c7SMatthew Ahrens * If we actually created a non-clone, we need to create the 999ae46e4c7SMatthew Ahrens * objset in our new dataset. 1000ae46e4c7SMatthew Ahrens */ 10013b2aab18SMatthew Ahrens if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) { 1002ae46e4c7SMatthew Ahrens (void) dmu_objset_create_impl(dp->dp_spa, 10033b2aab18SMatthew Ahrens newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx); 1004ae46e4c7SMatthew Ahrens } 1005ae46e4c7SMatthew Ahrens 10063b2aab18SMatthew Ahrens drba->drba_cookie->drc_ds = newds; 1007dc7cd546SMark Shellenbaum 10083b2aab18SMatthew Ahrens spa_history_log_internal_ds(newds, "receive", tx, ""); 1009dc7cd546SMark Shellenbaum } 1010dc7cd546SMark Shellenbaum 10113cb34c60Sahrens /* 10123cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 10133cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 10143cb34c60Sahrens */ 10153cb34c60Sahrens int 10163b2aab18SMatthew Ahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 10173b2aab18SMatthew Ahrens boolean_t force, char *origin, dmu_recv_cookie_t *drc) 1018efb80947Sahrens { 10193b2aab18SMatthew Ahrens dmu_recv_begin_arg_t drba = { 0 }; 10203b2aab18SMatthew Ahrens dmu_replay_record_t *drr; 1021ab04eb8eStimh 10223cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 10233cb34c60Sahrens drc->drc_drrb = drrb; 10243cb34c60Sahrens drc->drc_tosnap = tosnap; 10253b2aab18SMatthew Ahrens drc->drc_tofs = tofs; 10263cb34c60Sahrens drc->drc_force = force; 1027*a2afb611SJerry Jelinek drc->drc_cred = CRED(); 1028efb80947Sahrens 10293b2aab18SMatthew Ahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 10303b2aab18SMatthew Ahrens drc->drc_byteswap = B_TRUE; 10313b2aab18SMatthew Ahrens else if (drrb->drr_magic != DMU_BACKUP_MAGIC) 1032be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1033efb80947Sahrens 10343b2aab18SMatthew Ahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 10353b2aab18SMatthew Ahrens drr->drr_type = DRR_BEGIN; 10363b2aab18SMatthew Ahrens drr->drr_u.drr_begin = *drc->drc_drrb; 10373b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 10383b2aab18SMatthew Ahrens fletcher_4_incremental_byteswap(drr, 10393b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 10403b2aab18SMatthew Ahrens } else { 10413b2aab18SMatthew Ahrens fletcher_4_incremental_native(drr, 10423b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 10433b2aab18SMatthew Ahrens } 10443b2aab18SMatthew Ahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 1045dc7cd546SMark Shellenbaum 10463b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 10473b2aab18SMatthew Ahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 10483b2aab18SMatthew Ahrens drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 10493b2aab18SMatthew Ahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 10503b2aab18SMatthew Ahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 10513b2aab18SMatthew Ahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 10523b2aab18SMatthew Ahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 10533cb34c60Sahrens } 10543cb34c60Sahrens 10553b2aab18SMatthew Ahrens drba.drba_origin = origin; 10563b2aab18SMatthew Ahrens drba.drba_cookie = drc; 10573b2aab18SMatthew Ahrens drba.drba_cred = CRED(); 10583b2aab18SMatthew Ahrens 10593b2aab18SMatthew Ahrens return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync, 10603b2aab18SMatthew Ahrens &drba, 5)); 1061efb80947Sahrens } 1062efb80947Sahrens 10633cb34c60Sahrens struct restorearg { 10643cb34c60Sahrens int err; 10653b2aab18SMatthew Ahrens boolean_t byteswap; 10663cb34c60Sahrens vnode_t *vp; 10673cb34c60Sahrens char *buf; 10683cb34c60Sahrens uint64_t voff; 10693cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 10703cb34c60Sahrens zio_cksum_t cksum; 1071c99e4bdcSChris Kirby avl_tree_t *guid_to_ds_map; 10723cb34c60Sahrens }; 10733cb34c60Sahrens 10749e69d7d0SLori Alt typedef struct guid_map_entry { 10759e69d7d0SLori Alt uint64_t guid; 10769e69d7d0SLori Alt dsl_dataset_t *gme_ds; 10779e69d7d0SLori Alt avl_node_t avlnode; 10789e69d7d0SLori Alt } guid_map_entry_t; 10799e69d7d0SLori Alt 10809e69d7d0SLori Alt static int 10819e69d7d0SLori Alt guid_compare(const void *arg1, const void *arg2) 10829e69d7d0SLori Alt { 10839e69d7d0SLori Alt const guid_map_entry_t *gmep1 = arg1; 10849e69d7d0SLori Alt const guid_map_entry_t *gmep2 = arg2; 10859e69d7d0SLori Alt 10869e69d7d0SLori Alt if (gmep1->guid < gmep2->guid) 10879e69d7d0SLori Alt return (-1); 10889e69d7d0SLori Alt else if (gmep1->guid > gmep2->guid) 10899e69d7d0SLori Alt return (1); 10909e69d7d0SLori Alt return (0); 10919e69d7d0SLori Alt } 10929e69d7d0SLori Alt 1093c99e4bdcSChris Kirby static void 1094c99e4bdcSChris Kirby free_guid_map_onexit(void *arg) 1095c99e4bdcSChris Kirby { 1096c99e4bdcSChris Kirby avl_tree_t *ca = arg; 1097c99e4bdcSChris Kirby void *cookie = NULL; 1098c99e4bdcSChris Kirby guid_map_entry_t *gmep; 1099c99e4bdcSChris Kirby 1100c99e4bdcSChris Kirby while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { 11013b2aab18SMatthew Ahrens dsl_dataset_long_rele(gmep->gme_ds, gmep); 1102de8d9cffSMatthew Ahrens dsl_dataset_rele(gmep->gme_ds, gmep); 1103c99e4bdcSChris Kirby kmem_free(gmep, sizeof (guid_map_entry_t)); 1104c99e4bdcSChris Kirby } 1105c99e4bdcSChris Kirby avl_destroy(ca); 1106c99e4bdcSChris Kirby kmem_free(ca, sizeof (avl_tree_t)); 1107c99e4bdcSChris Kirby } 1108c99e4bdcSChris Kirby 1109efb80947Sahrens static void * 1110efb80947Sahrens restore_read(struct restorearg *ra, int len) 1111efb80947Sahrens { 1112efb80947Sahrens void *rv; 11133cb34c60Sahrens int done = 0; 1114efb80947Sahrens 1115efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 1116fb09f5aaSMadhav Suresh ASSERT0(len % 8); 1117efb80947Sahrens 11183cb34c60Sahrens while (done < len) { 1119efb80947Sahrens ssize_t resid; 1120efb80947Sahrens 1121efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 11223cb34c60Sahrens (caddr_t)ra->buf + done, len - done, 1123efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 1124efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 1125efb80947Sahrens 11263cb34c60Sahrens if (resid == len - done) 1127be6fd75aSMatthew Ahrens ra->err = SET_ERROR(EINVAL); 11283cb34c60Sahrens ra->voff += len - done - resid; 11293cb34c60Sahrens done = len - resid; 11303b2aab18SMatthew Ahrens if (ra->err != 0) 1131efb80947Sahrens return (NULL); 1132efb80947Sahrens } 1133efb80947Sahrens 11343cb34c60Sahrens ASSERT3U(done, ==, len); 11353cb34c60Sahrens rv = ra->buf; 1136efb80947Sahrens if (ra->byteswap) 11373cb34c60Sahrens fletcher_4_incremental_byteswap(rv, len, &ra->cksum); 1138efb80947Sahrens else 11393cb34c60Sahrens fletcher_4_incremental_native(rv, len, &ra->cksum); 1140efb80947Sahrens return (rv); 1141efb80947Sahrens } 1142efb80947Sahrens 1143efb80947Sahrens static void 1144efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 1145efb80947Sahrens { 1146efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 1147efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 1148efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 11493cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 1150efb80947Sahrens switch (drr->drr_type) { 1151efb80947Sahrens case DRR_BEGIN: 1152efb80947Sahrens DO64(drr_begin.drr_magic); 11539e69d7d0SLori Alt DO64(drr_begin.drr_versioninfo); 1154efb80947Sahrens DO64(drr_begin.drr_creation_time); 1155efb80947Sahrens DO32(drr_begin.drr_type); 11563cb34c60Sahrens DO32(drr_begin.drr_flags); 1157efb80947Sahrens DO64(drr_begin.drr_toguid); 1158efb80947Sahrens DO64(drr_begin.drr_fromguid); 1159efb80947Sahrens break; 1160efb80947Sahrens case DRR_OBJECT: 1161efb80947Sahrens DO64(drr_object.drr_object); 1162efb80947Sahrens /* DO64(drr_object.drr_allocation_txg); */ 1163efb80947Sahrens DO32(drr_object.drr_type); 1164efb80947Sahrens DO32(drr_object.drr_bonustype); 1165efb80947Sahrens DO32(drr_object.drr_blksz); 1166efb80947Sahrens DO32(drr_object.drr_bonuslen); 11679e69d7d0SLori Alt DO64(drr_object.drr_toguid); 1168efb80947Sahrens break; 1169efb80947Sahrens case DRR_FREEOBJECTS: 1170efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 1171efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 11729e69d7d0SLori Alt DO64(drr_freeobjects.drr_toguid); 1173efb80947Sahrens break; 1174efb80947Sahrens case DRR_WRITE: 1175efb80947Sahrens DO64(drr_write.drr_object); 1176efb80947Sahrens DO32(drr_write.drr_type); 1177efb80947Sahrens DO64(drr_write.drr_offset); 1178efb80947Sahrens DO64(drr_write.drr_length); 11799e69d7d0SLori Alt DO64(drr_write.drr_toguid); 11808e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[0]); 11818e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[1]); 11828e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[2]); 11838e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[3]); 11848e714474SLori Alt DO64(drr_write.drr_key.ddk_prop); 11859e69d7d0SLori Alt break; 11869e69d7d0SLori Alt case DRR_WRITE_BYREF: 11879e69d7d0SLori Alt DO64(drr_write_byref.drr_object); 11889e69d7d0SLori Alt DO64(drr_write_byref.drr_offset); 11899e69d7d0SLori Alt DO64(drr_write_byref.drr_length); 11909e69d7d0SLori Alt DO64(drr_write_byref.drr_toguid); 11919e69d7d0SLori Alt DO64(drr_write_byref.drr_refguid); 11929e69d7d0SLori Alt DO64(drr_write_byref.drr_refobject); 11939e69d7d0SLori Alt DO64(drr_write_byref.drr_refoffset); 11948e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[0]); 11958e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[1]); 11968e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[2]); 11978e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[3]); 11988e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_prop); 1199efb80947Sahrens break; 1200efb80947Sahrens case DRR_FREE: 1201efb80947Sahrens DO64(drr_free.drr_object); 1202efb80947Sahrens DO64(drr_free.drr_offset); 1203efb80947Sahrens DO64(drr_free.drr_length); 12049e69d7d0SLori Alt DO64(drr_free.drr_toguid); 1205efb80947Sahrens break; 12060a586ceaSMark Shellenbaum case DRR_SPILL: 12070a586ceaSMark Shellenbaum DO64(drr_spill.drr_object); 12080a586ceaSMark Shellenbaum DO64(drr_spill.drr_length); 12090a586ceaSMark Shellenbaum DO64(drr_spill.drr_toguid); 12100a586ceaSMark Shellenbaum break; 1211efb80947Sahrens case DRR_END: 1212efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 1213efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 1214efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 1215efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 12169e69d7d0SLori Alt DO64(drr_end.drr_toguid); 1217efb80947Sahrens break; 1218efb80947Sahrens } 1219efb80947Sahrens #undef DO64 1220efb80947Sahrens #undef DO32 1221efb80947Sahrens } 1222efb80947Sahrens 1223efb80947Sahrens static int 1224efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 1225efb80947Sahrens { 1226efb80947Sahrens int err; 1227efb80947Sahrens dmu_tx_t *tx; 1228adee0b6fSTim Haley void *data = NULL; 1229efb80947Sahrens 1230efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 1231ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_type) || 1232ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_bonustype) || 12339e69d7d0SLori Alt drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || 1234efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 1235efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 1236efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 1237efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 1238efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 1239be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1240efb80947Sahrens } 1241efb80947Sahrens 12422bf405a2SMark Maybee err = dmu_object_info(os, drro->drr_object, NULL); 12432bf405a2SMark Maybee 12442bf405a2SMark Maybee if (err != 0 && err != ENOENT) 1245be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 12462bf405a2SMark Maybee 1247adee0b6fSTim Haley if (drro->drr_bonuslen) { 1248adee0b6fSTim Haley data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8)); 12493b2aab18SMatthew Ahrens if (ra->err != 0) 1250adee0b6fSTim Haley return (ra->err); 1251adee0b6fSTim Haley } 1252adee0b6fSTim Haley 1253efb80947Sahrens if (err == ENOENT) { 1254efb80947Sahrens /* currently free, want to be allocated */ 12552bf405a2SMark Maybee tx = dmu_tx_create(os); 1256efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1257efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 12583b2aab18SMatthew Ahrens if (err != 0) { 1259efb80947Sahrens dmu_tx_abort(tx); 1260efb80947Sahrens return (err); 1261efb80947Sahrens } 1262efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 1263efb80947Sahrens drro->drr_type, drro->drr_blksz, 1264efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 12652bf405a2SMark Maybee dmu_tx_commit(tx); 1266efb80947Sahrens } else { 1267efb80947Sahrens /* currently allocated, want to be allocated */ 1268efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 1269efb80947Sahrens drro->drr_type, drro->drr_blksz, 12702bf405a2SMark Maybee drro->drr_bonustype, drro->drr_bonuslen); 1271efb80947Sahrens } 12723b2aab18SMatthew Ahrens if (err != 0) { 1273be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 12740a586ceaSMark Shellenbaum } 12752bf405a2SMark Maybee 12762bf405a2SMark Maybee tx = dmu_tx_create(os); 12772bf405a2SMark Maybee dmu_tx_hold_bonus(tx, drro->drr_object); 12782bf405a2SMark Maybee err = dmu_tx_assign(tx, TXG_WAIT); 12793b2aab18SMatthew Ahrens if (err != 0) { 12802bf405a2SMark Maybee dmu_tx_abort(tx); 12812bf405a2SMark Maybee return (err); 1282efb80947Sahrens } 1283efb80947Sahrens 12849e69d7d0SLori Alt dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 12859e69d7d0SLori Alt tx); 1286efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1287efb80947Sahrens 1288adee0b6fSTim Haley if (data != NULL) { 1289efb80947Sahrens dmu_buf_t *db; 1290adee0b6fSTim Haley 1291efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 1292efb80947Sahrens dmu_buf_will_dirty(db, tx); 1293efb80947Sahrens 12941934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 12951934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 1296efb80947Sahrens if (ra->byteswap) { 1297ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1298ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drro->drr_bonustype); 1299ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(db->db_data, 1300efb80947Sahrens drro->drr_bonuslen); 1301efb80947Sahrens } 1302efb80947Sahrens dmu_buf_rele(db, FTAG); 1303efb80947Sahrens } 1304efb80947Sahrens dmu_tx_commit(tx); 1305efb80947Sahrens return (0); 1306efb80947Sahrens } 1307efb80947Sahrens 1308efb80947Sahrens /* ARGSUSED */ 1309efb80947Sahrens static int 1310efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 1311efb80947Sahrens struct drr_freeobjects *drrfo) 1312efb80947Sahrens { 1313efb80947Sahrens uint64_t obj; 1314efb80947Sahrens 1315efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 1316be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1317efb80947Sahrens 1318efb80947Sahrens for (obj = drrfo->drr_firstobj; 1319432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1320432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 1321efb80947Sahrens int err; 1322efb80947Sahrens 1323efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 1324efb80947Sahrens continue; 1325efb80947Sahrens 1326713d6c20SMatthew Ahrens err = dmu_free_long_object(os, obj); 13273b2aab18SMatthew Ahrens if (err != 0) 1328efb80947Sahrens return (err); 1329efb80947Sahrens } 1330efb80947Sahrens return (0); 1331efb80947Sahrens } 1332efb80947Sahrens 1333efb80947Sahrens static int 1334efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 1335efb80947Sahrens struct drr_write *drrw) 1336efb80947Sahrens { 1337efb80947Sahrens dmu_tx_t *tx; 1338efb80947Sahrens void *data; 1339efb80947Sahrens int err; 1340efb80947Sahrens 1341efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 1342ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drrw->drr_type)) 1343be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1344efb80947Sahrens 1345efb80947Sahrens data = restore_read(ra, drrw->drr_length); 1346efb80947Sahrens if (data == NULL) 1347efb80947Sahrens return (ra->err); 1348efb80947Sahrens 1349efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1350be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1351efb80947Sahrens 1352efb80947Sahrens tx = dmu_tx_create(os); 1353efb80947Sahrens 1354efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 1355efb80947Sahrens drrw->drr_offset, drrw->drr_length); 1356efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 13573b2aab18SMatthew Ahrens if (err != 0) { 1358efb80947Sahrens dmu_tx_abort(tx); 1359efb80947Sahrens return (err); 1360efb80947Sahrens } 1361ad135b5dSChristopher Siden if (ra->byteswap) { 1362ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1363ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drrw->drr_type); 1364ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1365ad135b5dSChristopher Siden } 1366efb80947Sahrens dmu_write(os, drrw->drr_object, 1367efb80947Sahrens drrw->drr_offset, drrw->drr_length, data, tx); 1368efb80947Sahrens dmu_tx_commit(tx); 1369efb80947Sahrens return (0); 1370efb80947Sahrens } 1371efb80947Sahrens 13729e69d7d0SLori Alt /* 13739e69d7d0SLori Alt * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed 13749e69d7d0SLori Alt * streams to refer to a copy of the data that is already on the 13759e69d7d0SLori Alt * system because it came in earlier in the stream. This function 13769e69d7d0SLori Alt * finds the earlier copy of the data, and uses that copy instead of 13779e69d7d0SLori Alt * data from the stream to fulfill this write. 13789e69d7d0SLori Alt */ 13799e69d7d0SLori Alt static int 13809e69d7d0SLori Alt restore_write_byref(struct restorearg *ra, objset_t *os, 13819e69d7d0SLori Alt struct drr_write_byref *drrwbr) 13829e69d7d0SLori Alt { 13839e69d7d0SLori Alt dmu_tx_t *tx; 13849e69d7d0SLori Alt int err; 13859e69d7d0SLori Alt guid_map_entry_t gmesrch; 13869e69d7d0SLori Alt guid_map_entry_t *gmep; 13879e69d7d0SLori Alt avl_index_t where; 13889e69d7d0SLori Alt objset_t *ref_os = NULL; 13899e69d7d0SLori Alt dmu_buf_t *dbp; 13909e69d7d0SLori Alt 13919e69d7d0SLori Alt if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset) 1392be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 13939e69d7d0SLori Alt 13949e69d7d0SLori Alt /* 13959e69d7d0SLori Alt * If the GUID of the referenced dataset is different from the 13969e69d7d0SLori Alt * GUID of the target dataset, find the referenced dataset. 13979e69d7d0SLori Alt */ 13989e69d7d0SLori Alt if (drrwbr->drr_toguid != drrwbr->drr_refguid) { 13999e69d7d0SLori Alt gmesrch.guid = drrwbr->drr_refguid; 1400c99e4bdcSChris Kirby if ((gmep = avl_find(ra->guid_to_ds_map, &gmesrch, 14019e69d7d0SLori Alt &where)) == NULL) { 1402be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 14039e69d7d0SLori Alt } 14049e69d7d0SLori Alt if (dmu_objset_from_ds(gmep->gme_ds, &ref_os)) 1405be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 14069e69d7d0SLori Alt } else { 14079e69d7d0SLori Alt ref_os = os; 14089e69d7d0SLori Alt } 14099e69d7d0SLori Alt 14109e69d7d0SLori Alt if (err = dmu_buf_hold(ref_os, drrwbr->drr_refobject, 141147cb52daSJeff Bonwick drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH)) 14129e69d7d0SLori Alt return (err); 14139e69d7d0SLori Alt 14149e69d7d0SLori Alt tx = dmu_tx_create(os); 14159e69d7d0SLori Alt 14169e69d7d0SLori Alt dmu_tx_hold_write(tx, drrwbr->drr_object, 14179e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length); 14189e69d7d0SLori Alt err = dmu_tx_assign(tx, TXG_WAIT); 14193b2aab18SMatthew Ahrens if (err != 0) { 14209e69d7d0SLori Alt dmu_tx_abort(tx); 14219e69d7d0SLori Alt return (err); 14229e69d7d0SLori Alt } 14239e69d7d0SLori Alt dmu_write(os, drrwbr->drr_object, 14249e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 14259e69d7d0SLori Alt dmu_buf_rele(dbp, FTAG); 14269e69d7d0SLori Alt dmu_tx_commit(tx); 14279e69d7d0SLori Alt return (0); 14289e69d7d0SLori Alt } 14299e69d7d0SLori Alt 14300a586ceaSMark Shellenbaum static int 14310a586ceaSMark Shellenbaum restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs) 14320a586ceaSMark Shellenbaum { 14330a586ceaSMark Shellenbaum dmu_tx_t *tx; 14340a586ceaSMark Shellenbaum void *data; 14350a586ceaSMark Shellenbaum dmu_buf_t *db, *db_spill; 14360a586ceaSMark Shellenbaum int err; 14370a586ceaSMark Shellenbaum 14380a586ceaSMark Shellenbaum if (drrs->drr_length < SPA_MINBLOCKSIZE || 14390a586ceaSMark Shellenbaum drrs->drr_length > SPA_MAXBLOCKSIZE) 1440be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 14410a586ceaSMark Shellenbaum 14420a586ceaSMark Shellenbaum data = restore_read(ra, drrs->drr_length); 14430a586ceaSMark Shellenbaum if (data == NULL) 14440a586ceaSMark Shellenbaum return (ra->err); 14450a586ceaSMark Shellenbaum 14460a586ceaSMark Shellenbaum if (dmu_object_info(os, drrs->drr_object, NULL) != 0) 1447be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 14480a586ceaSMark Shellenbaum 14490a586ceaSMark Shellenbaum VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db)); 14500a586ceaSMark Shellenbaum if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) { 14510a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 14520a586ceaSMark Shellenbaum return (err); 14530a586ceaSMark Shellenbaum } 14540a586ceaSMark Shellenbaum 14550a586ceaSMark Shellenbaum tx = dmu_tx_create(os); 14560a586ceaSMark Shellenbaum 14570a586ceaSMark Shellenbaum dmu_tx_hold_spill(tx, db->db_object); 14580a586ceaSMark Shellenbaum 14590a586ceaSMark Shellenbaum err = dmu_tx_assign(tx, TXG_WAIT); 14603b2aab18SMatthew Ahrens if (err != 0) { 14610a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 14620a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 14630a586ceaSMark Shellenbaum dmu_tx_abort(tx); 14640a586ceaSMark Shellenbaum return (err); 14650a586ceaSMark Shellenbaum } 14660a586ceaSMark Shellenbaum dmu_buf_will_dirty(db_spill, tx); 14670a586ceaSMark Shellenbaum 14680a586ceaSMark Shellenbaum if (db_spill->db_size < drrs->drr_length) 14690a586ceaSMark Shellenbaum VERIFY(0 == dbuf_spill_set_blksz(db_spill, 14700a586ceaSMark Shellenbaum drrs->drr_length, tx)); 14710a586ceaSMark Shellenbaum bcopy(data, db_spill->db_data, drrs->drr_length); 14720a586ceaSMark Shellenbaum 14730a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 14740a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 14750a586ceaSMark Shellenbaum 14760a586ceaSMark Shellenbaum dmu_tx_commit(tx); 14770a586ceaSMark Shellenbaum return (0); 14780a586ceaSMark Shellenbaum } 14790a586ceaSMark Shellenbaum 1480efb80947Sahrens /* ARGSUSED */ 1481efb80947Sahrens static int 1482efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 1483efb80947Sahrens struct drr_free *drrf) 1484efb80947Sahrens { 1485efb80947Sahrens int err; 1486efb80947Sahrens 1487efb80947Sahrens if (drrf->drr_length != -1ULL && 1488efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 1489be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1490efb80947Sahrens 1491efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1492be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1493efb80947Sahrens 1494cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 1495efb80947Sahrens drrf->drr_offset, drrf->drr_length); 1496efb80947Sahrens return (err); 1497efb80947Sahrens } 1498efb80947Sahrens 14993b2aab18SMatthew Ahrens /* used to destroy the drc_ds on error */ 15003b2aab18SMatthew Ahrens static void 15013b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) 15023b2aab18SMatthew Ahrens { 15033b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 15043b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 15053b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 15063b2aab18SMatthew Ahrens (void) dsl_destroy_head(name); 15073b2aab18SMatthew Ahrens } 15083b2aab18SMatthew Ahrens 15093cb34c60Sahrens /* 15103cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 15113cb34c60Sahrens */ 1512efb80947Sahrens int 1513c99e4bdcSChris Kirby dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp, 1514c99e4bdcSChris Kirby int cleanup_fd, uint64_t *action_handlep) 1515efb80947Sahrens { 15163cb34c60Sahrens struct restorearg ra = { 0 }; 1517efb80947Sahrens dmu_replay_record_t *drr; 15183cb34c60Sahrens objset_t *os; 15193cb34c60Sahrens zio_cksum_t pcksum; 15209e69d7d0SLori Alt int featureflags; 1521efb80947Sahrens 15223b2aab18SMatthew Ahrens ra.byteswap = drc->drc_byteswap; 15233b2aab18SMatthew Ahrens ra.cksum = drc->drc_cksum; 15243cb34c60Sahrens ra.vp = vp; 15253cb34c60Sahrens ra.voff = *voffp; 15263cb34c60Sahrens ra.bufsize = 1<<20; 15273cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1528efb80947Sahrens 15293cb34c60Sahrens /* these were verified in dmu_recv_begin */ 15303b2aab18SMatthew Ahrens ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==, 15319e69d7d0SLori Alt DMU_SUBSTREAM); 15323b2aab18SMatthew Ahrens ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES); 1533efb80947Sahrens 1534efb80947Sahrens /* 1535efb80947Sahrens * Open the objset we are modifying. 1536efb80947Sahrens */ 15373b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os)); 1538efb80947Sahrens 15393b2aab18SMatthew Ahrens ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1540efb80947Sahrens 15419e69d7d0SLori Alt featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 15429e69d7d0SLori Alt 15439e69d7d0SLori Alt /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 15449e69d7d0SLori Alt if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1545a7f53a56SChris Kirby minor_t minor; 1546a7f53a56SChris Kirby 1547c99e4bdcSChris Kirby if (cleanup_fd == -1) { 1548be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EBADF); 1549c99e4bdcSChris Kirby goto out; 1550c99e4bdcSChris Kirby } 1551a7f53a56SChris Kirby ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); 15523b2aab18SMatthew Ahrens if (ra.err != 0) { 1553a7f53a56SChris Kirby cleanup_fd = -1; 1554a7f53a56SChris Kirby goto out; 1555a7f53a56SChris Kirby } 1556a7f53a56SChris Kirby 1557c99e4bdcSChris Kirby if (*action_handlep == 0) { 1558c99e4bdcSChris Kirby ra.guid_to_ds_map = 1559c99e4bdcSChris Kirby kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1560c99e4bdcSChris Kirby avl_create(ra.guid_to_ds_map, guid_compare, 1561c99e4bdcSChris Kirby sizeof (guid_map_entry_t), 1562c99e4bdcSChris Kirby offsetof(guid_map_entry_t, avlnode)); 1563a7f53a56SChris Kirby ra.err = zfs_onexit_add_cb(minor, 1564c99e4bdcSChris Kirby free_guid_map_onexit, ra.guid_to_ds_map, 1565c99e4bdcSChris Kirby action_handlep); 15663b2aab18SMatthew Ahrens if (ra.err != 0) 1567c99e4bdcSChris Kirby goto out; 1568c99e4bdcSChris Kirby } else { 1569a7f53a56SChris Kirby ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1570c99e4bdcSChris Kirby (void **)&ra.guid_to_ds_map); 15713b2aab18SMatthew Ahrens if (ra.err != 0) 1572c99e4bdcSChris Kirby goto out; 1573c99e4bdcSChris Kirby } 1574ec5cf9d5SAlexander Stetsenko 1575ec5cf9d5SAlexander Stetsenko drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 15769e69d7d0SLori Alt } 15779e69d7d0SLori Alt 1578efb80947Sahrens /* 1579efb80947Sahrens * Read records and process them. 1580efb80947Sahrens */ 15813cb34c60Sahrens pcksum = ra.cksum; 1582efb80947Sahrens while (ra.err == 0 && 1583efb80947Sahrens NULL != (drr = restore_read(&ra, sizeof (*drr)))) { 1584efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 1585be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EINTR); 1586efb80947Sahrens goto out; 1587efb80947Sahrens } 1588efb80947Sahrens 1589efb80947Sahrens if (ra.byteswap) 1590efb80947Sahrens backup_byteswap(drr); 1591efb80947Sahrens 1592efb80947Sahrens switch (drr->drr_type) { 1593efb80947Sahrens case DRR_OBJECT: 1594efb80947Sahrens { 1595efb80947Sahrens /* 1596efb80947Sahrens * We need to make a copy of the record header, 1597efb80947Sahrens * because restore_{object,write} may need to 1598efb80947Sahrens * restore_read(), which will invalidate drr. 1599efb80947Sahrens */ 1600efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 1601efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 1602efb80947Sahrens break; 1603efb80947Sahrens } 1604efb80947Sahrens case DRR_FREEOBJECTS: 1605efb80947Sahrens { 1606efb80947Sahrens struct drr_freeobjects drrfo = 1607efb80947Sahrens drr->drr_u.drr_freeobjects; 1608efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 1609efb80947Sahrens break; 1610efb80947Sahrens } 1611efb80947Sahrens case DRR_WRITE: 1612efb80947Sahrens { 1613efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 1614efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 1615efb80947Sahrens break; 1616efb80947Sahrens } 16179e69d7d0SLori Alt case DRR_WRITE_BYREF: 16189e69d7d0SLori Alt { 16199e69d7d0SLori Alt struct drr_write_byref drrwbr = 16209e69d7d0SLori Alt drr->drr_u.drr_write_byref; 16219e69d7d0SLori Alt ra.err = restore_write_byref(&ra, os, &drrwbr); 16229e69d7d0SLori Alt break; 16239e69d7d0SLori Alt } 1624efb80947Sahrens case DRR_FREE: 1625efb80947Sahrens { 1626efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 1627efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 1628efb80947Sahrens break; 1629efb80947Sahrens } 1630efb80947Sahrens case DRR_END: 1631efb80947Sahrens { 1632efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1633efb80947Sahrens /* 1634efb80947Sahrens * We compare against the *previous* checksum 1635efb80947Sahrens * value, because the stored checksum is of 1636efb80947Sahrens * everything before the DRR_END record. 1637efb80947Sahrens */ 1638137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1639be6fd75aSMatthew Ahrens ra.err = SET_ERROR(ECKSUM); 1640efb80947Sahrens goto out; 1641efb80947Sahrens } 16420a586ceaSMark Shellenbaum case DRR_SPILL: 16430a586ceaSMark Shellenbaum { 16440a586ceaSMark Shellenbaum struct drr_spill drrs = drr->drr_u.drr_spill; 16450a586ceaSMark Shellenbaum ra.err = restore_spill(&ra, os, &drrs); 16460a586ceaSMark Shellenbaum break; 16470a586ceaSMark Shellenbaum } 1648efb80947Sahrens default: 1649be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EINVAL); 1650efb80947Sahrens goto out; 1651efb80947Sahrens } 16523cb34c60Sahrens pcksum = ra.cksum; 1653efb80947Sahrens } 1654137fa067Sahrens ASSERT(ra.err != 0); 1655efb80947Sahrens 1656efb80947Sahrens out: 1657a7f53a56SChris Kirby if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1658a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 1659a7f53a56SChris Kirby 16603cb34c60Sahrens if (ra.err != 0) { 1661efb80947Sahrens /* 1662f4b94bdeSMatthew Ahrens * destroy what we created, so we don't leave it in the 1663f4b94bdeSMatthew Ahrens * inconsistent restoring state. 1664efb80947Sahrens */ 16653b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 1666efb80947Sahrens } 1667efb80947Sahrens 1668efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 16693cb34c60Sahrens *voffp = ra.voff; 1670efb80947Sahrens return (ra.err); 1671efb80947Sahrens } 1672f18faf3fSek 16733cb34c60Sahrens static int 16743b2aab18SMatthew Ahrens dmu_recv_end_check(void *arg, dmu_tx_t *tx) 16753cb34c60Sahrens { 16763b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 16773b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 16783b2aab18SMatthew Ahrens int error; 16793b2aab18SMatthew Ahrens 16803b2aab18SMatthew Ahrens ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag); 16813cb34c60Sahrens 16823b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 16833b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 16843b2aab18SMatthew Ahrens 16853b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head); 16863b2aab18SMatthew Ahrens if (error != 0) 16873b2aab18SMatthew Ahrens return (error); 168834f2f8cfSMatthew Ahrens if (drc->drc_force) { 168934f2f8cfSMatthew Ahrens /* 169034f2f8cfSMatthew Ahrens * We will destroy any snapshots in tofs (i.e. before 169134f2f8cfSMatthew Ahrens * origin_head) that are after the origin (which is 169234f2f8cfSMatthew Ahrens * the snap before drc_ds, because drc_ds can not 169334f2f8cfSMatthew Ahrens * have any snaps of its own). 169434f2f8cfSMatthew Ahrens */ 169534f2f8cfSMatthew Ahrens uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 169634f2f8cfSMatthew Ahrens while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 169734f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 169834f2f8cfSMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 169934f2f8cfSMatthew Ahrens &snap); 170034f2f8cfSMatthew Ahrens if (error != 0) 170134f2f8cfSMatthew Ahrens return (error); 170234f2f8cfSMatthew Ahrens if (snap->ds_dir != origin_head->ds_dir) 170334f2f8cfSMatthew Ahrens error = SET_ERROR(EINVAL); 170434f2f8cfSMatthew Ahrens if (error == 0) { 170534f2f8cfSMatthew Ahrens error = dsl_destroy_snapshot_check_impl( 170634f2f8cfSMatthew Ahrens snap, B_FALSE); 170734f2f8cfSMatthew Ahrens } 170834f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 170934f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 171034f2f8cfSMatthew Ahrens if (error != 0) 171134f2f8cfSMatthew Ahrens return (error); 171234f2f8cfSMatthew Ahrens } 171334f2f8cfSMatthew Ahrens } 17143b2aab18SMatthew Ahrens error = dsl_dataset_clone_swap_check_impl(drc->drc_ds, 171591948b51SKeith M Wesolowski origin_head, drc->drc_force, drc->drc_owner, tx); 17163b2aab18SMatthew Ahrens if (error != 0) { 17173b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 17183b2aab18SMatthew Ahrens return (error); 17193b2aab18SMatthew Ahrens } 17203b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(origin_head, 1721*a2afb611SJerry Jelinek drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); 17223b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 17233b2aab18SMatthew Ahrens if (error != 0) 17243b2aab18SMatthew Ahrens return (error); 17253b2aab18SMatthew Ahrens 17263b2aab18SMatthew Ahrens error = dsl_destroy_head_check_impl(drc->drc_ds, 1); 17273b2aab18SMatthew Ahrens } else { 17283b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(drc->drc_ds, 1729*a2afb611SJerry Jelinek drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); 17303b2aab18SMatthew Ahrens } 17313b2aab18SMatthew Ahrens return (error); 17323cb34c60Sahrens } 17333cb34c60Sahrens 17343cb34c60Sahrens static void 17353b2aab18SMatthew Ahrens dmu_recv_end_sync(void *arg, dmu_tx_t *tx) 17363cb34c60Sahrens { 17373b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 17383b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 17393b2aab18SMatthew Ahrens 17403b2aab18SMatthew Ahrens spa_history_log_internal_ds(drc->drc_ds, "finish receiving", 17413b2aab18SMatthew Ahrens tx, "snap=%s", drc->drc_tosnap); 17423b2aab18SMatthew Ahrens 17433b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 17443b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 17453b2aab18SMatthew Ahrens 17463b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG, 17473b2aab18SMatthew Ahrens &origin_head)); 174834f2f8cfSMatthew Ahrens 174934f2f8cfSMatthew Ahrens if (drc->drc_force) { 175034f2f8cfSMatthew Ahrens /* 175134f2f8cfSMatthew Ahrens * Destroy any snapshots of drc_tofs (origin_head) 175234f2f8cfSMatthew Ahrens * after the origin (the snap before drc_ds). 175334f2f8cfSMatthew Ahrens */ 175434f2f8cfSMatthew Ahrens uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 175534f2f8cfSMatthew Ahrens while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 175634f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 175734f2f8cfSMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG, 175834f2f8cfSMatthew Ahrens &snap)); 175934f2f8cfSMatthew Ahrens ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir); 176034f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 176134f2f8cfSMatthew Ahrens dsl_destroy_snapshot_sync_impl(snap, 176234f2f8cfSMatthew Ahrens B_FALSE, tx); 176334f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 176434f2f8cfSMatthew Ahrens } 176534f2f8cfSMatthew Ahrens } 176634f2f8cfSMatthew Ahrens VERIFY3P(drc->drc_ds->ds_prev, ==, 176734f2f8cfSMatthew Ahrens origin_head->ds_prev); 176834f2f8cfSMatthew Ahrens 17693b2aab18SMatthew Ahrens dsl_dataset_clone_swap_sync_impl(drc->drc_ds, 17703b2aab18SMatthew Ahrens origin_head, tx); 17713b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(origin_head, 17723b2aab18SMatthew Ahrens drc->drc_tosnap, tx); 17733b2aab18SMatthew Ahrens 17743b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 17753b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx); 17763b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_creation_time = 17773b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 17783b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_guid = 17793b2aab18SMatthew Ahrens drc->drc_drrb->drr_toguid; 17803b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_flags &= 17813b2aab18SMatthew Ahrens ~DS_FLAG_INCONSISTENT; 17823b2aab18SMatthew Ahrens 17833b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_dbuf, tx); 17843b2aab18SMatthew Ahrens origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 17853b2aab18SMatthew Ahrens 17863b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 17873b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(drc->drc_ds, tx); 178891948b51SKeith M Wesolowski 178991948b51SKeith M Wesolowski if (drc->drc_owner != NULL) 179091948b51SKeith M Wesolowski VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner); 17913b2aab18SMatthew Ahrens } else { 17923b2aab18SMatthew Ahrens dsl_dataset_t *ds = drc->drc_ds; 17933cb34c60Sahrens 17943b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx); 17953cb34c60Sahrens 17963b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 17973b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 17983b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_creation_time = 17993b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 18003b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid; 18013b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 18023cb34c60Sahrens 18033b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 18043b2aab18SMatthew Ahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 18053b2aab18SMatthew Ahrens } 18063b2aab18SMatthew Ahrens drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj; 18073b2aab18SMatthew Ahrens /* 18083b2aab18SMatthew Ahrens * Release the hold from dmu_recv_begin. This must be done before 18093b2aab18SMatthew Ahrens * we return to open context, so that when we free the dataset's dnode, 18103b2aab18SMatthew Ahrens * we can evict its bonus buffer. 18113b2aab18SMatthew Ahrens */ 18123b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 18133b2aab18SMatthew Ahrens drc->drc_ds = NULL; 18143cb34c60Sahrens } 18153cb34c60Sahrens 1816ec5cf9d5SAlexander Stetsenko static int 18173b2aab18SMatthew Ahrens add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj) 1818ec5cf9d5SAlexander Stetsenko { 18193b2aab18SMatthew Ahrens dsl_pool_t *dp; 1820ec5cf9d5SAlexander Stetsenko dsl_dataset_t *snapds; 1821ec5cf9d5SAlexander Stetsenko guid_map_entry_t *gmep; 1822ec5cf9d5SAlexander Stetsenko int err; 1823ec5cf9d5SAlexander Stetsenko 1824ec5cf9d5SAlexander Stetsenko ASSERT(guid_map != NULL); 1825ec5cf9d5SAlexander Stetsenko 18263b2aab18SMatthew Ahrens err = dsl_pool_hold(name, FTAG, &dp); 18273b2aab18SMatthew Ahrens if (err != 0) 18283b2aab18SMatthew Ahrens return (err); 1829de8d9cffSMatthew Ahrens gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP); 1830de8d9cffSMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds); 1831ec5cf9d5SAlexander Stetsenko if (err == 0) { 1832ec5cf9d5SAlexander Stetsenko gmep->guid = snapds->ds_phys->ds_guid; 1833ec5cf9d5SAlexander Stetsenko gmep->gme_ds = snapds; 1834ec5cf9d5SAlexander Stetsenko avl_add(guid_map, gmep); 18353b2aab18SMatthew Ahrens dsl_dataset_long_hold(snapds, gmep); 1836de8d9cffSMatthew Ahrens } else { 1837de8d9cffSMatthew Ahrens kmem_free(gmep, sizeof (*gmep)); 1838ec5cf9d5SAlexander Stetsenko } 1839ec5cf9d5SAlexander Stetsenko 18403b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 1841ec5cf9d5SAlexander Stetsenko return (err); 1842ec5cf9d5SAlexander Stetsenko } 1843ec5cf9d5SAlexander Stetsenko 18443b2aab18SMatthew Ahrens static int dmu_recv_end_modified_blocks = 3; 18453b2aab18SMatthew Ahrens 1846ae46e4c7SMatthew Ahrens static int 1847ae46e4c7SMatthew Ahrens dmu_recv_existing_end(dmu_recv_cookie_t *drc) 1848f18faf3fSek { 18493b2aab18SMatthew Ahrens int error; 18503b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 18513cb34c60Sahrens 18523b2aab18SMatthew Ahrens #ifdef _KERNEL 18533b2aab18SMatthew Ahrens /* 18543b2aab18SMatthew Ahrens * We will be destroying the ds; make sure its origin is unmounted if 18553b2aab18SMatthew Ahrens * necessary. 18563b2aab18SMatthew Ahrens */ 18573b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 18583b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(name); 18593b2aab18SMatthew Ahrens #endif 18603cb34c60Sahrens 18613b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 18623b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 18633b2aab18SMatthew Ahrens dmu_recv_end_modified_blocks); 18643cb34c60Sahrens 18653b2aab18SMatthew Ahrens if (error != 0) 18663b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 18673b2aab18SMatthew Ahrens return (error); 1868f18faf3fSek } 1869ae46e4c7SMatthew Ahrens 1870ae46e4c7SMatthew Ahrens static int 1871ae46e4c7SMatthew Ahrens dmu_recv_new_end(dmu_recv_cookie_t *drc) 1872ae46e4c7SMatthew Ahrens { 18733b2aab18SMatthew Ahrens int error; 1874ae46e4c7SMatthew Ahrens 18753b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 18763b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 18773b2aab18SMatthew Ahrens dmu_recv_end_modified_blocks); 1878ae46e4c7SMatthew Ahrens 18793b2aab18SMatthew Ahrens if (error != 0) { 18803b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 18813b2aab18SMatthew Ahrens } else if (drc->drc_guid_to_ds_map != NULL) { 18823b2aab18SMatthew Ahrens (void) add_ds_to_guidmap(drc->drc_tofs, 18833b2aab18SMatthew Ahrens drc->drc_guid_to_ds_map, 18843b2aab18SMatthew Ahrens drc->drc_newsnapobj); 1885ae46e4c7SMatthew Ahrens } 18863b2aab18SMatthew Ahrens return (error); 1887ae46e4c7SMatthew Ahrens } 1888ae46e4c7SMatthew Ahrens 1889ae46e4c7SMatthew Ahrens int 189091948b51SKeith M Wesolowski dmu_recv_end(dmu_recv_cookie_t *drc, void *owner) 1891ae46e4c7SMatthew Ahrens { 189291948b51SKeith M Wesolowski drc->drc_owner = owner; 189391948b51SKeith M Wesolowski 18943b2aab18SMatthew Ahrens if (drc->drc_newfs) 1895ae46e4c7SMatthew Ahrens return (dmu_recv_new_end(drc)); 18963b2aab18SMatthew Ahrens else 18973b2aab18SMatthew Ahrens return (dmu_recv_existing_end(drc)); 1898ae46e4c7SMatthew Ahrens } 18992f3d8780SMatthew Ahrens 19002f3d8780SMatthew Ahrens /* 19012f3d8780SMatthew Ahrens * Return TRUE if this objset is currently being received into. 19022f3d8780SMatthew Ahrens */ 19032f3d8780SMatthew Ahrens boolean_t 19042f3d8780SMatthew Ahrens dmu_objset_is_receiving(objset_t *os) 19052f3d8780SMatthew Ahrens { 19062f3d8780SMatthew Ahrens return (os->os_dsl_dataset != NULL && 19072f3d8780SMatthew Ahrens os->os_dsl_dataset->ds_owner == dmu_recv_tag); 19082f3d8780SMatthew Ahrens } 1909