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. 247802d7bfSMatthew Ahrens * Copyright (c) 2011, 2014 by Delphix. All rights reserved. 25a2afb611SJerry Jelinek * Copyright (c) 2014, Joyent, Inc. All rights reserved. 26*e77d42eaSMatthew Ahrens * Copyright 2014 HybridCluster. All rights reserved. 27ec5cf9d5SAlexander Stetsenko */ 28efb80947Sahrens 29efb80947Sahrens #include <sys/dmu.h> 30efb80947Sahrens #include <sys/dmu_impl.h> 31efb80947Sahrens #include <sys/dmu_tx.h> 32efb80947Sahrens #include <sys/dbuf.h> 33efb80947Sahrens #include <sys/dnode.h> 34efb80947Sahrens #include <sys/zfs_context.h> 35efb80947Sahrens #include <sys/dmu_objset.h> 36efb80947Sahrens #include <sys/dmu_traverse.h> 37efb80947Sahrens #include <sys/dsl_dataset.h> 38efb80947Sahrens #include <sys/dsl_dir.h> 3992241e0bSTom Erickson #include <sys/dsl_prop.h> 40efb80947Sahrens #include <sys/dsl_pool.h> 41efb80947Sahrens #include <sys/dsl_synctask.h> 42efb80947Sahrens #include <sys/zfs_ioctl.h> 43efb80947Sahrens #include <sys/zap.h> 44efb80947Sahrens #include <sys/zio_checksum.h> 45dc7cd546SMark Shellenbaum #include <sys/zfs_znode.h> 46cde58dbcSMatthew Ahrens #include <zfs_fletcher.h> 479e69d7d0SLori Alt #include <sys/avl.h> 488e714474SLori Alt #include <sys/ddt.h> 49c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 503b2aab18SMatthew Ahrens #include <sys/dmu_send.h> 513b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 525d7b4d43SMatthew Ahrens #include <sys/blkptr.h> 5378f17100SMatthew Ahrens #include <sys/dsl_bookmark.h> 545d7b4d43SMatthew Ahrens #include <sys/zfeature.h> 55efb80947Sahrens 5619b94df9SMatthew Ahrens /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 5719b94df9SMatthew Ahrens int zfs_send_corrupt_data = B_FALSE; 5819b94df9SMatthew Ahrens 593cb34c60Sahrens static char *dmu_recv_tag = "dmu_recv_tag"; 603b2aab18SMatthew Ahrens static const char *recv_clone_name = "%recv"; 613cb34c60Sahrens 62efb80947Sahrens static int 634e3c9f44SBill Pijewski dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 64efb80947Sahrens { 654e3c9f44SBill Pijewski dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 66efb80947Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 67fb09f5aaSMadhav Suresh ASSERT0(len % 8); 68efb80947Sahrens 694e3c9f44SBill Pijewski fletcher_4_incremental_native(buf, len, &dsp->dsa_zc); 704e3c9f44SBill Pijewski dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp, 71efb80947Sahrens (caddr_t)buf, len, 72efb80947Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 734e3c9f44SBill Pijewski 744e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 754e3c9f44SBill Pijewski *dsp->dsa_off += len; 764e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 774e3c9f44SBill Pijewski 784e3c9f44SBill Pijewski return (dsp->dsa_err); 79efb80947Sahrens } 80efb80947Sahrens 81efb80947Sahrens static int 824e3c9f44SBill Pijewski dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 83efb80947Sahrens uint64_t length) 84efb80947Sahrens { 854e3c9f44SBill Pijewski struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free); 869e69d7d0SLori Alt 872f3d8780SMatthew Ahrens /* 882f3d8780SMatthew Ahrens * When we receive a free record, dbuf_free_range() assumes 892f3d8780SMatthew Ahrens * that the receiving system doesn't have any dbufs in the range 902f3d8780SMatthew Ahrens * being freed. This is always true because there is a one-record 912f3d8780SMatthew Ahrens * constraint: we only send one WRITE record for any given 922f3d8780SMatthew Ahrens * object+offset. We know that the one-record constraint is 932f3d8780SMatthew Ahrens * true because we always send data in increasing order by 942f3d8780SMatthew Ahrens * object,offset. 952f3d8780SMatthew Ahrens * 962f3d8780SMatthew Ahrens * If the increasing-order constraint ever changes, we should find 972f3d8780SMatthew Ahrens * another way to assert that the one-record constraint is still 982f3d8780SMatthew Ahrens * satisfied. 992f3d8780SMatthew Ahrens */ 1002f3d8780SMatthew Ahrens ASSERT(object > dsp->dsa_last_data_object || 1012f3d8780SMatthew Ahrens (object == dsp->dsa_last_data_object && 1022f3d8780SMatthew Ahrens offset > dsp->dsa_last_data_offset)); 1032f3d8780SMatthew Ahrens 1042f3d8780SMatthew Ahrens /* 1052f3d8780SMatthew Ahrens * If we are doing a non-incremental send, then there can't 1062f3d8780SMatthew Ahrens * be any data in the dataset we're receiving into. Therefore 1072f3d8780SMatthew Ahrens * a free record would simply be a no-op. Save space by not 1082f3d8780SMatthew Ahrens * sending it to begin with. 1092f3d8780SMatthew Ahrens */ 1102f3d8780SMatthew Ahrens if (!dsp->dsa_incremental) 1112f3d8780SMatthew Ahrens return (0); 1122f3d8780SMatthew Ahrens 113534029e5SSimon Klinkert if (length != -1ULL && offset + length < offset) 114534029e5SSimon Klinkert length = -1ULL; 115534029e5SSimon Klinkert 1169e69d7d0SLori Alt /* 1179e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREE, push it out, 1189e69d7d0SLori Alt * since free block aggregation can only be done for blocks of the 1199e69d7d0SLori Alt * same type (i.e., DRR_FREE records can only be aggregated with 1209e69d7d0SLori Alt * other DRR_FREE records. DRR_FREEOBJECTS records can only be 1219e69d7d0SLori Alt * aggregated with other DRR_FREEOBJECTS records. 1229e69d7d0SLori Alt */ 1234e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 1244e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREE) { 1254e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1264e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 127be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1284e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1299e69d7d0SLori Alt } 1309e69d7d0SLori Alt 1314e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREE) { 1329e69d7d0SLori Alt /* 1339e69d7d0SLori Alt * There should never be a PENDING_FREE if length is -1 1349e69d7d0SLori Alt * (because dump_dnode is the only place where this 1359e69d7d0SLori Alt * function is called with a -1, and only after flushing 1369e69d7d0SLori Alt * any pending record). 1379e69d7d0SLori Alt */ 1389e69d7d0SLori Alt ASSERT(length != -1ULL); 1399e69d7d0SLori Alt /* 1409e69d7d0SLori Alt * Check to see whether this free block can be aggregated 1419e69d7d0SLori Alt * with pending one. 1429e69d7d0SLori Alt */ 1439e69d7d0SLori Alt if (drrf->drr_object == object && drrf->drr_offset + 1449e69d7d0SLori Alt drrf->drr_length == offset) { 1459e69d7d0SLori Alt drrf->drr_length += length; 1469e69d7d0SLori Alt return (0); 1479e69d7d0SLori Alt } else { 1489e69d7d0SLori Alt /* not a continuation. Push out pending record */ 1494e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1509e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 151be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1524e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1539e69d7d0SLori Alt } 1549e69d7d0SLori Alt } 1559e69d7d0SLori Alt /* create a FREE record and make it pending */ 1564e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 1574e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREE; 1589e69d7d0SLori Alt drrf->drr_object = object; 1599e69d7d0SLori Alt drrf->drr_offset = offset; 1609e69d7d0SLori Alt drrf->drr_length = length; 1614e3c9f44SBill Pijewski drrf->drr_toguid = dsp->dsa_toguid; 1629e69d7d0SLori Alt if (length == -1ULL) { 1634e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1644e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 165be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1669e69d7d0SLori Alt } else { 1674e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREE; 1689e69d7d0SLori Alt } 169efb80947Sahrens 170efb80947Sahrens return (0); 171efb80947Sahrens } 172efb80947Sahrens 173efb80947Sahrens static int 1745d7b4d43SMatthew Ahrens dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type, 1758e714474SLori Alt uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) 176efb80947Sahrens { 1774e3c9f44SBill Pijewski struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write); 1789e69d7d0SLori Alt 1792f3d8780SMatthew Ahrens /* 1802f3d8780SMatthew Ahrens * We send data in increasing object, offset order. 1812f3d8780SMatthew Ahrens * See comment in dump_free() for details. 1822f3d8780SMatthew Ahrens */ 1832f3d8780SMatthew Ahrens ASSERT(object > dsp->dsa_last_data_object || 1842f3d8780SMatthew Ahrens (object == dsp->dsa_last_data_object && 1852f3d8780SMatthew Ahrens offset > dsp->dsa_last_data_offset)); 1862f3d8780SMatthew Ahrens dsp->dsa_last_data_object = object; 1872f3d8780SMatthew Ahrens dsp->dsa_last_data_offset = offset + blksz - 1; 1888e714474SLori Alt 1899e69d7d0SLori Alt /* 1909e69d7d0SLori Alt * If there is any kind of pending aggregation (currently either 1919e69d7d0SLori Alt * a grouping of free objects or free blocks), push it out to 1929e69d7d0SLori Alt * the stream, since aggregation can't be done across operations 1939e69d7d0SLori Alt * of different types. 1949e69d7d0SLori Alt */ 1954e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 1964e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1974e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 198be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1994e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2009e69d7d0SLori Alt } 201efb80947Sahrens /* write a DATA record */ 2024e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2034e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_WRITE; 2049e69d7d0SLori Alt drrw->drr_object = object; 2059e69d7d0SLori Alt drrw->drr_type = type; 2069e69d7d0SLori Alt drrw->drr_offset = offset; 2079e69d7d0SLori Alt drrw->drr_length = blksz; 2084e3c9f44SBill Pijewski drrw->drr_toguid = dsp->dsa_toguid; 2095d7b4d43SMatthew Ahrens if (BP_IS_EMBEDDED(bp)) { 2105d7b4d43SMatthew Ahrens /* 2115d7b4d43SMatthew Ahrens * There's no pre-computed checksum of embedded BP's, so 2125d7b4d43SMatthew Ahrens * (like fletcher4-checkummed blocks) userland will have 2135d7b4d43SMatthew Ahrens * to compute a dedup-capable checksum itself. 2145d7b4d43SMatthew Ahrens */ 2155d7b4d43SMatthew Ahrens drrw->drr_checksumtype = ZIO_CHECKSUM_OFF; 2165d7b4d43SMatthew Ahrens } else { 2175d7b4d43SMatthew Ahrens drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); 2185d7b4d43SMatthew Ahrens if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) 2195d7b4d43SMatthew Ahrens drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; 2205d7b4d43SMatthew Ahrens DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); 2215d7b4d43SMatthew Ahrens DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); 2225d7b4d43SMatthew Ahrens DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); 2235d7b4d43SMatthew Ahrens drrw->drr_key.ddk_cksum = bp->blk_cksum; 2245d7b4d43SMatthew Ahrens } 225efb80947Sahrens 2264e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 227be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2284e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz) != 0) 229be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 230efb80947Sahrens return (0); 231efb80947Sahrens } 232efb80947Sahrens 2335d7b4d43SMatthew Ahrens static int 2345d7b4d43SMatthew Ahrens dump_write_embedded(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 2355d7b4d43SMatthew Ahrens int blksz, const blkptr_t *bp) 2365d7b4d43SMatthew Ahrens { 2375d7b4d43SMatthew Ahrens char buf[BPE_PAYLOAD_SIZE]; 2385d7b4d43SMatthew Ahrens struct drr_write_embedded *drrw = 2395d7b4d43SMatthew Ahrens &(dsp->dsa_drr->drr_u.drr_write_embedded); 2405d7b4d43SMatthew Ahrens 2415d7b4d43SMatthew Ahrens if (dsp->dsa_pending_op != PENDING_NONE) { 2425d7b4d43SMatthew Ahrens if (dump_bytes(dsp, dsp->dsa_drr, 2435d7b4d43SMatthew Ahrens sizeof (dmu_replay_record_t)) != 0) 2445d7b4d43SMatthew Ahrens return (EINTR); 2455d7b4d43SMatthew Ahrens dsp->dsa_pending_op = PENDING_NONE; 2465d7b4d43SMatthew Ahrens } 2475d7b4d43SMatthew Ahrens 2485d7b4d43SMatthew Ahrens ASSERT(BP_IS_EMBEDDED(bp)); 2495d7b4d43SMatthew Ahrens 2505d7b4d43SMatthew Ahrens bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2515d7b4d43SMatthew Ahrens dsp->dsa_drr->drr_type = DRR_WRITE_EMBEDDED; 2525d7b4d43SMatthew Ahrens drrw->drr_object = object; 2535d7b4d43SMatthew Ahrens drrw->drr_offset = offset; 2545d7b4d43SMatthew Ahrens drrw->drr_length = blksz; 2555d7b4d43SMatthew Ahrens drrw->drr_toguid = dsp->dsa_toguid; 2565d7b4d43SMatthew Ahrens drrw->drr_compression = BP_GET_COMPRESS(bp); 2575d7b4d43SMatthew Ahrens drrw->drr_etype = BPE_GET_ETYPE(bp); 2585d7b4d43SMatthew Ahrens drrw->drr_lsize = BPE_GET_LSIZE(bp); 2595d7b4d43SMatthew Ahrens drrw->drr_psize = BPE_GET_PSIZE(bp); 2605d7b4d43SMatthew Ahrens 2615d7b4d43SMatthew Ahrens decode_embedded_bp_compressed(bp, buf); 2625d7b4d43SMatthew Ahrens 2635d7b4d43SMatthew Ahrens if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 2645d7b4d43SMatthew Ahrens return (EINTR); 2655d7b4d43SMatthew Ahrens if (dump_bytes(dsp, buf, P2ROUNDUP(drrw->drr_psize, 8)) != 0) 2665d7b4d43SMatthew Ahrens return (EINTR); 2675d7b4d43SMatthew Ahrens return (0); 2685d7b4d43SMatthew Ahrens } 2695d7b4d43SMatthew Ahrens 2700a586ceaSMark Shellenbaum static int 2714e3c9f44SBill Pijewski dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data) 2720a586ceaSMark Shellenbaum { 2734e3c9f44SBill Pijewski struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill); 2740a586ceaSMark Shellenbaum 2754e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 2764e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2774e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 278be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2794e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2800a586ceaSMark Shellenbaum } 2810a586ceaSMark Shellenbaum 2820a586ceaSMark Shellenbaum /* write a SPILL record */ 2834e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2844e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_SPILL; 2850a586ceaSMark Shellenbaum drrs->drr_object = object; 2860a586ceaSMark Shellenbaum drrs->drr_length = blksz; 2874e3c9f44SBill Pijewski drrs->drr_toguid = dsp->dsa_toguid; 2880a586ceaSMark Shellenbaum 2894e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t))) 290be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2914e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz)) 292be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2930a586ceaSMark Shellenbaum return (0); 2940a586ceaSMark Shellenbaum } 2950a586ceaSMark Shellenbaum 296efb80947Sahrens static int 2974e3c9f44SBill Pijewski dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs) 298efb80947Sahrens { 2994e3c9f44SBill Pijewski struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects); 3009e69d7d0SLori Alt 3012f3d8780SMatthew Ahrens /* See comment in dump_free(). */ 3022f3d8780SMatthew Ahrens if (!dsp->dsa_incremental) 3032f3d8780SMatthew Ahrens return (0); 3042f3d8780SMatthew Ahrens 3059e69d7d0SLori Alt /* 3069e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREEOBJECTS, 3079e69d7d0SLori Alt * push it out, since free block aggregation can only be done for 3089e69d7d0SLori Alt * blocks of the same type (i.e., DRR_FREE records can only be 3099e69d7d0SLori Alt * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records 3109e69d7d0SLori Alt * can only be aggregated with other DRR_FREEOBJECTS records. 3119e69d7d0SLori Alt */ 3124e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 3134e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREEOBJECTS) { 3144e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3154e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 316be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3174e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3189e69d7d0SLori Alt } 3194e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) { 3209e69d7d0SLori Alt /* 3219e69d7d0SLori Alt * See whether this free object array can be aggregated 3229e69d7d0SLori Alt * with pending one 3239e69d7d0SLori Alt */ 3249e69d7d0SLori Alt if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { 3259e69d7d0SLori Alt drrfo->drr_numobjs += numobjs; 3269e69d7d0SLori Alt return (0); 3279e69d7d0SLori Alt } else { 3289e69d7d0SLori Alt /* can't be aggregated. Push out pending record */ 3294e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3309e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 331be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3324e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3339e69d7d0SLori Alt } 3349e69d7d0SLori Alt } 3359e69d7d0SLori Alt 336efb80947Sahrens /* write a FREEOBJECTS record */ 3374e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 3384e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREEOBJECTS; 3399e69d7d0SLori Alt drrfo->drr_firstobj = firstobj; 3409e69d7d0SLori Alt drrfo->drr_numobjs = numobjs; 3414e3c9f44SBill Pijewski drrfo->drr_toguid = dsp->dsa_toguid; 3429e69d7d0SLori Alt 3434e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREEOBJECTS; 344efb80947Sahrens 345efb80947Sahrens return (0); 346efb80947Sahrens } 347efb80947Sahrens 348efb80947Sahrens static int 3494e3c9f44SBill Pijewski dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp) 350efb80947Sahrens { 3514e3c9f44SBill Pijewski struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object); 3529e69d7d0SLori Alt 353efb80947Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 3544e3c9f44SBill Pijewski return (dump_freeobjects(dsp, object, 1)); 355efb80947Sahrens 3564e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 3574e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3584e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 359be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3604e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3619e69d7d0SLori Alt } 3629e69d7d0SLori Alt 363efb80947Sahrens /* write an OBJECT record */ 3644e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 3654e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_OBJECT; 3669e69d7d0SLori Alt drro->drr_object = object; 3679e69d7d0SLori Alt drro->drr_type = dnp->dn_type; 3689e69d7d0SLori Alt drro->drr_bonustype = dnp->dn_bonustype; 3699e69d7d0SLori Alt drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 3709e69d7d0SLori Alt drro->drr_bonuslen = dnp->dn_bonuslen; 3719e69d7d0SLori Alt drro->drr_checksumtype = dnp->dn_checksum; 3729e69d7d0SLori Alt drro->drr_compress = dnp->dn_compress; 3734e3c9f44SBill Pijewski drro->drr_toguid = dsp->dsa_toguid; 3749e69d7d0SLori Alt 3754e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 376be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 377efb80947Sahrens 3784e3c9f44SBill Pijewski if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 379be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 380efb80947Sahrens 3812f3d8780SMatthew Ahrens /* Free anything past the end of the file. */ 3824e3c9f44SBill Pijewski if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 3832f3d8780SMatthew Ahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL) != 0) 384be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3853b2aab18SMatthew Ahrens if (dsp->dsa_err != 0) 386be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 387efb80947Sahrens return (0); 388efb80947Sahrens } 389efb80947Sahrens 3905d7b4d43SMatthew Ahrens static boolean_t 3915d7b4d43SMatthew Ahrens backup_do_embed(dmu_sendarg_t *dsp, const blkptr_t *bp) 3925d7b4d43SMatthew Ahrens { 3935d7b4d43SMatthew Ahrens if (!BP_IS_EMBEDDED(bp)) 3945d7b4d43SMatthew Ahrens return (B_FALSE); 3955d7b4d43SMatthew Ahrens 3965d7b4d43SMatthew Ahrens /* 3975d7b4d43SMatthew Ahrens * Compression function must be legacy, or explicitly enabled. 3985d7b4d43SMatthew Ahrens */ 3995d7b4d43SMatthew Ahrens if ((BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_LEGACY_FUNCTIONS && 4005d7b4d43SMatthew Ahrens !(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_EMBED_DATA_LZ4))) 4015d7b4d43SMatthew Ahrens return (B_FALSE); 4025d7b4d43SMatthew Ahrens 4035d7b4d43SMatthew Ahrens /* 4045d7b4d43SMatthew Ahrens * Embed type must be explicitly enabled. 4055d7b4d43SMatthew Ahrens */ 4065d7b4d43SMatthew Ahrens switch (BPE_GET_ETYPE(bp)) { 4075d7b4d43SMatthew Ahrens case BP_EMBEDDED_TYPE_DATA: 4085d7b4d43SMatthew Ahrens if (dsp->dsa_featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) 4095d7b4d43SMatthew Ahrens return (B_TRUE); 4105d7b4d43SMatthew Ahrens break; 4115d7b4d43SMatthew Ahrens default: 4125d7b4d43SMatthew Ahrens return (B_FALSE); 4135d7b4d43SMatthew Ahrens } 4145d7b4d43SMatthew Ahrens return (B_FALSE); 4155d7b4d43SMatthew Ahrens } 4165d7b4d43SMatthew Ahrens 417efb80947Sahrens #define BP_SPAN(dnp, level) \ 418efb80947Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 419efb80947Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 420efb80947Sahrens 421b24ab676SJeff Bonwick /* ARGSUSED */ 422efb80947Sahrens static int 4231b912ec7SGeorge Wilson backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 4247802d7bfSMatthew Ahrens const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 425efb80947Sahrens { 4264e3c9f44SBill Pijewski dmu_sendarg_t *dsp = arg; 427efb80947Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 428efb80947Sahrens int err = 0; 429efb80947Sahrens 430efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 431be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 432efb80947Sahrens 433b24ab676SJeff Bonwick if (zb->zb_object != DMU_META_DNODE_OBJECT && 434b24ab676SJeff Bonwick DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 43514843421SMatthew Ahrens return (0); 43678f17100SMatthew Ahrens } else if (zb->zb_level == ZB_ZIL_LEVEL) { 43778f17100SMatthew Ahrens /* 43878f17100SMatthew Ahrens * If we are sending a non-snapshot (which is allowed on 43978f17100SMatthew Ahrens * read-only pools), it may have a ZIL, which must be ignored. 44078f17100SMatthew Ahrens */ 44178f17100SMatthew Ahrens return (0); 44243466aaeSMax Grossman } else if (BP_IS_HOLE(bp) && 44343466aaeSMax Grossman zb->zb_object == DMU_META_DNODE_OBJECT) { 44488b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 44588b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 4464e3c9f44SBill Pijewski err = dump_freeobjects(dsp, dnobj, span >> DNODE_SHIFT); 44743466aaeSMax Grossman } else if (BP_IS_HOLE(bp)) { 44888b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 4494e3c9f44SBill Pijewski err = dump_free(dsp, zb->zb_object, zb->zb_blkid * span, span); 45088b7b0f2SMatthew Ahrens } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 45188b7b0f2SMatthew Ahrens return (0); 45288b7b0f2SMatthew Ahrens } else if (type == DMU_OT_DNODE) { 45388b7b0f2SMatthew Ahrens dnode_phys_t *blk; 454efb80947Sahrens int i; 455efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 45688b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 45788b7b0f2SMatthew Ahrens arc_buf_t *abuf; 458efb80947Sahrens 4591b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4601b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4611b912ec7SGeorge Wilson &aflags, zb) != 0) 462be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 46388b7b0f2SMatthew Ahrens 46488b7b0f2SMatthew Ahrens blk = abuf->b_data; 465efb80947Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 46688b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid << 46788b7b0f2SMatthew Ahrens (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 4684e3c9f44SBill Pijewski err = dump_dnode(dsp, dnobj, blk+i); 4693b2aab18SMatthew Ahrens if (err != 0) 470efb80947Sahrens break; 471efb80947Sahrens } 47288b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 4730a586ceaSMark Shellenbaum } else if (type == DMU_OT_SA) { 4740a586ceaSMark Shellenbaum uint32_t aflags = ARC_WAIT; 4750a586ceaSMark Shellenbaum arc_buf_t *abuf; 4760a586ceaSMark Shellenbaum int blksz = BP_GET_LSIZE(bp); 4770a586ceaSMark Shellenbaum 4781b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4791b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4801b912ec7SGeorge Wilson &aflags, zb) != 0) 481be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 4820a586ceaSMark Shellenbaum 4834e3c9f44SBill Pijewski err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data); 4840a586ceaSMark Shellenbaum (void) arc_buf_remove_ref(abuf, &abuf); 4855d7b4d43SMatthew Ahrens } else if (backup_do_embed(dsp, bp)) { 4865d7b4d43SMatthew Ahrens /* it's an embedded level-0 block of a regular object */ 4875d7b4d43SMatthew Ahrens int blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 4885d7b4d43SMatthew Ahrens err = dump_write_embedded(dsp, zb->zb_object, 4895d7b4d43SMatthew Ahrens zb->zb_blkid * blksz, blksz, bp); 49088b7b0f2SMatthew Ahrens } else { /* it's a level-0 block of a regular object */ 49188b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 49288b7b0f2SMatthew Ahrens arc_buf_t *abuf; 493efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 49488b7b0f2SMatthew Ahrens 4955d7b4d43SMatthew Ahrens ASSERT3U(blksz, ==, dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT); 49678f17100SMatthew Ahrens ASSERT0(zb->zb_level); 4971b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4981b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4991b912ec7SGeorge Wilson &aflags, zb) != 0) { 50019b94df9SMatthew Ahrens if (zfs_send_corrupt_data) { 50119b94df9SMatthew Ahrens /* Send a block filled with 0x"zfs badd bloc" */ 50219b94df9SMatthew Ahrens abuf = arc_buf_alloc(spa, blksz, &abuf, 50319b94df9SMatthew Ahrens ARC_BUFC_DATA); 50419b94df9SMatthew Ahrens uint64_t *ptr; 50519b94df9SMatthew Ahrens for (ptr = abuf->b_data; 50619b94df9SMatthew Ahrens (char *)ptr < (char *)abuf->b_data + blksz; 50719b94df9SMatthew Ahrens ptr++) 50819b94df9SMatthew Ahrens *ptr = 0x2f5baddb10c; 50919b94df9SMatthew Ahrens } else { 510be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 51119b94df9SMatthew Ahrens } 51219b94df9SMatthew Ahrens } 51388b7b0f2SMatthew Ahrens 5145d7b4d43SMatthew Ahrens err = dump_write(dsp, type, zb->zb_object, zb->zb_blkid * blksz, 5158e714474SLori Alt blksz, bp, abuf->b_data); 51688b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 517efb80947Sahrens } 518efb80947Sahrens 519efb80947Sahrens ASSERT(err == 0 || err == EINTR); 520efb80947Sahrens return (err); 521efb80947Sahrens } 522efb80947Sahrens 5234445fffbSMatthew Ahrens /* 52478f17100SMatthew Ahrens * Releases dp using the specified tag. 5254445fffbSMatthew Ahrens */ 5263b2aab18SMatthew Ahrens static int 5273b2aab18SMatthew Ahrens dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds, 5285d7b4d43SMatthew Ahrens zfs_bookmark_phys_t *fromzb, boolean_t is_clone, boolean_t embedok, 5295d7b4d43SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 530efb80947Sahrens { 5313b2aab18SMatthew Ahrens objset_t *os; 532efb80947Sahrens dmu_replay_record_t *drr; 5334e3c9f44SBill Pijewski dmu_sendarg_t *dsp; 534efb80947Sahrens int err; 5353cb34c60Sahrens uint64_t fromtxg = 0; 5365d7b4d43SMatthew Ahrens uint64_t featureflags = 0; 537efb80947Sahrens 5383b2aab18SMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 5393b2aab18SMatthew Ahrens if (err != 0) { 5403b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 5413b2aab18SMatthew Ahrens return (err); 5423b2aab18SMatthew Ahrens } 543efb80947Sahrens 544efb80947Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 545efb80947Sahrens drr->drr_type = DRR_BEGIN; 546efb80947Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 5479e69d7d0SLori Alt DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 5489e69d7d0SLori Alt DMU_SUBSTREAM); 549dc7cd546SMark Shellenbaum 550dc7cd546SMark Shellenbaum #ifdef _KERNEL 5513b2aab18SMatthew Ahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 552dc7cd546SMark Shellenbaum uint64_t version; 5533b2aab18SMatthew Ahrens if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) { 5544e3c9f44SBill Pijewski kmem_free(drr, sizeof (dmu_replay_record_t)); 5553b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 556be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5574e3c9f44SBill Pijewski } 5583b2aab18SMatthew Ahrens if (version >= ZPL_VERSION_SA) { 5595d7b4d43SMatthew Ahrens featureflags |= DMU_BACKUP_FEATURE_SA_SPILL; 560dc7cd546SMark Shellenbaum } 561dc7cd546SMark Shellenbaum } 562dc7cd546SMark Shellenbaum #endif 563dc7cd546SMark Shellenbaum 5645d7b4d43SMatthew Ahrens if (embedok && 5655d7b4d43SMatthew Ahrens spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) { 5665d7b4d43SMatthew Ahrens featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA; 5675d7b4d43SMatthew Ahrens if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) 5685d7b4d43SMatthew Ahrens featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA_LZ4; 5695d7b4d43SMatthew Ahrens } else { 5705d7b4d43SMatthew Ahrens embedok = B_FALSE; 5715d7b4d43SMatthew Ahrens } 5725d7b4d43SMatthew Ahrens 5735d7b4d43SMatthew Ahrens DMU_SET_FEATUREFLAGS(drr->drr_u.drr_begin.drr_versioninfo, 5745d7b4d43SMatthew Ahrens featureflags); 5755d7b4d43SMatthew Ahrens 576efb80947Sahrens drr->drr_u.drr_begin.drr_creation_time = 577efb80947Sahrens ds->ds_phys->ds_creation_time; 5783b2aab18SMatthew Ahrens drr->drr_u.drr_begin.drr_type = dmu_objset_type(os); 57978f17100SMatthew Ahrens if (is_clone) 5803cb34c60Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 581efb80947Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 582ab04eb8eStimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 583ab04eb8eStimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 584ab04eb8eStimh 58578f17100SMatthew Ahrens if (fromzb != NULL) { 58678f17100SMatthew Ahrens drr->drr_u.drr_begin.drr_fromguid = fromzb->zbm_guid; 58778f17100SMatthew Ahrens fromtxg = fromzb->zbm_creation_txg; 58878f17100SMatthew Ahrens } 589efb80947Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 59078f17100SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 59178f17100SMatthew Ahrens (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--", 59278f17100SMatthew Ahrens sizeof (drr->drr_u.drr_begin.drr_toname)); 5933b2aab18SMatthew Ahrens } 5943cb34c60Sahrens 5954e3c9f44SBill Pijewski dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 5964e3c9f44SBill Pijewski 5974e3c9f44SBill Pijewski dsp->dsa_drr = drr; 5984e3c9f44SBill Pijewski dsp->dsa_vp = vp; 5994e3c9f44SBill Pijewski dsp->dsa_outfd = outfd; 6004e3c9f44SBill Pijewski dsp->dsa_proc = curproc; 6013b2aab18SMatthew Ahrens dsp->dsa_os = os; 6024e3c9f44SBill Pijewski dsp->dsa_off = off; 6034e3c9f44SBill Pijewski dsp->dsa_toguid = ds->ds_phys->ds_guid; 6044e3c9f44SBill Pijewski ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 6054e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 60678f17100SMatthew Ahrens dsp->dsa_incremental = (fromzb != NULL); 6075d7b4d43SMatthew Ahrens dsp->dsa_featureflags = featureflags; 6084e3c9f44SBill Pijewski 6094e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 6104e3c9f44SBill Pijewski list_insert_head(&ds->ds_sendstreams, dsp); 6114e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 6124e3c9f44SBill Pijewski 613de8d9cffSMatthew Ahrens dsl_dataset_long_hold(ds, FTAG); 614de8d9cffSMatthew Ahrens dsl_pool_rele(dp, tag); 615de8d9cffSMatthew Ahrens 6164e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 6174e3c9f44SBill Pijewski err = dsp->dsa_err; 6184e3c9f44SBill Pijewski goto out; 619efb80947Sahrens } 620efb80947Sahrens 62188b7b0f2SMatthew Ahrens err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 6224e3c9f44SBill Pijewski backup_cb, dsp); 623efb80947Sahrens 6244e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) 6254e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 626be6fd75aSMatthew Ahrens err = SET_ERROR(EINTR); 6279e69d7d0SLori Alt 6283b2aab18SMatthew Ahrens if (err != 0) { 6293b2aab18SMatthew Ahrens if (err == EINTR && dsp->dsa_err != 0) 6304e3c9f44SBill Pijewski err = dsp->dsa_err; 6314e3c9f44SBill Pijewski goto out; 632efb80947Sahrens } 633efb80947Sahrens 634efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 635efb80947Sahrens drr->drr_type = DRR_END; 6364e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 6374e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; 638efb80947Sahrens 6394e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 6404e3c9f44SBill Pijewski err = dsp->dsa_err; 6414e3c9f44SBill Pijewski goto out; 6427b5309bbSgw } 643efb80947Sahrens 6444e3c9f44SBill Pijewski out: 6454e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 6464e3c9f44SBill Pijewski list_remove(&ds->ds_sendstreams, dsp); 6474e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 6484e3c9f44SBill Pijewski 649efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 6504e3c9f44SBill Pijewski kmem_free(dsp, sizeof (dmu_sendarg_t)); 651efb80947Sahrens 6523b2aab18SMatthew Ahrens dsl_dataset_long_rele(ds, FTAG); 6533b2aab18SMatthew Ahrens 6544e3c9f44SBill Pijewski return (err); 655efb80947Sahrens } 656efb80947Sahrens 65719b94df9SMatthew Ahrens int 6583b2aab18SMatthew Ahrens dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, 6595d7b4d43SMatthew Ahrens boolean_t embedok, int outfd, vnode_t *vp, offset_t *off) 6603b2aab18SMatthew Ahrens { 6613b2aab18SMatthew Ahrens dsl_pool_t *dp; 6623b2aab18SMatthew Ahrens dsl_dataset_t *ds; 6633b2aab18SMatthew Ahrens dsl_dataset_t *fromds = NULL; 6643b2aab18SMatthew Ahrens int err; 6653b2aab18SMatthew Ahrens 6663b2aab18SMatthew Ahrens err = dsl_pool_hold(pool, FTAG, &dp); 6673b2aab18SMatthew Ahrens if (err != 0) 6683b2aab18SMatthew Ahrens return (err); 6693b2aab18SMatthew Ahrens 6703b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds); 6713b2aab18SMatthew Ahrens if (err != 0) { 6723b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 6733b2aab18SMatthew Ahrens return (err); 6743b2aab18SMatthew Ahrens } 6753b2aab18SMatthew Ahrens 6763b2aab18SMatthew Ahrens if (fromsnap != 0) { 67778f17100SMatthew Ahrens zfs_bookmark_phys_t zb; 67878f17100SMatthew Ahrens boolean_t is_clone; 67978f17100SMatthew Ahrens 6803b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds); 6813b2aab18SMatthew Ahrens if (err != 0) { 6823b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 6833b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 6843b2aab18SMatthew Ahrens return (err); 6853b2aab18SMatthew Ahrens } 68678f17100SMatthew Ahrens if (!dsl_dataset_is_before(ds, fromds, 0)) 68778f17100SMatthew Ahrens err = SET_ERROR(EXDEV); 68878f17100SMatthew Ahrens zb.zbm_creation_time = fromds->ds_phys->ds_creation_time; 68978f17100SMatthew Ahrens zb.zbm_creation_txg = fromds->ds_phys->ds_creation_txg; 69078f17100SMatthew Ahrens zb.zbm_guid = fromds->ds_phys->ds_guid; 69178f17100SMatthew Ahrens is_clone = (fromds->ds_dir != ds->ds_dir); 69278f17100SMatthew Ahrens dsl_dataset_rele(fromds, FTAG); 6935d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone, embedok, 69478f17100SMatthew Ahrens outfd, vp, off); 69578f17100SMatthew Ahrens } else { 6965d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE, embedok, 69778f17100SMatthew Ahrens outfd, vp, off); 6983b2aab18SMatthew Ahrens } 69978f17100SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 70078f17100SMatthew Ahrens return (err); 7013b2aab18SMatthew Ahrens } 7023b2aab18SMatthew Ahrens 7033b2aab18SMatthew Ahrens int 7045d7b4d43SMatthew Ahrens dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok, 7053b2aab18SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 7063b2aab18SMatthew Ahrens { 7073b2aab18SMatthew Ahrens dsl_pool_t *dp; 7083b2aab18SMatthew Ahrens dsl_dataset_t *ds; 7093b2aab18SMatthew Ahrens int err; 71078f17100SMatthew Ahrens boolean_t owned = B_FALSE; 7113b2aab18SMatthew Ahrens 71278f17100SMatthew Ahrens if (fromsnap != NULL && strpbrk(fromsnap, "@#") == NULL) 713be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 7143b2aab18SMatthew Ahrens 7153b2aab18SMatthew Ahrens err = dsl_pool_hold(tosnap, FTAG, &dp); 7163b2aab18SMatthew Ahrens if (err != 0) 7173b2aab18SMatthew Ahrens return (err); 7183b2aab18SMatthew Ahrens 71978f17100SMatthew Ahrens if (strchr(tosnap, '@') == NULL && spa_writeable(dp->dp_spa)) { 72078f17100SMatthew Ahrens /* 72178f17100SMatthew Ahrens * We are sending a filesystem or volume. Ensure 72278f17100SMatthew Ahrens * that it doesn't change by owning the dataset. 72378f17100SMatthew Ahrens */ 72478f17100SMatthew Ahrens err = dsl_dataset_own(dp, tosnap, FTAG, &ds); 72578f17100SMatthew Ahrens owned = B_TRUE; 72678f17100SMatthew Ahrens } else { 72778f17100SMatthew Ahrens err = dsl_dataset_hold(dp, tosnap, FTAG, &ds); 72878f17100SMatthew Ahrens } 7293b2aab18SMatthew Ahrens if (err != 0) { 7303b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 7313b2aab18SMatthew Ahrens return (err); 7323b2aab18SMatthew Ahrens } 7333b2aab18SMatthew Ahrens 7343b2aab18SMatthew Ahrens if (fromsnap != NULL) { 73578f17100SMatthew Ahrens zfs_bookmark_phys_t zb; 73678f17100SMatthew Ahrens boolean_t is_clone = B_FALSE; 73778f17100SMatthew Ahrens int fsnamelen = strchr(tosnap, '@') - tosnap; 73878f17100SMatthew Ahrens 73978f17100SMatthew Ahrens /* 74078f17100SMatthew Ahrens * If the fromsnap is in a different filesystem, then 74178f17100SMatthew Ahrens * mark the send stream as a clone. 74278f17100SMatthew Ahrens */ 74378f17100SMatthew Ahrens if (strncmp(tosnap, fromsnap, fsnamelen) != 0 || 74478f17100SMatthew Ahrens (fromsnap[fsnamelen] != '@' && 74578f17100SMatthew Ahrens fromsnap[fsnamelen] != '#')) { 74678f17100SMatthew Ahrens is_clone = B_TRUE; 74778f17100SMatthew Ahrens } 74878f17100SMatthew Ahrens 74978f17100SMatthew Ahrens if (strchr(fromsnap, '@')) { 75078f17100SMatthew Ahrens dsl_dataset_t *fromds; 75178f17100SMatthew Ahrens err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds); 75278f17100SMatthew Ahrens if (err == 0) { 75378f17100SMatthew Ahrens if (!dsl_dataset_is_before(ds, fromds, 0)) 75478f17100SMatthew Ahrens err = SET_ERROR(EXDEV); 75578f17100SMatthew Ahrens zb.zbm_creation_time = 75678f17100SMatthew Ahrens fromds->ds_phys->ds_creation_time; 75778f17100SMatthew Ahrens zb.zbm_creation_txg = 75878f17100SMatthew Ahrens fromds->ds_phys->ds_creation_txg; 75978f17100SMatthew Ahrens zb.zbm_guid = fromds->ds_phys->ds_guid; 76078f17100SMatthew Ahrens is_clone = (ds->ds_dir != fromds->ds_dir); 76178f17100SMatthew Ahrens dsl_dataset_rele(fromds, FTAG); 76278f17100SMatthew Ahrens } 76378f17100SMatthew Ahrens } else { 76478f17100SMatthew Ahrens err = dsl_bookmark_lookup(dp, fromsnap, ds, &zb); 76578f17100SMatthew Ahrens } 7663b2aab18SMatthew Ahrens if (err != 0) { 7673b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 7683b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 7693b2aab18SMatthew Ahrens return (err); 7703b2aab18SMatthew Ahrens } 7715d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone, embedok, 77278f17100SMatthew Ahrens outfd, vp, off); 77378f17100SMatthew Ahrens } else { 7745d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE, embedok, 77578f17100SMatthew Ahrens outfd, vp, off); 7763b2aab18SMatthew Ahrens } 77778f17100SMatthew Ahrens if (owned) 77878f17100SMatthew Ahrens dsl_dataset_disown(ds, FTAG); 77978f17100SMatthew Ahrens else 78078f17100SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 78178f17100SMatthew Ahrens return (err); 7823b2aab18SMatthew Ahrens } 7833b2aab18SMatthew Ahrens 7843b2aab18SMatthew Ahrens int 7853b2aab18SMatthew Ahrens dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep) 78619b94df9SMatthew Ahrens { 78719b94df9SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 78819b94df9SMatthew Ahrens int err; 78919b94df9SMatthew Ahrens uint64_t size; 79019b94df9SMatthew Ahrens 7913b2aab18SMatthew Ahrens ASSERT(dsl_pool_config_held(dp)); 7923b2aab18SMatthew Ahrens 79319b94df9SMatthew Ahrens /* tosnap must be a snapshot */ 7943b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) 795be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 79619b94df9SMatthew Ahrens 7974445fffbSMatthew Ahrens /* 7984445fffbSMatthew Ahrens * fromsnap must be an earlier snapshot from the same fs as tosnap, 7994445fffbSMatthew Ahrens * or the origin's fs. 8004445fffbSMatthew Ahrens */ 80178f17100SMatthew Ahrens if (fromds != NULL && !dsl_dataset_is_before(ds, fromds, 0)) 802be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 80319b94df9SMatthew Ahrens 80419b94df9SMatthew Ahrens /* Get uncompressed size estimate of changed data. */ 80519b94df9SMatthew Ahrens if (fromds == NULL) { 80619b94df9SMatthew Ahrens size = ds->ds_phys->ds_uncompressed_bytes; 80719b94df9SMatthew Ahrens } else { 80819b94df9SMatthew Ahrens uint64_t used, comp; 80919b94df9SMatthew Ahrens err = dsl_dataset_space_written(fromds, ds, 81019b94df9SMatthew Ahrens &used, &comp, &size); 8113b2aab18SMatthew Ahrens if (err != 0) 81219b94df9SMatthew Ahrens return (err); 81319b94df9SMatthew Ahrens } 81419b94df9SMatthew Ahrens 81519b94df9SMatthew Ahrens /* 81619b94df9SMatthew Ahrens * Assume that space (both on-disk and in-stream) is dominated by 81719b94df9SMatthew Ahrens * data. We will adjust for indirect blocks and the copies property, 81819b94df9SMatthew Ahrens * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 81919b94df9SMatthew Ahrens */ 82019b94df9SMatthew Ahrens 82119b94df9SMatthew Ahrens /* 82219b94df9SMatthew Ahrens * Subtract out approximate space used by indirect blocks. 82319b94df9SMatthew Ahrens * Assume most space is used by data blocks (non-indirect, non-dnode). 82419b94df9SMatthew Ahrens * Assume all blocks are recordsize. Assume ditto blocks and 82519b94df9SMatthew Ahrens * internal fragmentation counter out compression. 82619b94df9SMatthew Ahrens * 82719b94df9SMatthew Ahrens * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 82819b94df9SMatthew Ahrens * block, which we observe in practice. 82919b94df9SMatthew Ahrens */ 83019b94df9SMatthew Ahrens uint64_t recordsize; 8313b2aab18SMatthew Ahrens err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize); 8323b2aab18SMatthew Ahrens if (err != 0) 83319b94df9SMatthew Ahrens return (err); 83419b94df9SMatthew Ahrens size -= size / recordsize * sizeof (blkptr_t); 83519b94df9SMatthew Ahrens 83619b94df9SMatthew Ahrens /* Add in the space for the record associated with each block. */ 83719b94df9SMatthew Ahrens size += size / recordsize * sizeof (dmu_replay_record_t); 83819b94df9SMatthew Ahrens 83919b94df9SMatthew Ahrens *sizep = size; 84019b94df9SMatthew Ahrens 84119b94df9SMatthew Ahrens return (0); 84219b94df9SMatthew Ahrens } 84319b94df9SMatthew Ahrens 8443b2aab18SMatthew Ahrens typedef struct dmu_recv_begin_arg { 8453b2aab18SMatthew Ahrens const char *drba_origin; 8463b2aab18SMatthew Ahrens dmu_recv_cookie_t *drba_cookie; 8473b2aab18SMatthew Ahrens cred_t *drba_cred; 84834f2f8cfSMatthew Ahrens uint64_t drba_snapobj; 8493b2aab18SMatthew Ahrens } dmu_recv_begin_arg_t; 850f18faf3fSek 851f18faf3fSek static int 8523b2aab18SMatthew Ahrens recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds, 8533b2aab18SMatthew Ahrens uint64_t fromguid) 854f18faf3fSek { 8553cb34c60Sahrens uint64_t val; 8563b2aab18SMatthew Ahrens int error; 8573b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 858f18faf3fSek 8593b2aab18SMatthew Ahrens /* temporary clone name must not exist */ 8603b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 8613b2aab18SMatthew Ahrens ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name, 8623b2aab18SMatthew Ahrens 8, 1, &val); 8633b2aab18SMatthew Ahrens if (error != ENOENT) 8643b2aab18SMatthew Ahrens return (error == 0 ? EBUSY : error); 8653b2aab18SMatthew Ahrens 866feaa74e4SMark Maybee /* new snapshot name must not exist */ 8673b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 8683b2aab18SMatthew Ahrens ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap, 8693b2aab18SMatthew Ahrens 8, 1, &val); 8703b2aab18SMatthew Ahrens if (error != ENOENT) 8713b2aab18SMatthew Ahrens return (error == 0 ? EEXIST : error); 872feaa74e4SMark Maybee 873a2afb611SJerry Jelinek /* 874a2afb611SJerry Jelinek * Check snapshot limit before receiving. We'll recheck again at the 875a2afb611SJerry Jelinek * end, but might as well abort before receiving if we're already over 876a2afb611SJerry Jelinek * the limit. 877a2afb611SJerry Jelinek * 878a2afb611SJerry Jelinek * Note that we do not check the file system limit with 879a2afb611SJerry Jelinek * dsl_dir_fscount_check because the temporary %clones don't count 880a2afb611SJerry Jelinek * against that limit. 881a2afb611SJerry Jelinek */ 882a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT, 883a2afb611SJerry Jelinek NULL, drba->drba_cred); 884a2afb611SJerry Jelinek if (error != 0) 885a2afb611SJerry Jelinek return (error); 886a2afb611SJerry Jelinek 8873b2aab18SMatthew Ahrens if (fromguid != 0) { 88834f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 88934f2f8cfSMatthew Ahrens uint64_t obj = ds->ds_phys->ds_prev_snap_obj; 89034f2f8cfSMatthew Ahrens 89134f2f8cfSMatthew Ahrens /* Find snapshot in this dir that matches fromguid. */ 89234f2f8cfSMatthew Ahrens while (obj != 0) { 89334f2f8cfSMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 89434f2f8cfSMatthew Ahrens &snap); 89534f2f8cfSMatthew Ahrens if (error != 0) 89634f2f8cfSMatthew Ahrens return (SET_ERROR(ENODEV)); 89734f2f8cfSMatthew Ahrens if (snap->ds_dir != ds->ds_dir) { 89834f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 89934f2f8cfSMatthew Ahrens return (SET_ERROR(ENODEV)); 90034f2f8cfSMatthew Ahrens } 90134f2f8cfSMatthew Ahrens if (snap->ds_phys->ds_guid == fromguid) 90234f2f8cfSMatthew Ahrens break; 90334f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 90434f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 90534f2f8cfSMatthew Ahrens } 90634f2f8cfSMatthew Ahrens if (obj == 0) 907be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 90892241e0bSTom Erickson 90934f2f8cfSMatthew Ahrens if (drba->drba_cookie->drc_force) { 91034f2f8cfSMatthew Ahrens drba->drba_snapobj = obj; 91134f2f8cfSMatthew Ahrens } else { 91234f2f8cfSMatthew Ahrens /* 91334f2f8cfSMatthew Ahrens * If we are not forcing, there must be no 91434f2f8cfSMatthew Ahrens * changes since fromsnap. 91534f2f8cfSMatthew Ahrens */ 91634f2f8cfSMatthew Ahrens if (dsl_dataset_modified_since_snap(ds, snap)) { 91792241e0bSTom Erickson dsl_dataset_rele(snap, FTAG); 91834f2f8cfSMatthew Ahrens return (SET_ERROR(ETXTBSY)); 91992241e0bSTom Erickson } 92034f2f8cfSMatthew Ahrens drba->drba_snapobj = ds->ds_prev->ds_object; 92192241e0bSTom Erickson } 92234f2f8cfSMatthew Ahrens 92334f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 924ae46e4c7SMatthew Ahrens } else { 925ae46e4c7SMatthew Ahrens /* if full, most recent snapshot must be $ORIGIN */ 926ae46e4c7SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 927be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 92834f2f8cfSMatthew Ahrens drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj; 929ae46e4c7SMatthew Ahrens } 9303cb34c60Sahrens 9313cb34c60Sahrens return (0); 9323b2aab18SMatthew Ahrens 9333b2aab18SMatthew Ahrens } 9343b2aab18SMatthew Ahrens 9353b2aab18SMatthew Ahrens static int 9363b2aab18SMatthew Ahrens dmu_recv_begin_check(void *arg, dmu_tx_t *tx) 9373b2aab18SMatthew Ahrens { 9383b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 9393b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 9403b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 9413b2aab18SMatthew Ahrens uint64_t fromguid = drrb->drr_fromguid; 9423b2aab18SMatthew Ahrens int flags = drrb->drr_flags; 9433b2aab18SMatthew Ahrens int error; 9445d7b4d43SMatthew Ahrens uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo); 9453b2aab18SMatthew Ahrens dsl_dataset_t *ds; 9463b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 9473b2aab18SMatthew Ahrens 9483b2aab18SMatthew Ahrens /* already checked */ 9493b2aab18SMatthew Ahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 9503b2aab18SMatthew Ahrens 9513b2aab18SMatthew Ahrens if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == 9523b2aab18SMatthew Ahrens DMU_COMPOUNDSTREAM || 9533b2aab18SMatthew Ahrens drrb->drr_type >= DMU_OST_NUMTYPES || 9543b2aab18SMatthew Ahrens ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) 955be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 9563b2aab18SMatthew Ahrens 9573b2aab18SMatthew Ahrens /* Verify pool version supports SA if SA_SPILL feature set */ 9585d7b4d43SMatthew Ahrens if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) && 9595d7b4d43SMatthew Ahrens spa_version(dp->dp_spa) < SPA_VERSION_SA) 9605d7b4d43SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 9615d7b4d43SMatthew Ahrens 9625d7b4d43SMatthew Ahrens /* 9635d7b4d43SMatthew Ahrens * The receiving code doesn't know how to translate a WRITE_EMBEDDED 9645d7b4d43SMatthew Ahrens * record to a plan WRITE record, so the pool must have the 9655d7b4d43SMatthew Ahrens * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED 9665d7b4d43SMatthew Ahrens * records. Same with WRITE_EMBEDDED records that use LZ4 compression. 9675d7b4d43SMatthew Ahrens */ 9685d7b4d43SMatthew Ahrens if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) && 9695d7b4d43SMatthew Ahrens !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) 9705d7b4d43SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 9715d7b4d43SMatthew Ahrens if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA_LZ4) && 9725d7b4d43SMatthew Ahrens !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) 973be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 9743b2aab18SMatthew Ahrens 9753b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 9763b2aab18SMatthew Ahrens if (error == 0) { 9773b2aab18SMatthew Ahrens /* target fs already exists; recv into temp clone */ 9783b2aab18SMatthew Ahrens 9793b2aab18SMatthew Ahrens /* Can't recv a clone into an existing fs */ 9803b2aab18SMatthew Ahrens if (flags & DRR_FLAG_CLONE) { 9813b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 982be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 9833b2aab18SMatthew Ahrens } 9843b2aab18SMatthew Ahrens 9853b2aab18SMatthew Ahrens error = recv_begin_check_existing_impl(drba, ds, fromguid); 9863b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9873b2aab18SMatthew Ahrens } else if (error == ENOENT) { 9883b2aab18SMatthew Ahrens /* target fs does not exist; must be a full backup or clone */ 9893b2aab18SMatthew Ahrens char buf[MAXNAMELEN]; 9903b2aab18SMatthew Ahrens 9913b2aab18SMatthew Ahrens /* 9923b2aab18SMatthew Ahrens * If it's a non-clone incremental, we are missing the 9933b2aab18SMatthew Ahrens * target fs, so fail the recv. 9943b2aab18SMatthew Ahrens */ 9953b2aab18SMatthew Ahrens if (fromguid != 0 && !(flags & DRR_FLAG_CLONE)) 996be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 9973b2aab18SMatthew Ahrens 9983b2aab18SMatthew Ahrens /* Open the parent of tofs */ 9993b2aab18SMatthew Ahrens ASSERT3U(strlen(tofs), <, MAXNAMELEN); 10003b2aab18SMatthew Ahrens (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1); 10013b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, buf, FTAG, &ds); 10023b2aab18SMatthew Ahrens if (error != 0) 10033b2aab18SMatthew Ahrens return (error); 10043b2aab18SMatthew Ahrens 1005a2afb611SJerry Jelinek /* 1006a2afb611SJerry Jelinek * Check filesystem and snapshot limits before receiving. We'll 1007a2afb611SJerry Jelinek * recheck snapshot limits again at the end (we create the 1008a2afb611SJerry Jelinek * filesystems and increment those counts during begin_sync). 1009a2afb611SJerry Jelinek */ 1010a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, 1011a2afb611SJerry Jelinek ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred); 1012a2afb611SJerry Jelinek if (error != 0) { 1013a2afb611SJerry Jelinek dsl_dataset_rele(ds, FTAG); 1014a2afb611SJerry Jelinek return (error); 1015a2afb611SJerry Jelinek } 1016a2afb611SJerry Jelinek 1017a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, 1018a2afb611SJerry Jelinek ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred); 1019a2afb611SJerry Jelinek if (error != 0) { 1020a2afb611SJerry Jelinek dsl_dataset_rele(ds, FTAG); 1021a2afb611SJerry Jelinek return (error); 1022a2afb611SJerry Jelinek } 1023a2afb611SJerry Jelinek 10243b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 10253b2aab18SMatthew Ahrens dsl_dataset_t *origin; 10263b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drba->drba_origin, 10273b2aab18SMatthew Ahrens FTAG, &origin); 10283b2aab18SMatthew Ahrens if (error != 0) { 10293b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10303b2aab18SMatthew Ahrens return (error); 10313b2aab18SMatthew Ahrens } 10323b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(origin)) { 10333b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10343b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 1035be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 10363b2aab18SMatthew Ahrens } 10373b2aab18SMatthew Ahrens if (origin->ds_phys->ds_guid != fromguid) { 10383b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10393b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 1040be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 10413b2aab18SMatthew Ahrens } 10423b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10433b2aab18SMatthew Ahrens } 10443b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10453b2aab18SMatthew Ahrens error = 0; 10463b2aab18SMatthew Ahrens } 10473b2aab18SMatthew Ahrens return (error); 1048f18faf3fSek } 1049f18faf3fSek 1050f18faf3fSek static void 10513b2aab18SMatthew Ahrens dmu_recv_begin_sync(void *arg, dmu_tx_t *tx) 1052f18faf3fSek { 10533b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 10543b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 10553b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 10563b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 10573b2aab18SMatthew Ahrens dsl_dataset_t *ds, *newds; 1058f18faf3fSek uint64_t dsobj; 10593b2aab18SMatthew Ahrens int error; 10603b2aab18SMatthew Ahrens uint64_t crflags; 10613b2aab18SMatthew Ahrens 10623b2aab18SMatthew Ahrens crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ? 10633b2aab18SMatthew Ahrens DS_FLAG_CI_DATASET : 0; 1064f18faf3fSek 10653b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 10663b2aab18SMatthew Ahrens if (error == 0) { 10673b2aab18SMatthew Ahrens /* create temporary clone */ 106834f2f8cfSMatthew Ahrens dsl_dataset_t *snap = NULL; 106934f2f8cfSMatthew Ahrens if (drba->drba_snapobj != 0) { 107034f2f8cfSMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 107134f2f8cfSMatthew Ahrens drba->drba_snapobj, FTAG, &snap)); 107234f2f8cfSMatthew Ahrens } 10733b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name, 107434f2f8cfSMatthew Ahrens snap, crflags, drba->drba_cred, tx); 107534f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 10763b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10773b2aab18SMatthew Ahrens } else { 10783b2aab18SMatthew Ahrens dsl_dir_t *dd; 10793b2aab18SMatthew Ahrens const char *tail; 10803b2aab18SMatthew Ahrens dsl_dataset_t *origin = NULL; 10813b2aab18SMatthew Ahrens 10823b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail)); 10833b2aab18SMatthew Ahrens 10843b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 10853b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drba->drba_origin, 10863b2aab18SMatthew Ahrens FTAG, &origin)); 10873b2aab18SMatthew Ahrens } 10883b2aab18SMatthew Ahrens 10893b2aab18SMatthew Ahrens /* Create new dataset. */ 10903b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(dd, 10913b2aab18SMatthew Ahrens strrchr(tofs, '/') + 1, 10923b2aab18SMatthew Ahrens origin, crflags, drba->drba_cred, tx); 10933b2aab18SMatthew Ahrens if (origin != NULL) 10943b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10953b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 10963b2aab18SMatthew Ahrens drba->drba_cookie->drc_newfs = B_TRUE; 10973b2aab18SMatthew Ahrens } 10983b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds)); 10993b2aab18SMatthew Ahrens 11003b2aab18SMatthew Ahrens dmu_buf_will_dirty(newds->ds_dbuf, tx); 11013b2aab18SMatthew Ahrens newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 11023cb34c60Sahrens 1103ae46e4c7SMatthew Ahrens /* 1104ae46e4c7SMatthew Ahrens * If we actually created a non-clone, we need to create the 1105ae46e4c7SMatthew Ahrens * objset in our new dataset. 1106ae46e4c7SMatthew Ahrens */ 11073b2aab18SMatthew Ahrens if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) { 1108ae46e4c7SMatthew Ahrens (void) dmu_objset_create_impl(dp->dp_spa, 11093b2aab18SMatthew Ahrens newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx); 1110ae46e4c7SMatthew Ahrens } 1111ae46e4c7SMatthew Ahrens 11123b2aab18SMatthew Ahrens drba->drba_cookie->drc_ds = newds; 1113dc7cd546SMark Shellenbaum 11143b2aab18SMatthew Ahrens spa_history_log_internal_ds(newds, "receive", tx, ""); 1115dc7cd546SMark Shellenbaum } 1116dc7cd546SMark Shellenbaum 11173cb34c60Sahrens /* 11183cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 11193cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 11203cb34c60Sahrens */ 11213cb34c60Sahrens int 11223b2aab18SMatthew Ahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 11233b2aab18SMatthew Ahrens boolean_t force, char *origin, dmu_recv_cookie_t *drc) 1124efb80947Sahrens { 11253b2aab18SMatthew Ahrens dmu_recv_begin_arg_t drba = { 0 }; 11263b2aab18SMatthew Ahrens dmu_replay_record_t *drr; 1127ab04eb8eStimh 11283cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 11293cb34c60Sahrens drc->drc_drrb = drrb; 11303cb34c60Sahrens drc->drc_tosnap = tosnap; 11313b2aab18SMatthew Ahrens drc->drc_tofs = tofs; 11323cb34c60Sahrens drc->drc_force = force; 1133a2afb611SJerry Jelinek drc->drc_cred = CRED(); 1134efb80947Sahrens 11353b2aab18SMatthew Ahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 11363b2aab18SMatthew Ahrens drc->drc_byteswap = B_TRUE; 11373b2aab18SMatthew Ahrens else if (drrb->drr_magic != DMU_BACKUP_MAGIC) 1138be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1139efb80947Sahrens 11403b2aab18SMatthew Ahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 11413b2aab18SMatthew Ahrens drr->drr_type = DRR_BEGIN; 11423b2aab18SMatthew Ahrens drr->drr_u.drr_begin = *drc->drc_drrb; 11433b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 11443b2aab18SMatthew Ahrens fletcher_4_incremental_byteswap(drr, 11453b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 11463b2aab18SMatthew Ahrens } else { 11473b2aab18SMatthew Ahrens fletcher_4_incremental_native(drr, 11483b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 11493b2aab18SMatthew Ahrens } 11503b2aab18SMatthew Ahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 1151dc7cd546SMark Shellenbaum 11523b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 11533b2aab18SMatthew Ahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 11543b2aab18SMatthew Ahrens drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 11553b2aab18SMatthew Ahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 11563b2aab18SMatthew Ahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 11573b2aab18SMatthew Ahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 11583b2aab18SMatthew Ahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 11593cb34c60Sahrens } 11603cb34c60Sahrens 11613b2aab18SMatthew Ahrens drba.drba_origin = origin; 11623b2aab18SMatthew Ahrens drba.drba_cookie = drc; 11633b2aab18SMatthew Ahrens drba.drba_cred = CRED(); 11643b2aab18SMatthew Ahrens 11653b2aab18SMatthew Ahrens return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync, 11667d46dc6cSMatthew Ahrens &drba, 5, ZFS_SPACE_CHECK_NORMAL)); 1167efb80947Sahrens } 1168efb80947Sahrens 11693cb34c60Sahrens struct restorearg { 11703cb34c60Sahrens int err; 11713b2aab18SMatthew Ahrens boolean_t byteswap; 11723cb34c60Sahrens vnode_t *vp; 11733cb34c60Sahrens char *buf; 11743cb34c60Sahrens uint64_t voff; 11753cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 11763cb34c60Sahrens zio_cksum_t cksum; 1177c99e4bdcSChris Kirby avl_tree_t *guid_to_ds_map; 11783cb34c60Sahrens }; 11793cb34c60Sahrens 11809e69d7d0SLori Alt typedef struct guid_map_entry { 11819e69d7d0SLori Alt uint64_t guid; 11829e69d7d0SLori Alt dsl_dataset_t *gme_ds; 11839e69d7d0SLori Alt avl_node_t avlnode; 11849e69d7d0SLori Alt } guid_map_entry_t; 11859e69d7d0SLori Alt 11869e69d7d0SLori Alt static int 11879e69d7d0SLori Alt guid_compare(const void *arg1, const void *arg2) 11889e69d7d0SLori Alt { 11899e69d7d0SLori Alt const guid_map_entry_t *gmep1 = arg1; 11909e69d7d0SLori Alt const guid_map_entry_t *gmep2 = arg2; 11919e69d7d0SLori Alt 11929e69d7d0SLori Alt if (gmep1->guid < gmep2->guid) 11939e69d7d0SLori Alt return (-1); 11949e69d7d0SLori Alt else if (gmep1->guid > gmep2->guid) 11959e69d7d0SLori Alt return (1); 11969e69d7d0SLori Alt return (0); 11979e69d7d0SLori Alt } 11989e69d7d0SLori Alt 1199c99e4bdcSChris Kirby static void 1200c99e4bdcSChris Kirby free_guid_map_onexit(void *arg) 1201c99e4bdcSChris Kirby { 1202c99e4bdcSChris Kirby avl_tree_t *ca = arg; 1203c99e4bdcSChris Kirby void *cookie = NULL; 1204c99e4bdcSChris Kirby guid_map_entry_t *gmep; 1205c99e4bdcSChris Kirby 1206c99e4bdcSChris Kirby while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { 12073b2aab18SMatthew Ahrens dsl_dataset_long_rele(gmep->gme_ds, gmep); 1208de8d9cffSMatthew Ahrens dsl_dataset_rele(gmep->gme_ds, gmep); 1209c99e4bdcSChris Kirby kmem_free(gmep, sizeof (guid_map_entry_t)); 1210c99e4bdcSChris Kirby } 1211c99e4bdcSChris Kirby avl_destroy(ca); 1212c99e4bdcSChris Kirby kmem_free(ca, sizeof (avl_tree_t)); 1213c99e4bdcSChris Kirby } 1214c99e4bdcSChris Kirby 1215efb80947Sahrens static void * 12168a904709SMatthew Ahrens restore_read(struct restorearg *ra, int len, char *buf) 1217efb80947Sahrens { 12183cb34c60Sahrens int done = 0; 1219efb80947Sahrens 12208a904709SMatthew Ahrens if (buf == NULL) 12218a904709SMatthew Ahrens buf = ra->buf; 12228a904709SMatthew Ahrens 1223efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 1224fb09f5aaSMadhav Suresh ASSERT0(len % 8); 1225efb80947Sahrens 12263cb34c60Sahrens while (done < len) { 1227efb80947Sahrens ssize_t resid; 1228efb80947Sahrens 1229efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 12308a904709SMatthew Ahrens buf + done, len - done, 1231efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 1232efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 1233efb80947Sahrens 12343cb34c60Sahrens if (resid == len - done) 1235be6fd75aSMatthew Ahrens ra->err = SET_ERROR(EINVAL); 12363cb34c60Sahrens ra->voff += len - done - resid; 12373cb34c60Sahrens done = len - resid; 12383b2aab18SMatthew Ahrens if (ra->err != 0) 1239efb80947Sahrens return (NULL); 1240efb80947Sahrens } 1241efb80947Sahrens 12423cb34c60Sahrens ASSERT3U(done, ==, len); 1243efb80947Sahrens if (ra->byteswap) 12448a904709SMatthew Ahrens fletcher_4_incremental_byteswap(buf, len, &ra->cksum); 1245efb80947Sahrens else 12468a904709SMatthew Ahrens fletcher_4_incremental_native(buf, len, &ra->cksum); 12478a904709SMatthew Ahrens return (buf); 1248efb80947Sahrens } 1249efb80947Sahrens 1250efb80947Sahrens static void 1251efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 1252efb80947Sahrens { 1253efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 1254efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 1255efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 12563cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 1257efb80947Sahrens switch (drr->drr_type) { 1258efb80947Sahrens case DRR_BEGIN: 1259efb80947Sahrens DO64(drr_begin.drr_magic); 12609e69d7d0SLori Alt DO64(drr_begin.drr_versioninfo); 1261efb80947Sahrens DO64(drr_begin.drr_creation_time); 1262efb80947Sahrens DO32(drr_begin.drr_type); 12633cb34c60Sahrens DO32(drr_begin.drr_flags); 1264efb80947Sahrens DO64(drr_begin.drr_toguid); 1265efb80947Sahrens DO64(drr_begin.drr_fromguid); 1266efb80947Sahrens break; 1267efb80947Sahrens case DRR_OBJECT: 1268efb80947Sahrens DO64(drr_object.drr_object); 1269efb80947Sahrens DO32(drr_object.drr_type); 1270efb80947Sahrens DO32(drr_object.drr_bonustype); 1271efb80947Sahrens DO32(drr_object.drr_blksz); 1272efb80947Sahrens DO32(drr_object.drr_bonuslen); 12739e69d7d0SLori Alt DO64(drr_object.drr_toguid); 1274efb80947Sahrens break; 1275efb80947Sahrens case DRR_FREEOBJECTS: 1276efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 1277efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 12789e69d7d0SLori Alt DO64(drr_freeobjects.drr_toguid); 1279efb80947Sahrens break; 1280efb80947Sahrens case DRR_WRITE: 1281efb80947Sahrens DO64(drr_write.drr_object); 1282efb80947Sahrens DO32(drr_write.drr_type); 1283efb80947Sahrens DO64(drr_write.drr_offset); 1284efb80947Sahrens DO64(drr_write.drr_length); 12859e69d7d0SLori Alt DO64(drr_write.drr_toguid); 12868e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[0]); 12878e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[1]); 12888e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[2]); 12898e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[3]); 12908e714474SLori Alt DO64(drr_write.drr_key.ddk_prop); 12919e69d7d0SLori Alt break; 12929e69d7d0SLori Alt case DRR_WRITE_BYREF: 12939e69d7d0SLori Alt DO64(drr_write_byref.drr_object); 12949e69d7d0SLori Alt DO64(drr_write_byref.drr_offset); 12959e69d7d0SLori Alt DO64(drr_write_byref.drr_length); 12969e69d7d0SLori Alt DO64(drr_write_byref.drr_toguid); 12979e69d7d0SLori Alt DO64(drr_write_byref.drr_refguid); 12989e69d7d0SLori Alt DO64(drr_write_byref.drr_refobject); 12999e69d7d0SLori Alt DO64(drr_write_byref.drr_refoffset); 13008e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[0]); 13018e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[1]); 13028e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[2]); 13038e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[3]); 13048e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_prop); 1305efb80947Sahrens break; 13065d7b4d43SMatthew Ahrens case DRR_WRITE_EMBEDDED: 13075d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_object); 13085d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_offset); 13095d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_length); 13105d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_toguid); 13115d7b4d43SMatthew Ahrens DO32(drr_write_embedded.drr_lsize); 13125d7b4d43SMatthew Ahrens DO32(drr_write_embedded.drr_psize); 13135d7b4d43SMatthew Ahrens break; 1314efb80947Sahrens case DRR_FREE: 1315efb80947Sahrens DO64(drr_free.drr_object); 1316efb80947Sahrens DO64(drr_free.drr_offset); 1317efb80947Sahrens DO64(drr_free.drr_length); 13189e69d7d0SLori Alt DO64(drr_free.drr_toguid); 1319efb80947Sahrens break; 13200a586ceaSMark Shellenbaum case DRR_SPILL: 13210a586ceaSMark Shellenbaum DO64(drr_spill.drr_object); 13220a586ceaSMark Shellenbaum DO64(drr_spill.drr_length); 13230a586ceaSMark Shellenbaum DO64(drr_spill.drr_toguid); 13240a586ceaSMark Shellenbaum break; 1325efb80947Sahrens case DRR_END: 1326efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 1327efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 1328efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 1329efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 13309e69d7d0SLori Alt DO64(drr_end.drr_toguid); 1331efb80947Sahrens break; 1332efb80947Sahrens } 1333efb80947Sahrens #undef DO64 1334efb80947Sahrens #undef DO32 1335efb80947Sahrens } 1336efb80947Sahrens 1337*e77d42eaSMatthew Ahrens static inline uint8_t 1338*e77d42eaSMatthew Ahrens deduce_nblkptr(dmu_object_type_t bonus_type, uint64_t bonus_size) 1339*e77d42eaSMatthew Ahrens { 1340*e77d42eaSMatthew Ahrens if (bonus_type == DMU_OT_SA) { 1341*e77d42eaSMatthew Ahrens return (1); 1342*e77d42eaSMatthew Ahrens } else { 1343*e77d42eaSMatthew Ahrens return (1 + 1344*e77d42eaSMatthew Ahrens ((DN_MAX_BONUSLEN - bonus_size) >> SPA_BLKPTRSHIFT)); 1345*e77d42eaSMatthew Ahrens } 1346*e77d42eaSMatthew Ahrens } 1347*e77d42eaSMatthew Ahrens 1348efb80947Sahrens static int 1349efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 1350efb80947Sahrens { 1351*e77d42eaSMatthew Ahrens dmu_object_info_t doi; 1352efb80947Sahrens dmu_tx_t *tx; 1353adee0b6fSTim Haley void *data = NULL; 1354*e77d42eaSMatthew Ahrens uint64_t object; 1355*e77d42eaSMatthew Ahrens int err; 1356efb80947Sahrens 1357efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 1358ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_type) || 1359ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_bonustype) || 13609e69d7d0SLori Alt drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || 1361efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 1362efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 1363efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 1364efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 1365efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 1366be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1367efb80947Sahrens } 1368efb80947Sahrens 1369*e77d42eaSMatthew Ahrens err = dmu_object_info(os, drro->drr_object, &doi); 13702bf405a2SMark Maybee 13712bf405a2SMark Maybee if (err != 0 && err != ENOENT) 1372be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1373*e77d42eaSMatthew Ahrens object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT; 13742bf405a2SMark Maybee 1375adee0b6fSTim Haley if (drro->drr_bonuslen) { 13768a904709SMatthew Ahrens data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8), NULL); 13773b2aab18SMatthew Ahrens if (ra->err != 0) 1378adee0b6fSTim Haley return (ra->err); 1379adee0b6fSTim Haley } 1380adee0b6fSTim Haley 1381*e77d42eaSMatthew Ahrens /* 1382*e77d42eaSMatthew Ahrens * If we are losing blkptrs or changing the block size this must 1383*e77d42eaSMatthew Ahrens * be a new file instance. We must clear out the previous file 1384*e77d42eaSMatthew Ahrens * contents before we can change this type of metadata in the dnode. 1385*e77d42eaSMatthew Ahrens */ 1386*e77d42eaSMatthew Ahrens if (err == 0) { 1387*e77d42eaSMatthew Ahrens int nblkptr; 1388*e77d42eaSMatthew Ahrens 1389*e77d42eaSMatthew Ahrens nblkptr = deduce_nblkptr(drro->drr_bonustype, 1390*e77d42eaSMatthew Ahrens drro->drr_bonuslen); 1391*e77d42eaSMatthew Ahrens 1392*e77d42eaSMatthew Ahrens if (drro->drr_blksz != doi.doi_data_block_size || 1393*e77d42eaSMatthew Ahrens nblkptr < doi.doi_nblkptr) { 1394*e77d42eaSMatthew Ahrens err = dmu_free_long_range(os, drro->drr_object, 1395*e77d42eaSMatthew Ahrens 0, DMU_OBJECT_END); 1396*e77d42eaSMatthew Ahrens if (err != 0) 1397*e77d42eaSMatthew Ahrens return (SET_ERROR(EINVAL)); 1398efb80947Sahrens } 1399*e77d42eaSMatthew Ahrens } 1400*e77d42eaSMatthew Ahrens 1401*e77d42eaSMatthew Ahrens tx = dmu_tx_create(os); 1402*e77d42eaSMatthew Ahrens dmu_tx_hold_bonus(tx, object); 1403*e77d42eaSMatthew Ahrens err = dmu_tx_assign(tx, TXG_WAIT); 1404*e77d42eaSMatthew Ahrens if (err != 0) { 1405*e77d42eaSMatthew Ahrens dmu_tx_abort(tx); 1406*e77d42eaSMatthew Ahrens return (err); 1407*e77d42eaSMatthew Ahrens } 1408*e77d42eaSMatthew Ahrens 1409*e77d42eaSMatthew Ahrens if (object == DMU_NEW_OBJECT) { 1410*e77d42eaSMatthew Ahrens /* currently free, want to be allocated */ 1411efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 1412efb80947Sahrens drro->drr_type, drro->drr_blksz, 1413efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 1414*e77d42eaSMatthew Ahrens } else if (drro->drr_type != doi.doi_type || 1415*e77d42eaSMatthew Ahrens drro->drr_blksz != doi.doi_data_block_size || 1416*e77d42eaSMatthew Ahrens drro->drr_bonustype != doi.doi_bonus_type || 1417*e77d42eaSMatthew Ahrens drro->drr_bonuslen != doi.doi_bonus_size) { 1418*e77d42eaSMatthew Ahrens /* currently allocated, but with different properties */ 1419efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 1420efb80947Sahrens drro->drr_type, drro->drr_blksz, 1421*e77d42eaSMatthew Ahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 1422efb80947Sahrens } 14233b2aab18SMatthew Ahrens if (err != 0) { 1424*e77d42eaSMatthew Ahrens dmu_tx_commit(tx); 1425be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 14260a586ceaSMark Shellenbaum } 14272bf405a2SMark Maybee 14289e69d7d0SLori Alt dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 14299e69d7d0SLori Alt tx); 1430efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1431efb80947Sahrens 1432adee0b6fSTim Haley if (data != NULL) { 1433efb80947Sahrens dmu_buf_t *db; 1434adee0b6fSTim Haley 1435efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 1436efb80947Sahrens dmu_buf_will_dirty(db, tx); 1437efb80947Sahrens 14381934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 14391934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 1440efb80947Sahrens if (ra->byteswap) { 1441ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1442ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drro->drr_bonustype); 1443ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(db->db_data, 1444efb80947Sahrens drro->drr_bonuslen); 1445efb80947Sahrens } 1446efb80947Sahrens dmu_buf_rele(db, FTAG); 1447efb80947Sahrens } 1448efb80947Sahrens dmu_tx_commit(tx); 1449efb80947Sahrens return (0); 1450efb80947Sahrens } 1451efb80947Sahrens 1452efb80947Sahrens /* ARGSUSED */ 1453efb80947Sahrens static int 1454efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 1455efb80947Sahrens struct drr_freeobjects *drrfo) 1456efb80947Sahrens { 1457efb80947Sahrens uint64_t obj; 1458efb80947Sahrens 1459efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 1460be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1461efb80947Sahrens 1462efb80947Sahrens for (obj = drrfo->drr_firstobj; 1463432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1464432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 1465efb80947Sahrens int err; 1466efb80947Sahrens 1467efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 1468efb80947Sahrens continue; 1469efb80947Sahrens 1470713d6c20SMatthew Ahrens err = dmu_free_long_object(os, obj); 14713b2aab18SMatthew Ahrens if (err != 0) 1472efb80947Sahrens return (err); 1473efb80947Sahrens } 1474efb80947Sahrens return (0); 1475efb80947Sahrens } 1476efb80947Sahrens 1477efb80947Sahrens static int 1478efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 1479efb80947Sahrens struct drr_write *drrw) 1480efb80947Sahrens { 1481efb80947Sahrens dmu_tx_t *tx; 1482efb80947Sahrens void *data; 1483efb80947Sahrens int err; 1484efb80947Sahrens 1485efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 1486ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drrw->drr_type)) 1487be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1488efb80947Sahrens 1489efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1490be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1491efb80947Sahrens 14928a904709SMatthew Ahrens dmu_buf_t *bonus; 14938a904709SMatthew Ahrens if (dmu_bonus_hold(os, drrw->drr_object, FTAG, &bonus) != 0) 14948a904709SMatthew Ahrens return (SET_ERROR(EINVAL)); 14958a904709SMatthew Ahrens 14968a904709SMatthew Ahrens arc_buf_t *abuf = dmu_request_arcbuf(bonus, drrw->drr_length); 14978a904709SMatthew Ahrens 14988a904709SMatthew Ahrens data = restore_read(ra, drrw->drr_length, abuf->b_data); 14998a904709SMatthew Ahrens if (data == NULL) { 15008a904709SMatthew Ahrens dmu_return_arcbuf(abuf); 15018a904709SMatthew Ahrens dmu_buf_rele(bonus, FTAG); 15028a904709SMatthew Ahrens return (ra->err); 15038a904709SMatthew Ahrens } 15048a904709SMatthew Ahrens 1505efb80947Sahrens tx = dmu_tx_create(os); 1506efb80947Sahrens 1507efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 1508efb80947Sahrens drrw->drr_offset, drrw->drr_length); 1509efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 15103b2aab18SMatthew Ahrens if (err != 0) { 15118a904709SMatthew Ahrens dmu_return_arcbuf(abuf); 15128a904709SMatthew Ahrens dmu_buf_rele(bonus, FTAG); 1513efb80947Sahrens dmu_tx_abort(tx); 1514efb80947Sahrens return (err); 1515efb80947Sahrens } 1516ad135b5dSChristopher Siden if (ra->byteswap) { 1517ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1518ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drrw->drr_type); 1519ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1520ad135b5dSChristopher Siden } 15218a904709SMatthew Ahrens dmu_assign_arcbuf(bonus, drrw->drr_offset, abuf, tx); 1522efb80947Sahrens dmu_tx_commit(tx); 15238a904709SMatthew Ahrens dmu_buf_rele(bonus, FTAG); 1524efb80947Sahrens return (0); 1525efb80947Sahrens } 1526efb80947Sahrens 15279e69d7d0SLori Alt /* 15289e69d7d0SLori Alt * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed 15299e69d7d0SLori Alt * streams to refer to a copy of the data that is already on the 15309e69d7d0SLori Alt * system because it came in earlier in the stream. This function 15319e69d7d0SLori Alt * finds the earlier copy of the data, and uses that copy instead of 15329e69d7d0SLori Alt * data from the stream to fulfill this write. 15339e69d7d0SLori Alt */ 15349e69d7d0SLori Alt static int 15359e69d7d0SLori Alt restore_write_byref(struct restorearg *ra, objset_t *os, 15369e69d7d0SLori Alt struct drr_write_byref *drrwbr) 15379e69d7d0SLori Alt { 15389e69d7d0SLori Alt dmu_tx_t *tx; 15399e69d7d0SLori Alt int err; 15409e69d7d0SLori Alt guid_map_entry_t gmesrch; 15419e69d7d0SLori Alt guid_map_entry_t *gmep; 15425d7b4d43SMatthew Ahrens avl_index_t where; 15439e69d7d0SLori Alt objset_t *ref_os = NULL; 15449e69d7d0SLori Alt dmu_buf_t *dbp; 15459e69d7d0SLori Alt 15469e69d7d0SLori Alt if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset) 1547be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 15489e69d7d0SLori Alt 15499e69d7d0SLori Alt /* 15509e69d7d0SLori Alt * If the GUID of the referenced dataset is different from the 15519e69d7d0SLori Alt * GUID of the target dataset, find the referenced dataset. 15529e69d7d0SLori Alt */ 15539e69d7d0SLori Alt if (drrwbr->drr_toguid != drrwbr->drr_refguid) { 15549e69d7d0SLori Alt gmesrch.guid = drrwbr->drr_refguid; 1555c99e4bdcSChris Kirby if ((gmep = avl_find(ra->guid_to_ds_map, &gmesrch, 15569e69d7d0SLori Alt &where)) == NULL) { 1557be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 15589e69d7d0SLori Alt } 15599e69d7d0SLori Alt if (dmu_objset_from_ds(gmep->gme_ds, &ref_os)) 1560be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 15619e69d7d0SLori Alt } else { 15629e69d7d0SLori Alt ref_os = os; 15639e69d7d0SLori Alt } 15649e69d7d0SLori Alt 15655d7b4d43SMatthew Ahrens err = dmu_buf_hold(ref_os, drrwbr->drr_refobject, 15665d7b4d43SMatthew Ahrens drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH); 15675d7b4d43SMatthew Ahrens if (err != 0) 15689e69d7d0SLori Alt return (err); 15699e69d7d0SLori Alt 15709e69d7d0SLori Alt tx = dmu_tx_create(os); 15719e69d7d0SLori Alt 15729e69d7d0SLori Alt dmu_tx_hold_write(tx, drrwbr->drr_object, 15739e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length); 15749e69d7d0SLori Alt err = dmu_tx_assign(tx, TXG_WAIT); 15753b2aab18SMatthew Ahrens if (err != 0) { 15769e69d7d0SLori Alt dmu_tx_abort(tx); 15779e69d7d0SLori Alt return (err); 15789e69d7d0SLori Alt } 15799e69d7d0SLori Alt dmu_write(os, drrwbr->drr_object, 15809e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 15819e69d7d0SLori Alt dmu_buf_rele(dbp, FTAG); 15829e69d7d0SLori Alt dmu_tx_commit(tx); 15839e69d7d0SLori Alt return (0); 15849e69d7d0SLori Alt } 15859e69d7d0SLori Alt 15865d7b4d43SMatthew Ahrens static int 15875d7b4d43SMatthew Ahrens restore_write_embedded(struct restorearg *ra, objset_t *os, 15885d7b4d43SMatthew Ahrens struct drr_write_embedded *drrwnp) 15895d7b4d43SMatthew Ahrens { 15905d7b4d43SMatthew Ahrens dmu_tx_t *tx; 15915d7b4d43SMatthew Ahrens int err; 15925d7b4d43SMatthew Ahrens void *data; 15935d7b4d43SMatthew Ahrens 15945d7b4d43SMatthew Ahrens if (drrwnp->drr_offset + drrwnp->drr_length < drrwnp->drr_offset) 15955d7b4d43SMatthew Ahrens return (EINVAL); 15965d7b4d43SMatthew Ahrens 15975d7b4d43SMatthew Ahrens if (drrwnp->drr_psize > BPE_PAYLOAD_SIZE) 15985d7b4d43SMatthew Ahrens return (EINVAL); 15995d7b4d43SMatthew Ahrens 16005d7b4d43SMatthew Ahrens if (drrwnp->drr_etype >= NUM_BP_EMBEDDED_TYPES) 16015d7b4d43SMatthew Ahrens return (EINVAL); 16025d7b4d43SMatthew Ahrens if (drrwnp->drr_compression >= ZIO_COMPRESS_FUNCTIONS) 16035d7b4d43SMatthew Ahrens return (EINVAL); 16045d7b4d43SMatthew Ahrens 16058a904709SMatthew Ahrens data = restore_read(ra, P2ROUNDUP(drrwnp->drr_psize, 8), NULL); 16065d7b4d43SMatthew Ahrens if (data == NULL) 16075d7b4d43SMatthew Ahrens return (ra->err); 16085d7b4d43SMatthew Ahrens 16095d7b4d43SMatthew Ahrens tx = dmu_tx_create(os); 16105d7b4d43SMatthew Ahrens 16115d7b4d43SMatthew Ahrens dmu_tx_hold_write(tx, drrwnp->drr_object, 16125d7b4d43SMatthew Ahrens drrwnp->drr_offset, drrwnp->drr_length); 16135d7b4d43SMatthew Ahrens err = dmu_tx_assign(tx, TXG_WAIT); 16145d7b4d43SMatthew Ahrens if (err != 0) { 16155d7b4d43SMatthew Ahrens dmu_tx_abort(tx); 16165d7b4d43SMatthew Ahrens return (err); 16175d7b4d43SMatthew Ahrens } 16185d7b4d43SMatthew Ahrens 16195d7b4d43SMatthew Ahrens dmu_write_embedded(os, drrwnp->drr_object, 16205d7b4d43SMatthew Ahrens drrwnp->drr_offset, data, drrwnp->drr_etype, 16215d7b4d43SMatthew Ahrens drrwnp->drr_compression, drrwnp->drr_lsize, drrwnp->drr_psize, 16225d7b4d43SMatthew Ahrens ra->byteswap ^ ZFS_HOST_BYTEORDER, tx); 16235d7b4d43SMatthew Ahrens 16245d7b4d43SMatthew Ahrens dmu_tx_commit(tx); 16255d7b4d43SMatthew Ahrens return (0); 16265d7b4d43SMatthew Ahrens } 16275d7b4d43SMatthew Ahrens 16280a586ceaSMark Shellenbaum static int 16290a586ceaSMark Shellenbaum restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs) 16300a586ceaSMark Shellenbaum { 16310a586ceaSMark Shellenbaum dmu_tx_t *tx; 16320a586ceaSMark Shellenbaum void *data; 16330a586ceaSMark Shellenbaum dmu_buf_t *db, *db_spill; 16340a586ceaSMark Shellenbaum int err; 16350a586ceaSMark Shellenbaum 16360a586ceaSMark Shellenbaum if (drrs->drr_length < SPA_MINBLOCKSIZE || 16370a586ceaSMark Shellenbaum drrs->drr_length > SPA_MAXBLOCKSIZE) 1638be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 16390a586ceaSMark Shellenbaum 16408a904709SMatthew Ahrens data = restore_read(ra, drrs->drr_length, NULL); 16410a586ceaSMark Shellenbaum if (data == NULL) 16420a586ceaSMark Shellenbaum return (ra->err); 16430a586ceaSMark Shellenbaum 16440a586ceaSMark Shellenbaum if (dmu_object_info(os, drrs->drr_object, NULL) != 0) 1645be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 16460a586ceaSMark Shellenbaum 16470a586ceaSMark Shellenbaum VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db)); 16480a586ceaSMark Shellenbaum if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) { 16490a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 16500a586ceaSMark Shellenbaum return (err); 16510a586ceaSMark Shellenbaum } 16520a586ceaSMark Shellenbaum 16530a586ceaSMark Shellenbaum tx = dmu_tx_create(os); 16540a586ceaSMark Shellenbaum 16550a586ceaSMark Shellenbaum dmu_tx_hold_spill(tx, db->db_object); 16560a586ceaSMark Shellenbaum 16570a586ceaSMark Shellenbaum err = dmu_tx_assign(tx, TXG_WAIT); 16583b2aab18SMatthew Ahrens if (err != 0) { 16590a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 16600a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 16610a586ceaSMark Shellenbaum dmu_tx_abort(tx); 16620a586ceaSMark Shellenbaum return (err); 16630a586ceaSMark Shellenbaum } 16640a586ceaSMark Shellenbaum dmu_buf_will_dirty(db_spill, tx); 16650a586ceaSMark Shellenbaum 16660a586ceaSMark Shellenbaum if (db_spill->db_size < drrs->drr_length) 16670a586ceaSMark Shellenbaum VERIFY(0 == dbuf_spill_set_blksz(db_spill, 16680a586ceaSMark Shellenbaum drrs->drr_length, tx)); 16690a586ceaSMark Shellenbaum bcopy(data, db_spill->db_data, drrs->drr_length); 16700a586ceaSMark Shellenbaum 16710a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 16720a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 16730a586ceaSMark Shellenbaum 16740a586ceaSMark Shellenbaum dmu_tx_commit(tx); 16750a586ceaSMark Shellenbaum return (0); 16760a586ceaSMark Shellenbaum } 16770a586ceaSMark Shellenbaum 1678efb80947Sahrens /* ARGSUSED */ 1679efb80947Sahrens static int 1680efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 1681efb80947Sahrens struct drr_free *drrf) 1682efb80947Sahrens { 1683efb80947Sahrens int err; 1684efb80947Sahrens 1685efb80947Sahrens if (drrf->drr_length != -1ULL && 1686efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 1687be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1688efb80947Sahrens 1689efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1690be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1691efb80947Sahrens 1692cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 1693efb80947Sahrens drrf->drr_offset, drrf->drr_length); 1694efb80947Sahrens return (err); 1695efb80947Sahrens } 1696efb80947Sahrens 16973b2aab18SMatthew Ahrens /* used to destroy the drc_ds on error */ 16983b2aab18SMatthew Ahrens static void 16993b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) 17003b2aab18SMatthew Ahrens { 17013b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 17023b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 17033b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 17043b2aab18SMatthew Ahrens (void) dsl_destroy_head(name); 17053b2aab18SMatthew Ahrens } 17063b2aab18SMatthew Ahrens 17073cb34c60Sahrens /* 17083cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 17093cb34c60Sahrens */ 1710efb80947Sahrens int 1711c99e4bdcSChris Kirby dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp, 1712c99e4bdcSChris Kirby int cleanup_fd, uint64_t *action_handlep) 1713efb80947Sahrens { 17143cb34c60Sahrens struct restorearg ra = { 0 }; 1715efb80947Sahrens dmu_replay_record_t *drr; 17163cb34c60Sahrens objset_t *os; 17173cb34c60Sahrens zio_cksum_t pcksum; 17189e69d7d0SLori Alt int featureflags; 1719efb80947Sahrens 17203b2aab18SMatthew Ahrens ra.byteswap = drc->drc_byteswap; 17213b2aab18SMatthew Ahrens ra.cksum = drc->drc_cksum; 17223cb34c60Sahrens ra.vp = vp; 17233cb34c60Sahrens ra.voff = *voffp; 17243cb34c60Sahrens ra.bufsize = 1<<20; 17253cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1726efb80947Sahrens 17273cb34c60Sahrens /* these were verified in dmu_recv_begin */ 17283b2aab18SMatthew Ahrens ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==, 17299e69d7d0SLori Alt DMU_SUBSTREAM); 17303b2aab18SMatthew Ahrens ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES); 1731efb80947Sahrens 1732efb80947Sahrens /* 1733efb80947Sahrens * Open the objset we are modifying. 1734efb80947Sahrens */ 17353b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os)); 1736efb80947Sahrens 17373b2aab18SMatthew Ahrens ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1738efb80947Sahrens 17399e69d7d0SLori Alt featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 17409e69d7d0SLori Alt 17419e69d7d0SLori Alt /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 17429e69d7d0SLori Alt if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1743a7f53a56SChris Kirby minor_t minor; 1744a7f53a56SChris Kirby 1745c99e4bdcSChris Kirby if (cleanup_fd == -1) { 1746be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EBADF); 1747c99e4bdcSChris Kirby goto out; 1748c99e4bdcSChris Kirby } 1749a7f53a56SChris Kirby ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); 17503b2aab18SMatthew Ahrens if (ra.err != 0) { 1751a7f53a56SChris Kirby cleanup_fd = -1; 1752a7f53a56SChris Kirby goto out; 1753a7f53a56SChris Kirby } 1754a7f53a56SChris Kirby 1755c99e4bdcSChris Kirby if (*action_handlep == 0) { 1756c99e4bdcSChris Kirby ra.guid_to_ds_map = 1757c99e4bdcSChris Kirby kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1758c99e4bdcSChris Kirby avl_create(ra.guid_to_ds_map, guid_compare, 1759c99e4bdcSChris Kirby sizeof (guid_map_entry_t), 1760c99e4bdcSChris Kirby offsetof(guid_map_entry_t, avlnode)); 1761a7f53a56SChris Kirby ra.err = zfs_onexit_add_cb(minor, 1762c99e4bdcSChris Kirby free_guid_map_onexit, ra.guid_to_ds_map, 1763c99e4bdcSChris Kirby action_handlep); 17643b2aab18SMatthew Ahrens if (ra.err != 0) 1765c99e4bdcSChris Kirby goto out; 1766c99e4bdcSChris Kirby } else { 1767a7f53a56SChris Kirby ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1768c99e4bdcSChris Kirby (void **)&ra.guid_to_ds_map); 17693b2aab18SMatthew Ahrens if (ra.err != 0) 1770c99e4bdcSChris Kirby goto out; 1771c99e4bdcSChris Kirby } 1772ec5cf9d5SAlexander Stetsenko 1773ec5cf9d5SAlexander Stetsenko drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 17749e69d7d0SLori Alt } 17759e69d7d0SLori Alt 1776efb80947Sahrens /* 1777efb80947Sahrens * Read records and process them. 1778efb80947Sahrens */ 17793cb34c60Sahrens pcksum = ra.cksum; 1780efb80947Sahrens while (ra.err == 0 && 17818a904709SMatthew Ahrens NULL != (drr = restore_read(&ra, sizeof (*drr), NULL))) { 1782efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 1783be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EINTR); 1784efb80947Sahrens goto out; 1785efb80947Sahrens } 1786efb80947Sahrens 1787efb80947Sahrens if (ra.byteswap) 1788efb80947Sahrens backup_byteswap(drr); 1789efb80947Sahrens 1790efb80947Sahrens switch (drr->drr_type) { 1791efb80947Sahrens case DRR_OBJECT: 1792efb80947Sahrens { 1793efb80947Sahrens /* 1794efb80947Sahrens * We need to make a copy of the record header, 1795efb80947Sahrens * because restore_{object,write} may need to 1796efb80947Sahrens * restore_read(), which will invalidate drr. 1797efb80947Sahrens */ 1798efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 1799efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 1800efb80947Sahrens break; 1801efb80947Sahrens } 1802efb80947Sahrens case DRR_FREEOBJECTS: 1803efb80947Sahrens { 1804efb80947Sahrens struct drr_freeobjects drrfo = 1805efb80947Sahrens drr->drr_u.drr_freeobjects; 1806efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 1807efb80947Sahrens break; 1808efb80947Sahrens } 1809efb80947Sahrens case DRR_WRITE: 1810efb80947Sahrens { 1811efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 1812efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 1813efb80947Sahrens break; 1814efb80947Sahrens } 18159e69d7d0SLori Alt case DRR_WRITE_BYREF: 18169e69d7d0SLori Alt { 18179e69d7d0SLori Alt struct drr_write_byref drrwbr = 18189e69d7d0SLori Alt drr->drr_u.drr_write_byref; 18199e69d7d0SLori Alt ra.err = restore_write_byref(&ra, os, &drrwbr); 18209e69d7d0SLori Alt break; 18219e69d7d0SLori Alt } 18225d7b4d43SMatthew Ahrens case DRR_WRITE_EMBEDDED: 18235d7b4d43SMatthew Ahrens { 18245d7b4d43SMatthew Ahrens struct drr_write_embedded drrwe = 18255d7b4d43SMatthew Ahrens drr->drr_u.drr_write_embedded; 18265d7b4d43SMatthew Ahrens ra.err = restore_write_embedded(&ra, os, &drrwe); 18275d7b4d43SMatthew Ahrens break; 18285d7b4d43SMatthew Ahrens } 1829efb80947Sahrens case DRR_FREE: 1830efb80947Sahrens { 1831efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 1832efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 1833efb80947Sahrens break; 1834efb80947Sahrens } 1835efb80947Sahrens case DRR_END: 1836efb80947Sahrens { 1837efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1838efb80947Sahrens /* 1839efb80947Sahrens * We compare against the *previous* checksum 1840efb80947Sahrens * value, because the stored checksum is of 1841efb80947Sahrens * everything before the DRR_END record. 1842efb80947Sahrens */ 1843137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1844be6fd75aSMatthew Ahrens ra.err = SET_ERROR(ECKSUM); 1845efb80947Sahrens goto out; 1846efb80947Sahrens } 18470a586ceaSMark Shellenbaum case DRR_SPILL: 18480a586ceaSMark Shellenbaum { 18490a586ceaSMark Shellenbaum struct drr_spill drrs = drr->drr_u.drr_spill; 18500a586ceaSMark Shellenbaum ra.err = restore_spill(&ra, os, &drrs); 18510a586ceaSMark Shellenbaum break; 18520a586ceaSMark Shellenbaum } 1853efb80947Sahrens default: 1854be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EINVAL); 1855efb80947Sahrens goto out; 1856efb80947Sahrens } 18573cb34c60Sahrens pcksum = ra.cksum; 1858efb80947Sahrens } 1859137fa067Sahrens ASSERT(ra.err != 0); 1860efb80947Sahrens 1861efb80947Sahrens out: 1862a7f53a56SChris Kirby if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1863a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 1864a7f53a56SChris Kirby 18653cb34c60Sahrens if (ra.err != 0) { 1866efb80947Sahrens /* 1867f4b94bdeSMatthew Ahrens * destroy what we created, so we don't leave it in the 1868f4b94bdeSMatthew Ahrens * inconsistent restoring state. 1869efb80947Sahrens */ 18703b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 1871efb80947Sahrens } 1872efb80947Sahrens 1873efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 18743cb34c60Sahrens *voffp = ra.voff; 1875efb80947Sahrens return (ra.err); 1876efb80947Sahrens } 1877f18faf3fSek 18783cb34c60Sahrens static int 18793b2aab18SMatthew Ahrens dmu_recv_end_check(void *arg, dmu_tx_t *tx) 18803cb34c60Sahrens { 18813b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 18823b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 18833b2aab18SMatthew Ahrens int error; 18843b2aab18SMatthew Ahrens 18853b2aab18SMatthew Ahrens ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag); 18863cb34c60Sahrens 18873b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 18883b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 18893b2aab18SMatthew Ahrens 18903b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head); 18913b2aab18SMatthew Ahrens if (error != 0) 18923b2aab18SMatthew Ahrens return (error); 189334f2f8cfSMatthew Ahrens if (drc->drc_force) { 189434f2f8cfSMatthew Ahrens /* 189534f2f8cfSMatthew Ahrens * We will destroy any snapshots in tofs (i.e. before 189634f2f8cfSMatthew Ahrens * origin_head) that are after the origin (which is 189734f2f8cfSMatthew Ahrens * the snap before drc_ds, because drc_ds can not 189834f2f8cfSMatthew Ahrens * have any snaps of its own). 189934f2f8cfSMatthew Ahrens */ 190034f2f8cfSMatthew Ahrens uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 190134f2f8cfSMatthew Ahrens while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 190234f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 190334f2f8cfSMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 190434f2f8cfSMatthew Ahrens &snap); 190534f2f8cfSMatthew Ahrens if (error != 0) 190634f2f8cfSMatthew Ahrens return (error); 190734f2f8cfSMatthew Ahrens if (snap->ds_dir != origin_head->ds_dir) 190834f2f8cfSMatthew Ahrens error = SET_ERROR(EINVAL); 190934f2f8cfSMatthew Ahrens if (error == 0) { 191034f2f8cfSMatthew Ahrens error = dsl_destroy_snapshot_check_impl( 191134f2f8cfSMatthew Ahrens snap, B_FALSE); 191234f2f8cfSMatthew Ahrens } 191334f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 191434f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 191534f2f8cfSMatthew Ahrens if (error != 0) 191634f2f8cfSMatthew Ahrens return (error); 191734f2f8cfSMatthew Ahrens } 191834f2f8cfSMatthew Ahrens } 19193b2aab18SMatthew Ahrens error = dsl_dataset_clone_swap_check_impl(drc->drc_ds, 192091948b51SKeith M Wesolowski origin_head, drc->drc_force, drc->drc_owner, tx); 19213b2aab18SMatthew Ahrens if (error != 0) { 19223b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 19233b2aab18SMatthew Ahrens return (error); 19243b2aab18SMatthew Ahrens } 19253b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(origin_head, 1926a2afb611SJerry Jelinek drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); 19273b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 19283b2aab18SMatthew Ahrens if (error != 0) 19293b2aab18SMatthew Ahrens return (error); 19303b2aab18SMatthew Ahrens 19313b2aab18SMatthew Ahrens error = dsl_destroy_head_check_impl(drc->drc_ds, 1); 19323b2aab18SMatthew Ahrens } else { 19333b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(drc->drc_ds, 1934a2afb611SJerry Jelinek drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); 19353b2aab18SMatthew Ahrens } 19363b2aab18SMatthew Ahrens return (error); 19373cb34c60Sahrens } 19383cb34c60Sahrens 19393cb34c60Sahrens static void 19403b2aab18SMatthew Ahrens dmu_recv_end_sync(void *arg, dmu_tx_t *tx) 19413cb34c60Sahrens { 19423b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 19433b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 19443b2aab18SMatthew Ahrens 19453b2aab18SMatthew Ahrens spa_history_log_internal_ds(drc->drc_ds, "finish receiving", 19463b2aab18SMatthew Ahrens tx, "snap=%s", drc->drc_tosnap); 19473b2aab18SMatthew Ahrens 19483b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 19493b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 19503b2aab18SMatthew Ahrens 19513b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG, 19523b2aab18SMatthew Ahrens &origin_head)); 195334f2f8cfSMatthew Ahrens 195434f2f8cfSMatthew Ahrens if (drc->drc_force) { 195534f2f8cfSMatthew Ahrens /* 195634f2f8cfSMatthew Ahrens * Destroy any snapshots of drc_tofs (origin_head) 195734f2f8cfSMatthew Ahrens * after the origin (the snap before drc_ds). 195834f2f8cfSMatthew Ahrens */ 195934f2f8cfSMatthew Ahrens uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 196034f2f8cfSMatthew Ahrens while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 196134f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 196234f2f8cfSMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG, 196334f2f8cfSMatthew Ahrens &snap)); 196434f2f8cfSMatthew Ahrens ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir); 196534f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 196634f2f8cfSMatthew Ahrens dsl_destroy_snapshot_sync_impl(snap, 196734f2f8cfSMatthew Ahrens B_FALSE, tx); 196834f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 196934f2f8cfSMatthew Ahrens } 197034f2f8cfSMatthew Ahrens } 197134f2f8cfSMatthew Ahrens VERIFY3P(drc->drc_ds->ds_prev, ==, 197234f2f8cfSMatthew Ahrens origin_head->ds_prev); 197334f2f8cfSMatthew Ahrens 19743b2aab18SMatthew Ahrens dsl_dataset_clone_swap_sync_impl(drc->drc_ds, 19753b2aab18SMatthew Ahrens origin_head, tx); 19763b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(origin_head, 19773b2aab18SMatthew Ahrens drc->drc_tosnap, tx); 19783b2aab18SMatthew Ahrens 19793b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 19803b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx); 19813b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_creation_time = 19823b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 19833b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_guid = 19843b2aab18SMatthew Ahrens drc->drc_drrb->drr_toguid; 19853b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_flags &= 19863b2aab18SMatthew Ahrens ~DS_FLAG_INCONSISTENT; 19873b2aab18SMatthew Ahrens 19883b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_dbuf, tx); 19893b2aab18SMatthew Ahrens origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 19903b2aab18SMatthew Ahrens 19913b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 19923b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(drc->drc_ds, tx); 199391948b51SKeith M Wesolowski 199491948b51SKeith M Wesolowski if (drc->drc_owner != NULL) 199591948b51SKeith M Wesolowski VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner); 19963b2aab18SMatthew Ahrens } else { 19973b2aab18SMatthew Ahrens dsl_dataset_t *ds = drc->drc_ds; 19983cb34c60Sahrens 19993b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx); 20003cb34c60Sahrens 20013b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 20023b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 20033b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_creation_time = 20043b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 20053b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid; 20063b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 20073cb34c60Sahrens 20083b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 20093b2aab18SMatthew Ahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 20103b2aab18SMatthew Ahrens } 20113b2aab18SMatthew Ahrens drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj; 20123b2aab18SMatthew Ahrens /* 20133b2aab18SMatthew Ahrens * Release the hold from dmu_recv_begin. This must be done before 20143b2aab18SMatthew Ahrens * we return to open context, so that when we free the dataset's dnode, 20153b2aab18SMatthew Ahrens * we can evict its bonus buffer. 20163b2aab18SMatthew Ahrens */ 20173b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 20183b2aab18SMatthew Ahrens drc->drc_ds = NULL; 20193cb34c60Sahrens } 20203cb34c60Sahrens 2021ec5cf9d5SAlexander Stetsenko static int 20223b2aab18SMatthew Ahrens add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj) 2023ec5cf9d5SAlexander Stetsenko { 20243b2aab18SMatthew Ahrens dsl_pool_t *dp; 2025ec5cf9d5SAlexander Stetsenko dsl_dataset_t *snapds; 2026ec5cf9d5SAlexander Stetsenko guid_map_entry_t *gmep; 2027ec5cf9d5SAlexander Stetsenko int err; 2028ec5cf9d5SAlexander Stetsenko 2029ec5cf9d5SAlexander Stetsenko ASSERT(guid_map != NULL); 2030ec5cf9d5SAlexander Stetsenko 20313b2aab18SMatthew Ahrens err = dsl_pool_hold(name, FTAG, &dp); 20323b2aab18SMatthew Ahrens if (err != 0) 20333b2aab18SMatthew Ahrens return (err); 2034de8d9cffSMatthew Ahrens gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP); 2035de8d9cffSMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds); 2036ec5cf9d5SAlexander Stetsenko if (err == 0) { 2037ec5cf9d5SAlexander Stetsenko gmep->guid = snapds->ds_phys->ds_guid; 2038ec5cf9d5SAlexander Stetsenko gmep->gme_ds = snapds; 2039ec5cf9d5SAlexander Stetsenko avl_add(guid_map, gmep); 20403b2aab18SMatthew Ahrens dsl_dataset_long_hold(snapds, gmep); 2041de8d9cffSMatthew Ahrens } else { 2042de8d9cffSMatthew Ahrens kmem_free(gmep, sizeof (*gmep)); 2043ec5cf9d5SAlexander Stetsenko } 2044ec5cf9d5SAlexander Stetsenko 20453b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 2046ec5cf9d5SAlexander Stetsenko return (err); 2047ec5cf9d5SAlexander Stetsenko } 2048ec5cf9d5SAlexander Stetsenko 20493b2aab18SMatthew Ahrens static int dmu_recv_end_modified_blocks = 3; 20503b2aab18SMatthew Ahrens 2051ae46e4c7SMatthew Ahrens static int 2052ae46e4c7SMatthew Ahrens dmu_recv_existing_end(dmu_recv_cookie_t *drc) 2053f18faf3fSek { 20543b2aab18SMatthew Ahrens int error; 20553b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 20563cb34c60Sahrens 20573b2aab18SMatthew Ahrens #ifdef _KERNEL 20583b2aab18SMatthew Ahrens /* 20593b2aab18SMatthew Ahrens * We will be destroying the ds; make sure its origin is unmounted if 20603b2aab18SMatthew Ahrens * necessary. 20613b2aab18SMatthew Ahrens */ 20623b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 20633b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(name); 20643b2aab18SMatthew Ahrens #endif 20653cb34c60Sahrens 20663b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 20673b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 20687d46dc6cSMatthew Ahrens dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL); 20693cb34c60Sahrens 20703b2aab18SMatthew Ahrens if (error != 0) 20713b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 20723b2aab18SMatthew Ahrens return (error); 2073f18faf3fSek } 2074ae46e4c7SMatthew Ahrens 2075ae46e4c7SMatthew Ahrens static int 2076ae46e4c7SMatthew Ahrens dmu_recv_new_end(dmu_recv_cookie_t *drc) 2077ae46e4c7SMatthew Ahrens { 20783b2aab18SMatthew Ahrens int error; 2079ae46e4c7SMatthew Ahrens 20803b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 20813b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 20827d46dc6cSMatthew Ahrens dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL); 2083ae46e4c7SMatthew Ahrens 20843b2aab18SMatthew Ahrens if (error != 0) { 20853b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 20863b2aab18SMatthew Ahrens } else if (drc->drc_guid_to_ds_map != NULL) { 20873b2aab18SMatthew Ahrens (void) add_ds_to_guidmap(drc->drc_tofs, 20883b2aab18SMatthew Ahrens drc->drc_guid_to_ds_map, 20893b2aab18SMatthew Ahrens drc->drc_newsnapobj); 2090ae46e4c7SMatthew Ahrens } 20913b2aab18SMatthew Ahrens return (error); 2092ae46e4c7SMatthew Ahrens } 2093ae46e4c7SMatthew Ahrens 2094ae46e4c7SMatthew Ahrens int 209591948b51SKeith M Wesolowski dmu_recv_end(dmu_recv_cookie_t *drc, void *owner) 2096ae46e4c7SMatthew Ahrens { 209791948b51SKeith M Wesolowski drc->drc_owner = owner; 209891948b51SKeith M Wesolowski 20993b2aab18SMatthew Ahrens if (drc->drc_newfs) 2100ae46e4c7SMatthew Ahrens return (dmu_recv_new_end(drc)); 21013b2aab18SMatthew Ahrens else 21023b2aab18SMatthew Ahrens return (dmu_recv_existing_end(drc)); 2103ae46e4c7SMatthew Ahrens } 21042f3d8780SMatthew Ahrens 21052f3d8780SMatthew Ahrens /* 21062f3d8780SMatthew Ahrens * Return TRUE if this objset is currently being received into. 21072f3d8780SMatthew Ahrens */ 21082f3d8780SMatthew Ahrens boolean_t 21092f3d8780SMatthew Ahrens dmu_objset_is_receiving(objset_t *os) 21102f3d8780SMatthew Ahrens { 21112f3d8780SMatthew Ahrens return (os->os_dsl_dataset != NULL && 21122f3d8780SMatthew Ahrens os->os_dsl_dataset->ds_owner == dmu_recv_tag); 21132f3d8780SMatthew Ahrens } 2114