xref: /freebsd/contrib/jemalloc/src/emap.c (revision c43cad87172039ccf38172129c79755ea79e6102)
1*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_preamble.h"
2*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_internal_includes.h"
3*c43cad87SWarner Losh 
4*c43cad87SWarner Losh #include "jemalloc/internal/emap.h"
5*c43cad87SWarner Losh 
6*c43cad87SWarner Losh enum emap_lock_result_e {
7*c43cad87SWarner Losh 	emap_lock_result_success,
8*c43cad87SWarner Losh 	emap_lock_result_failure,
9*c43cad87SWarner Losh 	emap_lock_result_no_extent
10*c43cad87SWarner Losh };
11*c43cad87SWarner Losh typedef enum emap_lock_result_e emap_lock_result_t;
12*c43cad87SWarner Losh 
13*c43cad87SWarner Losh bool
14*c43cad87SWarner Losh emap_init(emap_t *emap, base_t *base, bool zeroed) {
15*c43cad87SWarner Losh 	return rtree_new(&emap->rtree, base, zeroed);
16*c43cad87SWarner Losh }
17*c43cad87SWarner Losh 
18*c43cad87SWarner Losh void
19*c43cad87SWarner Losh emap_update_edata_state(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
20*c43cad87SWarner Losh     extent_state_t state) {
21*c43cad87SWarner Losh 	witness_assert_positive_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
22*c43cad87SWarner Losh 	    WITNESS_RANK_CORE);
23*c43cad87SWarner Losh 
24*c43cad87SWarner Losh 	edata_state_set(edata, state);
25*c43cad87SWarner Losh 
26*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
27*c43cad87SWarner Losh 	rtree_leaf_elm_t *elm1 = rtree_leaf_elm_lookup(tsdn, &emap->rtree,
28*c43cad87SWarner Losh 	    rtree_ctx, (uintptr_t)edata_base_get(edata), /* dependent */ true,
29*c43cad87SWarner Losh 	    /* init_missing */ false);
30*c43cad87SWarner Losh 	assert(elm1 != NULL);
31*c43cad87SWarner Losh 	rtree_leaf_elm_t *elm2 = edata_size_get(edata) == PAGE ? NULL :
32*c43cad87SWarner Losh 	    rtree_leaf_elm_lookup(tsdn, &emap->rtree, rtree_ctx,
33*c43cad87SWarner Losh 	    (uintptr_t)edata_last_get(edata), /* dependent */ true,
34*c43cad87SWarner Losh 	    /* init_missing */ false);
35*c43cad87SWarner Losh 
36*c43cad87SWarner Losh 	rtree_leaf_elm_state_update(tsdn, &emap->rtree, elm1, elm2, state);
37*c43cad87SWarner Losh 
38*c43cad87SWarner Losh 	emap_assert_mapped(tsdn, emap, edata);
39*c43cad87SWarner Losh }
40*c43cad87SWarner Losh 
41*c43cad87SWarner Losh static inline edata_t *
42*c43cad87SWarner Losh emap_try_acquire_edata_neighbor_impl(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
43*c43cad87SWarner Losh     extent_pai_t pai, extent_state_t expected_state, bool forward,
44*c43cad87SWarner Losh     bool expanding) {
45*c43cad87SWarner Losh 	witness_assert_positive_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
46*c43cad87SWarner Losh 	    WITNESS_RANK_CORE);
47*c43cad87SWarner Losh 	assert(!edata_guarded_get(edata));
48*c43cad87SWarner Losh 	assert(!expanding || forward);
49*c43cad87SWarner Losh 	assert(!edata_state_in_transition(expected_state));
50*c43cad87SWarner Losh 	assert(expected_state == extent_state_dirty ||
51*c43cad87SWarner Losh 	       expected_state == extent_state_muzzy ||
52*c43cad87SWarner Losh 	       expected_state == extent_state_retained);
53*c43cad87SWarner Losh 
54*c43cad87SWarner Losh 	void *neighbor_addr = forward ? edata_past_get(edata) :
55*c43cad87SWarner Losh 	    edata_before_get(edata);
56*c43cad87SWarner Losh 	/*
57*c43cad87SWarner Losh 	 * This is subtle; the rtree code asserts that its input pointer is
58*c43cad87SWarner Losh 	 * non-NULL, and this is a useful thing to check.  But it's possible
59*c43cad87SWarner Losh 	 * that edata corresponds to an address of (void *)PAGE (in practice,
60*c43cad87SWarner Losh 	 * this has only been observed on FreeBSD when address-space
61*c43cad87SWarner Losh 	 * randomization is on, but it could in principle happen anywhere).  In
62*c43cad87SWarner Losh 	 * this case, edata_before_get(edata) is NULL, triggering the assert.
63*c43cad87SWarner Losh 	 */
64*c43cad87SWarner Losh 	if (neighbor_addr == NULL) {
65*c43cad87SWarner Losh 		return NULL;
66*c43cad87SWarner Losh 	}
67*c43cad87SWarner Losh 
68*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
69*c43cad87SWarner Losh 	rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &emap->rtree,
70*c43cad87SWarner Losh 	    rtree_ctx, (uintptr_t)neighbor_addr, /* dependent*/ false,
71*c43cad87SWarner Losh 	    /* init_missing */ false);
72*c43cad87SWarner Losh 	if (elm == NULL) {
73*c43cad87SWarner Losh 		return NULL;
74*c43cad87SWarner Losh 	}
75*c43cad87SWarner Losh 
76*c43cad87SWarner Losh 	rtree_contents_t neighbor_contents = rtree_leaf_elm_read(tsdn,
77*c43cad87SWarner Losh 	    &emap->rtree, elm, /* dependent */ true);
78*c43cad87SWarner Losh 	if (!extent_can_acquire_neighbor(edata, neighbor_contents, pai,
79*c43cad87SWarner Losh 	    expected_state, forward, expanding)) {
80*c43cad87SWarner Losh 		return NULL;
81*c43cad87SWarner Losh 	}
82*c43cad87SWarner Losh 
83*c43cad87SWarner Losh 	/* From this point, the neighbor edata can be safely acquired. */
84*c43cad87SWarner Losh 	edata_t *neighbor = neighbor_contents.edata;
85*c43cad87SWarner Losh 	assert(edata_state_get(neighbor) == expected_state);
86*c43cad87SWarner Losh 	emap_update_edata_state(tsdn, emap, neighbor, extent_state_merging);
87*c43cad87SWarner Losh 	if (expanding) {
88*c43cad87SWarner Losh 		extent_assert_can_expand(edata, neighbor);
89*c43cad87SWarner Losh 	} else {
90*c43cad87SWarner Losh 		extent_assert_can_coalesce(edata, neighbor);
91*c43cad87SWarner Losh 	}
92*c43cad87SWarner Losh 
93*c43cad87SWarner Losh 	return neighbor;
94*c43cad87SWarner Losh }
95*c43cad87SWarner Losh 
96*c43cad87SWarner Losh edata_t *
97*c43cad87SWarner Losh emap_try_acquire_edata_neighbor(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
98*c43cad87SWarner Losh     extent_pai_t pai, extent_state_t expected_state, bool forward) {
99*c43cad87SWarner Losh 	return emap_try_acquire_edata_neighbor_impl(tsdn, emap, edata, pai,
100*c43cad87SWarner Losh 	    expected_state, forward, /* expand */ false);
101*c43cad87SWarner Losh }
102*c43cad87SWarner Losh 
103*c43cad87SWarner Losh edata_t *
104*c43cad87SWarner Losh emap_try_acquire_edata_neighbor_expand(tsdn_t *tsdn, emap_t *emap,
105*c43cad87SWarner Losh     edata_t *edata, extent_pai_t pai, extent_state_t expected_state) {
106*c43cad87SWarner Losh 	/* Try expanding forward. */
107*c43cad87SWarner Losh 	return emap_try_acquire_edata_neighbor_impl(tsdn, emap, edata, pai,
108*c43cad87SWarner Losh 	    expected_state, /* forward */ true, /* expand */ true);
109*c43cad87SWarner Losh }
110*c43cad87SWarner Losh 
111*c43cad87SWarner Losh void
112*c43cad87SWarner Losh emap_release_edata(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
113*c43cad87SWarner Losh     extent_state_t new_state) {
114*c43cad87SWarner Losh 	assert(emap_edata_in_transition(tsdn, emap, edata));
115*c43cad87SWarner Losh 	assert(emap_edata_is_acquired(tsdn, emap, edata));
116*c43cad87SWarner Losh 
117*c43cad87SWarner Losh 	emap_update_edata_state(tsdn, emap, edata, new_state);
118*c43cad87SWarner Losh }
119*c43cad87SWarner Losh 
120*c43cad87SWarner Losh static bool
121*c43cad87SWarner Losh emap_rtree_leaf_elms_lookup(tsdn_t *tsdn, emap_t *emap, rtree_ctx_t *rtree_ctx,
122*c43cad87SWarner Losh     const edata_t *edata, bool dependent, bool init_missing,
123*c43cad87SWarner Losh     rtree_leaf_elm_t **r_elm_a, rtree_leaf_elm_t **r_elm_b) {
124*c43cad87SWarner Losh 	*r_elm_a = rtree_leaf_elm_lookup(tsdn, &emap->rtree, rtree_ctx,
125*c43cad87SWarner Losh 	    (uintptr_t)edata_base_get(edata), dependent, init_missing);
126*c43cad87SWarner Losh 	if (!dependent && *r_elm_a == NULL) {
127*c43cad87SWarner Losh 		return true;
128*c43cad87SWarner Losh 	}
129*c43cad87SWarner Losh 	assert(*r_elm_a != NULL);
130*c43cad87SWarner Losh 
131*c43cad87SWarner Losh 	*r_elm_b = rtree_leaf_elm_lookup(tsdn, &emap->rtree, rtree_ctx,
132*c43cad87SWarner Losh 	    (uintptr_t)edata_last_get(edata), dependent, init_missing);
133*c43cad87SWarner Losh 	if (!dependent && *r_elm_b == NULL) {
134*c43cad87SWarner Losh 		return true;
135*c43cad87SWarner Losh 	}
136*c43cad87SWarner Losh 	assert(*r_elm_b != NULL);
137*c43cad87SWarner Losh 
138*c43cad87SWarner Losh 	return false;
139*c43cad87SWarner Losh }
140*c43cad87SWarner Losh 
141*c43cad87SWarner Losh static void
142*c43cad87SWarner Losh emap_rtree_write_acquired(tsdn_t *tsdn, emap_t *emap, rtree_leaf_elm_t *elm_a,
143*c43cad87SWarner Losh     rtree_leaf_elm_t *elm_b, edata_t *edata, szind_t szind, bool slab) {
144*c43cad87SWarner Losh 	rtree_contents_t contents;
145*c43cad87SWarner Losh 	contents.edata = edata;
146*c43cad87SWarner Losh 	contents.metadata.szind = szind;
147*c43cad87SWarner Losh 	contents.metadata.slab = slab;
148*c43cad87SWarner Losh 	contents.metadata.is_head = (edata == NULL) ? false :
149*c43cad87SWarner Losh 	    edata_is_head_get(edata);
150*c43cad87SWarner Losh 	contents.metadata.state = (edata == NULL) ? 0 : edata_state_get(edata);
151*c43cad87SWarner Losh 	rtree_leaf_elm_write(tsdn, &emap->rtree, elm_a, contents);
152*c43cad87SWarner Losh 	if (elm_b != NULL) {
153*c43cad87SWarner Losh 		rtree_leaf_elm_write(tsdn, &emap->rtree, elm_b, contents);
154*c43cad87SWarner Losh 	}
155*c43cad87SWarner Losh }
156*c43cad87SWarner Losh 
157*c43cad87SWarner Losh bool
158*c43cad87SWarner Losh emap_register_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
159*c43cad87SWarner Losh     szind_t szind, bool slab) {
160*c43cad87SWarner Losh 	assert(edata_state_get(edata) == extent_state_active);
161*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
162*c43cad87SWarner Losh 
163*c43cad87SWarner Losh 	rtree_leaf_elm_t *elm_a, *elm_b;
164*c43cad87SWarner Losh 	bool err = emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, edata,
165*c43cad87SWarner Losh 	    false, true, &elm_a, &elm_b);
166*c43cad87SWarner Losh 	if (err) {
167*c43cad87SWarner Losh 		return true;
168*c43cad87SWarner Losh 	}
169*c43cad87SWarner Losh 	assert(rtree_leaf_elm_read(tsdn, &emap->rtree, elm_a,
170*c43cad87SWarner Losh 	    /* dependent */ false).edata == NULL);
171*c43cad87SWarner Losh 	assert(rtree_leaf_elm_read(tsdn, &emap->rtree, elm_b,
172*c43cad87SWarner Losh 	    /* dependent */ false).edata == NULL);
173*c43cad87SWarner Losh 	emap_rtree_write_acquired(tsdn, emap, elm_a, elm_b, edata, szind, slab);
174*c43cad87SWarner Losh 	return false;
175*c43cad87SWarner Losh }
176*c43cad87SWarner Losh 
177*c43cad87SWarner Losh /* Invoked *after* emap_register_boundary. */
178*c43cad87SWarner Losh void
179*c43cad87SWarner Losh emap_register_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
180*c43cad87SWarner Losh     szind_t szind) {
181*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
182*c43cad87SWarner Losh 
183*c43cad87SWarner Losh 	assert(edata_slab_get(edata));
184*c43cad87SWarner Losh 	assert(edata_state_get(edata) == extent_state_active);
185*c43cad87SWarner Losh 
186*c43cad87SWarner Losh 	if (config_debug) {
187*c43cad87SWarner Losh 		/* Making sure the boundary is registered already. */
188*c43cad87SWarner Losh 		rtree_leaf_elm_t *elm_a, *elm_b;
189*c43cad87SWarner Losh 		bool err = emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx,
190*c43cad87SWarner Losh 		    edata, /* dependent */ true, /* init_missing */ false,
191*c43cad87SWarner Losh 		    &elm_a, &elm_b);
192*c43cad87SWarner Losh 		assert(!err);
193*c43cad87SWarner Losh 		rtree_contents_t contents_a, contents_b;
194*c43cad87SWarner Losh 		contents_a = rtree_leaf_elm_read(tsdn, &emap->rtree, elm_a,
195*c43cad87SWarner Losh 		    /* dependent */ true);
196*c43cad87SWarner Losh 		contents_b = rtree_leaf_elm_read(tsdn, &emap->rtree, elm_b,
197*c43cad87SWarner Losh 		    /* dependent */ true);
198*c43cad87SWarner Losh 		assert(contents_a.edata == edata && contents_b.edata == edata);
199*c43cad87SWarner Losh 		assert(contents_a.metadata.slab && contents_b.metadata.slab);
200*c43cad87SWarner Losh 	}
201*c43cad87SWarner Losh 
202*c43cad87SWarner Losh 	rtree_contents_t contents;
203*c43cad87SWarner Losh 	contents.edata = edata;
204*c43cad87SWarner Losh 	contents.metadata.szind = szind;
205*c43cad87SWarner Losh 	contents.metadata.slab = true;
206*c43cad87SWarner Losh 	contents.metadata.state = extent_state_active;
207*c43cad87SWarner Losh 	contents.metadata.is_head = false; /* Not allowed to access. */
208*c43cad87SWarner Losh 
209*c43cad87SWarner Losh 	assert(edata_size_get(edata) > (2 << LG_PAGE));
210*c43cad87SWarner Losh 	rtree_write_range(tsdn, &emap->rtree, rtree_ctx,
211*c43cad87SWarner Losh 	    (uintptr_t)edata_base_get(edata) + PAGE,
212*c43cad87SWarner Losh 	    (uintptr_t)edata_last_get(edata) - PAGE, contents);
213*c43cad87SWarner Losh }
214*c43cad87SWarner Losh 
215*c43cad87SWarner Losh void
216*c43cad87SWarner Losh emap_deregister_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
217*c43cad87SWarner Losh 	/*
218*c43cad87SWarner Losh 	 * The edata must be either in an acquired state, or protected by state
219*c43cad87SWarner Losh 	 * based locks.
220*c43cad87SWarner Losh 	 */
221*c43cad87SWarner Losh 	if (!emap_edata_is_acquired(tsdn, emap, edata)) {
222*c43cad87SWarner Losh 		witness_assert_positive_depth_to_rank(
223*c43cad87SWarner Losh 		    tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE);
224*c43cad87SWarner Losh 	}
225*c43cad87SWarner Losh 
226*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
227*c43cad87SWarner Losh 	rtree_leaf_elm_t *elm_a, *elm_b;
228*c43cad87SWarner Losh 
229*c43cad87SWarner Losh 	emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, edata,
230*c43cad87SWarner Losh 	    true, false, &elm_a, &elm_b);
231*c43cad87SWarner Losh 	emap_rtree_write_acquired(tsdn, emap, elm_a, elm_b, NULL, SC_NSIZES,
232*c43cad87SWarner Losh 	    false);
233*c43cad87SWarner Losh }
234*c43cad87SWarner Losh 
235*c43cad87SWarner Losh void
236*c43cad87SWarner Losh emap_deregister_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
237*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
238*c43cad87SWarner Losh 
239*c43cad87SWarner Losh 	assert(edata_slab_get(edata));
240*c43cad87SWarner Losh 	if (edata_size_get(edata) > (2 << LG_PAGE)) {
241*c43cad87SWarner Losh 		rtree_clear_range(tsdn, &emap->rtree, rtree_ctx,
242*c43cad87SWarner Losh 		    (uintptr_t)edata_base_get(edata) + PAGE,
243*c43cad87SWarner Losh 		    (uintptr_t)edata_last_get(edata) - PAGE);
244*c43cad87SWarner Losh 	}
245*c43cad87SWarner Losh }
246*c43cad87SWarner Losh 
247*c43cad87SWarner Losh void
248*c43cad87SWarner Losh emap_remap(tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind,
249*c43cad87SWarner Losh     bool slab) {
250*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
251*c43cad87SWarner Losh 
252*c43cad87SWarner Losh 	if (szind != SC_NSIZES) {
253*c43cad87SWarner Losh 		rtree_contents_t contents;
254*c43cad87SWarner Losh 		contents.edata = edata;
255*c43cad87SWarner Losh 		contents.metadata.szind = szind;
256*c43cad87SWarner Losh 		contents.metadata.slab = slab;
257*c43cad87SWarner Losh 		contents.metadata.is_head = edata_is_head_get(edata);
258*c43cad87SWarner Losh 		contents.metadata.state = edata_state_get(edata);
259*c43cad87SWarner Losh 
260*c43cad87SWarner Losh 		rtree_write(tsdn, &emap->rtree, rtree_ctx,
261*c43cad87SWarner Losh 		    (uintptr_t)edata_addr_get(edata), contents);
262*c43cad87SWarner Losh 		/*
263*c43cad87SWarner Losh 		 * Recall that this is called only for active->inactive and
264*c43cad87SWarner Losh 		 * inactive->active transitions (since only active extents have
265*c43cad87SWarner Losh 		 * meaningful values for szind and slab).  Active, non-slab
266*c43cad87SWarner Losh 		 * extents only need to handle lookups at their head (on
267*c43cad87SWarner Losh 		 * deallocation), so we don't bother filling in the end
268*c43cad87SWarner Losh 		 * boundary.
269*c43cad87SWarner Losh 		 *
270*c43cad87SWarner Losh 		 * For slab extents, we do the end-mapping change.  This still
271*c43cad87SWarner Losh 		 * leaves the interior unmodified; an emap_register_interior
272*c43cad87SWarner Losh 		 * call is coming in those cases, though.
273*c43cad87SWarner Losh 		 */
274*c43cad87SWarner Losh 		if (slab && edata_size_get(edata) > PAGE) {
275*c43cad87SWarner Losh 			uintptr_t key = (uintptr_t)edata_past_get(edata)
276*c43cad87SWarner Losh 			    - (uintptr_t)PAGE;
277*c43cad87SWarner Losh 			rtree_write(tsdn, &emap->rtree, rtree_ctx, key,
278*c43cad87SWarner Losh 			    contents);
279*c43cad87SWarner Losh 		}
280*c43cad87SWarner Losh 	}
281*c43cad87SWarner Losh }
282*c43cad87SWarner Losh 
283*c43cad87SWarner Losh bool
284*c43cad87SWarner Losh emap_split_prepare(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
285*c43cad87SWarner Losh     edata_t *edata, size_t size_a, edata_t *trail, size_t size_b) {
286*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
287*c43cad87SWarner Losh 
288*c43cad87SWarner Losh 	/*
289*c43cad87SWarner Losh 	 * We use incorrect constants for things like arena ind, zero, ranged,
290*c43cad87SWarner Losh 	 * and commit state, and head status.  This is a fake edata_t, used to
291*c43cad87SWarner Losh 	 * facilitate a lookup.
292*c43cad87SWarner Losh 	 */
293*c43cad87SWarner Losh 	edata_t lead = {0};
294*c43cad87SWarner Losh 	edata_init(&lead, 0U, edata_addr_get(edata), size_a, false, 0, 0,
295*c43cad87SWarner Losh 	    extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD);
296*c43cad87SWarner Losh 
297*c43cad87SWarner Losh 	emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, &lead, false, true,
298*c43cad87SWarner Losh 	    &prepare->lead_elm_a, &prepare->lead_elm_b);
299*c43cad87SWarner Losh 	emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, trail, false, true,
300*c43cad87SWarner Losh 	    &prepare->trail_elm_a, &prepare->trail_elm_b);
301*c43cad87SWarner Losh 
302*c43cad87SWarner Losh 	if (prepare->lead_elm_a == NULL || prepare->lead_elm_b == NULL
303*c43cad87SWarner Losh 	    || prepare->trail_elm_a == NULL || prepare->trail_elm_b == NULL) {
304*c43cad87SWarner Losh 		return true;
305*c43cad87SWarner Losh 	}
306*c43cad87SWarner Losh 	return false;
307*c43cad87SWarner Losh }
308*c43cad87SWarner Losh 
309*c43cad87SWarner Losh void
310*c43cad87SWarner Losh emap_split_commit(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
311*c43cad87SWarner Losh     edata_t *lead, size_t size_a, edata_t *trail, size_t size_b) {
312*c43cad87SWarner Losh 	/*
313*c43cad87SWarner Losh 	 * We should think about not writing to the lead leaf element.  We can
314*c43cad87SWarner Losh 	 * get into situations where a racing realloc-like call can disagree
315*c43cad87SWarner Losh 	 * with a size lookup request.  I think it's fine to declare that these
316*c43cad87SWarner Losh 	 * situations are race bugs, but there's an argument to be made that for
317*c43cad87SWarner Losh 	 * things like xallocx, a size lookup call should return either the old
318*c43cad87SWarner Losh 	 * size or the new size, but not anything else.
319*c43cad87SWarner Losh 	 */
320*c43cad87SWarner Losh 	emap_rtree_write_acquired(tsdn, emap, prepare->lead_elm_a,
321*c43cad87SWarner Losh 	    prepare->lead_elm_b, lead, SC_NSIZES, /* slab */ false);
322*c43cad87SWarner Losh 	emap_rtree_write_acquired(tsdn, emap, prepare->trail_elm_a,
323*c43cad87SWarner Losh 	    prepare->trail_elm_b, trail, SC_NSIZES, /* slab */ false);
324*c43cad87SWarner Losh }
325*c43cad87SWarner Losh 
326*c43cad87SWarner Losh void
327*c43cad87SWarner Losh emap_merge_prepare(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
328*c43cad87SWarner Losh     edata_t *lead, edata_t *trail) {
329*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
330*c43cad87SWarner Losh 	emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, lead, true, false,
331*c43cad87SWarner Losh 	    &prepare->lead_elm_a, &prepare->lead_elm_b);
332*c43cad87SWarner Losh 	emap_rtree_leaf_elms_lookup(tsdn, emap, rtree_ctx, trail, true, false,
333*c43cad87SWarner Losh 	    &prepare->trail_elm_a, &prepare->trail_elm_b);
334*c43cad87SWarner Losh }
335*c43cad87SWarner Losh 
336*c43cad87SWarner Losh void
337*c43cad87SWarner Losh emap_merge_commit(tsdn_t *tsdn, emap_t *emap, emap_prepare_t *prepare,
338*c43cad87SWarner Losh     edata_t *lead, edata_t *trail) {
339*c43cad87SWarner Losh 	rtree_contents_t clear_contents;
340*c43cad87SWarner Losh 	clear_contents.edata = NULL;
341*c43cad87SWarner Losh 	clear_contents.metadata.szind = SC_NSIZES;
342*c43cad87SWarner Losh 	clear_contents.metadata.slab = false;
343*c43cad87SWarner Losh 	clear_contents.metadata.is_head = false;
344*c43cad87SWarner Losh 	clear_contents.metadata.state = (extent_state_t)0;
345*c43cad87SWarner Losh 
346*c43cad87SWarner Losh 	if (prepare->lead_elm_b != NULL) {
347*c43cad87SWarner Losh 		rtree_leaf_elm_write(tsdn, &emap->rtree,
348*c43cad87SWarner Losh 		    prepare->lead_elm_b, clear_contents);
349*c43cad87SWarner Losh 	}
350*c43cad87SWarner Losh 
351*c43cad87SWarner Losh 	rtree_leaf_elm_t *merged_b;
352*c43cad87SWarner Losh 	if (prepare->trail_elm_b != NULL) {
353*c43cad87SWarner Losh 		rtree_leaf_elm_write(tsdn, &emap->rtree,
354*c43cad87SWarner Losh 		    prepare->trail_elm_a, clear_contents);
355*c43cad87SWarner Losh 		merged_b = prepare->trail_elm_b;
356*c43cad87SWarner Losh 	} else {
357*c43cad87SWarner Losh 		merged_b = prepare->trail_elm_a;
358*c43cad87SWarner Losh 	}
359*c43cad87SWarner Losh 
360*c43cad87SWarner Losh 	emap_rtree_write_acquired(tsdn, emap, prepare->lead_elm_a, merged_b,
361*c43cad87SWarner Losh 	    lead, SC_NSIZES, false);
362*c43cad87SWarner Losh }
363*c43cad87SWarner Losh 
364*c43cad87SWarner Losh void
365*c43cad87SWarner Losh emap_do_assert_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
366*c43cad87SWarner Losh 	EMAP_DECLARE_RTREE_CTX;
367*c43cad87SWarner Losh 
368*c43cad87SWarner Losh 	rtree_contents_t contents = rtree_read(tsdn, &emap->rtree, rtree_ctx,
369*c43cad87SWarner Losh 	    (uintptr_t)edata_base_get(edata));
370*c43cad87SWarner Losh 	assert(contents.edata == edata);
371*c43cad87SWarner Losh 	assert(contents.metadata.is_head == edata_is_head_get(edata));
372*c43cad87SWarner Losh 	assert(contents.metadata.state == edata_state_get(edata));
373*c43cad87SWarner Losh }
374*c43cad87SWarner Losh 
375*c43cad87SWarner Losh void
376*c43cad87SWarner Losh emap_do_assert_not_mapped(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
377*c43cad87SWarner Losh 	emap_full_alloc_ctx_t context1 = {0};
378*c43cad87SWarner Losh 	emap_full_alloc_ctx_try_lookup(tsdn, emap, edata_base_get(edata),
379*c43cad87SWarner Losh 	    &context1);
380*c43cad87SWarner Losh 	assert(context1.edata == NULL);
381*c43cad87SWarner Losh 
382*c43cad87SWarner Losh 	emap_full_alloc_ctx_t context2 = {0};
383*c43cad87SWarner Losh 	emap_full_alloc_ctx_try_lookup(tsdn, emap, edata_last_get(edata),
384*c43cad87SWarner Losh 	    &context2);
385*c43cad87SWarner Losh 	assert(context2.edata == NULL);
386*c43cad87SWarner Losh }
387