Coverage Report

Created: 2024-06-18 06:29

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