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 2009 Sun Microsystems, Inc. All rights reserved. 23*eda14cbcSMatt Macy * Use is subject to license terms. 24*eda14cbcSMatt Macy */ 25*eda14cbcSMatt Macy /* 26*eda14cbcSMatt Macy * Copyright (c) 2013, 2019 by Delphix. All rights reserved. 27*eda14cbcSMatt Macy */ 28*eda14cbcSMatt Macy 29*eda14cbcSMatt Macy #include <sys/zfs_context.h> 30*eda14cbcSMatt Macy #include <sys/range_tree.h> 31*eda14cbcSMatt Macy #include <sys/space_reftree.h> 32*eda14cbcSMatt Macy 33*eda14cbcSMatt Macy /* 34*eda14cbcSMatt Macy * Space reference trees. 35*eda14cbcSMatt Macy * 36*eda14cbcSMatt Macy * A range tree is a collection of integers. Every integer is either 37*eda14cbcSMatt Macy * in the tree, or it's not. A space reference tree generalizes 38*eda14cbcSMatt Macy * the idea: it allows its members to have arbitrary reference counts, 39*eda14cbcSMatt Macy * as opposed to the implicit reference count of 0 or 1 in a range tree. 40*eda14cbcSMatt Macy * This representation comes in handy when computing the union or 41*eda14cbcSMatt Macy * intersection of multiple space maps. For example, the union of 42*eda14cbcSMatt Macy * N range trees is the subset of the reference tree with refcnt >= 1. 43*eda14cbcSMatt Macy * The intersection of N range trees is the subset with refcnt >= N. 44*eda14cbcSMatt Macy * 45*eda14cbcSMatt Macy * [It's very much like a Fourier transform. Unions and intersections 46*eda14cbcSMatt Macy * are hard to perform in the 'range tree domain', so we convert the trees 47*eda14cbcSMatt Macy * into the 'reference count domain', where it's trivial, then invert.] 48*eda14cbcSMatt Macy * 49*eda14cbcSMatt Macy * vdev_dtl_reassess() uses computations of this form to determine 50*eda14cbcSMatt Macy * DTL_MISSING and DTL_OUTAGE for interior vdevs -- e.g. a RAID-Z vdev 51*eda14cbcSMatt Macy * has an outage wherever refcnt >= vdev_nparity + 1, and a mirror vdev 52*eda14cbcSMatt Macy * has an outage wherever refcnt >= vdev_children. 53*eda14cbcSMatt Macy */ 54*eda14cbcSMatt Macy static int 55*eda14cbcSMatt Macy space_reftree_compare(const void *x1, const void *x2) 56*eda14cbcSMatt Macy { 57*eda14cbcSMatt Macy const space_ref_t *sr1 = (const space_ref_t *)x1; 58*eda14cbcSMatt Macy const space_ref_t *sr2 = (const space_ref_t *)x2; 59*eda14cbcSMatt Macy 60*eda14cbcSMatt Macy int cmp = TREE_CMP(sr1->sr_offset, sr2->sr_offset); 61*eda14cbcSMatt Macy if (likely(cmp)) 62*eda14cbcSMatt Macy return (cmp); 63*eda14cbcSMatt Macy 64*eda14cbcSMatt Macy return (TREE_PCMP(sr1, sr2)); 65*eda14cbcSMatt Macy } 66*eda14cbcSMatt Macy 67*eda14cbcSMatt Macy void 68*eda14cbcSMatt Macy space_reftree_create(avl_tree_t *t) 69*eda14cbcSMatt Macy { 70*eda14cbcSMatt Macy avl_create(t, space_reftree_compare, 71*eda14cbcSMatt Macy sizeof (space_ref_t), offsetof(space_ref_t, sr_node)); 72*eda14cbcSMatt Macy } 73*eda14cbcSMatt Macy 74*eda14cbcSMatt Macy void 75*eda14cbcSMatt Macy space_reftree_destroy(avl_tree_t *t) 76*eda14cbcSMatt Macy { 77*eda14cbcSMatt Macy space_ref_t *sr; 78*eda14cbcSMatt Macy void *cookie = NULL; 79*eda14cbcSMatt Macy 80*eda14cbcSMatt Macy while ((sr = avl_destroy_nodes(t, &cookie)) != NULL) 81*eda14cbcSMatt Macy kmem_free(sr, sizeof (*sr)); 82*eda14cbcSMatt Macy 83*eda14cbcSMatt Macy avl_destroy(t); 84*eda14cbcSMatt Macy } 85*eda14cbcSMatt Macy 86*eda14cbcSMatt Macy static void 87*eda14cbcSMatt Macy space_reftree_add_node(avl_tree_t *t, uint64_t offset, int64_t refcnt) 88*eda14cbcSMatt Macy { 89*eda14cbcSMatt Macy space_ref_t *sr; 90*eda14cbcSMatt Macy 91*eda14cbcSMatt Macy sr = kmem_alloc(sizeof (*sr), KM_SLEEP); 92*eda14cbcSMatt Macy sr->sr_offset = offset; 93*eda14cbcSMatt Macy sr->sr_refcnt = refcnt; 94*eda14cbcSMatt Macy 95*eda14cbcSMatt Macy avl_add(t, sr); 96*eda14cbcSMatt Macy } 97*eda14cbcSMatt Macy 98*eda14cbcSMatt Macy void 99*eda14cbcSMatt Macy space_reftree_add_seg(avl_tree_t *t, uint64_t start, uint64_t end, 100*eda14cbcSMatt Macy int64_t refcnt) 101*eda14cbcSMatt Macy { 102*eda14cbcSMatt Macy space_reftree_add_node(t, start, refcnt); 103*eda14cbcSMatt Macy space_reftree_add_node(t, end, -refcnt); 104*eda14cbcSMatt Macy } 105*eda14cbcSMatt Macy 106*eda14cbcSMatt Macy /* 107*eda14cbcSMatt Macy * Convert (or add) a range tree into a reference tree. 108*eda14cbcSMatt Macy */ 109*eda14cbcSMatt Macy void 110*eda14cbcSMatt Macy space_reftree_add_map(avl_tree_t *t, range_tree_t *rt, int64_t refcnt) 111*eda14cbcSMatt Macy { 112*eda14cbcSMatt Macy zfs_btree_index_t where; 113*eda14cbcSMatt Macy 114*eda14cbcSMatt Macy for (range_seg_t *rs = zfs_btree_first(&rt->rt_root, &where); rs; rs = 115*eda14cbcSMatt Macy zfs_btree_next(&rt->rt_root, &where, &where)) { 116*eda14cbcSMatt Macy space_reftree_add_seg(t, rs_get_start(rs, rt), rs_get_end(rs, 117*eda14cbcSMatt Macy rt), refcnt); 118*eda14cbcSMatt Macy } 119*eda14cbcSMatt Macy } 120*eda14cbcSMatt Macy 121*eda14cbcSMatt Macy /* 122*eda14cbcSMatt Macy * Convert a reference tree into a range tree. The range tree will contain 123*eda14cbcSMatt Macy * all members of the reference tree for which refcnt >= minref. 124*eda14cbcSMatt Macy */ 125*eda14cbcSMatt Macy void 126*eda14cbcSMatt Macy space_reftree_generate_map(avl_tree_t *t, range_tree_t *rt, int64_t minref) 127*eda14cbcSMatt Macy { 128*eda14cbcSMatt Macy uint64_t start = -1ULL; 129*eda14cbcSMatt Macy int64_t refcnt = 0; 130*eda14cbcSMatt Macy space_ref_t *sr; 131*eda14cbcSMatt Macy 132*eda14cbcSMatt Macy range_tree_vacate(rt, NULL, NULL); 133*eda14cbcSMatt Macy 134*eda14cbcSMatt Macy for (sr = avl_first(t); sr != NULL; sr = AVL_NEXT(t, sr)) { 135*eda14cbcSMatt Macy refcnt += sr->sr_refcnt; 136*eda14cbcSMatt Macy if (refcnt >= minref) { 137*eda14cbcSMatt Macy if (start == -1ULL) { 138*eda14cbcSMatt Macy start = sr->sr_offset; 139*eda14cbcSMatt Macy } 140*eda14cbcSMatt Macy } else { 141*eda14cbcSMatt Macy if (start != -1ULL) { 142*eda14cbcSMatt Macy uint64_t end = sr->sr_offset; 143*eda14cbcSMatt Macy ASSERT(start <= end); 144*eda14cbcSMatt Macy if (end > start) 145*eda14cbcSMatt Macy range_tree_add(rt, start, end - start); 146*eda14cbcSMatt Macy start = -1ULL; 147*eda14cbcSMatt Macy } 148*eda14cbcSMatt Macy } 149*eda14cbcSMatt Macy } 150*eda14cbcSMatt Macy ASSERT(refcnt == 0); 151*eda14cbcSMatt Macy ASSERT(start == -1ULL); 152*eda14cbcSMatt Macy } 153