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