1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy /* 22eda14cbcSMatt Macy * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23eda14cbcSMatt Macy * Copyright (c) 2012, 2018 by Delphix. All rights reserved. 24eda14cbcSMatt Macy * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>. All rights reserved. 25eda14cbcSMatt Macy */ 26eda14cbcSMatt Macy 27eda14cbcSMatt Macy #include <sys/dmu.h> 28eda14cbcSMatt Macy #include <sys/dmu_impl.h> 29eda14cbcSMatt Macy #include <sys/dmu_tx.h> 30eda14cbcSMatt Macy #include <sys/dbuf.h> 31eda14cbcSMatt Macy #include <sys/dnode.h> 32eda14cbcSMatt Macy #include <sys/zfs_context.h> 33eda14cbcSMatt Macy #include <sys/dmu_objset.h> 34eda14cbcSMatt Macy #include <sys/dmu_traverse.h> 35eda14cbcSMatt Macy #include <sys/dsl_dataset.h> 36eda14cbcSMatt Macy #include <sys/dsl_dir.h> 37eda14cbcSMatt Macy #include <sys/dsl_pool.h> 38eda14cbcSMatt Macy #include <sys/dsl_synctask.h> 39eda14cbcSMatt Macy #include <sys/zfs_ioctl.h> 40eda14cbcSMatt Macy #include <sys/zap.h> 41eda14cbcSMatt Macy #include <sys/zio_checksum.h> 42eda14cbcSMatt Macy #include <sys/zfs_znode.h> 43eda14cbcSMatt Macy #include <sys/zfs_file.h> 44eda14cbcSMatt Macy 45eda14cbcSMatt Macy 46eda14cbcSMatt Macy typedef struct dmu_diffarg { 47eda14cbcSMatt Macy zfs_file_t *da_fp; /* file to which we are reporting */ 48eda14cbcSMatt Macy offset_t *da_offp; 49eda14cbcSMatt Macy int da_err; /* error that stopped diff search */ 50eda14cbcSMatt Macy dmu_diff_record_t da_ddr; 51eda14cbcSMatt Macy } dmu_diffarg_t; 52eda14cbcSMatt Macy 53eda14cbcSMatt Macy static int 54eda14cbcSMatt Macy write_record(dmu_diffarg_t *da) 55eda14cbcSMatt Macy { 56eda14cbcSMatt Macy zfs_file_t *fp; 57eda14cbcSMatt Macy ssize_t resid; 58eda14cbcSMatt Macy 59eda14cbcSMatt Macy if (da->da_ddr.ddr_type == DDR_NONE) { 60eda14cbcSMatt Macy da->da_err = 0; 61eda14cbcSMatt Macy return (0); 62eda14cbcSMatt Macy } 63eda14cbcSMatt Macy 64eda14cbcSMatt Macy fp = da->da_fp; 65eda14cbcSMatt Macy da->da_err = zfs_file_write(fp, (caddr_t)&da->da_ddr, 66eda14cbcSMatt Macy sizeof (da->da_ddr), &resid); 67eda14cbcSMatt Macy *da->da_offp += sizeof (da->da_ddr); 68eda14cbcSMatt Macy return (da->da_err); 69eda14cbcSMatt Macy } 70eda14cbcSMatt Macy 71eda14cbcSMatt Macy static int 72eda14cbcSMatt Macy report_free_dnode_range(dmu_diffarg_t *da, uint64_t first, uint64_t last) 73eda14cbcSMatt Macy { 74eda14cbcSMatt Macy ASSERT(first <= last); 75eda14cbcSMatt Macy if (da->da_ddr.ddr_type != DDR_FREE || 76eda14cbcSMatt Macy first != da->da_ddr.ddr_last + 1) { 77eda14cbcSMatt Macy if (write_record(da) != 0) 78eda14cbcSMatt Macy return (da->da_err); 79eda14cbcSMatt Macy da->da_ddr.ddr_type = DDR_FREE; 80eda14cbcSMatt Macy da->da_ddr.ddr_first = first; 81eda14cbcSMatt Macy da->da_ddr.ddr_last = last; 82eda14cbcSMatt Macy return (0); 83eda14cbcSMatt Macy } 84eda14cbcSMatt Macy da->da_ddr.ddr_last = last; 85eda14cbcSMatt Macy return (0); 86eda14cbcSMatt Macy } 87eda14cbcSMatt Macy 88eda14cbcSMatt Macy static int 89eda14cbcSMatt Macy report_dnode(dmu_diffarg_t *da, uint64_t object, dnode_phys_t *dnp) 90eda14cbcSMatt Macy { 91eda14cbcSMatt Macy ASSERT(dnp != NULL); 92eda14cbcSMatt Macy if (dnp->dn_type == DMU_OT_NONE) 93eda14cbcSMatt Macy return (report_free_dnode_range(da, object, object)); 94eda14cbcSMatt Macy 95eda14cbcSMatt Macy if (da->da_ddr.ddr_type != DDR_INUSE || 96eda14cbcSMatt Macy object != da->da_ddr.ddr_last + 1) { 97eda14cbcSMatt Macy if (write_record(da) != 0) 98eda14cbcSMatt Macy return (da->da_err); 99eda14cbcSMatt Macy da->da_ddr.ddr_type = DDR_INUSE; 100eda14cbcSMatt Macy da->da_ddr.ddr_first = da->da_ddr.ddr_last = object; 101eda14cbcSMatt Macy return (0); 102eda14cbcSMatt Macy } 103eda14cbcSMatt Macy da->da_ddr.ddr_last = object; 104eda14cbcSMatt Macy return (0); 105eda14cbcSMatt Macy } 106eda14cbcSMatt Macy 107eda14cbcSMatt Macy #define DBP_SPAN(dnp, level) \ 108eda14cbcSMatt Macy (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \ 109eda14cbcSMatt Macy (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) 110eda14cbcSMatt Macy 111eda14cbcSMatt Macy static int 112eda14cbcSMatt Macy diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 113eda14cbcSMatt Macy const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 114eda14cbcSMatt Macy { 115e92ffd9bSMartin Matuska (void) zilog; 116eda14cbcSMatt Macy dmu_diffarg_t *da = arg; 117eda14cbcSMatt Macy int err = 0; 118eda14cbcSMatt Macy 119*aca928a5SMartin Matuska if (issig()) 120eda14cbcSMatt Macy return (SET_ERROR(EINTR)); 121eda14cbcSMatt Macy 122eda14cbcSMatt Macy if (zb->zb_level == ZB_DNODE_LEVEL || 123eda14cbcSMatt Macy zb->zb_object != DMU_META_DNODE_OBJECT) 124eda14cbcSMatt Macy return (0); 125eda14cbcSMatt Macy 126eda14cbcSMatt Macy if (BP_IS_HOLE(bp)) { 127eda14cbcSMatt Macy uint64_t span = DBP_SPAN(dnp, zb->zb_level); 128eda14cbcSMatt Macy uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT; 129eda14cbcSMatt Macy 130eda14cbcSMatt Macy err = report_free_dnode_range(da, dnobj, 131eda14cbcSMatt Macy dnobj + (span >> DNODE_SHIFT) - 1); 132eda14cbcSMatt Macy if (err) 133eda14cbcSMatt Macy return (err); 134eda14cbcSMatt Macy } else if (zb->zb_level == 0) { 135eda14cbcSMatt Macy dnode_phys_t *blk; 136eda14cbcSMatt Macy arc_buf_t *abuf; 137eda14cbcSMatt Macy arc_flags_t aflags = ARC_FLAG_WAIT; 138eda14cbcSMatt Macy int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT; 139eda14cbcSMatt Macy int zio_flags = ZIO_FLAG_CANFAIL; 140eda14cbcSMatt Macy int i; 141eda14cbcSMatt Macy 142eda14cbcSMatt Macy if (BP_IS_PROTECTED(bp)) 143eda14cbcSMatt Macy zio_flags |= ZIO_FLAG_RAW; 144eda14cbcSMatt Macy 145eda14cbcSMatt Macy if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf, 146eda14cbcSMatt Macy ZIO_PRIORITY_ASYNC_READ, zio_flags, &aflags, zb) != 0) 147eda14cbcSMatt Macy return (SET_ERROR(EIO)); 148eda14cbcSMatt Macy 149eda14cbcSMatt Macy blk = abuf->b_data; 150eda14cbcSMatt Macy for (i = 0; i < epb; i += blk[i].dn_extra_slots + 1) { 151eda14cbcSMatt Macy uint64_t dnobj = (zb->zb_blkid << 152eda14cbcSMatt Macy (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; 153eda14cbcSMatt Macy err = report_dnode(da, dnobj, blk+i); 154eda14cbcSMatt Macy if (err) 155eda14cbcSMatt Macy break; 156eda14cbcSMatt Macy } 157eda14cbcSMatt Macy arc_buf_destroy(abuf, &abuf); 158eda14cbcSMatt Macy if (err) 159eda14cbcSMatt Macy return (err); 160eda14cbcSMatt Macy /* Don't care about the data blocks */ 161eda14cbcSMatt Macy return (TRAVERSE_VISIT_NO_CHILDREN); 162eda14cbcSMatt Macy } 163eda14cbcSMatt Macy return (0); 164eda14cbcSMatt Macy } 165eda14cbcSMatt Macy 166eda14cbcSMatt Macy int 167eda14cbcSMatt Macy dmu_diff(const char *tosnap_name, const char *fromsnap_name, 168eda14cbcSMatt Macy zfs_file_t *fp, offset_t *offp) 169eda14cbcSMatt Macy { 170eda14cbcSMatt Macy dmu_diffarg_t da; 171eda14cbcSMatt Macy dsl_dataset_t *fromsnap; 172eda14cbcSMatt Macy dsl_dataset_t *tosnap; 173eda14cbcSMatt Macy dsl_pool_t *dp; 174eda14cbcSMatt Macy int error; 175eda14cbcSMatt Macy uint64_t fromtxg; 176eda14cbcSMatt Macy 177eda14cbcSMatt Macy if (strchr(tosnap_name, '@') == NULL || 178eda14cbcSMatt Macy strchr(fromsnap_name, '@') == NULL) 179eda14cbcSMatt Macy return (SET_ERROR(EINVAL)); 180eda14cbcSMatt Macy 181eda14cbcSMatt Macy error = dsl_pool_hold(tosnap_name, FTAG, &dp); 182eda14cbcSMatt Macy if (error != 0) 183eda14cbcSMatt Macy return (error); 184eda14cbcSMatt Macy 185eda14cbcSMatt Macy error = dsl_dataset_hold(dp, tosnap_name, FTAG, &tosnap); 186eda14cbcSMatt Macy if (error != 0) { 187eda14cbcSMatt Macy dsl_pool_rele(dp, FTAG); 188eda14cbcSMatt Macy return (error); 189eda14cbcSMatt Macy } 190eda14cbcSMatt Macy 191eda14cbcSMatt Macy error = dsl_dataset_hold(dp, fromsnap_name, FTAG, &fromsnap); 192eda14cbcSMatt Macy if (error != 0) { 193eda14cbcSMatt Macy dsl_dataset_rele(tosnap, FTAG); 194eda14cbcSMatt Macy dsl_pool_rele(dp, FTAG); 195eda14cbcSMatt Macy return (error); 196eda14cbcSMatt Macy } 197eda14cbcSMatt Macy 198eda14cbcSMatt Macy if (!dsl_dataset_is_before(tosnap, fromsnap, 0)) { 199eda14cbcSMatt Macy dsl_dataset_rele(fromsnap, FTAG); 200eda14cbcSMatt Macy dsl_dataset_rele(tosnap, FTAG); 201eda14cbcSMatt Macy dsl_pool_rele(dp, FTAG); 202eda14cbcSMatt Macy return (SET_ERROR(EXDEV)); 203eda14cbcSMatt Macy } 204eda14cbcSMatt Macy 205eda14cbcSMatt Macy fromtxg = dsl_dataset_phys(fromsnap)->ds_creation_txg; 206eda14cbcSMatt Macy dsl_dataset_rele(fromsnap, FTAG); 207eda14cbcSMatt Macy 208eda14cbcSMatt Macy dsl_dataset_long_hold(tosnap, FTAG); 209eda14cbcSMatt Macy dsl_pool_rele(dp, FTAG); 210eda14cbcSMatt Macy 211eda14cbcSMatt Macy da.da_fp = fp; 212eda14cbcSMatt Macy da.da_offp = offp; 213eda14cbcSMatt Macy da.da_ddr.ddr_type = DDR_NONE; 214eda14cbcSMatt Macy da.da_ddr.ddr_first = da.da_ddr.ddr_last = 0; 215eda14cbcSMatt Macy da.da_err = 0; 216eda14cbcSMatt Macy 217eda14cbcSMatt Macy /* 218eda14cbcSMatt Macy * Since zfs diff only looks at dnodes which are stored in plaintext 219eda14cbcSMatt Macy * (other than bonus buffers), we don't technically need to decrypt 220eda14cbcSMatt Macy * the dataset to perform this operation. However, the command line 221eda14cbcSMatt Macy * utility will still fail if the keys are not loaded because the 222eda14cbcSMatt Macy * dataset isn't mounted and because it will fail when it attempts to 223eda14cbcSMatt Macy * call the ZFS_IOC_OBJ_TO_STATS ioctl. 224eda14cbcSMatt Macy */ 225eda14cbcSMatt Macy error = traverse_dataset(tosnap, fromtxg, 226eda14cbcSMatt Macy TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_NO_DECRYPT, 227eda14cbcSMatt Macy diff_cb, &da); 228eda14cbcSMatt Macy 229eda14cbcSMatt Macy if (error != 0) { 230eda14cbcSMatt Macy da.da_err = error; 231eda14cbcSMatt Macy } else { 232eda14cbcSMatt Macy /* we set the da.da_err we return as side-effect */ 233eda14cbcSMatt Macy (void) write_record(&da); 234eda14cbcSMatt Macy } 235eda14cbcSMatt Macy 236eda14cbcSMatt Macy dsl_dataset_long_rele(tosnap, FTAG); 237eda14cbcSMatt Macy dsl_dataset_rele(tosnap, FTAG); 238eda14cbcSMatt Macy 239eda14cbcSMatt Macy return (da.da_err); 240eda14cbcSMatt Macy } 241