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 storage based on element counts, sizes, and alignment. 21 * 22 * This is a generalized form of our allocation use case: It allocates an array of objects, 23 * optionally preceded by one object of another type (i.e., a struct with trailing variable-length 24 * array), with the alignment indicated. 25 * 26 * Why is this inline? The sizes and alignment will always be constant, when invoked through the 27 * macros below, and often the count will be a compile-time constant 1 or the number of extra bytes 28 * will be a compile-time constant 0. So at least some of the arithmetic can usually be optimized 29 * away, and the run-time selection between allocation functions always can. In many cases, it'll 30 * boil down to just a function call with a constant size. 31 * 32 * @count: The number of objects to allocate 33 * @size: The size of an object 34 * @extra: The number of additional bytes to allocate 35 * @align: The required alignment 36 * @what: What is being allocated (for error logging) 37 * @ptr: A pointer to hold the allocated memory 38 * 39 * Return: VDO_SUCCESS or an error code 40 */ 41 static inline int __vdo_do_allocation(size_t count, size_t size, size_t extra, 42 size_t align, const char *what, void *ptr) 43 { 44 size_t total_size = count * size + extra; 45 46 /* Overflow check: */ 47 if ((size > 0) && (count > ((SIZE_MAX - extra) / size))) { 48 /* 49 * This is kind of a hack: We rely on the fact that SIZE_MAX would cover the entire 50 * address space (minus one byte) and thus the system can never allocate that much 51 * and the call will always fail. So we can report an overflow as "out of memory" 52 * by asking for "merely" SIZE_MAX bytes. 53 */ 54 total_size = SIZE_MAX; 55 } 56 57 return vdo_allocate_memory(total_size, align, what, ptr); 58 } 59 60 /* 61 * Allocate one or more elements of the indicated type, logging an error if the allocation fails. 62 * The memory will be zeroed. 63 * 64 * @COUNT: The number of objects to allocate 65 * @TYPE: The type of objects to allocate. This type determines the alignment of the allocation. 66 * @WHAT: What is being allocated (for error logging) 67 * @PTR: A pointer to hold the allocated memory 68 * 69 * Return: VDO_SUCCESS or an error code 70 */ 71 #define vdo_allocate(COUNT, TYPE, WHAT, PTR) \ 72 __vdo_do_allocation(COUNT, sizeof(TYPE), 0, __alignof__(TYPE), WHAT, PTR) 73 74 /* 75 * Allocate a structure with a flexible array member, with a specified number of elements, logging 76 * an error if the allocation fails. The memory will be zeroed. 77 * 78 * @COUNT: The number of objects to allocate 79 * @FIELD: The flexible array field at the end of the structure 80 * @WHAT: What is being allocated (for error logging) 81 * @PTR: A pointer to hold the allocated memory 82 * 83 * Return: VDO_SUCCESS or an error code 84 */ 85 #define vdo_allocate_extended(COUNT, FIELD, WHAT, PTR) \ 86 vdo_allocate_memory(struct_size(*(PTR), FIELD, (COUNT)), \ 87 __alignof__(typeof(**(PTR))), \ 88 WHAT, \ 89 (PTR)) 90 91 /* 92 * Allocate memory starting on a cache line boundary, logging an error if the allocation fails. The 93 * memory will be zeroed. 94 * 95 * @size: The number of bytes to allocate 96 * @what: What is being allocated (for error logging) 97 * @ptr: A pointer to hold the allocated memory 98 * 99 * Return: VDO_SUCCESS or an error code 100 */ 101 static inline int __must_check vdo_allocate_cache_aligned(size_t size, const char *what, void *ptr) 102 { 103 return vdo_allocate_memory(size, L1_CACHE_BYTES, what, ptr); 104 } 105 106 /* 107 * Allocate one element of the indicated type immediately, failing if the required memory is not 108 * immediately available. 109 * 110 * @size: The number of bytes to allocate 111 * @what: What is being allocated (for error logging) 112 * 113 * Return: pointer to the memory, or NULL if the memory is not available. 114 */ 115 void *__must_check vdo_allocate_memory_nowait(size_t size, const char *what); 116 117 int __must_check vdo_reallocate_memory(void *ptr, size_t old_size, size_t size, 118 const char *what, void *new_ptr); 119 120 int __must_check vdo_duplicate_string(const char *string, const char *what, 121 char **new_string); 122 123 /* Free memory allocated with vdo_allocate(). */ 124 void vdo_free(void *ptr); 125 126 static inline void *__vdo_forget(void **ptr_ptr) 127 { 128 void *ptr = *ptr_ptr; 129 130 *ptr_ptr = NULL; 131 return ptr; 132 } 133 134 /* 135 * Null out a pointer and return a copy to it. This macro should be used when passing a pointer to 136 * a function for which it is not safe to access the pointer once the function returns. 137 */ 138 #define vdo_forget(ptr) __vdo_forget((void **) &(ptr)) 139 140 void vdo_memory_init(void); 141 142 void vdo_memory_exit(void); 143 144 void vdo_register_allocating_thread(struct registered_thread *new_thread, 145 const bool *flag_ptr); 146 147 void vdo_unregister_allocating_thread(void); 148 149 void vdo_get_memory_stats(u64 *bytes_used, u64 *peak_bytes_used); 150 151 void vdo_report_memory_usage(void); 152 153 #endif /* VDO_MEMORY_ALLOC_H */ 154