summaryrefslogtreecommitdiffstats
path: root/include/sys/space_map.h
blob: 6f935c9db27e50868661f62c0c873f6b38d7afff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_SPACE_MAP_H
#define	_SYS_SPACE_MAP_H

#include <sys/avl.h>
#include <sys/dmu.h>

#ifdef	__cplusplus
extern "C" {
#endif

typedef struct space_map_ops space_map_ops_t;

typedef struct space_map {
	avl_tree_t	sm_root;	/* AVL tree of map segments */
	uint64_t	sm_space;	/* sum of all segments in the map */
	uint64_t	sm_start;	/* start of map */
	uint64_t	sm_size;	/* size of map */
	uint8_t		sm_shift;	/* unit shift */
	uint8_t		sm_pad[3];	/* unused */
	uint8_t		sm_loaded;	/* map loaded? */
	uint8_t		sm_loading;	/* map loading? */
	kcondvar_t	sm_load_cv;	/* map load completion */
	space_map_ops_t	*sm_ops;	/* space map block picker ops vector */
	avl_tree_t	*sm_pp_root;	/* picker-private AVL tree */
	void		*sm_ppd;	/* picker-private data */
	kmutex_t	*sm_lock;	/* pointer to lock that protects map */
} space_map_t;

typedef struct space_seg {
	avl_node_t	ss_node;	/* AVL node */
	avl_node_t	ss_pp_node;	/* AVL picker-private node */
	uint64_t	ss_start;	/* starting offset of this segment */
	uint64_t	ss_end;		/* ending offset (non-inclusive) */
} space_seg_t;

typedef struct space_ref {
	avl_node_t	sr_node;	/* AVL node */
	uint64_t	sr_offset;	/* offset (start or end) */
	int64_t		sr_refcnt;	/* associated reference count */
} space_ref_t;

typedef struct space_map_obj {
	uint64_t	smo_object;	/* on-disk space map object */
	uint64_t	smo_objsize;	/* size of the object */
	uint64_t	smo_alloc;	/* space allocated from the map */
} space_map_obj_t;

struct space_map_ops {
	void	(*smop_load)(space_map_t *sm);
	void	(*smop_unload)(space_map_t *sm);
	uint64_t (*smop_alloc)(space_map_t *sm, uint64_t size);
	void	(*smop_claim)(space_map_t *sm, uint64_t start, uint64_t size);
	void	(*smop_free)(space_map_t *sm, uint64_t start, uint64_t size);
	uint64_t (*smop_max)(space_map_t *sm);
	boolean_t (*smop_fragmented)(space_map_t *sm);
};

/*
 * debug entry
 *
 *    1      3         10                     50
 *  ,---+--------+------------+---------------------------------.
 *  | 1 | action |  syncpass  |        txg (lower bits)         |
 *  `---+--------+------------+---------------------------------'
 *   63  62    60 59        50 49                               0
 *
 *
 *
 * non-debug entry
 *
 *    1               47                   1           15
 *  ,-----------------------------------------------------------.
 *  | 0 |   offset (sm_shift units)    | type |       run       |
 *  `-----------------------------------------------------------'
 *   63  62                          17   16   15               0
 */

/* All this stuff takes and returns bytes */
#define	SM_RUN_DECODE(x)	(BF64_DECODE(x, 0, 15) + 1)
#define	SM_RUN_ENCODE(x)	BF64_ENCODE((x) - 1, 0, 15)
#define	SM_TYPE_DECODE(x)	BF64_DECODE(x, 15, 1)
#define	SM_TYPE_ENCODE(x)	BF64_ENCODE(x, 15, 1)
#define	SM_OFFSET_DECODE(x)	BF64_DECODE(x, 16, 47)
#define	SM_OFFSET_ENCODE(x)	BF64_ENCODE(x, 16, 47)
#define	SM_DEBUG_DECODE(x)	BF64_DECODE(x, 63, 1)
#define	SM_DEBUG_ENCODE(x)	BF64_ENCODE(x, 63, 1)

#define	SM_DEBUG_ACTION_DECODE(x)	BF64_DECODE(x, 60, 3)
#define	SM_DEBUG_ACTION_ENCODE(x)	BF64_ENCODE(x, 60, 3)

#define	SM_DEBUG_SYNCPASS_DECODE(x)	BF64_DECODE(x, 50, 10)
#define	SM_DEBUG_SYNCPASS_ENCODE(x)	BF64_ENCODE(x, 50, 10)

#define	SM_DEBUG_TXG_DECODE(x)		BF64_DECODE(x, 0, 50)
#define	SM_DEBUG_TXG_ENCODE(x)		BF64_ENCODE(x, 0, 50)

#define	SM_RUN_MAX			SM_RUN_DECODE(~0ULL)

#define	SM_ALLOC	0x0
#define	SM_FREE		0x1

/*
 * The data for a given space map can be kept on blocks of any size.
 * Larger blocks entail fewer i/o operations, but they also cause the
 * DMU to keep more data in-core, and also to waste more i/o bandwidth
 * when only a few blocks have changed since the last transaction group.
 * This could use a lot more research, but for now, set the freelist
 * block size to 4k (2^12).
 */
#define	SPACE_MAP_BLOCKSHIFT	12

typedef void space_map_func_t(space_map_t *sm, uint64_t start, uint64_t size);

extern void space_map_create(space_map_t *sm, uint64_t start, uint64_t size,
    uint8_t shift, kmutex_t *lp);
extern void space_map_destroy(space_map_t *sm);
extern void space_map_add(space_map_t *sm, uint64_t start, uint64_t size);
extern void space_map_remove(space_map_t *sm, uint64_t start, uint64_t size);
extern boolean_t space_map_contains(space_map_t *sm,
    uint64_t start, uint64_t size);
extern void space_map_vacate(space_map_t *sm,
    space_map_func_t *func, space_map_t *mdest);
extern void space_map_walk(space_map_t *sm,
    space_map_func_t *func, space_map_t *mdest);

extern void space_map_load_wait(space_map_t *sm);
extern int space_map_load(space_map_t *sm, space_map_ops_t *ops,
    uint8_t maptype, space_map_obj_t *smo, objset_t *os);
extern void space_map_unload(space_map_t *sm);

extern uint64_t space_map_alloc(space_map_t *sm, uint64_t size);
extern void space_map_claim(space_map_t *sm, uint64_t start, uint64_t size);
extern void space_map_free(space_map_t *sm, uint64_t start, uint64_t size);
extern uint64_t space_map_maxsize(space_map_t *sm);

extern void space_map_sync(space_map_t *sm, uint8_t maptype,
    space_map_obj_t *smo, objset_t *os, dmu_tx_t *tx);
extern void space_map_truncate(space_map_obj_t *smo,
    objset_t *os, dmu_tx_t *tx);

extern void space_map_ref_create(avl_tree_t *t);
extern void space_map_ref_destroy(avl_tree_t *t);
extern void space_map_ref_add_seg(avl_tree_t *t,
    uint64_t start, uint64_t end, int64_t refcnt);
extern void space_map_ref_add_map(avl_tree_t *t,
    space_map_t *sm, int64_t refcnt);
extern void space_map_ref_generate_map(avl_tree_t *t,
    space_map_t *sm, int64_t minref);

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_SPACE_MAP_H */