root/usr/src/uts/common/fs/zfs/sys/vdev_indirect_mapping.h
/*
 * CDDL HEADER START
 *
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2015 by Delphix. All rights reserved.
 */

#ifndef _SYS_VDEV_INDIRECT_MAPPING_H
#define _SYS_VDEV_INDIRECT_MAPPING_H

#include <sys/dmu.h>
#include <sys/list.h>
#include <sys/spa.h>
#include <sys/space_map.h>

#ifdef  __cplusplus
extern "C" {
#endif

typedef struct vdev_indirect_mapping_entry_phys {
        /*
         * Decode with DVA_MAPPING_* macros.
         * Contains:
         *   the source offset (low 63 bits)
         *   the one-bit "mark", used for garbage collection (by zdb)
         */
        uint64_t vimep_src;

        /*
         * Note: the DVA's asize is 24 bits, and can thus store ranges
         * up to 8GB.
         */
        dva_t   vimep_dst;
} vdev_indirect_mapping_entry_phys_t;

#define DVA_MAPPING_GET_SRC_OFFSET(vimep)       \
        BF64_GET_SB((vimep)->vimep_src, 0, 63, SPA_MINBLOCKSHIFT, 0)
#define DVA_MAPPING_SET_SRC_OFFSET(vimep, x)    \
        BF64_SET_SB((vimep)->vimep_src, 0, 63, SPA_MINBLOCKSHIFT, 0, x)

typedef struct vdev_indirect_mapping_entry {
        vdev_indirect_mapping_entry_phys_t      vime_mapping;
        uint32_t                                vime_obsolete_count;
        list_node_t                             vime_node;
} vdev_indirect_mapping_entry_t;

/*
 * This is stored in the bonus buffer of the mapping object, see comment of
 * vdev_indirect_config for more details.
 */
typedef struct vdev_indirect_mapping_phys {
        uint64_t        vimp_max_offset;
        uint64_t        vimp_bytes_mapped;
        uint64_t        vimp_num_entries; /* number of v_i_m_entry_phys_t's */

        /*
         * For each entry in the mapping object, this object contains an
         * entry representing the number of bytes of that mapping entry
         * that were no longer in use by the pool at the time this indirect
         * vdev was last condensed.
         */
        uint64_t        vimp_counts_object;
} vdev_indirect_mapping_phys_t;

#define VDEV_INDIRECT_MAPPING_SIZE_V0   (3 * sizeof (uint64_t))

typedef struct vdev_indirect_mapping {
        uint64_t        vim_object;
        boolean_t       vim_havecounts;

        /*
         * An ordered array of all mapping entries, sorted by source offset.
         * Note that vim_entries is needed during a removal (and contains
         * mappings that have been synced to disk so far) to handle frees
         * from the removing device.
         */
        vdev_indirect_mapping_entry_phys_t *vim_entries;

        objset_t        *vim_objset;

        dmu_buf_t       *vim_dbuf;
        vdev_indirect_mapping_phys_t    *vim_phys;
} vdev_indirect_mapping_t;

extern vdev_indirect_mapping_t *vdev_indirect_mapping_open(objset_t *os,
    uint64_t object);
extern void vdev_indirect_mapping_close(vdev_indirect_mapping_t *vim);
extern uint64_t vdev_indirect_mapping_alloc(objset_t *os, dmu_tx_t *tx);
extern void vdev_indirect_mapping_free(objset_t *os, uint64_t obj,
    dmu_tx_t *tx);

extern uint64_t vdev_indirect_mapping_num_entries(vdev_indirect_mapping_t *vim);
extern uint64_t vdev_indirect_mapping_max_offset(vdev_indirect_mapping_t *vim);
extern uint64_t vdev_indirect_mapping_object(vdev_indirect_mapping_t *vim);
extern uint64_t vdev_indirect_mapping_bytes_mapped(
    vdev_indirect_mapping_t *vim);
extern uint64_t vdev_indirect_mapping_size(vdev_indirect_mapping_t *vim);

/*
 * Writes the given list of vdev_indirect_mapping_entry_t to the mapping
 * then updates internal state.
 */
extern void vdev_indirect_mapping_add_entries(vdev_indirect_mapping_t *vim,
    list_t *vime_list, dmu_tx_t *tx);

extern vdev_indirect_mapping_entry_phys_t *
    vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim,
    uint64_t offset);

extern vdev_indirect_mapping_entry_phys_t *
    vdev_indirect_mapping_entry_for_offset_or_next(vdev_indirect_mapping_t *vim,
    uint64_t offset);

extern uint32_t *vdev_indirect_mapping_load_obsolete_counts(
    vdev_indirect_mapping_t *vim);
extern void vdev_indirect_mapping_load_obsolete_spacemap(
    vdev_indirect_mapping_t *vim,
    uint32_t *counts, space_map_t *obsolete_space_sm);
extern void vdev_indirect_mapping_increment_obsolete_count(
    vdev_indirect_mapping_t *vim,
    uint64_t offset, uint64_t asize, uint32_t *counts);
extern void vdev_indirect_mapping_free_obsolete_counts(
    vdev_indirect_mapping_t *vim, uint32_t *counts);

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_VDEV_INDIRECT_MAPPING_H */