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