Lines Matching +full:page +full:- +full:size
1 // SPDX-License-Identifier: GPL-2.0-only
12 * page.
19 * single memory page called a "zbud page". The first buddy is "left
20 * justified" at the beginning of the zbud page, and the last buddy is "right
21 * justified" at the end of the zbud page. The benefit is that if either
24 * within the zbud page.
31 * zbud pages are divided into "chunks". The size of the chunks is fixed at
35 * zbud page.
63 * allocation granularity will be in chunks of size PAGE_SIZE/64. As one chunk
64 * in allocated page is occupied by zbud header, NCHUNKS will be calculated to
65 * 63 which shows the max number of free chunks in zbud page, also there will be
70 #define CHUNK_SHIFT (PAGE_SHIFT - NCHUNKS_ORDER)
73 #define NCHUNKS ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT)
78 * struct zbud_pool - stores metadata for each zbud pool
80 * zbud page in the pool
82 * the lists each zbud page is added to depends on the size of
105 * struct zbud_header - zbud page metadata occupying the first chunk of each
106 * zbud page.
107 * @buddy: links the zbud page into the unbuddied/buddied lists in the pool
108 * @first_chunks: the size of the first buddy in chunks, 0 if free
109 * @last_chunks: the size of the last buddy in chunks, 0 if free
126 /* Converts an allocation size in bytes to size in zbud chunks */
127 static int size_to_chunks(size_t size)
129 return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
135 /* Initializes the zbud header of a newly allocated zbud page */
136 static struct zbud_header *init_zbud_page(struct page *page)
138 struct zbud_header *zhdr = page_address(page);
139 zhdr->first_chunks = 0;
140 zhdr->last_chunks = 0;
141 INIT_LIST_HEAD(&zhdr->buddy);
145 /* Resets the struct page fields and frees the page */
152 * Encodes the handle of a particular buddy within a zbud page
170 handle += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT);
174 /* Returns the zbud page where a given handle is stored */
180 /* Returns the number of free chunks in a zbud page */
187 return NCHUNKS - zhdr->first_chunks - zhdr->last_chunks;
194 * zbud_create_pool() - create a new zbud pool
208 spin_lock_init(&pool->lock);
210 INIT_LIST_HEAD(&pool->unbuddied[i]);
211 INIT_LIST_HEAD(&pool->buddied);
212 pool->pages_nr = 0;
217 * zbud_destroy_pool() - destroys an existing zbud pool
228 * zbud_alloc() - allocates a region of a given size
230 * @size: size in bytes of the desired allocation
236 * performed first. If no suitable free region is found, then a new page is
242 * Return: 0 if success and handle is set, otherwise -EINVAL if the size or
243 * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
244 * a new page.
246 static int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
252 struct page *page;
254 if (!size || (gfp & __GFP_HIGHMEM))
255 return -EINVAL;
256 if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
257 return -ENOSPC;
258 chunks = size_to_chunks(size);
259 spin_lock(&pool->lock);
261 /* First, try to find an unbuddied zbud page. */
263 if (!list_empty(&pool->unbuddied[i])) {
264 zhdr = list_first_entry(&pool->unbuddied[i],
266 list_del(&zhdr->buddy);
267 if (zhdr->first_chunks == 0)
275 /* Couldn't find unbuddied zbud page, create new one */
276 spin_unlock(&pool->lock);
277 page = alloc_page(gfp);
278 if (!page)
279 return -ENOMEM;
280 spin_lock(&pool->lock);
281 pool->pages_nr++;
282 zhdr = init_zbud_page(page);
287 zhdr->first_chunks = chunks;
289 zhdr->last_chunks = chunks;
291 if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0) {
294 list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
297 list_add(&zhdr->buddy, &pool->buddied);
301 spin_unlock(&pool->lock);
307 * zbud_free() - frees the allocation associated with the given handle
316 spin_lock(&pool->lock);
319 /* If first buddy, handle will be page aligned */
320 if ((handle - ZHDR_SIZE_ALIGNED) & ~PAGE_MASK)
321 zhdr->last_chunks = 0;
323 zhdr->first_chunks = 0;
326 list_del(&zhdr->buddy);
328 if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
329 /* zbud page is empty, free */
331 pool->pages_nr--;
335 list_add(&zhdr->buddy, &pool->unbuddied[freechunks]);
338 spin_unlock(&pool->lock);
342 * zbud_map() - maps the allocation associated with the given handle
359 * zbud_unmap() - maps the allocation associated with the given handle
368 * zbud_get_pool_pages() - gets the zbud pool size in pages
369 * @pool: pool whose size is being queried
371 * Returns: size in pages of the given pool. The pool lock need not be
376 return pool->pages_nr;
393 static int zbud_zpool_malloc(void *pool, size_t size, gfp_t gfp,
396 return zbud_alloc(pool, size, gfp, handle);
431 MODULE_ALIAS("zpool-zbud");