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