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