Line | Count | Source (jump to first uncovered line) |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the COPYING file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /*------------------------------------------------------------------------- |
14 | | * |
15 | | * Created: H5MF.c |
16 | | * |
17 | | * Purpose: File memory management functions. |
18 | | * |
19 | | *------------------------------------------------------------------------- |
20 | | */ |
21 | | |
22 | | /****************/ |
23 | | /* Module Setup */ |
24 | | /****************/ |
25 | | |
26 | | #define H5F_FRIEND /*suppress error about including H5Fpkg */ |
27 | | #define H5FS_FRIEND /*suppress error about including H5Fpkg */ |
28 | | #include "H5MFmodule.h" /* This source code file is part of the H5MF module */ |
29 | | |
30 | | /***********/ |
31 | | /* Headers */ |
32 | | /***********/ |
33 | | #include "H5private.h" /* Generic Functions */ |
34 | | #include "H5Eprivate.h" /* Error handling */ |
35 | | #include "H5Fpkg.h" /* File access */ |
36 | | #include "H5FSpkg.h" /* File free space */ |
37 | | #include "H5MFpkg.h" /* File memory management */ |
38 | | #include "H5VMprivate.h" /* Vectors and arrays */ |
39 | | |
40 | | /****************/ |
41 | | /* Local Macros */ |
42 | | /****************/ |
43 | | |
44 | 0 | #define H5MF_FSPACE_SHRINK 80 /* Percent of "normal" size to shrink serialized free space size */ |
45 | 0 | #define H5MF_FSPACE_EXPAND 120 /* Percent of "normal" size to expand serialized free space size */ |
46 | | |
47 | | #define H5MF_CHECK_FSM(FSM, CF) \ |
48 | 0 | do { \ |
49 | 0 | assert(*CF == false); \ |
50 | 0 | if (!H5_addr_defined(FSM->addr) || !H5_addr_defined(FSM->sect_addr)) \ |
51 | 0 | *CF = true; \ |
52 | 0 | } while (0) |
53 | | |
54 | | /* For non-paged aggregation: map allocation request type to tracked free-space type */ |
55 | | /* F_SH -- pointer to H5F_shared_t; T -- H5FD_mem_t */ |
56 | | #define H5MF_ALLOC_TO_FS_AGGR_TYPE(F_SH, T) \ |
57 | 0 | ((H5FD_MEM_DEFAULT == (F_SH)->fs_type_map[T]) ? (T) : (F_SH)->fs_type_map[T]) |
58 | | |
59 | | /******************/ |
60 | | /* Local Typedefs */ |
61 | | /******************/ |
62 | | |
63 | | /* Enum for kind of free space section+aggregator merging allowed for a file */ |
64 | | typedef enum { |
65 | | H5MF_AGGR_MERGE_SEPARATE, /* Everything in separate free list */ |
66 | | H5MF_AGGR_MERGE_DICHOTOMY, /* Metadata in one free list and raw data in another */ |
67 | | H5MF_AGGR_MERGE_TOGETHER /* Metadata & raw data in one free list */ |
68 | | } H5MF_aggr_merge_t; |
69 | | |
70 | | /* User data for section info iterator callback for iterating over free space sections */ |
71 | | typedef struct { |
72 | | H5F_sect_info_t *sects; /* section info to be retrieved */ |
73 | | size_t sect_count; /* # of sections requested */ |
74 | | size_t sect_idx; /* the current count of sections */ |
75 | | } H5MF_sect_iter_ud_t; |
76 | | |
77 | | /********************/ |
78 | | /* Package Typedefs */ |
79 | | /********************/ |
80 | | |
81 | | /********************/ |
82 | | /* Local Prototypes */ |
83 | | /********************/ |
84 | | |
85 | | /* Allocator routines */ |
86 | | static haddr_t H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size); |
87 | | |
88 | | /* "File closing" routines */ |
89 | | static herr_t H5MF__close_aggrfs(H5F_t *f); |
90 | | static herr_t H5MF__close_pagefs(H5F_t *f); |
91 | | static herr_t H5MF__close_shrink_eoa(H5F_t *f); |
92 | | |
93 | | /* General routines */ |
94 | | static herr_t H5MF__get_free_sects(H5F_t *f, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums); |
95 | | static bool H5MF__fsm_type_is_self_referential(H5F_shared_t *f_sh, H5F_mem_page_t fsm_type); |
96 | | static bool H5MF__fsm_is_self_referential(H5F_shared_t *f_sh, H5FS_t *fspace); |
97 | | static herr_t H5MF__continue_alloc_fsm(H5F_shared_t *f_sh, H5FS_t *sm_hdr_fspace, H5FS_t *sm_sinfo_fspace, |
98 | | H5FS_t *lg_hdr_fspace, H5FS_t *lg_sinfo_fspace, |
99 | | bool *continue_alloc_fsm); |
100 | | |
101 | | /* Free-space type manager routines */ |
102 | | static herr_t H5MF__create_fstype(H5F_t *f, H5F_mem_page_t type); |
103 | | static herr_t H5MF__close_fstype(H5F_t *f, H5F_mem_page_t type); |
104 | | static herr_t H5MF__delete_fstype(H5F_t *f, H5F_mem_page_t type); |
105 | | static herr_t H5MF__close_delete_fstype(H5F_t *f, H5F_mem_page_t type); |
106 | | |
107 | | /* Callbacks */ |
108 | | static herr_t H5MF__sects_cb(H5FS_section_info_t *_sect, void *_udata); |
109 | | |
110 | | /*********************/ |
111 | | /* Package Variables */ |
112 | | /*********************/ |
113 | | |
114 | | /*****************************/ |
115 | | /* Library Private Variables */ |
116 | | /*****************************/ |
117 | | |
118 | | /*******************/ |
119 | | /* Local Variables */ |
120 | | /*******************/ |
121 | | |
122 | | /*------------------------------------------------------------------------- |
123 | | * Function: H5MF_init_merge_flags |
124 | | * |
125 | | * Purpose: Initialize the free space section+aggregator merge flags |
126 | | * for the file. |
127 | | * |
128 | | * Return: SUCCEED/FAIL |
129 | | * |
130 | | *------------------------------------------------------------------------- |
131 | | */ |
132 | | herr_t |
133 | | H5MF_init_merge_flags(H5F_shared_t *f_sh) |
134 | 10 | { |
135 | 10 | H5MF_aggr_merge_t mapping_type; /* Type of free list mapping */ |
136 | 10 | H5FD_mem_t type; /* Memory type for iteration */ |
137 | 10 | bool all_same; /* Whether all the types map to the same value */ |
138 | 10 | herr_t ret_value = SUCCEED; /* Return value */ |
139 | | |
140 | 10 | FUNC_ENTER_NOAPI(FAIL) |
141 | | |
142 | | /* check args */ |
143 | 10 | assert(f_sh); |
144 | 10 | assert(f_sh->lf); |
145 | | |
146 | | /* Iterate over all the free space types to determine if sections of that type |
147 | | * can merge with the metadata or small 'raw' data aggregator |
148 | | */ |
149 | 10 | all_same = true; |
150 | 40 | for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) |
151 | | /* Check for any different type mappings */ |
152 | 40 | if (f_sh->fs_type_map[type] != f_sh->fs_type_map[H5FD_MEM_DEFAULT]) { |
153 | 10 | all_same = false; |
154 | 10 | break; |
155 | 10 | } /* end if */ |
156 | | |
157 | | /* Check for all allocation types mapping to the same free list type */ |
158 | 10 | if (all_same) { |
159 | 0 | if (f_sh->fs_type_map[H5FD_MEM_DEFAULT] == H5FD_MEM_DEFAULT) |
160 | 0 | mapping_type = H5MF_AGGR_MERGE_SEPARATE; |
161 | 0 | else |
162 | 0 | mapping_type = H5MF_AGGR_MERGE_TOGETHER; |
163 | 0 | } /* end if */ |
164 | 10 | else { |
165 | | /* Check for raw data mapping into same list as metadata */ |
166 | 10 | if (f_sh->fs_type_map[H5FD_MEM_DRAW] == f_sh->fs_type_map[H5FD_MEM_SUPER]) |
167 | 0 | mapping_type = H5MF_AGGR_MERGE_SEPARATE; |
168 | 10 | else { |
169 | 10 | bool all_metadata_same; /* Whether all metadata go in same free list */ |
170 | | |
171 | | /* One or more allocation type don't map to the same free list type */ |
172 | | /* Check if all the metadata allocation types map to the same type */ |
173 | 10 | all_metadata_same = true; |
174 | 70 | for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++) |
175 | | /* Skip checking raw data free list mapping */ |
176 | | /* (global heap is treated as raw data) */ |
177 | 60 | if (type != H5FD_MEM_DRAW && type != H5FD_MEM_GHEAP) { |
178 | | /* Check for any different type mappings */ |
179 | 40 | if (f_sh->fs_type_map[type] != f_sh->fs_type_map[H5FD_MEM_SUPER]) { |
180 | 0 | all_metadata_same = false; |
181 | 0 | break; |
182 | 0 | } /* end if */ |
183 | 40 | } /* end if */ |
184 | | |
185 | | /* Check for all metadata on same free list */ |
186 | 10 | if (all_metadata_same) |
187 | 10 | mapping_type = H5MF_AGGR_MERGE_DICHOTOMY; |
188 | 0 | else |
189 | 0 | mapping_type = H5MF_AGGR_MERGE_SEPARATE; |
190 | 10 | } /* end else */ |
191 | 10 | } /* end else */ |
192 | | |
193 | | /* Based on mapping type, initialize merging flags for each free list type */ |
194 | 10 | switch (mapping_type) { |
195 | 0 | case H5MF_AGGR_MERGE_SEPARATE: |
196 | | /* Don't merge any metadata together */ |
197 | 0 | memset(f_sh->fs_aggr_merge, 0, sizeof(f_sh->fs_aggr_merge)); |
198 | | |
199 | | /* Check if merging raw data should be allowed */ |
200 | | /* (treat global heaps as raw data) */ |
201 | 0 | if (H5FD_MEM_DRAW == f_sh->fs_type_map[H5FD_MEM_DRAW] || |
202 | 0 | H5FD_MEM_DEFAULT == f_sh->fs_type_map[H5FD_MEM_DRAW]) { |
203 | 0 | f_sh->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA; |
204 | 0 | f_sh->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA; |
205 | 0 | } /* end if */ |
206 | 0 | break; |
207 | | |
208 | 10 | case H5MF_AGGR_MERGE_DICHOTOMY: |
209 | | /* Merge all metadata together (but not raw data) */ |
210 | 10 | memset(f_sh->fs_aggr_merge, H5F_FS_MERGE_METADATA, sizeof(f_sh->fs_aggr_merge)); |
211 | | |
212 | | /* Allow merging raw data allocations together */ |
213 | | /* (treat global heaps as raw data) */ |
214 | 10 | f_sh->fs_aggr_merge[H5FD_MEM_DRAW] = H5F_FS_MERGE_RAWDATA; |
215 | 10 | f_sh->fs_aggr_merge[H5FD_MEM_GHEAP] = H5F_FS_MERGE_RAWDATA; |
216 | 10 | break; |
217 | | |
218 | 0 | case H5MF_AGGR_MERGE_TOGETHER: |
219 | | /* Merge all allocation types together */ |
220 | 0 | memset(f_sh->fs_aggr_merge, (H5F_FS_MERGE_METADATA | H5F_FS_MERGE_RAWDATA), |
221 | 0 | sizeof(f_sh->fs_aggr_merge)); |
222 | 0 | break; |
223 | | |
224 | 0 | default: |
225 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_BADVALUE, FAIL, "invalid mapping type"); |
226 | 10 | } /* end switch */ |
227 | | |
228 | 10 | done: |
229 | 10 | FUNC_LEAVE_NOAPI(ret_value) |
230 | 10 | } /* end H5MF_init_merge_flags() */ |
231 | | |
232 | | /*------------------------------------------------------------------------- |
233 | | * Function: H5MF__alloc_to_fs_type |
234 | | * |
235 | | * Purpose: Map "alloc_type" to the free-space manager type |
236 | | * |
237 | | * Return: Success: non-negative |
238 | | * Failure: negative |
239 | | * |
240 | | *------------------------------------------------------------------------- |
241 | | */ |
242 | | void |
243 | | H5MF__alloc_to_fs_type(H5F_shared_t *f_sh, H5FD_mem_t alloc_type, hsize_t size, H5F_mem_page_t *fs_type) |
244 | 0 | { |
245 | 0 | FUNC_ENTER_PACKAGE_NOERR |
246 | | |
247 | | /* Check arguments */ |
248 | 0 | assert(f_sh); |
249 | 0 | assert(fs_type); |
250 | |
|
251 | 0 | if (H5F_SHARED_PAGED_AGGR(f_sh)) { /* paged aggregation */ |
252 | 0 | if (size >= f_sh->fs_page_size) { |
253 | 0 | if (H5F_SHARED_HAS_FEATURE(f_sh, H5FD_FEAT_PAGED_AGGR)) { /* multi or split driver */ |
254 | | /* For non-contiguous address space, map to large size free-space manager for each alloc_type |
255 | | */ |
256 | 0 | if (H5FD_MEM_DEFAULT == f_sh->fs_type_map[alloc_type]) |
257 | 0 | *fs_type = (H5F_mem_page_t)(alloc_type + (H5FD_MEM_NTYPES - 1)); |
258 | 0 | else |
259 | 0 | *fs_type = (H5F_mem_page_t)(f_sh->fs_type_map[alloc_type] + (H5FD_MEM_NTYPES - 1)); |
260 | 0 | } /* end if */ |
261 | 0 | else |
262 | | /* For contiguous address space, map to generic large size free-space manager */ |
263 | 0 | *fs_type = H5F_MEM_PAGE_GENERIC; /* H5F_MEM_PAGE_SUPER */ |
264 | 0 | } /* end if */ |
265 | 0 | else |
266 | 0 | *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f_sh, alloc_type); |
267 | 0 | } /* end if */ |
268 | 0 | else /* non-paged aggregation */ |
269 | 0 | *fs_type = (H5F_mem_page_t)H5MF_ALLOC_TO_FS_AGGR_TYPE(f_sh, alloc_type); |
270 | |
|
271 | 0 | FUNC_LEAVE_NOAPI_VOID |
272 | 0 | } /* end H5MF__alloc_to_fs_type() */ |
273 | | |
274 | | /*------------------------------------------------------------------------- |
275 | | * Function: H5MF__open_fstype |
276 | | * |
277 | | * Purpose: Open an existing free space manager of TYPE for file by |
278 | | * creating a free-space structure. |
279 | | * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. |
280 | | * |
281 | | * Return: Success: non-negative |
282 | | * Failure: negative |
283 | | * |
284 | | *------------------------------------------------------------------------- |
285 | | */ |
286 | | herr_t |
287 | | H5MF__open_fstype(H5F_t *f, H5F_mem_page_t type) |
288 | 0 | { |
289 | 0 | const H5FS_section_class_t *classes[] = {/* Free space section classes implemented for file */ |
290 | 0 | H5MF_FSPACE_SECT_CLS_SIMPLE, H5MF_FSPACE_SECT_CLS_SMALL, |
291 | 0 | H5MF_FSPACE_SECT_CLS_LARGE}; |
292 | 0 | hsize_t alignment; /* Alignment to use */ |
293 | 0 | hsize_t threshold; /* Threshold to use */ |
294 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
295 | 0 | H5AC_ring_t fsm_ring; /* Ring of FSM */ |
296 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
297 | |
|
298 | 0 | FUNC_ENTER_PACKAGE_TAG(H5AC__FREESPACE_TAG) |
299 | | |
300 | | /* |
301 | | * Check arguments. |
302 | | */ |
303 | 0 | assert(f); |
304 | 0 | if (H5F_PAGED_AGGR(f)) |
305 | 0 | assert(type < H5F_MEM_PAGE_NTYPES); |
306 | 0 | else { |
307 | 0 | assert((H5FD_mem_t)type < H5FD_MEM_NTYPES); |
308 | 0 | assert((H5FD_mem_t)type != H5FD_MEM_NOLIST); |
309 | 0 | } /* end else */ |
310 | 0 | assert(f->shared); |
311 | 0 | assert(H5_addr_defined(f->shared->fs_addr[type])); |
312 | 0 | assert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED); |
313 | | |
314 | | /* Set up the alignment and threshold to use depending on the manager type */ |
315 | 0 | if (H5F_PAGED_AGGR(f)) { |
316 | 0 | alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF; |
317 | 0 | threshold = H5F_ALIGN_THRHD_DEF; |
318 | 0 | } /* end if */ |
319 | 0 | else { |
320 | 0 | alignment = f->shared->alignment; |
321 | 0 | threshold = f->shared->threshold; |
322 | 0 | } /* end else */ |
323 | | |
324 | | /* Set the ring type in the API context */ |
325 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, type)) |
326 | 0 | fsm_ring = H5AC_RING_MDFSM; |
327 | 0 | else |
328 | 0 | fsm_ring = H5AC_RING_RDFSM; |
329 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
330 | | |
331 | | /* Open an existing free space structure for the file */ |
332 | 0 | if (NULL == (f->shared->fs_man[type] = H5FS_open(f, f->shared->fs_addr[type], NELMTS(classes), classes, f, |
333 | 0 | alignment, threshold))) |
334 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info"); |
335 | | |
336 | | /* Set the state for the free space manager to "open", if it is now */ |
337 | 0 | if (f->shared->fs_man[type]) |
338 | 0 | f->shared->fs_state[type] = H5F_FS_STATE_OPEN; |
339 | |
|
340 | 0 | done: |
341 | | /* Reset the ring in the API context */ |
342 | 0 | if (orig_ring != H5AC_RING_INV) |
343 | 0 | H5AC_set_ring(orig_ring, NULL); |
344 | |
|
345 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
346 | 0 | } /* end H5MF__open_fstype() */ |
347 | | |
348 | | /*------------------------------------------------------------------------- |
349 | | * Function: H5MF__create_fstype |
350 | | * |
351 | | * Purpose: Create free space manager of TYPE for the file by creating |
352 | | * a free-space structure |
353 | | * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. |
354 | | * |
355 | | * Return: Success: non-negative |
356 | | * Failure: negative |
357 | | * |
358 | | *------------------------------------------------------------------------- |
359 | | */ |
360 | | static herr_t |
361 | | H5MF__create_fstype(H5F_t *f, H5F_mem_page_t type) |
362 | 0 | { |
363 | 0 | const H5FS_section_class_t *classes[] = {/* Free space section classes implemented for file */ |
364 | 0 | H5MF_FSPACE_SECT_CLS_SIMPLE, H5MF_FSPACE_SECT_CLS_SMALL, |
365 | 0 | H5MF_FSPACE_SECT_CLS_LARGE}; |
366 | 0 | H5FS_create_t fs_create; /* Free space creation parameters */ |
367 | 0 | hsize_t alignment; /* Alignment to use */ |
368 | 0 | hsize_t threshold; /* Threshold to use */ |
369 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
370 | 0 | H5AC_ring_t fsm_ring; /* Ring of FSM */ |
371 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
372 | |
|
373 | 0 | FUNC_ENTER_PACKAGE |
374 | | |
375 | | /* |
376 | | * Check arguments. |
377 | | */ |
378 | 0 | assert(f); |
379 | 0 | if (H5F_PAGED_AGGR(f)) |
380 | 0 | assert(type < H5F_MEM_PAGE_NTYPES); |
381 | 0 | else { |
382 | 0 | assert((H5FD_mem_t)type < H5FD_MEM_NTYPES); |
383 | 0 | assert((H5FD_mem_t)type != H5FD_MEM_NOLIST); |
384 | 0 | } /* end else */ |
385 | 0 | assert(f->shared); |
386 | 0 | assert(!H5_addr_defined(f->shared->fs_addr[type])); |
387 | 0 | assert(f->shared->fs_state[type] == H5F_FS_STATE_CLOSED); |
388 | | |
389 | | /* Set the free space creation parameters */ |
390 | 0 | fs_create.client = H5FS_CLIENT_FILE_ID; |
391 | 0 | fs_create.shrink_percent = H5MF_FSPACE_SHRINK; |
392 | 0 | fs_create.expand_percent = H5MF_FSPACE_EXPAND; |
393 | 0 | fs_create.max_sect_addr = 1 + H5VM_log2_gen((uint64_t)f->shared->maxaddr); |
394 | 0 | fs_create.max_sect_size = f->shared->maxaddr; |
395 | | |
396 | | /* Set up alignment and threshold to use depending on TYPE */ |
397 | 0 | if (H5F_PAGED_AGGR(f)) { |
398 | 0 | alignment = (type == H5F_MEM_PAGE_GENERIC) ? f->shared->fs_page_size : (hsize_t)H5F_ALIGN_DEF; |
399 | 0 | threshold = H5F_ALIGN_THRHD_DEF; |
400 | 0 | } /* end if */ |
401 | 0 | else { |
402 | 0 | alignment = f->shared->alignment; |
403 | 0 | threshold = f->shared->threshold; |
404 | 0 | } /* end else */ |
405 | | |
406 | | /* Set the ring type in the API context */ |
407 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, type)) |
408 | 0 | fsm_ring = H5AC_RING_MDFSM; |
409 | 0 | else |
410 | 0 | fsm_ring = H5AC_RING_RDFSM; |
411 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
412 | |
|
413 | 0 | if (NULL == (f->shared->fs_man[type] = |
414 | 0 | H5FS_create(f, NULL, &fs_create, NELMTS(classes), classes, f, alignment, threshold))) |
415 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space info"); |
416 | | |
417 | | /* Set the state for the free space manager to "open", if it is now */ |
418 | 0 | if (f->shared->fs_man[type]) |
419 | 0 | f->shared->fs_state[type] = H5F_FS_STATE_OPEN; |
420 | |
|
421 | 0 | done: |
422 | | /* Reset the ring in the API context */ |
423 | 0 | if (orig_ring != H5AC_RING_INV) |
424 | 0 | H5AC_set_ring(orig_ring, NULL); |
425 | |
|
426 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
427 | 0 | } /* end H5MF__create_fstype() */ |
428 | | |
429 | | /*------------------------------------------------------------------------- |
430 | | * Function: H5MF__start_fstype |
431 | | * |
432 | | * Purpose: Open or create a free space manager of a given TYPE. |
433 | | * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. |
434 | | * |
435 | | * Return: Success: non-negative |
436 | | * Failure: negative |
437 | | * |
438 | | *------------------------------------------------------------------------- |
439 | | */ |
440 | | herr_t |
441 | | H5MF__start_fstype(H5F_t *f, H5F_mem_page_t type) |
442 | 0 | { |
443 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
444 | |
|
445 | 0 | FUNC_ENTER_PACKAGE |
446 | | |
447 | | /* |
448 | | * Check arguments. |
449 | | */ |
450 | 0 | assert(f); |
451 | 0 | assert(f->shared); |
452 | 0 | if (H5F_PAGED_AGGR(f)) |
453 | 0 | assert(type < H5F_MEM_PAGE_NTYPES); |
454 | 0 | else { |
455 | 0 | assert((H5FD_mem_t)type < H5FD_MEM_NTYPES); |
456 | 0 | assert((H5FD_mem_t)type != H5FD_MEM_NOLIST); |
457 | 0 | } /* end else */ |
458 | | |
459 | | /* Check if the free space manager exists already */ |
460 | 0 | if (H5_addr_defined(f->shared->fs_addr[type])) { |
461 | | /* Open existing free space manager */ |
462 | 0 | if (H5MF__open_fstype(f, type) < 0) |
463 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, FAIL, "can't initialize file free space"); |
464 | 0 | } /* end if */ |
465 | 0 | else { |
466 | | /* Create new free space manager */ |
467 | 0 | if (H5MF__create_fstype(f, type) < 0) |
468 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCREATE, FAIL, "can't initialize file free space"); |
469 | 0 | } /* end else */ |
470 | | |
471 | 0 | done: |
472 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
473 | 0 | } /* end H5MF__start_fstype() */ |
474 | | |
475 | | /*------------------------------------------------------------------------- |
476 | | * Function: H5MF__delete_fstype |
477 | | * |
478 | | * Purpose: Delete the free-space manager as specified by TYPE. |
479 | | * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. |
480 | | * |
481 | | * Return: Success: non-negative |
482 | | * Failure: negative |
483 | | * |
484 | | *------------------------------------------------------------------------- |
485 | | */ |
486 | | static herr_t |
487 | | H5MF__delete_fstype(H5F_t *f, H5F_mem_page_t type) |
488 | 0 | { |
489 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
490 | 0 | H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of FSM */ |
491 | 0 | haddr_t tmp_fs_addr; /* Temporary holder for free space manager address */ |
492 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
493 | |
|
494 | 0 | FUNC_ENTER_PACKAGE |
495 | | |
496 | | /* check args */ |
497 | 0 | assert(f); |
498 | 0 | if (H5F_PAGED_AGGR(f)) |
499 | 0 | assert(type < H5F_MEM_PAGE_NTYPES); |
500 | 0 | else |
501 | 0 | assert((H5FD_mem_t)type < H5FD_MEM_NTYPES); |
502 | 0 | assert(H5_addr_defined(f->shared->fs_addr[type])); |
503 | | |
504 | | /* Put address into temporary variable and reset it */ |
505 | | /* (Avoids loopback in file space freeing routine) */ |
506 | 0 | tmp_fs_addr = f->shared->fs_addr[type]; |
507 | 0 | f->shared->fs_addr[type] = HADDR_UNDEF; |
508 | | |
509 | | /* Shift to "deleting" state, to make certain we don't track any |
510 | | * file space freed as a result of deleting the free space manager. |
511 | | */ |
512 | 0 | f->shared->fs_state[type] = H5F_FS_STATE_DELETING; |
513 | | |
514 | | /* Set the ring type in the API context */ |
515 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, type)) |
516 | 0 | fsm_ring = H5AC_RING_MDFSM; |
517 | 0 | else |
518 | 0 | fsm_ring = H5AC_RING_RDFSM; |
519 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
520 | |
|
521 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
522 | | fprintf(stderr, "%s: Before deleting free space manager\n", __func__); |
523 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
524 | | |
525 | | /* Delete free space manager for this type */ |
526 | 0 | if (H5FS_delete(f, tmp_fs_addr) < 0) |
527 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't delete free space manager"); |
528 | | |
529 | | /* Shift [back] to closed state */ |
530 | 0 | assert(f->shared->fs_state[type] == H5F_FS_STATE_DELETING); |
531 | 0 | f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; |
532 | | |
533 | | /* Sanity check that the free space manager for this type wasn't started up again */ |
534 | 0 | assert(!H5_addr_defined(f->shared->fs_addr[type])); |
535 | |
|
536 | 0 | done: |
537 | | /* Reset the ring in the API context */ |
538 | 0 | if (orig_ring != H5AC_RING_INV) |
539 | 0 | H5AC_set_ring(orig_ring, NULL); |
540 | |
|
541 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
542 | 0 | } /* end H5MF__delete_fstype() */ |
543 | | |
544 | | /*------------------------------------------------------------------------- |
545 | | * Function: H5MF__close_fstype |
546 | | * |
547 | | * Purpose: Close the free space manager of TYPE for file |
548 | | * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. |
549 | | * |
550 | | * Return: Success: non-negative |
551 | | * Failure: negative |
552 | | * |
553 | | *------------------------------------------------------------------------- |
554 | | */ |
555 | | static herr_t |
556 | | H5MF__close_fstype(H5F_t *f, H5F_mem_page_t type) |
557 | 0 | { |
558 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
559 | |
|
560 | 0 | FUNC_ENTER_PACKAGE |
561 | | |
562 | | /* |
563 | | * Check arguments. |
564 | | */ |
565 | 0 | assert(f); |
566 | 0 | if (H5F_PAGED_AGGR(f)) |
567 | 0 | assert(type < H5F_MEM_PAGE_NTYPES); |
568 | 0 | else |
569 | 0 | assert((H5FD_mem_t)type < H5FD_MEM_NTYPES); |
570 | 0 | assert(f->shared); |
571 | 0 | assert(f->shared->fs_man[type]); |
572 | 0 | assert(f->shared->fs_state[type] != H5F_FS_STATE_CLOSED); |
573 | |
|
574 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
575 | | fprintf(stderr, "%s: Before closing free space manager\n", __func__); |
576 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
577 | | |
578 | | /* Close an existing free space structure for the file */ |
579 | 0 | if (H5FS_close(f, f->shared->fs_man[type]) < 0) |
580 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't release free space info"); |
581 | 0 | f->shared->fs_man[type] = NULL; |
582 | 0 | f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; |
583 | |
|
584 | 0 | done: |
585 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
586 | 0 | } /* end H5MF__close_fstype() */ |
587 | | |
588 | | /*------------------------------------------------------------------------- |
589 | | * Function: H5MF__add_sect |
590 | | * |
591 | | * Purpose: To add a section to the specified free-space manager. |
592 | | * |
593 | | * Return: Success: non-negative |
594 | | * Failure: negative |
595 | | * |
596 | | *------------------------------------------------------------------------- |
597 | | */ |
598 | | herr_t |
599 | | H5MF__add_sect(H5F_t *f, H5FD_mem_t alloc_type, H5FS_t *fspace, H5MF_free_section_t *node) |
600 | 0 | { |
601 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
602 | 0 | H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of FSM */ |
603 | 0 | H5MF_sect_ud_t udata; /* User data for callback */ |
604 | 0 | H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */ |
605 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
606 | |
|
607 | 0 | FUNC_ENTER_PACKAGE |
608 | |
|
609 | 0 | assert(f); |
610 | 0 | assert(fspace); |
611 | 0 | assert(node); |
612 | |
|
613 | 0 | H5MF__alloc_to_fs_type(f->shared, alloc_type, node->sect_info.size, &fs_type); |
614 | | |
615 | | /* Construct user data for callbacks */ |
616 | 0 | udata.f = f; |
617 | 0 | udata.alloc_type = alloc_type; |
618 | 0 | udata.allow_sect_absorb = true; |
619 | 0 | udata.allow_eoa_shrink_only = false; |
620 | | |
621 | | /* Set the ring type in the API context */ |
622 | 0 | if (H5MF__fsm_is_self_referential(f->shared, fspace)) |
623 | 0 | fsm_ring = H5AC_RING_MDFSM; |
624 | 0 | else |
625 | 0 | fsm_ring = H5AC_RING_RDFSM; |
626 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
627 | |
|
628 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
629 | | fprintf(stderr, |
630 | | "%s: adding node, node->sect_info.addr = %" PRIuHADDR ", node->sect_info.size = %" PRIuHSIZE "\n", |
631 | | __func__, node->sect_info.addr, node->sect_info.size); |
632 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
633 | | /* Add the section */ |
634 | 0 | if (H5FS_sect_add(f, fspace, (H5FS_section_info_t *)node, H5FS_ADD_RETURNED_SPACE, &udata) < 0) |
635 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space"); |
636 | | |
637 | 0 | done: |
638 | | /* Reset the ring in the API context */ |
639 | 0 | if (orig_ring != H5AC_RING_INV) |
640 | 0 | H5AC_set_ring(orig_ring, NULL); |
641 | |
|
642 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
643 | 0 | } /* end H5MF__add_sect() */ |
644 | | |
645 | | /*------------------------------------------------------------------------- |
646 | | * Function: H5MF__find_sect |
647 | | * |
648 | | * Purpose: To find a section from the specified free-space manager to fulfill the request. |
649 | | * If found, re-add the left-over space back to the manager. |
650 | | * |
651 | | * Return: true if a section is found to fulfill the request |
652 | | * false if not |
653 | | * |
654 | | *------------------------------------------------------------------------- |
655 | | */ |
656 | | htri_t |
657 | | H5MF__find_sect(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size, H5FS_t *fspace, haddr_t *addr) |
658 | 0 | { |
659 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
660 | 0 | H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of FSM */ |
661 | 0 | H5MF_free_section_t *node; /* Free space section pointer */ |
662 | 0 | htri_t ret_value = FAIL; /* Whether an existing free list node was found */ |
663 | |
|
664 | 0 | FUNC_ENTER_PACKAGE |
665 | |
|
666 | 0 | assert(f); |
667 | 0 | assert(fspace); |
668 | | |
669 | | /* Set the ring type in the API context */ |
670 | 0 | if (H5MF__fsm_is_self_referential(f->shared, fspace)) |
671 | 0 | fsm_ring = H5AC_RING_MDFSM; |
672 | 0 | else |
673 | 0 | fsm_ring = H5AC_RING_RDFSM; |
674 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
675 | | |
676 | | /* Try to get a section from the free space manager */ |
677 | 0 | if ((ret_value = H5FS_sect_find(f, fspace, size, (H5FS_section_info_t **)&node)) < 0) |
678 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "error locating free space in file"); |
679 | | |
680 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
681 | | fprintf(stderr, "%s: section found = %d\n", __func__, ret_value); |
682 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
683 | | |
684 | | /* Check for actually finding section */ |
685 | 0 | if (ret_value) { |
686 | | /* Sanity check */ |
687 | 0 | assert(node); |
688 | | |
689 | | /* Retrieve return value */ |
690 | 0 | if (addr) |
691 | 0 | *addr = node->sect_info.addr; |
692 | | |
693 | | /* Check for eliminating the section */ |
694 | 0 | if (node->sect_info.size == size) { |
695 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
696 | | fprintf(stderr, "%s: freeing node\n", __func__); |
697 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
698 | | |
699 | | /* Free section node */ |
700 | 0 | if (H5MF__sect_free((H5FS_section_info_t *)node) < 0) |
701 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node"); |
702 | 0 | } /* end if */ |
703 | 0 | else { |
704 | | /* Adjust information for section */ |
705 | 0 | node->sect_info.addr += size; |
706 | 0 | node->sect_info.size -= size; |
707 | |
|
708 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
709 | | fprintf(stderr, "%s: re-adding node, node->sect_info.size = %" PRIuHSIZE "\n", __func__, |
710 | | node->sect_info.size); |
711 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
712 | | |
713 | | /* Re-add the section to the free-space manager */ |
714 | 0 | if (H5MF__add_sect(f, alloc_type, fspace, node) < 0) |
715 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space"); |
716 | 0 | } /* end else */ |
717 | 0 | } /* end if */ |
718 | | |
719 | 0 | done: |
720 | | /* Reset the ring in the API context */ |
721 | 0 | if (orig_ring != H5AC_RING_INV) |
722 | 0 | H5AC_set_ring(orig_ring, NULL); |
723 | |
|
724 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
725 | 0 | } /* end H5MF__find_sect() */ |
726 | | |
727 | | /*------------------------------------------------------------------------- |
728 | | * Function: H5MF_alloc |
729 | | * |
730 | | * Purpose: Allocate SIZE bytes of file memory and return the relative |
731 | | * address where that contiguous chunk of file memory exists. |
732 | | * The TYPE argument describes the purpose for which the storage |
733 | | * is being requested. |
734 | | * |
735 | | * Return: Success: The file address of new chunk. |
736 | | * Failure: HADDR_UNDEF |
737 | | * |
738 | | *------------------------------------------------------------------------- |
739 | | */ |
740 | | haddr_t |
741 | | H5MF_alloc(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size) |
742 | 0 | { |
743 | 0 | H5AC_ring_t fsm_ring = H5AC_RING_INV; /* free space manager ring */ |
744 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
745 | 0 | H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */ |
746 | 0 | haddr_t ret_value = HADDR_UNDEF; /* Return value */ |
747 | |
|
748 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, HADDR_UNDEF) |
749 | | #ifdef H5MF_ALLOC_DEBUG |
750 | | fprintf(stderr, "%s: alloc_type = %u, size = %" PRIuHSIZE "\n", __func__, (unsigned)alloc_type, size); |
751 | | #endif /* H5MF_ALLOC_DEBUG */ |
752 | | |
753 | | /* check arguments */ |
754 | 0 | assert(f); |
755 | 0 | assert(f->shared); |
756 | 0 | assert(f->shared->lf); |
757 | 0 | assert(size > 0); |
758 | |
|
759 | 0 | H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type); |
760 | |
|
761 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
762 | | fprintf(stderr, "%s: Check 1.0\n", __func__); |
763 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
764 | | |
765 | | /* Set the ring type in the API context */ |
766 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, fs_type)) |
767 | 0 | fsm_ring = H5AC_RING_MDFSM; |
768 | 0 | else |
769 | 0 | fsm_ring = H5AC_RING_RDFSM; |
770 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
771 | | |
772 | | /* Check if we are using the free space manager for this file */ |
773 | 0 | if (H5F_HAVE_FREE_SPACE_MANAGER(f)) { |
774 | | /* We are about to change the contents of the free space manager -- |
775 | | * notify metadata cache that the associated fsm ring is |
776 | | * unsettled |
777 | | */ |
778 | 0 | if (H5AC_unsettle_ring(f, fsm_ring) < 0) |
779 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, HADDR_UNDEF, |
780 | 0 | "attempt to notify cache that ring is unsettled failed"); |
781 | | |
782 | | /* Check if the free space manager for the file has been initialized */ |
783 | 0 | if (!f->shared->fs_man[fs_type] && H5_addr_defined(f->shared->fs_addr[fs_type])) { |
784 | | /* Open the free-space manager */ |
785 | 0 | if (H5MF__open_fstype(f, fs_type) < 0) |
786 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTOPENOBJ, HADDR_UNDEF, "can't initialize file free space"); |
787 | 0 | assert(f->shared->fs_man[fs_type]); |
788 | 0 | } /* end if */ |
789 | | |
790 | | /* Search for large enough space in the free space manager */ |
791 | 0 | if (f->shared->fs_man[fs_type]) |
792 | 0 | if (H5MF__find_sect(f, alloc_type, size, f->shared->fs_man[fs_type], &ret_value) < 0) |
793 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "error locating a node"); |
794 | 0 | } /* end if */ |
795 | | |
796 | | /* If no space is found from the free-space manager, continue further action */ |
797 | 0 | if (!H5_addr_defined(ret_value)) { |
798 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
799 | | fprintf(stderr, "%s: Check 2.0\n", __func__); |
800 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
801 | 0 | if (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_PAGE) { |
802 | 0 | assert(f->shared->fs_page_size >= H5F_FILE_SPACE_PAGE_SIZE_MIN); |
803 | 0 | if (HADDR_UNDEF == (ret_value = H5MF__alloc_pagefs(f, alloc_type, size))) |
804 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, |
805 | 0 | "allocation failed from paged aggregation"); |
806 | 0 | } /* end if */ |
807 | 0 | else { /* For non-paged aggregation, continue further action */ |
808 | 0 | if (HADDR_UNDEF == (ret_value = H5MF_aggr_vfd_alloc(f, alloc_type, size))) |
809 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "allocation failed from aggr/vfd"); |
810 | 0 | } /* end else */ |
811 | 0 | } /* end if */ |
812 | 0 | assert(H5_addr_defined(ret_value)); |
813 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
814 | | fprintf(stderr, "%s: Check 3.0\n", __func__); |
815 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
816 | |
|
817 | 0 | done: |
818 | | /* Reset the ring in the API context */ |
819 | 0 | if (orig_ring != H5AC_RING_INV) |
820 | 0 | H5AC_set_ring(orig_ring, NULL); |
821 | |
|
822 | | #ifdef H5MF_ALLOC_DEBUG |
823 | | fprintf(stderr, "%s: Leaving: ret_value = %" PRIuHADDR ", size = %" PRIuHSIZE "\n", __func__, ret_value, |
824 | | size); |
825 | | #endif /* H5MF_ALLOC_DEBUG */ |
826 | | #ifdef H5MF_ALLOC_DEBUG_DUMP |
827 | | H5MF__sects_dump(f, stderr); |
828 | | #endif /* H5MF_ALLOC_DEBUG_DUMP */ |
829 | |
|
830 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
831 | 0 | } /* end H5MF_alloc() */ |
832 | | |
833 | | /*------------------------------------------------------------------------- |
834 | | * Function: H5MF__alloc_pagefs |
835 | | * |
836 | | * Purpose: Allocate space from either the large or small free-space manager. |
837 | | * For "large" request: |
838 | | * Allocate request from VFD |
839 | | * Determine mis-aligned fragment and return the fragment to the |
840 | | * appropriate manager |
841 | | * For "small" request: |
842 | | * Allocate a page from the large manager |
843 | | * Determine whether space is available from a mis-aligned fragment |
844 | | * being returned to the manager |
845 | | * Return left-over space to the manager after fulfilling request |
846 | | * |
847 | | * Return: Success: The file address of new chunk. |
848 | | * Failure: HADDR_UNDEF |
849 | | * |
850 | | *------------------------------------------------------------------------- |
851 | | */ |
852 | | static haddr_t |
853 | | H5MF__alloc_pagefs(H5F_t *f, H5FD_mem_t alloc_type, hsize_t size) |
854 | 0 | { |
855 | 0 | H5F_mem_page_t ptype; /* Free-space manager type */ |
856 | 0 | H5MF_free_section_t *node = NULL; /* Free space section pointer */ |
857 | 0 | haddr_t ret_value = HADDR_UNDEF; /* Return value */ |
858 | |
|
859 | 0 | FUNC_ENTER_PACKAGE |
860 | |
|
861 | | #ifdef H5MF_ALLOC_DEBUG |
862 | | fprintf(stderr, "%s: alloc_type = %u, size = %" PRIuHSIZE "\n", __func__, (unsigned)alloc_type, size); |
863 | | #endif /* H5MF_ALLOC_DEBUG */ |
864 | |
|
865 | 0 | H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &ptype); |
866 | |
|
867 | 0 | switch (ptype) { |
868 | 0 | case H5F_MEM_PAGE_GENERIC: |
869 | 0 | case H5F_MEM_PAGE_LARGE_BTREE: |
870 | 0 | case H5F_MEM_PAGE_LARGE_DRAW: |
871 | 0 | case H5F_MEM_PAGE_LARGE_GHEAP: |
872 | 0 | case H5F_MEM_PAGE_LARGE_LHEAP: |
873 | 0 | case H5F_MEM_PAGE_LARGE_OHDR: { |
874 | 0 | haddr_t eoa; /* EOA for the file */ |
875 | 0 | hsize_t frag_size = 0; /* Fragment size */ |
876 | | |
877 | | /* Get the EOA for the file */ |
878 | 0 | if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type))) |
879 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "Unable to get eoa"); |
880 | 0 | assert(!(eoa % f->shared->fs_page_size)); |
881 | |
|
882 | 0 | H5MF_EOA_MISALIGN(f, (eoa + size), f->shared->fs_page_size, frag_size); |
883 | | |
884 | | /* Allocate from VFD */ |
885 | 0 | if (HADDR_UNDEF == (ret_value = H5F__alloc(f, alloc_type, size + frag_size, NULL, NULL))) |
886 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space"); |
887 | | |
888 | | /* If there is a mis-aligned fragment at EOA */ |
889 | 0 | if (frag_size) { |
890 | | |
891 | | /* Start up the free-space manager */ |
892 | 0 | if (!(f->shared->fs_man[ptype])) |
893 | 0 | if (H5MF__start_fstype(f, ptype) < 0) |
894 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, |
895 | 0 | "can't initialize file free space"); |
896 | | |
897 | | /* Create free space section for the fragment */ |
898 | 0 | if (NULL == (node = H5MF__sect_new(H5MF_FSPACE_SECT_LARGE, ret_value + size, frag_size))) |
899 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, |
900 | 0 | "can't initialize free space section"); |
901 | | |
902 | | /* Add the fragment to the large free-space manager */ |
903 | 0 | if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[ptype], node) < 0) |
904 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, |
905 | 0 | "can't re-add section to file free space"); |
906 | | |
907 | 0 | node = NULL; |
908 | 0 | } /* end if */ |
909 | 0 | } break; |
910 | | |
911 | 0 | case H5F_MEM_PAGE_META: |
912 | 0 | case H5F_MEM_PAGE_DRAW: |
913 | 0 | case H5F_MEM_PAGE_BTREE: |
914 | 0 | case H5F_MEM_PAGE_GHEAP: |
915 | 0 | case H5F_MEM_PAGE_LHEAP: |
916 | 0 | case H5F_MEM_PAGE_OHDR: { |
917 | 0 | haddr_t new_page; /* The address for the new file size page */ |
918 | | |
919 | | /* Allocate one file space page */ |
920 | 0 | if (HADDR_UNDEF == (new_page = H5MF_alloc(f, alloc_type, f->shared->fs_page_size))) |
921 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, "can't allocate file space"); |
922 | | |
923 | | /* Start up the free-space manager */ |
924 | 0 | if (!(f->shared->fs_man[ptype])) |
925 | 0 | if (H5MF__start_fstype(f, ptype) < 0) |
926 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize file free space"); |
927 | 0 | assert(f->shared->fs_man[ptype]); |
928 | |
|
929 | 0 | if (NULL == (node = H5MF__sect_new(H5MF_FSPACE_SECT_SMALL, (new_page + size), |
930 | 0 | (f->shared->fs_page_size - size)))) |
931 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, HADDR_UNDEF, "can't initialize free space section"); |
932 | | |
933 | | /* Add the remaining space in the page to the manager */ |
934 | 0 | if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[ptype], node) < 0) |
935 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, |
936 | 0 | "can't re-add section to file free space"); |
937 | | |
938 | 0 | node = NULL; |
939 | | |
940 | | /* Insert the new page into the Page Buffer list of new pages so |
941 | | we don't read an empty page from disk */ |
942 | 0 | if (f->shared->page_buf != NULL && H5PB_add_new_page(f->shared, alloc_type, new_page) < 0) |
943 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, HADDR_UNDEF, |
944 | 0 | "can't add new page to Page Buffer new page list"); |
945 | | |
946 | 0 | ret_value = new_page; |
947 | 0 | } break; |
948 | | |
949 | 0 | case H5F_MEM_PAGE_NTYPES: |
950 | 0 | case H5F_MEM_PAGE_DEFAULT: |
951 | 0 | default: |
952 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, HADDR_UNDEF, |
953 | 0 | "can't allocate file space: unrecognized type"); |
954 | 0 | break; |
955 | 0 | } /* end switch */ |
956 | | |
957 | 0 | done: |
958 | | #ifdef H5MF_ALLOC_DEBUG |
959 | | fprintf(stderr, "%s: Leaving: ret_value = %" PRIuHADDR ", size = %" PRIuHSIZE "\n", __func__, ret_value, |
960 | | size); |
961 | | #endif /* H5MF_ALLOC_DEBUG */ |
962 | | #ifdef H5MF_ALLOC_DEBUG_DUMP |
963 | | H5MF__sects_dump(f, stderr); |
964 | | #endif /* H5MF_ALLOC_DEBUG_DUMP */ |
965 | | |
966 | | /* Release section node, if allocated and not added to section list or merged */ |
967 | 0 | if (node) |
968 | 0 | if (H5MF__sect_free((H5FS_section_info_t *)node) < 0) |
969 | 0 | HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, HADDR_UNDEF, "can't free section node"); |
970 | |
|
971 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
972 | 0 | } /* end H5MF__alloc_pagefs() */ |
973 | | |
974 | | /*------------------------------------------------------------------------- |
975 | | * Function: H5MF_alloc_tmp |
976 | | * |
977 | | * Purpose: Allocate temporary space in the file |
978 | | * |
979 | | * Note: The address returned is non-overlapping with any other address |
980 | | * in the file and suitable for insertion into the metadata |
981 | | * cache. |
982 | | * |
983 | | * The address is _not_ suitable for actual file I/O and will |
984 | | * cause an error if it is so used. |
985 | | * |
986 | | * The space allocated with this routine should _not_ be freed, |
987 | | * it should just be abandoned. Calling H5MF_xfree() with space |
988 | | * from this routine will cause an error. |
989 | | * |
990 | | * Return: Success: Temporary file address |
991 | | * Failure: HADDR_UNDEF |
992 | | * |
993 | | *------------------------------------------------------------------------- |
994 | | */ |
995 | | haddr_t |
996 | | H5MF_alloc_tmp(H5F_t *f, hsize_t size) |
997 | 0 | { |
998 | 0 | haddr_t eoa; /* End of allocated space in the file */ |
999 | 0 | haddr_t ret_value = HADDR_UNDEF; /* Return value */ |
1000 | |
|
1001 | 0 | FUNC_ENTER_NOAPI(HADDR_UNDEF) |
1002 | | #ifdef H5MF_ALLOC_DEBUG |
1003 | | fprintf(stderr, "%s: size = %" PRIuHSIZE "\n", __func__, size); |
1004 | | #endif /* H5MF_ALLOC_DEBUG */ |
1005 | | |
1006 | | /* check args */ |
1007 | 0 | assert(f); |
1008 | 0 | assert(f->shared); |
1009 | 0 | assert(f->shared->lf); |
1010 | 0 | assert(size > 0); |
1011 | | |
1012 | | /* Retrieve the 'eoa' for the file */ |
1013 | 0 | if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, H5FD_MEM_DEFAULT))) |
1014 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed"); |
1015 | | |
1016 | | /* Compute value to return */ |
1017 | 0 | ret_value = f->shared->tmp_addr - size; |
1018 | | |
1019 | | /* Check for overlap into the actual allocated space in the file */ |
1020 | 0 | if (H5_addr_le(ret_value, eoa)) |
1021 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, HADDR_UNDEF, "driver get_eoa request failed"); |
1022 | | |
1023 | | /* Adjust temporary address allocator in the file */ |
1024 | 0 | f->shared->tmp_addr = ret_value; |
1025 | |
|
1026 | 0 | done: |
1027 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1028 | 0 | } /* end H5MF_alloc_tmp() */ |
1029 | | |
1030 | | /*------------------------------------------------------------------------- |
1031 | | * Function: H5MF_xfree |
1032 | | * |
1033 | | * Purpose: Frees part of a file, making that part of the file |
1034 | | * available for reuse. |
1035 | | * |
1036 | | * Return: Non-negative on success/Negative on failure |
1037 | | * |
1038 | | *------------------------------------------------------------------------- |
1039 | | */ |
1040 | | herr_t |
1041 | | H5MF_xfree(H5F_t *f, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size) |
1042 | 0 | { |
1043 | 0 | H5F_mem_page_t fs_type; /* Free space type (mapped from allocation type) */ |
1044 | 0 | H5MF_free_section_t *node = NULL; /* Free space section pointer */ |
1045 | 0 | unsigned ctype; /* section class type */ |
1046 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
1047 | 0 | H5AC_ring_t fsm_ring; /* Ring of FSM */ |
1048 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1049 | |
|
1050 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
1051 | | #ifdef H5MF_ALLOC_DEBUG |
1052 | | fprintf(stderr, "%s: Entering - alloc_type = %u, addr = %" PRIuHADDR ", size = %" PRIuHSIZE "\n", |
1053 | | __func__, (unsigned)alloc_type, addr, size); |
1054 | | #endif /* H5MF_ALLOC_DEBUG */ |
1055 | | |
1056 | | /* check arguments */ |
1057 | 0 | assert(f); |
1058 | 0 | if (!H5_addr_defined(addr) || 0 == size) |
1059 | 0 | HGOTO_DONE(SUCCEED); |
1060 | 0 | assert(addr != 0); /* Can't deallocate the superblock :-) */ |
1061 | |
|
1062 | 0 | H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type); |
1063 | | |
1064 | | /* Set the ring type in the API context */ |
1065 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, fs_type)) |
1066 | 0 | fsm_ring = H5AC_RING_MDFSM; |
1067 | 0 | else |
1068 | 0 | fsm_ring = H5AC_RING_RDFSM; |
1069 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
1070 | | |
1071 | | /* we are about to change the contents of the free space manager -- |
1072 | | * notify metadata cache that the associated fsm ring is |
1073 | | * unsettled |
1074 | | */ |
1075 | | /* Only do so for strategies that use free-space managers */ |
1076 | 0 | if (H5F_HAVE_FREE_SPACE_MANAGER(f)) |
1077 | 0 | if (H5AC_unsettle_ring(f, fsm_ring) < 0) |
1078 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_SYSTEM, FAIL, |
1079 | 0 | "attempt to notify cache that ring is unsettled failed"); |
1080 | | |
1081 | | /* Check for attempting to free space that's a 'temporary' file address */ |
1082 | 0 | if (H5_addr_le(f->shared->tmp_addr, addr)) |
1083 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_BADRANGE, FAIL, "attempting to free temporary file space"); |
1084 | | |
1085 | | /* If it's metadata, check if the space to free intersects with the file's |
1086 | | * metadata accumulator |
1087 | | */ |
1088 | 0 | if (H5FD_MEM_DRAW != alloc_type) { |
1089 | | /* Check if the space to free intersects with the file's metadata accumulator */ |
1090 | 0 | if (H5F__accum_free(f->shared, alloc_type, addr, size) < 0) |
1091 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, |
1092 | 0 | "can't check free space intersection w/metadata accumulator"); |
1093 | 0 | } /* end if */ |
1094 | | |
1095 | | /* Check if the free space manager for the file has been initialized */ |
1096 | 0 | if (!f->shared->fs_man[fs_type]) { |
1097 | | /* If there's no free space manager for objects of this type, |
1098 | | * see if we can avoid creating one by checking if the freed |
1099 | | * space is at the end of the file |
1100 | | */ |
1101 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1102 | | fprintf(stderr, "%s: fs_addr = %" PRIuHADDR "\n", __func__, f->shared->fs_addr[fs_type]); |
1103 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1104 | 0 | if (!H5_addr_defined(f->shared->fs_addr[fs_type])) { |
1105 | 0 | htri_t status; /* "can absorb" status for section into */ |
1106 | |
|
1107 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1108 | | fprintf(stderr, "%s: Trying to avoid starting up free space manager\n", __func__); |
1109 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1110 | | /* Try to shrink the file or absorb the block into a block aggregator */ |
1111 | 0 | if ((status = H5MF_try_shrink(f, alloc_type, addr, size)) < 0) |
1112 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check for absorbing block"); |
1113 | 0 | else if (status > 0) |
1114 | | /* Indicate success */ |
1115 | 0 | HGOTO_DONE(SUCCEED); |
1116 | 0 | else if (size < f->shared->fs_threshold) { |
1117 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1118 | | fprintf(stderr, "%s: dropping addr = %" PRIuHADDR ", size = %" PRIuHSIZE ", on the floor!\n", |
1119 | | __func__, addr, size); |
1120 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1121 | 0 | HGOTO_DONE(SUCCEED); |
1122 | 0 | } /* end else-if */ |
1123 | 0 | } /* end if */ |
1124 | | |
1125 | | /* If we are deleting the free space manager, leave now, to avoid |
1126 | | * [re-]starting it. |
1127 | | * or if file space strategy type is not using a free space manager |
1128 | | * (H5F_FSPACE_STRATEGY_AGGR or H5F_FSPACE_STRATEGY_NONE), drop free space |
1129 | | * section on the floor. |
1130 | | * |
1131 | | * Note: this drops the space to free on the floor... |
1132 | | * |
1133 | | */ |
1134 | 0 | if (f->shared->fs_state[fs_type] == H5F_FS_STATE_DELETING || !H5F_HAVE_FREE_SPACE_MANAGER(f)) { |
1135 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1136 | | fprintf(stderr, "%s: dropping addr = %" PRIuHADDR ", size = %" PRIuHSIZE ", on the floor!\n", |
1137 | | __func__, addr, size); |
1138 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1139 | 0 | HGOTO_DONE(SUCCEED); |
1140 | 0 | } /* end if */ |
1141 | | |
1142 | | /* There's either already a free space manager, or the freed |
1143 | | * space isn't at the end of the file, so start up (or create) |
1144 | | * the file space manager |
1145 | | */ |
1146 | 0 | if (H5MF__start_fstype(f, fs_type) < 0) |
1147 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space"); |
1148 | 0 | } /* end if */ |
1149 | | |
1150 | | /* Create the free-space section for the freed section */ |
1151 | 0 | ctype = H5MF_SECT_CLASS_TYPE(f, size); |
1152 | 0 | if (NULL == (node = H5MF__sect_new(ctype, addr, size))) |
1153 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section"); |
1154 | | |
1155 | | /* If size of the freed section is larger than threshold, add it to the free space manager */ |
1156 | 0 | if (size >= f->shared->fs_threshold) { |
1157 | 0 | assert(f->shared->fs_man[fs_type]); |
1158 | |
|
1159 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1160 | | fprintf(stderr, "%s: Before H5FS_sect_add()\n", __func__); |
1161 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1162 | | |
1163 | | /* Add to the free space for the file */ |
1164 | 0 | if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[fs_type], node) < 0) |
1165 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't add section to file free space"); |
1166 | 0 | node = NULL; |
1167 | |
|
1168 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1169 | | fprintf(stderr, "%s: After H5FS_sect_add()\n", __func__); |
1170 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1171 | 0 | } /* end if */ |
1172 | 0 | else { |
1173 | 0 | htri_t merged; /* Whether node was merged */ |
1174 | 0 | H5MF_sect_ud_t udata; /* User data for callback */ |
1175 | | |
1176 | | /* Construct user data for callbacks */ |
1177 | 0 | udata.f = f; |
1178 | 0 | udata.alloc_type = alloc_type; |
1179 | 0 | udata.allow_sect_absorb = true; |
1180 | 0 | udata.allow_eoa_shrink_only = false; |
1181 | | |
1182 | | /* Try to merge the section that is smaller than threshold */ |
1183 | 0 | if ((merged = H5FS_sect_try_merge(f, f->shared->fs_man[fs_type], (H5FS_section_info_t *)node, |
1184 | 0 | H5FS_ADD_RETURNED_SPACE, &udata)) < 0) |
1185 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't merge section to file free space"); |
1186 | 0 | else if (merged == true) /* successfully merged */ |
1187 | | /* Indicate that the node was used */ |
1188 | 0 | node = NULL; |
1189 | 0 | } /* end else */ |
1190 | | |
1191 | 0 | done: |
1192 | | /* Reset the ring in the API context */ |
1193 | 0 | if (orig_ring != H5AC_RING_INV) |
1194 | 0 | H5AC_set_ring(orig_ring, NULL); |
1195 | | |
1196 | | /* Release section node, if allocated and not added to section list or merged */ |
1197 | 0 | if (node) |
1198 | 0 | if (H5MF__sect_free((H5FS_section_info_t *)node) < 0) |
1199 | 0 | HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node"); |
1200 | |
|
1201 | | #ifdef H5MF_ALLOC_DEBUG |
1202 | | fprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value); |
1203 | | #endif /* H5MF_ALLOC_DEBUG */ |
1204 | | #ifdef H5MF_ALLOC_DEBUG_DUMP |
1205 | | H5MF__sects_dump(f, stderr); |
1206 | | #endif /* H5MF_ALLOC_DEBUG_DUMP */ |
1207 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1208 | 0 | } /* end H5MF_xfree() */ |
1209 | | |
1210 | | /*------------------------------------------------------------------------- |
1211 | | * Function: H5MF_try_extend |
1212 | | * |
1213 | | * Purpose: Extend a block in the file if possible. |
1214 | | * For non-paged aggregation: |
1215 | | * --try to extend at EOA |
1216 | | * --try to extend into the aggregators |
1217 | | * --try to extend into a free-space section if adjoined |
1218 | | * For paged aggregation: |
1219 | | * --try to extend at EOA |
1220 | | * --try to extend into a free-space section if adjoined |
1221 | | * --try to extend into the page end threshold if a metadata block |
1222 | | * |
1223 | | * Return: Success: true(1) - Block was extended |
1224 | | * false(0) - Block could not be extended |
1225 | | * Failure: FAIL |
1226 | | * |
1227 | | *------------------------------------------------------------------------- |
1228 | | */ |
1229 | | htri_t |
1230 | | H5MF_try_extend(H5F_t *f, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size, hsize_t extra_requested) |
1231 | 0 | { |
1232 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
1233 | 0 | H5AC_ring_t fsm_ring; /* Ring of FSM */ |
1234 | 0 | haddr_t end; /* End of block to extend */ |
1235 | 0 | H5FD_mem_t map_type; /* Mapped type */ |
1236 | 0 | H5F_mem_page_t fs_type; /* free space type */ |
1237 | 0 | htri_t allow_extend = true; /* Possible to extend the block */ |
1238 | 0 | hsize_t frag_size = 0; /* Size of mis-aligned fragment */ |
1239 | 0 | htri_t ret_value = false; /* Return value */ |
1240 | |
|
1241 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
1242 | | #ifdef H5MF_ALLOC_DEBUG |
1243 | | fprintf(stderr, |
1244 | | "%s: Entering: alloc_type = %u, addr = %" PRIuHADDR ", size = %" PRIuHSIZE |
1245 | | ", extra_requested = %" PRIuHSIZE "\n", |
1246 | | __func__, (unsigned)alloc_type, addr, size, extra_requested); |
1247 | | #endif /* H5MF_ALLOC_DEBUG */ |
1248 | | |
1249 | | /* Sanity check */ |
1250 | 0 | assert(f); |
1251 | 0 | assert(H5F_INTENT(f) & H5F_ACC_RDWR); |
1252 | | |
1253 | | /* Set mapped type, treating global heap as raw data */ |
1254 | 0 | map_type = (alloc_type == H5FD_MEM_GHEAP) ? H5FD_MEM_DRAW : alloc_type; |
1255 | | |
1256 | | /* Compute end of block to extend */ |
1257 | 0 | end = addr + size; |
1258 | | |
1259 | | /* For paged aggregation: |
1260 | | * To extend a small block: can only extend if not crossing page boundary |
1261 | | * To extend a large block at EOA: calculate in advance mis-aligned fragment so EOA will still end at |
1262 | | * page boundary |
1263 | | */ |
1264 | 0 | if (H5F_PAGED_AGGR(f)) { |
1265 | 0 | if (size < f->shared->fs_page_size) { |
1266 | | /* To extend a small block: cannot cross page boundary */ |
1267 | 0 | if ((addr / f->shared->fs_page_size) != (((end + extra_requested) - 1) / f->shared->fs_page_size)) |
1268 | 0 | allow_extend = false; |
1269 | 0 | } /* end if */ |
1270 | 0 | else { |
1271 | 0 | haddr_t eoa; /* EOA for the file */ |
1272 | | |
1273 | | /* To extend a large block: calculate in advance the mis-aligned fragment so EOA will end at |
1274 | | * page boundary if extended */ |
1275 | 0 | if (HADDR_UNDEF == (eoa = H5F_get_eoa(f, alloc_type))) |
1276 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "Unable to get eoa"); |
1277 | 0 | assert(!(eoa % f->shared->fs_page_size)); |
1278 | |
|
1279 | 0 | H5MF_EOA_MISALIGN(f, (eoa + extra_requested), f->shared->fs_page_size, frag_size); |
1280 | 0 | } /* end else */ |
1281 | 0 | } /* end if */ |
1282 | | |
1283 | | /* Get free space type from allocation type */ |
1284 | 0 | H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type); |
1285 | | |
1286 | | /* Set the ring type in the API context */ |
1287 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, fs_type)) |
1288 | 0 | fsm_ring = H5AC_RING_MDFSM; |
1289 | 0 | else |
1290 | 0 | fsm_ring = H5AC_RING_RDFSM; |
1291 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
1292 | |
|
1293 | 0 | if (allow_extend) { |
1294 | | /* Try extending the block at EOA */ |
1295 | 0 | if ((ret_value = H5F__try_extend(f, map_type, end, extra_requested + frag_size)) < 0) |
1296 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending file"); |
1297 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1298 | | fprintf(stderr, "%s: extended = %d\n", __func__, ret_value); |
1299 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1300 | | |
1301 | | /* If extending at EOA succeeds: */ |
1302 | | /* for paged aggregation, put the fragment into the large-sized free-space manager */ |
1303 | 0 | if (ret_value == true && H5F_PAGED_AGGR(f) && frag_size) { |
1304 | 0 | H5MF_free_section_t *node = NULL; /* Free space section pointer */ |
1305 | | |
1306 | | /* Should be large-sized block */ |
1307 | 0 | assert(size >= f->shared->fs_page_size); |
1308 | | |
1309 | | /* Start up the free-space manager */ |
1310 | 0 | if (!(f->shared->fs_man[fs_type])) |
1311 | 0 | if (H5MF__start_fstype(f, fs_type) < 0) |
1312 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space"); |
1313 | | |
1314 | | /* Create free space section for the fragment */ |
1315 | 0 | if (NULL == (node = H5MF__sect_new(H5MF_FSPACE_SECT_LARGE, end + extra_requested, frag_size))) |
1316 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section"); |
1317 | | |
1318 | | /* Add the fragment to the large-sized free-space manager */ |
1319 | 0 | if (H5MF__add_sect(f, alloc_type, f->shared->fs_man[fs_type], node) < 0) |
1320 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINSERT, FAIL, "can't re-add section to file free space"); |
1321 | | |
1322 | 0 | node = NULL; |
1323 | 0 | } /* end if */ |
1324 | | |
1325 | | /* For non-paged aggregation: try to extend into the aggregators */ |
1326 | 0 | if (ret_value == false && (f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR || |
1327 | 0 | f->shared->fs_strategy == H5F_FSPACE_STRATEGY_AGGR)) { |
1328 | 0 | H5F_blk_aggr_t *aggr; /* Aggregator to use */ |
1329 | | |
1330 | | /* Check if the block is able to extend into aggregation block */ |
1331 | 0 | aggr = (map_type == H5FD_MEM_DRAW) ? &(f->shared->sdata_aggr) : &(f->shared->meta_aggr); |
1332 | 0 | if ((ret_value = H5MF__aggr_try_extend(f, aggr, map_type, end, extra_requested)) < 0) |
1333 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, "error extending aggregation block"); |
1334 | |
|
1335 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1336 | | fprintf(stderr, "%s: H5MF__aggr_try_extend = %d\n", __func__, ret_value); |
1337 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1338 | 0 | } /* end if */ |
1339 | | |
1340 | | /* If no extension so far, try to extend into a free-space section */ |
1341 | 0 | if (ret_value == false && |
1342 | 0 | ((f->shared->fs_strategy == H5F_FSPACE_STRATEGY_FSM_AGGR) || (H5F_PAGED_AGGR(f)))) { |
1343 | 0 | H5MF_sect_ud_t udata; /* User data */ |
1344 | | |
1345 | | /* Construct user data for callbacks */ |
1346 | 0 | udata.f = f; |
1347 | 0 | udata.alloc_type = alloc_type; |
1348 | | |
1349 | | /* Check if the free space for the file has been initialized */ |
1350 | 0 | if (!f->shared->fs_man[fs_type] && H5_addr_defined(f->shared->fs_addr[fs_type])) |
1351 | | /* Open the free-space manager */ |
1352 | 0 | if (H5MF__open_fstype(f, fs_type) < 0) |
1353 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space"); |
1354 | | |
1355 | | /* Try to extend the block into a free-space section */ |
1356 | 0 | if (f->shared->fs_man[fs_type]) { |
1357 | 0 | if ((ret_value = H5FS_sect_try_extend(f, f->shared->fs_man[fs_type], addr, size, |
1358 | 0 | extra_requested, H5FS_ADD_RETURNED_SPACE, &udata)) < 0) |
1359 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTEXTEND, FAIL, |
1360 | 0 | "error extending block in free space manager"); |
1361 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1362 | | fprintf(stderr, "%s: Try to H5FS_sect_try_extend = %d\n", __func__, ret_value); |
1363 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1364 | 0 | } /* end if */ |
1365 | | |
1366 | | /* For paged aggregation and a metadata block: try to extend into page end threshold */ |
1367 | 0 | if (ret_value == false && H5F_PAGED_AGGR(f) && map_type != H5FD_MEM_DRAW) { |
1368 | 0 | H5MF_EOA_MISALIGN(f, end, f->shared->fs_page_size, frag_size); |
1369 | |
|
1370 | 0 | if (frag_size <= H5F_PGEND_META_THRES(f) && extra_requested <= frag_size) |
1371 | 0 | ret_value = true; |
1372 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1373 | | fprintf(stderr, "%s: Try to extend into the page end threshold = %d\n", __func__, ret_value); |
1374 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1375 | 0 | } /* end if */ |
1376 | 0 | } /* end if */ |
1377 | 0 | } /* allow_extend */ |
1378 | | |
1379 | 0 | done: |
1380 | | /* Reset the ring in the API context */ |
1381 | 0 | if (orig_ring != H5AC_RING_INV) |
1382 | 0 | H5AC_set_ring(orig_ring, NULL); |
1383 | |
|
1384 | | #ifdef H5MF_ALLOC_DEBUG |
1385 | | fprintf(stderr, "%s: Leaving: ret_value = %d\n", __func__, ret_value); |
1386 | | #endif /* H5MF_ALLOC_DEBUG */ |
1387 | | #ifdef H5MF_ALLOC_DEBUG_DUMP |
1388 | | H5MF__sects_dump(f, stderr); |
1389 | | #endif /* H5MF_ALLOC_DEBUG_DUMP */ |
1390 | |
|
1391 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1392 | 0 | } /* end H5MF_try_extend() */ |
1393 | | |
1394 | | /*------------------------------------------------------------------------- |
1395 | | * Function: H5MF_try_shrink |
1396 | | * |
1397 | | * Purpose: Try to shrink the size of a file with a block or absorb it |
1398 | | * into a block aggregator. |
1399 | | * |
1400 | | * Return: Non-negative on success/Negative on failure |
1401 | | * |
1402 | | *------------------------------------------------------------------------- |
1403 | | */ |
1404 | | htri_t |
1405 | | H5MF_try_shrink(H5F_t *f, H5FD_mem_t alloc_type, haddr_t addr, hsize_t size) |
1406 | 0 | { |
1407 | 0 | H5MF_free_section_t *node = NULL; /* Free space section pointer */ |
1408 | 0 | H5MF_sect_ud_t udata; /* User data for callback */ |
1409 | 0 | const H5FS_section_class_t *sect_cls; /* Section class */ |
1410 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
1411 | 0 | H5AC_ring_t fsm_ring = H5AC_RING_INV; /* Ring of FSM */ |
1412 | 0 | H5F_mem_page_t fs_type; /* Free space type */ |
1413 | 0 | htri_t ret_value = false; /* Return value */ |
1414 | |
|
1415 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
1416 | | #ifdef H5MF_ALLOC_DEBUG |
1417 | | fprintf(stderr, "%s: Entering - alloc_type = %u, addr = %" PRIuHADDR ", size = %" PRIuHSIZE "\n", |
1418 | | __func__, (unsigned)alloc_type, addr, size); |
1419 | | #endif /* H5MF_ALLOC_DEBUG */ |
1420 | | |
1421 | | /* check arguments */ |
1422 | 0 | assert(f); |
1423 | 0 | assert(f->shared); |
1424 | 0 | assert(f->shared->lf); |
1425 | 0 | assert(H5_addr_defined(addr)); |
1426 | 0 | assert(size > 0); |
1427 | | |
1428 | | /* Set up free-space section class information */ |
1429 | 0 | sect_cls = H5MF_SECT_CLS_TYPE(f, size); |
1430 | 0 | assert(sect_cls); |
1431 | | |
1432 | | /* Get free space type from allocation type */ |
1433 | 0 | H5MF__alloc_to_fs_type(f->shared, alloc_type, size, &fs_type); |
1434 | | |
1435 | | /* Set the ring type in the API context */ |
1436 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, fs_type)) |
1437 | 0 | fsm_ring = H5AC_RING_MDFSM; |
1438 | 0 | else |
1439 | 0 | fsm_ring = H5AC_RING_RDFSM; |
1440 | 0 | H5AC_set_ring(fsm_ring, &orig_ring); |
1441 | | |
1442 | | /* Create free-space section for block */ |
1443 | 0 | if (NULL == (node = H5MF__sect_new(sect_cls->type, addr, size))) |
1444 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize free space section"); |
1445 | | |
1446 | | /* Construct user data for callbacks */ |
1447 | 0 | udata.f = f; |
1448 | 0 | udata.alloc_type = alloc_type; |
1449 | 0 | udata.allow_sect_absorb = false; /* Force section to be absorbed into aggregator */ |
1450 | 0 | udata.allow_eoa_shrink_only = false; |
1451 | | |
1452 | | /* Check if the block can shrink the container */ |
1453 | 0 | if (sect_cls->can_shrink) { |
1454 | 0 | if ((ret_value = (*sect_cls->can_shrink)((const H5FS_section_info_t *)node, &udata)) < 0) |
1455 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTMERGE, FAIL, "can't check if section can shrink container"); |
1456 | 0 | if (ret_value > 0) { |
1457 | 0 | assert(sect_cls->shrink); |
1458 | |
|
1459 | 0 | if ((*sect_cls->shrink)((H5FS_section_info_t **)&node, &udata) < 0) |
1460 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink container"); |
1461 | 0 | } /* end if */ |
1462 | 0 | } /* end if */ |
1463 | | |
1464 | 0 | done: |
1465 | | /* Reset the ring in the API context */ |
1466 | 0 | if (orig_ring != H5AC_RING_INV) |
1467 | 0 | H5AC_set_ring(orig_ring, NULL); |
1468 | | |
1469 | | /* Free section node allocated */ |
1470 | 0 | if (node && H5MF__sect_free((H5FS_section_info_t *)node) < 0) |
1471 | 0 | HDONE_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't free simple section node"); |
1472 | |
|
1473 | | #ifdef H5MF_ALLOC_DEBUG |
1474 | | fprintf(stderr, "%s: Leaving, ret_value = %d\n", __func__, ret_value); |
1475 | | #endif /* H5MF_ALLOC_DEBUG */ |
1476 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1477 | 0 | } /* end H5MF_try_shrink() */ |
1478 | | |
1479 | | /*------------------------------------------------------------------------- |
1480 | | * Function: H5MF_close |
1481 | | * |
1482 | | * Purpose: Close the free space tracker(s) for a file: |
1483 | | * paged or non-paged aggregation |
1484 | | * |
1485 | | * Return: SUCCEED/FAIL |
1486 | | * |
1487 | | *------------------------------------------------------------------------- |
1488 | | */ |
1489 | | herr_t |
1490 | | H5MF_close(H5F_t *f) |
1491 | 0 | { |
1492 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1493 | |
|
1494 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
1495 | | #ifdef H5MF_ALLOC_DEBUG |
1496 | | fprintf(stderr, "%s: Entering\n", __func__); |
1497 | | #endif /* H5MF_ALLOC_DEBUG */ |
1498 | | |
1499 | | /* check args */ |
1500 | 0 | assert(f); |
1501 | 0 | assert(f->shared); |
1502 | |
|
1503 | 0 | if (H5F_PAGED_AGGR(f)) { |
1504 | 0 | if ((ret_value = H5MF__close_pagefs(f)) < 0) |
1505 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, |
1506 | 0 | "can't close free-space managers for 'page' file space"); |
1507 | 0 | } |
1508 | 0 | else { |
1509 | 0 | if ((ret_value = H5MF__close_aggrfs(f)) < 0) |
1510 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, |
1511 | 0 | "can't close free-space managers for 'aggr' file space"); |
1512 | 0 | } |
1513 | | |
1514 | 0 | done: |
1515 | | #ifdef H5MF_ALLOC_DEBUG |
1516 | | fprintf(stderr, "%s: Leaving\n", __func__); |
1517 | | #endif /* H5MF_ALLOC_DEBUG */ |
1518 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1519 | 0 | } /* end H5MF_close() */ |
1520 | | |
1521 | | /*------------------------------------------------------------------------- |
1522 | | * Function: H5MF__close_delete_fstype |
1523 | | * |
1524 | | * Purpose: Common code for closing and deleting the freespace manager |
1525 | | * of TYPE for file. |
1526 | | * Note that TYPE can be H5F_mem_page_t or H5FD_mem_t enum types. |
1527 | | * |
1528 | | * Return: SUCCEED/FAIL |
1529 | | * |
1530 | | *------------------------------------------------------------------------- |
1531 | | */ |
1532 | | static herr_t |
1533 | | H5MF__close_delete_fstype(H5F_t *f, H5F_mem_page_t type) |
1534 | 0 | { |
1535 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1536 | |
|
1537 | 0 | FUNC_ENTER_PACKAGE |
1538 | | #ifdef H5MF_ALLOC_DEBUG |
1539 | | fprintf(stderr, "%s: Entering\n", __func__); |
1540 | | #endif /* H5MF_ALLOC_DEBUG */ |
1541 | | |
1542 | | /* check args */ |
1543 | 0 | assert(f); |
1544 | 0 | assert(f->shared); |
1545 | 0 | if (H5F_PAGED_AGGR(f)) |
1546 | 0 | assert(type < H5F_MEM_PAGE_NTYPES); |
1547 | 0 | else |
1548 | 0 | assert((H5FD_mem_t)type < H5FD_MEM_NTYPES); |
1549 | |
|
1550 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1551 | | fprintf(stderr, "%s: Check 1.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %" PRIuHADDR "\n", |
1552 | | __func__, (unsigned)type, (void *)f->shared->fs_man[type], (unsigned)type, |
1553 | | f->shared->fs_addr[type]); |
1554 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1555 | | |
1556 | | /* If the free space manager for this type is open, close it */ |
1557 | 0 | if (f->shared->fs_man[type]) |
1558 | 0 | if (H5MF__close_fstype(f, type) < 0) |
1559 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager"); |
1560 | | |
1561 | | #ifdef H5MF_ALLOC_DEBUG_MORE |
1562 | | fprintf(stderr, "%s: Check 2.0 - f->shared->fs_man[%u] = %p, f->shared->fs_addr[%u] = %" PRIuHADDR "\n", |
1563 | | __func__, (unsigned)type, (void *)f->shared->fs_man[type], (unsigned)type, |
1564 | | f->shared->fs_addr[type]); |
1565 | | #endif /* H5MF_ALLOC_DEBUG_MORE */ |
1566 | | |
1567 | | /* If there is free space manager info for this type, delete it */ |
1568 | 0 | if (H5_addr_defined(f->shared->fs_addr[type])) |
1569 | 0 | if (H5MF__delete_fstype(f, type) < 0) |
1570 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't delete the free space manager"); |
1571 | | |
1572 | 0 | done: |
1573 | | #ifdef H5MF_ALLOC_DEBUG |
1574 | | fprintf(stderr, "%s: Leaving\n", __func__); |
1575 | | #endif /* H5MF_ALLOC_DEBUG */ |
1576 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1577 | 0 | } /* H5MF__close_delete() */ |
1578 | | |
1579 | | /*------------------------------------------------------------------------- |
1580 | | * Function: H5MF_try_close |
1581 | | * |
1582 | | * Purpose: This is called by H5Fformat_convert() to close and delete |
1583 | | * free-space managers when downgrading persistent free-space |
1584 | | * to non-persistent. |
1585 | | * |
1586 | | * Return: SUCCEED/FAIL |
1587 | | * |
1588 | | *------------------------------------------------------------------------- |
1589 | | */ |
1590 | | herr_t |
1591 | | H5MF_try_close(H5F_t *f) |
1592 | 0 | { |
1593 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
1594 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
1595 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */ |
1596 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1597 | |
|
1598 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
1599 | | #ifdef H5MF_ALLOC_DEBUG |
1600 | | fprintf(stderr, "%s: Entering\n", __func__); |
1601 | | #endif /* H5MF_ALLOC_DEBUG */ |
1602 | | |
1603 | | /* check args */ |
1604 | 0 | assert(f); |
1605 | | |
1606 | | /* If there have been no file space allocations / deallocation so |
1607 | | * far, must call H5MF_tidy_self_referential_fsm_hack() to float |
1608 | | * all self referential FSMs and release file space allocated to |
1609 | | * them. Otherwise, the function will be called after the format |
1610 | | * conversion, and will become very confused. |
1611 | | * |
1612 | | * The situation is further complicated if a cache image exists |
1613 | | * and had not yet been loaded into the metadata cache. In this |
1614 | | * case, call H5AC_force_cache_image_load() instead of |
1615 | | * H5MF_tidy_self_referential_fsm_hack(). H5AC_force_cache_image_load() |
1616 | | * will load the cache image, and then call |
1617 | | * H5MF_tidy_self_referential_fsm_hack() to discard the cache image |
1618 | | * block. |
1619 | | */ |
1620 | | |
1621 | | /* Set the ring type in the API context. In most cases, we will |
1622 | | * need H5AC_RING_RDFSM, so initially set the ring in |
1623 | | * the context to that value. We will alter this later if needed. |
1624 | | */ |
1625 | 0 | H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring); |
1626 | 0 | curr_ring = H5AC_RING_RDFSM; |
1627 | |
|
1628 | 0 | if (H5F_PAGED_AGGR(f)) { |
1629 | 0 | H5F_mem_page_t ptype; /* Memory type for iteration */ |
1630 | | |
1631 | | /* Iterate over all the free space types that have managers and |
1632 | | * get each free list's space |
1633 | | */ |
1634 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) { |
1635 | | /* Test to see if we need to switch rings -- do so if required */ |
1636 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, ptype)) |
1637 | 0 | needed_ring = H5AC_RING_MDFSM; |
1638 | 0 | else |
1639 | 0 | needed_ring = H5AC_RING_RDFSM; |
1640 | |
|
1641 | 0 | if (needed_ring != curr_ring) { |
1642 | 0 | H5AC_set_ring(needed_ring, NULL); |
1643 | 0 | curr_ring = needed_ring; |
1644 | 0 | } /* end if */ |
1645 | |
|
1646 | 0 | if (H5MF__close_delete_fstype(f, ptype) < 0) |
1647 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager"); |
1648 | 0 | } /* end for */ |
1649 | 0 | } /* end if */ |
1650 | 0 | else { |
1651 | 0 | H5FD_mem_t type; /* Memory type for iteration */ |
1652 | | |
1653 | | /* Iterate over all the free space types that have managers and |
1654 | | * get each free list's space |
1655 | | */ |
1656 | 0 | for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) { |
1657 | | /* Test to see if we need to switch rings -- do so if required */ |
1658 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type)) |
1659 | 0 | needed_ring = H5AC_RING_MDFSM; |
1660 | 0 | else |
1661 | 0 | needed_ring = H5AC_RING_RDFSM; |
1662 | |
|
1663 | 0 | if (needed_ring != curr_ring) { |
1664 | 0 | H5AC_set_ring(needed_ring, NULL); |
1665 | 0 | curr_ring = needed_ring; |
1666 | 0 | } /* end if */ |
1667 | |
|
1668 | 0 | if (H5MF__close_delete_fstype(f, (H5F_mem_page_t)type) < 0) |
1669 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager"); |
1670 | 0 | } /* end for */ |
1671 | 0 | } /* end else */ |
1672 | | |
1673 | 0 | done: |
1674 | | /* Reset the ring in the API context */ |
1675 | 0 | if (orig_ring != H5AC_RING_INV) |
1676 | 0 | H5AC_set_ring(orig_ring, NULL); |
1677 | |
|
1678 | | #ifdef H5MF_ALLOC_DEBUG |
1679 | | fprintf(stderr, "%s: Leaving\n", __func__); |
1680 | | #endif /* H5MF_ALLOC_DEBUG */ |
1681 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
1682 | 0 | } /* H5MF_try_close() */ |
1683 | | |
1684 | | /*------------------------------------------------------------------------- |
1685 | | * Function: H5MF__close_aggrfs |
1686 | | * |
1687 | | * Purpose: Close the free space tracker(s) for a file: non-paged aggregation |
1688 | | * |
1689 | | * Return: SUCCEED/FAIL |
1690 | | * |
1691 | | *------------------------------------------------------------------------- |
1692 | | */ |
1693 | | static herr_t |
1694 | | H5MF__close_aggrfs(H5F_t *f) |
1695 | 0 | { |
1696 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
1697 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
1698 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ |
1699 | 0 | H5FD_mem_t type; /* Memory type for iteration */ |
1700 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1701 | |
|
1702 | 0 | FUNC_ENTER_PACKAGE |
1703 | | #ifdef H5MF_ALLOC_DEBUG |
1704 | | fprintf(stderr, "%s: Entering\n", __func__); |
1705 | | #endif /* H5MF_ALLOC_DEBUG */ |
1706 | | |
1707 | | /* check args */ |
1708 | 0 | assert(f); |
1709 | 0 | assert(f->shared); |
1710 | 0 | assert(f->shared->lf); |
1711 | 0 | assert(f->shared->sblock); |
1712 | | |
1713 | | /* Set the ring type in the API context. In most cases, we will |
1714 | | * need H5AC_RING_RDFSM, so initially set the ring in |
1715 | | * the context to that value. We will alter this later if needed. |
1716 | | */ |
1717 | 0 | H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring); |
1718 | 0 | curr_ring = H5AC_RING_RDFSM; |
1719 | | |
1720 | | /* Free the space in aggregators */ |
1721 | | /* (for space not at EOA, it may be put into free space managers) */ |
1722 | 0 | if (H5MF_free_aggrs(f) < 0) |
1723 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators"); |
1724 | | |
1725 | | /* Trying shrinking the EOA for the file */ |
1726 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
1727 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
1728 | | |
1729 | | /* Making free-space managers persistent for superblock version >= 2 */ |
1730 | 0 | if (f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2 && f->shared->fs_persist) { |
1731 | 0 | H5O_fsinfo_t fsinfo; /* File space info message */ |
1732 | 0 | haddr_t final_eoa; /* Final eoa -- for sanity check */ |
1733 | 0 | H5F_mem_page_t ptype; /* Memory type for iteration */ |
1734 | | |
1735 | | /* superblock extension and free space manager message should |
1736 | | * exist at this point -- verify at least the former. |
1737 | | */ |
1738 | 0 | assert(H5_addr_defined(f->shared->sblock->ext_addr)); |
1739 | | |
1740 | | /* file space for all non-empty free space managers should be |
1741 | | * allocated at this point, and these free space managers should |
1742 | | * be written to file and thus their headers and section info |
1743 | | * entries in the metadata cache should be clean. |
1744 | | */ |
1745 | | |
1746 | | /* gather data for the free space manager superblock extension message. |
1747 | | * |
1748 | | * In passing, verify that all the free space managers are closed. |
1749 | | */ |
1750 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) |
1751 | 0 | fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF; |
1752 | 0 | for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++) |
1753 | 0 | fsinfo.fs_addr[type - 1] = f->shared->fs_addr[type]; |
1754 | 0 | fsinfo.strategy = f->shared->fs_strategy; |
1755 | 0 | fsinfo.persist = f->shared->fs_persist; |
1756 | 0 | fsinfo.threshold = f->shared->fs_threshold; |
1757 | 0 | fsinfo.page_size = f->shared->fs_page_size; |
1758 | 0 | fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres; |
1759 | 0 | fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_fsm_fsalloc; |
1760 | 0 | fsinfo.version = f->shared->fs_version; |
1761 | | |
1762 | | /* Write the free space manager message -- message must already exist */ |
1763 | 0 | if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, false, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) |
1764 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, |
1765 | 0 | "error in writing message to superblock extension"); |
1766 | | |
1767 | | /* Close the free space managers */ |
1768 | 0 | for (type = H5FD_MEM_SUPER; type < H5FD_MEM_NTYPES; type++) { |
1769 | 0 | if (f->shared->fs_man[type]) { |
1770 | | /* Test to see if we need to switch rings -- do so if required */ |
1771 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type)) |
1772 | 0 | needed_ring = H5AC_RING_MDFSM; |
1773 | 0 | else |
1774 | 0 | needed_ring = H5AC_RING_RDFSM; |
1775 | |
|
1776 | 0 | if (needed_ring != curr_ring) { |
1777 | 0 | H5AC_set_ring(needed_ring, NULL); |
1778 | 0 | curr_ring = needed_ring; |
1779 | 0 | } /* end if */ |
1780 | |
|
1781 | 0 | assert(f->shared->fs_state[type] == H5F_FS_STATE_OPEN); |
1782 | |
|
1783 | 0 | if (H5FS_close(f, f->shared->fs_man[type]) < 0) |
1784 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager"); |
1785 | 0 | f->shared->fs_man[type] = NULL; |
1786 | 0 | f->shared->fs_state[type] = H5F_FS_STATE_CLOSED; |
1787 | 0 | } /* end if */ |
1788 | 0 | f->shared->fs_addr[type] = HADDR_UNDEF; |
1789 | 0 | } /* end for */ |
1790 | | |
1791 | | /* verify that we haven't dirtied any metadata cache entries |
1792 | | * from the metadata free space manager ring out. |
1793 | | */ |
1794 | 0 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1795 | | |
1796 | | /* verify that the aggregators are still shutdown. */ |
1797 | 0 | assert(f->shared->sdata_aggr.tot_size == 0); |
1798 | 0 | assert(f->shared->sdata_aggr.addr == 0); |
1799 | 0 | assert(f->shared->sdata_aggr.size == 0); |
1800 | |
|
1801 | 0 | assert(f->shared->meta_aggr.tot_size == 0); |
1802 | 0 | assert(f->shared->meta_aggr.addr == 0); |
1803 | 0 | assert(f->shared->meta_aggr.size == 0); |
1804 | | |
1805 | | /* Trying shrinking the EOA for the file */ |
1806 | | /* (in case any free space is now at the EOA) */ |
1807 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
1808 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
1809 | | |
1810 | | /* get the eoa, and verify that it has the expected value */ |
1811 | 0 | if (HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) |
1812 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size"); |
1813 | | |
1814 | | /* f->shared->eoa_post_fsm_fsalloc is undefined if there has |
1815 | | * been no file space allocation or deallocation since file |
1816 | | * open. |
1817 | | */ |
1818 | 0 | assert(H5F_NULL_FSM_ADDR(f) || final_eoa == f->shared->eoa_fsm_fsalloc); |
1819 | 0 | } /* end if */ |
1820 | 0 | else { /* super_vers can be 0, 1, 2 */ |
1821 | 0 | for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) |
1822 | 0 | if (H5MF__close_delete_fstype(f, (H5F_mem_page_t)type) < 0) |
1823 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space"); |
1824 | 0 | } /* end else */ |
1825 | | |
1826 | | /* Free the space in aggregators (again) */ |
1827 | | /* (in case any free space information re-started them) */ |
1828 | 0 | if (H5MF_free_aggrs(f) < 0) |
1829 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTFREE, FAIL, "can't free aggregators"); |
1830 | | |
1831 | | /* Trying shrinking the EOA for the file */ |
1832 | | /* (in case any free space is now at the EOA) */ |
1833 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
1834 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
1835 | | |
1836 | 0 | done: |
1837 | | /* Reset the ring in the API context */ |
1838 | 0 | if (orig_ring != H5AC_RING_INV) |
1839 | 0 | H5AC_set_ring(orig_ring, NULL); |
1840 | |
|
1841 | | #ifdef H5MF_ALLOC_DEBUG |
1842 | | fprintf(stderr, "%s: Leaving\n", __func__); |
1843 | | #endif /* H5MF_ALLOC_DEBUG */ |
1844 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1845 | 0 | } /* end H5MF__close_aggrfs() */ |
1846 | | |
1847 | | /*------------------------------------------------------------------------- |
1848 | | * Function: H5MF__close_pagefs |
1849 | | * |
1850 | | * Purpose: Close the free space tracker(s) for a file: paged aggregation |
1851 | | * |
1852 | | * Return: SUCCEED/FAIL |
1853 | | * |
1854 | | *------------------------------------------------------------------------- |
1855 | | */ |
1856 | | static herr_t |
1857 | | H5MF__close_pagefs(H5F_t *f) |
1858 | 0 | { |
1859 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
1860 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
1861 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ |
1862 | 0 | H5F_mem_page_t ptype; /* Memory type for iteration */ |
1863 | 0 | H5O_fsinfo_t fsinfo; /* File space info message */ |
1864 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
1865 | |
|
1866 | 0 | FUNC_ENTER_PACKAGE |
1867 | | #ifdef H5MF_ALLOC_DEBUG |
1868 | | fprintf(stderr, "%s: Entering\n", __func__); |
1869 | | #endif /* H5MF_ALLOC_DEBUG */ |
1870 | | |
1871 | | /* check args */ |
1872 | 0 | assert(f); |
1873 | 0 | assert(f->shared); |
1874 | 0 | assert(f->shared->lf); |
1875 | 0 | assert(f->shared->sblock); |
1876 | 0 | assert(f->shared->fs_page_size); |
1877 | 0 | assert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2); |
1878 | | |
1879 | | /* Set the ring type in the API context. In most cases, we will |
1880 | | * need H5AC_RING_RDFSM, so initially set the ring in |
1881 | | * the context to that value. We will alter this later if needed. |
1882 | | */ |
1883 | 0 | H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring); |
1884 | 0 | curr_ring = H5AC_RING_RDFSM; |
1885 | | |
1886 | | /* Trying shrinking the EOA for the file */ |
1887 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
1888 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
1889 | | |
1890 | | /* Set up file space info message */ |
1891 | 0 | fsinfo.strategy = f->shared->fs_strategy; |
1892 | 0 | fsinfo.persist = f->shared->fs_persist; |
1893 | 0 | fsinfo.threshold = f->shared->fs_threshold; |
1894 | 0 | fsinfo.page_size = f->shared->fs_page_size; |
1895 | 0 | fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres; |
1896 | 0 | fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF; |
1897 | 0 | fsinfo.version = f->shared->fs_version; |
1898 | |
|
1899 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) |
1900 | 0 | fsinfo.fs_addr[ptype - 1] = HADDR_UNDEF; |
1901 | |
|
1902 | 0 | if (f->shared->fs_persist) { |
1903 | 0 | haddr_t final_eoa; /* final eoa -- for sanity check */ |
1904 | | |
1905 | | /* superblock extension and free space manager message should |
1906 | | * exist at this point -- verify at least the former. |
1907 | | */ |
1908 | 0 | assert(H5_addr_defined(f->shared->sblock->ext_addr)); |
1909 | | |
1910 | | /* file space for all non-empty free space managers should be |
1911 | | * allocated at this point, and these free space managers should |
1912 | | * be written to file and thus their headers and section info |
1913 | | * entries in the metadata cache should be clean. |
1914 | | */ |
1915 | | |
1916 | | /* gather data for the free space manager superblock extension message. |
1917 | | * Only need addresses of FSMs and eoa prior to allocation of |
1918 | | * file space for the self referential free space managers. Other |
1919 | | * data was gathered above. |
1920 | | */ |
1921 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) |
1922 | 0 | fsinfo.fs_addr[ptype - 1] = f->shared->fs_addr[ptype]; |
1923 | 0 | fsinfo.eoa_pre_fsm_fsalloc = f->shared->eoa_fsm_fsalloc; |
1924 | | |
1925 | | /* Write the free space manager message -- message must already exist */ |
1926 | 0 | if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, false, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) |
1927 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, |
1928 | 0 | "error in writing message to superblock extension"); |
1929 | | |
1930 | | /* Close the free space managers */ |
1931 | | /* use H5MF__close_fstype() for this? */ |
1932 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) { |
1933 | 0 | if (f->shared->fs_man[ptype]) { |
1934 | | /* Test to see if we need to switch rings -- do so if required */ |
1935 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, ptype)) |
1936 | 0 | needed_ring = H5AC_RING_MDFSM; |
1937 | 0 | else |
1938 | 0 | needed_ring = H5AC_RING_RDFSM; |
1939 | |
|
1940 | 0 | if (needed_ring != curr_ring) { |
1941 | 0 | H5AC_set_ring(needed_ring, NULL); |
1942 | 0 | curr_ring = needed_ring; |
1943 | 0 | } /* end if */ |
1944 | |
|
1945 | 0 | assert(f->shared->fs_state[ptype] == H5F_FS_STATE_OPEN); |
1946 | |
|
1947 | 0 | if (H5FS_close(f, f->shared->fs_man[ptype]) < 0) |
1948 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close free space manager"); |
1949 | 0 | f->shared->fs_man[ptype] = NULL; |
1950 | 0 | f->shared->fs_state[ptype] = H5F_FS_STATE_CLOSED; |
1951 | 0 | } /* end if */ |
1952 | 0 | f->shared->fs_addr[ptype] = HADDR_UNDEF; |
1953 | 0 | } /* end for */ |
1954 | | |
1955 | | /* verify that we haven't dirtied any metadata cache entries |
1956 | | * from the metadata free space manager ring out. |
1957 | | */ |
1958 | 0 | assert(H5AC_cache_is_clean(f, H5AC_RING_MDFSM)); |
1959 | | |
1960 | | /* Trying shrinking the EOA for the file */ |
1961 | | /* (in case any free space is now at the EOA) */ |
1962 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
1963 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
1964 | | |
1965 | | /* get the eoa, and verify that it has the expected value */ |
1966 | 0 | if (HADDR_UNDEF == (final_eoa = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) |
1967 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size"); |
1968 | | |
1969 | | /* f->shared->eoa_post_fsm_fsalloc is undefined if there has |
1970 | | * been no file space allocation or deallocation since file |
1971 | | * open. |
1972 | | * |
1973 | | * If there is a cache image in the file at file open, |
1974 | | * f->shared->first_alloc_dealloc will always be false unless |
1975 | | * the file is opened R/O, as otherwise, the image will have been |
1976 | | * read and discarded by this point. |
1977 | | * |
1978 | | * If a cache image was created on file close, the actual EOA |
1979 | | * should be in f->shared->eoa_post_mdci_fsalloc. Note that in |
1980 | | * this case, it is conceivable that f->shared->first_alloc_dealloc |
1981 | | * will still be true, as the cache image is allocated directly from |
1982 | | * the file driver layer. However, as this possibility seems remote, |
1983 | | * it is ignored in the following assert. |
1984 | | */ |
1985 | 0 | assert((H5F_NULL_FSM_ADDR(f)) || (final_eoa == f->shared->eoa_fsm_fsalloc) || |
1986 | 0 | ((H5_addr_defined(f->shared->eoa_post_mdci_fsalloc)) && |
1987 | 0 | (final_eoa == f->shared->eoa_post_mdci_fsalloc))); |
1988 | 0 | } /* end if */ |
1989 | 0 | else { |
1990 | | /* Iterate over all the free space types that have managers |
1991 | | * and get each free list's space |
1992 | | */ |
1993 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) |
1994 | 0 | if (H5MF__close_delete_fstype(f, ptype) < 0) |
1995 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't close the free space manager"); |
1996 | | |
1997 | | /* Write file space info message to superblock extension object header */ |
1998 | | /* Create the superblock extension object header in advance if needed */ |
1999 | 0 | if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, false, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) |
2000 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, |
2001 | 0 | "error in writing message to superblock extension"); |
2002 | 0 | } /* end else */ |
2003 | | |
2004 | | /* Trying shrinking the EOA for the file */ |
2005 | | /* (in case any free space is now at the EOA) */ |
2006 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
2007 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
2008 | | |
2009 | 0 | done: |
2010 | | /* Reset the ring in the API context */ |
2011 | 0 | if (orig_ring != H5AC_RING_INV) |
2012 | 0 | H5AC_set_ring(orig_ring, NULL); |
2013 | |
|
2014 | | #ifdef H5MF_ALLOC_DEBUG |
2015 | | fprintf(stderr, "%s: Leaving\n", __func__); |
2016 | | #endif /* H5MF_ALLOC_DEBUG */ |
2017 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2018 | 0 | } /* end H5MF__close_pagefs() */ |
2019 | | |
2020 | | /*------------------------------------------------------------------------- |
2021 | | * Function: H5MF__close_shrink_eoa |
2022 | | * |
2023 | | * Purpose: Shrink the EOA while closing |
2024 | | * |
2025 | | * Return: SUCCEED/FAIL |
2026 | | * |
2027 | | *------------------------------------------------------------------------- |
2028 | | */ |
2029 | | static herr_t |
2030 | | H5MF__close_shrink_eoa(H5F_t *f) |
2031 | 0 | { |
2032 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
2033 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
2034 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ |
2035 | 0 | H5F_mem_t type; |
2036 | 0 | H5F_mem_page_t ptype; /* Memory type for iteration */ |
2037 | 0 | bool eoa_shrank; /* Whether an EOA shrink occurs */ |
2038 | 0 | htri_t status; /* Status value */ |
2039 | 0 | H5MF_sect_ud_t udata; /* User data for callback */ |
2040 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2041 | |
|
2042 | 0 | FUNC_ENTER_PACKAGE |
2043 | | |
2044 | | /* check args */ |
2045 | 0 | assert(f); |
2046 | 0 | assert(f->shared); |
2047 | | |
2048 | | /* Construct user data for callbacks */ |
2049 | 0 | udata.f = f; |
2050 | 0 | udata.allow_sect_absorb = false; |
2051 | 0 | udata.allow_eoa_shrink_only = true; |
2052 | | |
2053 | | /* Set the ring type in the API context */ |
2054 | 0 | H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring); |
2055 | 0 | curr_ring = H5AC_RING_RDFSM; |
2056 | | |
2057 | | /* Iterate until no more EOA shrinking occurs */ |
2058 | 0 | do { |
2059 | 0 | eoa_shrank = false; |
2060 | |
|
2061 | 0 | if (H5F_PAGED_AGGR(f)) { |
2062 | | /* Check the last section of each free-space manager */ |
2063 | 0 | for (ptype = H5F_MEM_PAGE_META; ptype < H5F_MEM_PAGE_NTYPES; ptype++) { |
2064 | 0 | if (f->shared->fs_man[ptype]) { |
2065 | | /* Test to see if we need to switch rings -- do so if required */ |
2066 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, ptype)) |
2067 | 0 | needed_ring = H5AC_RING_MDFSM; |
2068 | 0 | else |
2069 | 0 | needed_ring = H5AC_RING_RDFSM; |
2070 | |
|
2071 | 0 | if (needed_ring != curr_ring) { |
2072 | 0 | H5AC_set_ring(needed_ring, NULL); |
2073 | 0 | curr_ring = needed_ring; |
2074 | 0 | } /* end if */ |
2075 | |
|
2076 | 0 | udata.alloc_type = |
2077 | 0 | (H5FD_mem_t)((H5FD_mem_t)ptype < H5FD_MEM_NTYPES ? ptype |
2078 | 0 | : ((ptype % H5FD_MEM_NTYPES) + 1)); |
2079 | |
|
2080 | 0 | if ((status = H5FS_sect_try_shrink_eoa(f, f->shared->fs_man[ptype], &udata)) < 0) |
2081 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa"); |
2082 | 0 | else if (status > 0) |
2083 | 0 | eoa_shrank = true; |
2084 | 0 | } /* end if */ |
2085 | 0 | } /* end for */ |
2086 | 0 | } /* end if */ |
2087 | 0 | else { |
2088 | | /* Check the last section of each free-space manager */ |
2089 | 0 | for (type = H5FD_MEM_DEFAULT; type < H5FD_MEM_NTYPES; type++) { |
2090 | 0 | if (f->shared->fs_man[type]) { |
2091 | | /* Test to see if we need to switch rings -- do so if required */ |
2092 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type)) |
2093 | 0 | needed_ring = H5AC_RING_MDFSM; |
2094 | 0 | else |
2095 | 0 | needed_ring = H5AC_RING_RDFSM; |
2096 | |
|
2097 | 0 | if (needed_ring != curr_ring) { |
2098 | 0 | H5AC_set_ring(needed_ring, NULL); |
2099 | 0 | curr_ring = needed_ring; |
2100 | 0 | } /* end if */ |
2101 | |
|
2102 | 0 | udata.alloc_type = type; |
2103 | |
|
2104 | 0 | if ((status = H5FS_sect_try_shrink_eoa(f, f->shared->fs_man[type], &udata)) < 0) |
2105 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa"); |
2106 | 0 | else if (status > 0) |
2107 | 0 | eoa_shrank = true; |
2108 | 0 | } /* end if */ |
2109 | 0 | } /* end for */ |
2110 | | |
2111 | | /* check the two aggregators */ |
2112 | 0 | if ((status = H5MF__aggrs_try_shrink_eoa(f)) < 0) |
2113 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't check for shrinking eoa"); |
2114 | 0 | else if (status > 0) |
2115 | 0 | eoa_shrank = true; |
2116 | 0 | } /* end else */ |
2117 | 0 | } while (eoa_shrank); |
2118 | | |
2119 | 0 | done: |
2120 | | /* Reset the ring in the API context */ |
2121 | 0 | if (orig_ring != H5AC_RING_INV) |
2122 | 0 | H5AC_set_ring(orig_ring, NULL); |
2123 | |
|
2124 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2125 | 0 | } /* end H5MF__close_shrink_eoa() */ |
2126 | | |
2127 | | /*------------------------------------------------------------------------- |
2128 | | * Function: H5MF_get_freespace |
2129 | | * |
2130 | | * Purpose: Retrieve the amount of free space in the file |
2131 | | * |
2132 | | * Return: Success: Amount of free space in file |
2133 | | * Failure: Negative |
2134 | | * |
2135 | | *------------------------------------------------------------------------- |
2136 | | */ |
2137 | | herr_t |
2138 | | H5MF_get_freespace(H5F_t *f, hsize_t *tot_space, hsize_t *meta_size) |
2139 | 0 | { |
2140 | 0 | haddr_t ma_addr = HADDR_UNDEF; /* Base "metadata aggregator" address */ |
2141 | 0 | hsize_t ma_size = 0; /* Size of "metadata aggregator" */ |
2142 | 0 | haddr_t sda_addr = HADDR_UNDEF; /* Base "small data aggregator" address */ |
2143 | 0 | hsize_t sda_size = 0; /* Size of "small data aggregator" */ |
2144 | 0 | hsize_t tot_fs_size = 0; /* Amount of all free space managed */ |
2145 | 0 | hsize_t tot_meta_size = 0; /* Amount of metadata for free space managers */ |
2146 | 0 | H5FD_mem_t tt; /* Memory type for iteration */ |
2147 | 0 | H5F_mem_page_t type; /* Memory type for iteration */ |
2148 | 0 | H5F_mem_page_t start_type; /* Memory type for iteration */ |
2149 | 0 | H5F_mem_page_t end_type; /* Memory type for iteration */ |
2150 | 0 | htri_t fs_started[H5F_MEM_PAGE_NTYPES]; /* Indicate whether the free-space manager has been started */ |
2151 | 0 | haddr_t fs_eoa[H5FD_MEM_NTYPES]; /* EAO for each free-space manager */ |
2152 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
2153 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
2154 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ |
2155 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2156 | |
|
2157 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
2158 | | |
2159 | | /* check args */ |
2160 | 0 | assert(f); |
2161 | 0 | assert(f->shared); |
2162 | 0 | assert(f->shared->lf); |
2163 | | |
2164 | | /* Set the ring type in the API context. In most cases, we will |
2165 | | * need H5AC_RING_RDFSM, so initially set the ring in |
2166 | | * the context to that value. We will alter this later if needed. |
2167 | | */ |
2168 | 0 | H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring); |
2169 | 0 | curr_ring = H5AC_RING_RDFSM; |
2170 | | |
2171 | | /* Determine start/end points for loop */ |
2172 | 0 | if (H5F_PAGED_AGGR(f)) { |
2173 | 0 | start_type = H5F_MEM_PAGE_META; |
2174 | 0 | end_type = H5F_MEM_PAGE_NTYPES; |
2175 | 0 | } /* end if */ |
2176 | 0 | else { |
2177 | 0 | start_type = (H5F_mem_page_t)H5FD_MEM_SUPER; |
2178 | 0 | end_type = (H5F_mem_page_t)H5FD_MEM_NTYPES; |
2179 | 0 | } /* end else */ |
2180 | |
|
2181 | 0 | for (tt = H5FD_MEM_SUPER; tt < H5FD_MEM_NTYPES; tt++) |
2182 | 0 | if (HADDR_UNDEF == (fs_eoa[tt] = H5F_get_eoa(f, tt))) |
2183 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "driver get_eoa request failed"); |
2184 | | |
2185 | 0 | if (!H5F_PAGED_AGGR(f)) { |
2186 | | /* Retrieve metadata aggregator info, if available */ |
2187 | 0 | if (H5MF__aggr_query(f, &(f->shared->meta_aggr), &ma_addr, &ma_size) < 0) |
2188 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query metadata aggregator stats"); |
2189 | | |
2190 | | /* Retrieve 'small data' aggregator info, if available */ |
2191 | 0 | if (H5MF__aggr_query(f, &(f->shared->sdata_aggr), &sda_addr, &sda_size) < 0) |
2192 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query small data aggregator stats"); |
2193 | 0 | } /* end if */ |
2194 | | |
2195 | | /* Iterate over all the free space types that have managers and get each free list's space */ |
2196 | 0 | for (type = start_type; type < end_type; type++) { |
2197 | 0 | fs_started[type] = false; |
2198 | | |
2199 | | /* Check if the free space for the file has been initialized */ |
2200 | 0 | if (!f->shared->fs_man[type] && H5_addr_defined(f->shared->fs_addr[type])) { |
2201 | 0 | if (H5MF__open_fstype(f, type) < 0) |
2202 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't initialize file free space"); |
2203 | 0 | assert(f->shared->fs_man[type]); |
2204 | 0 | fs_started[type] = true; |
2205 | 0 | } /* end if */ |
2206 | | |
2207 | | /* Test to see if we need to switch rings -- do so if required */ |
2208 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type)) |
2209 | 0 | needed_ring = H5AC_RING_MDFSM; |
2210 | 0 | else |
2211 | 0 | needed_ring = H5AC_RING_RDFSM; |
2212 | |
|
2213 | 0 | if (needed_ring != curr_ring) { |
2214 | 0 | H5AC_set_ring(needed_ring, NULL); |
2215 | 0 | curr_ring = needed_ring; |
2216 | 0 | } /* end if */ |
2217 | | |
2218 | | /* Check if there's free space of this type */ |
2219 | 0 | if (f->shared->fs_man[type]) { |
2220 | 0 | hsize_t type_fs_size = 0; /* Amount of free space managed for each type */ |
2221 | 0 | hsize_t type_meta_size = 0; /* Amount of free space metadata for each type */ |
2222 | | |
2223 | | /* Retrieve free space size from free space manager */ |
2224 | 0 | if (H5FS_sect_stats(f->shared->fs_man[type], &type_fs_size, NULL) < 0) |
2225 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats"); |
2226 | 0 | if (H5FS_size(f->shared->fs_man[type], &type_meta_size) < 0) |
2227 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space metadata stats"); |
2228 | | |
2229 | | /* Increment total free space for types */ |
2230 | 0 | tot_fs_size += type_fs_size; |
2231 | 0 | tot_meta_size += type_meta_size; |
2232 | 0 | } /* end if */ |
2233 | 0 | } /* end for */ |
2234 | | |
2235 | | /* Close the free-space managers if they were opened earlier in this routine */ |
2236 | 0 | for (type = start_type; type < end_type; type++) { |
2237 | | /* Test to see if we need to switch rings -- do so if required */ |
2238 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, (H5F_mem_page_t)type)) |
2239 | 0 | needed_ring = H5AC_RING_MDFSM; |
2240 | 0 | else |
2241 | 0 | needed_ring = H5AC_RING_RDFSM; |
2242 | |
|
2243 | 0 | if (needed_ring != curr_ring) { |
2244 | 0 | H5AC_set_ring(needed_ring, &curr_ring); |
2245 | 0 | curr_ring = needed_ring; |
2246 | 0 | } /* end if */ |
2247 | |
|
2248 | 0 | if (fs_started[type]) |
2249 | 0 | if (H5MF__close_fstype(f, type) < 0) |
2250 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, "can't close file free space"); |
2251 | 0 | } /* end for */ |
2252 | | |
2253 | | /* Set the value(s) to return */ |
2254 | | /* (The metadata & small data aggregators count as free space now, since they aren't at EOA) */ |
2255 | 0 | if (tot_space) |
2256 | 0 | *tot_space = tot_fs_size + ma_size + sda_size; |
2257 | 0 | if (meta_size) |
2258 | 0 | *meta_size = tot_meta_size; |
2259 | |
|
2260 | 0 | done: |
2261 | | /* Reset the ring in the API context */ |
2262 | 0 | if (orig_ring != H5AC_RING_INV) |
2263 | 0 | H5AC_set_ring(orig_ring, NULL); |
2264 | |
|
2265 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
2266 | 0 | } /* end H5MF_get_freespace() */ |
2267 | | |
2268 | | /*------------------------------------------------------------------------- |
2269 | | * Function: H5MF_get_free_sections() |
2270 | | * |
2271 | | * Purpose: To retrieve free-space section information for |
2272 | | * paged or non-paged aggregation |
2273 | | * |
2274 | | * Return: SUCCEED/FAIL |
2275 | | * |
2276 | | *------------------------------------------------------------------------- |
2277 | | */ |
2278 | | herr_t |
2279 | | H5MF_get_free_sections(H5F_t *f, H5FD_mem_t type, size_t nsects, H5F_sect_info_t *sect_info, |
2280 | | size_t *sect_count) |
2281 | 0 | { |
2282 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
2283 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
2284 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration. */ |
2285 | 0 | size_t total_sects = 0; /* Total number of sections */ |
2286 | 0 | H5MF_sect_iter_ud_t sect_udata; /* User data for callback */ |
2287 | 0 | H5F_mem_page_t start_type, end_type; /* Memory types to iterate over */ |
2288 | 0 | H5F_mem_page_t ty; /* Memory type for iteration */ |
2289 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2290 | |
|
2291 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
2292 | | |
2293 | | /* check args */ |
2294 | 0 | assert(f); |
2295 | 0 | assert(f->shared); |
2296 | 0 | assert(f->shared->lf); |
2297 | | |
2298 | | /* H5MF_tidy_self_referential_fsm_hack() will fail if any self |
2299 | | * referential FSM is opened prior to the call to it. Thus call |
2300 | | * it here if necessary and if it hasn't been called already. |
2301 | | * |
2302 | | * The situation is further complicated if a cache image exists |
2303 | | * and had not yet been loaded into the metadata cache. In this |
2304 | | * case, call H5AC_force_cache_image_load() instead of |
2305 | | * H5MF_tidy_self_referential_fsm_hack(). H5AC_force_cache_image_load() |
2306 | | * will load the cache image, and then call |
2307 | | * H5MF_tidy_self_referential_fsm_hack() to discard the cache image |
2308 | | * block. |
2309 | | */ |
2310 | |
|
2311 | 0 | if (type == H5FD_MEM_DEFAULT) { |
2312 | 0 | start_type = H5F_MEM_PAGE_SUPER; |
2313 | 0 | end_type = H5F_MEM_PAGE_NTYPES; |
2314 | 0 | } /* end if */ |
2315 | 0 | else { |
2316 | 0 | start_type = end_type = (H5F_mem_page_t)type; |
2317 | 0 | if (H5F_PAGED_AGGR(f)) /* set to the corresponding LARGE free-space manager */ |
2318 | 0 | end_type = (H5F_mem_page_t)(end_type + H5FD_MEM_NTYPES); |
2319 | 0 | else |
2320 | 0 | end_type++; |
2321 | 0 | } /* end else */ |
2322 | | |
2323 | | /* Set up user data for section iteration */ |
2324 | 0 | sect_udata.sects = sect_info; |
2325 | 0 | sect_udata.sect_count = nsects; |
2326 | 0 | sect_udata.sect_idx = 0; |
2327 | | |
2328 | | /* Set the ring type in the API context. In most cases, we will |
2329 | | * need H5AC_RING_RDFSM, so initially set the ring in |
2330 | | * the context to that value. We will alter this later if needed. |
2331 | | */ |
2332 | 0 | H5AC_set_ring(H5AC_RING_RDFSM, &orig_ring); |
2333 | 0 | curr_ring = H5AC_RING_RDFSM; |
2334 | | |
2335 | | /* Iterate over memory types, retrieving the number of sections of each type */ |
2336 | 0 | for (ty = start_type; ty < end_type; ty++) { |
2337 | 0 | bool fs_started = false; /* The free-space manager is opened or not */ |
2338 | 0 | size_t nums = 0; /* The number of free-space sections */ |
2339 | | |
2340 | | /* Test to see if we need to switch rings -- do so if required */ |
2341 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, ty)) |
2342 | 0 | needed_ring = H5AC_RING_MDFSM; |
2343 | 0 | else |
2344 | 0 | needed_ring = H5AC_RING_RDFSM; |
2345 | |
|
2346 | 0 | if (needed_ring != curr_ring) { |
2347 | 0 | H5AC_set_ring(needed_ring, &curr_ring); |
2348 | 0 | curr_ring = needed_ring; |
2349 | 0 | } /* end if */ |
2350 | |
|
2351 | 0 | if (!f->shared->fs_man[ty] && H5_addr_defined(f->shared->fs_addr[ty])) { |
2352 | 0 | if (H5MF__open_fstype(f, ty) < 0) |
2353 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't open the free space manager"); |
2354 | 0 | assert(f->shared->fs_man[ty]); |
2355 | 0 | fs_started = true; |
2356 | 0 | } /* end if */ |
2357 | | |
2358 | | /* Check if there's free space sections of this type */ |
2359 | 0 | if (f->shared->fs_man[ty]) |
2360 | 0 | if (H5MF__get_free_sects(f, f->shared->fs_man[ty], §_udata, &nums) < 0) |
2361 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, |
2362 | 0 | "can't get section info for the free space manager"); |
2363 | | |
2364 | | /* Increment total # of sections */ |
2365 | 0 | total_sects += nums; |
2366 | | |
2367 | | /* Close the free space manager of this type, if we started it here */ |
2368 | 0 | if (fs_started) |
2369 | 0 | if (H5MF__close_fstype(f, ty) < 0) |
2370 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTCLOSEOBJ, FAIL, "can't close file free space"); |
2371 | 0 | if ((H5F_PAGED_AGGR(f)) && (type != H5FD_MEM_DEFAULT)) |
2372 | 0 | ty = (H5F_mem_page_t)(ty + H5FD_MEM_NTYPES - 2); |
2373 | 0 | } /* end for */ |
2374 | | |
2375 | | /* Set value to return */ |
2376 | 0 | *sect_count = total_sects; |
2377 | |
|
2378 | 0 | done: |
2379 | | /* Reset the ring in the API context */ |
2380 | 0 | if (orig_ring != H5AC_RING_INV) |
2381 | 0 | H5AC_set_ring(orig_ring, NULL); |
2382 | |
|
2383 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
2384 | 0 | } /* H5MF_get_free_sections() */ |
2385 | | |
2386 | | /*------------------------------------------------------------------------- |
2387 | | * Function: H5MF__sects_cb() |
2388 | | * |
2389 | | * Purpose: Iterator callback for each free-space section |
2390 | | * Retrieve address and size into user data |
2391 | | * |
2392 | | * Return: Always succeed |
2393 | | * |
2394 | | *------------------------------------------------------------------------- |
2395 | | */ |
2396 | | static herr_t |
2397 | | H5MF__sects_cb(H5FS_section_info_t *_sect, void *_udata) |
2398 | 0 | { |
2399 | 0 | H5MF_free_section_t *sect = (H5MF_free_section_t *)_sect; |
2400 | 0 | H5MF_sect_iter_ud_t *udata = (H5MF_sect_iter_ud_t *)_udata; |
2401 | |
|
2402 | 0 | FUNC_ENTER_PACKAGE_NOERR |
2403 | |
|
2404 | 0 | if (udata->sect_idx < udata->sect_count) { |
2405 | 0 | udata->sects[udata->sect_idx].addr = sect->sect_info.addr; |
2406 | 0 | udata->sects[udata->sect_idx].size = sect->sect_info.size; |
2407 | 0 | udata->sect_idx++; |
2408 | 0 | } /* end if */ |
2409 | |
|
2410 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
2411 | 0 | } /* H5MF__sects_cb() */ |
2412 | | |
2413 | | /*------------------------------------------------------------------------- |
2414 | | * Function: H5MF__get_free_sects |
2415 | | * |
2416 | | * Purpose: Retrieve section information for the specified free-space manager. |
2417 | | * |
2418 | | * Return: Success: non-negative |
2419 | | * Failure: negative |
2420 | | * |
2421 | | *------------------------------------------------------------------------- |
2422 | | */ |
2423 | | static herr_t |
2424 | | H5MF__get_free_sects(H5F_t *f, H5FS_t *fspace, H5MF_sect_iter_ud_t *sect_udata, size_t *nums) |
2425 | 0 | { |
2426 | 0 | hsize_t hnums = 0; /* # of sections */ |
2427 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2428 | |
|
2429 | 0 | FUNC_ENTER_PACKAGE |
2430 | | |
2431 | | /* check args */ |
2432 | 0 | assert(f); |
2433 | 0 | assert(sect_udata); |
2434 | 0 | assert(nums); |
2435 | 0 | assert(fspace); |
2436 | | |
2437 | | /* Query how many sections of this type */ |
2438 | 0 | if (H5FS_sect_stats(fspace, NULL, &hnums) < 0) |
2439 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't query free space stats"); |
2440 | 0 | H5_CHECKED_ASSIGN(*nums, size_t, hnums, hsize_t); |
2441 | | |
2442 | | /* Check if we should retrieve the section info */ |
2443 | 0 | if (sect_udata->sects && *nums > 0) |
2444 | | /* Iterate over all the free space sections of this type, adding them to the user's section info */ |
2445 | 0 | if (H5FS_sect_iterate(f, fspace, H5MF__sects_cb, sect_udata) < 0) |
2446 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_BADITER, FAIL, "can't iterate over sections"); |
2447 | | |
2448 | 0 | done: |
2449 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
2450 | 0 | } /* H5MF__get_free_sects() */ |
2451 | | |
2452 | | /*------------------------------------------------------------------------- |
2453 | | * Function: H5MF_settle_raw_data_fsm() |
2454 | | * |
2455 | | * Purpose: Handle any tasks required before the metadata cache |
2456 | | * can serialize or flush the raw data free space manager |
2457 | | * and any metadata free space managers that reside in the |
2458 | | * raw data free space manager ring. |
2459 | | * |
2460 | | * Specifically, this means any metadata managers that DON'T |
2461 | | * handle space allocation for free space manager header or |
2462 | | * section info will reside in the raw data free space manager |
2463 | | * ring. |
2464 | | * |
2465 | | * In the absence of page allocation, there is at most one |
2466 | | * free space manager per memory type defined in H5F_mem_t. |
2467 | | * Of these, the one that allocates H5FD_MEM_DRAW will |
2468 | | * always reside in the raw data free space manager ring. |
2469 | | * If there is more than one metadata free space manager, |
2470 | | * all that don't handle H5FD_MEM_FSPACE_HDR or |
2471 | | * H5FD_MEM_FSPACE_SINFO (which map to H5FD_MEM_OHDR and |
2472 | | * H5FD_MEM_LHEAP respectively) will reside in the raw |
2473 | | * data free space manager ring as well |
2474 | | * |
2475 | | * With page allocation, the situation is conceptually |
2476 | | * identical, but more complex in practice. |
2477 | | * |
2478 | | * In the worst case (multi file driver) page allocation |
2479 | | * can result in two free space managers for each memory |
2480 | | * type -- one for small (less than on equal to one page) |
2481 | | * allocations, and one for large (greater than one page) |
2482 | | * allocations. |
2483 | | * |
2484 | | * In the more common one file case, page allocation will |
2485 | | * result in a total of three free space managers -- one for |
2486 | | * small (<= one page) raw data allocations, one for small |
2487 | | * metadata allocations (i.e, all memory types other than |
2488 | | * H5FD_MEM_DRAW), and one for all large (> one page) |
2489 | | * allocations. |
2490 | | * |
2491 | | * Despite these complications, the solution is the same in |
2492 | | * the page allocation case -- free space managers (be they |
2493 | | * small data or large) are assigned to the raw data free |
2494 | | * space manager ring if they don't allocate file space for |
2495 | | * free space managers. Note that in the one file case, the |
2496 | | * large free space manager must be assigned to the metadata |
2497 | | * free space manager ring, as it both allocates pages for |
2498 | | * the metadata free space manager, and allocates space for |
2499 | | * large (> 1 page) metadata cache entries. |
2500 | | * |
2501 | | * At present, the task list for this routine is: |
2502 | | * |
2503 | | * 1) Reduce the EOA to the extent possible. To do this: |
2504 | | * |
2505 | | * a) Free both aggregators. Space not at EOA will be |
2506 | | * added to the appropriate free space manager. |
2507 | | * |
2508 | | * The raw data aggregator should not be restarted |
2509 | | * after this point. It is possible that the metadata |
2510 | | * aggregator will be. |
2511 | | * |
2512 | | * b) Free all file space currently allocated to free |
2513 | | * space managers. |
2514 | | * |
2515 | | * c) Delete the free space manager superblock |
2516 | | * extension message if allocated. |
2517 | | * |
2518 | | * This done, reduce the EOA by moving it to just before |
2519 | | * the last piece of free memory in the file. |
2520 | | * |
2521 | | * 2) Ensure that space is allocated for the free space |
2522 | | * manager superblock extension message. Must do this |
2523 | | * now, before reallocating file space for free space |
2524 | | * managers, as it is possible that this allocation may |
2525 | | * grab the last section in a FSM -- making it unnecessary |
2526 | | * to re-allocate file space for it. |
2527 | | * |
2528 | | * 3) Scan all free space managers not involved in allocating |
2529 | | * space for free space managers. For each such free space |
2530 | | * manager, test to see if it contains free space. If |
2531 | | * it does, allocate file space for its header and section |
2532 | | * data. If it contains no free space, leave it without |
2533 | | * allocated file space as there is no need to save it to |
2534 | | * file. |
2535 | | * |
2536 | | * Note that all free space managers in this class should |
2537 | | * see no further space allocations / deallocations as |
2538 | | * at this point, all raw data allocations should be |
2539 | | * finalized, as should all metadata allocations not |
2540 | | * involving free space managers. |
2541 | | * |
2542 | | * We will allocate space for free space managers involved |
2543 | | * in the allocation of file space for free space managers |
2544 | | * in H5MF_settle_meta_data_fsm() |
2545 | | * |
2546 | | * Return: SUCCEED/FAIL |
2547 | | * |
2548 | | *------------------------------------------------------------------------- |
2549 | | */ |
2550 | | herr_t |
2551 | | H5MF_settle_raw_data_fsm(H5F_t *f, bool *fsm_settled) |
2552 | 0 | { |
2553 | 0 | int pass_count; |
2554 | 0 | hsize_t alloc_size; |
2555 | 0 | H5F_mem_t mem_type; /* Memory type for iteration */ |
2556 | 0 | H5F_mem_page_t fsm_type; /* FSM type for iteration */ |
2557 | 0 | H5O_fsinfo_t fsinfo; /* Free space manager info message */ |
2558 | 0 | H5FS_stat_t fs_stat; /* Information for free-space manager */ |
2559 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
2560 | 0 | H5AC_ring_t curr_ring = H5AC_RING_INV; /* Current ring value */ |
2561 | 0 | H5AC_ring_t needed_ring = H5AC_RING_INV; /* Ring value needed for this iteration */ |
2562 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
2563 | |
|
2564 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
2565 | | |
2566 | | /* Check args */ |
2567 | 0 | assert(f); |
2568 | 0 | assert(f->shared); |
2569 | 0 | assert(fsm_settled); |
2570 | | |
2571 | | /* Initialize structs */ |
2572 | 0 | memset(&fsinfo, 0, sizeof(fsinfo)); |
2573 | 0 | memset(&fs_stat, 0, sizeof(fs_stat)); |
2574 | | |
2575 | | /* |
2576 | | * Only need to settle things if we are persisting free space and |
2577 | | * the private property in f->shared->null_fsm_addr is not enabled. |
2578 | | */ |
2579 | 0 | if (f->shared->fs_persist && !H5F_NULL_FSM_ADDR(f)) { |
2580 | 0 | bool fsm_opened[H5F_MEM_PAGE_NTYPES]; /* State of FSM */ |
2581 | 0 | bool fsm_visited[H5F_MEM_PAGE_NTYPES]; /* State of FSM */ |
2582 | | |
2583 | | /* should only be called if file is opened R/W */ |
2584 | 0 | assert(H5F_INTENT(f) & H5F_ACC_RDWR); |
2585 | | |
2586 | | /* shouldn't be called unless we have a superblock supporting the |
2587 | | * superblock extension. |
2588 | | */ |
2589 | 0 | if (f->shared->sblock) |
2590 | 0 | assert(f->shared->sblock->super_vers >= HDF5_SUPERBLOCK_VERSION_2); |
2591 | | |
2592 | | /* Initialize fsm_opened and fsm_visited */ |
2593 | 0 | memset(fsm_opened, 0, sizeof(fsm_opened)); |
2594 | 0 | memset(fsm_visited, 0, sizeof(fsm_visited)); |
2595 | | |
2596 | | /* 1) Reduce the EOA to the extent possible. */ |
2597 | | |
2598 | | /* a) Free the space in aggregators: |
2599 | | * |
2600 | | * (for space not at EOF, it may be put into free space managers) |
2601 | | * |
2602 | | * Do this now so that the raw data FSM (and any other FSM that isn't |
2603 | | * involved in space allocation for FSMs) will have no further activity. |
2604 | | * |
2605 | | * Note that while the raw data aggregator should not be restarted during |
2606 | | * the close process, this need not be the case for the metadata aggregator. |
2607 | | * |
2608 | | * Note also that the aggregators will not exist if page aggregation |
2609 | | * is enabled -- skip this if so. |
2610 | | */ |
2611 | | /* Vailin -- is this correct? */ |
2612 | 0 | if (!H5F_PAGED_AGGR(f) && (H5MF_free_aggrs(f) < 0)) |
2613 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators"); |
2614 | | |
2615 | | /* Set the ring type in the DXPL. In most cases, we will |
2616 | | * need H5AC_RING_MDFSM first, so initially set the ring in |
2617 | | * the DXPL to that value. We will alter this later if |
2618 | | * needed. |
2619 | | */ |
2620 | 0 | H5AC_set_ring(H5AC_RING_MDFSM, &orig_ring); |
2621 | 0 | curr_ring = H5AC_RING_MDFSM; |
2622 | | |
2623 | | /* b) Free the file space (if any) allocated to each free space manager. |
2624 | | * |
2625 | | * Do this to facilitate reduction of the size of the file to the |
2626 | | * extent possible. We will re-allocate space to free space managers |
2627 | | * that have free space to save after this reduction. |
2628 | | * |
2629 | | * In the case of the raw data free space manager, and any other free |
2630 | | * space manager that does not allocate space for free space managers, |
2631 | | * allocations should be complete at this point, as all raw data should |
2632 | | * have space allocated and be flushed to file by now. Thus we |
2633 | | * can examine such free space managers and only re-allocate space for |
2634 | | * them if they contain free space. Do this later in this function after |
2635 | | * the EOA has been reduced to the extent possible. |
2636 | | * |
2637 | | * For free space managers that allocate file space for free space |
2638 | | * managers (usually just a single metadata free space manager, but for |
2639 | | * now at least, free space managers for different types of metadata |
2640 | | * are possible), the matter is more ticklish due to the self- |
2641 | | * referential nature of the problem. These FSMs are dealt with in |
2642 | | * H5MF_settle_meta_data_fsm(). |
2643 | | * |
2644 | | * Since paged allocation may be enabled, there may be up to two |
2645 | | * free space managers per memory type -- one for small and one for |
2646 | | * large allocation. Hence we must loop over the memory types twice |
2647 | | * setting the allocation size accordingly if paged allocation is |
2648 | | * enabled. |
2649 | | */ |
2650 | 0 | for (pass_count = 0; pass_count <= 1; pass_count++) { |
2651 | 0 | if (pass_count == 0) |
2652 | 0 | alloc_size = 1; |
2653 | 0 | else if (H5F_PAGED_AGGR(f)) |
2654 | 0 | alloc_size = f->shared->fs_page_size + 1; |
2655 | 0 | else /* no need for a second pass */ |
2656 | 0 | break; |
2657 | | |
2658 | 0 | for (mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; mem_type++) { |
2659 | 0 | H5MF__alloc_to_fs_type(f->shared, mem_type, alloc_size, &fsm_type); |
2660 | |
|
2661 | 0 | if (pass_count == 0) { /* this is the first pass */ |
2662 | 0 | assert(fsm_type > H5F_MEM_PAGE_DEFAULT); |
2663 | 0 | assert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER); |
2664 | 0 | } /* end if */ |
2665 | 0 | else if (H5F_PAGED_AGGR(f)) { /* page alloc active */ |
2666 | 0 | assert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER); |
2667 | 0 | assert(fsm_type < H5F_MEM_PAGE_NTYPES); |
2668 | 0 | } /* end else-if */ |
2669 | 0 | else /* paged allocation disabled -- should be unreachable */ |
2670 | 0 | assert(false); |
2671 | |
|
2672 | 0 | if (!fsm_visited[fsm_type]) { |
2673 | 0 | fsm_visited[fsm_type] = true; |
2674 | | |
2675 | | /* If there is no active FSM for this type, but such a FSM has |
2676 | | * space allocated in file, open it so that we can free its file |
2677 | | * space. |
2678 | | */ |
2679 | 0 | if (NULL == f->shared->fs_man[fsm_type]) { |
2680 | 0 | if (H5_addr_defined(f->shared->fs_addr[fsm_type])) { |
2681 | | /* Sanity check */ |
2682 | 0 | assert(fsm_opened[fsm_type] == false); |
2683 | |
|
2684 | 0 | if (H5MF__open_fstype(f, fsm_type) < 0) |
2685 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, |
2686 | 0 | "can't initialize file free space manager"); |
2687 | 0 | fsm_opened[fsm_type] = true; |
2688 | 0 | } /* end if */ |
2689 | 0 | } /* end if */ |
2690 | | |
2691 | 0 | if (f->shared->fs_man[fsm_type]) { |
2692 | | /* Test to see if we need to switch rings -- do so if required */ |
2693 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, fsm_type)) |
2694 | 0 | needed_ring = H5AC_RING_MDFSM; |
2695 | 0 | else |
2696 | 0 | needed_ring = H5AC_RING_RDFSM; |
2697 | |
|
2698 | 0 | if (needed_ring != curr_ring) { |
2699 | 0 | H5AC_set_ring(needed_ring, NULL); |
2700 | 0 | curr_ring = needed_ring; |
2701 | 0 | } /* end if */ |
2702 | | |
2703 | | /* Query free space manager info for this type */ |
2704 | 0 | if (H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) |
2705 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, "can't get free-space info"); |
2706 | | |
2707 | | /* Check if the free space manager has space in the file */ |
2708 | 0 | if (H5_addr_defined(fs_stat.addr) || H5_addr_defined(fs_stat.sect_addr)) { |
2709 | | /* Delete the free space manager in the file. Will |
2710 | | * reallocate later if the free space manager contains |
2711 | | * any free space. |
2712 | | */ |
2713 | 0 | if (H5FS_free(f, f->shared->fs_man[fsm_type], true) < 0) |
2714 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, |
2715 | 0 | "can't release free-space headers"); |
2716 | 0 | f->shared->fs_addr[fsm_type] = HADDR_UNDEF; |
2717 | 0 | } /* end if */ |
2718 | 0 | } /* end if */ |
2719 | | |
2720 | | /* note that we are tracking opened FSM -- we will close them |
2721 | | * at the end of the function. |
2722 | | */ |
2723 | 0 | } /* end if */ |
2724 | 0 | } /* end for */ |
2725 | 0 | } /* end for */ |
2726 | | |
2727 | | /* c) Delete the free space manager superblock extension message |
2728 | | * if allocated. |
2729 | | * |
2730 | | * Must do this since the routine that writes / creates superblock |
2731 | | * extension messages will choke if the target message is |
2732 | | * unexpectedly either absent or present. |
2733 | | * |
2734 | | * Update: This is probably unnecessary, as I gather that the |
2735 | | * file space manager info message is guaranteed to exist. |
2736 | | * Leave it in for now, but consider removing it. |
2737 | | */ |
2738 | 0 | if (f->shared->sblock) { |
2739 | 0 | if (H5_addr_defined(f->shared->sblock->ext_addr)) |
2740 | 0 | if (H5F__super_ext_remove_msg(f, H5O_FSINFO_ID) < 0) |
2741 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, |
2742 | 0 | "error in removing message from superblock extension"); |
2743 | 0 | } |
2744 | | |
2745 | | /* As the final element in 1), shrink the EOA for the file */ |
2746 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
2747 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
2748 | | |
2749 | 0 | if (f->shared->sblock) { |
2750 | | /* 2) Ensure that space is allocated for the free space manager superblock |
2751 | | * extension message. Must do this now, before reallocating file space |
2752 | | * for free space managers, as it is possible that this allocation may |
2753 | | * grab the last section in a FSM -- making it unnecessary to |
2754 | | * re-allocate file space for it. |
2755 | | * |
2756 | | * Do this by writing a free space manager superblock extension message. |
2757 | | * |
2758 | | * Since no free space manager has file space allocated for it, this |
2759 | | * message must be invalid since we can't save addresses of FSMs when |
2760 | | * those addresses are unknown. This is OK -- we will write the correct |
2761 | | * values to the message at free space manager shutdown. |
2762 | | */ |
2763 | 0 | for (fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; fsm_type++) |
2764 | 0 | fsinfo.fs_addr[fsm_type - 1] = HADDR_UNDEF; |
2765 | 0 | fsinfo.strategy = f->shared->fs_strategy; |
2766 | 0 | fsinfo.persist = f->shared->fs_persist; |
2767 | 0 | fsinfo.threshold = f->shared->fs_threshold; |
2768 | 0 | fsinfo.page_size = f->shared->fs_page_size; |
2769 | 0 | fsinfo.pgend_meta_thres = f->shared->pgend_meta_thres; |
2770 | 0 | fsinfo.eoa_pre_fsm_fsalloc = HADDR_UNDEF; |
2771 | |
|
2772 | 0 | if (H5F__super_ext_write_msg(f, H5O_FSINFO_ID, &fsinfo, true, H5O_MSG_FLAG_MARK_IF_UNKNOWN) < 0) |
2773 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_WRITEERROR, FAIL, |
2774 | 0 | "error in writing fsinfo message to superblock extension"); |
2775 | 0 | } |
2776 | | |
2777 | | /* 3) Scan all free space managers not involved in allocating |
2778 | | * space for free space managers. For each such free space |
2779 | | * manager, test to see if it contains free space. If |
2780 | | * it does, allocate file space for its header and section |
2781 | | * data. If it contains no free space, leave it without |
2782 | | * allocated file space as there is no need to save it to |
2783 | | * file. |
2784 | | * |
2785 | | * Note that all free space managers in this class should |
2786 | | * see no further space allocations / deallocations as |
2787 | | * at this point, all raw data allocations should be |
2788 | | * finalized, as should all metadata allocations not involving |
2789 | | * free space managers. |
2790 | | * |
2791 | | * We will allocate space for free space managers involved |
2792 | | * in the allocation of file space for free space managers |
2793 | | * in H5MF_settle_meta_data_fsm() |
2794 | | */ |
2795 | | |
2796 | | /* Reinitialize fsm_visited */ |
2797 | 0 | for (fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; fsm_type++) |
2798 | 0 | fsm_visited[fsm_type] = false; |
2799 | |
|
2800 | 0 | for (pass_count = 0; pass_count <= 1; pass_count++) { |
2801 | 0 | if (pass_count == 0) |
2802 | 0 | alloc_size = 1; |
2803 | 0 | else if (H5F_PAGED_AGGR(f)) |
2804 | 0 | alloc_size = f->shared->fs_page_size + 1; |
2805 | 0 | else /* no need for a second pass */ |
2806 | 0 | break; |
2807 | | |
2808 | 0 | for (mem_type = H5FD_MEM_SUPER; mem_type < H5FD_MEM_NTYPES; mem_type++) { |
2809 | 0 | H5MF__alloc_to_fs_type(f->shared, mem_type, alloc_size, &fsm_type); |
2810 | |
|
2811 | 0 | if (pass_count == 0) { /* this is the first pass */ |
2812 | 0 | assert(fsm_type > H5F_MEM_PAGE_DEFAULT); |
2813 | 0 | assert(fsm_type < H5F_MEM_PAGE_LARGE_SUPER); |
2814 | 0 | } /* end if */ |
2815 | 0 | else if (H5F_PAGED_AGGR(f)) { /* page alloc active */ |
2816 | 0 | assert(fsm_type >= H5F_MEM_PAGE_LARGE_SUPER); |
2817 | 0 | assert(fsm_type < H5F_MEM_PAGE_NTYPES); |
2818 | 0 | } /* end else-if */ |
2819 | 0 | else /* paged allocation disabled -- should be unreachable */ |
2820 | 0 | assert(false); |
2821 | | |
2822 | | /* Test to see if we need to switch rings -- do so if required */ |
2823 | 0 | if (H5MF__fsm_type_is_self_referential(f->shared, fsm_type)) |
2824 | 0 | needed_ring = H5AC_RING_MDFSM; |
2825 | 0 | else |
2826 | 0 | needed_ring = H5AC_RING_RDFSM; |
2827 | |
|
2828 | 0 | if (needed_ring != curr_ring) { |
2829 | 0 | H5AC_set_ring(needed_ring, NULL); |
2830 | 0 | curr_ring = needed_ring; |
2831 | 0 | } /* end if */ |
2832 | | |
2833 | | /* Since there can be a many-to-one mapping from memory types |
2834 | | * to free space managers, ensure that we don't visit any FSM |
2835 | | * more than once. |
2836 | | */ |
2837 | 0 | if (!fsm_visited[fsm_type]) { |
2838 | 0 | fsm_visited[fsm_type] = true; |
2839 | |
|
2840 | 0 | if (f->shared->fs_man[fsm_type]) { |
2841 | | /* Only allocate file space if the target free space manager |
2842 | | * doesn't allocate file space for free space managers. Note |
2843 | | * that this is also the deciding factor as to whether a FSM |
2844 | | * in in the raw data FSM ring. |
2845 | | */ |
2846 | 0 | if (!H5MF__fsm_type_is_self_referential(f->shared, fsm_type)) { |
2847 | | /* The current ring should be H5AC_RING_RDFSM */ |
2848 | 0 | assert(curr_ring == H5AC_RING_RDFSM); |
2849 | | |
2850 | | /* Query free space manager info for this type */ |
2851 | 0 | if (H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) |
2852 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info"); |
2853 | | |
2854 | | /* If the free space manager contains section info, |
2855 | | * allocate space for the header and sinfo (note that |
2856 | | * space must not be allocated at present -- verify |
2857 | | * verify this with assertions). |
2858 | | */ |
2859 | 0 | if (fs_stat.serial_sect_count > 0) { |
2860 | | /* Sanity check */ |
2861 | 0 | assert(!H5_addr_defined(fs_stat.addr)); |
2862 | | |
2863 | | /* Allocate FSM header */ |
2864 | 0 | if (H5FS_alloc_hdr(f, f->shared->fs_man[fsm_type], |
2865 | 0 | &f->shared->fs_addr[fsm_type]) < 0) |
2866 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, |
2867 | 0 | "can't allocated free-space header"); |
2868 | | |
2869 | | /* Allocate FSM section info */ |
2870 | 0 | assert(!H5_addr_defined(fs_stat.sect_addr)); |
2871 | 0 | assert(fs_stat.alloc_sect_size == 0); |
2872 | 0 | if (H5FS_alloc_sect(f, f->shared->fs_man[fsm_type]) < 0) |
2873 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, |
2874 | 0 | "can't allocate free-space section info"); |
2875 | |
|
2876 | | #ifndef NDEBUG |
2877 | | /* Re-Query free space manager info for this type */ |
2878 | | if (H5FS_stat_info(f, f->shared->fs_man[fsm_type], &fs_stat) < 0) |
2879 | | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTRELEASE, FAIL, |
2880 | | "can't get free-space info"); |
2881 | | |
2882 | | assert(H5_addr_defined(fs_stat.addr)); |
2883 | | assert(H5_addr_defined(fs_stat.sect_addr)); |
2884 | | assert(fs_stat.serial_sect_count > 0); |
2885 | | assert(fs_stat.alloc_sect_size > 0); |
2886 | | assert(fs_stat.alloc_sect_size == fs_stat.sect_size); |
2887 | | #endif /* NDEBUG */ |
2888 | 0 | } /* end if */ |
2889 | 0 | else { |
2890 | 0 | assert(!H5_addr_defined(fs_stat.addr)); |
2891 | 0 | assert(!H5_addr_defined(fs_stat.sect_addr)); |
2892 | 0 | assert(fs_stat.serial_sect_count == 0); |
2893 | 0 | assert(fs_stat.alloc_sect_size == 0); |
2894 | 0 | } /* end else */ |
2895 | 0 | } /* end if */ |
2896 | 0 | } /* end if */ |
2897 | | |
2898 | | /* Close any opened FSMs */ |
2899 | 0 | if (fsm_opened[fsm_type]) { |
2900 | 0 | if (H5MF__close_fstype(f, fsm_type) < 0) |
2901 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTINIT, FAIL, |
2902 | 0 | "can't close file free space manager"); |
2903 | 0 | fsm_opened[fsm_type] = false; |
2904 | 0 | } /* end if */ |
2905 | 0 | } /* end if */ |
2906 | 0 | } /* end for */ |
2907 | 0 | } /* end for */ |
2908 | | |
2909 | | /* verify that all opened FSMs were closed */ |
2910 | 0 | for (fsm_type = H5F_MEM_PAGE_SUPER; fsm_type < H5F_MEM_PAGE_NTYPES; fsm_type++) |
2911 | 0 | assert(!fsm_opened[fsm_type]); |
2912 | | |
2913 | | /* Indicate that the FSM was settled successfully */ |
2914 | 0 | *fsm_settled = true; |
2915 | 0 | } /* end if */ |
2916 | | |
2917 | 0 | done: |
2918 | | /* Reset the ring in the API context */ |
2919 | 0 | if (orig_ring != H5AC_RING_INV) |
2920 | 0 | H5AC_set_ring(orig_ring, NULL); |
2921 | |
|
2922 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
2923 | 0 | } /* H5MF_settle_raw_data_fsm() */ |
2924 | | |
2925 | | /*------------------------------------------------------------------------- |
2926 | | * Function: H5MF_settle_meta_data_fsm() |
2927 | | * |
2928 | | * Purpose: If the free space manager is persistent, handle any tasks |
2929 | | * required before the metadata cache can serialize or flush |
2930 | | * the metadata free space manager(s) that handle file space |
2931 | | * allocation for free space managers. |
2932 | | * |
2933 | | * In most cases, there will be only one manager assigned |
2934 | | * to this role. However, since for reasons unknown, |
2935 | | * free space manager headers and section info blocks are |
2936 | | * different classes of memory, it is possible that two free |
2937 | | * space managers will be involved. |
2938 | | * |
2939 | | * On entry to this function, the raw data settle routine |
2940 | | * (H5MF_settle_raw_data_fsm()) should have: |
2941 | | * |
2942 | | * 1) Freed the aggregators. |
2943 | | * |
2944 | | * 2) Freed all file space allocated to the free space managers. |
2945 | | * |
2946 | | * 3) Deleted the free space manager superblock extension message |
2947 | | * |
2948 | | * 4) Reduced the EOA to the extent possible. |
2949 | | * |
2950 | | * 5) Re-created the free space manager superblock extension |
2951 | | * message. |
2952 | | * |
2953 | | * 6) Reallocated file space for all non-empty free space |
2954 | | * managers NOT involved in allocation of space for free |
2955 | | * space managers. |
2956 | | * |
2957 | | * Note that these free space managers (if not empty) should |
2958 | | * have been written to file by this point, and that no |
2959 | | * further space allocations involving them should take |
2960 | | * place during file close. |
2961 | | * |
2962 | | * On entry to this routine, the free space manager(s) involved |
2963 | | * in allocation of file space for free space managers should |
2964 | | * still be floating. (i.e. should not have any file space |
2965 | | * allocated to them.) |
2966 | | * |
2967 | | * Similarly, the raw data aggregator should not have been |
2968 | | * restarted. Note that it is probable that reallocation of |
2969 | | * space in 5) and 6) above will have re-started the metadata |
2970 | | * aggregator. |
2971 | | * |
2972 | | * |
2973 | | * In this routine, we proceed as follows: |
2974 | | * |
2975 | | * 1) Verify that the free space manager(s) involved in file |
2976 | | * space allocation for free space managers are still floating. |
2977 | | * |
2978 | | * 2) Free the aggregators. |
2979 | | * |
2980 | | * 3) Reduce the EOA to the extent possible, and make note |
2981 | | * of the resulting value. This value will be stored |
2982 | | * in the fsinfo superblock extension message and be used |
2983 | | * in the subsequent file open. |
2984 | | * |
2985 | | * 4) Re-allocate space for any free space manager(s) that: |
2986 | | * |
2987 | | * a) are involved in allocation of space for free space |
2988 | | * managers, and |
2989 | | * |
2990 | | * b) contain free space. |
2991 | | * |
2992 | | * It is possible that we could allocate space for one |
2993 | | * of these free space manager(s) only to have the allocation |
2994 | | * result in the free space manager being empty and thus |
2995 | | * obliging us to free the space again. Thus there is the |
2996 | | * potential for an infinite loop if we want to avoid saving |
2997 | | * empty free space managers. |
2998 | | * |
2999 | | * Similarly, it is possible that we could allocate space |
3000 | | * for a section info block, only to discover that this |
3001 | | * allocation has changed the size of the section info -- |
3002 | | * forcing us to deallocate and start the loop over again. |
3003 | | * |
3004 | | * The solution is to modify the FSM code to |
3005 | | * save empty FSMs to file, and to allow section info blocks |
3006 | | * to be oversized. That is, only allow section info to increase |
3007 | | * in size, not shrink. The solution is now implemented. |
3008 | | * |
3009 | | * 5) Make note of the EOA -- used for sanity checking on |
3010 | | * FSM shutdown. This is saved as eoa_pre_fsm_fsalloc in |
3011 | | * the free-space info message for backward compatibility |
3012 | | * with the 1.10 library that has the hack. |
3013 | | * |
3014 | | * Return: SUCCEED/FAIL |
3015 | | * |
3016 | | *------------------------------------------------------------------------- |
3017 | | */ |
3018 | | herr_t |
3019 | | H5MF_settle_meta_data_fsm(H5F_t *f, bool *fsm_settled) |
3020 | 0 | { |
3021 | 0 | H5F_mem_page_t sm_fshdr_fs_type; /* small fs hdr fsm */ |
3022 | 0 | H5F_mem_page_t sm_fssinfo_fs_type; /* small fs sinfo fsm */ |
3023 | 0 | H5F_mem_page_t lg_fshdr_fs_type = H5F_MEM_PAGE_DEFAULT; /* large fs hdr fsm */ |
3024 | 0 | H5F_mem_page_t lg_fssinfo_fs_type = H5F_MEM_PAGE_DEFAULT; /* large fs sinfo fsm */ |
3025 | 0 | H5FS_t *sm_hdr_fspace = NULL; /* ptr to sm FSM hdr alloc FSM */ |
3026 | 0 | H5FS_t *sm_sinfo_fspace = NULL; /* ptr to sm FSM sinfo alloc FSM */ |
3027 | 0 | H5FS_t *lg_hdr_fspace = NULL; /* ptr to lg FSM hdr alloc FSM */ |
3028 | 0 | H5FS_t *lg_sinfo_fspace = NULL; /* ptr to lg FSM sinfo alloc FSM */ |
3029 | 0 | haddr_t eoa_fsm_fsalloc; /* eoa after file space allocation */ |
3030 | | /* for self referential FSMs */ |
3031 | 0 | bool continue_alloc_fsm = false; /* Continue allocating addr and sect_addr for FSMs */ |
3032 | 0 | H5AC_ring_t orig_ring = H5AC_RING_INV; /* Original ring value */ |
3033 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
3034 | |
|
3035 | 0 | FUNC_ENTER_NOAPI_TAG(H5AC__FREESPACE_TAG, FAIL) |
3036 | | |
3037 | | /* Check args */ |
3038 | 0 | assert(f); |
3039 | 0 | assert(f->shared); |
3040 | 0 | assert(fsm_settled); |
3041 | | |
3042 | | /* |
3043 | | * Only need to settle things if we are persisting free space and |
3044 | | * the private property in f->shared->null_fsm_addr is not enabled. |
3045 | | */ |
3046 | 0 | if (f->shared->fs_persist && !H5F_NULL_FSM_ADDR(f)) { |
3047 | | /* Sanity check */ |
3048 | 0 | assert(f->shared->lf); |
3049 | | |
3050 | | /* should only be called if file is opened R/W */ |
3051 | 0 | assert(H5F_INTENT(f) & H5F_ACC_RDWR); |
3052 | |
|
3053 | 0 | H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fs_type); |
3054 | 0 | H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fs_type); |
3055 | |
|
3056 | 0 | assert(sm_fshdr_fs_type > H5F_MEM_PAGE_DEFAULT); |
3057 | 0 | assert(sm_fshdr_fs_type < H5F_MEM_PAGE_LARGE_SUPER); |
3058 | |
|
3059 | 0 | assert(sm_fssinfo_fs_type > H5F_MEM_PAGE_DEFAULT); |
3060 | 0 | assert(sm_fssinfo_fs_type < H5F_MEM_PAGE_LARGE_SUPER); |
3061 | |
|
3062 | 0 | assert(!H5_addr_defined(f->shared->fs_addr[sm_fshdr_fs_type])); |
3063 | 0 | assert(!H5_addr_defined(f->shared->fs_addr[sm_fssinfo_fs_type])); |
3064 | | |
3065 | | /* Note that in most cases, sm_hdr_fspace will equal sm_sinfo_fspace. */ |
3066 | 0 | sm_hdr_fspace = f->shared->fs_man[sm_fshdr_fs_type]; |
3067 | 0 | sm_sinfo_fspace = f->shared->fs_man[sm_fssinfo_fs_type]; |
3068 | |
|
3069 | 0 | if (H5F_PAGED_AGGR(f)) { |
3070 | 0 | H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_HDR, f->shared->fs_page_size + 1, |
3071 | 0 | &lg_fshdr_fs_type); |
3072 | 0 | H5MF__alloc_to_fs_type(f->shared, H5FD_MEM_FSPACE_SINFO, f->shared->fs_page_size + 1, |
3073 | 0 | &lg_fssinfo_fs_type); |
3074 | |
|
3075 | 0 | assert(lg_fshdr_fs_type >= H5F_MEM_PAGE_LARGE_SUPER); |
3076 | 0 | assert(lg_fshdr_fs_type < H5F_MEM_PAGE_NTYPES); |
3077 | |
|
3078 | 0 | assert(lg_fssinfo_fs_type >= H5F_MEM_PAGE_LARGE_SUPER); |
3079 | 0 | assert(lg_fssinfo_fs_type < H5F_MEM_PAGE_NTYPES); |
3080 | |
|
3081 | 0 | assert(!H5_addr_defined(f->shared->fs_addr[lg_fshdr_fs_type])); |
3082 | 0 | assert(!H5_addr_defined(f->shared->fs_addr[lg_fssinfo_fs_type])); |
3083 | | |
3084 | | /* Note that in most cases, lg_hdr_fspace will equal lg_sinfo_fspace. */ |
3085 | 0 | lg_hdr_fspace = f->shared->fs_man[lg_fshdr_fs_type]; |
3086 | 0 | lg_sinfo_fspace = f->shared->fs_man[lg_fssinfo_fs_type]; |
3087 | 0 | } /* end if */ |
3088 | | |
3089 | | /* Set the ring in the API context appropriately for subsequent calls */ |
3090 | 0 | H5AC_set_ring(H5AC_RING_MDFSM, &orig_ring); |
3091 | |
|
3092 | | #ifndef NDEBUG |
3093 | | { |
3094 | | H5FS_stat_t fs_stat; /* Information for hdr FSM */ |
3095 | | |
3096 | | if (sm_hdr_fspace) { |
3097 | | /* Query free space manager info for this type */ |
3098 | | if (H5FS_stat_info(f, sm_hdr_fspace, &fs_stat) < 0) |
3099 | | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info"); |
3100 | | |
3101 | | assert(!H5_addr_defined(fs_stat.addr)); |
3102 | | assert(!H5_addr_defined(fs_stat.sect_addr)); |
3103 | | assert(fs_stat.alloc_sect_size == 0); |
3104 | | } /* end if */ |
3105 | | |
3106 | | /* Verify that sm_sinfo_fspace is floating if it exists and is distinct */ |
3107 | | if ((sm_sinfo_fspace) && (sm_hdr_fspace != sm_sinfo_fspace)) { |
3108 | | /* Query free space manager info for this type */ |
3109 | | if (H5FS_stat_info(f, sm_sinfo_fspace, &fs_stat) < 0) |
3110 | | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info"); |
3111 | | |
3112 | | assert(!H5_addr_defined(fs_stat.addr)); |
3113 | | assert(!H5_addr_defined(fs_stat.sect_addr)); |
3114 | | assert(fs_stat.alloc_sect_size == 0); |
3115 | | } /* end if */ |
3116 | | |
3117 | | if (H5F_PAGED_AGGR(f)) { |
3118 | | /* Verify that lg_hdr_fspace is floating if it exists */ |
3119 | | if (lg_hdr_fspace) { |
3120 | | /* Query free space manager info for this type */ |
3121 | | if (H5FS_stat_info(f, lg_hdr_fspace, &fs_stat) < 0) |
3122 | | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (3)"); |
3123 | | |
3124 | | assert(!H5_addr_defined(fs_stat.addr)); |
3125 | | assert(!H5_addr_defined(fs_stat.sect_addr)); |
3126 | | assert(fs_stat.alloc_sect_size == 0); |
3127 | | } /* end if */ |
3128 | | |
3129 | | /* Verify that lg_sinfo_fspace is floating if it |
3130 | | * exists and is distinct |
3131 | | */ |
3132 | | if ((lg_sinfo_fspace) && (lg_hdr_fspace != lg_sinfo_fspace)) { |
3133 | | /* Query free space manager info for this type */ |
3134 | | if (H5FS_stat_info(f, lg_sinfo_fspace, &fs_stat) < 0) |
3135 | | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTGET, FAIL, "can't get free-space info (4)"); |
3136 | | |
3137 | | assert(!H5_addr_defined(fs_stat.addr)); |
3138 | | assert(!H5_addr_defined(fs_stat.sect_addr)); |
3139 | | assert(fs_stat.alloc_sect_size == 0); |
3140 | | } /* end if */ |
3141 | | } /* end if */ |
3142 | | } |
3143 | | #endif /* NDEBUG */ |
3144 | | |
3145 | | /* Free the space in the metadata aggregator. Do this via the |
3146 | | * H5MF_free_aggrs() call. Note that the raw data aggregator must |
3147 | | * have already been freed. Sanity checks for this? |
3148 | | * |
3149 | | * Note that the aggregators will not exist if paged aggregation |
3150 | | * is enabled -- don't attempt to free if this is the case. |
3151 | | */ |
3152 | | /* (for space not at EOF, it may be put into free space managers) */ |
3153 | 0 | if ((!H5F_PAGED_AGGR(f)) && (H5MF_free_aggrs(f) < 0)) |
3154 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTFREE, FAIL, "can't free aggregators"); |
3155 | | |
3156 | | /* Trying shrinking the EOA for the file */ |
3157 | 0 | if (H5MF__close_shrink_eoa(f) < 0) |
3158 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTSHRINK, FAIL, "can't shrink eoa"); |
3159 | | |
3160 | | /* WARNING: This approach settling the self referential free space |
3161 | | * managers and allocating space for them in the file will |
3162 | | * not work as currently implemented with the split and |
3163 | | * multi file drivers, as the self referential free space |
3164 | | * manager header and section info can be stored in up to |
3165 | | * two different files -- requiring that up to two EOA's |
3166 | | * be stored in the free space manager's superblock |
3167 | | * extension message. |
3168 | | * |
3169 | | * As of this writing, we are solving this problem by |
3170 | | * simply not supporting persistent FSMs with the split |
3171 | | * and multi file drivers. |
3172 | | * |
3173 | | * Current plans are to do away with the multi file |
3174 | | * driver, so this should be a non-issue in this case. |
3175 | | * |
3176 | | * We should be able to support the split file driver |
3177 | | * without a file format change. However, the code to |
3178 | | * do so does not exist at present. |
3179 | | * NOTE: not sure whether to remove or keep the above comments |
3180 | | */ |
3181 | | |
3182 | | /* |
3183 | | * Continue allocating file space for the header and section info until |
3184 | | * they are all settled, |
3185 | | */ |
3186 | 0 | do { |
3187 | 0 | continue_alloc_fsm = false; |
3188 | 0 | if (sm_hdr_fspace) |
3189 | 0 | if (H5FS_vfd_alloc_hdr_and_section_info_if_needed( |
3190 | 0 | f, sm_hdr_fspace, &(f->shared->fs_addr[sm_fshdr_fs_type])) < 0) |
3191 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, |
3192 | 0 | "can't vfd allocate sm hdr FSM file space"); |
3193 | | |
3194 | 0 | if (sm_sinfo_fspace && (sm_sinfo_fspace != sm_hdr_fspace)) |
3195 | 0 | if (H5FS_vfd_alloc_hdr_and_section_info_if_needed( |
3196 | 0 | f, sm_sinfo_fspace, &(f->shared->fs_addr[sm_fssinfo_fs_type])) < 0) |
3197 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, |
3198 | 0 | "can't vfd allocate sm sinfo FSM file space"); |
3199 | | |
3200 | 0 | if (H5F_PAGED_AGGR(f)) { |
3201 | 0 | if (lg_hdr_fspace) |
3202 | 0 | if (H5FS_vfd_alloc_hdr_and_section_info_if_needed( |
3203 | 0 | f, lg_hdr_fspace, &(f->shared->fs_addr[lg_fshdr_fs_type])) < 0) |
3204 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, |
3205 | 0 | "can't vfd allocate lg hdr FSM file space"); |
3206 | | |
3207 | 0 | if (lg_sinfo_fspace && (lg_sinfo_fspace != lg_hdr_fspace)) |
3208 | 0 | if (H5FS_vfd_alloc_hdr_and_section_info_if_needed( |
3209 | 0 | f, lg_sinfo_fspace, &(f->shared->fs_addr[lg_fssinfo_fs_type])) < 0) |
3210 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, |
3211 | 0 | "can't vfd allocate lg sinfo FSM file space"); |
3212 | 0 | } /* end if */ |
3213 | | |
3214 | 0 | sm_hdr_fspace = f->shared->fs_man[sm_fshdr_fs_type]; |
3215 | 0 | sm_sinfo_fspace = f->shared->fs_man[sm_fssinfo_fs_type]; |
3216 | 0 | if (H5F_PAGED_AGGR(f)) { |
3217 | 0 | lg_hdr_fspace = f->shared->fs_man[lg_fshdr_fs_type]; |
3218 | 0 | lg_sinfo_fspace = f->shared->fs_man[lg_fssinfo_fs_type]; |
3219 | 0 | } |
3220 | |
|
3221 | 0 | if (H5MF__continue_alloc_fsm(f->shared, sm_hdr_fspace, sm_sinfo_fspace, lg_hdr_fspace, |
3222 | 0 | lg_sinfo_fspace, &continue_alloc_fsm) < 0) |
3223 | 0 | HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't vfd allocate lg sinfo FSM file space"); |
3224 | 0 | } while (continue_alloc_fsm); |
3225 | | |
3226 | | /* All free space managers should have file space allocated for them |
3227 | | * now, and should see no further allocations / deallocations. |
3228 | | * For backward compatibility, store the eoa in f->shared->eoa_fsm_fsalloc |
3229 | | * which will be set to fsinfo.eoa_pre_fsm_fsalloc when we actually write |
3230 | | * the free-space info message to the superblock extension. |
3231 | | * This will allow the 1.10 library with the hack to open the file with |
3232 | | * the new solution. |
3233 | | */ |
3234 | | /* Get the eoa after allocation of file space for the self referential |
3235 | | * free space managers. Assuming no cache image, this should be the |
3236 | | * final EOA of the file. |
3237 | | */ |
3238 | 0 | if (HADDR_UNDEF == (eoa_fsm_fsalloc = H5FD_get_eoa(f->shared->lf, H5FD_MEM_DEFAULT))) |
3239 | 0 | HGOTO_ERROR(H5E_FILE, H5E_CANTGET, FAIL, "unable to get file size"); |
3240 | 0 | f->shared->eoa_fsm_fsalloc = eoa_fsm_fsalloc; |
3241 | | |
3242 | | /* Indicate that the FSM was settled successfully */ |
3243 | 0 | *fsm_settled = true; |
3244 | 0 | } /* end if */ |
3245 | | |
3246 | 0 | done: |
3247 | | /* Reset the ring in the API context */ |
3248 | 0 | if (orig_ring != H5AC_RING_INV) |
3249 | 0 | H5AC_set_ring(orig_ring, NULL); |
3250 | |
|
3251 | 0 | FUNC_LEAVE_NOAPI_TAG(ret_value) |
3252 | 0 | } /* H5MF_settle_meta_data_fsm() */ |
3253 | | |
3254 | | /*------------------------------------------------------------------------- |
3255 | | * Function: H5MF__continue_alloc_fsm |
3256 | | * |
3257 | | * Purpose: To determine whether any of the input FSMs has allocated |
3258 | | * its "addr" and "sect_addr". |
3259 | | * Return true or false in *continue_alloc_fsm. |
3260 | | * |
3261 | | * Return: SUCCEED/FAIL |
3262 | | * |
3263 | | *------------------------------------------------------------------------- |
3264 | | */ |
3265 | | static herr_t |
3266 | | H5MF__continue_alloc_fsm(H5F_shared_t *f_sh, H5FS_t *sm_hdr_fspace, H5FS_t *sm_sinfo_fspace, |
3267 | | H5FS_t *lg_hdr_fspace, H5FS_t *lg_sinfo_fspace, bool *continue_alloc_fsm) |
3268 | 0 | { |
3269 | 0 | FUNC_ENTER_PACKAGE_NOERR |
3270 | | |
3271 | | /* Sanity checks */ |
3272 | 0 | assert(f_sh); |
3273 | 0 | assert(continue_alloc_fsm); |
3274 | | |
3275 | | /* Check sm_hdr_fspace */ |
3276 | 0 | if (sm_hdr_fspace && sm_hdr_fspace->serial_sect_count > 0 && sm_hdr_fspace->sinfo) |
3277 | 0 | H5MF_CHECK_FSM(sm_hdr_fspace, continue_alloc_fsm); |
3278 | |
|
3279 | 0 | if (!(*continue_alloc_fsm)) |
3280 | 0 | if (sm_sinfo_fspace && sm_sinfo_fspace != sm_hdr_fspace && sm_sinfo_fspace->serial_sect_count > 0 && |
3281 | 0 | sm_sinfo_fspace->sinfo) |
3282 | 0 | H5MF_CHECK_FSM(sm_hdr_fspace, continue_alloc_fsm); |
3283 | |
|
3284 | 0 | if (H5F_SHARED_PAGED_AGGR(f_sh) && !(*continue_alloc_fsm)) { |
3285 | | /* Check lg_hdr_fspace */ |
3286 | 0 | if (lg_hdr_fspace && lg_hdr_fspace->serial_sect_count > 0 && lg_hdr_fspace->sinfo) |
3287 | 0 | H5MF_CHECK_FSM(lg_hdr_fspace, continue_alloc_fsm); |
3288 | | |
3289 | | /* Check lg_sinfo_fspace */ |
3290 | 0 | if (!(*continue_alloc_fsm)) |
3291 | 0 | if (lg_sinfo_fspace && lg_sinfo_fspace != lg_hdr_fspace && |
3292 | 0 | lg_sinfo_fspace->serial_sect_count > 0 && lg_sinfo_fspace->sinfo) |
3293 | 0 | H5MF_CHECK_FSM(lg_sinfo_fspace, continue_alloc_fsm); |
3294 | 0 | } /* end if */ |
3295 | |
|
3296 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
3297 | 0 | } /* H5MF__continue_alloc_fsm() */ |
3298 | | |
3299 | | /*------------------------------------------------------------------------- |
3300 | | * Function: H5MF__fsm_type_is_self_referential() |
3301 | | * |
3302 | | * Purpose: Return true if the indicated free space manager allocates |
3303 | | * file space for free space managers. Return false otherwise. |
3304 | | * |
3305 | | * Return: true/false |
3306 | | * |
3307 | | *------------------------------------------------------------------------- |
3308 | | */ |
3309 | | static bool |
3310 | | H5MF__fsm_type_is_self_referential(H5F_shared_t *f_sh, H5F_mem_page_t fsm_type) |
3311 | 0 | { |
3312 | 0 | H5F_mem_page_t sm_fshdr_fsm; |
3313 | 0 | H5F_mem_page_t sm_fssinfo_fsm; |
3314 | 0 | H5F_mem_page_t lg_fshdr_fsm; |
3315 | 0 | H5F_mem_page_t lg_fssinfo_fsm; |
3316 | 0 | bool result = false; |
3317 | |
|
3318 | 0 | FUNC_ENTER_PACKAGE_NOERR |
3319 | | |
3320 | | /* Sanity check */ |
3321 | 0 | assert(f_sh); |
3322 | 0 | assert(fsm_type >= H5F_MEM_PAGE_DEFAULT); |
3323 | 0 | assert(fsm_type < H5F_MEM_PAGE_NTYPES); |
3324 | |
|
3325 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm); |
3326 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm); |
3327 | |
|
3328 | 0 | if (H5F_SHARED_PAGED_AGGR(f_sh)) { |
3329 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, f_sh->fs_page_size + 1, &lg_fshdr_fsm); |
3330 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, f_sh->fs_page_size + 1, &lg_fssinfo_fsm); |
3331 | |
|
3332 | 0 | result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm) || (fsm_type == lg_fshdr_fsm) || |
3333 | 0 | (fsm_type == lg_fssinfo_fsm); |
3334 | 0 | } /* end if */ |
3335 | 0 | else { |
3336 | | /* In principle, fsm_type should always be less than |
3337 | | * H5F_MEM_PAGE_LARGE_SUPER whenever paged aggregation |
3338 | | * is not enabled. However, since there is code that does |
3339 | | * not observe this principle, force the result to false if |
3340 | | * fsm_type is greater than or equal to H5F_MEM_PAGE_LARGE_SUPER. |
3341 | | */ |
3342 | 0 | if (fsm_type >= H5F_MEM_PAGE_LARGE_SUPER) |
3343 | 0 | result = false; |
3344 | 0 | else |
3345 | 0 | result = (fsm_type == sm_fshdr_fsm) || (fsm_type == sm_fssinfo_fsm); |
3346 | 0 | } /* end else */ |
3347 | |
|
3348 | 0 | FUNC_LEAVE_NOAPI(result) |
3349 | 0 | } /* H5MF__fsm_type_is_self_referential() */ |
3350 | | |
3351 | | /*------------------------------------------------------------------------- |
3352 | | * Function: H5MF__fsm_is_self_referential() |
3353 | | * |
3354 | | * Purpose: Return true if the indicated free space manager allocates |
3355 | | * file space for free space managers. Return false otherwise. |
3356 | | * |
3357 | | * Return: true/false |
3358 | | * |
3359 | | *------------------------------------------------------------------------- |
3360 | | */ |
3361 | | static bool |
3362 | | H5MF__fsm_is_self_referential(H5F_shared_t *f_sh, H5FS_t *fspace) |
3363 | 0 | { |
3364 | 0 | H5F_mem_page_t sm_fshdr_fsm; |
3365 | 0 | H5F_mem_page_t sm_fssinfo_fsm; |
3366 | 0 | bool result = false; |
3367 | |
|
3368 | 0 | FUNC_ENTER_PACKAGE_NOERR |
3369 | | |
3370 | | /* Sanity check */ |
3371 | 0 | assert(f_sh); |
3372 | 0 | assert(fspace); |
3373 | |
|
3374 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, (size_t)1, &sm_fshdr_fsm); |
3375 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, (size_t)1, &sm_fssinfo_fsm); |
3376 | |
|
3377 | 0 | if (H5F_SHARED_PAGED_AGGR(f_sh)) { |
3378 | 0 | H5F_mem_page_t lg_fshdr_fsm; |
3379 | 0 | H5F_mem_page_t lg_fssinfo_fsm; |
3380 | |
|
3381 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_HDR, f_sh->fs_page_size + 1, &lg_fshdr_fsm); |
3382 | 0 | H5MF__alloc_to_fs_type(f_sh, H5FD_MEM_FSPACE_SINFO, f_sh->fs_page_size + 1, &lg_fssinfo_fsm); |
3383 | |
|
3384 | 0 | result = (fspace == f_sh->fs_man[sm_fshdr_fsm]) || (fspace == f_sh->fs_man[sm_fssinfo_fsm]) || |
3385 | 0 | (fspace == f_sh->fs_man[lg_fshdr_fsm]) || (fspace == f_sh->fs_man[lg_fssinfo_fsm]); |
3386 | 0 | } /* end if */ |
3387 | 0 | else |
3388 | 0 | result = (fspace == f_sh->fs_man[sm_fshdr_fsm]) || (fspace == f_sh->fs_man[sm_fssinfo_fsm]); |
3389 | |
|
3390 | 0 | FUNC_LEAVE_NOAPI(result) |
3391 | 0 | } /* H5MF__fsm_is_self_referential() */ |