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. 26ec5cf9d5SAlexander Stetsenko */ 27efb80947Sahrens 28efb80947Sahrens #include <sys/dmu.h> 29efb80947Sahrens #include <sys/dmu_impl.h> 30efb80947Sahrens #include <sys/dmu_tx.h> 31efb80947Sahrens #include <sys/dbuf.h> 32efb80947Sahrens #include <sys/dnode.h> 33efb80947Sahrens #include <sys/zfs_context.h> 34efb80947Sahrens #include <sys/dmu_objset.h> 35efb80947Sahrens #include <sys/dmu_traverse.h> 36efb80947Sahrens #include <sys/dsl_dataset.h> 37efb80947Sahrens #include <sys/dsl_dir.h> 3892241e0bSTom Erickson #include <sys/dsl_prop.h> 39efb80947Sahrens #include <sys/dsl_pool.h> 40efb80947Sahrens #include <sys/dsl_synctask.h> 41efb80947Sahrens #include <sys/zfs_ioctl.h> 42efb80947Sahrens #include <sys/zap.h> 43efb80947Sahrens #include <sys/zio_checksum.h> 44dc7cd546SMark Shellenbaum #include <sys/zfs_znode.h> 45cde58dbcSMatthew Ahrens #include <zfs_fletcher.h> 469e69d7d0SLori Alt #include <sys/avl.h> 478e714474SLori Alt #include <sys/ddt.h> 48c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 493b2aab18SMatthew Ahrens #include <sys/dmu_send.h> 503b2aab18SMatthew Ahrens #include <sys/dsl_destroy.h> 515d7b4d43SMatthew Ahrens #include <sys/blkptr.h> 5278f17100SMatthew Ahrens #include <sys/dsl_bookmark.h> 535d7b4d43SMatthew Ahrens #include <sys/zfeature.h> 54efb80947Sahrens 5519b94df9SMatthew Ahrens /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */ 5619b94df9SMatthew Ahrens int zfs_send_corrupt_data = B_FALSE; 5719b94df9SMatthew Ahrens 583cb34c60Sahrens static char *dmu_recv_tag = "dmu_recv_tag"; 593b2aab18SMatthew Ahrens static const char *recv_clone_name = "%recv"; 603cb34c60Sahrens 61efb80947Sahrens static int 624e3c9f44SBill Pijewski dump_bytes(dmu_sendarg_t *dsp, void *buf, int len) 63efb80947Sahrens { 644e3c9f44SBill Pijewski dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset; 65efb80947Sahrens ssize_t resid; /* have to get resid to get detailed errno */ 66fb09f5aaSMadhav Suresh ASSERT0(len % 8); 67efb80947Sahrens 684e3c9f44SBill Pijewski fletcher_4_incremental_native(buf, len, &dsp->dsa_zc); 694e3c9f44SBill Pijewski dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp, 70efb80947Sahrens (caddr_t)buf, len, 71efb80947Sahrens 0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid); 724e3c9f44SBill Pijewski 734e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 744e3c9f44SBill Pijewski *dsp->dsa_off += len; 754e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 764e3c9f44SBill Pijewski 774e3c9f44SBill Pijewski return (dsp->dsa_err); 78efb80947Sahrens } 79efb80947Sahrens 80efb80947Sahrens static int 814e3c9f44SBill Pijewski dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 82efb80947Sahrens uint64_t length) 83efb80947Sahrens { 844e3c9f44SBill Pijewski struct drr_free *drrf = &(dsp->dsa_drr->drr_u.drr_free); 859e69d7d0SLori Alt 862f3d8780SMatthew Ahrens /* 872f3d8780SMatthew Ahrens * When we receive a free record, dbuf_free_range() assumes 882f3d8780SMatthew Ahrens * that the receiving system doesn't have any dbufs in the range 892f3d8780SMatthew Ahrens * being freed. This is always true because there is a one-record 902f3d8780SMatthew Ahrens * constraint: we only send one WRITE record for any given 912f3d8780SMatthew Ahrens * object+offset. We know that the one-record constraint is 922f3d8780SMatthew Ahrens * true because we always send data in increasing order by 932f3d8780SMatthew Ahrens * object,offset. 942f3d8780SMatthew Ahrens * 952f3d8780SMatthew Ahrens * If the increasing-order constraint ever changes, we should find 962f3d8780SMatthew Ahrens * another way to assert that the one-record constraint is still 972f3d8780SMatthew Ahrens * satisfied. 982f3d8780SMatthew Ahrens */ 992f3d8780SMatthew Ahrens ASSERT(object > dsp->dsa_last_data_object || 1002f3d8780SMatthew Ahrens (object == dsp->dsa_last_data_object && 1012f3d8780SMatthew Ahrens offset > dsp->dsa_last_data_offset)); 1022f3d8780SMatthew Ahrens 1032f3d8780SMatthew Ahrens /* 1042f3d8780SMatthew Ahrens * If we are doing a non-incremental send, then there can't 1052f3d8780SMatthew Ahrens * be any data in the dataset we're receiving into. Therefore 1062f3d8780SMatthew Ahrens * a free record would simply be a no-op. Save space by not 1072f3d8780SMatthew Ahrens * sending it to begin with. 1082f3d8780SMatthew Ahrens */ 1092f3d8780SMatthew Ahrens if (!dsp->dsa_incremental) 1102f3d8780SMatthew Ahrens return (0); 1112f3d8780SMatthew Ahrens 112534029e5SSimon Klinkert if (length != -1ULL && offset + length < offset) 113534029e5SSimon Klinkert length = -1ULL; 114534029e5SSimon Klinkert 1159e69d7d0SLori Alt /* 1169e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREE, push it out, 1179e69d7d0SLori Alt * since free block aggregation can only be done for blocks of the 1189e69d7d0SLori Alt * same type (i.e., DRR_FREE records can only be aggregated with 1199e69d7d0SLori Alt * other DRR_FREE records. DRR_FREEOBJECTS records can only be 1209e69d7d0SLori Alt * aggregated with other DRR_FREEOBJECTS records. 1219e69d7d0SLori Alt */ 1224e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 1234e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREE) { 1244e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1254e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 126be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1274e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1289e69d7d0SLori Alt } 1299e69d7d0SLori Alt 1304e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREE) { 1319e69d7d0SLori Alt /* 1329e69d7d0SLori Alt * There should never be a PENDING_FREE if length is -1 1339e69d7d0SLori Alt * (because dump_dnode is the only place where this 1349e69d7d0SLori Alt * function is called with a -1, and only after flushing 1359e69d7d0SLori Alt * any pending record). 1369e69d7d0SLori Alt */ 1379e69d7d0SLori Alt ASSERT(length != -1ULL); 1389e69d7d0SLori Alt /* 1399e69d7d0SLori Alt * Check to see whether this free block can be aggregated 1409e69d7d0SLori Alt * with pending one. 1419e69d7d0SLori Alt */ 1429e69d7d0SLori Alt if (drrf->drr_object == object && drrf->drr_offset + 1439e69d7d0SLori Alt drrf->drr_length == offset) { 1449e69d7d0SLori Alt drrf->drr_length += length; 1459e69d7d0SLori Alt return (0); 1469e69d7d0SLori Alt } else { 1479e69d7d0SLori Alt /* not a continuation. Push out pending record */ 1484e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1499e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 150be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1514e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1529e69d7d0SLori Alt } 1539e69d7d0SLori Alt } 1549e69d7d0SLori Alt /* create a FREE record and make it pending */ 1554e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 1564e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREE; 1579e69d7d0SLori Alt drrf->drr_object = object; 1589e69d7d0SLori Alt drrf->drr_offset = offset; 1599e69d7d0SLori Alt drrf->drr_length = length; 1604e3c9f44SBill Pijewski drrf->drr_toguid = dsp->dsa_toguid; 1619e69d7d0SLori Alt if (length == -1ULL) { 1624e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1634e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 164be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1659e69d7d0SLori Alt } else { 1664e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREE; 1679e69d7d0SLori Alt } 168efb80947Sahrens 169efb80947Sahrens return (0); 170efb80947Sahrens } 171efb80947Sahrens 172efb80947Sahrens static int 1735d7b4d43SMatthew Ahrens dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type, 1748e714474SLori Alt uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data) 175efb80947Sahrens { 1764e3c9f44SBill Pijewski struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write); 1779e69d7d0SLori Alt 1782f3d8780SMatthew Ahrens /* 1792f3d8780SMatthew Ahrens * We send data in increasing object, offset order. 1802f3d8780SMatthew Ahrens * See comment in dump_free() for details. 1812f3d8780SMatthew Ahrens */ 1822f3d8780SMatthew Ahrens ASSERT(object > dsp->dsa_last_data_object || 1832f3d8780SMatthew Ahrens (object == dsp->dsa_last_data_object && 1842f3d8780SMatthew Ahrens offset > dsp->dsa_last_data_offset)); 1852f3d8780SMatthew Ahrens dsp->dsa_last_data_object = object; 1862f3d8780SMatthew Ahrens dsp->dsa_last_data_offset = offset + blksz - 1; 1878e714474SLori Alt 1889e69d7d0SLori Alt /* 1899e69d7d0SLori Alt * If there is any kind of pending aggregation (currently either 1909e69d7d0SLori Alt * a grouping of free objects or free blocks), push it out to 1919e69d7d0SLori Alt * the stream, since aggregation can't be done across operations 1929e69d7d0SLori Alt * of different types. 1939e69d7d0SLori Alt */ 1944e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 1954e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 1964e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 197be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 1984e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 1999e69d7d0SLori Alt } 200efb80947Sahrens /* write a DATA record */ 2014e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2024e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_WRITE; 2039e69d7d0SLori Alt drrw->drr_object = object; 2049e69d7d0SLori Alt drrw->drr_type = type; 2059e69d7d0SLori Alt drrw->drr_offset = offset; 2069e69d7d0SLori Alt drrw->drr_length = blksz; 2074e3c9f44SBill Pijewski drrw->drr_toguid = dsp->dsa_toguid; 2085d7b4d43SMatthew Ahrens if (BP_IS_EMBEDDED(bp)) { 2095d7b4d43SMatthew Ahrens /* 2105d7b4d43SMatthew Ahrens * There's no pre-computed checksum of embedded BP's, so 2115d7b4d43SMatthew Ahrens * (like fletcher4-checkummed blocks) userland will have 2125d7b4d43SMatthew Ahrens * to compute a dedup-capable checksum itself. 2135d7b4d43SMatthew Ahrens */ 2145d7b4d43SMatthew Ahrens drrw->drr_checksumtype = ZIO_CHECKSUM_OFF; 2155d7b4d43SMatthew Ahrens } else { 2165d7b4d43SMatthew Ahrens drrw->drr_checksumtype = BP_GET_CHECKSUM(bp); 2175d7b4d43SMatthew Ahrens if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup) 2185d7b4d43SMatthew Ahrens drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP; 2195d7b4d43SMatthew Ahrens DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp)); 2205d7b4d43SMatthew Ahrens DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp)); 2215d7b4d43SMatthew Ahrens DDK_SET_COMPRESS(&drrw->drr_key, BP_GET_COMPRESS(bp)); 2225d7b4d43SMatthew Ahrens drrw->drr_key.ddk_cksum = bp->blk_cksum; 2235d7b4d43SMatthew Ahrens } 224efb80947Sahrens 2254e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 226be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2274e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz) != 0) 228be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 229efb80947Sahrens return (0); 230efb80947Sahrens } 231efb80947Sahrens 2325d7b4d43SMatthew Ahrens static int 2335d7b4d43SMatthew Ahrens dump_write_embedded(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset, 2345d7b4d43SMatthew Ahrens int blksz, const blkptr_t *bp) 2355d7b4d43SMatthew Ahrens { 2365d7b4d43SMatthew Ahrens char buf[BPE_PAYLOAD_SIZE]; 2375d7b4d43SMatthew Ahrens struct drr_write_embedded *drrw = 2385d7b4d43SMatthew Ahrens &(dsp->dsa_drr->drr_u.drr_write_embedded); 2395d7b4d43SMatthew Ahrens 2405d7b4d43SMatthew Ahrens if (dsp->dsa_pending_op != PENDING_NONE) { 2415d7b4d43SMatthew Ahrens if (dump_bytes(dsp, dsp->dsa_drr, 2425d7b4d43SMatthew Ahrens sizeof (dmu_replay_record_t)) != 0) 2435d7b4d43SMatthew Ahrens return (EINTR); 2445d7b4d43SMatthew Ahrens dsp->dsa_pending_op = PENDING_NONE; 2455d7b4d43SMatthew Ahrens } 2465d7b4d43SMatthew Ahrens 2475d7b4d43SMatthew Ahrens ASSERT(BP_IS_EMBEDDED(bp)); 2485d7b4d43SMatthew Ahrens 2495d7b4d43SMatthew Ahrens bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2505d7b4d43SMatthew Ahrens dsp->dsa_drr->drr_type = DRR_WRITE_EMBEDDED; 2515d7b4d43SMatthew Ahrens drrw->drr_object = object; 2525d7b4d43SMatthew Ahrens drrw->drr_offset = offset; 2535d7b4d43SMatthew Ahrens drrw->drr_length = blksz; 2545d7b4d43SMatthew Ahrens drrw->drr_toguid = dsp->dsa_toguid; 2555d7b4d43SMatthew Ahrens drrw->drr_compression = BP_GET_COMPRESS(bp); 2565d7b4d43SMatthew Ahrens drrw->drr_etype = BPE_GET_ETYPE(bp); 2575d7b4d43SMatthew Ahrens drrw->drr_lsize = BPE_GET_LSIZE(bp); 2585d7b4d43SMatthew Ahrens drrw->drr_psize = BPE_GET_PSIZE(bp); 2595d7b4d43SMatthew Ahrens 2605d7b4d43SMatthew Ahrens decode_embedded_bp_compressed(bp, buf); 2615d7b4d43SMatthew Ahrens 2625d7b4d43SMatthew Ahrens if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 2635d7b4d43SMatthew Ahrens return (EINTR); 2645d7b4d43SMatthew Ahrens if (dump_bytes(dsp, buf, P2ROUNDUP(drrw->drr_psize, 8)) != 0) 2655d7b4d43SMatthew Ahrens return (EINTR); 2665d7b4d43SMatthew Ahrens return (0); 2675d7b4d43SMatthew Ahrens } 2685d7b4d43SMatthew Ahrens 2690a586ceaSMark Shellenbaum static int 2704e3c9f44SBill Pijewski dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data) 2710a586ceaSMark Shellenbaum { 2724e3c9f44SBill Pijewski struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill); 2730a586ceaSMark Shellenbaum 2744e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 2754e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 2764e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 277be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2784e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 2790a586ceaSMark Shellenbaum } 2800a586ceaSMark Shellenbaum 2810a586ceaSMark Shellenbaum /* write a SPILL record */ 2824e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 2834e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_SPILL; 2840a586ceaSMark Shellenbaum drrs->drr_object = object; 2850a586ceaSMark Shellenbaum drrs->drr_length = blksz; 2864e3c9f44SBill Pijewski drrs->drr_toguid = dsp->dsa_toguid; 2870a586ceaSMark Shellenbaum 2884e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t))) 289be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2904e3c9f44SBill Pijewski if (dump_bytes(dsp, data, blksz)) 291be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 2920a586ceaSMark Shellenbaum return (0); 2930a586ceaSMark Shellenbaum } 2940a586ceaSMark Shellenbaum 295efb80947Sahrens static int 2964e3c9f44SBill Pijewski dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs) 297efb80947Sahrens { 2984e3c9f44SBill Pijewski struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects); 2999e69d7d0SLori Alt 3002f3d8780SMatthew Ahrens /* See comment in dump_free(). */ 3012f3d8780SMatthew Ahrens if (!dsp->dsa_incremental) 3022f3d8780SMatthew Ahrens return (0); 3032f3d8780SMatthew Ahrens 3049e69d7d0SLori Alt /* 3059e69d7d0SLori Alt * If there is a pending op, but it's not PENDING_FREEOBJECTS, 3069e69d7d0SLori Alt * push it out, since free block aggregation can only be done for 3079e69d7d0SLori Alt * blocks of the same type (i.e., DRR_FREE records can only be 3089e69d7d0SLori Alt * aggregated with other DRR_FREE records. DRR_FREEOBJECTS records 3099e69d7d0SLori Alt * can only be aggregated with other DRR_FREEOBJECTS records. 3109e69d7d0SLori Alt */ 3114e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE && 3124e3c9f44SBill Pijewski dsp->dsa_pending_op != PENDING_FREEOBJECTS) { 3134e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3144e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 315be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3164e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3179e69d7d0SLori Alt } 3184e3c9f44SBill Pijewski if (dsp->dsa_pending_op == PENDING_FREEOBJECTS) { 3199e69d7d0SLori Alt /* 3209e69d7d0SLori Alt * See whether this free object array can be aggregated 3219e69d7d0SLori Alt * with pending one 3229e69d7d0SLori Alt */ 3239e69d7d0SLori Alt if (drrfo->drr_firstobj + drrfo->drr_numobjs == firstobj) { 3249e69d7d0SLori Alt drrfo->drr_numobjs += numobjs; 3259e69d7d0SLori Alt return (0); 3269e69d7d0SLori Alt } else { 3279e69d7d0SLori Alt /* can't be aggregated. Push out pending record */ 3284e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3299e69d7d0SLori Alt sizeof (dmu_replay_record_t)) != 0) 330be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3314e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3329e69d7d0SLori Alt } 3339e69d7d0SLori Alt } 3349e69d7d0SLori Alt 335efb80947Sahrens /* write a FREEOBJECTS record */ 3364e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 3374e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_FREEOBJECTS; 3389e69d7d0SLori Alt drrfo->drr_firstobj = firstobj; 3399e69d7d0SLori Alt drrfo->drr_numobjs = numobjs; 3404e3c9f44SBill Pijewski drrfo->drr_toguid = dsp->dsa_toguid; 3419e69d7d0SLori Alt 3424e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_FREEOBJECTS; 343efb80947Sahrens 344efb80947Sahrens return (0); 345efb80947Sahrens } 346efb80947Sahrens 347efb80947Sahrens static int 3484e3c9f44SBill Pijewski dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp) 349efb80947Sahrens { 3504e3c9f44SBill Pijewski struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object); 3519e69d7d0SLori Alt 352efb80947Sahrens if (dnp == NULL || dnp->dn_type == DMU_OT_NONE) 3534e3c9f44SBill Pijewski return (dump_freeobjects(dsp, object, 1)); 354efb80947Sahrens 3554e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) { 3564e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, 3574e3c9f44SBill Pijewski sizeof (dmu_replay_record_t)) != 0) 358be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3594e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 3609e69d7d0SLori Alt } 3619e69d7d0SLori Alt 362efb80947Sahrens /* write an OBJECT record */ 3634e3c9f44SBill Pijewski bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t)); 3644e3c9f44SBill Pijewski dsp->dsa_drr->drr_type = DRR_OBJECT; 3659e69d7d0SLori Alt drro->drr_object = object; 3669e69d7d0SLori Alt drro->drr_type = dnp->dn_type; 3679e69d7d0SLori Alt drro->drr_bonustype = dnp->dn_bonustype; 3689e69d7d0SLori Alt drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 3699e69d7d0SLori Alt drro->drr_bonuslen = dnp->dn_bonuslen; 3709e69d7d0SLori Alt drro->drr_checksumtype = dnp->dn_checksum; 3719e69d7d0SLori Alt drro->drr_compress = dnp->dn_compress; 3724e3c9f44SBill Pijewski drro->drr_toguid = dsp->dsa_toguid; 3739e69d7d0SLori Alt 3744e3c9f44SBill Pijewski if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0) 375be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 376efb80947Sahrens 3774e3c9f44SBill Pijewski if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) 378be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 379efb80947Sahrens 3802f3d8780SMatthew Ahrens /* Free anything past the end of the file. */ 3814e3c9f44SBill Pijewski if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) * 3822f3d8780SMatthew Ahrens (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT), -1ULL) != 0) 383be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 3843b2aab18SMatthew Ahrens if (dsp->dsa_err != 0) 385be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 386efb80947Sahrens return (0); 387efb80947Sahrens } 388efb80947Sahrens 3895d7b4d43SMatthew Ahrens static boolean_t 3905d7b4d43SMatthew Ahrens backup_do_embed(dmu_sendarg_t *dsp, const blkptr_t *bp) 3915d7b4d43SMatthew Ahrens { 3925d7b4d43SMatthew Ahrens if (!BP_IS_EMBEDDED(bp)) 3935d7b4d43SMatthew Ahrens return (B_FALSE); 3945d7b4d43SMatthew Ahrens 3955d7b4d43SMatthew Ahrens /* 3965d7b4d43SMatthew Ahrens * Compression function must be legacy, or explicitly enabled. 3975d7b4d43SMatthew Ahrens */ 3985d7b4d43SMatthew Ahrens if ((BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_LEGACY_FUNCTIONS && 3995d7b4d43SMatthew Ahrens !(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_EMBED_DATA_LZ4))) 4005d7b4d43SMatthew Ahrens return (B_FALSE); 4015d7b4d43SMatthew Ahrens 4025d7b4d43SMatthew Ahrens /* 4035d7b4d43SMatthew Ahrens * Embed type must be explicitly enabled. 4045d7b4d43SMatthew Ahrens */ 4055d7b4d43SMatthew Ahrens switch (BPE_GET_ETYPE(bp)) { 4065d7b4d43SMatthew Ahrens case BP_EMBEDDED_TYPE_DATA: 4075d7b4d43SMatthew Ahrens if (dsp->dsa_featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) 4085d7b4d43SMatthew Ahrens return (B_TRUE); 4095d7b4d43SMatthew Ahrens break; 4105d7b4d43SMatthew Ahrens default: 4115d7b4d43SMatthew Ahrens return (B_FALSE); 4125d7b4d43SMatthew Ahrens } 4135d7b4d43SMatthew Ahrens return (B_FALSE); 4145d7b4d43SMatthew Ahrens } 4155d7b4d43SMatthew Ahrens 416efb80947Sahrens #define BP_SPAN(dnp, level) \ 417efb80947Sahrens (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 418efb80947Sahrens (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 419efb80947Sahrens 420b24ab676SJeff Bonwick /* ARGSUSED */ 421efb80947Sahrens static int 4221b912ec7SGeorge Wilson backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 4237802d7bfSMatthew Ahrens const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 424efb80947Sahrens { 4254e3c9f44SBill Pijewski dmu_sendarg_t *dsp = arg; 426efb80947Sahrens dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE; 427efb80947Sahrens int err = 0; 428efb80947Sahrens 429efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) 430be6fd75aSMatthew Ahrens return (SET_ERROR(EINTR)); 431efb80947Sahrens 432b24ab676SJeff Bonwick if (zb->zb_object != DMU_META_DNODE_OBJECT && 433b24ab676SJeff Bonwick DMU_OBJECT_IS_SPECIAL(zb->zb_object)) { 43414843421SMatthew Ahrens return (0); 43578f17100SMatthew Ahrens } else if (zb->zb_level == ZB_ZIL_LEVEL) { 43678f17100SMatthew Ahrens /* 43778f17100SMatthew Ahrens * If we are sending a non-snapshot (which is allowed on 43878f17100SMatthew Ahrens * read-only pools), it may have a ZIL, which must be ignored. 43978f17100SMatthew Ahrens */ 44078f17100SMatthew Ahrens return (0); 44143466aaeSMax Grossman } else if (BP_IS_HOLE(bp) && 44243466aaeSMax Grossman zb->zb_object == DMU_META_DNODE_OBJECT) { 44388b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 44488b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 4454e3c9f44SBill Pijewski err = dump_freeobjects(dsp, dnobj, span >> DNODE_SHIFT); 44643466aaeSMax Grossman } else if (BP_IS_HOLE(bp)) { 44788b7b0f2SMatthew Ahrens uint64_t span = BP_SPAN(dnp, zb->zb_level); 4484e3c9f44SBill Pijewski err = dump_free(dsp, zb->zb_object, zb->zb_blkid * span, span); 44988b7b0f2SMatthew Ahrens } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) { 45088b7b0f2SMatthew Ahrens return (0); 45188b7b0f2SMatthew Ahrens } else if (type == DMU_OT_DNODE) { 45288b7b0f2SMatthew Ahrens dnode_phys_t *blk; 453efb80947Sahrens int i; 454efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 45588b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 45688b7b0f2SMatthew Ahrens arc_buf_t *abuf; 457efb80947Sahrens 4581b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4591b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4601b912ec7SGeorge Wilson &aflags, zb) != 0) 461be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 46288b7b0f2SMatthew Ahrens 46388b7b0f2SMatthew Ahrens blk = abuf->b_data; 464efb80947Sahrens for (i = 0; i < blksz >> DNODE_SHIFT; i++) { 46588b7b0f2SMatthew Ahrens uint64_t dnobj = (zb->zb_blkid << 46688b7b0f2SMatthew Ahrens (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 4674e3c9f44SBill Pijewski err = dump_dnode(dsp, dnobj, blk+i); 4683b2aab18SMatthew Ahrens if (err != 0) 469efb80947Sahrens break; 470efb80947Sahrens } 47188b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 4720a586ceaSMark Shellenbaum } else if (type == DMU_OT_SA) { 4730a586ceaSMark Shellenbaum uint32_t aflags = ARC_WAIT; 4740a586ceaSMark Shellenbaum arc_buf_t *abuf; 4750a586ceaSMark Shellenbaum int blksz = BP_GET_LSIZE(bp); 4760a586ceaSMark Shellenbaum 4771b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4781b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4791b912ec7SGeorge Wilson &aflags, zb) != 0) 480be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 4810a586ceaSMark Shellenbaum 4824e3c9f44SBill Pijewski err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data); 4830a586ceaSMark Shellenbaum (void) arc_buf_remove_ref(abuf, &abuf); 4845d7b4d43SMatthew Ahrens } else if (backup_do_embed(dsp, bp)) { 4855d7b4d43SMatthew Ahrens /* it's an embedded level-0 block of a regular object */ 4865d7b4d43SMatthew Ahrens int blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT; 4875d7b4d43SMatthew Ahrens err = dump_write_embedded(dsp, zb->zb_object, 4885d7b4d43SMatthew Ahrens zb->zb_blkid * blksz, blksz, bp); 48988b7b0f2SMatthew Ahrens } else { /* it's a level-0 block of a regular object */ 49088b7b0f2SMatthew Ahrens uint32_t aflags = ARC_WAIT; 49188b7b0f2SMatthew Ahrens arc_buf_t *abuf; 492efb80947Sahrens int blksz = BP_GET_LSIZE(bp); 49388b7b0f2SMatthew Ahrens 4945d7b4d43SMatthew Ahrens ASSERT3U(blksz, ==, dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT); 49578f17100SMatthew Ahrens ASSERT0(zb->zb_level); 4961b912ec7SGeorge Wilson if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 4971b912ec7SGeorge Wilson ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, 4981b912ec7SGeorge Wilson &aflags, zb) != 0) { 49919b94df9SMatthew Ahrens if (zfs_send_corrupt_data) { 50019b94df9SMatthew Ahrens /* Send a block filled with 0x"zfs badd bloc" */ 50119b94df9SMatthew Ahrens abuf = arc_buf_alloc(spa, blksz, &abuf, 50219b94df9SMatthew Ahrens ARC_BUFC_DATA); 50319b94df9SMatthew Ahrens uint64_t *ptr; 50419b94df9SMatthew Ahrens for (ptr = abuf->b_data; 50519b94df9SMatthew Ahrens (char *)ptr < (char *)abuf->b_data + blksz; 50619b94df9SMatthew Ahrens ptr++) 50719b94df9SMatthew Ahrens *ptr = 0x2f5baddb10c; 50819b94df9SMatthew Ahrens } else { 509be6fd75aSMatthew Ahrens return (SET_ERROR(EIO)); 51019b94df9SMatthew Ahrens } 51119b94df9SMatthew Ahrens } 51288b7b0f2SMatthew Ahrens 5135d7b4d43SMatthew Ahrens err = dump_write(dsp, type, zb->zb_object, zb->zb_blkid * blksz, 5148e714474SLori Alt blksz, bp, abuf->b_data); 51588b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(abuf, &abuf); 516efb80947Sahrens } 517efb80947Sahrens 518efb80947Sahrens ASSERT(err == 0 || err == EINTR); 519efb80947Sahrens return (err); 520efb80947Sahrens } 521efb80947Sahrens 5224445fffbSMatthew Ahrens /* 52378f17100SMatthew Ahrens * Releases dp using the specified tag. 5244445fffbSMatthew Ahrens */ 5253b2aab18SMatthew Ahrens static int 5263b2aab18SMatthew Ahrens dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds, 5275d7b4d43SMatthew Ahrens zfs_bookmark_phys_t *fromzb, boolean_t is_clone, boolean_t embedok, 5285d7b4d43SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 529efb80947Sahrens { 5303b2aab18SMatthew Ahrens objset_t *os; 531efb80947Sahrens dmu_replay_record_t *drr; 5324e3c9f44SBill Pijewski dmu_sendarg_t *dsp; 533efb80947Sahrens int err; 5343cb34c60Sahrens uint64_t fromtxg = 0; 5355d7b4d43SMatthew Ahrens uint64_t featureflags = 0; 536efb80947Sahrens 5373b2aab18SMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 5383b2aab18SMatthew Ahrens if (err != 0) { 5393b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 5403b2aab18SMatthew Ahrens return (err); 5413b2aab18SMatthew Ahrens } 542efb80947Sahrens 543efb80947Sahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 544efb80947Sahrens drr->drr_type = DRR_BEGIN; 545efb80947Sahrens drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC; 5469e69d7d0SLori Alt DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo, 5479e69d7d0SLori Alt DMU_SUBSTREAM); 548dc7cd546SMark Shellenbaum 549dc7cd546SMark Shellenbaum #ifdef _KERNEL 5503b2aab18SMatthew Ahrens if (dmu_objset_type(os) == DMU_OST_ZFS) { 551dc7cd546SMark Shellenbaum uint64_t version; 5523b2aab18SMatthew Ahrens if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &version) != 0) { 5534e3c9f44SBill Pijewski kmem_free(drr, sizeof (dmu_replay_record_t)); 5543b2aab18SMatthew Ahrens dsl_pool_rele(dp, tag); 555be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 5564e3c9f44SBill Pijewski } 5573b2aab18SMatthew Ahrens if (version >= ZPL_VERSION_SA) { 5585d7b4d43SMatthew Ahrens featureflags |= DMU_BACKUP_FEATURE_SA_SPILL; 559dc7cd546SMark Shellenbaum } 560dc7cd546SMark Shellenbaum } 561dc7cd546SMark Shellenbaum #endif 562dc7cd546SMark Shellenbaum 5635d7b4d43SMatthew Ahrens if (embedok && 5645d7b4d43SMatthew Ahrens spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) { 5655d7b4d43SMatthew Ahrens featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA; 5665d7b4d43SMatthew Ahrens if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) 5675d7b4d43SMatthew Ahrens featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA_LZ4; 5685d7b4d43SMatthew Ahrens } else { 5695d7b4d43SMatthew Ahrens embedok = B_FALSE; 5705d7b4d43SMatthew Ahrens } 5715d7b4d43SMatthew Ahrens 5725d7b4d43SMatthew Ahrens DMU_SET_FEATUREFLAGS(drr->drr_u.drr_begin.drr_versioninfo, 5735d7b4d43SMatthew Ahrens featureflags); 5745d7b4d43SMatthew Ahrens 575efb80947Sahrens drr->drr_u.drr_begin.drr_creation_time = 576efb80947Sahrens ds->ds_phys->ds_creation_time; 5773b2aab18SMatthew Ahrens drr->drr_u.drr_begin.drr_type = dmu_objset_type(os); 57878f17100SMatthew Ahrens if (is_clone) 5793cb34c60Sahrens drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE; 580efb80947Sahrens drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid; 581ab04eb8eStimh if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 582ab04eb8eStimh drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA; 583ab04eb8eStimh 58478f17100SMatthew Ahrens if (fromzb != NULL) { 58578f17100SMatthew Ahrens drr->drr_u.drr_begin.drr_fromguid = fromzb->zbm_guid; 58678f17100SMatthew Ahrens fromtxg = fromzb->zbm_creation_txg; 58778f17100SMatthew Ahrens } 588efb80947Sahrens dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname); 58978f17100SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 59078f17100SMatthew Ahrens (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--", 59178f17100SMatthew Ahrens sizeof (drr->drr_u.drr_begin.drr_toname)); 5923b2aab18SMatthew Ahrens } 5933cb34c60Sahrens 5944e3c9f44SBill Pijewski dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP); 5954e3c9f44SBill Pijewski 5964e3c9f44SBill Pijewski dsp->dsa_drr = drr; 5974e3c9f44SBill Pijewski dsp->dsa_vp = vp; 5984e3c9f44SBill Pijewski dsp->dsa_outfd = outfd; 5994e3c9f44SBill Pijewski dsp->dsa_proc = curproc; 6003b2aab18SMatthew Ahrens dsp->dsa_os = os; 6014e3c9f44SBill Pijewski dsp->dsa_off = off; 6024e3c9f44SBill Pijewski dsp->dsa_toguid = ds->ds_phys->ds_guid; 6034e3c9f44SBill Pijewski ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0); 6044e3c9f44SBill Pijewski dsp->dsa_pending_op = PENDING_NONE; 60578f17100SMatthew Ahrens dsp->dsa_incremental = (fromzb != NULL); 6065d7b4d43SMatthew Ahrens dsp->dsa_featureflags = featureflags; 6074e3c9f44SBill Pijewski 6084e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 6094e3c9f44SBill Pijewski list_insert_head(&ds->ds_sendstreams, dsp); 6104e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 6114e3c9f44SBill Pijewski 612de8d9cffSMatthew Ahrens dsl_dataset_long_hold(ds, FTAG); 613de8d9cffSMatthew Ahrens dsl_pool_rele(dp, tag); 614de8d9cffSMatthew Ahrens 6154e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 6164e3c9f44SBill Pijewski err = dsp->dsa_err; 6174e3c9f44SBill Pijewski goto out; 618efb80947Sahrens } 619efb80947Sahrens 62088b7b0f2SMatthew Ahrens err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH, 6214e3c9f44SBill Pijewski backup_cb, dsp); 622efb80947Sahrens 6234e3c9f44SBill Pijewski if (dsp->dsa_pending_op != PENDING_NONE) 6244e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) 625be6fd75aSMatthew Ahrens err = SET_ERROR(EINTR); 6269e69d7d0SLori Alt 6273b2aab18SMatthew Ahrens if (err != 0) { 6283b2aab18SMatthew Ahrens if (err == EINTR && dsp->dsa_err != 0) 6294e3c9f44SBill Pijewski err = dsp->dsa_err; 6304e3c9f44SBill Pijewski goto out; 631efb80947Sahrens } 632efb80947Sahrens 633efb80947Sahrens bzero(drr, sizeof (dmu_replay_record_t)); 634efb80947Sahrens drr->drr_type = DRR_END; 6354e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc; 6364e3c9f44SBill Pijewski drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid; 637efb80947Sahrens 6384e3c9f44SBill Pijewski if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) { 6394e3c9f44SBill Pijewski err = dsp->dsa_err; 6404e3c9f44SBill Pijewski goto out; 6417b5309bbSgw } 642efb80947Sahrens 6434e3c9f44SBill Pijewski out: 6444e3c9f44SBill Pijewski mutex_enter(&ds->ds_sendstream_lock); 6454e3c9f44SBill Pijewski list_remove(&ds->ds_sendstreams, dsp); 6464e3c9f44SBill Pijewski mutex_exit(&ds->ds_sendstream_lock); 6474e3c9f44SBill Pijewski 648efb80947Sahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 6494e3c9f44SBill Pijewski kmem_free(dsp, sizeof (dmu_sendarg_t)); 650efb80947Sahrens 6513b2aab18SMatthew Ahrens dsl_dataset_long_rele(ds, FTAG); 6523b2aab18SMatthew Ahrens 6534e3c9f44SBill Pijewski return (err); 654efb80947Sahrens } 655efb80947Sahrens 65619b94df9SMatthew Ahrens int 6573b2aab18SMatthew Ahrens dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, 6585d7b4d43SMatthew Ahrens boolean_t embedok, int outfd, vnode_t *vp, offset_t *off) 6593b2aab18SMatthew Ahrens { 6603b2aab18SMatthew Ahrens dsl_pool_t *dp; 6613b2aab18SMatthew Ahrens dsl_dataset_t *ds; 6623b2aab18SMatthew Ahrens dsl_dataset_t *fromds = NULL; 6633b2aab18SMatthew Ahrens int err; 6643b2aab18SMatthew Ahrens 6653b2aab18SMatthew Ahrens err = dsl_pool_hold(pool, FTAG, &dp); 6663b2aab18SMatthew Ahrens if (err != 0) 6673b2aab18SMatthew Ahrens return (err); 6683b2aab18SMatthew Ahrens 6693b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, tosnap, FTAG, &ds); 6703b2aab18SMatthew Ahrens if (err != 0) { 6713b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 6723b2aab18SMatthew Ahrens return (err); 6733b2aab18SMatthew Ahrens } 6743b2aab18SMatthew Ahrens 6753b2aab18SMatthew Ahrens if (fromsnap != 0) { 67678f17100SMatthew Ahrens zfs_bookmark_phys_t zb; 67778f17100SMatthew Ahrens boolean_t is_clone; 67878f17100SMatthew Ahrens 6793b2aab18SMatthew Ahrens err = dsl_dataset_hold_obj(dp, fromsnap, FTAG, &fromds); 6803b2aab18SMatthew Ahrens if (err != 0) { 6813b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 6823b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 6833b2aab18SMatthew Ahrens return (err); 6843b2aab18SMatthew Ahrens } 68578f17100SMatthew Ahrens if (!dsl_dataset_is_before(ds, fromds, 0)) 68678f17100SMatthew Ahrens err = SET_ERROR(EXDEV); 68778f17100SMatthew Ahrens zb.zbm_creation_time = fromds->ds_phys->ds_creation_time; 68878f17100SMatthew Ahrens zb.zbm_creation_txg = fromds->ds_phys->ds_creation_txg; 68978f17100SMatthew Ahrens zb.zbm_guid = fromds->ds_phys->ds_guid; 69078f17100SMatthew Ahrens is_clone = (fromds->ds_dir != ds->ds_dir); 69178f17100SMatthew Ahrens dsl_dataset_rele(fromds, FTAG); 6925d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone, embedok, 69378f17100SMatthew Ahrens outfd, vp, off); 69478f17100SMatthew Ahrens } else { 6955d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE, embedok, 69678f17100SMatthew Ahrens outfd, vp, off); 6973b2aab18SMatthew Ahrens } 69878f17100SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 69978f17100SMatthew Ahrens return (err); 7003b2aab18SMatthew Ahrens } 7013b2aab18SMatthew Ahrens 7023b2aab18SMatthew Ahrens int 7035d7b4d43SMatthew Ahrens dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok, 7043b2aab18SMatthew Ahrens int outfd, vnode_t *vp, offset_t *off) 7053b2aab18SMatthew Ahrens { 7063b2aab18SMatthew Ahrens dsl_pool_t *dp; 7073b2aab18SMatthew Ahrens dsl_dataset_t *ds; 7083b2aab18SMatthew Ahrens int err; 70978f17100SMatthew Ahrens boolean_t owned = B_FALSE; 7103b2aab18SMatthew Ahrens 71178f17100SMatthew Ahrens if (fromsnap != NULL && strpbrk(fromsnap, "@#") == NULL) 712be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 7133b2aab18SMatthew Ahrens 7143b2aab18SMatthew Ahrens err = dsl_pool_hold(tosnap, FTAG, &dp); 7153b2aab18SMatthew Ahrens if (err != 0) 7163b2aab18SMatthew Ahrens return (err); 7173b2aab18SMatthew Ahrens 71878f17100SMatthew Ahrens if (strchr(tosnap, '@') == NULL && spa_writeable(dp->dp_spa)) { 71978f17100SMatthew Ahrens /* 72078f17100SMatthew Ahrens * We are sending a filesystem or volume. Ensure 72178f17100SMatthew Ahrens * that it doesn't change by owning the dataset. 72278f17100SMatthew Ahrens */ 72378f17100SMatthew Ahrens err = dsl_dataset_own(dp, tosnap, FTAG, &ds); 72478f17100SMatthew Ahrens owned = B_TRUE; 72578f17100SMatthew Ahrens } else { 72678f17100SMatthew Ahrens err = dsl_dataset_hold(dp, tosnap, FTAG, &ds); 72778f17100SMatthew Ahrens } 7283b2aab18SMatthew Ahrens if (err != 0) { 7293b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 7303b2aab18SMatthew Ahrens return (err); 7313b2aab18SMatthew Ahrens } 7323b2aab18SMatthew Ahrens 7333b2aab18SMatthew Ahrens if (fromsnap != NULL) { 73478f17100SMatthew Ahrens zfs_bookmark_phys_t zb; 73578f17100SMatthew Ahrens boolean_t is_clone = B_FALSE; 73678f17100SMatthew Ahrens int fsnamelen = strchr(tosnap, '@') - tosnap; 73778f17100SMatthew Ahrens 73878f17100SMatthew Ahrens /* 73978f17100SMatthew Ahrens * If the fromsnap is in a different filesystem, then 74078f17100SMatthew Ahrens * mark the send stream as a clone. 74178f17100SMatthew Ahrens */ 74278f17100SMatthew Ahrens if (strncmp(tosnap, fromsnap, fsnamelen) != 0 || 74378f17100SMatthew Ahrens (fromsnap[fsnamelen] != '@' && 74478f17100SMatthew Ahrens fromsnap[fsnamelen] != '#')) { 74578f17100SMatthew Ahrens is_clone = B_TRUE; 74678f17100SMatthew Ahrens } 74778f17100SMatthew Ahrens 74878f17100SMatthew Ahrens if (strchr(fromsnap, '@')) { 74978f17100SMatthew Ahrens dsl_dataset_t *fromds; 75078f17100SMatthew Ahrens err = dsl_dataset_hold(dp, fromsnap, FTAG, &fromds); 75178f17100SMatthew Ahrens if (err == 0) { 75278f17100SMatthew Ahrens if (!dsl_dataset_is_before(ds, fromds, 0)) 75378f17100SMatthew Ahrens err = SET_ERROR(EXDEV); 75478f17100SMatthew Ahrens zb.zbm_creation_time = 75578f17100SMatthew Ahrens fromds->ds_phys->ds_creation_time; 75678f17100SMatthew Ahrens zb.zbm_creation_txg = 75778f17100SMatthew Ahrens fromds->ds_phys->ds_creation_txg; 75878f17100SMatthew Ahrens zb.zbm_guid = fromds->ds_phys->ds_guid; 75978f17100SMatthew Ahrens is_clone = (ds->ds_dir != fromds->ds_dir); 76078f17100SMatthew Ahrens dsl_dataset_rele(fromds, FTAG); 76178f17100SMatthew Ahrens } 76278f17100SMatthew Ahrens } else { 76378f17100SMatthew Ahrens err = dsl_bookmark_lookup(dp, fromsnap, ds, &zb); 76478f17100SMatthew Ahrens } 7653b2aab18SMatthew Ahrens if (err != 0) { 7663b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 7673b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 7683b2aab18SMatthew Ahrens return (err); 7693b2aab18SMatthew Ahrens } 7705d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone, embedok, 77178f17100SMatthew Ahrens outfd, vp, off); 77278f17100SMatthew Ahrens } else { 7735d7b4d43SMatthew Ahrens err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE, embedok, 77478f17100SMatthew Ahrens outfd, vp, off); 7753b2aab18SMatthew Ahrens } 77678f17100SMatthew Ahrens if (owned) 77778f17100SMatthew Ahrens dsl_dataset_disown(ds, FTAG); 77878f17100SMatthew Ahrens else 77978f17100SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 78078f17100SMatthew Ahrens return (err); 7813b2aab18SMatthew Ahrens } 7823b2aab18SMatthew Ahrens 7833b2aab18SMatthew Ahrens int 7843b2aab18SMatthew Ahrens dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep) 78519b94df9SMatthew Ahrens { 78619b94df9SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 78719b94df9SMatthew Ahrens int err; 78819b94df9SMatthew Ahrens uint64_t size; 78919b94df9SMatthew Ahrens 7903b2aab18SMatthew Ahrens ASSERT(dsl_pool_config_held(dp)); 7913b2aab18SMatthew Ahrens 79219b94df9SMatthew Ahrens /* tosnap must be a snapshot */ 7933b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) 794be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 79519b94df9SMatthew Ahrens 7964445fffbSMatthew Ahrens /* 7974445fffbSMatthew Ahrens * fromsnap must be an earlier snapshot from the same fs as tosnap, 7984445fffbSMatthew Ahrens * or the origin's fs. 7994445fffbSMatthew Ahrens */ 80078f17100SMatthew Ahrens if (fromds != NULL && !dsl_dataset_is_before(ds, fromds, 0)) 801be6fd75aSMatthew Ahrens return (SET_ERROR(EXDEV)); 80219b94df9SMatthew Ahrens 80319b94df9SMatthew Ahrens /* Get uncompressed size estimate of changed data. */ 80419b94df9SMatthew Ahrens if (fromds == NULL) { 80519b94df9SMatthew Ahrens size = ds->ds_phys->ds_uncompressed_bytes; 80619b94df9SMatthew Ahrens } else { 80719b94df9SMatthew Ahrens uint64_t used, comp; 80819b94df9SMatthew Ahrens err = dsl_dataset_space_written(fromds, ds, 80919b94df9SMatthew Ahrens &used, &comp, &size); 8103b2aab18SMatthew Ahrens if (err != 0) 81119b94df9SMatthew Ahrens return (err); 81219b94df9SMatthew Ahrens } 81319b94df9SMatthew Ahrens 81419b94df9SMatthew Ahrens /* 81519b94df9SMatthew Ahrens * Assume that space (both on-disk and in-stream) is dominated by 81619b94df9SMatthew Ahrens * data. We will adjust for indirect blocks and the copies property, 81719b94df9SMatthew Ahrens * but ignore per-object space used (eg, dnodes and DRR_OBJECT records). 81819b94df9SMatthew Ahrens */ 81919b94df9SMatthew Ahrens 82019b94df9SMatthew Ahrens /* 82119b94df9SMatthew Ahrens * Subtract out approximate space used by indirect blocks. 82219b94df9SMatthew Ahrens * Assume most space is used by data blocks (non-indirect, non-dnode). 82319b94df9SMatthew Ahrens * Assume all blocks are recordsize. Assume ditto blocks and 82419b94df9SMatthew Ahrens * internal fragmentation counter out compression. 82519b94df9SMatthew Ahrens * 82619b94df9SMatthew Ahrens * Therefore, space used by indirect blocks is sizeof(blkptr_t) per 82719b94df9SMatthew Ahrens * block, which we observe in practice. 82819b94df9SMatthew Ahrens */ 82919b94df9SMatthew Ahrens uint64_t recordsize; 8303b2aab18SMatthew Ahrens err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize); 8313b2aab18SMatthew Ahrens if (err != 0) 83219b94df9SMatthew Ahrens return (err); 83319b94df9SMatthew Ahrens size -= size / recordsize * sizeof (blkptr_t); 83419b94df9SMatthew Ahrens 83519b94df9SMatthew Ahrens /* Add in the space for the record associated with each block. */ 83619b94df9SMatthew Ahrens size += size / recordsize * sizeof (dmu_replay_record_t); 83719b94df9SMatthew Ahrens 83819b94df9SMatthew Ahrens *sizep = size; 83919b94df9SMatthew Ahrens 84019b94df9SMatthew Ahrens return (0); 84119b94df9SMatthew Ahrens } 84219b94df9SMatthew Ahrens 8433b2aab18SMatthew Ahrens typedef struct dmu_recv_begin_arg { 8443b2aab18SMatthew Ahrens const char *drba_origin; 8453b2aab18SMatthew Ahrens dmu_recv_cookie_t *drba_cookie; 8463b2aab18SMatthew Ahrens cred_t *drba_cred; 84734f2f8cfSMatthew Ahrens uint64_t drba_snapobj; 8483b2aab18SMatthew Ahrens } dmu_recv_begin_arg_t; 849f18faf3fSek 850f18faf3fSek static int 8513b2aab18SMatthew Ahrens recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds, 8523b2aab18SMatthew Ahrens uint64_t fromguid) 853f18faf3fSek { 8543cb34c60Sahrens uint64_t val; 8553b2aab18SMatthew Ahrens int error; 8563b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 857f18faf3fSek 8583b2aab18SMatthew Ahrens /* temporary clone name must not exist */ 8593b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 8603b2aab18SMatthew Ahrens ds->ds_dir->dd_phys->dd_child_dir_zapobj, recv_clone_name, 8613b2aab18SMatthew Ahrens 8, 1, &val); 8623b2aab18SMatthew Ahrens if (error != ENOENT) 8633b2aab18SMatthew Ahrens return (error == 0 ? EBUSY : error); 8643b2aab18SMatthew Ahrens 865feaa74e4SMark Maybee /* new snapshot name must not exist */ 8663b2aab18SMatthew Ahrens error = zap_lookup(dp->dp_meta_objset, 8673b2aab18SMatthew Ahrens ds->ds_phys->ds_snapnames_zapobj, drba->drba_cookie->drc_tosnap, 8683b2aab18SMatthew Ahrens 8, 1, &val); 8693b2aab18SMatthew Ahrens if (error != ENOENT) 8703b2aab18SMatthew Ahrens return (error == 0 ? EEXIST : error); 871feaa74e4SMark Maybee 872a2afb611SJerry Jelinek /* 873a2afb611SJerry Jelinek * Check snapshot limit before receiving. We'll recheck again at the 874a2afb611SJerry Jelinek * end, but might as well abort before receiving if we're already over 875a2afb611SJerry Jelinek * the limit. 876a2afb611SJerry Jelinek * 877a2afb611SJerry Jelinek * Note that we do not check the file system limit with 878a2afb611SJerry Jelinek * dsl_dir_fscount_check because the temporary %clones don't count 879a2afb611SJerry Jelinek * against that limit. 880a2afb611SJerry Jelinek */ 881a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT, 882a2afb611SJerry Jelinek NULL, drba->drba_cred); 883a2afb611SJerry Jelinek if (error != 0) 884a2afb611SJerry Jelinek return (error); 885a2afb611SJerry Jelinek 8863b2aab18SMatthew Ahrens if (fromguid != 0) { 88734f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 88834f2f8cfSMatthew Ahrens uint64_t obj = ds->ds_phys->ds_prev_snap_obj; 88934f2f8cfSMatthew Ahrens 89034f2f8cfSMatthew Ahrens /* Find snapshot in this dir that matches fromguid. */ 89134f2f8cfSMatthew Ahrens while (obj != 0) { 89234f2f8cfSMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 89334f2f8cfSMatthew Ahrens &snap); 89434f2f8cfSMatthew Ahrens if (error != 0) 89534f2f8cfSMatthew Ahrens return (SET_ERROR(ENODEV)); 89634f2f8cfSMatthew Ahrens if (snap->ds_dir != ds->ds_dir) { 89734f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 89834f2f8cfSMatthew Ahrens return (SET_ERROR(ENODEV)); 89934f2f8cfSMatthew Ahrens } 90034f2f8cfSMatthew Ahrens if (snap->ds_phys->ds_guid == fromguid) 90134f2f8cfSMatthew Ahrens break; 90234f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 90334f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 90434f2f8cfSMatthew Ahrens } 90534f2f8cfSMatthew Ahrens if (obj == 0) 906be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 90792241e0bSTom Erickson 90834f2f8cfSMatthew Ahrens if (drba->drba_cookie->drc_force) { 90934f2f8cfSMatthew Ahrens drba->drba_snapobj = obj; 91034f2f8cfSMatthew Ahrens } else { 91134f2f8cfSMatthew Ahrens /* 91234f2f8cfSMatthew Ahrens * If we are not forcing, there must be no 91334f2f8cfSMatthew Ahrens * changes since fromsnap. 91434f2f8cfSMatthew Ahrens */ 91534f2f8cfSMatthew Ahrens if (dsl_dataset_modified_since_snap(ds, snap)) { 91692241e0bSTom Erickson dsl_dataset_rele(snap, FTAG); 91734f2f8cfSMatthew Ahrens return (SET_ERROR(ETXTBSY)); 91892241e0bSTom Erickson } 91934f2f8cfSMatthew Ahrens drba->drba_snapobj = ds->ds_prev->ds_object; 92092241e0bSTom Erickson } 92134f2f8cfSMatthew Ahrens 92234f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 923ae46e4c7SMatthew Ahrens } else { 924ae46e4c7SMatthew Ahrens /* if full, most recent snapshot must be $ORIGIN */ 925ae46e4c7SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_txg >= TXG_INITIAL) 926be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 92734f2f8cfSMatthew Ahrens drba->drba_snapobj = ds->ds_phys->ds_prev_snap_obj; 928ae46e4c7SMatthew Ahrens } 9293cb34c60Sahrens 9303cb34c60Sahrens return (0); 9313b2aab18SMatthew Ahrens 9323b2aab18SMatthew Ahrens } 9333b2aab18SMatthew Ahrens 9343b2aab18SMatthew Ahrens static int 9353b2aab18SMatthew Ahrens dmu_recv_begin_check(void *arg, dmu_tx_t *tx) 9363b2aab18SMatthew Ahrens { 9373b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 9383b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 9393b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 9403b2aab18SMatthew Ahrens uint64_t fromguid = drrb->drr_fromguid; 9413b2aab18SMatthew Ahrens int flags = drrb->drr_flags; 9423b2aab18SMatthew Ahrens int error; 9435d7b4d43SMatthew Ahrens uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo); 9443b2aab18SMatthew Ahrens dsl_dataset_t *ds; 9453b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 9463b2aab18SMatthew Ahrens 9473b2aab18SMatthew Ahrens /* already checked */ 9483b2aab18SMatthew Ahrens ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC); 9493b2aab18SMatthew Ahrens 9503b2aab18SMatthew Ahrens if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == 9513b2aab18SMatthew Ahrens DMU_COMPOUNDSTREAM || 9523b2aab18SMatthew Ahrens drrb->drr_type >= DMU_OST_NUMTYPES || 9533b2aab18SMatthew Ahrens ((flags & DRR_FLAG_CLONE) && drba->drba_origin == NULL)) 954be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 9553b2aab18SMatthew Ahrens 9563b2aab18SMatthew Ahrens /* Verify pool version supports SA if SA_SPILL feature set */ 9575d7b4d43SMatthew Ahrens if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) && 9585d7b4d43SMatthew Ahrens spa_version(dp->dp_spa) < SPA_VERSION_SA) 9595d7b4d43SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 9605d7b4d43SMatthew Ahrens 9615d7b4d43SMatthew Ahrens /* 9625d7b4d43SMatthew Ahrens * The receiving code doesn't know how to translate a WRITE_EMBEDDED 9635d7b4d43SMatthew Ahrens * record to a plan WRITE record, so the pool must have the 9645d7b4d43SMatthew Ahrens * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED 9655d7b4d43SMatthew Ahrens * records. Same with WRITE_EMBEDDED records that use LZ4 compression. 9665d7b4d43SMatthew Ahrens */ 9675d7b4d43SMatthew Ahrens if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) && 9685d7b4d43SMatthew Ahrens !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) 9695d7b4d43SMatthew Ahrens return (SET_ERROR(ENOTSUP)); 9705d7b4d43SMatthew Ahrens if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA_LZ4) && 9715d7b4d43SMatthew Ahrens !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) 972be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 9733b2aab18SMatthew Ahrens 9743b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 9753b2aab18SMatthew Ahrens if (error == 0) { 9763b2aab18SMatthew Ahrens /* target fs already exists; recv into temp clone */ 9773b2aab18SMatthew Ahrens 9783b2aab18SMatthew Ahrens /* Can't recv a clone into an existing fs */ 9793b2aab18SMatthew Ahrens if (flags & DRR_FLAG_CLONE) { 9803b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 981be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 9823b2aab18SMatthew Ahrens } 9833b2aab18SMatthew Ahrens 9843b2aab18SMatthew Ahrens error = recv_begin_check_existing_impl(drba, ds, fromguid); 9853b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9863b2aab18SMatthew Ahrens } else if (error == ENOENT) { 9873b2aab18SMatthew Ahrens /* target fs does not exist; must be a full backup or clone */ 9883b2aab18SMatthew Ahrens char buf[MAXNAMELEN]; 9893b2aab18SMatthew Ahrens 9903b2aab18SMatthew Ahrens /* 9913b2aab18SMatthew Ahrens * If it's a non-clone incremental, we are missing the 9923b2aab18SMatthew Ahrens * target fs, so fail the recv. 9933b2aab18SMatthew Ahrens */ 9943b2aab18SMatthew Ahrens if (fromguid != 0 && !(flags & DRR_FLAG_CLONE)) 995be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT)); 9963b2aab18SMatthew Ahrens 9973b2aab18SMatthew Ahrens /* Open the parent of tofs */ 9983b2aab18SMatthew Ahrens ASSERT3U(strlen(tofs), <, MAXNAMELEN); 9993b2aab18SMatthew Ahrens (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1); 10003b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, buf, FTAG, &ds); 10013b2aab18SMatthew Ahrens if (error != 0) 10023b2aab18SMatthew Ahrens return (error); 10033b2aab18SMatthew Ahrens 1004a2afb611SJerry Jelinek /* 1005a2afb611SJerry Jelinek * Check filesystem and snapshot limits before receiving. We'll 1006a2afb611SJerry Jelinek * recheck snapshot limits again at the end (we create the 1007a2afb611SJerry Jelinek * filesystems and increment those counts during begin_sync). 1008a2afb611SJerry Jelinek */ 1009a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, 1010a2afb611SJerry Jelinek ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred); 1011a2afb611SJerry Jelinek if (error != 0) { 1012a2afb611SJerry Jelinek dsl_dataset_rele(ds, FTAG); 1013a2afb611SJerry Jelinek return (error); 1014a2afb611SJerry Jelinek } 1015a2afb611SJerry Jelinek 1016a2afb611SJerry Jelinek error = dsl_fs_ss_limit_check(ds->ds_dir, 1, 1017a2afb611SJerry Jelinek ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred); 1018a2afb611SJerry Jelinek if (error != 0) { 1019a2afb611SJerry Jelinek dsl_dataset_rele(ds, FTAG); 1020a2afb611SJerry Jelinek return (error); 1021a2afb611SJerry Jelinek } 1022a2afb611SJerry Jelinek 10233b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 10243b2aab18SMatthew Ahrens dsl_dataset_t *origin; 10253b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drba->drba_origin, 10263b2aab18SMatthew Ahrens FTAG, &origin); 10273b2aab18SMatthew Ahrens if (error != 0) { 10283b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10293b2aab18SMatthew Ahrens return (error); 10303b2aab18SMatthew Ahrens } 10313b2aab18SMatthew Ahrens if (!dsl_dataset_is_snapshot(origin)) { 10323b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10333b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 1034be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 10353b2aab18SMatthew Ahrens } 10363b2aab18SMatthew Ahrens if (origin->ds_phys->ds_guid != fromguid) { 10373b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10383b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 1039be6fd75aSMatthew Ahrens return (SET_ERROR(ENODEV)); 10403b2aab18SMatthew Ahrens } 10413b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10423b2aab18SMatthew Ahrens } 10433b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10443b2aab18SMatthew Ahrens error = 0; 10453b2aab18SMatthew Ahrens } 10463b2aab18SMatthew Ahrens return (error); 1047f18faf3fSek } 1048f18faf3fSek 1049f18faf3fSek static void 10503b2aab18SMatthew Ahrens dmu_recv_begin_sync(void *arg, dmu_tx_t *tx) 1051f18faf3fSek { 10523b2aab18SMatthew Ahrens dmu_recv_begin_arg_t *drba = arg; 10533b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 10543b2aab18SMatthew Ahrens struct drr_begin *drrb = drba->drba_cookie->drc_drrb; 10553b2aab18SMatthew Ahrens const char *tofs = drba->drba_cookie->drc_tofs; 10563b2aab18SMatthew Ahrens dsl_dataset_t *ds, *newds; 1057f18faf3fSek uint64_t dsobj; 10583b2aab18SMatthew Ahrens int error; 10593b2aab18SMatthew Ahrens uint64_t crflags; 10603b2aab18SMatthew Ahrens 10613b2aab18SMatthew Ahrens crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ? 10623b2aab18SMatthew Ahrens DS_FLAG_CI_DATASET : 0; 1063f18faf3fSek 10643b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, tofs, FTAG, &ds); 10653b2aab18SMatthew Ahrens if (error == 0) { 10663b2aab18SMatthew Ahrens /* create temporary clone */ 106734f2f8cfSMatthew Ahrens dsl_dataset_t *snap = NULL; 106834f2f8cfSMatthew Ahrens if (drba->drba_snapobj != 0) { 106934f2f8cfSMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 107034f2f8cfSMatthew Ahrens drba->drba_snapobj, FTAG, &snap)); 107134f2f8cfSMatthew Ahrens } 10723b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name, 107334f2f8cfSMatthew Ahrens snap, crflags, drba->drba_cred, tx); 107434f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 10753b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10763b2aab18SMatthew Ahrens } else { 10773b2aab18SMatthew Ahrens dsl_dir_t *dd; 10783b2aab18SMatthew Ahrens const char *tail; 10793b2aab18SMatthew Ahrens dsl_dataset_t *origin = NULL; 10803b2aab18SMatthew Ahrens 10813b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold(dp, tofs, FTAG, &dd, &tail)); 10823b2aab18SMatthew Ahrens 10833b2aab18SMatthew Ahrens if (drba->drba_origin != NULL) { 10843b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drba->drba_origin, 10853b2aab18SMatthew Ahrens FTAG, &origin)); 10863b2aab18SMatthew Ahrens } 10873b2aab18SMatthew Ahrens 10883b2aab18SMatthew Ahrens /* Create new dataset. */ 10893b2aab18SMatthew Ahrens dsobj = dsl_dataset_create_sync(dd, 10903b2aab18SMatthew Ahrens strrchr(tofs, '/') + 1, 10913b2aab18SMatthew Ahrens origin, crflags, drba->drba_cred, tx); 10923b2aab18SMatthew Ahrens if (origin != NULL) 10933b2aab18SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 10943b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 10953b2aab18SMatthew Ahrens drba->drba_cookie->drc_newfs = B_TRUE; 10963b2aab18SMatthew Ahrens } 10973b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds)); 10983b2aab18SMatthew Ahrens 10993b2aab18SMatthew Ahrens dmu_buf_will_dirty(newds->ds_dbuf, tx); 11003b2aab18SMatthew Ahrens newds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 11013cb34c60Sahrens 1102ae46e4c7SMatthew Ahrens /* 1103ae46e4c7SMatthew Ahrens * If we actually created a non-clone, we need to create the 1104ae46e4c7SMatthew Ahrens * objset in our new dataset. 1105ae46e4c7SMatthew Ahrens */ 11063b2aab18SMatthew Ahrens if (BP_IS_HOLE(dsl_dataset_get_blkptr(newds))) { 1107ae46e4c7SMatthew Ahrens (void) dmu_objset_create_impl(dp->dp_spa, 11083b2aab18SMatthew Ahrens newds, dsl_dataset_get_blkptr(newds), drrb->drr_type, tx); 1109ae46e4c7SMatthew Ahrens } 1110ae46e4c7SMatthew Ahrens 11113b2aab18SMatthew Ahrens drba->drba_cookie->drc_ds = newds; 1112dc7cd546SMark Shellenbaum 11133b2aab18SMatthew Ahrens spa_history_log_internal_ds(newds, "receive", tx, ""); 1114dc7cd546SMark Shellenbaum } 1115dc7cd546SMark Shellenbaum 11163cb34c60Sahrens /* 11173cb34c60Sahrens * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin() 11183cb34c60Sahrens * succeeds; otherwise we will leak the holds on the datasets. 11193cb34c60Sahrens */ 11203cb34c60Sahrens int 11213b2aab18SMatthew Ahrens dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, 11223b2aab18SMatthew Ahrens boolean_t force, char *origin, dmu_recv_cookie_t *drc) 1123efb80947Sahrens { 11243b2aab18SMatthew Ahrens dmu_recv_begin_arg_t drba = { 0 }; 11253b2aab18SMatthew Ahrens dmu_replay_record_t *drr; 1126ab04eb8eStimh 11273cb34c60Sahrens bzero(drc, sizeof (dmu_recv_cookie_t)); 11283cb34c60Sahrens drc->drc_drrb = drrb; 11293cb34c60Sahrens drc->drc_tosnap = tosnap; 11303b2aab18SMatthew Ahrens drc->drc_tofs = tofs; 11313cb34c60Sahrens drc->drc_force = force; 1132a2afb611SJerry Jelinek drc->drc_cred = CRED(); 1133efb80947Sahrens 11343b2aab18SMatthew Ahrens if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) 11353b2aab18SMatthew Ahrens drc->drc_byteswap = B_TRUE; 11363b2aab18SMatthew Ahrens else if (drrb->drr_magic != DMU_BACKUP_MAGIC) 1137be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1138efb80947Sahrens 11393b2aab18SMatthew Ahrens drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP); 11403b2aab18SMatthew Ahrens drr->drr_type = DRR_BEGIN; 11413b2aab18SMatthew Ahrens drr->drr_u.drr_begin = *drc->drc_drrb; 11423b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 11433b2aab18SMatthew Ahrens fletcher_4_incremental_byteswap(drr, 11443b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 11453b2aab18SMatthew Ahrens } else { 11463b2aab18SMatthew Ahrens fletcher_4_incremental_native(drr, 11473b2aab18SMatthew Ahrens sizeof (dmu_replay_record_t), &drc->drc_cksum); 11483b2aab18SMatthew Ahrens } 11493b2aab18SMatthew Ahrens kmem_free(drr, sizeof (dmu_replay_record_t)); 1150dc7cd546SMark Shellenbaum 11513b2aab18SMatthew Ahrens if (drc->drc_byteswap) { 11523b2aab18SMatthew Ahrens drrb->drr_magic = BSWAP_64(drrb->drr_magic); 11533b2aab18SMatthew Ahrens drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo); 11543b2aab18SMatthew Ahrens drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time); 11553b2aab18SMatthew Ahrens drrb->drr_type = BSWAP_32(drrb->drr_type); 11563b2aab18SMatthew Ahrens drrb->drr_toguid = BSWAP_64(drrb->drr_toguid); 11573b2aab18SMatthew Ahrens drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid); 11583cb34c60Sahrens } 11593cb34c60Sahrens 11603b2aab18SMatthew Ahrens drba.drba_origin = origin; 11613b2aab18SMatthew Ahrens drba.drba_cookie = drc; 11623b2aab18SMatthew Ahrens drba.drba_cred = CRED(); 11633b2aab18SMatthew Ahrens 11643b2aab18SMatthew Ahrens return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync, 11657d46dc6cSMatthew Ahrens &drba, 5, ZFS_SPACE_CHECK_NORMAL)); 1166efb80947Sahrens } 1167efb80947Sahrens 11683cb34c60Sahrens struct restorearg { 11693cb34c60Sahrens int err; 11703b2aab18SMatthew Ahrens boolean_t byteswap; 11713cb34c60Sahrens vnode_t *vp; 11723cb34c60Sahrens char *buf; 11733cb34c60Sahrens uint64_t voff; 11743cb34c60Sahrens int bufsize; /* amount of memory allocated for buf */ 11753cb34c60Sahrens zio_cksum_t cksum; 1176c99e4bdcSChris Kirby avl_tree_t *guid_to_ds_map; 11773cb34c60Sahrens }; 11783cb34c60Sahrens 11799e69d7d0SLori Alt typedef struct guid_map_entry { 11809e69d7d0SLori Alt uint64_t guid; 11819e69d7d0SLori Alt dsl_dataset_t *gme_ds; 11829e69d7d0SLori Alt avl_node_t avlnode; 11839e69d7d0SLori Alt } guid_map_entry_t; 11849e69d7d0SLori Alt 11859e69d7d0SLori Alt static int 11869e69d7d0SLori Alt guid_compare(const void *arg1, const void *arg2) 11879e69d7d0SLori Alt { 11889e69d7d0SLori Alt const guid_map_entry_t *gmep1 = arg1; 11899e69d7d0SLori Alt const guid_map_entry_t *gmep2 = arg2; 11909e69d7d0SLori Alt 11919e69d7d0SLori Alt if (gmep1->guid < gmep2->guid) 11929e69d7d0SLori Alt return (-1); 11939e69d7d0SLori Alt else if (gmep1->guid > gmep2->guid) 11949e69d7d0SLori Alt return (1); 11959e69d7d0SLori Alt return (0); 11969e69d7d0SLori Alt } 11979e69d7d0SLori Alt 1198c99e4bdcSChris Kirby static void 1199c99e4bdcSChris Kirby free_guid_map_onexit(void *arg) 1200c99e4bdcSChris Kirby { 1201c99e4bdcSChris Kirby avl_tree_t *ca = arg; 1202c99e4bdcSChris Kirby void *cookie = NULL; 1203c99e4bdcSChris Kirby guid_map_entry_t *gmep; 1204c99e4bdcSChris Kirby 1205c99e4bdcSChris Kirby while ((gmep = avl_destroy_nodes(ca, &cookie)) != NULL) { 12063b2aab18SMatthew Ahrens dsl_dataset_long_rele(gmep->gme_ds, gmep); 1207de8d9cffSMatthew Ahrens dsl_dataset_rele(gmep->gme_ds, gmep); 1208c99e4bdcSChris Kirby kmem_free(gmep, sizeof (guid_map_entry_t)); 1209c99e4bdcSChris Kirby } 1210c99e4bdcSChris Kirby avl_destroy(ca); 1211c99e4bdcSChris Kirby kmem_free(ca, sizeof (avl_tree_t)); 1212c99e4bdcSChris Kirby } 1213c99e4bdcSChris Kirby 1214efb80947Sahrens static void * 1215*8a904709SMatthew Ahrens restore_read(struct restorearg *ra, int len, char *buf) 1216efb80947Sahrens { 12173cb34c60Sahrens int done = 0; 1218efb80947Sahrens 1219*8a904709SMatthew Ahrens if (buf == NULL) 1220*8a904709SMatthew Ahrens buf = ra->buf; 1221*8a904709SMatthew Ahrens 1222efb80947Sahrens /* some things will require 8-byte alignment, so everything must */ 1223fb09f5aaSMadhav Suresh ASSERT0(len % 8); 1224efb80947Sahrens 12253cb34c60Sahrens while (done < len) { 1226efb80947Sahrens ssize_t resid; 1227efb80947Sahrens 1228efb80947Sahrens ra->err = vn_rdwr(UIO_READ, ra->vp, 1229*8a904709SMatthew Ahrens buf + done, len - done, 1230efb80947Sahrens ra->voff, UIO_SYSSPACE, FAPPEND, 1231efb80947Sahrens RLIM64_INFINITY, CRED(), &resid); 1232efb80947Sahrens 12333cb34c60Sahrens if (resid == len - done) 1234be6fd75aSMatthew Ahrens ra->err = SET_ERROR(EINVAL); 12353cb34c60Sahrens ra->voff += len - done - resid; 12363cb34c60Sahrens done = len - resid; 12373b2aab18SMatthew Ahrens if (ra->err != 0) 1238efb80947Sahrens return (NULL); 1239efb80947Sahrens } 1240efb80947Sahrens 12413cb34c60Sahrens ASSERT3U(done, ==, len); 1242efb80947Sahrens if (ra->byteswap) 1243*8a904709SMatthew Ahrens fletcher_4_incremental_byteswap(buf, len, &ra->cksum); 1244efb80947Sahrens else 1245*8a904709SMatthew Ahrens fletcher_4_incremental_native(buf, len, &ra->cksum); 1246*8a904709SMatthew Ahrens return (buf); 1247efb80947Sahrens } 1248efb80947Sahrens 1249efb80947Sahrens static void 1250efb80947Sahrens backup_byteswap(dmu_replay_record_t *drr) 1251efb80947Sahrens { 1252efb80947Sahrens #define DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X)) 1253efb80947Sahrens #define DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X)) 1254efb80947Sahrens drr->drr_type = BSWAP_32(drr->drr_type); 12553cb34c60Sahrens drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen); 1256efb80947Sahrens switch (drr->drr_type) { 1257efb80947Sahrens case DRR_BEGIN: 1258efb80947Sahrens DO64(drr_begin.drr_magic); 12599e69d7d0SLori Alt DO64(drr_begin.drr_versioninfo); 1260efb80947Sahrens DO64(drr_begin.drr_creation_time); 1261efb80947Sahrens DO32(drr_begin.drr_type); 12623cb34c60Sahrens DO32(drr_begin.drr_flags); 1263efb80947Sahrens DO64(drr_begin.drr_toguid); 1264efb80947Sahrens DO64(drr_begin.drr_fromguid); 1265efb80947Sahrens break; 1266efb80947Sahrens case DRR_OBJECT: 1267efb80947Sahrens DO64(drr_object.drr_object); 1268efb80947Sahrens DO32(drr_object.drr_type); 1269efb80947Sahrens DO32(drr_object.drr_bonustype); 1270efb80947Sahrens DO32(drr_object.drr_blksz); 1271efb80947Sahrens DO32(drr_object.drr_bonuslen); 12729e69d7d0SLori Alt DO64(drr_object.drr_toguid); 1273efb80947Sahrens break; 1274efb80947Sahrens case DRR_FREEOBJECTS: 1275efb80947Sahrens DO64(drr_freeobjects.drr_firstobj); 1276efb80947Sahrens DO64(drr_freeobjects.drr_numobjs); 12779e69d7d0SLori Alt DO64(drr_freeobjects.drr_toguid); 1278efb80947Sahrens break; 1279efb80947Sahrens case DRR_WRITE: 1280efb80947Sahrens DO64(drr_write.drr_object); 1281efb80947Sahrens DO32(drr_write.drr_type); 1282efb80947Sahrens DO64(drr_write.drr_offset); 1283efb80947Sahrens DO64(drr_write.drr_length); 12849e69d7d0SLori Alt DO64(drr_write.drr_toguid); 12858e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[0]); 12868e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[1]); 12878e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[2]); 12888e714474SLori Alt DO64(drr_write.drr_key.ddk_cksum.zc_word[3]); 12898e714474SLori Alt DO64(drr_write.drr_key.ddk_prop); 12909e69d7d0SLori Alt break; 12919e69d7d0SLori Alt case DRR_WRITE_BYREF: 12929e69d7d0SLori Alt DO64(drr_write_byref.drr_object); 12939e69d7d0SLori Alt DO64(drr_write_byref.drr_offset); 12949e69d7d0SLori Alt DO64(drr_write_byref.drr_length); 12959e69d7d0SLori Alt DO64(drr_write_byref.drr_toguid); 12969e69d7d0SLori Alt DO64(drr_write_byref.drr_refguid); 12979e69d7d0SLori Alt DO64(drr_write_byref.drr_refobject); 12989e69d7d0SLori Alt DO64(drr_write_byref.drr_refoffset); 12998e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[0]); 13008e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[1]); 13018e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[2]); 13028e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[3]); 13038e714474SLori Alt DO64(drr_write_byref.drr_key.ddk_prop); 1304efb80947Sahrens break; 13055d7b4d43SMatthew Ahrens case DRR_WRITE_EMBEDDED: 13065d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_object); 13075d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_offset); 13085d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_length); 13095d7b4d43SMatthew Ahrens DO64(drr_write_embedded.drr_toguid); 13105d7b4d43SMatthew Ahrens DO32(drr_write_embedded.drr_lsize); 13115d7b4d43SMatthew Ahrens DO32(drr_write_embedded.drr_psize); 13125d7b4d43SMatthew Ahrens break; 1313efb80947Sahrens case DRR_FREE: 1314efb80947Sahrens DO64(drr_free.drr_object); 1315efb80947Sahrens DO64(drr_free.drr_offset); 1316efb80947Sahrens DO64(drr_free.drr_length); 13179e69d7d0SLori Alt DO64(drr_free.drr_toguid); 1318efb80947Sahrens break; 13190a586ceaSMark Shellenbaum case DRR_SPILL: 13200a586ceaSMark Shellenbaum DO64(drr_spill.drr_object); 13210a586ceaSMark Shellenbaum DO64(drr_spill.drr_length); 13220a586ceaSMark Shellenbaum DO64(drr_spill.drr_toguid); 13230a586ceaSMark Shellenbaum break; 1324efb80947Sahrens case DRR_END: 1325efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[0]); 1326efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[1]); 1327efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[2]); 1328efb80947Sahrens DO64(drr_end.drr_checksum.zc_word[3]); 13299e69d7d0SLori Alt DO64(drr_end.drr_toguid); 1330efb80947Sahrens break; 1331efb80947Sahrens } 1332efb80947Sahrens #undef DO64 1333efb80947Sahrens #undef DO32 1334efb80947Sahrens } 1335efb80947Sahrens 1336efb80947Sahrens static int 1337efb80947Sahrens restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) 1338efb80947Sahrens { 1339efb80947Sahrens int err; 1340efb80947Sahrens dmu_tx_t *tx; 1341adee0b6fSTim Haley void *data = NULL; 1342efb80947Sahrens 1343efb80947Sahrens if (drro->drr_type == DMU_OT_NONE || 1344ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_type) || 1345ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drro->drr_bonustype) || 13469e69d7d0SLori Alt drro->drr_checksumtype >= ZIO_CHECKSUM_FUNCTIONS || 1347efb80947Sahrens drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS || 1348efb80947Sahrens P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) || 1349efb80947Sahrens drro->drr_blksz < SPA_MINBLOCKSIZE || 1350efb80947Sahrens drro->drr_blksz > SPA_MAXBLOCKSIZE || 1351efb80947Sahrens drro->drr_bonuslen > DN_MAX_BONUSLEN) { 1352be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1353efb80947Sahrens } 1354efb80947Sahrens 13552bf405a2SMark Maybee err = dmu_object_info(os, drro->drr_object, NULL); 13562bf405a2SMark Maybee 13572bf405a2SMark Maybee if (err != 0 && err != ENOENT) 1358be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 13592bf405a2SMark Maybee 1360adee0b6fSTim Haley if (drro->drr_bonuslen) { 1361*8a904709SMatthew Ahrens data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8), NULL); 13623b2aab18SMatthew Ahrens if (ra->err != 0) 1363adee0b6fSTim Haley return (ra->err); 1364adee0b6fSTim Haley } 1365adee0b6fSTim Haley 1366efb80947Sahrens if (err == ENOENT) { 1367efb80947Sahrens /* currently free, want to be allocated */ 13682bf405a2SMark Maybee tx = dmu_tx_create(os); 1369efb80947Sahrens dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); 1370efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 13713b2aab18SMatthew Ahrens if (err != 0) { 1372efb80947Sahrens dmu_tx_abort(tx); 1373efb80947Sahrens return (err); 1374efb80947Sahrens } 1375efb80947Sahrens err = dmu_object_claim(os, drro->drr_object, 1376efb80947Sahrens drro->drr_type, drro->drr_blksz, 1377efb80947Sahrens drro->drr_bonustype, drro->drr_bonuslen, tx); 13782bf405a2SMark Maybee dmu_tx_commit(tx); 1379efb80947Sahrens } else { 1380efb80947Sahrens /* currently allocated, want to be allocated */ 1381efb80947Sahrens err = dmu_object_reclaim(os, drro->drr_object, 1382efb80947Sahrens drro->drr_type, drro->drr_blksz, 13832bf405a2SMark Maybee drro->drr_bonustype, drro->drr_bonuslen); 1384efb80947Sahrens } 13853b2aab18SMatthew Ahrens if (err != 0) { 1386be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 13870a586ceaSMark Shellenbaum } 13882bf405a2SMark Maybee 13892bf405a2SMark Maybee tx = dmu_tx_create(os); 13902bf405a2SMark Maybee dmu_tx_hold_bonus(tx, drro->drr_object); 13912bf405a2SMark Maybee err = dmu_tx_assign(tx, TXG_WAIT); 13923b2aab18SMatthew Ahrens if (err != 0) { 13932bf405a2SMark Maybee dmu_tx_abort(tx); 13942bf405a2SMark Maybee return (err); 1395efb80947Sahrens } 1396efb80947Sahrens 13979e69d7d0SLori Alt dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, 13989e69d7d0SLori Alt tx); 1399efb80947Sahrens dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); 1400efb80947Sahrens 1401adee0b6fSTim Haley if (data != NULL) { 1402efb80947Sahrens dmu_buf_t *db; 1403adee0b6fSTim Haley 1404efb80947Sahrens VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db)); 1405efb80947Sahrens dmu_buf_will_dirty(db, tx); 1406efb80947Sahrens 14071934e92fSmaybee ASSERT3U(db->db_size, >=, drro->drr_bonuslen); 14081934e92fSmaybee bcopy(data, db->db_data, drro->drr_bonuslen); 1409efb80947Sahrens if (ra->byteswap) { 1410ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1411ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drro->drr_bonustype); 1412ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(db->db_data, 1413efb80947Sahrens drro->drr_bonuslen); 1414efb80947Sahrens } 1415efb80947Sahrens dmu_buf_rele(db, FTAG); 1416efb80947Sahrens } 1417efb80947Sahrens dmu_tx_commit(tx); 1418efb80947Sahrens return (0); 1419efb80947Sahrens } 1420efb80947Sahrens 1421efb80947Sahrens /* ARGSUSED */ 1422efb80947Sahrens static int 1423efb80947Sahrens restore_freeobjects(struct restorearg *ra, objset_t *os, 1424efb80947Sahrens struct drr_freeobjects *drrfo) 1425efb80947Sahrens { 1426efb80947Sahrens uint64_t obj; 1427efb80947Sahrens 1428efb80947Sahrens if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj) 1429be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1430efb80947Sahrens 1431efb80947Sahrens for (obj = drrfo->drr_firstobj; 1432432f72fdSahrens obj < drrfo->drr_firstobj + drrfo->drr_numobjs; 1433432f72fdSahrens (void) dmu_object_next(os, &obj, FALSE, 0)) { 1434efb80947Sahrens int err; 1435efb80947Sahrens 1436efb80947Sahrens if (dmu_object_info(os, obj, NULL) != 0) 1437efb80947Sahrens continue; 1438efb80947Sahrens 1439713d6c20SMatthew Ahrens err = dmu_free_long_object(os, obj); 14403b2aab18SMatthew Ahrens if (err != 0) 1441efb80947Sahrens return (err); 1442efb80947Sahrens } 1443efb80947Sahrens return (0); 1444efb80947Sahrens } 1445efb80947Sahrens 1446efb80947Sahrens static int 1447efb80947Sahrens restore_write(struct restorearg *ra, objset_t *os, 1448efb80947Sahrens struct drr_write *drrw) 1449efb80947Sahrens { 1450efb80947Sahrens dmu_tx_t *tx; 1451efb80947Sahrens void *data; 1452efb80947Sahrens int err; 1453efb80947Sahrens 1454efb80947Sahrens if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset || 1455ad135b5dSChristopher Siden !DMU_OT_IS_VALID(drrw->drr_type)) 1456be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1457efb80947Sahrens 1458efb80947Sahrens if (dmu_object_info(os, drrw->drr_object, NULL) != 0) 1459be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1460efb80947Sahrens 1461*8a904709SMatthew Ahrens dmu_buf_t *bonus; 1462*8a904709SMatthew Ahrens if (dmu_bonus_hold(os, drrw->drr_object, FTAG, &bonus) != 0) 1463*8a904709SMatthew Ahrens return (SET_ERROR(EINVAL)); 1464*8a904709SMatthew Ahrens 1465*8a904709SMatthew Ahrens arc_buf_t *abuf = dmu_request_arcbuf(bonus, drrw->drr_length); 1466*8a904709SMatthew Ahrens 1467*8a904709SMatthew Ahrens data = restore_read(ra, drrw->drr_length, abuf->b_data); 1468*8a904709SMatthew Ahrens if (data == NULL) { 1469*8a904709SMatthew Ahrens dmu_return_arcbuf(abuf); 1470*8a904709SMatthew Ahrens dmu_buf_rele(bonus, FTAG); 1471*8a904709SMatthew Ahrens return (ra->err); 1472*8a904709SMatthew Ahrens } 1473*8a904709SMatthew Ahrens 1474efb80947Sahrens tx = dmu_tx_create(os); 1475efb80947Sahrens 1476efb80947Sahrens dmu_tx_hold_write(tx, drrw->drr_object, 1477efb80947Sahrens drrw->drr_offset, drrw->drr_length); 1478efb80947Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 14793b2aab18SMatthew Ahrens if (err != 0) { 1480*8a904709SMatthew Ahrens dmu_return_arcbuf(abuf); 1481*8a904709SMatthew Ahrens dmu_buf_rele(bonus, FTAG); 1482efb80947Sahrens dmu_tx_abort(tx); 1483efb80947Sahrens return (err); 1484efb80947Sahrens } 1485ad135b5dSChristopher Siden if (ra->byteswap) { 1486ad135b5dSChristopher Siden dmu_object_byteswap_t byteswap = 1487ad135b5dSChristopher Siden DMU_OT_BYTESWAP(drrw->drr_type); 1488ad135b5dSChristopher Siden dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length); 1489ad135b5dSChristopher Siden } 1490*8a904709SMatthew Ahrens dmu_assign_arcbuf(bonus, drrw->drr_offset, abuf, tx); 1491efb80947Sahrens dmu_tx_commit(tx); 1492*8a904709SMatthew Ahrens dmu_buf_rele(bonus, FTAG); 1493efb80947Sahrens return (0); 1494efb80947Sahrens } 1495efb80947Sahrens 14969e69d7d0SLori Alt /* 14979e69d7d0SLori Alt * Handle a DRR_WRITE_BYREF record. This record is used in dedup'ed 14989e69d7d0SLori Alt * streams to refer to a copy of the data that is already on the 14999e69d7d0SLori Alt * system because it came in earlier in the stream. This function 15009e69d7d0SLori Alt * finds the earlier copy of the data, and uses that copy instead of 15019e69d7d0SLori Alt * data from the stream to fulfill this write. 15029e69d7d0SLori Alt */ 15039e69d7d0SLori Alt static int 15049e69d7d0SLori Alt restore_write_byref(struct restorearg *ra, objset_t *os, 15059e69d7d0SLori Alt struct drr_write_byref *drrwbr) 15069e69d7d0SLori Alt { 15079e69d7d0SLori Alt dmu_tx_t *tx; 15089e69d7d0SLori Alt int err; 15099e69d7d0SLori Alt guid_map_entry_t gmesrch; 15109e69d7d0SLori Alt guid_map_entry_t *gmep; 15115d7b4d43SMatthew Ahrens avl_index_t where; 15129e69d7d0SLori Alt objset_t *ref_os = NULL; 15139e69d7d0SLori Alt dmu_buf_t *dbp; 15149e69d7d0SLori Alt 15159e69d7d0SLori Alt if (drrwbr->drr_offset + drrwbr->drr_length < drrwbr->drr_offset) 1516be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 15179e69d7d0SLori Alt 15189e69d7d0SLori Alt /* 15199e69d7d0SLori Alt * If the GUID of the referenced dataset is different from the 15209e69d7d0SLori Alt * GUID of the target dataset, find the referenced dataset. 15219e69d7d0SLori Alt */ 15229e69d7d0SLori Alt if (drrwbr->drr_toguid != drrwbr->drr_refguid) { 15239e69d7d0SLori Alt gmesrch.guid = drrwbr->drr_refguid; 1524c99e4bdcSChris Kirby if ((gmep = avl_find(ra->guid_to_ds_map, &gmesrch, 15259e69d7d0SLori Alt &where)) == NULL) { 1526be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 15279e69d7d0SLori Alt } 15289e69d7d0SLori Alt if (dmu_objset_from_ds(gmep->gme_ds, &ref_os)) 1529be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 15309e69d7d0SLori Alt } else { 15319e69d7d0SLori Alt ref_os = os; 15329e69d7d0SLori Alt } 15339e69d7d0SLori Alt 15345d7b4d43SMatthew Ahrens err = dmu_buf_hold(ref_os, drrwbr->drr_refobject, 15355d7b4d43SMatthew Ahrens drrwbr->drr_refoffset, FTAG, &dbp, DMU_READ_PREFETCH); 15365d7b4d43SMatthew Ahrens if (err != 0) 15379e69d7d0SLori Alt return (err); 15389e69d7d0SLori Alt 15399e69d7d0SLori Alt tx = dmu_tx_create(os); 15409e69d7d0SLori Alt 15419e69d7d0SLori Alt dmu_tx_hold_write(tx, drrwbr->drr_object, 15429e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length); 15439e69d7d0SLori Alt err = dmu_tx_assign(tx, TXG_WAIT); 15443b2aab18SMatthew Ahrens if (err != 0) { 15459e69d7d0SLori Alt dmu_tx_abort(tx); 15469e69d7d0SLori Alt return (err); 15479e69d7d0SLori Alt } 15489e69d7d0SLori Alt dmu_write(os, drrwbr->drr_object, 15499e69d7d0SLori Alt drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx); 15509e69d7d0SLori Alt dmu_buf_rele(dbp, FTAG); 15519e69d7d0SLori Alt dmu_tx_commit(tx); 15529e69d7d0SLori Alt return (0); 15539e69d7d0SLori Alt } 15549e69d7d0SLori Alt 15555d7b4d43SMatthew Ahrens static int 15565d7b4d43SMatthew Ahrens restore_write_embedded(struct restorearg *ra, objset_t *os, 15575d7b4d43SMatthew Ahrens struct drr_write_embedded *drrwnp) 15585d7b4d43SMatthew Ahrens { 15595d7b4d43SMatthew Ahrens dmu_tx_t *tx; 15605d7b4d43SMatthew Ahrens int err; 15615d7b4d43SMatthew Ahrens void *data; 15625d7b4d43SMatthew Ahrens 15635d7b4d43SMatthew Ahrens if (drrwnp->drr_offset + drrwnp->drr_length < drrwnp->drr_offset) 15645d7b4d43SMatthew Ahrens return (EINVAL); 15655d7b4d43SMatthew Ahrens 15665d7b4d43SMatthew Ahrens if (drrwnp->drr_psize > BPE_PAYLOAD_SIZE) 15675d7b4d43SMatthew Ahrens return (EINVAL); 15685d7b4d43SMatthew Ahrens 15695d7b4d43SMatthew Ahrens if (drrwnp->drr_etype >= NUM_BP_EMBEDDED_TYPES) 15705d7b4d43SMatthew Ahrens return (EINVAL); 15715d7b4d43SMatthew Ahrens if (drrwnp->drr_compression >= ZIO_COMPRESS_FUNCTIONS) 15725d7b4d43SMatthew Ahrens return (EINVAL); 15735d7b4d43SMatthew Ahrens 1574*8a904709SMatthew Ahrens data = restore_read(ra, P2ROUNDUP(drrwnp->drr_psize, 8), NULL); 15755d7b4d43SMatthew Ahrens if (data == NULL) 15765d7b4d43SMatthew Ahrens return (ra->err); 15775d7b4d43SMatthew Ahrens 15785d7b4d43SMatthew Ahrens tx = dmu_tx_create(os); 15795d7b4d43SMatthew Ahrens 15805d7b4d43SMatthew Ahrens dmu_tx_hold_write(tx, drrwnp->drr_object, 15815d7b4d43SMatthew Ahrens drrwnp->drr_offset, drrwnp->drr_length); 15825d7b4d43SMatthew Ahrens err = dmu_tx_assign(tx, TXG_WAIT); 15835d7b4d43SMatthew Ahrens if (err != 0) { 15845d7b4d43SMatthew Ahrens dmu_tx_abort(tx); 15855d7b4d43SMatthew Ahrens return (err); 15865d7b4d43SMatthew Ahrens } 15875d7b4d43SMatthew Ahrens 15885d7b4d43SMatthew Ahrens dmu_write_embedded(os, drrwnp->drr_object, 15895d7b4d43SMatthew Ahrens drrwnp->drr_offset, data, drrwnp->drr_etype, 15905d7b4d43SMatthew Ahrens drrwnp->drr_compression, drrwnp->drr_lsize, drrwnp->drr_psize, 15915d7b4d43SMatthew Ahrens ra->byteswap ^ ZFS_HOST_BYTEORDER, tx); 15925d7b4d43SMatthew Ahrens 15935d7b4d43SMatthew Ahrens dmu_tx_commit(tx); 15945d7b4d43SMatthew Ahrens return (0); 15955d7b4d43SMatthew Ahrens } 15965d7b4d43SMatthew Ahrens 15970a586ceaSMark Shellenbaum static int 15980a586ceaSMark Shellenbaum restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs) 15990a586ceaSMark Shellenbaum { 16000a586ceaSMark Shellenbaum dmu_tx_t *tx; 16010a586ceaSMark Shellenbaum void *data; 16020a586ceaSMark Shellenbaum dmu_buf_t *db, *db_spill; 16030a586ceaSMark Shellenbaum int err; 16040a586ceaSMark Shellenbaum 16050a586ceaSMark Shellenbaum if (drrs->drr_length < SPA_MINBLOCKSIZE || 16060a586ceaSMark Shellenbaum drrs->drr_length > SPA_MAXBLOCKSIZE) 1607be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 16080a586ceaSMark Shellenbaum 1609*8a904709SMatthew Ahrens data = restore_read(ra, drrs->drr_length, NULL); 16100a586ceaSMark Shellenbaum if (data == NULL) 16110a586ceaSMark Shellenbaum return (ra->err); 16120a586ceaSMark Shellenbaum 16130a586ceaSMark Shellenbaum if (dmu_object_info(os, drrs->drr_object, NULL) != 0) 1614be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 16150a586ceaSMark Shellenbaum 16160a586ceaSMark Shellenbaum VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db)); 16170a586ceaSMark Shellenbaum if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) { 16180a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 16190a586ceaSMark Shellenbaum return (err); 16200a586ceaSMark Shellenbaum } 16210a586ceaSMark Shellenbaum 16220a586ceaSMark Shellenbaum tx = dmu_tx_create(os); 16230a586ceaSMark Shellenbaum 16240a586ceaSMark Shellenbaum dmu_tx_hold_spill(tx, db->db_object); 16250a586ceaSMark Shellenbaum 16260a586ceaSMark Shellenbaum err = dmu_tx_assign(tx, TXG_WAIT); 16273b2aab18SMatthew Ahrens if (err != 0) { 16280a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 16290a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 16300a586ceaSMark Shellenbaum dmu_tx_abort(tx); 16310a586ceaSMark Shellenbaum return (err); 16320a586ceaSMark Shellenbaum } 16330a586ceaSMark Shellenbaum dmu_buf_will_dirty(db_spill, tx); 16340a586ceaSMark Shellenbaum 16350a586ceaSMark Shellenbaum if (db_spill->db_size < drrs->drr_length) 16360a586ceaSMark Shellenbaum VERIFY(0 == dbuf_spill_set_blksz(db_spill, 16370a586ceaSMark Shellenbaum drrs->drr_length, tx)); 16380a586ceaSMark Shellenbaum bcopy(data, db_spill->db_data, drrs->drr_length); 16390a586ceaSMark Shellenbaum 16400a586ceaSMark Shellenbaum dmu_buf_rele(db, FTAG); 16410a586ceaSMark Shellenbaum dmu_buf_rele(db_spill, FTAG); 16420a586ceaSMark Shellenbaum 16430a586ceaSMark Shellenbaum dmu_tx_commit(tx); 16440a586ceaSMark Shellenbaum return (0); 16450a586ceaSMark Shellenbaum } 16460a586ceaSMark Shellenbaum 1647efb80947Sahrens /* ARGSUSED */ 1648efb80947Sahrens static int 1649efb80947Sahrens restore_free(struct restorearg *ra, objset_t *os, 1650efb80947Sahrens struct drr_free *drrf) 1651efb80947Sahrens { 1652efb80947Sahrens int err; 1653efb80947Sahrens 1654efb80947Sahrens if (drrf->drr_length != -1ULL && 1655efb80947Sahrens drrf->drr_offset + drrf->drr_length < drrf->drr_offset) 1656be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1657efb80947Sahrens 1658efb80947Sahrens if (dmu_object_info(os, drrf->drr_object, NULL) != 0) 1659be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 1660efb80947Sahrens 1661cdb0ab79Smaybee err = dmu_free_long_range(os, drrf->drr_object, 1662efb80947Sahrens drrf->drr_offset, drrf->drr_length); 1663efb80947Sahrens return (err); 1664efb80947Sahrens } 1665efb80947Sahrens 16663b2aab18SMatthew Ahrens /* used to destroy the drc_ds on error */ 16673b2aab18SMatthew Ahrens static void 16683b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc) 16693b2aab18SMatthew Ahrens { 16703b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 16713b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 16723b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 16733b2aab18SMatthew Ahrens (void) dsl_destroy_head(name); 16743b2aab18SMatthew Ahrens } 16753b2aab18SMatthew Ahrens 16763cb34c60Sahrens /* 16773cb34c60Sahrens * NB: callers *must* call dmu_recv_end() if this succeeds. 16783cb34c60Sahrens */ 1679efb80947Sahrens int 1680c99e4bdcSChris Kirby dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp, 1681c99e4bdcSChris Kirby int cleanup_fd, uint64_t *action_handlep) 1682efb80947Sahrens { 16833cb34c60Sahrens struct restorearg ra = { 0 }; 1684efb80947Sahrens dmu_replay_record_t *drr; 16853cb34c60Sahrens objset_t *os; 16863cb34c60Sahrens zio_cksum_t pcksum; 16879e69d7d0SLori Alt int featureflags; 1688efb80947Sahrens 16893b2aab18SMatthew Ahrens ra.byteswap = drc->drc_byteswap; 16903b2aab18SMatthew Ahrens ra.cksum = drc->drc_cksum; 16913cb34c60Sahrens ra.vp = vp; 16923cb34c60Sahrens ra.voff = *voffp; 16933cb34c60Sahrens ra.bufsize = 1<<20; 16943cb34c60Sahrens ra.buf = kmem_alloc(ra.bufsize, KM_SLEEP); 1695efb80947Sahrens 16963cb34c60Sahrens /* these were verified in dmu_recv_begin */ 16973b2aab18SMatthew Ahrens ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==, 16989e69d7d0SLori Alt DMU_SUBSTREAM); 16993b2aab18SMatthew Ahrens ASSERT3U(drc->drc_drrb->drr_type, <, DMU_OST_NUMTYPES); 1700efb80947Sahrens 1701efb80947Sahrens /* 1702efb80947Sahrens * Open the objset we are modifying. 1703efb80947Sahrens */ 17043b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os)); 1705efb80947Sahrens 17063b2aab18SMatthew Ahrens ASSERT(drc->drc_ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT); 1707efb80947Sahrens 17089e69d7d0SLori Alt featureflags = DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo); 17099e69d7d0SLori Alt 17109e69d7d0SLori Alt /* if this stream is dedup'ed, set up the avl tree for guid mapping */ 17119e69d7d0SLori Alt if (featureflags & DMU_BACKUP_FEATURE_DEDUP) { 1712a7f53a56SChris Kirby minor_t minor; 1713a7f53a56SChris Kirby 1714c99e4bdcSChris Kirby if (cleanup_fd == -1) { 1715be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EBADF); 1716c99e4bdcSChris Kirby goto out; 1717c99e4bdcSChris Kirby } 1718a7f53a56SChris Kirby ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor); 17193b2aab18SMatthew Ahrens if (ra.err != 0) { 1720a7f53a56SChris Kirby cleanup_fd = -1; 1721a7f53a56SChris Kirby goto out; 1722a7f53a56SChris Kirby } 1723a7f53a56SChris Kirby 1724c99e4bdcSChris Kirby if (*action_handlep == 0) { 1725c99e4bdcSChris Kirby ra.guid_to_ds_map = 1726c99e4bdcSChris Kirby kmem_alloc(sizeof (avl_tree_t), KM_SLEEP); 1727c99e4bdcSChris Kirby avl_create(ra.guid_to_ds_map, guid_compare, 1728c99e4bdcSChris Kirby sizeof (guid_map_entry_t), 1729c99e4bdcSChris Kirby offsetof(guid_map_entry_t, avlnode)); 1730a7f53a56SChris Kirby ra.err = zfs_onexit_add_cb(minor, 1731c99e4bdcSChris Kirby free_guid_map_onexit, ra.guid_to_ds_map, 1732c99e4bdcSChris Kirby action_handlep); 17333b2aab18SMatthew Ahrens if (ra.err != 0) 1734c99e4bdcSChris Kirby goto out; 1735c99e4bdcSChris Kirby } else { 1736a7f53a56SChris Kirby ra.err = zfs_onexit_cb_data(minor, *action_handlep, 1737c99e4bdcSChris Kirby (void **)&ra.guid_to_ds_map); 17383b2aab18SMatthew Ahrens if (ra.err != 0) 1739c99e4bdcSChris Kirby goto out; 1740c99e4bdcSChris Kirby } 1741ec5cf9d5SAlexander Stetsenko 1742ec5cf9d5SAlexander Stetsenko drc->drc_guid_to_ds_map = ra.guid_to_ds_map; 17439e69d7d0SLori Alt } 17449e69d7d0SLori Alt 1745efb80947Sahrens /* 1746efb80947Sahrens * Read records and process them. 1747efb80947Sahrens */ 17483cb34c60Sahrens pcksum = ra.cksum; 1749efb80947Sahrens while (ra.err == 0 && 1750*8a904709SMatthew Ahrens NULL != (drr = restore_read(&ra, sizeof (*drr), NULL))) { 1751efb80947Sahrens if (issig(JUSTLOOKING) && issig(FORREAL)) { 1752be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EINTR); 1753efb80947Sahrens goto out; 1754efb80947Sahrens } 1755efb80947Sahrens 1756efb80947Sahrens if (ra.byteswap) 1757efb80947Sahrens backup_byteswap(drr); 1758efb80947Sahrens 1759efb80947Sahrens switch (drr->drr_type) { 1760efb80947Sahrens case DRR_OBJECT: 1761efb80947Sahrens { 1762efb80947Sahrens /* 1763efb80947Sahrens * We need to make a copy of the record header, 1764efb80947Sahrens * because restore_{object,write} may need to 1765efb80947Sahrens * restore_read(), which will invalidate drr. 1766efb80947Sahrens */ 1767efb80947Sahrens struct drr_object drro = drr->drr_u.drr_object; 1768efb80947Sahrens ra.err = restore_object(&ra, os, &drro); 1769efb80947Sahrens break; 1770efb80947Sahrens } 1771efb80947Sahrens case DRR_FREEOBJECTS: 1772efb80947Sahrens { 1773efb80947Sahrens struct drr_freeobjects drrfo = 1774efb80947Sahrens drr->drr_u.drr_freeobjects; 1775efb80947Sahrens ra.err = restore_freeobjects(&ra, os, &drrfo); 1776efb80947Sahrens break; 1777efb80947Sahrens } 1778efb80947Sahrens case DRR_WRITE: 1779efb80947Sahrens { 1780efb80947Sahrens struct drr_write drrw = drr->drr_u.drr_write; 1781efb80947Sahrens ra.err = restore_write(&ra, os, &drrw); 1782efb80947Sahrens break; 1783efb80947Sahrens } 17849e69d7d0SLori Alt case DRR_WRITE_BYREF: 17859e69d7d0SLori Alt { 17869e69d7d0SLori Alt struct drr_write_byref drrwbr = 17879e69d7d0SLori Alt drr->drr_u.drr_write_byref; 17889e69d7d0SLori Alt ra.err = restore_write_byref(&ra, os, &drrwbr); 17899e69d7d0SLori Alt break; 17909e69d7d0SLori Alt } 17915d7b4d43SMatthew Ahrens case DRR_WRITE_EMBEDDED: 17925d7b4d43SMatthew Ahrens { 17935d7b4d43SMatthew Ahrens struct drr_write_embedded drrwe = 17945d7b4d43SMatthew Ahrens drr->drr_u.drr_write_embedded; 17955d7b4d43SMatthew Ahrens ra.err = restore_write_embedded(&ra, os, &drrwe); 17965d7b4d43SMatthew Ahrens break; 17975d7b4d43SMatthew Ahrens } 1798efb80947Sahrens case DRR_FREE: 1799efb80947Sahrens { 1800efb80947Sahrens struct drr_free drrf = drr->drr_u.drr_free; 1801efb80947Sahrens ra.err = restore_free(&ra, os, &drrf); 1802efb80947Sahrens break; 1803efb80947Sahrens } 1804efb80947Sahrens case DRR_END: 1805efb80947Sahrens { 1806efb80947Sahrens struct drr_end drre = drr->drr_u.drr_end; 1807efb80947Sahrens /* 1808efb80947Sahrens * We compare against the *previous* checksum 1809efb80947Sahrens * value, because the stored checksum is of 1810efb80947Sahrens * everything before the DRR_END record. 1811efb80947Sahrens */ 1812137fa067Sahrens if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum)) 1813be6fd75aSMatthew Ahrens ra.err = SET_ERROR(ECKSUM); 1814efb80947Sahrens goto out; 1815efb80947Sahrens } 18160a586ceaSMark Shellenbaum case DRR_SPILL: 18170a586ceaSMark Shellenbaum { 18180a586ceaSMark Shellenbaum struct drr_spill drrs = drr->drr_u.drr_spill; 18190a586ceaSMark Shellenbaum ra.err = restore_spill(&ra, os, &drrs); 18200a586ceaSMark Shellenbaum break; 18210a586ceaSMark Shellenbaum } 1822efb80947Sahrens default: 1823be6fd75aSMatthew Ahrens ra.err = SET_ERROR(EINVAL); 1824efb80947Sahrens goto out; 1825efb80947Sahrens } 18263cb34c60Sahrens pcksum = ra.cksum; 1827efb80947Sahrens } 1828137fa067Sahrens ASSERT(ra.err != 0); 1829efb80947Sahrens 1830efb80947Sahrens out: 1831a7f53a56SChris Kirby if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1)) 1832a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 1833a7f53a56SChris Kirby 18343cb34c60Sahrens if (ra.err != 0) { 1835efb80947Sahrens /* 1836f4b94bdeSMatthew Ahrens * destroy what we created, so we don't leave it in the 1837f4b94bdeSMatthew Ahrens * inconsistent restoring state. 1838efb80947Sahrens */ 18393b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 1840efb80947Sahrens } 1841efb80947Sahrens 1842efb80947Sahrens kmem_free(ra.buf, ra.bufsize); 18433cb34c60Sahrens *voffp = ra.voff; 1844efb80947Sahrens return (ra.err); 1845efb80947Sahrens } 1846f18faf3fSek 18473cb34c60Sahrens static int 18483b2aab18SMatthew Ahrens dmu_recv_end_check(void *arg, dmu_tx_t *tx) 18493cb34c60Sahrens { 18503b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 18513b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 18523b2aab18SMatthew Ahrens int error; 18533b2aab18SMatthew Ahrens 18543b2aab18SMatthew Ahrens ASSERT3P(drc->drc_ds->ds_owner, ==, dmu_recv_tag); 18553cb34c60Sahrens 18563b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 18573b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 18583b2aab18SMatthew Ahrens 18593b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, drc->drc_tofs, FTAG, &origin_head); 18603b2aab18SMatthew Ahrens if (error != 0) 18613b2aab18SMatthew Ahrens return (error); 186234f2f8cfSMatthew Ahrens if (drc->drc_force) { 186334f2f8cfSMatthew Ahrens /* 186434f2f8cfSMatthew Ahrens * We will destroy any snapshots in tofs (i.e. before 186534f2f8cfSMatthew Ahrens * origin_head) that are after the origin (which is 186634f2f8cfSMatthew Ahrens * the snap before drc_ds, because drc_ds can not 186734f2f8cfSMatthew Ahrens * have any snaps of its own). 186834f2f8cfSMatthew Ahrens */ 186934f2f8cfSMatthew Ahrens uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 187034f2f8cfSMatthew Ahrens while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 187134f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 187234f2f8cfSMatthew Ahrens error = dsl_dataset_hold_obj(dp, obj, FTAG, 187334f2f8cfSMatthew Ahrens &snap); 187434f2f8cfSMatthew Ahrens if (error != 0) 187534f2f8cfSMatthew Ahrens return (error); 187634f2f8cfSMatthew Ahrens if (snap->ds_dir != origin_head->ds_dir) 187734f2f8cfSMatthew Ahrens error = SET_ERROR(EINVAL); 187834f2f8cfSMatthew Ahrens if (error == 0) { 187934f2f8cfSMatthew Ahrens error = dsl_destroy_snapshot_check_impl( 188034f2f8cfSMatthew Ahrens snap, B_FALSE); 188134f2f8cfSMatthew Ahrens } 188234f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 188334f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 188434f2f8cfSMatthew Ahrens if (error != 0) 188534f2f8cfSMatthew Ahrens return (error); 188634f2f8cfSMatthew Ahrens } 188734f2f8cfSMatthew Ahrens } 18883b2aab18SMatthew Ahrens error = dsl_dataset_clone_swap_check_impl(drc->drc_ds, 188991948b51SKeith M Wesolowski origin_head, drc->drc_force, drc->drc_owner, tx); 18903b2aab18SMatthew Ahrens if (error != 0) { 18913b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 18923b2aab18SMatthew Ahrens return (error); 18933b2aab18SMatthew Ahrens } 18943b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(origin_head, 1895a2afb611SJerry Jelinek drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); 18963b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 18973b2aab18SMatthew Ahrens if (error != 0) 18983b2aab18SMatthew Ahrens return (error); 18993b2aab18SMatthew Ahrens 19003b2aab18SMatthew Ahrens error = dsl_destroy_head_check_impl(drc->drc_ds, 1); 19013b2aab18SMatthew Ahrens } else { 19023b2aab18SMatthew Ahrens error = dsl_dataset_snapshot_check_impl(drc->drc_ds, 1903a2afb611SJerry Jelinek drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred); 19043b2aab18SMatthew Ahrens } 19053b2aab18SMatthew Ahrens return (error); 19063cb34c60Sahrens } 19073cb34c60Sahrens 19083cb34c60Sahrens static void 19093b2aab18SMatthew Ahrens dmu_recv_end_sync(void *arg, dmu_tx_t *tx) 19103cb34c60Sahrens { 19113b2aab18SMatthew Ahrens dmu_recv_cookie_t *drc = arg; 19123b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 19133b2aab18SMatthew Ahrens 19143b2aab18SMatthew Ahrens spa_history_log_internal_ds(drc->drc_ds, "finish receiving", 19153b2aab18SMatthew Ahrens tx, "snap=%s", drc->drc_tosnap); 19163b2aab18SMatthew Ahrens 19173b2aab18SMatthew Ahrens if (!drc->drc_newfs) { 19183b2aab18SMatthew Ahrens dsl_dataset_t *origin_head; 19193b2aab18SMatthew Ahrens 19203b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, drc->drc_tofs, FTAG, 19213b2aab18SMatthew Ahrens &origin_head)); 192234f2f8cfSMatthew Ahrens 192334f2f8cfSMatthew Ahrens if (drc->drc_force) { 192434f2f8cfSMatthew Ahrens /* 192534f2f8cfSMatthew Ahrens * Destroy any snapshots of drc_tofs (origin_head) 192634f2f8cfSMatthew Ahrens * after the origin (the snap before drc_ds). 192734f2f8cfSMatthew Ahrens */ 192834f2f8cfSMatthew Ahrens uint64_t obj = origin_head->ds_phys->ds_prev_snap_obj; 192934f2f8cfSMatthew Ahrens while (obj != drc->drc_ds->ds_phys->ds_prev_snap_obj) { 193034f2f8cfSMatthew Ahrens dsl_dataset_t *snap; 193134f2f8cfSMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, obj, FTAG, 193234f2f8cfSMatthew Ahrens &snap)); 193334f2f8cfSMatthew Ahrens ASSERT3P(snap->ds_dir, ==, origin_head->ds_dir); 193434f2f8cfSMatthew Ahrens obj = snap->ds_phys->ds_prev_snap_obj; 193534f2f8cfSMatthew Ahrens dsl_destroy_snapshot_sync_impl(snap, 193634f2f8cfSMatthew Ahrens B_FALSE, tx); 193734f2f8cfSMatthew Ahrens dsl_dataset_rele(snap, FTAG); 193834f2f8cfSMatthew Ahrens } 193934f2f8cfSMatthew Ahrens } 194034f2f8cfSMatthew Ahrens VERIFY3P(drc->drc_ds->ds_prev, ==, 194134f2f8cfSMatthew Ahrens origin_head->ds_prev); 194234f2f8cfSMatthew Ahrens 19433b2aab18SMatthew Ahrens dsl_dataset_clone_swap_sync_impl(drc->drc_ds, 19443b2aab18SMatthew Ahrens origin_head, tx); 19453b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(origin_head, 19463b2aab18SMatthew Ahrens drc->drc_tosnap, tx); 19473b2aab18SMatthew Ahrens 19483b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 19493b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_prev->ds_dbuf, tx); 19503b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_creation_time = 19513b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 19523b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_guid = 19533b2aab18SMatthew Ahrens drc->drc_drrb->drr_toguid; 19543b2aab18SMatthew Ahrens origin_head->ds_prev->ds_phys->ds_flags &= 19553b2aab18SMatthew Ahrens ~DS_FLAG_INCONSISTENT; 19563b2aab18SMatthew Ahrens 19573b2aab18SMatthew Ahrens dmu_buf_will_dirty(origin_head->ds_dbuf, tx); 19583b2aab18SMatthew Ahrens origin_head->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 19593b2aab18SMatthew Ahrens 19603b2aab18SMatthew Ahrens dsl_dataset_rele(origin_head, FTAG); 19613b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(drc->drc_ds, tx); 196291948b51SKeith M Wesolowski 196391948b51SKeith M Wesolowski if (drc->drc_owner != NULL) 196491948b51SKeith M Wesolowski VERIFY3P(origin_head->ds_owner, ==, drc->drc_owner); 19653b2aab18SMatthew Ahrens } else { 19663b2aab18SMatthew Ahrens dsl_dataset_t *ds = drc->drc_ds; 19673cb34c60Sahrens 19683b2aab18SMatthew Ahrens dsl_dataset_snapshot_sync_impl(ds, drc->drc_tosnap, tx); 19693cb34c60Sahrens 19703b2aab18SMatthew Ahrens /* set snapshot's creation time and guid */ 19713b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 19723b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_creation_time = 19733b2aab18SMatthew Ahrens drc->drc_drrb->drr_creation_time; 19743b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_guid = drc->drc_drrb->drr_toguid; 19753b2aab18SMatthew Ahrens ds->ds_prev->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 19763cb34c60Sahrens 19773b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 19783b2aab18SMatthew Ahrens ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT; 19793b2aab18SMatthew Ahrens } 19803b2aab18SMatthew Ahrens drc->drc_newsnapobj = drc->drc_ds->ds_phys->ds_prev_snap_obj; 19813b2aab18SMatthew Ahrens /* 19823b2aab18SMatthew Ahrens * Release the hold from dmu_recv_begin. This must be done before 19833b2aab18SMatthew Ahrens * we return to open context, so that when we free the dataset's dnode, 19843b2aab18SMatthew Ahrens * we can evict its bonus buffer. 19853b2aab18SMatthew Ahrens */ 19863b2aab18SMatthew Ahrens dsl_dataset_disown(drc->drc_ds, dmu_recv_tag); 19873b2aab18SMatthew Ahrens drc->drc_ds = NULL; 19883cb34c60Sahrens } 19893cb34c60Sahrens 1990ec5cf9d5SAlexander Stetsenko static int 19913b2aab18SMatthew Ahrens add_ds_to_guidmap(const char *name, avl_tree_t *guid_map, uint64_t snapobj) 1992ec5cf9d5SAlexander Stetsenko { 19933b2aab18SMatthew Ahrens dsl_pool_t *dp; 1994ec5cf9d5SAlexander Stetsenko dsl_dataset_t *snapds; 1995ec5cf9d5SAlexander Stetsenko guid_map_entry_t *gmep; 1996ec5cf9d5SAlexander Stetsenko int err; 1997ec5cf9d5SAlexander Stetsenko 1998ec5cf9d5SAlexander Stetsenko ASSERT(guid_map != NULL); 1999ec5cf9d5SAlexander Stetsenko 20003b2aab18SMatthew Ahrens err = dsl_pool_hold(name, FTAG, &dp); 20013b2aab18SMatthew Ahrens if (err != 0) 20023b2aab18SMatthew Ahrens return (err); 2003de8d9cffSMatthew Ahrens gmep = kmem_alloc(sizeof (*gmep), KM_SLEEP); 2004de8d9cffSMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, gmep, &snapds); 2005ec5cf9d5SAlexander Stetsenko if (err == 0) { 2006ec5cf9d5SAlexander Stetsenko gmep->guid = snapds->ds_phys->ds_guid; 2007ec5cf9d5SAlexander Stetsenko gmep->gme_ds = snapds; 2008ec5cf9d5SAlexander Stetsenko avl_add(guid_map, gmep); 20093b2aab18SMatthew Ahrens dsl_dataset_long_hold(snapds, gmep); 2010de8d9cffSMatthew Ahrens } else { 2011de8d9cffSMatthew Ahrens kmem_free(gmep, sizeof (*gmep)); 2012ec5cf9d5SAlexander Stetsenko } 2013ec5cf9d5SAlexander Stetsenko 20143b2aab18SMatthew Ahrens dsl_pool_rele(dp, FTAG); 2015ec5cf9d5SAlexander Stetsenko return (err); 2016ec5cf9d5SAlexander Stetsenko } 2017ec5cf9d5SAlexander Stetsenko 20183b2aab18SMatthew Ahrens static int dmu_recv_end_modified_blocks = 3; 20193b2aab18SMatthew Ahrens 2020ae46e4c7SMatthew Ahrens static int 2021ae46e4c7SMatthew Ahrens dmu_recv_existing_end(dmu_recv_cookie_t *drc) 2022f18faf3fSek { 20233b2aab18SMatthew Ahrens int error; 20243b2aab18SMatthew Ahrens char name[MAXNAMELEN]; 20253cb34c60Sahrens 20263b2aab18SMatthew Ahrens #ifdef _KERNEL 20273b2aab18SMatthew Ahrens /* 20283b2aab18SMatthew Ahrens * We will be destroying the ds; make sure its origin is unmounted if 20293b2aab18SMatthew Ahrens * necessary. 20303b2aab18SMatthew Ahrens */ 20313b2aab18SMatthew Ahrens dsl_dataset_name(drc->drc_ds, name); 20323b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(name); 20333b2aab18SMatthew Ahrens #endif 20343cb34c60Sahrens 20353b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 20363b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 20377d46dc6cSMatthew Ahrens dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL); 20383cb34c60Sahrens 20393b2aab18SMatthew Ahrens if (error != 0) 20403b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 20413b2aab18SMatthew Ahrens return (error); 2042f18faf3fSek } 2043ae46e4c7SMatthew Ahrens 2044ae46e4c7SMatthew Ahrens static int 2045ae46e4c7SMatthew Ahrens dmu_recv_new_end(dmu_recv_cookie_t *drc) 2046ae46e4c7SMatthew Ahrens { 20473b2aab18SMatthew Ahrens int error; 2048ae46e4c7SMatthew Ahrens 20493b2aab18SMatthew Ahrens error = dsl_sync_task(drc->drc_tofs, 20503b2aab18SMatthew Ahrens dmu_recv_end_check, dmu_recv_end_sync, drc, 20517d46dc6cSMatthew Ahrens dmu_recv_end_modified_blocks, ZFS_SPACE_CHECK_NORMAL); 2052ae46e4c7SMatthew Ahrens 20533b2aab18SMatthew Ahrens if (error != 0) { 20543b2aab18SMatthew Ahrens dmu_recv_cleanup_ds(drc); 20553b2aab18SMatthew Ahrens } else if (drc->drc_guid_to_ds_map != NULL) { 20563b2aab18SMatthew Ahrens (void) add_ds_to_guidmap(drc->drc_tofs, 20573b2aab18SMatthew Ahrens drc->drc_guid_to_ds_map, 20583b2aab18SMatthew Ahrens drc->drc_newsnapobj); 2059ae46e4c7SMatthew Ahrens } 20603b2aab18SMatthew Ahrens return (error); 2061ae46e4c7SMatthew Ahrens } 2062ae46e4c7SMatthew Ahrens 2063ae46e4c7SMatthew Ahrens int 206491948b51SKeith M Wesolowski dmu_recv_end(dmu_recv_cookie_t *drc, void *owner) 2065ae46e4c7SMatthew Ahrens { 206691948b51SKeith M Wesolowski drc->drc_owner = owner; 206791948b51SKeith M Wesolowski 20683b2aab18SMatthew Ahrens if (drc->drc_newfs) 2069ae46e4c7SMatthew Ahrens return (dmu_recv_new_end(drc)); 20703b2aab18SMatthew Ahrens else 20713b2aab18SMatthew Ahrens return (dmu_recv_existing_end(drc)); 2072ae46e4c7SMatthew Ahrens } 20732f3d8780SMatthew Ahrens 20742f3d8780SMatthew Ahrens /* 20752f3d8780SMatthew Ahrens * Return TRUE if this objset is currently being received into. 20762f3d8780SMatthew Ahrens */ 20772f3d8780SMatthew Ahrens boolean_t 20782f3d8780SMatthew Ahrens dmu_objset_is_receiving(objset_t *os) 20792f3d8780SMatthew Ahrens { 20802f3d8780SMatthew Ahrens return (os->os_dsl_dataset != NULL && 20812f3d8780SMatthew Ahrens os->os_dsl_dataset->ds_owner == dmu_recv_tag); 20822f3d8780SMatthew Ahrens } 2083