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], &sect_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