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