Author: mav
Date: Mon Jun  3 20:49:20 2019
New Revision: 348584
URL: https://svnweb.freebsd.org/changeset/base/348584

Log:
  MFV r348583: 9847 leaking dd_clones (DMU_OT_DSL_CLONES) objects
  
  illumos/illumos-gate@17fb938fd6cdce3ff1bb47dafda0774f742249a3
  
  Reviewed by: George Wilson <george.wil...@delphix.com>
  Reviewed by: Serapheim Dimitropoulos <seraph...@delphix.com>
  Reviewed by: Brian Behlendorf <behlendo...@llnl.gov>
  Approved by: Richard Lowe <richl...@richlowe.net>
  Author:     Matthew Ahrens <mahr...@delphix.com>

Modified:
  head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_indirect_mapping.c
Directory Properties:
  head/cddl/contrib/opensolaris/   (props changed)
  head/sys/cddl/contrib/opensolaris/   (props changed)

Modified: head/cddl/contrib/opensolaris/cmd/zdb/zdb.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zdb/zdb.c Mon Jun  3 20:45:48 2019        
(r348583)
+++ head/cddl/contrib/opensolaris/cmd/zdb/zdb.c Mon Jun  3 20:49:20 2019        
(r348584)
@@ -63,6 +63,7 @@
 #include <sys/zfeature.h>
 #include <sys/abd.h>
 #include <sys/blkptr.h>
+#include <sys/dsl_scan.h>
 #include <zfs_comutil.h>
 #include <libcmdutils.h>
 #undef verify
@@ -111,6 +112,7 @@ static uint64_t max_inflight = 1000;
 static int leaked_objects = 0;
 
 static void snprintf_blkptr_compact(char *, size_t, const blkptr_t *);
+static void mos_obj_refd(uint64_t);
 
 /*
  * These libumem hooks provide a reasonable set of defaults for the allocator's
@@ -1592,6 +1594,8 @@ dump_dsl_dir(objset_t *os, uint64_t object, void *data
        DO(CHILD_RSRV);
        DO(REFRSRV);
 #undef DO
+       (void) printf("\t\tclones = %llu\n",
+           (u_longlong_t)dd->dd_clones);
 }
 
 /*ARGSUSED*/
@@ -1774,6 +1778,33 @@ dump_full_bpobj(bpobj_t *bpo, const char *name, int in
 }
 
 static void
+bpobj_count_refd(bpobj_t *bpo)
+{
+       mos_obj_refd(bpo->bpo_object);
+
+       if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
+               mos_obj_refd(bpo->bpo_phys->bpo_subobjs);
+               for (uint64_t i = 0; i < bpo->bpo_phys->bpo_num_subobjs; i++) {
+                       uint64_t subobj;
+                       bpobj_t subbpo;
+                       int error;
+                       VERIFY0(dmu_read(bpo->bpo_os,
+                           bpo->bpo_phys->bpo_subobjs,
+                           i * sizeof (subobj), sizeof (subobj), &subobj, 0));
+                       error = bpobj_open(&subbpo, bpo->bpo_os, subobj);
+                       if (error != 0) {
+                               (void) printf("ERROR %u while trying to open "
+                                   "subobj id %llu\n",
+                                   error, (u_longlong_t)subobj);
+                               continue;
+                       }
+                       bpobj_count_refd(&subbpo);
+                       bpobj_close(&subbpo);
+               }
+       }
+}
+
+static void
 dump_deadlist(dsl_deadlist_t *dl)
 {
        dsl_deadlist_entry_t *dle;
@@ -1781,7 +1812,24 @@ dump_deadlist(dsl_deadlist_t *dl)
        char bytes[32];
        char comp[32];
        char uncomp[32];
+       uint64_t empty_bpobj =
+           dmu_objset_spa(dl->dl_os)->spa_dsl_pool->dp_empty_bpobj;
 
+       /* force the tree to be loaded */
+       dsl_deadlist_space_range(dl, 0, UINT64_MAX, &unused, &unused, &unused);
+
+       if (dl->dl_oldfmt) {
+               if (dl->dl_bpobj.bpo_object != empty_bpobj)
+                       bpobj_count_refd(&dl->dl_bpobj);
+       } else {
+               mos_obj_refd(dl->dl_object);
+               for (dle = avl_first(&dl->dl_tree); dle;
+                   dle = AVL_NEXT(&dl->dl_tree, dle)) {
+                       if (dle->dle_bpobj.bpo_object != empty_bpobj)
+                               bpobj_count_refd(&dle->dle_bpobj);
+               }
+       }
+
        /* make sure nicenum has enough space */
        CTASSERT(sizeof (bytes) >= NN_NUMBUF_SZ);
        CTASSERT(sizeof (comp) >= NN_NUMBUF_SZ);
@@ -1806,9 +1854,6 @@ dump_deadlist(dsl_deadlist_t *dl)
 
        (void) printf("\n");
 
-       /* force the tree to be loaded */
-       dsl_deadlist_space_range(dl, 0, UINT64_MAX, &unused, &unused, &unused);
-
        for (dle = avl_first(&dl->dl_tree); dle;
            dle = AVL_NEXT(&dl->dl_tree, dle)) {
                if (dump_opt['d'] >= 5) {
@@ -2219,6 +2264,30 @@ dump_object(objset_t *os, uint64_t object, int verbosi
                dmu_buf_rele(db, FTAG);
 }
 
+static void
+count_dir_mos_objects(dsl_dir_t *dd)
+{
+       mos_obj_refd(dd->dd_object);
+       mos_obj_refd(dsl_dir_phys(dd)->dd_child_dir_zapobj);
+       mos_obj_refd(dsl_dir_phys(dd)->dd_deleg_zapobj);
+       mos_obj_refd(dsl_dir_phys(dd)->dd_props_zapobj);
+       mos_obj_refd(dsl_dir_phys(dd)->dd_clones);
+}
+
+static void
+count_ds_mos_objects(dsl_dataset_t *ds)
+{
+       mos_obj_refd(ds->ds_object);
+       mos_obj_refd(dsl_dataset_phys(ds)->ds_next_clones_obj);
+       mos_obj_refd(dsl_dataset_phys(ds)->ds_props_obj);
+       mos_obj_refd(dsl_dataset_phys(ds)->ds_userrefs_obj);
+       mos_obj_refd(dsl_dataset_phys(ds)->ds_snapnames_zapobj);
+
+       if (!dsl_dataset_is_snapshot(ds)) {
+               count_dir_mos_objects(ds->ds_dir);
+       }
+}
+
 static const char *objset_types[DMU_OST_NUMTYPES] = {
        "NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" };
 
@@ -2296,6 +2365,7 @@ dump_dir(objset_t *os)
                        (void) printf("ds_remap_deadlist:\n");
                        dump_deadlist(&ds->ds_remap_deadlist);
                }
+               count_ds_mos_objects(ds);
        }
 
        if (verbosity < 2)
@@ -4460,7 +4530,162 @@ verify_checkpoint(spa_t *spa)
        return (error);
 }
 
+/* ARGSUSED */
 static void
+mos_leaks_cb(void *arg, uint64_t start, uint64_t size)
+{
+       for (uint64_t i = start; i < size; i++) {
+               (void) printf("MOS object %llu referenced but not allocated\n",
+                   (u_longlong_t)i);
+       }
+}
+
+static range_tree_t *mos_refd_objs;
+
+static void
+mos_obj_refd(uint64_t obj)
+{
+       if (obj != 0 && mos_refd_objs != NULL)
+               range_tree_add(mos_refd_objs, obj, 1);
+}
+
+static void
+mos_leak_vdev(vdev_t *vd)
+{
+       mos_obj_refd(vd->vdev_dtl_object);
+       mos_obj_refd(vd->vdev_ms_array);
+       mos_obj_refd(vd->vdev_top_zap);
+       mos_obj_refd(vd->vdev_indirect_config.vic_births_object);
+       mos_obj_refd(vd->vdev_indirect_config.vic_mapping_object);
+       mos_obj_refd(vd->vdev_leaf_zap);
+       if (vd->vdev_checkpoint_sm != NULL)
+               mos_obj_refd(vd->vdev_checkpoint_sm->sm_object);
+       if (vd->vdev_indirect_mapping != NULL) {
+               mos_obj_refd(vd->vdev_indirect_mapping->
+                   vim_phys->vimp_counts_object);
+       }
+       if (vd->vdev_obsolete_sm != NULL)
+               mos_obj_refd(vd->vdev_obsolete_sm->sm_object);
+
+       for (uint64_t m = 0; m < vd->vdev_ms_count; m++) {
+               metaslab_t *ms = vd->vdev_ms[m];
+               mos_obj_refd(space_map_object(ms->ms_sm));
+       }
+
+       for (uint64_t c = 0; c < vd->vdev_children; c++) {
+               mos_leak_vdev(vd->vdev_child[c]);
+       }
+}
+
+static int
+dump_mos_leaks(spa_t *spa)
+{
+       int rv = 0;
+       objset_t *mos = spa->spa_meta_objset;
+       dsl_pool_t *dp = spa->spa_dsl_pool;
+
+       /* Visit and mark all referenced objects in the MOS */
+
+       mos_obj_refd(DMU_POOL_DIRECTORY_OBJECT);
+       mos_obj_refd(spa->spa_pool_props_object);
+       mos_obj_refd(spa->spa_config_object);
+       mos_obj_refd(spa->spa_ddt_stat_object);
+       mos_obj_refd(spa->spa_feat_desc_obj);
+       mos_obj_refd(spa->spa_feat_enabled_txg_obj);
+       mos_obj_refd(spa->spa_feat_for_read_obj);
+       mos_obj_refd(spa->spa_feat_for_write_obj);
+       mos_obj_refd(spa->spa_history);
+       mos_obj_refd(spa->spa_errlog_last);
+       mos_obj_refd(spa->spa_errlog_scrub);
+       mos_obj_refd(spa->spa_all_vdev_zaps);
+       mos_obj_refd(spa->spa_dsl_pool->dp_bptree_obj);
+       mos_obj_refd(spa->spa_dsl_pool->dp_tmp_userrefs_obj);
+       mos_obj_refd(spa->spa_dsl_pool->dp_scan->scn_phys.scn_queue_obj);
+       bpobj_count_refd(&spa->spa_deferred_bpobj);
+       mos_obj_refd(dp->dp_empty_bpobj);
+       bpobj_count_refd(&dp->dp_obsolete_bpobj);
+       bpobj_count_refd(&dp->dp_free_bpobj);
+       mos_obj_refd(spa->spa_l2cache.sav_object);
+       mos_obj_refd(spa->spa_spares.sav_object);
+
+       mos_obj_refd(spa->spa_condensing_indirect_phys.
+           scip_next_mapping_object);
+       mos_obj_refd(spa->spa_condensing_indirect_phys.
+           scip_prev_obsolete_sm_object);
+       if (spa->spa_condensing_indirect_phys.scip_next_mapping_object != 0) {
+               vdev_indirect_mapping_t *vim =
+                   vdev_indirect_mapping_open(mos,
+                   spa->spa_condensing_indirect_phys.scip_next_mapping_object);
+               mos_obj_refd(vim->vim_phys->vimp_counts_object);
+               vdev_indirect_mapping_close(vim);
+       }
+
+       if (dp->dp_origin_snap != NULL) {
+               dsl_dataset_t *ds;
+
+               dsl_pool_config_enter(dp, FTAG);
+               VERIFY0(dsl_dataset_hold_obj(dp,
+                   dsl_dataset_phys(dp->dp_origin_snap)->ds_next_snap_obj,
+                   FTAG, &ds));
+               count_ds_mos_objects(ds);
+               dump_deadlist(&ds->ds_deadlist);
+               dsl_dataset_rele(ds, FTAG);
+               dsl_pool_config_exit(dp, FTAG);
+
+               count_ds_mos_objects(dp->dp_origin_snap);
+               dump_deadlist(&dp->dp_origin_snap->ds_deadlist);
+       }
+       count_dir_mos_objects(dp->dp_mos_dir);
+       if (dp->dp_free_dir != NULL)
+               count_dir_mos_objects(dp->dp_free_dir);
+       if (dp->dp_leak_dir != NULL)
+               count_dir_mos_objects(dp->dp_leak_dir);
+
+       mos_leak_vdev(spa->spa_root_vdev);
+
+       for (uint64_t class = 0; class < DDT_CLASSES; class++) {
+               for (uint64_t type = 0; type < DDT_TYPES; type++) {
+                       for (uint64_t cksum = 0;
+                           cksum < ZIO_CHECKSUM_FUNCTIONS; cksum++) {
+                               ddt_t *ddt = spa->spa_ddt[cksum];
+                               mos_obj_refd(ddt->ddt_object[type][class]);
+                       }
+               }
+       }
+
+       /*
+        * Visit all allocated objects and make sure they are referenced.
+        */
+       uint64_t object = 0;
+       while (dmu_object_next(mos, &object, B_FALSE, 0) == 0) {
+               if (range_tree_contains(mos_refd_objs, object, 1)) {
+                       range_tree_remove(mos_refd_objs, object, 1);
+               } else {
+                       dmu_object_info_t doi;
+                       const char *name;
+                       dmu_object_info(mos, object, &doi);
+                       if (doi.doi_type & DMU_OT_NEWTYPE) {
+                               dmu_object_byteswap_t bswap =
+                                   DMU_OT_BYTESWAP(doi.doi_type);
+                               name = dmu_ot_byteswap[bswap].ob_name;
+                       } else {
+                               name = dmu_ot[doi.doi_type].ot_name;
+                       }
+
+                       (void) printf("MOS object %llu (%s) leaked\n",
+                           (u_longlong_t)object, name);
+                       rv = 2;
+               }
+       }
+       (void) range_tree_walk(mos_refd_objs, mos_leaks_cb, NULL);
+       if (!range_tree_is_empty(mos_refd_objs))
+               rv = 2;
+       range_tree_vacate(mos_refd_objs, NULL, NULL);
+       range_tree_destroy(mos_refd_objs);
+       return (rv);
+}
+
+static void
 dump_zpool(spa_t *spa)
 {
        dsl_pool_t *dp = spa_get_dsl(spa);
@@ -4491,7 +4716,9 @@ dump_zpool(spa_t *spa)
                dump_metaslab_groups(spa);
 
        if (dump_opt['d'] || dump_opt['i']) {
+               mos_refd_objs = range_tree_create(NULL, NULL);
                dump_dir(dp->dp_meta_objset);
+
                if (dump_opt['d'] >= 3) {
                        dsl_pool_t *dp = spa->spa_dsl_pool;
                        dump_full_bpobj(&spa->spa_deferred_bpobj,
@@ -4518,6 +4745,9 @@ dump_zpool(spa_t *spa)
                (void) dmu_objset_find(spa_name(spa), dump_one_dir,
                    NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
 
+               if (rc == 0 && !dump_opt['L'])
+                       rc = dump_mos_leaks(spa);
+
                for (spa_feature_t f = 0; f < SPA_FEATURES; f++) {
                        uint64_t refcount;
 
@@ -4547,6 +4777,7 @@ dump_zpool(spa_t *spa)
                        rc = verify_device_removal_feature_counts(spa);
                }
        }
+
        if (rc == 0 && (dump_opt['b'] || dump_opt['c']))
                rc = dump_block_stats(spa);
 

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c   Mon Jun 
 3 20:45:48 2019        (r348583)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_destroy.c   Mon Jun 
 3 20:49:20 2019        (r348584)
@@ -786,6 +786,8 @@ dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx)
 
        VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_child_dir_zapobj, tx));
        VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_props_zapobj, tx));
+       if (dsl_dir_phys(dd)->dd_clones != 0)
+               VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_clones, tx));
        VERIFY0(dsl_deleg_destroy(mos, dsl_dir_phys(dd)->dd_deleg_zapobj, tx));
        VERIFY0(zap_remove(mos,
            dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj,

Modified: 
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_indirect_mapping.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_indirect_mapping.c 
Mon Jun  3 20:45:48 2019        (r348583)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_indirect_mapping.c 
Mon Jun  3 20:49:20 2019        (r348584)
@@ -279,7 +279,6 @@ vdev_indirect_mapping_entry_for_offset_or_next(vdev_in
            B_TRUE));
 }
 
-
 void
 vdev_indirect_mapping_close(vdev_indirect_mapping_t *vim)
 {
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to