Coverage Report

Created: 2026-01-17 07:04

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