Coverage Report

Created: 2026-09-14 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5FScache.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:     H5FScache.c
16
 *
17
 * Purpose:     Implement file free space metadata cache methods.
18
 *
19
 *-------------------------------------------------------------------------
20
 */
21
22
/****************/
23
/* Module Setup */
24
/****************/
25
26
#include "H5FSmodule.h" /* This source code file is part of the H5FS module */
27
28
/***********/
29
/* Headers */
30
/***********/
31
#include "H5private.h"   /* Generic Functions     */
32
#include "H5ACprivate.h" /* Metadata cache                       */
33
#include "H5Eprivate.h"  /* Error handling        */
34
#include "H5Fprivate.h"  /* File                */
35
#include "H5FSpkg.h"     /* File free space     */
36
#include "H5MFprivate.h" /* File memory management    */
37
#include "H5MMprivate.h" /* Memory management     */
38
#include "H5SLprivate.h" /* Skip Lists                               */
39
#include "H5VMprivate.h" /* Vectors and arrays      */
40
41
/****************/
42
/* Local Macros */
43
/****************/
44
45
/* File free space format version #'s */
46
0
#define H5FS_HDR_VERSION   0 /* Header */
47
0
#define H5FS_SINFO_VERSION 0 /* Serialized sections */
48
49
/******************/
50
/* Local Typedefs */
51
/******************/
52
53
/* User data for skip list iterator callback for iterating over section size nodes when syncing */
54
typedef struct {
55
    H5FS_sinfo_t *sinfo;         /* Free space section info */
56
    uint8_t     **image;         /* Pointer to address of buffer pointer to serialize with */
57
    unsigned      sect_cnt_size; /* # of bytes to encode section size counts in */
58
} H5FS_iter_ud_t;
59
60
/********************/
61
/* Package Typedefs */
62
/********************/
63
64
/********************/
65
/* Local Prototypes */
66
/********************/
67
68
/* Section info routines */
69
static herr_t H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata);
70
static herr_t H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata);
71
72
/* Metadata cache callbacks */
73
static herr_t H5FS__cache_hdr_get_initial_load_size(void *udata, size_t *image_len);
74
static htri_t H5FS__cache_hdr_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
75
static void  *H5FS__cache_hdr_deserialize(const void *image, size_t len, void *udata, bool *dirty);
76
static herr_t H5FS__cache_hdr_image_len(const void *thing, size_t *image_len);
77
static herr_t H5FS__cache_hdr_pre_serialize(H5F_t *f, void *thing, haddr_t addr, size_t len,
78
                                            haddr_t *new_addr, size_t *new_len, unsigned *flags);
79
static herr_t H5FS__cache_hdr_serialize(const H5F_t *f, void *image, size_t len, void *thing);
80
static herr_t H5FS__cache_hdr_notify(H5AC_notify_action_t action, void *thing);
81
static herr_t H5FS__cache_hdr_free_icr(void *thing);
82
83
static herr_t H5FS__cache_sinfo_get_initial_load_size(void *udata, size_t *image_len);
84
static htri_t H5FS__cache_sinfo_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
85
static void  *H5FS__cache_sinfo_deserialize(const void *image, size_t len, void *udata, bool *dirty);
86
static herr_t H5FS__cache_sinfo_image_len(const void *thing, size_t *image_len);
87
static herr_t H5FS__cache_sinfo_pre_serialize(H5F_t *f, void *thing, haddr_t addr, size_t len,
88
                                              haddr_t *new_addr, size_t *new_len, unsigned *flags);
89
static herr_t H5FS__cache_sinfo_serialize(const H5F_t *f, void *image, size_t len, void *thing);
90
static herr_t H5FS__cache_sinfo_notify(H5AC_notify_action_t action, void *thing);
91
static herr_t H5FS__cache_sinfo_free_icr(void *thing);
92
93
/*********************/
94
/* Package Variables */
95
/*********************/
96
97
/* H5FS header inherits cache-like properties from H5AC */
98
const H5AC_class_t H5AC_FSPACE_HDR[1] = {{
99
    H5AC_FSPACE_HDR_ID,                    /* Metadata client ID */
100
    "Free Space Header",                   /* Metadata client name (for debugging) */
101
    H5FD_MEM_FSPACE_HDR,                   /* File space memory type for client */
102
    H5AC__CLASS_NO_FLAGS_SET,              /* Client class behavior flags */
103
    H5FS__cache_hdr_get_initial_load_size, /* 'get_initial_load_size' callback */
104
    NULL,                                  /* 'get_final_load_size' callback */
105
    H5FS__cache_hdr_verify_chksum,         /* 'verify_chksum' callback */
106
    H5FS__cache_hdr_deserialize,           /* 'deserialize' callback */
107
    H5FS__cache_hdr_image_len,             /* 'image_len' callback */
108
    H5FS__cache_hdr_pre_serialize,         /* 'pre_serialize' callback */
109
    H5FS__cache_hdr_serialize,             /* 'serialize' callback */
110
    H5FS__cache_hdr_notify,                /* 'notify' callback */
111
    H5FS__cache_hdr_free_icr,              /* 'free_icr' callback */
112
    NULL,                                  /* 'fsf_size' callback */
113
}};
114
115
/* H5FS section info inherits cache-like properties from H5AC */
116
const H5AC_class_t H5AC_FSPACE_SINFO[1] = {{
117
    H5AC_FSPACE_SINFO_ID,                    /* Metadata client ID */
118
    "Free Space Section Info",               /* Metadata client name (for debugging) */
119
    H5FD_MEM_FSPACE_SINFO,                   /* File space memory type for client */
120
    H5AC__CLASS_NO_FLAGS_SET,                /* Client class behavior flags */
121
    H5FS__cache_sinfo_get_initial_load_size, /* 'get_initial_load_size' callback */
122
    NULL,                                    /* 'get_final_load_size' callback */
123
    H5FS__cache_sinfo_verify_chksum,         /* 'verify_chksum' callback */
124
    H5FS__cache_sinfo_deserialize,           /* 'deserialize' callback */
125
    H5FS__cache_sinfo_image_len,             /* 'image_len' callback */
126
    H5FS__cache_sinfo_pre_serialize,         /* 'pre_serialize' callback */
127
    H5FS__cache_sinfo_serialize,             /* 'serialize' callback */
128
    H5FS__cache_sinfo_notify,                /* 'notify' callback */
129
    H5FS__cache_sinfo_free_icr,              /* 'free_icr' callback */
130
    NULL,                                    /* 'fsf_size' callback */
131
}};
132
133
/*****************************/
134
/* Library Private Variables */
135
/*****************************/
136
137
/*******************/
138
/* Local Variables */
139
/*******************/
140
141
/*-------------------------------------------------------------------------
142
 * Function:    H5FS__cache_hdr_get_initial_load_size
143
 *
144
 * Purpose:     Compute the size of the data structure on disk.
145
 *
146
 * Return:      Non-negative on success/Negative on failure
147
 *
148
 *-------------------------------------------------------------------------
149
 */
150
static herr_t
151
H5FS__cache_hdr_get_initial_load_size(void *_udata, size_t *image_len)
152
1
{
153
1
    H5FS_hdr_cache_ud_t *udata = (H5FS_hdr_cache_ud_t *)_udata; /* User-data for metadata cache callback */
154
155
1
    FUNC_ENTER_PACKAGE_NOERR
156
157
    /* Check arguments */
158
1
    assert(udata);
159
1
    assert(udata->f);
160
1
    assert(image_len);
161
162
    /* Set the image length size */
163
1
    *image_len = (size_t)H5FS_HEADER_SIZE(udata->f);
164
165
1
    FUNC_LEAVE_NOAPI(SUCCEED)
166
1
} /* end H5FS__cache_hdr_get_initial_load_size() */
167
168
/*-------------------------------------------------------------------------
169
 * Function:    H5FS__cache_hdr_verify_chksum
170
 *
171
 * Purpose:     Verify the computed checksum of the data structure is the
172
 *              same as the stored chksum.
173
 *
174
 * Return:      Success:        true/false
175
 *              Failure:        Negative
176
 *
177
 *-------------------------------------------------------------------------
178
 */
179
htri_t
180
H5FS__cache_hdr_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
181
0
{
182
0
    const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
183
0
    uint32_t       stored_chksum;                   /* Stored metadata checksum value */
184
0
    uint32_t       computed_chksum;                 /* Computed metadata checksum value */
185
0
    htri_t         ret_value = true;                /* Return value */
186
187
0
    FUNC_ENTER_PACKAGE
188
189
    /* Check arguments */
190
0
    assert(image);
191
192
    /* Get stored and computed checksums */
193
0
    if (H5F_get_checksums(image, len, &stored_chksum, &computed_chksum) < 0)
194
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get checksums");
195
196
0
    if (stored_chksum != computed_chksum)
197
0
        ret_value = false;
198
199
0
done:
200
0
    FUNC_LEAVE_NOAPI(ret_value)
201
0
} /* end H5FS__cache_hdr_verify_chksum() */
202
203
/*-------------------------------------------------------------------------
204
 * Function:  H5FS__cache_hdr_deserialize
205
 *
206
 * Purpose: Given a buffer containing the on disk image of the free space
207
 *        manager section info, allocate an instance of H5FS_t, load
208
 *        it with the data contained in the image, and return a pointer
209
 *              to the new instance.
210
 *
211
 * Return:  Success:  Pointer to new object
212
 *    Failure:  NULL
213
 *
214
 *-------------------------------------------------------------------------
215
 */
216
static void *
217
H5FS__cache_hdr_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUSED len, void *_udata,
218
                            bool H5_ATTR_UNUSED *dirty)
219
0
{
220
0
    H5FS_t              *fspace = NULL;                          /* Free space header info */
221
0
    H5FS_hdr_cache_ud_t *udata  = (H5FS_hdr_cache_ud_t *)_udata; /* User data for callback */
222
0
    const uint8_t       *image  = (const uint8_t *)_image;       /* Pointer into raw data buffer */
223
0
    uint32_t             stored_chksum;                          /* Stored metadata checksum value */
224
0
    unsigned             nclasses;                               /* Number of section classes */
225
0
    H5FS_t              *ret_value = NULL;                       /* Return value */
226
227
0
    FUNC_ENTER_PACKAGE
228
229
    /* Check arguments */
230
0
    assert(image);
231
0
    assert(udata);
232
0
    assert(udata->f);
233
234
    /* Allocate a new free space manager */
235
0
    if (NULL == (fspace = H5FS__new(udata->f, udata->nclasses, udata->classes, udata->cls_init_udata)))
236
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
237
238
    /* Set free space manager's internal information */
239
0
    fspace->addr = udata->addr;
240
241
    /* Magic number */
242
0
    if (memcmp(image, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
243
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space header signature");
244
0
    image += H5_SIZEOF_MAGIC;
245
246
    /* Version */
247
0
    if (*image++ != H5FS_HDR_VERSION)
248
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space header version");
249
250
    /* Client ID */
251
0
    fspace->client = (H5FS_client_t)*image++;
252
0
    if (fspace->client >= H5FS_NUM_CLIENT_ID)
253
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "unknown client ID in free space header");
254
255
    /* Total space tracked */
256
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->tot_space);
257
258
    /* Total # of free space sections tracked */
259
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->tot_sect_count);
260
261
    /* # of serializable free space sections tracked */
262
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->serial_sect_count);
263
264
    /* # of ghost free space sections tracked */
265
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->ghost_sect_count);
266
267
    /* # of section classes */
268
    /* (only check if we actually have some classes) */
269
0
    UINT16DECODE(image, nclasses);
270
0
    if (fspace->nclasses > 0 && nclasses > fspace->nclasses)
271
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "section class count mismatch");
272
273
    /* Shrink percent */
274
0
    UINT16DECODE(image, fspace->shrink_percent);
275
276
    /* Expand percent */
277
0
    UINT16DECODE(image, fspace->expand_percent);
278
279
    /* Size of address space free space sections are within
280
     * (log2 of actual value)
281
     */
282
0
    UINT16DECODE(image, fspace->max_sect_addr);
283
284
    /* Max. size of section to track */
285
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->max_sect_size);
286
287
    /* Address of serialized free space sections */
288
0
    H5F_addr_decode(udata->f, &image, &fspace->sect_addr);
289
290
    /* Size of serialized free space sections */
291
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->sect_size);
292
293
    /* Allocated size of serialized free space sections */
294
0
    H5F_DECODE_LENGTH(udata->f, image, fspace->alloc_sect_size);
295
296
    /* checksum verification already done in verify_chksum cb */
297
298
    /* Metadata checksum */
299
0
    UINT32DECODE(image, stored_chksum);
300
301
    /* Sanity check */
302
0
    assert((size_t)(image - (const uint8_t *)_image) <= len);
303
304
    /* Set return value */
305
0
    ret_value = fspace;
306
307
0
done:
308
    /* Release resources */
309
0
    if (!ret_value && fspace)
310
0
        if (H5FS__hdr_dest(fspace) < 0)
311
0
            HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space header");
312
313
0
    FUNC_LEAVE_NOAPI(ret_value)
314
0
} /* end H5FS__cache_hdr_deserialize() */
315
316
/*-------------------------------------------------------------------------
317
 * Function:    H5FS__cache_hdr_image_len
318
 *
319
 * Purpose:     Compute the size of the data structure on disk and return
320
 *              it in *image_len.
321
 *
322
 * Return:      Non-negative on success/Negative on failure
323
 *
324
 *-------------------------------------------------------------------------
325
 */
326
static herr_t
327
H5FS__cache_hdr_image_len(const void *_thing, size_t *image_len)
328
0
{
329
0
    const H5FS_t *fspace = (const H5FS_t *)_thing; /* Pointer to the object */
330
331
0
    FUNC_ENTER_PACKAGE_NOERR
332
333
    /* Check arguments */
334
0
    assert(fspace);
335
0
    assert(fspace->cache_info.type == H5AC_FSPACE_HDR);
336
0
    assert(image_len);
337
338
    /* Set the image length size */
339
0
    *image_len = fspace->hdr_size;
340
341
0
    FUNC_LEAVE_NOAPI(SUCCEED)
342
0
} /* end H5FS__cache_hdr_image_len() */
343
344
/*-------------------------------------------------------------------------
345
 * Function:  H5FS__cache_hdr_pre_serialize
346
 *
347
 * Purpose: The free space manager header contains the address, size, and
348
 *    allocation size of the free space manager section info.  However,
349
 *    since it is possible for the section info to either not be allocated
350
 *    at all, or be allocated in temporary (AKA imaginary) files space,
351
 *    it is possible for the above mentioned fields to contain giberish
352
 *    when the free space manager header is serialized.
353
 *
354
 *    This function exists to prevent this problem.  It does so by
355
 *    forcing allocation of real file space for the section information.
356
 *
357
 *    Note that in the Version 2 cache, this problem was dealt with by
358
 *    simply flushing the section info before flushing the header.  This
359
 *    was possible, since the clients handled file I/O directly.  As
360
 *    this responsibility has moved to the cache in Version 3, this
361
 *    solution is no longer directly applicable.
362
 *
363
 * Return:  Success:  SUCCEED
364
 *    Failure:  FAIL
365
 *
366
 *-------------------------------------------------------------------------
367
 */
368
static herr_t
369
H5FS__cache_hdr_pre_serialize(H5F_t *f, void *_thing, haddr_t addr, size_t H5_ATTR_UNUSED len,
370
                              haddr_t H5_ATTR_NDEBUG_UNUSED *new_addr, size_t H5_ATTR_NDEBUG_UNUSED *new_len,
371
                              unsigned *flags)
372
0
{
373
0
    H5FS_t     *fspace    = (H5FS_t *)_thing; /* Pointer to the object */
374
0
    H5AC_ring_t orig_ring = H5AC_RING_INV;    /* Original ring value */
375
0
    herr_t      ret_value = SUCCEED;          /* Return value */
376
377
0
    FUNC_ENTER_PACKAGE
378
379
    /* Sanity check */
380
0
    assert(f);
381
0
    assert(fspace);
382
0
    assert(fspace->cache_info.type == H5AC_FSPACE_HDR);
383
0
    assert(H5_addr_defined(addr));
384
0
    assert(new_addr);
385
0
    assert(new_len);
386
0
    assert(flags);
387
388
0
    if (fspace->sinfo) {
389
0
        H5AC_ring_t ring;
390
391
        /* Retrieve the ring type for the header */
392
0
        if (H5AC_get_entry_ring(f, addr, &ring) < 0)
393
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "unable to get property value");
394
395
        /* Set the ring type for the section info in the API context */
396
0
        H5AC_set_ring(ring, &orig_ring);
397
398
        /* This implies that the header "owns" the section info.
399
         *
400
         * Unfortunately, the comments in the code are not clear as to
401
         * what this means, but from reviewing the code (most particularly
402
         * H5FS_close(), H5FS_sinfo_lock, and H5FS_sinfo_unlock()), I
403
         * gather that it means that the header is maintaining a pointer to
404
         * an instance of H5FS_sinfo_t in which free space data is
405
         * maintained, and either:
406
         *
407
         * 1) The instance of H5FS_sinfo_t is not in the metadata cache.
408
         *
409
         *    This will be true iff H5_addr_defined(fspace->sect_addr)
410
         *    is false, and fspace->sinfo is not NULL.  This is sometimes
411
         *    referred to as "floating" section info in the comments.
412
         *
413
         *    If the section info structure contains free space data
414
         *    that must be placed on disk eventually, then
415
         *
416
         *        fspace->serial_sect_count > 0
417
         *
418
         *    and
419
         *
420
         *        H5_addr_defined(fspace->addr)
421
         *
422
         *    will both be true.  If this condition does not hold, then
423
         *    either the free space info is not persistent
424
         *    (!H5_addr_defined(fspace->addr)???) or the section info
425
         *    contains no free space data that must be written to file
426
         *    ( fspace->serial_sect_count == 0 ).
427
         *
428
         * 2) The instance of H5FS_sinfo_t is in the metadata cache with
429
         *    address in temporary file space (AKA imaginary file space).
430
         *    The entry may or may not be protected, and if protected, it
431
         *    may be protected either RW or RO (as indicated by
432
         *    fspace->sinfo_protected and  fspace->sinfo_accmod).
433
         *
434
         * 3) The instance of H5FS_sinfo_t is in the metadata cache with
435
         *    address in real file space.  As in case 2) above, the entry
436
         *    may or may not be protected, and if protected, it
437
         *    may be protected either RW or RO (as indicated by
438
         *    fspace->sinfo_protected and  fspace->sinfo_accmod).
439
         *
440
         * Observe that fspace->serial_sect_count > 0 must be true in
441
         * cases 2) and 3), as the section info should not be stored on
442
         * disk if it doesn't exist.  Similarly, since the section info
443
         * will not be stored to disk unless the header is,
444
         * H5_addr_defined(fspace->addr) must hold as well.
445
         *
446
         * As the objective is to touch up the free space manager header
447
         * so that it contains sensical data on the size and location of
448
         * the section information, we have to handle each of the above
449
         * cases differently.
450
         *
451
         * Case 1) If either fspace->serial_sect_count == 0 or
452
         *         ! H5_addr_defined(fspace->addr) do nothing as either
453
         *         the free space manager data is not persistent, or the
454
         *         section info is empty.
455
         *
456
         *         Otherwise, allocate space for the section info in real
457
         *         file space, insert the section info at this location, and
458
         *         set fspace->sect_addr, fspace->sect_size, and
459
         *         fspace->alloc_sect_size to reflect the new location
460
         *         of the section info.  Note that it is not necessary to
461
         *         force a write of the section info.
462
         *
463
         * Case 2) Allocate space for the section info in real file space,
464
         *         and tell the metadata cache to relocate the entry.
465
         *         Update fspace->sect_addr, fspace->sect_size, and
466
         *         fspace->alloc_sect_size to reflect the new location.
467
         *
468
         * Case 3) Nothing to be done in this case, although it is useful
469
         *         to perform sanity checks.
470
         *
471
         * Note that while we may alter the contents of the free space
472
         * header in cases 1) and 2), there is no need to mark the header
473
         * as dirty, as the metadata cache would not be attempting to
474
         * serialize the header if it thought it was clean.
475
         */
476
0
        if (fspace->serial_sect_count > 0 && H5_addr_defined(fspace->addr)) {
477
            /* Sanity check */
478
0
            assert(fspace->sect_size > 0);
479
480
0
            if (!H5_addr_defined(fspace->sect_addr)) { /* case 1 */
481
0
                haddr_t tag = HADDR_UNDEF;
482
0
                haddr_t sect_addr;
483
0
                hsize_t saved_sect_size, new_sect_size;
484
485
                /* allocate file space for the section info, and insert it
486
                 * into the metadata cache.
487
                 */
488
0
                saved_sect_size = fspace->sect_size;
489
0
                if (HADDR_UNDEF ==
490
0
                    (sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, fspace->sect_size)))
491
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL,
492
0
                                "file allocation failed for free space sections");
493
494
                /* fspace->sect_size may change in size after H5MF_alloc().
495
                 * If increased in size, free the previous allocation and
496
                 * allocate again with the bigger fspace->sect_size.
497
                 */
498
0
                if (fspace->sect_size > saved_sect_size) {
499
500
0
                    new_sect_size = fspace->sect_size;
501
502
0
                    if (H5MF_xfree(f, H5FD_MEM_FSPACE_SINFO, sect_addr, saved_sect_size) < 0)
503
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to free free space sections");
504
505
0
                    if (HADDR_UNDEF ==
506
0
                        (sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, new_sect_size)))
507
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL,
508
0
                                    "file allocation failed for free space sections");
509
0
                    fspace->sect_size       = new_sect_size;
510
0
                    fspace->alloc_sect_size = new_sect_size;
511
0
                }
512
0
                else {
513
0
                    fspace->alloc_sect_size = saved_sect_size;
514
0
                    fspace->sect_size       = saved_sect_size;
515
0
                }
516
0
                fspace->sect_addr = sect_addr;
517
518
                /* Get the tag for this free space manager and use it to insert the entry */
519
0
                if (H5AC_get_tag((const void *)fspace, &tag) < 0)
520
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTTAG, FAIL, "can't get tag for metadata cache object");
521
0
                H5_BEGIN_TAG(tag)
522
0
                if (H5AC_insert_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, fspace->sinfo,
523
0
                                      H5AC__NO_FLAGS_SET) < 0)
524
0
                    HGOTO_ERROR_TAG(H5E_FSPACE, H5E_CANTINIT, FAIL, "can't add free space sections to cache");
525
0
                H5_END_TAG
526
527
0
                assert(fspace->sinfo->cache_info.size == fspace->alloc_sect_size);
528
529
                /* the metadata cache is now managing the section info,
530
                 * so set fspace->sinfo to NULL.
531
                 */
532
0
                fspace->sinfo = NULL;
533
0
            }                                                 /* end if */
534
0
            else if (H5F_IS_TMP_ADDR(f, fspace->sect_addr)) { /* case 2 */
535
0
                haddr_t new_sect_addr;
536
537
                /* move the section info from temporary (AKA imaginary) file
538
                 * space to real file space.
539
                 */
540
541
                /* if my reading of the code is correct, this should always
542
                 * be the case.  If not, we will have to add code to resize
543
                 * file space allocation for section info as well as moving it.
544
                 */
545
0
                assert(fspace->sect_size > 0);
546
0
                assert(fspace->alloc_sect_size == (size_t)fspace->sect_size);
547
548
                /* Allocate space for the section info in file */
549
0
                if (HADDR_UNDEF ==
550
0
                    (new_sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, fspace->sect_size)))
551
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL,
552
0
                                "file allocation failed for free space sections");
553
554
0
                fspace->alloc_sect_size = (size_t)fspace->sect_size;
555
0
                assert(fspace->sinfo->cache_info.size == fspace->alloc_sect_size);
556
557
                /* Let the metadata cache know the section info moved */
558
0
                if (H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, new_sect_addr) < 0)
559
0
                    HGOTO_ERROR(H5E_HEAP, H5E_CANTMOVE, FAIL, "unable to move section info");
560
561
0
                fspace->sect_addr = new_sect_addr;
562
0
            }      /* end else-if */
563
0
            else { /* case 3 -- nothing to do but sanity checking */
564
                /* if my reading of the code is correct, this should always
565
                 * be the case.  If not, we will have to add code to resize
566
                 * file space allocation for section info.
567
                 */
568
0
                assert(fspace->sect_size > 0);
569
0
                assert(fspace->alloc_sect_size == (size_t)fspace->sect_size);
570
0
            } /* end else */
571
0
        }     /* end else */
572
0
        else {
573
            /* for one reason or another (see comment above) there should
574
             * not be any file space allocated for the section info.
575
             */
576
0
            assert(!H5_addr_defined(fspace->sect_addr));
577
0
        } /* end else */
578
0
    }     /* end if */
579
0
    else if (H5_addr_defined(fspace->sect_addr)) {
580
        /* Here the metadata cache is managing the section info.
581
         *
582
         * Do some sanity checks, and then test to see if the section
583
         * info is in real file space.  If it isn't relocate it into
584
         * real file space lest the header be written to file with
585
         * a nonsense section info address.
586
         */
587
0
        if (!H5F_POINT_OF_NO_RETURN(f)) {
588
0
            assert(fspace->sect_size > 0);
589
0
            assert(fspace->alloc_sect_size == (size_t)fspace->sect_size);
590
0
        } /* end if */
591
592
0
        if (H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
593
0
            unsigned sect_status = 0;
594
0
            haddr_t  new_sect_addr;
595
596
            /* we have work to do -- must relocate section info into
597
             * real file space.
598
             *
599
             * Since the section info address is in temporary space (AKA
600
             * imaginary space), it follows that the entry must be in
601
             * cache.  Further, since fspace->sinfo is NULL, it must be
602
             * unprotected and un-pinned.  Start by verifying this.
603
             */
604
0
            if (H5AC_get_entry_status(f, fspace->sect_addr, &sect_status) < 0)
605
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get section info status");
606
607
0
            assert(sect_status & H5AC_ES__IN_CACHE);
608
0
            assert((sect_status & H5AC_ES__IS_PROTECTED) == 0);
609
0
            assert((sect_status & H5AC_ES__IS_PINNED) == 0);
610
611
            /* Allocate space for the section info in file */
612
0
            if (HADDR_UNDEF ==
613
0
                (new_sect_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, fspace->sect_size)))
614
0
                HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections");
615
616
0
            fspace->alloc_sect_size = (size_t)fspace->sect_size;
617
618
            /* Sanity check */
619
0
            assert(!H5_addr_eq(fspace->sect_addr, new_sect_addr));
620
621
            /* Let the metadata cache know the section info moved */
622
0
            if (H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, fspace->sect_addr, new_sect_addr) < 0)
623
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTMOVE, FAIL, "unable to move section info");
624
625
            /* Update the internal address for the section info */
626
0
            fspace->sect_addr = new_sect_addr;
627
628
            /* No need to mark the header dirty, as we are about to
629
             * serialize it.
630
             */
631
0
        }  /* end if */
632
0
    }      /* end else-if */
633
0
    else { /* there is no section info at present */
634
        /* do some sanity checks */
635
0
        assert(fspace->serial_sect_count == 0);
636
0
        assert(fspace->tot_sect_count == fspace->ghost_sect_count);
637
0
    } /* end else */
638
639
    /* what ever happened above, set *flags to 0 */
640
0
    *flags = 0;
641
642
0
done:
643
    /* Reset the ring in the API context */
644
0
    if (orig_ring != H5AC_RING_INV)
645
0
        H5AC_set_ring(orig_ring, NULL);
646
647
0
    FUNC_LEAVE_NOAPI(ret_value)
648
0
} /* end H5FS__cache_hdr_pre_serialize() */
649
650
/*-------------------------------------------------------------------------
651
 * Function:    H5FS__cache_hdr_serialize
652
 *
653
 * Purpose:   Given an instance of H5FS_t and a suitably sized buffer,
654
 *        serialize the contents of the instance of H5FS_t and write
655
 *        its contents to the buffer.  This buffer will be used to
656
 *        write the image of the instance to file.
657
 *
658
 * Return:      Success:        SUCCEED
659
 *              Failure:        FAIL
660
 *
661
 *-------------------------------------------------------------------------
662
 */
663
static herr_t
664
H5FS__cache_hdr_serialize(const H5F_t *f, void *_image, size_t H5_ATTR_NDEBUG_UNUSED len, void *_thing)
665
0
{
666
0
    H5FS_t  *fspace = (H5FS_t *)_thing;  /* Pointer to the object */
667
0
    uint8_t *image  = (uint8_t *)_image; /* Pointer into raw data buffer */
668
0
    uint32_t metadata_chksum;            /* Computed metadata checksum value */
669
0
    herr_t   ret_value = SUCCEED;        /* Return value */
670
671
0
    FUNC_ENTER_PACKAGE_NOERR
672
673
    /* Check arguments */
674
0
    assert(f);
675
0
    assert(image);
676
0
    assert(fspace);
677
0
    assert(fspace->cache_info.type == H5AC_FSPACE_HDR);
678
0
    assert(fspace->hdr_size == len);
679
680
    /* The section information does not always exits, and if it does,
681
     * it is not always in the cache.  To make matters more interesting,
682
     * even if it is in the cache, it may not be in real file space.
683
     *
684
     * The pre-serialize function should have moved the section info
685
     * into real file space if necessary before this function was called.
686
     * The following asserts are a cursory check on this.
687
     */
688
0
    assert((!H5_addr_defined(fspace->sect_addr)) || (!H5F_IS_TMP_ADDR(f, fspace->sect_addr)));
689
690
0
    if (!H5F_POINT_OF_NO_RETURN(f))
691
0
        assert((!H5_addr_defined(fspace->sect_addr)) ||
692
0
               ((fspace->sect_size > 0) && (fspace->alloc_sect_size == (size_t)fspace->sect_size)));
693
694
    /* Magic number */
695
0
    H5MM_memcpy(image, H5FS_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC);
696
0
    image += H5_SIZEOF_MAGIC;
697
698
    /* Version # */
699
0
    *image++ = H5FS_HDR_VERSION;
700
701
    /* Client ID */
702
0
    H5_CHECKED_ASSIGN(*image++, uint8_t, fspace->client, int);
703
704
    /* Total space tracked */
705
0
    H5F_ENCODE_LENGTH(f, image, fspace->tot_space);
706
707
    /* Total # of free space sections tracked */
708
0
    H5F_ENCODE_LENGTH(f, image, fspace->tot_sect_count);
709
710
    /* # of serializable free space sections tracked */
711
0
    H5F_ENCODE_LENGTH(f, image, fspace->serial_sect_count);
712
713
    /* # of ghost free space sections tracked */
714
0
    H5F_ENCODE_LENGTH(f, image, fspace->ghost_sect_count);
715
716
    /* # of section classes */
717
0
    UINT16ENCODE(image, fspace->nclasses);
718
719
    /* Shrink percent */
720
0
    UINT16ENCODE(image, fspace->shrink_percent);
721
722
    /* Expand percent */
723
0
    UINT16ENCODE(image, fspace->expand_percent);
724
725
    /* Size of address space free space sections are within (log2 of
726
     * actual value)
727
     */
728
0
    UINT16ENCODE(image, fspace->max_sect_addr);
729
730
    /* Max. size of section to track */
731
0
    H5F_ENCODE_LENGTH(f, image, fspace->max_sect_size);
732
733
    /* Address of serialized free space sections */
734
0
    H5F_addr_encode(f, &image, fspace->sect_addr);
735
736
    /* Size of serialized free space sections */
737
0
    H5F_ENCODE_LENGTH(f, image, fspace->sect_size);
738
739
    /* Allocated size of serialized free space sections */
740
0
    H5F_ENCODE_LENGTH(f, image, fspace->alloc_sect_size);
741
742
    /* Compute checksum */
743
0
    metadata_chksum = H5_checksum_metadata((uint8_t *)_image, (size_t)(image - (uint8_t *)_image), 0);
744
745
    /* Metadata checksum */
746
0
    UINT32ENCODE(image, metadata_chksum);
747
748
    /* sanity checks */
749
0
    assert((size_t)(image - (uint8_t *)_image) == fspace->hdr_size);
750
751
0
    FUNC_LEAVE_NOAPI(ret_value)
752
0
} /* H5FS__cache_hdr_serialize() */
753
754
/*-------------------------------------------------------------------------
755
 * Function:    H5FS__cache_hdr_notify
756
 *
757
 * Purpose:     Handle cache action notifications
758
 *
759
 * Return:      SUCCEED/FAIL
760
 *
761
 *-------------------------------------------------------------------------
762
 */
763
herr_t
764
H5FS__cache_hdr_notify(H5AC_notify_action_t action, void *_thing)
765
0
{
766
0
    H5FS_t *fspace    = (H5FS_t *)_thing; /* Pointer to the object */
767
0
    herr_t  ret_value = SUCCEED;          /* Return value */
768
769
0
    FUNC_ENTER_PACKAGE
770
771
    /* Sanity check */
772
0
    assert(fspace);
773
774
    /* Determine which action to take */
775
0
    switch (action) {
776
0
        case H5AC_NOTIFY_ACTION_AFTER_INSERT:
777
0
        case H5AC_NOTIFY_ACTION_AFTER_LOAD:
778
0
        case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
779
            /* do nothing */
780
0
            break;
781
782
0
        case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
783
0
            if (H5AC_unsettle_entry_ring(fspace) < 0)
784
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTFLUSH, FAIL, "unable to mark FSM ring as unsettled");
785
0
            break;
786
787
0
        case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
788
0
        case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
789
0
        case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
790
0
        case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
791
0
        case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
792
0
        case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
793
            /* do nothing */
794
0
            break;
795
796
0
        default:
797
0
#ifdef NDEBUG
798
0
            HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
799
#else  /* NDEBUG */
800
            assert(0 && "Unknown action?!?");
801
#endif /* NDEBUG */
802
0
    }  /* end switch */
803
804
0
done:
805
0
    FUNC_LEAVE_NOAPI(ret_value)
806
0
} /* end H5FS__cache_hdr_notify() */
807
808
/*-------------------------------------------------------------------------
809
 * Function:  H5FS__cache_hdr_free_icr
810
 *
811
 * Purpose: Destroys a free space header in memory.
812
 *
813
 * Return:  Success:        SUCCEED
814
 *              Failure:        FAIL
815
 *
816
 *-------------------------------------------------------------------------
817
 */
818
static herr_t
819
H5FS__cache_hdr_free_icr(void *_thing)
820
0
{
821
0
    H5FS_t *fspace    = (H5FS_t *)_thing; /* Pointer to the object */
822
0
    herr_t  ret_value = SUCCEED;          /* Return value */
823
824
0
    FUNC_ENTER_PACKAGE
825
826
    /* Sanity checks */
827
0
    assert(fspace);
828
0
    assert(fspace->cache_info.type == H5AC_FSPACE_HDR);
829
830
    /* We should not still be holding on to the free space section info */
831
0
    assert(!fspace->sinfo);
832
833
    /* Destroy free space header */
834
0
    if (H5FS__hdr_dest(fspace) < 0)
835
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space header");
836
837
0
done:
838
0
    FUNC_LEAVE_NOAPI(ret_value)
839
0
} /* end H5FS__cache_hdr_free_icr() */
840
841
/*-------------------------------------------------------------------------
842
 * Function:  H5FS__cache_sinfo_get_initial_load_size()
843
 *
844
 * Purpose: Compute the size of the on disk image of the free space
845
 *    manager section info, and place this value in *image_len.
846
 *
847
 * Return:  Success:  SUCCEED
848
 *    Failure:  FAIL
849
 *
850
 *-------------------------------------------------------------------------
851
 */
852
static herr_t
853
H5FS__cache_sinfo_get_initial_load_size(void *_udata, size_t *image_len)
854
0
{
855
0
    const H5FS_t          *fspace;                                  /* free space manager */
856
0
    H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */
857
858
0
    FUNC_ENTER_PACKAGE_NOERR
859
860
    /* Sanity checks */
861
0
    assert(udata);
862
0
    fspace = udata->fspace;
863
0
    assert(fspace);
864
0
    assert(fspace->sect_size > 0);
865
0
    assert(image_len);
866
867
    /* Set the image length size */
868
0
    *image_len = (size_t)(fspace->sect_size);
869
870
0
    FUNC_LEAVE_NOAPI(SUCCEED)
871
0
} /* end H5FS__cache_sinfo_get_initial_load_size() */
872
873
/*-------------------------------------------------------------------------
874
 * Function:    H5FS__cache_sinfo_verify_chksum
875
 *
876
 * Purpose:     Verify the computed checksum of the data structure is the
877
 *              same as the stored chksum.
878
 *
879
 * Return:      Success:        true/false
880
 *              Failure:        Negative
881
 *
882
 *-------------------------------------------------------------------------
883
 */
884
htri_t
885
H5FS__cache_sinfo_verify_chksum(const void *_image, size_t len, void H5_ATTR_UNUSED *_udata)
886
0
{
887
0
    const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
888
0
    uint32_t       stored_chksum;                   /* Stored metadata checksum value */
889
0
    uint32_t       computed_chksum;                 /* Computed metadata checksum value */
890
0
    htri_t         ret_value = true;                /* Return value */
891
892
0
    FUNC_ENTER_PACKAGE
893
894
    /* Check arguments */
895
0
    assert(image);
896
897
    /* Get stored and computed checksums */
898
0
    if (H5F_get_checksums(image, len, &stored_chksum, &computed_chksum) < 0)
899
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTGET, FAIL, "can't get checksums");
900
901
0
    if (stored_chksum != computed_chksum)
902
0
        ret_value = false;
903
904
0
done:
905
0
    FUNC_LEAVE_NOAPI(ret_value)
906
0
} /* end H5FS__cache_sinfo_verify_chksum() */
907
908
/*-------------------------------------------------------------------------
909
 * Function:  H5FS__cache_sinfo_deserialize
910
 *
911
 * Purpose: Given a buffer containing the on disk image of the free space
912
 *    manager section info, allocate an instance of H5FS_sinfo_t, load
913
 *    it with the data contained in the image, and return a pointer to
914
 *    the new instance.
915
 *
916
 * Return:  Success:  Pointer to in core representation
917
 *    Failure:  NULL
918
 *
919
 *-------------------------------------------------------------------------
920
 */
921
static void *
922
H5FS__cache_sinfo_deserialize(const void *_image, size_t H5_ATTR_NDEBUG_UNUSED len, void *_udata,
923
                              bool H5_ATTR_NDEBUG_UNUSED *dirty)
924
0
{
925
0
    H5FS_sinfo_cache_ud_t *udata = (H5FS_sinfo_cache_ud_t *)_udata; /* User data for callback */
926
0
    H5FS_t                *fspace;                                  /* free space manager */
927
0
    H5FS_sinfo_t          *sinfo = NULL;                            /* Free space section info */
928
0
    haddr_t                fs_addr;                                 /* Free space header address */
929
0
    size_t                 old_sect_size;                           /* Old section size */
930
0
    const uint8_t         *image = (const uint8_t *)_image;         /* Pointer into raw data buffer */
931
0
    const uint8_t         *chksum_image;                            /* Points to chksum location */
932
0
    uint32_t               stored_chksum;                           /* Stored metadata checksum  */
933
0
    void                  *ret_value = NULL;                        /* Return value */
934
935
0
    FUNC_ENTER_PACKAGE
936
937
    /* Sanity checks */
938
0
    assert(image);
939
0
    assert(udata);
940
0
    fspace = udata->fspace;
941
0
    assert(fspace);
942
0
    assert(fspace->sect_size == len);
943
0
    assert(dirty);
944
945
    /* Allocate a new free space section info */
946
0
    if (NULL == (sinfo = H5FS__sinfo_new(udata->f, fspace)))
947
0
        HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed");
948
949
    /* initialize old_sect_size */
950
0
    H5_CHECKED_ASSIGN(old_sect_size, size_t, fspace->sect_size, hsize_t);
951
952
    /* Magic number */
953
0
    if (memcmp(image, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC) != 0)
954
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space sections signature");
955
0
    image += H5_SIZEOF_MAGIC;
956
957
    /* Version */
958
0
    if (*image++ != H5FS_SINFO_VERSION)
959
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "wrong free space sections version");
960
961
    /* Address of free space header for these sections */
962
0
    H5F_addr_decode(udata->f, &image, &fs_addr);
963
0
    if (H5_addr_ne(fs_addr, fspace->addr))
964
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "incorrect header address for free space sections");
965
966
    /* Check for any serialized sections */
967
0
    if (fspace->serial_sect_count > 0) {
968
0
        hsize_t old_tot_sect_count; /* Total section count from header */
969
0
        hsize_t H5_ATTR_NDEBUG_UNUSED
970
0
            old_serial_sect_count;                          /* Total serializable section count from header */
971
0
        hsize_t H5_ATTR_NDEBUG_UNUSED old_ghost_sect_count; /* Total ghost section count from header */
972
0
        hsize_t H5_ATTR_NDEBUG_UNUSED old_tot_space;        /* Total space managed from header */
973
0
        unsigned                      sect_cnt_size;        /* The size of the section size counts */
974
975
        /* Compute the size of the section counts */
976
0
        sect_cnt_size = H5VM_limit_enc_size((uint64_t)fspace->serial_sect_count);
977
978
        /* Reset the section count, the "add" routine will update it */
979
0
        old_tot_sect_count        = fspace->tot_sect_count;
980
0
        old_serial_sect_count     = fspace->serial_sect_count;
981
0
        old_ghost_sect_count      = fspace->ghost_sect_count;
982
0
        old_tot_space             = fspace->tot_space;
983
0
        fspace->tot_sect_count    = 0;
984
0
        fspace->serial_sect_count = 0;
985
0
        fspace->ghost_sect_count  = 0;
986
0
        fspace->tot_space         = 0;
987
988
        /* Walk through the image, deserializing sections */
989
0
        do {
990
0
            hsize_t sect_size  = 0; /* Current section size */
991
0
            size_t  node_count = 0; /* # of sections of this size */
992
0
            size_t  u;              /* Local index variable */
993
994
            /* The number of sections of this node's size */
995
0
            UINT64DECODE_VAR(image, node_count, sect_cnt_size);
996
0
            assert(node_count);
997
998
            /* The size of the sections for this node */
999
0
            UINT64DECODE_VAR(image, sect_size, sinfo->sect_len_size);
1000
0
            assert(sect_size);
1001
1002
            /* Loop over nodes of this size */
1003
0
            for (u = 0; u < node_count; u++) {
1004
0
                H5FS_section_info_t *new_sect;      /* Section that was deserialized */
1005
0
                haddr_t              sect_addr = 0; /* Address of free space section in the address space */
1006
0
                unsigned             sect_type;     /* Type of free space section */
1007
0
                unsigned             des_flags;     /* Flags from deserialize callback */
1008
1009
                /* The address of the section */
1010
0
                UINT64DECODE_VAR(image, sect_addr, sinfo->sect_off_size);
1011
1012
                /* The type of this section */
1013
0
                sect_type = *image++;
1014
1015
                /* Validate the section type before using it to index the class
1016
                 * array, otherwise a corrupted file can drive an out-of-bounds
1017
                 * read and an indirect call through a bogus function pointer.
1018
                 */
1019
0
                if (sect_type >= fspace->nclasses)
1020
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTLOAD, NULL, "invalid free space section type");
1021
1022
                /* Call 'deserialize' callback for this section */
1023
0
                des_flags = 0;
1024
0
                assert(fspace->sect_cls[sect_type].deserialize);
1025
0
                if (NULL == (new_sect = (*fspace->sect_cls[sect_type].deserialize)(
1026
0
                                 &fspace->sect_cls[sect_type], image, sect_addr, sect_size, &des_flags)))
1027
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTDECODE, NULL, "can't deserialize section");
1028
1029
                /* Update offset in serialization image */
1030
0
                image += fspace->sect_cls[sect_type].serial_size;
1031
1032
                /* Insert section in free space manager, unless requested not to */
1033
0
                if (!(des_flags & H5FS_DESERIALIZE_NO_ADD))
1034
0
                    if (H5FS_sect_add(udata->f, fspace, new_sect, H5FS_ADD_DESERIALIZING, udata, NULL) < 0)
1035
0
                        HGOTO_ERROR(H5E_FSPACE, H5E_CANTINSERT, NULL,
1036
0
                                    "can't add section to free space manager");
1037
0
            } /* end for */
1038
1039
0
            if (fspace->tot_sect_count == old_tot_sect_count)
1040
0
                break;
1041
1042
0
        } while (image < (((const uint8_t *)_image + old_sect_size) - H5FS_SIZEOF_CHKSUM));
1043
1044
        /* Sanity check */
1045
0
        assert((size_t)(image - (const uint8_t *)_image) <= (old_sect_size - H5FS_SIZEOF_CHKSUM));
1046
0
        assert(old_sect_size == fspace->sect_size);
1047
0
        assert(old_tot_sect_count == fspace->tot_sect_count);
1048
0
        assert(old_serial_sect_count == fspace->serial_sect_count);
1049
0
        assert(old_ghost_sect_count == fspace->ghost_sect_count);
1050
0
        assert(old_tot_space == fspace->tot_space);
1051
0
    } /* end if */
1052
1053
    /* checksum verification already done in verify_chksum cb */
1054
1055
    /* There may be empty space between entries and chksum */
1056
0
    chksum_image = (const uint8_t *)(_image) + old_sect_size - H5FS_SIZEOF_CHKSUM;
1057
    /* Metadata checksum */
1058
0
    UINT32DECODE(chksum_image, stored_chksum);
1059
1060
    /* Sanity check */
1061
0
    assert((image == chksum_image) ||
1062
0
           ((size_t)((image - (const uint8_t *)_image) + (chksum_image - image)) == old_sect_size));
1063
1064
    /* Set return value */
1065
0
    ret_value = sinfo;
1066
1067
0
done:
1068
0
    if (!ret_value && sinfo)
1069
0
        if (H5FS__sinfo_dest(sinfo) < 0)
1070
0
            HDONE_ERROR(H5E_FSPACE, H5E_CANTFREE, NULL, "unable to destroy free space info");
1071
1072
0
    FUNC_LEAVE_NOAPI(ret_value)
1073
0
} /* end H5FS__cache_sinfo_deserialize() */
1074
1075
/*-------------------------------------------------------------------------
1076
 * Function:    H5FS__cache_sinfo_image_len
1077
 *
1078
 * Purpose:     Compute the size of the data structure on disk and return
1079
 *              it in *image_len.
1080
 *
1081
 * Return:      Non-negative on success/Negative on failure
1082
 *
1083
 *-------------------------------------------------------------------------
1084
 */
1085
static herr_t
1086
H5FS__cache_sinfo_image_len(const void *_thing, size_t *image_len)
1087
0
{
1088
0
    const H5FS_sinfo_t *sinfo = (const H5FS_sinfo_t *)_thing; /* Pointer to the object */
1089
1090
0
    FUNC_ENTER_PACKAGE_NOERR
1091
1092
    /* Sanity checks */
1093
0
    assert(sinfo);
1094
0
    assert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
1095
0
    assert(sinfo->fspace);
1096
0
    assert(sinfo->fspace->cache_info.type == H5AC_FSPACE_HDR);
1097
0
    assert(image_len);
1098
1099
    /* Set the image length size */
1100
0
    H5_CHECKED_ASSIGN(*image_len, size_t, sinfo->fspace->alloc_sect_size, hsize_t);
1101
1102
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1103
0
} /* end H5FS__cache_sinfo_image_len() */
1104
1105
/*-------------------------------------------------------------------------
1106
 * Function:  H5FS__cache_sinfo_pre_serialize
1107
 *
1108
 * Purpose: The objective of this function is to test to see if file space
1109
 *    for the section info is located in temporary (AKA imaginary) file
1110
 *    space.  If it is, relocate file space for the section info to
1111
 *    regular file space.
1112
 *
1113
 * Return:  Success:  SUCCEED
1114
 *    Failure:  FAIL
1115
 *
1116
 *-------------------------------------------------------------------------
1117
 */
1118
static herr_t
1119
H5FS__cache_sinfo_pre_serialize(H5F_t *f, void *_thing, haddr_t addr, size_t H5_ATTR_NDEBUG_UNUSED len,
1120
                                haddr_t *new_addr, size_t H5_ATTR_NDEBUG_UNUSED *new_len, unsigned *flags)
1121
0
{
1122
0
    H5FS_sinfo_t *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */
1123
0
    H5FS_t       *fspace;                         /* Free space header */
1124
0
    haddr_t       sinfo_addr;                     /* Address for section info */
1125
0
    herr_t        ret_value = SUCCEED;            /* Return value */
1126
1127
0
    FUNC_ENTER_PACKAGE
1128
1129
    /* Sanity checks */
1130
0
    assert(f);
1131
0
    assert(sinfo);
1132
0
    assert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
1133
0
    fspace = sinfo->fspace;
1134
0
    assert(fspace->cache_info.type == H5AC_FSPACE_HDR);
1135
0
    assert(fspace->cache_info.is_pinned);
1136
0
    assert(H5_addr_defined(addr));
1137
0
    assert(H5_addr_eq(fspace->sect_addr, addr));
1138
0
    assert(fspace->sect_size == len);
1139
0
    assert(new_addr);
1140
0
    assert(new_len);
1141
0
    assert(flags);
1142
1143
0
    sinfo_addr = addr; /* this will change if we relocate the section data */
1144
1145
    /* Check for section info at temporary address */
1146
0
    if (H5F_IS_TMP_ADDR(f, fspace->sect_addr)) {
1147
        /* Sanity check */
1148
0
        assert(fspace->sect_size > 0);
1149
0
        assert(H5_addr_eq(fspace->sect_addr, addr));
1150
1151
        /* Allocate space for the section info in file */
1152
0
        if (HADDR_UNDEF == (sinfo_addr = H5MF_alloc((H5F_t *)f, H5FD_MEM_FSPACE_SINFO, fspace->sect_size)))
1153
0
            HGOTO_ERROR(H5E_FSPACE, H5E_NOSPACE, FAIL, "file allocation failed for free space sections");
1154
1155
0
        fspace->alloc_sect_size = (size_t)fspace->sect_size;
1156
1157
        /* Sanity check */
1158
0
        assert(!H5_addr_eq(sinfo->fspace->sect_addr, sinfo_addr));
1159
1160
        /* Let the metadata cache know the section info moved */
1161
0
        if (H5AC_move_entry((H5F_t *)f, H5AC_FSPACE_SINFO, sinfo->fspace->sect_addr, sinfo_addr) < 0)
1162
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMOVE, FAIL, "unable to move section info");
1163
1164
        /* Update the internal address for the section info */
1165
0
        sinfo->fspace->sect_addr = sinfo_addr;
1166
1167
        /* Mark free space header as dirty */
1168
0
        if (H5AC_mark_entry_dirty(fspace) < 0)
1169
0
            HGOTO_ERROR(H5E_FSPACE, H5E_CANTMARKDIRTY, FAIL, "unable to mark free space header as dirty");
1170
0
    } /* end if */
1171
1172
0
    if (!H5_addr_eq(addr, sinfo_addr)) {
1173
0
        *new_addr = sinfo_addr;
1174
0
        *flags    = H5C__SERIALIZE_MOVED_FLAG;
1175
0
    } /* end if */
1176
0
    else
1177
0
        *flags = 0;
1178
1179
0
done:
1180
0
    FUNC_LEAVE_NOAPI(ret_value)
1181
0
} /* end H5FS__cache_sinfo_pre_serialize() */
1182
1183
/*-------------------------------------------------------------------------
1184
 * Function:  H5FS__cache_sinfo_serialize
1185
 *
1186
 * Purpose: Given an instance of H5FS_sinfo_t and a suitably sized buffer,
1187
 *    serialize the contents of the instance of H5FS_sinfo_t and write
1188
 *    its contents to the buffer.  This buffer will be used to write
1189
 *    the image of the instance to file.
1190
 *
1191
 * Return:  Success:  SUCCEED
1192
 *    Failure:  FAIL
1193
 *
1194
 *-------------------------------------------------------------------------
1195
 */
1196
static herr_t
1197
H5FS__cache_sinfo_serialize(const H5F_t *f, void *_image, size_t len, void *_thing)
1198
0
{
1199
0
    H5FS_sinfo_t  *sinfo = (H5FS_sinfo_t *)_thing; /* Pointer to the object */
1200
0
    H5FS_iter_ud_t udata;                          /* User data for callbacks */
1201
0
    ptrdiff_t      gap_size;
1202
0
    uint8_t       *image        = (uint8_t *)_image; /* Pointer into raw data buffer */
1203
0
    uint8_t       *chksum_image = NULL;              /* Points to chksum location */
1204
0
    uint32_t       metadata_chksum;                  /* Computed metadata checksum value */
1205
0
    unsigned       bin;                              /* Current bin we are on */
1206
0
    herr_t         ret_value = SUCCEED;              /* Return value */
1207
1208
0
    FUNC_ENTER_PACKAGE
1209
1210
    /* Sanity checks */
1211
0
    assert(f);
1212
0
    assert(image);
1213
0
    assert(sinfo);
1214
0
    assert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
1215
0
    assert(sinfo->fspace->cache_info.type == H5AC_FSPACE_HDR);
1216
0
    assert(sinfo->fspace->cache_info.is_pinned);
1217
0
    assert(sinfo->fspace->sect_size == len);
1218
0
    assert(sinfo->fspace->sect_cls);
1219
1220
    /* Magic number */
1221
0
    H5MM_memcpy(image, H5FS_SINFO_MAGIC, (size_t)H5_SIZEOF_MAGIC);
1222
0
    image += H5_SIZEOF_MAGIC;
1223
1224
    /* Version # */
1225
0
    *image++ = H5FS_SINFO_VERSION;
1226
1227
    /* Address of free space header for these sections */
1228
0
    H5F_addr_encode(f, &image, sinfo->fspace->addr);
1229
1230
    /* Set up user data for iterator */
1231
0
    udata.sinfo         = sinfo;
1232
0
    udata.image         = &image;
1233
0
    udata.sect_cnt_size = H5VM_limit_enc_size((uint64_t)sinfo->fspace->serial_sect_count);
1234
1235
    /* Iterate over all the bins */
1236
0
    for (bin = 0; bin < sinfo->nbins; bin++)
1237
        /* Check if there are any sections in this bin */
1238
0
        if (sinfo->bins[bin].bin_list)
1239
            /* Iterate over list of section size nodes for bin */
1240
0
            if (H5SL_iterate(sinfo->bins[bin].bin_list, H5FS__sinfo_serialize_node_cb, &udata) < 0)
1241
0
                HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section size nodes");
1242
1243
    /* Compute checksum */
1244
1245
    /* There may be empty space between entries and chksum */
1246
0
    chksum_image = (uint8_t *)(_image) + len - H5FS_SIZEOF_CHKSUM;
1247
1248
    /*
1249
     * If there is any empty space between the entries and
1250
     * checksum, make sure that the space is initialized
1251
     * before serializing it
1252
     */
1253
0
    gap_size = chksum_image - image;
1254
0
    if (gap_size > 0)
1255
0
        memset(image, 0, (size_t)gap_size);
1256
1257
0
    metadata_chksum = H5_checksum_metadata(_image, (size_t)(chksum_image - (uint8_t *)_image), 0);
1258
    /* Metadata checksum */
1259
0
    UINT32ENCODE(chksum_image, metadata_chksum);
1260
1261
    /* Sanity check */
1262
0
    assert((chksum_image == image) ||
1263
0
           ((size_t)((image - (uint8_t *)_image) + (chksum_image - image)) == sinfo->fspace->sect_size));
1264
0
    assert(sinfo->fspace->sect_size <= sinfo->fspace->alloc_sect_size);
1265
1266
0
done:
1267
0
    FUNC_LEAVE_NOAPI(ret_value)
1268
0
} /* end H5FS__cache_sinfo_serialize() */
1269
1270
/*-------------------------------------------------------------------------
1271
 * Function:    H5FS__cache_sinfo_notify
1272
 *
1273
 * Purpose:     Handle cache action notifications
1274
 *
1275
 * Return:      SUCCEED/FAIL
1276
 *
1277
 *-------------------------------------------------------------------------
1278
 */
1279
herr_t
1280
H5FS__cache_sinfo_notify(H5AC_notify_action_t action, void *_thing)
1281
0
{
1282
0
    H5FS_sinfo_t *sinfo     = (H5FS_sinfo_t *)_thing;
1283
0
    herr_t        ret_value = SUCCEED; /* Return value */
1284
1285
0
    FUNC_ENTER_PACKAGE
1286
1287
    /* Sanity check */
1288
0
    assert(sinfo);
1289
1290
    /* Check if the file was opened with SWMR-write access */
1291
0
    if (sinfo->fspace->swmr_write) {
1292
        /* Determine which action to take */
1293
0
        switch (action) {
1294
0
            case H5AC_NOTIFY_ACTION_AFTER_INSERT:
1295
0
            case H5AC_NOTIFY_ACTION_AFTER_LOAD:
1296
                /* Create flush dependency on parent */
1297
0
                if (H5FS__create_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0)
1298
0
                    HGOTO_ERROR(
1299
0
                        H5E_FSPACE, H5E_CANTDEPEND, FAIL,
1300
0
                        "unable to create flush dependency between data block and header, address = %llu",
1301
0
                        (unsigned long long)sinfo->fspace->sect_addr);
1302
0
                break;
1303
1304
0
            case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
1305
0
            case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
1306
0
            case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
1307
0
            case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
1308
0
            case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
1309
0
            case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
1310
0
            case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
1311
                /* do nothing */
1312
0
                break;
1313
1314
0
            case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
1315
                /* Destroy flush dependency on parent */
1316
0
                if (H5FS__destroy_flush_depend((H5AC_info_t *)sinfo->fspace, (H5AC_info_t *)sinfo) < 0)
1317
0
                    HGOTO_ERROR(H5E_FSPACE, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency");
1318
0
                break;
1319
1320
0
            default:
1321
0
#ifdef NDEBUG
1322
0
                HGOTO_ERROR(H5E_FSPACE, H5E_BADVALUE, FAIL, "unknown action from metadata cache");
1323
#else     /* NDEBUG */
1324
                assert(0 && "Unknown action?!?");
1325
#endif    /* NDEBUG */
1326
0
        } /* end switch */
1327
0
    }     /* end if */
1328
1329
0
done:
1330
0
    FUNC_LEAVE_NOAPI(ret_value)
1331
0
} /* end H5FS__cache_sinfo_notify() */
1332
1333
/*-------------------------------------------------------------------------
1334
 * Function:  H5FS__cache_sinfo_free_icr
1335
 *
1336
 * Purpose: Free the memory used for the in core representation of the
1337
 *    free space manager section info.
1338
 *
1339
 * Return:  Success:  SUCCEED
1340
 *    Failure:  FAIL
1341
 *
1342
 *-------------------------------------------------------------------------
1343
 */
1344
static herr_t
1345
H5FS__cache_sinfo_free_icr(void *_thing)
1346
0
{
1347
0
    H5FS_sinfo_t *sinfo     = (H5FS_sinfo_t *)_thing; /* Pointer to the object */
1348
0
    herr_t        ret_value = SUCCEED;                /* Return value */
1349
1350
0
    FUNC_ENTER_PACKAGE
1351
1352
    /* Sanity checks */
1353
0
    assert(sinfo);
1354
0
    assert(sinfo->cache_info.type == H5AC_FSPACE_SINFO);
1355
0
    assert(sinfo->fspace->cache_info.type == H5AC_FSPACE_HDR);
1356
0
    assert(sinfo->fspace->cache_info.is_pinned);
1357
1358
    /* Destroy free space info */
1359
0
    if (H5FS__sinfo_dest(sinfo) < 0)
1360
0
        HGOTO_ERROR(H5E_FSPACE, H5E_CANTFREE, FAIL, "unable to destroy free space info");
1361
1362
0
done:
1363
0
    FUNC_LEAVE_NOAPI(ret_value)
1364
0
} /* end H5FS__cache_sinfo_free_icr() */
1365
1366
/*-------------------------------------------------------------------------
1367
 * Function:  H5FS__sinfo_serialize_sect_cb
1368
 *
1369
 * Purpose: Skip list iterator callback to serialize free space sections
1370
 *              of a particular size
1371
 *
1372
 * Return:      SUCCEED/FAIL
1373
 *
1374
 *-------------------------------------------------------------------------
1375
 */
1376
static herr_t
1377
H5FS__sinfo_serialize_sect_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
1378
0
{
1379
0
    H5FS_section_class_t *sect_cls;                                 /* Class of section */
1380
0
    H5FS_section_info_t  *sect      = (H5FS_section_info_t *)_item; /* Free space section to work on */
1381
0
    H5FS_iter_ud_t       *udata     = (H5FS_iter_ud_t *)_udata;     /* Callback info */
1382
0
    herr_t                ret_value = SUCCEED;                      /* Return value */
1383
1384
0
    FUNC_ENTER_PACKAGE
1385
1386
    /* Check arguments. */
1387
0
    assert(sect);
1388
0
    assert(udata->sinfo);
1389
0
    assert(udata->image);
1390
1391
    /* Get section's class */
1392
0
    sect_cls = &udata->sinfo->fspace->sect_cls[sect->type];
1393
1394
    /* Check if this section should be serialized (i.e. is not a ghost section) */
1395
0
    if (!(sect_cls->flags & H5FS_CLS_GHOST_OBJ)) {
1396
        /* The address of the section */
1397
0
        UINT64ENCODE_VAR(*udata->image, sect->addr, udata->sinfo->sect_off_size);
1398
1399
        /* The type of this section */
1400
0
        *(*udata->image)++ = (uint8_t)sect->type;
1401
1402
        /* Call 'serialize' callback for this section */
1403
0
        if (sect_cls->serialize) {
1404
0
            if ((*sect_cls->serialize)(sect_cls, sect, *udata->image) < 0)
1405
0
                HGOTO_ERROR(H5E_FSPACE, H5E_CANTSERIALIZE, FAIL, "can't synchronize section");
1406
1407
            /* Update offset in serialization buffer */
1408
0
            (*udata->image) += sect_cls->serial_size;
1409
0
        } /* end if */
1410
0
        else
1411
0
            assert(sect_cls->serial_size == 0);
1412
0
    } /* end if */
1413
1414
0
done:
1415
0
    FUNC_LEAVE_NOAPI(ret_value)
1416
0
} /* H5FS__sinfo_serialize_sect_cb() */
1417
1418
/*-------------------------------------------------------------------------
1419
 * Function:  H5FS__sinfo_serialize_node_cb
1420
 *
1421
 * Purpose: Skip list iterator callback to serialize free space sections
1422
 *              in a bin
1423
 *
1424
 * Return:      SUCCEED/FAIL
1425
 *
1426
 *-------------------------------------------------------------------------
1427
 */
1428
static herr_t
1429
H5FS__sinfo_serialize_node_cb(void *_item, void H5_ATTR_UNUSED *key, void *_udata)
1430
0
{
1431
0
    H5FS_node_t    *fspace_node = (H5FS_node_t *)_item;     /* Free space size node to work on */
1432
0
    H5FS_iter_ud_t *udata       = (H5FS_iter_ud_t *)_udata; /* Callback info */
1433
0
    herr_t          ret_value   = SUCCEED;                  /* Return value */
1434
1435
0
    FUNC_ENTER_PACKAGE
1436
1437
    /* Check arguments. */
1438
0
    assert(fspace_node);
1439
0
    assert(udata->sinfo);
1440
0
    assert(udata->image);
1441
1442
    /* Check if this node has any serializable sections */
1443
0
    if (fspace_node->serial_count > 0) {
1444
        /* The number of serializable sections of this node's size */
1445
0
        UINT64ENCODE_VAR(*udata->image, fspace_node->serial_count, udata->sect_cnt_size);
1446
1447
        /* The size of the sections for this node */
1448
0
        UINT64ENCODE_VAR(*udata->image, fspace_node->sect_size, udata->sinfo->sect_len_size);
1449
1450
        /* Iterate through all the sections of this size */
1451
0
        assert(fspace_node->sect_list);
1452
0
        if (H5SL_iterate(fspace_node->sect_list, H5FS__sinfo_serialize_sect_cb, udata) < 0)
1453
0
            HGOTO_ERROR(H5E_FSPACE, H5E_BADITER, FAIL, "can't iterate over section nodes");
1454
0
    } /* end if */
1455
1456
0
done:
1457
0
    FUNC_LEAVE_NOAPI(ret_value)
1458
0
} /* H5FS__sinfo_serialize_node_cb() */