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