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://support.hdfgroup.org/ftp/HDF5/releases. *
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: H5Ocache.c
17 * Sep 28 2005
18 * Quincey Koziol <koziol@ncsa.uiuc.edu>
19 *
20 * Purpose: Object header metadata cache virtual functions.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #include "H5Omodule.h" /* This source code file is part of the H5O module */
30
31
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h" /* Generic Functions */
36 #include "H5Eprivate.h" /* Error handling */
37 #include "H5FLprivate.h" /* Free lists */
38 #include "H5MFprivate.h" /* File memory management */
39 #include "H5Opkg.h" /* Object headers */
40 #include "H5WBprivate.h" /* Wrapped Buffers */
41
42
43 /****************/
44 /* Local Macros */
45 /****************/
46
47
48 /******************/
49 /* Local Typedefs */
50 /******************/
51
52
53 /********************/
54 /* Package Typedefs */
55 /********************/
56
57
58 /********************/
59 /* Local Prototypes */
60 /********************/
61
62 /* Metadata cache callbacks */
63 static herr_t H5O__cache_get_initial_load_size(void *udata, size_t *image_len);
64 static herr_t H5O__cache_get_final_load_size(const void *image_ptr, size_t image_len,
65 void *udata, size_t *actual_len);
66 static htri_t H5O__cache_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
67 static void *H5O__cache_deserialize(const void *image, size_t len,
68 void *udata, hbool_t *dirty);
69 static herr_t H5O__cache_image_len(const void *thing, size_t *image_len);
70 static herr_t H5O__cache_serialize(const H5F_t *f, void *image, size_t len,
71 void *thing);
72 static herr_t H5O__cache_notify(H5AC_notify_action_t action, void *_thing);
73 static herr_t H5O__cache_free_icr(void *thing);
74
75 static herr_t H5O__cache_chk_get_initial_load_size(void *udata, size_t *image_len);
76 static htri_t H5O__cache_chk_verify_chksum(const void *image_ptr, size_t len, void *udata_ptr);
77 static void *H5O__cache_chk_deserialize(const void *image, size_t len,
78 void *udata, hbool_t *dirty);
79 static herr_t H5O__cache_chk_image_len(const void *thing, size_t *image_len);
80 static herr_t H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len,
81 void *thing);
82 static herr_t H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing);
83 static herr_t H5O__cache_chk_free_icr(void *thing);
84
85 /* Prefix routines */
86 static herr_t H5O__prefix_deserialize(const uint8_t *image,
87 H5O_cache_ud_t *udata);
88
89 /* Chunk routines */
90 static herr_t H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len,
91 const uint8_t *image, H5O_common_cache_ud_t *udata, hbool_t *dirty);
92 static herr_t H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno);
93
94 /* Misc. routines */
95 static herr_t H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info,
96 const H5O_cont_t *cont);
97
98
99 /*********************/
100 /* Package Variables */
101 /*********************/
102
103 /* H5O object header prefix inherits cache-like properties from H5AC */
104 const H5AC_class_t H5AC_OHDR[1] = {{
105 H5AC_OHDR_ID, /* Metadata client ID */
106 "object header", /* Metadata client name (for debugging) */
107 H5FD_MEM_OHDR, /* File space memory type for client */
108 H5AC__CLASS_SPECULATIVE_LOAD_FLAG, /* Client class behavior flags */
109 H5O__cache_get_initial_load_size, /* 'get_initial_load_size' callback */
110 H5O__cache_get_final_load_size, /* 'get_final_load_size' callback */
111 H5O__cache_verify_chksum, /* 'verify_chksum' callback */
112 H5O__cache_deserialize, /* 'deserialize' callback */
113 H5O__cache_image_len, /* 'image_len' callback */
114 NULL, /* 'pre_serialize' callback */
115 H5O__cache_serialize, /* 'serialize' callback */
116 H5O__cache_notify, /* 'notify' callback */
117 H5O__cache_free_icr, /* 'free_icr' callback */
118 NULL, /* 'fsf_size' callback */
119 }};
120
121 /* H5O object header chunk inherits cache-like properties from H5AC */
122 const H5AC_class_t H5AC_OHDR_CHK[1] = {{
123 H5AC_OHDR_CHK_ID, /* Metadata client ID */
124 "object header continuation chunk", /* Metadata client name (for debugging) */
125 H5FD_MEM_OHDR, /* File space memory type for client */
126 H5AC__CLASS_NO_FLAGS_SET, /* Client class behavior flags */
127 H5O__cache_chk_get_initial_load_size, /* 'get_initial_load_size' callback */
128 NULL, /* 'get_final_load_size' callback */
129 H5O__cache_chk_verify_chksum, /* 'verify_chksum' callback */
130 H5O__cache_chk_deserialize, /* 'deserialize' callback */
131 H5O__cache_chk_image_len, /* 'image_len' callback */
132 NULL, /* 'pre_serialize' callback */
133 H5O__cache_chk_serialize, /* 'serialize' callback */
134 H5O__cache_chk_notify, /* 'notify' callback */
135 H5O__cache_chk_free_icr, /* 'free_icr' callback */
136 NULL, /* 'fsf_size' callback */
137 }};
138
139 /* Declare external the free list for H5O_unknown_t's */
140 H5FL_EXTERN(H5O_unknown_t);
141
142 /* Declare extern the free list for H5O_chunk_proxy_t's */
143 H5FL_EXTERN(H5O_chunk_proxy_t);
144
145 /* Declare the free list for H5O_cont_t sequences */
146 H5FL_SEQ_DEFINE(H5O_cont_t);
147
148
149 /*****************************/
150 /* Library Private Variables */
151 /*****************************/
152
153
154 /*******************/
155 /* Local Variables */
156 /*******************/
157
158
159
160 /*-------------------------------------------------------------------------
161 * Function: H5O__cache_get_initial_load_size()
162 *
163 * Purpose: Tell the metadata cache how much data to read from file in
164 * the first speculative read for the object header.
165 *
166 * Return: Success: SUCCEED
167 * Failure: FAIL
168 *
169 * Programmer: John Mainzer
170 * 7/28/14
171 *
172 *-------------------------------------------------------------------------
173 */
174 static herr_t
H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED * _udata,size_t * image_len)175 H5O__cache_get_initial_load_size(void H5_ATTR_UNUSED *_udata, size_t *image_len)
176 {
177 FUNC_ENTER_STATIC_NOERR
178
179 /* Check arguments */
180 HDassert(image_len);
181
182 /* Set the image length size */
183 *image_len = H5O_SPEC_READ_SIZE;
184
185 FUNC_LEAVE_NOAPI(SUCCEED)
186 } /* end H5O__cache_get_initial_load_size() */
187
188
189 /*-------------------------------------------------------------------------
190 * Function: H5O__cache_get_final_load_size()
191 *
192 * Purpose: Tell the metadata cache the final size of an object header.
193 *
194 * Return: Success: SUCCEED
195 * Failure: FAIL
196 *
197 * Programmer: Quincey Koziol
198 * November 18, 2016
199 *
200 *-------------------------------------------------------------------------
201 */
202 static herr_t
H5O__cache_get_final_load_size(const void * image,size_t image_len,void * _udata,size_t * actual_len)203 H5O__cache_get_final_load_size(const void *image, size_t image_len,
204 void *_udata, size_t *actual_len)
205 {
206 H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */
207 herr_t ret_value = SUCCEED; /* Return value */
208
209 FUNC_ENTER_STATIC
210
211 /* Check arguments */
212 HDassert(image);
213 HDassert(udata);
214 HDassert(actual_len);
215 HDassert(*actual_len == image_len);
216
217 /* Deserialize the object header prefix */
218 if(H5O__prefix_deserialize((const uint8_t *)image, udata) < 0)
219 HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, FAIL, "can't deserialize object header prefix")
220
221 /* Sanity check */
222 HDassert(udata->oh);
223
224 /* Set the final size for the cache image */
225 *actual_len = udata->chunk0_size + (size_t)H5O_SIZEOF_HDR(udata->oh);
226
227 done:
228 FUNC_LEAVE_NOAPI(ret_value)
229 } /* end H5O__cache_get_final_load_size() */
230
231
232 /*-------------------------------------------------------------------------
233 * Function: H5O__cache_verify_chksum
234 *
235 * Purpose: Verify the computed checksum of the data structure is the
236 * same as the stored chksum.
237 *
238 * Return: Success: TRUE/FALSE
239 * Failure: Negative
240 *
241 * Programmer: Vailin Choi
242 * Aug 2015
243 *
244 *-------------------------------------------------------------------------
245 */
246 static htri_t
H5O__cache_verify_chksum(const void * _image,size_t len,void * _udata)247 H5O__cache_verify_chksum(const void *_image, size_t len, void *_udata)
248 {
249 const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
250 H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */
251 htri_t ret_value = TRUE; /* Return value */
252
253 FUNC_ENTER_STATIC_NOERR
254
255 /* Check arguments */
256 HDassert(image);
257 HDassert(udata);
258 HDassert(udata->oh);
259
260 /* There is no checksum for version 1 */
261 if(udata->oh->version != H5O_VERSION_1) {
262 uint32_t stored_chksum; /* Stored metadata checksum value */
263 uint32_t computed_chksum; /* Computed metadata checksum value */
264
265 /* Get stored and computed checksums */
266 H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
267
268 if(stored_chksum != computed_chksum) {
269 /* These fields are not deserialized yet in H5O__prefix_deserialize() */
270 HDassert(udata->oh->chunk == NULL);
271 HDassert(udata->oh->mesg == NULL);
272 HDassert(udata->oh->proxy == NULL);
273
274 /* Indicate that udata->oh is to be freed later
275 in H5O__prefix_deserialize() */
276 udata->free_oh = TRUE;
277 ret_value = FALSE;
278 } /* end if */
279 } /* end if */
280 else
281 HDassert(!(udata->common.file_intent & H5F_ACC_SWMR_WRITE));
282
283 FUNC_LEAVE_NOAPI(ret_value)
284 } /* end H5O__cache_verify_chksum() */
285
286
287 /*-------------------------------------------------------------------------
288 * Function: H5O__cache_deserialize
289 *
290 * Purpose: Attempt to deserialize the object header contained in the
291 * supplied buffer, load the data into an instance of H5O_t, and
292 * return a pointer to the new instance.
293 *
294 * Note that the object header is read with with a speculative read.
295 * If the initial read is too small, make note of this fact and return
296 * without error. H5C_load_entry() will note the size discrepency
297 * and retry the deserialize operation with the correct size read.
298 *
299 * Return: Success: Pointer to in core representation
300 * Failure: NULL
301 *
302 * Programmer: John Mainzer
303 * 7/28/14
304 *
305 *-------------------------------------------------------------------------
306 */
307 static void *
H5O__cache_deserialize(const void * image,size_t len,void * _udata,hbool_t * dirty)308 H5O__cache_deserialize(const void *image, size_t len, void *_udata,
309 hbool_t *dirty)
310 {
311 H5O_t *oh = NULL; /* Object header read in */
312 H5O_cache_ud_t *udata = (H5O_cache_ud_t *)_udata; /* User data for callback */
313 void * ret_value = NULL; /* Return value */
314
315 FUNC_ENTER_STATIC
316
317 /* Check arguments */
318 HDassert(image);
319 HDassert(len > 0);
320 HDassert(udata);
321 HDassert(udata->common.f);
322 HDassert(udata->common.cont_msg_info);
323 HDassert(dirty);
324
325 /* Check for partially deserialized object header */
326 /* (Object header prefix will be deserialized if the object header came
327 * through the 'get_final_load_size' callback and not deserialized if
328 * the object header is coming from a cache image - QAK, 2016/12/14)
329 */
330 if(NULL == udata->oh) {
331 /* Deserialize the object header prefix */
332 if(H5O__prefix_deserialize((const uint8_t *)image, udata) < 0)
333 HGOTO_ERROR(H5E_OHDR, H5E_CANTDECODE, NULL, "can't deserialize object header prefix")
334
335 /* Sanity check */
336 HDassert(udata->oh);
337 } /* end if */
338
339 /* Retrieve partially deserialized object header from user data */
340 oh = udata->oh;
341
342 /* Set SWMR flag, if appropriate */
343 oh->swmr_write = !!(H5F_INTENT(udata->common.f) & H5F_ACC_SWMR_WRITE);
344
345 /* Create object header proxy if doing SWMR writes */
346 if(oh->swmr_write) {
347 /* Create virtual entry, for use as proxy */
348 if(NULL == (oh->proxy = H5AC_proxy_entry_create()))
349 HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, NULL, "can't create object header proxy")
350 } /* end if */
351 else
352 oh->proxy = NULL;
353
354 /* Parse the first chunk */
355 if(H5O__chunk_deserialize(oh, udata->common.addr, udata->chunk0_size, (const uint8_t *)image, &(udata->common), dirty) < 0)
356 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize first object header chunk")
357
358 /* Note that we've loaded the object header from the file */
359 udata->made_attempt = TRUE;
360
361 /* Set return value */
362 ret_value = oh;
363
364 done:
365 /* Release the [possibly partially initialized] object header on errors */
366 if(!ret_value && oh)
367 if(H5O__free(oh) < 0)
368 HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header data")
369
370 FUNC_LEAVE_NOAPI(ret_value)
371 } /* end H5O__cache_deserialize() */
372
373
374 /*-------------------------------------------------------------------------
375 * Function: H5O__cache_image_len
376 *
377 * Purpose: Compute the size in bytes of the specified instance of
378 * H5O_t on disk, and return it in *image_len. On failure,
379 * the value of *image_len is undefined.
380 *
381 * Return: Success: SUCCEED
382 * Failure: FAIL
383 *
384 * Programmer: John Mainzer
385 * 7/28/14
386 *
387 *-------------------------------------------------------------------------
388 */
389 static herr_t
H5O__cache_image_len(const void * _thing,size_t * image_len)390 H5O__cache_image_len(const void *_thing, size_t *image_len)
391 {
392 const H5O_t *oh = (const H5O_t *)_thing; /* Object header to query */
393
394 FUNC_ENTER_STATIC_NOERR
395
396 /* Check arguments */
397 HDassert(oh);
398 HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
399 HDassert(oh->cache_info.type == H5AC_OHDR);
400 HDassert(image_len);
401
402 /* Report the object header's prefix+first chunk length */
403 *image_len = oh->chunk[0].size;
404
405 FUNC_LEAVE_NOAPI(SUCCEED)
406 } /* end H5O__cache_image_len() */
407
408
409 /*-------------------------------------------------------------------------
410 * Function: H5O__cache_serialize
411 *
412 * Purpose: Serialize the contents of the supplied object header, and
413 * load this data into the supplied buffer.
414 *
415 * Return: Success: SUCCEED
416 * Failure: FAIL
417 *
418 * Programmer: John Mainzer
419 * 7/28/14
420 *
421 *-------------------------------------------------------------------------
422 */
423 static herr_t
H5O__cache_serialize(const H5F_t * f,void * image,size_t len,void * _thing)424 H5O__cache_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
425 {
426 H5O_t *oh = (H5O_t *)_thing; /* Object header to encode */
427 uint8_t *chunk_image; /* Pointer to object header prefix buffer */
428 herr_t ret_value = SUCCEED; /* Return value */
429
430 FUNC_ENTER_STATIC
431
432 /* Check arguments */
433 HDassert(f);
434 HDassert(image);
435 HDassert(oh);
436 HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
437 HDassert(oh->cache_info.type == H5AC_OHDR);
438 HDassert(oh->chunk[0].size == len);
439 #ifdef H5O_DEBUG
440 H5O_assert(oh);
441 #endif /* H5O_DEBUG */
442
443 /* Point to raw data 'image' for first chunk, which
444 * has room for the prefix
445 */
446 chunk_image = oh->chunk[0].image;
447
448 /* Later versions of object header prefix have different format and
449 * also require that chunk 0 always be updated, since the checksum
450 * on the entire block of memory needs to be updated if anything is
451 * modified
452 */
453 if(oh->version > H5O_VERSION_1) {
454 uint64_t chunk0_size; /* Size of chunk 0's data */
455
456 HDassert(oh->chunk[0].size >= (size_t)H5O_SIZEOF_HDR(oh));
457 chunk0_size = oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh);
458
459 /* Verify magic number */
460 HDassert(!HDmemcmp(chunk_image, H5O_HDR_MAGIC, H5_SIZEOF_MAGIC));
461 chunk_image += H5_SIZEOF_MAGIC;
462
463 /* Version */
464 *chunk_image++ = oh->version;
465
466 /* Flags */
467 *chunk_image++ = oh->flags;
468
469 /* Time fields */
470 if(oh->flags & H5O_HDR_STORE_TIMES) {
471 UINT32ENCODE(chunk_image, oh->atime);
472 UINT32ENCODE(chunk_image, oh->mtime);
473 UINT32ENCODE(chunk_image, oh->ctime);
474 UINT32ENCODE(chunk_image, oh->btime);
475 } /* end if */
476
477 /* Attribute fields */
478 if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
479 UINT16ENCODE(chunk_image, oh->max_compact);
480 UINT16ENCODE(chunk_image, oh->min_dense);
481 } /* end if */
482
483 /* First chunk size */
484 switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
485 case 0: /* 1 byte size */
486 HDassert(chunk0_size < 256);
487 *chunk_image++ = (uint8_t)chunk0_size;
488 break;
489
490 case 1: /* 2 byte size */
491 HDassert(chunk0_size < 65536);
492 UINT16ENCODE(chunk_image, chunk0_size);
493 break;
494
495 case 2: /* 4 byte size */
496 /* use <= 2**32 -1 to stay within 4 bytes integer range */
497 HDassert(chunk0_size <= 4294967295UL);
498 UINT32ENCODE(chunk_image, chunk0_size);
499 break;
500
501 case 3: /* 8 byte size */
502 UINT64ENCODE(chunk_image, chunk0_size);
503 break;
504
505 default:
506 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0")
507 } /* end switch */
508 } /* end if */
509 else {
510 /* Version */
511 *chunk_image++ = oh->version;
512
513 /* Reserved */
514 *chunk_image++ = 0;
515
516 /* Number of messages */
517 #ifdef H5O_ENABLE_BAD_MESG_COUNT
518 if(oh->store_bad_mesg_count)
519 UINT16ENCODE(chunk_image, (oh->nmesgs - 1))
520 else
521 #endif /* H5O_ENABLE_BAD_MESG_COUNT */
522 UINT16ENCODE(chunk_image, oh->nmesgs);
523
524 /* Link count */
525 UINT32ENCODE(chunk_image, oh->nlink);
526
527 /* First chunk size */
528 UINT32ENCODE(chunk_image, (oh->chunk[0].size - (size_t)H5O_SIZEOF_HDR(oh)));
529
530 /* Zero to alignment */
531 HDmemset(chunk_image, 0, (size_t)(H5O_SIZEOF_HDR(oh) - 12));
532 chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - 12);
533 } /* end else */
534
535 HDassert((size_t)(chunk_image - oh->chunk[0].image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
536
537 /* Serialize messages for this chunk */
538 if(H5O__chunk_serialize(f, oh, (unsigned)0) < 0)
539 HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize first object header chunk")
540
541 /* copy the chunk into the image -- this is potentially expensive.
542 * Can we rework things so that the object header and the cache
543 * share a buffer?
544 */
545 HDmemcpy(image, oh->chunk[0].image, len);
546
547 done:
548 FUNC_LEAVE_NOAPI(ret_value)
549 } /* end H5O__cache_serialize() */
550
551
552 /*-------------------------------------------------------------------------
553 * Function: H5O__cache_notify
554 *
555 * Purpose: Handle cache action notifications
556 *
557 * Return: Non-negative on success/Negative on failure
558 *
559 * Programmer: Quincey Koziol
560 * Jul 23 2016
561 *
562 *-------------------------------------------------------------------------
563 */
564 static herr_t
H5O__cache_notify(H5AC_notify_action_t action,void * _thing)565 H5O__cache_notify(H5AC_notify_action_t action, void *_thing)
566 {
567 H5O_t *oh = (H5O_t *)_thing;
568 herr_t ret_value = SUCCEED; /* Return value */
569
570 FUNC_ENTER_STATIC
571
572 /*
573 * Check arguments.
574 */
575 HDassert(oh);
576
577 switch(action) {
578 case H5AC_NOTIFY_ACTION_AFTER_INSERT:
579 case H5AC_NOTIFY_ACTION_AFTER_LOAD:
580 if(oh->swmr_write) {
581 /* Sanity check */
582 HDassert(oh->proxy);
583
584 /* Register the object header as a parent of the virtual entry */
585 if(H5AC_proxy_entry_add_parent(oh->proxy, oh) < 0)
586 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header as parent of proxy")
587 } /* end if */
588 break;
589
590 case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
591 case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
592 /* do nothing */
593 break;
594
595 case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
596 {
597 unsigned u; /* Local index variable */
598
599 /* Mark messages stored with the object header (i.e. messages in chunk 0) as clean */
600 for(u = 0; u < oh->nmesgs; u++)
601 if(oh->mesg[u].chunkno == 0)
602 oh->mesg[u].dirty = FALSE;
603 #ifndef NDEBUG
604 /* Reset the number of messages dirtied by decoding */
605 oh->ndecode_dirtied = 0;
606 #endif /* NDEBUG */
607 }
608 break;
609
610 case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
611 case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
612 case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
613 case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
614 /* do nothing */
615 break;
616
617 case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
618 if(oh->swmr_write) {
619 /* Unregister the object header as a parent of the virtual entry */
620 if(H5AC_proxy_entry_remove_parent(oh->proxy, oh) < 0)
621 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header as parent of proxy")
622 } /* end if */
623 break;
624
625 default:
626 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
627 } /* end switch */
628
629 done:
630 FUNC_LEAVE_NOAPI(ret_value)
631 } /* end H5O__cache_notify() */
632
633
634 /*-------------------------------------------------------------------------
635 * Function: H5O__cache_free_icr
636 *
637 * Purpose: Free the in core representation of the supplied object header.
638 *
639 * Note: The metadata cache sets the object's cache_info.magic to
640 * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
641 * callback (checked in assert).
642 *
643 * Return: Success: SUCCEED
644 * Failure: FAIL
645 *
646 * Programmer: John Mainzer
647 * 7/28/14
648 *
649 *-------------------------------------------------------------------------
650 */
651 static herr_t
H5O__cache_free_icr(void * _thing)652 H5O__cache_free_icr(void *_thing)
653 {
654 H5O_t *oh = (H5O_t *)_thing; /* Object header to destroy */
655 herr_t ret_value = SUCCEED; /* Return value */
656
657 FUNC_ENTER_STATIC
658
659 /* Check arguments */
660 HDassert(oh);
661 HDassert(oh->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
662 HDassert(oh->cache_info.type == H5AC_OHDR);
663
664 /* Destroy object header */
665 if(H5O__free(oh) < 0)
666 HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header")
667
668 done:
669 FUNC_LEAVE_NOAPI(ret_value)
670 } /* end H5O__cache_free_icr() */
671
672
673 /*-------------------------------------------------------------------------
674 * Function: H5O__cache_chk_get_initial_load_size()
675 *
676 * Purpose: Tell the metadata cache how large the on disk image of the
677 * chunk proxy is, so it can load the image into a buffer for the
678 * deserialize call.
679 *
680 * Return: Success: SUCCEED
681 * Failure: FAIL
682 *
683 * Programmer: John Mainzer
684 * 7/28/14
685 *
686 *-------------------------------------------------------------------------
687 */
688 static herr_t
H5O__cache_chk_get_initial_load_size(void * _udata,size_t * image_len)689 H5O__cache_chk_get_initial_load_size(void *_udata, size_t *image_len)
690 {
691 const H5O_chk_cache_ud_t *udata = (const H5O_chk_cache_ud_t *)_udata; /* User data for callback */
692
693 FUNC_ENTER_STATIC_NOERR
694
695 /* Check arguments */
696 HDassert(udata);
697 HDassert(udata->oh);
698 HDassert(image_len);
699
700 /* Set the image length size */
701 *image_len = udata->size;
702
703 FUNC_LEAVE_NOAPI(SUCCEED)
704 } /* end H5O__cache_chk_get_initial_load_size() */
705
706
707 /*-------------------------------------------------------------------------
708 * Function: H5B2__cache_chk_verify_chksum
709 *
710 * Purpose: Verify the computed checksum of the data structure is the
711 * same as the stored chksum.
712 *
713 * Return: Success: TRUE/FALSE
714 * Failure: Negative
715 *
716 * Programmer: Vailin Choi
717 * Aug 2015
718 *
719 *-------------------------------------------------------------------------
720 */
721 static htri_t
H5O__cache_chk_verify_chksum(const void * _image,size_t len,void * _udata)722 H5O__cache_chk_verify_chksum(const void *_image, size_t len, void *_udata)
723 {
724 const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
725 H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */
726 htri_t ret_value = TRUE; /* Return value */
727
728 FUNC_ENTER_STATIC_NOERR
729
730 /* Check arguments */
731 HDassert(image);
732
733 /* There is no checksum for version 1 */
734 if(udata->oh->version != H5O_VERSION_1) {
735 uint32_t stored_chksum; /* Stored metadata checksum value */
736 uint32_t computed_chksum; /* Computed metadata checksum value */
737
738 /* Get stored and computed checksums */
739 H5F_get_checksums(image, len, &stored_chksum, &computed_chksum);
740
741 if(stored_chksum != computed_chksum)
742 ret_value = FALSE;
743 } /* end if */
744
745 FUNC_LEAVE_NOAPI(ret_value)
746 } /* end H5O__cache_chk_verify_chksum() */
747
748
749 /*-------------------------------------------------------------------------
750 * Function: H5O__cache_chk_deserialize
751 *
752 * Purpose: Attempt to deserialize the object header continuation chunk
753 * contained in the supplied buffer, load the data into an instance
754 * of H5O_chunk_proxy_t, and return a pointer to the new instance.
755 *
756 * Return: Success: Pointer to in core representation
757 * Failure: NULL
758 *
759 * Programmer: John Mainzer
760 * 7/28/14
761 *
762 *-------------------------------------------------------------------------
763 */
764 static void *
H5O__cache_chk_deserialize(const void * image,size_t len,void * _udata,hbool_t * dirty)765 H5O__cache_chk_deserialize(const void *image, size_t len, void *_udata,
766 hbool_t *dirty)
767 {
768 H5O_chunk_proxy_t *chk_proxy = NULL; /* Chunk proxy object */
769 H5O_chk_cache_ud_t *udata = (H5O_chk_cache_ud_t *)_udata; /* User data for callback */
770 void *ret_value = NULL; /* Return value */
771
772 FUNC_ENTER_STATIC
773
774 /* Check arguments */
775 HDassert(image);
776 HDassert(len > 0);
777 HDassert(udata);
778 HDassert(udata->oh);
779 HDassert(dirty);
780
781 /* Allocate space for the object header data structure */
782 if(NULL == (chk_proxy = H5FL_CALLOC(H5O_chunk_proxy_t)))
783 HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, NULL, "memory allocation failed")
784
785 /* Check if we are still decoding the object header */
786 /* (as opposed to bringing a piece of it back from the file) */
787 if(udata->decoding) {
788 /* Sanity check */
789 HDassert(udata->common.f);
790 HDassert(udata->common.cont_msg_info);
791
792 /* Parse the chunk */
793 if(H5O__chunk_deserialize(udata->oh, udata->common.addr, udata->size, (const uint8_t *)image, &(udata->common), dirty) < 0)
794 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, NULL, "can't deserialize object header chunk")
795
796 /* Set the chunk number for the chunk proxy */
797 H5_CHECKED_ASSIGN(chk_proxy->chunkno, unsigned, udata->oh->nchunks - 1, size_t);
798 } /* end if */
799 else {
800 /* Sanity check */
801 HDassert(udata->chunkno < udata->oh->nchunks);
802
803 /* Set the chunk number for the chunk proxy */
804 chk_proxy->chunkno = udata->chunkno;
805
806 /* Sanity check that the chunk representation we have in memory is
807 * the same as the one being brought in from disk.
808 */
809 HDassert(0 == HDmemcmp(image, udata->oh->chunk[chk_proxy->chunkno].image, udata->oh->chunk[chk_proxy->chunkno].size));
810 } /* end else */
811
812 /* Increment reference count of object header */
813 if(H5O__inc_rc(udata->oh) < 0)
814 HGOTO_ERROR(H5E_OHDR, H5E_CANTINC, NULL, "can't increment reference count on object header")
815 chk_proxy->oh = udata->oh;
816
817 /* Set return value */
818 ret_value = chk_proxy;
819
820 done:
821 if(NULL == ret_value)
822 if(chk_proxy && H5O__chunk_dest(chk_proxy) < 0)
823 HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, NULL, "unable to destroy object header chunk")
824
825 FUNC_LEAVE_NOAPI(ret_value)
826 } /* end H5O__cache_chk_deserialize() */
827
828
829 /*-------------------------------------------------------------------------
830 * Function: H5O__cache_chk_image_len
831 *
832 * Purpose: Return the on disk image size of a object header chunk to the
833 * metadata cache via the image_len.
834 *
835 * Return: Success: SUCCEED
836 * Failure: FAIL
837 *
838 * Programmer: John Mainzer
839 * 7/28/14
840 *
841 *-------------------------------------------------------------------------
842 */
843 static herr_t
H5O__cache_chk_image_len(const void * _thing,size_t * image_len)844 H5O__cache_chk_image_len(const void *_thing, size_t *image_len)
845 {
846 const H5O_chunk_proxy_t * chk_proxy = (const H5O_chunk_proxy_t *)_thing; /* Chunk proxy to query */
847
848 FUNC_ENTER_STATIC_NOERR
849
850 /* Check arguments */
851 HDassert(chk_proxy);
852 HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
853 HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
854 HDassert(chk_proxy->oh);
855 HDassert(image_len);
856
857 *image_len = chk_proxy->oh->chunk[chk_proxy->chunkno].size;
858
859 FUNC_LEAVE_NOAPI(SUCCEED)
860 } /* end H5O__cache_chk_image_len() */
861
862
863 /*-------------------------------------------------------------------------
864 * Function: H5O__cache_chk_serialize
865 *
866 * Purpose: Given a pointer to an instance of an object header chunk and an
867 * appropriately sized buffer, serialize the contents of the
868 * instance for writing to disk, and copy the serialized data
869 * into the buffer.
870 *
871 * Return: Success: SUCCEED
872 * Failure: FAIL
873 *
874 * Programmer: John Mainzer
875 * 7/28/14
876 *
877 *-------------------------------------------------------------------------
878 */
879 static herr_t
H5O__cache_chk_serialize(const H5F_t * f,void * image,size_t len,void * _thing)880 H5O__cache_chk_serialize(const H5F_t *f, void *image, size_t len, void *_thing)
881 {
882 H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk to serialize */
883 herr_t ret_value = SUCCEED; /* Return value */
884
885 FUNC_ENTER_STATIC
886
887 /* Check arguments */
888 HDassert(f);
889 HDassert(image);
890 HDassert(chk_proxy);
891 HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
892 HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
893 HDassert(chk_proxy->oh);
894 HDassert(chk_proxy->oh->chunk[chk_proxy->chunkno].size == len);
895
896 /* Serialize messages for this chunk */
897 if(H5O__chunk_serialize(f, chk_proxy->oh, chk_proxy->chunkno) < 0)
898 HGOTO_ERROR(H5E_OHDR, H5E_CANTSERIALIZE, FAIL, "unable to serialize object header continuation chunk")
899
900 /* copy the chunk into the image -- this is potentially expensive.
901 * Can we rework things so that the chunk and the cache share a buffer?
902 */
903 HDmemcpy(image, chk_proxy->oh->chunk[chk_proxy->chunkno].image, len);
904
905 done:
906 FUNC_LEAVE_NOAPI(ret_value)
907 } /* end H5O__cache_chk_serialize() */
908
909
910 /*-------------------------------------------------------------------------
911 * Function: H5O__cache_chk_notify
912 *
913 * Purpose: Handle cache action notifications
914 *
915 * Return: Non-negative on success/Negative on failure
916 *
917 * Programmer: Neil Fortner
918 * Mar 20 2012
919 *
920 *-------------------------------------------------------------------------
921 */
922 static herr_t
H5O__cache_chk_notify(H5AC_notify_action_t action,void * _thing)923 H5O__cache_chk_notify(H5AC_notify_action_t action, void *_thing)
924 {
925 H5O_chunk_proxy_t *chk_proxy = (H5O_chunk_proxy_t *)_thing;
926 herr_t ret_value = SUCCEED; /* Return value */
927
928 FUNC_ENTER_STATIC
929
930 /*
931 * Check arguments.
932 */
933 HDassert(chk_proxy);
934 HDassert(chk_proxy->oh);
935
936 switch(action) {
937 case H5AC_NOTIFY_ACTION_AFTER_INSERT:
938 case H5AC_NOTIFY_ACTION_AFTER_LOAD:
939 if(chk_proxy->oh->swmr_write) {
940 /* Add flush dependency on chunk with continuation, if one exists */
941 if(chk_proxy->fd_parent) {
942 /* Sanity checks */
943 HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
944 HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type);
945 HDassert((((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_ID)
946 || (((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_CHK_ID));
947
948 /* Add flush dependency from chunk containing the continuation message
949 * that points to this chunk (either oh or another chunk proxy object)
950 */
951 if(H5AC_create_flush_dependency(chk_proxy->fd_parent, chk_proxy) < 0)
952 HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
953 } /* end if */
954
955 /* Add flush dependency on object header */
956 {
957 if(H5AC_create_flush_dependency(chk_proxy->oh, chk_proxy) < 0)
958 HGOTO_ERROR(H5E_OHDR, H5E_CANTDEPEND, FAIL, "unable to create flush dependency")
959 } /* end if */
960
961 /* Add flush dependency on object header proxy, if proxy exists */
962 {
963 /* Sanity check */
964 HDassert(chk_proxy->oh->proxy);
965
966 /* Register the object header chunk as a parent of the virtual entry */
967 if(H5AC_proxy_entry_add_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
968 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add object header chunk as parent of proxy")
969 }
970 } /* end if */
971 break;
972
973 case H5AC_NOTIFY_ACTION_AFTER_FLUSH:
974 case H5AC_NOTIFY_ACTION_ENTRY_DIRTIED:
975 /* do nothing */
976 break;
977
978 case H5AC_NOTIFY_ACTION_ENTRY_CLEANED:
979 {
980 unsigned u; /* Local index variable */
981
982 /* Mark messages in chunk as clean */
983 for(u = 0; u < chk_proxy->oh->nmesgs; u++)
984 if(chk_proxy->oh->mesg[u].chunkno == chk_proxy->chunkno)
985 chk_proxy->oh->mesg[u].dirty = FALSE;
986 }
987 break;
988
989 case H5AC_NOTIFY_ACTION_CHILD_DIRTIED:
990 case H5AC_NOTIFY_ACTION_CHILD_CLEANED:
991 case H5AC_NOTIFY_ACTION_CHILD_UNSERIALIZED:
992 case H5AC_NOTIFY_ACTION_CHILD_SERIALIZED:
993 /* do nothing */
994 break;
995
996 case H5AC_NOTIFY_ACTION_BEFORE_EVICT:
997 if(chk_proxy->oh->swmr_write) {
998 /* Remove flush dependency on parent object header chunk, if one is set */
999 if(chk_proxy->fd_parent) {
1000 /* Sanity checks */
1001 HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->magic == H5C__H5C_CACHE_ENTRY_T_MAGIC);
1002 HDassert(((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type);
1003 HDassert((((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_ID) || (((H5C_cache_entry_t *)(chk_proxy->fd_parent))->type->id == H5AC_OHDR_CHK_ID));
1004
1005 if(H5AC_destroy_flush_dependency(chk_proxy->fd_parent, chk_proxy) < 0)
1006 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
1007 chk_proxy->fd_parent = NULL;
1008 } /* end if */
1009
1010 /* Unregister the object header as a parent of the virtual entry */
1011 if(H5AC_destroy_flush_dependency(chk_proxy->oh, chk_proxy) < 0)
1012 HGOTO_ERROR(H5E_OHDR, H5E_CANTUNDEPEND, FAIL, "unable to destroy flush dependency")
1013
1014 /* Unregister the object header chunk as a parent of the virtual entry */
1015 if(H5AC_proxy_entry_remove_parent(chk_proxy->oh->proxy, chk_proxy) < 0)
1016 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't remove object header chunk as parent of proxy")
1017 } /* end if */
1018 break;
1019
1020 default:
1021 #ifdef NDEBUG
1022 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown action from metadata cache")
1023 #else /* NDEBUG */
1024 HDassert(0 && "Unknown action?!?");
1025 #endif /* NDEBUG */
1026 } /* end switch */
1027
1028 done:
1029 FUNC_LEAVE_NOAPI(ret_value)
1030 } /* end H5O__cache_chk_notify() */
1031
1032
1033 /*-------------------------------------------------------------------------
1034 * Function: H5O__cache_chk_free_icr
1035 *
1036 * Purpose: Free the in core memory associated with the supplied object
1037 * header continuation chunk.
1038 *
1039 * Note: The metadata cache sets the object's cache_info.magic to
1040 * H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC before calling a free_icr
1041 * callback (checked in assert).
1042 *
1043 * Return: Success: SUCCEED
1044 * Failure: FAIL
1045 *
1046 * Programmer: John Mainzer
1047 * 7/28/14
1048 *
1049 *-------------------------------------------------------------------------
1050 */
1051 static herr_t
H5O__cache_chk_free_icr(void * _thing)1052 H5O__cache_chk_free_icr(void *_thing)
1053 {
1054 H5O_chunk_proxy_t * chk_proxy = (H5O_chunk_proxy_t *)_thing; /* Object header chunk proxy to release */
1055 herr_t ret_value = SUCCEED; /* Return value */
1056
1057 FUNC_ENTER_STATIC
1058
1059 /* Check arguments */
1060 HDassert(chk_proxy);
1061 HDassert(chk_proxy->cache_info.magic == H5C__H5C_CACHE_ENTRY_T_BAD_MAGIC);
1062 HDassert(chk_proxy->cache_info.type == H5AC_OHDR_CHK);
1063
1064 /* Destroy object header chunk proxy */
1065 if(H5O__chunk_dest(chk_proxy) < 0)
1066 HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header chunk proxy")
1067
1068 done:
1069 FUNC_LEAVE_NOAPI(ret_value)
1070 } /* end H5O__cache_chk_free_icr() */
1071
1072
1073 /*-------------------------------------------------------------------------
1074 * Function: H5O__add_cont_msg
1075 *
1076 * Purpose: Add information from a continuation message to the list of
1077 * continuation messages in the object header
1078 *
1079 * Return: Success: SUCCEED
1080 * Failure: FAIL
1081 *
1082 * Programmer: Quincey Koziol
1083 * koziol@hdfgroup.org
1084 * July 12, 2008
1085 *
1086 *-------------------------------------------------------------------------
1087 */
1088 static herr_t
H5O__add_cont_msg(H5O_cont_msgs_t * cont_msg_info,const H5O_cont_t * cont)1089 H5O__add_cont_msg(H5O_cont_msgs_t *cont_msg_info, const H5O_cont_t *cont)
1090 {
1091 size_t contno; /* Continuation message index */
1092 herr_t ret_value = SUCCEED; /* Return value */
1093
1094 FUNC_ENTER_STATIC
1095
1096 /* Check arguments */
1097 HDassert(cont_msg_info);
1098 HDassert(cont);
1099
1100 /* Increase chunk array size, if necessary */
1101 if(cont_msg_info->nmsgs >= cont_msg_info->alloc_nmsgs) {
1102 size_t na = MAX(H5O_NCHUNKS, cont_msg_info->alloc_nmsgs * 2); /* Double # of messages allocated */
1103 H5O_cont_t *x;
1104
1105 if(NULL == (x = H5FL_SEQ_REALLOC(H5O_cont_t, cont_msg_info->msgs, na)))
1106 HGOTO_ERROR(H5E_OHDR, H5E_NOSPACE, FAIL, "memory allocation failed")
1107 cont_msg_info->alloc_nmsgs = na;
1108 cont_msg_info->msgs = x;
1109 } /* end if */
1110
1111 /* Init the continuation message info */
1112 contno = cont_msg_info->nmsgs++;
1113 cont_msg_info->msgs[contno].addr = cont->addr;
1114 cont_msg_info->msgs[contno].size = cont->size;
1115 cont_msg_info->msgs[contno].chunkno = cont->chunkno;
1116
1117 done:
1118 FUNC_LEAVE_NOAPI(ret_value)
1119 } /* H5O__add_cont_msg() */
1120
1121
1122 /*-------------------------------------------------------------------------
1123 * Function: H5O__prefix_deserialize()
1124 *
1125 * Purpose: Deserialize an object header prefix
1126 *
1127 * Return: Success: SUCCEED
1128 * Failure: FAIL
1129 *
1130 * Programmer: Quincey Koziol
1131 * December 14, 2016
1132 *
1133 *-------------------------------------------------------------------------
1134 */
1135 static herr_t
H5O__prefix_deserialize(const uint8_t * _image,H5O_cache_ud_t * udata)1136 H5O__prefix_deserialize(const uint8_t *_image, H5O_cache_ud_t *udata)
1137 {
1138 const uint8_t *image = (const uint8_t *)_image; /* Pointer into raw data buffer */
1139 H5O_t *oh = NULL; /* Object header read in */
1140 herr_t ret_value = SUCCEED; /* Return value */
1141
1142 FUNC_ENTER_STATIC
1143
1144 /* Check arguments */
1145 HDassert(image);
1146 HDassert(udata);
1147
1148 /* Allocate space for the new object header data structure */
1149 if(NULL == (oh = H5FL_CALLOC(H5O_t)))
1150 HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1151
1152 /* File-specific, non-stored information */
1153 oh->sizeof_size = H5F_SIZEOF_SIZE(udata->common.f);
1154 oh->sizeof_addr = H5F_SIZEOF_ADDR(udata->common.f);
1155
1156 /* Check for presence of magic number */
1157 /* (indicates version 2 or later) */
1158 if(!HDmemcmp(image, H5O_HDR_MAGIC, (size_t)H5_SIZEOF_MAGIC)) {
1159 /* Magic number */
1160 image += H5_SIZEOF_MAGIC;
1161
1162 /* Version */
1163 oh->version = *image++;
1164 if(H5O_VERSION_2 != oh->version)
1165 HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number")
1166
1167 /* Flags */
1168 oh->flags = *image++;
1169 if(oh->flags & ~H5O_HDR_ALL_FLAGS)
1170 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unknown object header status flag(s)")
1171
1172 /* Number of links to object (unless overridden by refcount message) */
1173 oh->nlink = 1;
1174
1175 /* Time fields */
1176 if(oh->flags & H5O_HDR_STORE_TIMES) {
1177 uint32_t tmp; /* Temporary value */
1178
1179 UINT32DECODE(image, tmp);
1180 oh->atime = (time_t)tmp;
1181 UINT32DECODE(image, tmp);
1182 oh->mtime = (time_t)tmp;
1183 UINT32DECODE(image, tmp);
1184 oh->ctime = (time_t)tmp;
1185 UINT32DECODE(image, tmp);
1186 oh->btime = (time_t)tmp;
1187 } /* end if */
1188 else
1189 oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
1190
1191 /* Attribute fields */
1192 if(oh->flags & H5O_HDR_ATTR_STORE_PHASE_CHANGE) {
1193 UINT16DECODE(image, oh->max_compact);
1194 UINT16DECODE(image, oh->min_dense);
1195 if(oh->max_compact < oh->min_dense)
1196 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header attribute phase change values")
1197 } /* end if */
1198 else {
1199 oh->max_compact = H5O_CRT_ATTR_MAX_COMPACT_DEF;
1200 oh->min_dense = H5O_CRT_ATTR_MIN_DENSE_DEF;
1201 } /* end else */
1202
1203 /* First chunk size */
1204 switch(oh->flags & H5O_HDR_CHUNK0_SIZE) {
1205 case 0: /* 1 byte size */
1206 udata->chunk0_size = *image++;
1207 break;
1208
1209 case 1: /* 2 byte size */
1210 UINT16DECODE(image, udata->chunk0_size);
1211 break;
1212
1213 case 2: /* 4 byte size */
1214 UINT32DECODE(image, udata->chunk0_size);
1215 break;
1216
1217 case 3: /* 8 byte size */
1218 UINT64DECODE(image, udata->chunk0_size);
1219 break;
1220
1221 default:
1222 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad size for chunk 0")
1223 } /* end switch */
1224 if(udata->chunk0_size > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh))
1225 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size")
1226 } /* end if */
1227 else {
1228 /* Version */
1229 oh->version = *image++;
1230 if(H5O_VERSION_1 != oh->version)
1231 HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "bad object header version number")
1232
1233 /* Flags */
1234 oh->flags = H5O_CRT_OHDR_FLAGS_DEF;
1235
1236 /* Reserved */
1237 image++;
1238
1239 /* Number of messages */
1240 UINT16DECODE(image, udata->v1_pfx_nmesgs);
1241
1242 /* Link count */
1243 UINT32DECODE(image, oh->nlink);
1244
1245 /* Reset unused time fields */
1246 oh->atime = oh->mtime = oh->ctime = oh->btime = 0;
1247
1248 /* Reset unused attribute fields */
1249 oh->max_compact = 0;
1250 oh->min_dense = 0;
1251
1252 /* First chunk size */
1253 UINT32DECODE(image, udata->chunk0_size);
1254 if((udata->v1_pfx_nmesgs > 0 && udata->chunk0_size < H5O_SIZEOF_MSGHDR_OH(oh)) ||
1255 (udata->v1_pfx_nmesgs == 0 && udata->chunk0_size > 0))
1256 HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "bad object header chunk size")
1257
1258 /* Reserved, in version 1 (for 8-byte alignment padding) */
1259 image += 4;
1260 } /* end else */
1261
1262 /* Verify object header prefix length */
1263 HDassert((size_t)(image - _image) == (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh)));
1264
1265 /* If udata->oh is to be freed (see H5O__cache_verify_chksum),
1266 save the pointer to udata->oh and free it later after setting
1267 udata->oh with the new object header */
1268 if(udata->free_oh) {
1269 H5O_t *saved_oh = udata->oh;
1270 HDassert(udata->oh);
1271
1272 /* Save the object header for later use in 'deserialize' callback */
1273 udata->oh = oh;
1274 if(H5O__free(saved_oh) < 0)
1275 HGOTO_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "can't destroy object header")
1276 udata->free_oh = FALSE;
1277 } else
1278 /* Save the object header for later use in 'deserialize' callback */
1279 udata->oh = oh;
1280
1281 oh = NULL;
1282
1283 done:
1284 /* Release the [possibly partially initialized] object header on errors */
1285 if(ret_value < 0 && oh)
1286 if(H5O__free(oh) < 0)
1287 HDONE_ERROR(H5E_OHDR, H5E_CANTRELEASE, FAIL, "unable to destroy object header data")
1288
1289 FUNC_LEAVE_NOAPI(ret_value)
1290 } /* end H5O__prefix_deserialize() */
1291
1292
1293 /*-------------------------------------------------------------------------
1294 * Function: H5O__chunk_deserialize
1295 *
1296 * Purpose: Deserialize a chunk for an object header
1297 *
1298 * Return: Success: SUCCEED
1299 * Failure: FAIL
1300 *
1301 * Programmer: Quincey Koziol
1302 * koziol@hdfgroup.org
1303 * July 12, 2008
1304 *
1305 *-------------------------------------------------------------------------
1306 */
1307 static herr_t
H5O__chunk_deserialize(H5O_t * oh,haddr_t addr,size_t len,const uint8_t * image,H5O_common_cache_ud_t * udata,hbool_t * dirty)1308 H5O__chunk_deserialize(H5O_t *oh, haddr_t addr, size_t len, const uint8_t *image,
1309 H5O_common_cache_ud_t *udata, hbool_t *dirty)
1310 {
1311 const uint8_t *chunk_image; /* Pointer into buffer to decode */
1312 uint8_t *eom_ptr; /* Pointer to end of messages for a chunk */
1313 unsigned merged_null_msgs = 0; /* Number of null messages merged together */
1314 unsigned chunkno; /* Current chunk's index */
1315 #ifndef NDEBUG
1316 unsigned nullcnt; /* Count of null messages (for sanity checking gaps in chunks) */
1317 #endif /* NDEBUG */
1318 hbool_t mesgs_modified = FALSE; /* Whether any messages were modified when the object header was deserialized */
1319 herr_t ret_value = SUCCEED; /* Return value */
1320
1321 FUNC_ENTER_STATIC
1322
1323 /* Check arguments */
1324 HDassert(oh);
1325 HDassert(H5F_addr_defined(addr));
1326 HDassert(image);
1327 HDassert(udata->f);
1328 HDassert(udata->cont_msg_info);
1329
1330 /* Increase chunk array size, if necessary */
1331 if(oh->nchunks >= oh->alloc_nchunks) {
1332 size_t na = MAX(H5O_NCHUNKS, oh->alloc_nchunks * 2); /* Double # of chunks allocated */
1333 H5O_chunk_t *x;
1334
1335 if(NULL == (x = H5FL_SEQ_REALLOC(H5O_chunk_t, oh->chunk, na)))
1336 HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1337 oh->alloc_nchunks = na;
1338 oh->chunk = x;
1339 } /* end if */
1340
1341 /* Init the chunk data info */
1342 chunkno = (unsigned)oh->nchunks++;
1343 oh->chunk[chunkno].gap = 0;
1344 oh->chunk[chunkno].addr = addr;
1345 if(chunkno == 0)
1346 /* First chunk's 'image' includes room for the object header prefix */
1347 oh->chunk[0].size = len + (size_t)H5O_SIZEOF_HDR(oh);
1348 else
1349 oh->chunk[chunkno].size = len;
1350 if(NULL == (oh->chunk[chunkno].image = H5FL_BLK_MALLOC(chunk_image, oh->chunk[chunkno].size)))
1351 HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1352 oh->chunk[chunkno].chunk_proxy = NULL;
1353
1354 /* Copy disk image into chunk's image */
1355 HDmemcpy(oh->chunk[chunkno].image, image, oh->chunk[chunkno].size);
1356
1357 /* Point into chunk image to decode */
1358 chunk_image = oh->chunk[chunkno].image;
1359
1360 /* Handle chunk 0 as special case */
1361 if(chunkno == 0)
1362 /* Skip over [already decoded] prefix */
1363 chunk_image += (size_t)(H5O_SIZEOF_HDR(oh) - H5O_SIZEOF_CHKSUM_OH(oh));
1364 /* Check for magic # on chunks > 0 in later versions of the format */
1365 else if(chunkno > 0 && oh->version > H5O_VERSION_1) {
1366 /* Magic number */
1367 if(HDmemcmp(chunk_image, H5O_CHK_MAGIC, (size_t)H5_SIZEOF_MAGIC))
1368 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "wrong object header chunk signature")
1369 chunk_image += H5_SIZEOF_MAGIC;
1370 } /* end if */
1371
1372 /* Decode messages from this chunk */
1373 eom_ptr = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM_OH(oh));
1374 #ifndef NDEBUG
1375 nullcnt = 0;
1376 #endif /* NDEBUG */
1377 while(chunk_image < eom_ptr) {
1378 size_t mesg_size; /* Size of message read in */
1379 unsigned id; /* ID (type) of current message */
1380 uint8_t flags; /* Flags for current message */
1381 H5O_msg_crt_idx_t crt_idx = 0; /* Creation index for current message */
1382
1383 /* Decode message prefix info */
1384
1385 /* Version # */
1386 if(oh->version == H5O_VERSION_1)
1387 UINT16DECODE(chunk_image, id)
1388 else
1389 id = *chunk_image++;
1390
1391 /* Message size */
1392 UINT16DECODE(chunk_image, mesg_size);
1393 if(mesg_size != H5O_ALIGN_OH(oh, mesg_size))
1394 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message not aligned")
1395
1396 /* Message flags */
1397 flags = *chunk_image++;
1398 if(flags & ~H5O_MSG_FLAG_BITS)
1399 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unknown flag for message")
1400 if((flags & H5O_MSG_FLAG_SHARED) && (flags & H5O_MSG_FLAG_DONTSHARE))
1401 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
1402 if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
1403 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
1404 if((flags & H5O_MSG_FLAG_WAS_UNKNOWN) && !(flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN))
1405 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "bad flag combination for message")
1406 /* Delay checking the "shareable" flag until we've made sure id
1407 * references a valid message class that this version of the library
1408 * knows about */
1409
1410 /* Reserved bytes/creation index */
1411 if(oh->version == H5O_VERSION_1)
1412 chunk_image += 3; /*reserved*/
1413 else {
1414 /* Only decode creation index if they are being tracked */
1415 if(oh->flags & H5O_HDR_ATTR_CRT_ORDER_TRACKED)
1416 UINT16DECODE(chunk_image, crt_idx);
1417 } /* end else */
1418
1419 /* Try to detect invalidly formatted object header message that
1420 * extends past end of chunk.
1421 */
1422 if(chunk_image + mesg_size > eom_ptr)
1423 HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "corrupt object header")
1424
1425 #ifndef NDEBUG
1426 /* Increment count of null messages */
1427 if(H5O_NULL_ID == id)
1428 nullcnt++;
1429 #endif /* NDEBUG */
1430
1431 /* Check for combining two adjacent 'null' messages */
1432 if((udata->file_intent & H5F_ACC_RDWR) &&
1433 H5O_NULL_ID == id && oh->nmesgs > 0 &&
1434 H5O_NULL_ID == oh->mesg[oh->nmesgs - 1].type->id &&
1435 oh->mesg[oh->nmesgs - 1].chunkno == chunkno) {
1436
1437 size_t mesgno; /* Current message to operate on */
1438
1439 /* Combine adjacent null messages */
1440 mesgno = oh->nmesgs - 1;
1441 oh->mesg[mesgno].raw_size += (size_t)H5O_SIZEOF_MSGHDR_OH(oh) + mesg_size;
1442 oh->mesg[mesgno].dirty = TRUE;
1443 merged_null_msgs++;
1444 } /* end if */
1445 else {
1446 H5O_mesg_t *mesg; /* Pointer to new message */
1447 unsigned ioflags = 0; /* Flags for decode routine */
1448
1449 /* Check if we need to extend message table to hold the new message */
1450 if(oh->nmesgs >= oh->alloc_nmesgs)
1451 if(H5O_alloc_msgs(oh, (size_t)1) < 0)
1452 HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "can't allocate more space for messages")
1453
1454 /* Get pointer to message to set up */
1455 mesg = &oh->mesg[oh->nmesgs];
1456
1457 /* Increment # of messages */
1458 oh->nmesgs++;
1459
1460 /* Initialize information about message */
1461 mesg->dirty = FALSE;
1462 mesg->flags = flags;
1463 mesg->crt_idx = crt_idx;
1464 mesg->native = NULL;
1465 mesg->raw = (uint8_t *)chunk_image; /* Casting away const OK - QAK */
1466 mesg->raw_size = mesg_size;
1467 mesg->chunkno = chunkno;
1468
1469 /* Point unknown messages at 'unknown' message class */
1470 /* (Usually from future versions of the library) */
1471 if(id >= H5O_UNKNOWN_ID ||
1472 #ifdef H5O_ENABLE_BOGUS
1473 id == H5O_BOGUS_VALID_ID ||
1474 #endif
1475 NULL == H5O_msg_class_g[id]) {
1476
1477 H5O_unknown_t *unknown; /* Pointer to "unknown" message info */
1478
1479 /* Allocate "unknown" message info */
1480 if(NULL == (unknown = H5FL_MALLOC(H5O_unknown_t)))
1481 HGOTO_ERROR(H5E_OHDR, H5E_CANTALLOC, FAIL, "memory allocation failed")
1482
1483 /* Save the original message type ID */
1484 *unknown = id;
1485
1486 /* Save 'native' form of unknown message */
1487 mesg->native = unknown;
1488
1489 /* Set message to "unknown" class */
1490 mesg->type = H5O_msg_class_g[H5O_UNKNOWN_ID];
1491
1492 /* Check for "fail if unknown" message flags */
1493 if(((udata->file_intent & H5F_ACC_RDWR) &&
1494 (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_AND_OPEN_FOR_WRITE))
1495 || (flags & H5O_MSG_FLAG_FAIL_IF_UNKNOWN_ALWAYS))
1496 HGOTO_ERROR(H5E_OHDR, H5E_BADMESG, FAIL, "unknown message with 'fail if unknown' flag found")
1497 /* Check for "mark if unknown" message flag, etc. */
1498 else if((flags & H5O_MSG_FLAG_MARK_IF_UNKNOWN) &&
1499 !(flags & H5O_MSG_FLAG_WAS_UNKNOWN) &&
1500 (udata->file_intent & H5F_ACC_RDWR)) {
1501
1502 /* Mark the message as "unknown" */
1503 /* This is a bit aggressive, since the application may
1504 * never change anything about the object (metadata or
1505 * raw data), but we can sort out the finer details
1506 * when/if we start using the flag - QAK
1507 */
1508 /* Also, it's possible that this functionality may not
1509 * get invoked if the object header is brought into
1510 * the metadata cache in some other "weird" way, like
1511 * using H5Ocopy() - QAK
1512 */
1513 mesg->flags |= H5O_MSG_FLAG_WAS_UNKNOWN;
1514
1515 /* Mark the message and chunk as dirty */
1516 mesg->dirty = TRUE;
1517 mesgs_modified = TRUE;
1518 } /* end if */
1519 } /* end if */
1520 else {
1521 /* Check for message of unshareable class marked as "shareable"
1522 */
1523 if((flags & H5O_MSG_FLAG_SHAREABLE)
1524 && H5O_msg_class_g[id]
1525 && !(H5O_msg_class_g[id]->share_flags & H5O_SHARE_IS_SHARABLE))
1526 HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "message of unshareable class flagged as shareable")
1527
1528 /* Set message class for "known" messages */
1529 mesg->type = H5O_msg_class_g[id];
1530 } /* end else */
1531
1532 /* Do some inspection/interpretation of new messages from this chunk */
1533 /* (detect continuation messages, ref. count messages, etc.) */
1534
1535 /* Check if message is a continuation message */
1536 if(H5O_CONT_ID == id) {
1537 H5O_cont_t *cont;
1538
1539 /* Decode continuation message */
1540 cont = (H5O_cont_t *)(H5O_MSG_CONT->decode)(udata->f, NULL, 0, &ioflags, mesg->raw_size, mesg->raw);
1541 H5_CHECKED_ASSIGN(cont->chunkno, unsigned, udata->cont_msg_info->nmsgs + 1, size_t); /* the next continuation message/chunk */
1542
1543 /* Save 'native' form of continuation message */
1544 mesg->native = cont;
1545
1546 /* Add to continuation messages left to interpret */
1547 if(H5O__add_cont_msg(udata->cont_msg_info, cont) < 0)
1548 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't add continuation message")
1549 } /* end if */
1550 /* Check if message is a ref. count message */
1551 else if(H5O_REFCOUNT_ID == id) {
1552 H5O_refcount_t *refcount;
1553
1554 /* Decode ref. count message */
1555 if(oh->version <= H5O_VERSION_1)
1556 HGOTO_ERROR(H5E_OHDR, H5E_VERSION, FAIL, "object header version does not support reference count message")
1557 refcount = (H5O_refcount_t *)(H5O_MSG_REFCOUNT->decode)(udata->f, NULL, 0, &ioflags, mesg->raw_size, mesg->raw);
1558
1559 /* Save 'native' form of ref. count message */
1560 mesg->native = refcount;
1561
1562 /* Set object header values */
1563 oh->has_refcount_msg = TRUE;
1564 if(!refcount)
1565 HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't decode refcount")
1566 oh->nlink = *refcount;
1567 } /* end if */
1568 /* Check if message is a link message */
1569 else if(H5O_LINK_ID == id) {
1570 /* Increment the count of link messages */
1571 oh->link_msgs_seen++;
1572 } /* end if */
1573 /* Check if message is an attribute message */
1574 else if(H5O_ATTR_ID == id) {
1575 /* Increment the count of attribute messages */
1576 oh->attr_msgs_seen++;
1577 } /* end if */
1578
1579 /* Mark the message & chunk as dirty if the message was changed by decoding */
1580 if((ioflags & H5O_DECODEIO_DIRTY) && (udata->file_intent & H5F_ACC_RDWR)) {
1581 mesg->dirty = TRUE;
1582 mesgs_modified = TRUE;
1583 } /* end if */
1584 } /* end else */
1585
1586 /* Advance decode pointer past message */
1587 chunk_image += mesg_size;
1588
1589 /* Check for 'gap' at end of chunk */
1590 if((eom_ptr - chunk_image) > 0 && (eom_ptr - chunk_image) < H5O_SIZEOF_MSGHDR_OH(oh)) {
1591 /* Gaps can only occur in later versions of the format */
1592 HDassert(oh->version > H5O_VERSION_1);
1593
1594 /* Gaps should only occur in chunks with no null messages */
1595 HDassert(nullcnt == 0);
1596
1597 /* Set gap information for chunk */
1598 oh->chunk[chunkno].gap = (size_t)(eom_ptr - chunk_image);
1599
1600 /* Increment location in chunk */
1601 chunk_image += oh->chunk[chunkno].gap;
1602 } /* end if */
1603 } /* end while */
1604
1605 /* Check for correct checksum on chunks, in later versions of the format */
1606 if(oh->version > H5O_VERSION_1) {
1607 uint32_t stored_chksum; /* Checksum from file */
1608
1609 /* checksum verification already done in verify_chksum cb */
1610
1611 /* Metadata checksum */
1612 UINT32DECODE(chunk_image, stored_chksum);
1613 } /* end if */
1614
1615 /* Sanity check */
1616 HDassert(chunk_image == oh->chunk[chunkno].image + oh->chunk[chunkno].size);
1617
1618 /* Mark the chunk dirty if we've modified messages */
1619 if(mesgs_modified)
1620 *dirty = TRUE;
1621
1622 /* Mark the chunk dirty if we've merged null messages */
1623 if(merged_null_msgs > 0) {
1624 udata->merged_null_msgs += merged_null_msgs;
1625 *dirty = TRUE;
1626 } /* end if */
1627
1628 done:
1629 if(ret_value < 0 && udata->cont_msg_info->msgs) {
1630 udata->cont_msg_info->msgs = H5FL_SEQ_FREE(H5O_cont_t, udata->cont_msg_info->msgs);
1631 udata->cont_msg_info->alloc_nmsgs = 0;
1632 }
1633 FUNC_LEAVE_NOAPI(ret_value)
1634 } /* H5O__chunk_deserialize() */
1635
1636
1637 /*-------------------------------------------------------------------------
1638 * Function: H5O__chunk_serialize
1639 *
1640 * Purpose: Serialize a chunk for an object header
1641 *
1642 * Return: Success: SUCCEED
1643 * Failure: FAIL
1644 *
1645 * Programmer: Quincey Koziol
1646 * koziol@hdfgroup.org
1647 * July 12, 2008
1648 *
1649 *-------------------------------------------------------------------------
1650 */
1651 static herr_t
H5O__chunk_serialize(const H5F_t * f,H5O_t * oh,unsigned chunkno)1652 H5O__chunk_serialize(const H5F_t *f, H5O_t *oh, unsigned chunkno)
1653 {
1654 H5O_mesg_t *curr_msg; /* Pointer to current message being operated on */
1655 unsigned u; /* Local index variable */
1656 herr_t ret_value = SUCCEED; /* Return value */
1657
1658 FUNC_ENTER_STATIC
1659
1660 /* Check arguments */
1661 HDassert(f);
1662 HDassert(oh);
1663
1664 /* Encode any dirty messages in this chunk */
1665 for(u = 0, curr_msg = &oh->mesg[0]; u < oh->nmesgs; u++, curr_msg++)
1666 if(curr_msg->dirty && curr_msg->chunkno == chunkno)
1667 /* Casting away const OK -QAK */
1668 if(H5O_msg_flush((H5F_t *)f, oh, curr_msg) < 0)
1669 HGOTO_ERROR(H5E_OHDR, H5E_CANTENCODE, FAIL, "unable to encode object header message")
1670
1671 /* Sanity checks */
1672 if(oh->version > H5O_VERSION_1)
1673 /* Make certain the magic # is present */
1674 HDassert(!HDmemcmp(oh->chunk[chunkno].image, (chunkno == 0 ? H5O_HDR_MAGIC : H5O_CHK_MAGIC), H5_SIZEOF_MAGIC));
1675 else
1676 /* Gaps should never occur in version 1 of the format */
1677 HDassert(oh->chunk[chunkno].gap == 0);
1678
1679 /* Extra work, for later versions of the format */
1680 if(oh->version > H5O_VERSION_1) {
1681 uint32_t metadata_chksum; /* Computed metadata checksum value */
1682 uint8_t *chunk_image; /* Pointer into object header chunk */
1683
1684 /* Check for gap in chunk & zero it out */
1685 if(oh->chunk[chunkno].gap)
1686 HDmemset((oh->chunk[chunkno].image + oh->chunk[chunkno].size) -
1687 (H5O_SIZEOF_CHKSUM + oh->chunk[chunkno].gap), 0, oh->chunk[chunkno].gap);
1688
1689 /* Compute metadata checksum */
1690 metadata_chksum = H5_checksum_metadata(oh->chunk[chunkno].image, (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM), 0);
1691
1692 /* Metadata checksum */
1693 chunk_image = oh->chunk[chunkno].image + (oh->chunk[chunkno].size - H5O_SIZEOF_CHKSUM);
1694 UINT32ENCODE(chunk_image, metadata_chksum);
1695 } /* end if */
1696
1697 done:
1698 FUNC_LEAVE_NOAPI(ret_value)
1699 } /* H5O__chunk_serialize() */
1700
1701