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