1/*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source.  A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14 */
15
16/*
17 * Copyright (c) 2015 by Delphix. All rights reserved.
18 */
19
20#ifndef	_SYS_VDEV_INDIRECT_MAPPING_H
21#define	_SYS_VDEV_INDIRECT_MAPPING_H
22
23#include <sys/dmu.h>
24#include <sys/list.h>
25#include <sys/spa.h>
26#include <sys/space_map.h>
27
28#ifdef	__cplusplus
29extern "C" {
30#endif
31
32typedef struct vdev_indirect_mapping_entry_phys {
33	/*
34	 * Decode with DVA_MAPPING_* macros.
35	 * Contains:
36	 *   the source offset (low 63 bits)
37	 *   the one-bit "mark", used for garbage collection (by zdb)
38	 */
39	uint64_t vimep_src;
40
41	/*
42	 * Note: the DVA's asize is 24 bits, and can thus store ranges
43	 * up to 8GB.
44	 */
45	dva_t	vimep_dst;
46} vdev_indirect_mapping_entry_phys_t;
47
48#define	DVA_MAPPING_GET_SRC_OFFSET(vimep)	\
49	BF64_GET_SB((vimep)->vimep_src, 0, 63, SPA_MINBLOCKSHIFT, 0)
50#define	DVA_MAPPING_SET_SRC_OFFSET(vimep, x)	\
51	BF64_SET_SB((vimep)->vimep_src, 0, 63, SPA_MINBLOCKSHIFT, 0, x)
52
53typedef struct vdev_indirect_mapping_entry {
54	vdev_indirect_mapping_entry_phys_t	vime_mapping;
55	uint32_t				vime_obsolete_count;
56	list_node_t				vime_node;
57} vdev_indirect_mapping_entry_t;
58
59/*
60 * This is stored in the bonus buffer of the mapping object, see comment of
61 * vdev_indirect_config for more details.
62 */
63typedef struct vdev_indirect_mapping_phys {
64	uint64_t	vimp_max_offset;
65	uint64_t	vimp_bytes_mapped;
66	uint64_t	vimp_num_entries; /* number of v_i_m_entry_phys_t's */
67
68	/*
69	 * For each entry in the mapping object, this object contains an
70	 * entry representing the number of bytes of that mapping entry
71	 * that were no longer in use by the pool at the time this indirect
72	 * vdev was last condensed.
73	 */
74	uint64_t	vimp_counts_object;
75} vdev_indirect_mapping_phys_t;
76
77#define	VDEV_INDIRECT_MAPPING_SIZE_V0	(3 * sizeof (uint64_t))
78
79typedef struct vdev_indirect_mapping {
80	uint64_t	vim_object;
81	boolean_t	vim_havecounts;
82
83	/*
84	 * An ordered array of all mapping entries, sorted by source offset.
85	 * Note that vim_entries is needed during a removal (and contains
86	 * mappings that have been synced to disk so far) to handle frees
87	 * from the removing device.
88	 */
89	vdev_indirect_mapping_entry_phys_t *vim_entries;
90
91	objset_t	*vim_objset;
92
93	dmu_buf_t	*vim_dbuf;
94	vdev_indirect_mapping_phys_t	*vim_phys;
95} vdev_indirect_mapping_t;
96
97extern vdev_indirect_mapping_t *vdev_indirect_mapping_open(objset_t *os,
98    uint64_t object);
99extern void vdev_indirect_mapping_close(vdev_indirect_mapping_t *vim);
100extern uint64_t vdev_indirect_mapping_alloc(objset_t *os, dmu_tx_t *tx);
101extern void vdev_indirect_mapping_free(objset_t *os, uint64_t obj,
102    dmu_tx_t *tx);
103
104extern uint64_t vdev_indirect_mapping_num_entries(vdev_indirect_mapping_t *vim);
105extern uint64_t vdev_indirect_mapping_max_offset(vdev_indirect_mapping_t *vim);
106extern uint64_t vdev_indirect_mapping_object(vdev_indirect_mapping_t *vim);
107extern uint64_t vdev_indirect_mapping_bytes_mapped(
108    vdev_indirect_mapping_t *vim);
109extern uint64_t vdev_indirect_mapping_size(vdev_indirect_mapping_t *vim);
110
111/*
112 * Writes the given list of vdev_indirect_mapping_entry_t to the mapping
113 * then updates internal state.
114 */
115extern void vdev_indirect_mapping_add_entries(vdev_indirect_mapping_t *vim,
116    list_t *vime_list, dmu_tx_t *tx);
117
118extern vdev_indirect_mapping_entry_phys_t *
119    vdev_indirect_mapping_entry_for_offset(vdev_indirect_mapping_t *vim,
120    uint64_t offset);
121
122extern vdev_indirect_mapping_entry_phys_t *
123    vdev_indirect_mapping_entry_for_offset_or_next(vdev_indirect_mapping_t *vim,
124    uint64_t offset);
125
126extern uint32_t *vdev_indirect_mapping_load_obsolete_counts(
127    vdev_indirect_mapping_t *vim);
128extern void vdev_indirect_mapping_load_obsolete_spacemap(
129    vdev_indirect_mapping_t *vim,
130    uint32_t *counts, space_map_t *obsolete_space_sm);
131extern void vdev_indirect_mapping_increment_obsolete_count(
132    vdev_indirect_mapping_t *vim,
133    uint64_t offset, uint64_t asize, uint32_t *counts);
134extern void vdev_indirect_mapping_free_obsolete_counts(
135    vdev_indirect_mapping_t *vim, uint32_t *counts);
136
137#ifdef	__cplusplus
138}
139#endif
140
141#endif	/* _SYS_VDEV_INDIRECT_MAPPING_H */
142