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, §_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 = ℑ
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