The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/zfs/dmu_diff.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 066cacbf43a55169e9f65f2f25f9d8be


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.