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: H5FDspace.c
17 * Jan 3 2008
18 * Quincey Koziol <koziol@hdfgroup.org>
19 *
20 * Purpose: Space allocation routines for the file driver code.
21 *
22 *-------------------------------------------------------------------------
23 */
24
25 /****************/
26 /* Module Setup */
27 /****************/
28
29 #include "H5FDmodule.h" /* This source code file is part of the H5FD module */
30
31
32 /***********/
33 /* Headers */
34 /***********/
35 #include "H5private.h" /* Generic Functions */
36 #include "H5Eprivate.h" /* Error handling */
37 #include "H5Fprivate.h" /* File access */
38 #include "H5FDpkg.h" /* File Drivers */
39 #include "H5FDmulti.h" /* Usage-partitioned file family */
40
41
42 /****************/
43 /* Local Macros */
44 /****************/
45
46 /* Define this to display information about file allocations */
47 /* #define H5FD_ALLOC_DEBUG */
48
49
50 /******************/
51 /* Local Typedefs */
52 /******************/
53
54
55 /********************/
56 /* Package Typedefs */
57 /********************/
58
59
60 /********************/
61 /* Local Prototypes */
62 /********************/
63
64
65 /*********************/
66 /* Package Variables */
67 /*********************/
68
69
70 /*****************************/
71 /* Library Private Variables */
72 /*****************************/
73
74
75 /*******************/
76 /* Local Variables */
77 /*******************/
78
79 /* Declare a free list to manage the H5FD_free_t struct */
80 H5FL_DEFINE(H5FD_free_t);
81
82
83
84 /*-------------------------------------------------------------------------
85 * Function: H5FD_extend
86 *
87 * Purpose: Extend the EOA space of a file.
88 *
89 * NOTE: Returns absolute file offset
90 *
91 * Return: Success: The address of the previous EOA.
92 * Failure: The undefined address HADDR_UNDEF
93 *
94 * Programmer: Bill Wendling
95 * Wednesday, 04. December, 2002
96 *
97 *-------------------------------------------------------------------------
98 */
99 static haddr_t
H5FD_extend(H5FD_t * file,H5FD_mem_t type,hsize_t size)100 H5FD_extend(H5FD_t *file, H5FD_mem_t type, hsize_t size)
101 {
102 hsize_t orig_size = size; /* Original allocation size */
103 haddr_t eoa; /* Address of end-of-allocated space */
104 hsize_t extra; /* Extra space to allocate, to align request */
105 haddr_t ret_value = HADDR_UNDEF; /* Return value */
106
107 FUNC_ENTER_NOAPI_NOINIT
108
109 /* check args */
110 HDassert(file);
111 HDassert(file->cls);
112 HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
113 HDassert(size > 0);
114
115 /* Get current end-of-allocated space address */
116 eoa = file->cls->get_eoa(file, type);
117
118 /* Check for overflow when extending */
119 if(H5F_addr_overflow(eoa, size) || (eoa + size) > file->maxaddr)
120 HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed")
121
122 /* Set the [NOT aligned] address to return */
123 ret_value = eoa;
124
125 /* Extend the end-of-allocated space address */
126 eoa += size;
127 if(file->cls->set_eoa(file, type, eoa) < 0)
128 HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "file allocation request failed")
129
130 done:
131 FUNC_LEAVE_NOAPI(ret_value)
132 } /* end H5FD_extend() */
133
134
135 /*-------------------------------------------------------------------------
136 * Function: H5FD_alloc_real
137 *
138 * Purpose: Allocate space in the file with the VFD
139 * Note: the handling of alignment is moved up from each driver to
140 * this routine.
141 *
142 * Return: Success: The format address of the new file memory.
143 * Failure: The undefined address HADDR_UNDEF
144 *
145 * Programmer: Robb Matzke
146 * Wednesday, August 4, 1999
147 *
148 *-------------------------------------------------------------------------
149 */
150 haddr_t
H5FD_alloc_real(H5FD_t * file,hid_t dxpl_id,H5FD_mem_t type,hsize_t size,haddr_t * frag_addr,hsize_t * frag_size)151 H5FD_alloc_real(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, hsize_t size,
152 haddr_t *frag_addr, hsize_t *frag_size)
153 {
154 hsize_t orig_size = size; /* Original allocation size */
155 haddr_t eoa; /* Address of end-of-allocated space */
156 hsize_t extra; /* Extra space to allocate, to align request */
157 unsigned long flags = 0; /* Driver feature flags */
158 hbool_t use_alloc_size; /* Just pass alloc size to the driver */
159 haddr_t ret_value = HADDR_UNDEF; /* Return value */
160
161 FUNC_ENTER_NOAPI(HADDR_UNDEF)
162 #ifdef H5FD_ALLOC_DEBUG
163 HDfprintf(stderr, "%s: type = %u, size = %Hu\n", FUNC, (unsigned)type, size);
164 #endif /* H5FD_ALLOC_DEBUG */
165
166 /* check args */
167 HDassert(file);
168 HDassert(file->cls);
169 HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
170 HDassert(size > 0);
171
172 /* Check for query driver and call it */
173 if(file->cls->query)
174 (file->cls->query)(file, &flags);
175
176 /* Check for the driver feature flag */
177 use_alloc_size = flags & H5FD_FEAT_USE_ALLOC_SIZE;
178
179 /* Get current end-of-allocated space address */
180 eoa = file->cls->get_eoa(file, type);
181
182 /* Compute extra space to allocate, if this should be aligned */
183 extra = 0;
184 if(!file->paged_aggr && file->alignment > 1 && orig_size >= file->threshold) {
185 hsize_t mis_align; /* Amount EOA is misaligned */
186
187 /* Check for EOA already aligned */
188 if((mis_align = (eoa % file->alignment)) > 0) {
189 extra = file->alignment - mis_align;
190 if(frag_addr)
191 *frag_addr = eoa - file->base_addr; /* adjust for file's base address */
192 if(frag_size)
193 *frag_size = extra;
194 } /* end if */
195 } /* end if */
196
197 /* Dispatch to driver `alloc' callback or extend the end-of-address marker */
198 /* For the multi/split driver: the size passed down to the alloc callback is the original size from H5FD_alloc() */
199 /* For all other drivers: the size passed down to the alloc callback is the size + [possibly] alignment size */
200 if(file->cls->alloc) {
201 ret_value = (file->cls->alloc)(file, type, dxpl_id, use_alloc_size ? size : size + extra);
202 if(!H5F_addr_defined(ret_value))
203 HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver allocation request failed")
204 } /* end if */
205 else {
206 ret_value = H5FD_extend(file, type, size + extra);
207 if(!H5F_addr_defined(ret_value))
208 HGOTO_ERROR(H5E_VFL, H5E_NOSPACE, HADDR_UNDEF, "driver eoa update request failed")
209 } /* end else */
210
211 /* Set the [possibly aligned] address to return */
212 if(!use_alloc_size)
213 ret_value += extra;
214
215 /* Post-condition sanity check */
216 if(!file->paged_aggr && file->alignment > 1 && orig_size >= file->threshold)
217 HDassert(!(ret_value % file->alignment));
218
219 /* Convert absolute file offset to relative address */
220 ret_value -= file->base_addr;
221
222 done:
223 #ifdef H5FD_ALLOC_DEBUG
224 HDfprintf(stderr, "%s: ret_value = %a\n", FUNC, ret_value);
225 #endif /* H5FD_ALLOC_DEBUG */
226 FUNC_LEAVE_NOAPI(ret_value)
227 } /* end H5FD_alloc_real() */
228
229
230 /*-------------------------------------------------------------------------
231 * Function: H5FD_alloc
232 *
233 * Purpose: Wrapper for H5FD_alloc, to make certain EOA changes are
234 * reflected in superblock.
235 *
236 * Note: When the metadata cache routines are updated to allow
237 * marking an entry dirty without a H5F_t*, this routine should
238 * be changed to take a H5F_super_t* directly.
239 *
240 * Return: Success: The format address of the new file memory.
241 * Failure: The undefined address HADDR_UNDEF
242 *
243 * Programmer: Quincey Koziol
244 * Friday, August 14, 2009
245 *
246 *-------------------------------------------------------------------------
247 */
248 haddr_t
H5FD_alloc(H5FD_t * file,hid_t dxpl_id,H5FD_mem_t type,H5F_t * f,hsize_t size,haddr_t * frag_addr,hsize_t * frag_size)249 H5FD_alloc(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, H5F_t *f, hsize_t size,
250 haddr_t *frag_addr, hsize_t *frag_size)
251 {
252 haddr_t ret_value = HADDR_UNDEF; /* Return value */
253
254 FUNC_ENTER_NOAPI(HADDR_UNDEF)
255
256 /* check args */
257 HDassert(file);
258 HDassert(file->cls);
259 HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
260 HDassert(size > 0);
261
262 /* Call the real 'alloc' routine */
263 ret_value = H5FD_alloc_real(file, dxpl_id, type, size, frag_addr, frag_size);
264 if(!H5F_addr_defined(ret_value))
265 HGOTO_ERROR(H5E_VFL, H5E_CANTALLOC, HADDR_UNDEF, "real 'alloc' request failed")
266
267 /* Mark EOA info dirty in cache, so change will get encoded */
268 if(H5F_eoa_dirty(f, dxpl_id) < 0)
269 HGOTO_ERROR(H5E_VFL, H5E_CANTMARKDIRTY, HADDR_UNDEF, "unable to mark EOA info as dirty")
270
271 done:
272 FUNC_LEAVE_NOAPI(ret_value)
273 } /* end H5FD_alloc() */
274
275
276 /*-------------------------------------------------------------------------
277 * Function: H5FD_free_real
278 *
279 * Purpose: Release space back to the VFD
280 *
281 * Return: Success: Non-negative
282 * Failure: Negative
283 *
284 * Programmer: Robb Matzke
285 * Wednesday, August 4, 1999
286 *
287 *-------------------------------------------------------------------------
288 */
289 herr_t
H5FD_free_real(H5FD_t * file,hid_t dxpl_id,H5FD_mem_t type,haddr_t addr,hsize_t size)290 H5FD_free_real(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, hsize_t size)
291 {
292 herr_t ret_value = SUCCEED; /* Return value */
293
294 FUNC_ENTER_NOAPI_NOINIT
295
296 /* Check args */
297 HDassert(file);
298 HDassert(file->cls);
299 HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
300 HDassert(size > 0);
301
302 #ifdef H5FD_ALLOC_DEBUG
303 HDfprintf(stderr, "%s: type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)type, addr, size);
304 #endif /* H5FD_ALLOC_DEBUG */
305
306 /* Sanity checking */
307 if(!H5F_addr_defined(addr))
308 HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid file offset")
309
310 /* Convert address to absolute file offset */
311 addr += file->base_addr;
312
313 /* More sanity checking */
314 if(addr > file->maxaddr || H5F_addr_overflow(addr, size) || (addr + size) > file->maxaddr)
315 HGOTO_ERROR(H5E_VFL, H5E_BADVALUE, FAIL, "invalid file free space region to free")
316
317 /* Check for file driver 'free' callback and call it if available */
318 if(file->cls->free) {
319 #ifdef H5FD_ALLOC_DEBUG
320 HDfprintf(stderr, "%s: Letting VFD free space\n", FUNC);
321 #endif /* H5FD_ALLOC_DEBUG */
322 if((file->cls->free)(file, type, dxpl_id, addr, size) < 0)
323 HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "driver free request failed")
324 } /* end if */
325 /* Check if this free block is at the end of file allocated space.
326 * Truncate it if this is true.
327 */
328 else if(file->cls->get_eoa) {
329 haddr_t eoa;
330
331 eoa = file->cls->get_eoa(file, type);
332 #ifdef H5FD_ALLOC_DEBUG
333 HDfprintf(stderr, "%s: eoa = %a\n", FUNC, eoa);
334 #endif /* H5FD_ALLOC_DEBUG */
335 if(eoa == (addr + size)) {
336 #ifdef H5FD_ALLOC_DEBUG
337 HDfprintf(stderr, "%s: Reducing file size to = %a\n", FUNC, addr);
338 #endif /* H5FD_ALLOC_DEBUG */
339 if(file->cls->set_eoa(file, type, addr) < 0)
340 HGOTO_ERROR(H5E_VFL, H5E_CANTSET, FAIL, "set end of space allocation request failed")
341 } /* end if */
342 } /* end else-if */
343 else {
344 /* leak memory */
345 #ifdef H5FD_ALLOC_DEBUG
346 HDfprintf(stderr, "%s: LEAKED MEMORY!!! type = %u, addr = %a, size = %Hu\n", FUNC, (unsigned)type, addr, size);
347 #endif /* H5FD_ALLOC_DEBUG */
348 } /* end else */
349
350 done:
351 FUNC_LEAVE_NOAPI(ret_value)
352 } /* end H5FD_free_real() */
353
354
355 /*-------------------------------------------------------------------------
356 * Function: H5FD_free
357 *
358 * Purpose: Wrapper for H5FD_free_real, to make certain EOA changes are
359 * reflected in superblock.
360 *
361 * Note: When the metadata cache routines are updated to allow
362 * marking an entry dirty without a H5F_t*, this routine should
363 * be changed to take a H5F_super_t* directly.
364 *
365 * Return: Success: Non-negative
366 * Failure: Negative
367 *
368 * Programmer: Quincey Koziol
369 * Friday, August 14, 2009
370 *
371 *-------------------------------------------------------------------------
372 */
373 herr_t
H5FD_free(H5FD_t * file,hid_t dxpl_id,H5FD_mem_t type,H5F_t * f,haddr_t addr,hsize_t size)374 H5FD_free(H5FD_t *file, hid_t dxpl_id, H5FD_mem_t type, H5F_t *f,
375 haddr_t addr, hsize_t size)
376 {
377 herr_t ret_value = SUCCEED; /* Return value */
378
379 FUNC_ENTER_NOAPI(FAIL)
380
381 /* Check args */
382 HDassert(file);
383 HDassert(file->cls);
384 HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
385 HDassert(size > 0);
386
387 /* Call the real 'free' routine */
388 if(H5FD_free_real(file, dxpl_id, type, addr, size) < 0)
389 HGOTO_ERROR(H5E_VFL, H5E_CANTFREE, FAIL, "real 'free' request failed")
390
391 /* Mark EOA info dirty in cache, so change will get encoded */
392 if(H5F_eoa_dirty(f, dxpl_id) < 0)
393 HGOTO_ERROR(H5E_VFL, H5E_CANTMARKDIRTY, FAIL, "unable to mark EOA info as dirty")
394
395 done:
396 FUNC_LEAVE_NOAPI(ret_value)
397 } /* end H5FD_free() */
398
399
400 /*-------------------------------------------------------------------------
401 * Function: H5FD_try_extend
402 *
403 * Purpose: Extend a block at the end of the file, if possible.
404 *
405 * Note: When the metadata cache routines are updated to allow
406 * marking an entry dirty without a H5F_t*, this routine should
407 * be changed to take a H5F_super_t* directly.
408 *
409 * Return: Success: TRUE(1) - Block was extended
410 * FALSE(0) - Block could not be extended
411 * Failure: FAIL
412 *
413 * Programmer: Quincey Koziol
414 * Thursday, 17. January, 2008
415 *
416 *-------------------------------------------------------------------------
417 */
418 htri_t
H5FD_try_extend(H5FD_t * file,H5FD_mem_t type,H5F_t * f,hid_t dxpl_id,haddr_t blk_end,hsize_t extra_requested)419 H5FD_try_extend(H5FD_t *file, H5FD_mem_t type, H5F_t *f, hid_t dxpl_id,
420 haddr_t blk_end, hsize_t extra_requested)
421 {
422 haddr_t eoa; /* End of allocated space in file */
423 htri_t ret_value = FALSE; /* Return value */
424
425 FUNC_ENTER_NOAPI(FAIL)
426
427 /* check args */
428 HDassert(file);
429 HDassert(file->cls);
430 HDassert(type >= H5FD_MEM_DEFAULT && type < H5FD_MEM_NTYPES);
431 HDassert(extra_requested > 0);
432 HDassert(f);
433
434 /* Retrieve the end of the address space */
435 if(HADDR_UNDEF == (eoa = file->cls->get_eoa(file, type)))
436 HGOTO_ERROR(H5E_VFL, H5E_CANTGET, FAIL, "driver get_eoa request failed")
437
438 /* Adjust block end by base address of the file, to create absolute address */
439 blk_end += file->base_addr;
440
441 /* Check if the block is exactly at the end of the file */
442 if(H5F_addr_eq(blk_end, eoa)) {
443 /* Extend the object by extending the underlying file */
444 if(HADDR_UNDEF == H5FD_extend(file, type, extra_requested))
445 HGOTO_ERROR(H5E_VFL, H5E_CANTEXTEND, FAIL, "driver extend request failed")
446
447 /* Mark EOA info dirty in cache, so change will get encoded */
448 if(H5F_eoa_dirty(f, dxpl_id) < 0)
449 HGOTO_ERROR(H5E_VFL, H5E_CANTMARKDIRTY, FAIL, "unable to mark EOA info as dirty")
450
451 /* Indicate success */
452 HGOTO_DONE(TRUE)
453 } /* end if */
454
455 done:
456 FUNC_LEAVE_NOAPI(ret_value)
457 } /* end H5FD_try_extend() */
458
459