1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3 * Copyright 2023 Red Hat
4 */
5
6 #ifndef VDO_MEMORY_ALLOC_H
7 #define VDO_MEMORY_ALLOC_H
8
9 #include <linux/cache.h>
10 #include <linux/io.h> /* for PAGE_SIZE */
11 #include <linux/overflow.h>
12
13 #include "permassert.h"
14 #include "thread-registry.h"
15
16 /* Custom memory allocation function that tracks memory usage */
17 int __must_check vdo_allocate_memory(size_t size, size_t align, const char *what, void *ptr);
18
19 /*
20 * Allocate one or more elements of the indicated type, logging an error if the allocation fails.
21 * The memory will be zeroed.
22 *
23 * @COUNT: The number of objects to allocate
24 * @WHAT: What is being allocated (for error logging)
25 * @PTR: A pointer to hold the allocated memory
26 *
27 * Return: VDO_SUCCESS or an error code
28 */
29 #define vdo_allocate(COUNT, WHAT, PTR) \
30 vdo_allocate_memory(size_mul((COUNT), sizeof(typeof(**(PTR)))), \
31 __alignof__(typeof(**(PTR))), WHAT, PTR)
32
33 /*
34 * Allocate a structure with a flexible array member, with a specified number of elements, logging
35 * an error if the allocation fails. The memory will be zeroed.
36 *
37 * @COUNT: The number of objects to allocate
38 * @FIELD: The flexible array field at the end of the structure
39 * @WHAT: What is being allocated (for error logging)
40 * @PTR: A pointer to hold the allocated memory
41 *
42 * Return: VDO_SUCCESS or an error code
43 */
44 #define vdo_allocate_extended(COUNT, FIELD, WHAT, PTR) \
45 vdo_allocate_memory(struct_size(*(PTR), FIELD, (COUNT)), \
46 __alignof__(typeof(**(PTR))), \
47 WHAT, \
48 (PTR))
49
50 /*
51 * Allocate memory starting on a cache line boundary, logging an error if the allocation fails. The
52 * memory will be zeroed.
53 *
54 * @size: The number of bytes to allocate
55 * @what: What is being allocated (for error logging)
56 * @ptr: A pointer to hold the allocated memory
57 *
58 * Return: VDO_SUCCESS or an error code
59 */
vdo_allocate_cache_aligned(size_t size,const char * what,void * ptr)60 static inline int __must_check vdo_allocate_cache_aligned(size_t size, const char *what, void *ptr)
61 {
62 return vdo_allocate_memory(size, L1_CACHE_BYTES, what, ptr);
63 }
64
65 /*
66 * Allocate one element of the indicated type immediately, failing if the required memory is not
67 * immediately available.
68 *
69 * @size: The number of bytes to allocate
70 * @what: What is being allocated (for error logging)
71 *
72 * Return: pointer to the memory, or NULL if the memory is not available.
73 */
74 void *__must_check vdo_allocate_memory_nowait(size_t size, const char *what);
75
76 int __must_check vdo_reallocate_memory(void *ptr, size_t old_size, size_t size,
77 const char *what, void *new_ptr);
78
79 int __must_check vdo_duplicate_string(const char *string, const char *what,
80 char **new_string);
81
82 /* Free memory allocated with vdo_allocate(). */
83 void vdo_free(void *ptr);
84
__vdo_forget(void ** ptr_ptr)85 static inline void *__vdo_forget(void **ptr_ptr)
86 {
87 void *ptr = *ptr_ptr;
88
89 *ptr_ptr = NULL;
90 return ptr;
91 }
92
93 /*
94 * Null out a pointer and return a copy to it. This macro should be used when passing a pointer to
95 * a function for which it is not safe to access the pointer once the function returns.
96 */
97 #define vdo_forget(ptr) __vdo_forget((void **) &(ptr))
98
99 void vdo_memory_init(void);
100
101 void vdo_memory_exit(void);
102
103 void vdo_register_allocating_thread(struct registered_thread *new_thread,
104 const bool *flag_ptr);
105
106 void vdo_unregister_allocating_thread(void);
107
108 void vdo_get_memory_stats(u64 *bytes_used, u64 *peak_bytes_used);
109
110 void vdo_report_memory_usage(void);
111
112 #endif /* VDO_MEMORY_ALLOC_H */
113