Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2)  * A Remote Heap.  Remote means that we don't touch the memory that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * heap points to. Normal heap implementations use the memory they manage
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * to place their list. We cannot do that because the memory we manage may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * have special properties, for example it is uncachable or of different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * endianess.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * Author: Pantelis Antoniou <panto@intracom.gr>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * 2004 (c) INTRACOM S.A. Greece. This file is licensed under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * the terms of the GNU General Public License version 2. This program
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * is licensed "as is" without any warranty of any kind, whether express
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <asm/rheap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  * Fixup a list_head, needed when copying lists.  If the pointers fall
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  * between s and e, apply the delta.  This assumes that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  * sizeof(struct list_head *) == sizeof(unsigned long *).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) static inline void fixup(unsigned long s, unsigned long e, int d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 			 struct list_head *l)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	unsigned long *pp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	pp = (unsigned long *)&l->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	if (*pp >= s && *pp < e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 		*pp += d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	pp = (unsigned long *)&l->prev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	if (*pp >= s && *pp < e)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 		*pp += d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) /* Grow the allocated blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) static int grow(rh_info_t * info, int max_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	rh_block_t *block, *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	int i, new_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	int delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	unsigned long blks, blke;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	if (max_blocks <= info->max_blocks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	new_blocks = max_blocks - info->max_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	block = kmalloc_array(max_blocks, sizeof(rh_block_t), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	if (block == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	if (info->max_blocks > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		/* copy old block area */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		memcpy(block, info->block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		       sizeof(rh_block_t) * info->max_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		delta = (char *)block - (char *)info->block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		/* and fixup list pointers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		blks = (unsigned long)info->block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		blke = (unsigned long)(info->block + info->max_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		for (i = 0, blk = block; i < info->max_blocks; i++, blk++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 			fixup(blks, blke, delta, &blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		fixup(blks, blke, delta, &info->empty_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		fixup(blks, blke, delta, &info->free_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		fixup(blks, blke, delta, &info->taken_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		/* free the old allocated memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		if ((info->flags & RHIF_STATIC_BLOCK) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 			kfree(info->block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	info->block = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	info->empty_slots += new_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	info->max_blocks = max_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	info->flags &= ~RHIF_STATIC_BLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	/* add all new blocks to the free list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	blk = block + info->max_blocks - new_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	for (i = 0; i < new_blocks; i++, blk++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		list_add(&blk->list, &info->empty_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99)  * Assure at least the required amount of empty slots.  If this function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)  * causes a grow in the block area then all pointers kept to the block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)  * area are invalid!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static int assure_empty(rh_info_t * info, int slots)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	int max_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	/* This function is not meant to be used to grow uncontrollably */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	if (slots >= 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	/* Enough space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	if (info->empty_slots >= slots)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	/* Next 16 sized block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	max_blocks = ((info->max_blocks + slots) + 15) & ~15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	return grow(info, max_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static rh_block_t *get_slot(rh_info_t * info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	/* If no more free slots, and failure to extend. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	/* XXX: You should have called assure_empty before */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	if (info->empty_slots == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		printk(KERN_ERR "rh: out of slots; crash is imminent.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	/* Get empty slot to use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	blk = list_entry(info->empty_list.next, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	list_del_init(&blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	info->empty_slots--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	/* Initialize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	blk->start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	blk->size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	blk->owner = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	return blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static inline void release_slot(rh_info_t * info, rh_block_t * blk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	list_add(&blk->list, &info->empty_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	info->empty_slots++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	rh_block_t *before;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	rh_block_t *after;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	rh_block_t *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	unsigned long s, e, bs, be;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	/* We assume that they are aligned properly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	size = blkn->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	s = blkn->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	e = s + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	/* Find the blocks immediately before and after the given one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	 * (if any) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	before = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	after = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	next = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	list_for_each(l, &info->free_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		blk = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		bs = blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		be = bs + blk->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		if (next == NULL && s >= bs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 			next = blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		if (be == s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			before = blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		if (e == bs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			after = blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		/* If both are not null, break now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		if (before != NULL && after != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	/* Now check if they are really adjacent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	if (before && s != (before->start + before->size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		before = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	if (after && e != after->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		after = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	/* No coalescing; list insert and return */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	if (before == NULL && after == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		if (next != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 			list_add(&blkn->list, &next->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 			list_add(&blkn->list, &info->free_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	/* We don't need it anymore */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	release_slot(info, blkn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	/* Grow the before block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	if (before != NULL && after == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		before->size += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	/* Grow the after block backwards */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	if (before == NULL && after != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		after->start -= size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		after->size += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	/* Grow the before block, and release the after block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	before->size += size + after->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	list_del(&after->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	release_slot(info, after);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static void attach_taken_block(rh_info_t * info, rh_block_t * blkn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	/* Find the block immediately before the given one (if any) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	list_for_each(l, &info->taken_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 		blk = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		if (blk->start > blkn->start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 			list_add_tail(&blkn->list, &blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	list_add_tail(&blkn->list, &info->taken_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)  * Create a remote heap dynamically.  Note that no memory for the blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)  * are allocated.  It will upon the first allocation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) rh_info_t *rh_create(unsigned int alignment)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	rh_info_t *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	/* Alignment must be a power of two */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	if ((alignment & (alignment - 1)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	info = kmalloc(sizeof(*info), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	if (info == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	info->alignment = alignment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	/* Initially everything as empty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	info->block = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	info->max_blocks = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	info->empty_slots = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	info->flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	INIT_LIST_HEAD(&info->empty_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	INIT_LIST_HEAD(&info->free_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	INIT_LIST_HEAD(&info->taken_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 	return info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) EXPORT_SYMBOL_GPL(rh_create);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)  * Destroy a dynamically created remote heap.  Deallocate only if the areas
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)  * are not static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) void rh_destroy(rh_info_t * info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	if ((info->flags & RHIF_STATIC_BLOCK) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		kfree(info->block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	if ((info->flags & RHIF_STATIC_INFO) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 		kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) EXPORT_SYMBOL_GPL(rh_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)  * Initialize in place a remote heap info block.  This is needed to support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)  * operation very early in the startup of the kernel, when it is not yet safe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)  * to call kmalloc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	     rh_block_t * block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	/* Alignment must be a power of two */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	if ((alignment & (alignment - 1)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	info->alignment = alignment;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	/* Initially everything as empty */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	info->block = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	info->max_blocks = max_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	info->empty_slots = max_blocks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	info->flags = RHIF_STATIC_INFO | RHIF_STATIC_BLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	INIT_LIST_HEAD(&info->empty_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	INIT_LIST_HEAD(&info->free_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	INIT_LIST_HEAD(&info->taken_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	/* Add all new blocks to the free list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	for (i = 0, blk = block; i < max_blocks; i++, blk++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 		list_add(&blk->list, &info->empty_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) EXPORT_SYMBOL_GPL(rh_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* Attach a free memory region, coalesces regions if adjacent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) int rh_attach_region(rh_info_t * info, unsigned long start, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	unsigned long s, e, m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	/* The region must be aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	s = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	e = s + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	m = info->alignment - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	/* Round start up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	s = (s + m) & ~m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	/* Round end down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	e = e & ~m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	if (IS_ERR_VALUE(e) || (e < s))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 		return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	/* Take final values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	start = s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	size = e - s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	/* Grow the blocks, if needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	r = assure_empty(info, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	blk = get_slot(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	blk->start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	blk->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 	blk->owner = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	attach_free_block(info, blk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) EXPORT_SYMBOL_GPL(rh_attach_region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) /* Detatch given address range, splits free block if needed. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	rh_block_t *blk, *newblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	unsigned long s, e, m, bs, be;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 	/* Validate size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	if (size <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		return (unsigned long) -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	/* The region must be aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	s = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	e = s + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	m = info->alignment - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	/* Round start up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	s = (s + m) & ~m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	/* Round end down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	e = e & ~m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	if (assure_empty(info, 1) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		return (unsigned long) -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	list_for_each(l, &info->free_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 		blk = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 		/* The range must lie entirely inside one free block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		bs = blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		be = blk->start + blk->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 		if (s >= bs && e <= be)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 		blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	if (blk == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 		return (unsigned long) -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	/* Perfect fit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	if (bs == s && be == e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		/* Delete from free list, release slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		list_del(&blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 		release_slot(info, blk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		return s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	/* blk still in free list, with updated start and/or size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	if (bs == s || be == e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 		if (bs == s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 			blk->start += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		blk->size -= size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 		/* The front free fragment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 		blk->size = s - bs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 		/* the back free fragment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 		newblk = get_slot(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		newblk->start = e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 		newblk->size = be - e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 		list_add(&newblk->list, &blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	return s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) EXPORT_SYMBOL_GPL(rh_detach_region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) /* Allocate a block of memory at the specified alignment.  The value returned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)  * is an offset into the buffer initialized by rh_init(), or a negative number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)  * if there is an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	rh_block_t *newblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	unsigned long start, sp_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	/* Validate size, and alignment must be power of two */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	if (size <= 0 || (alignment & (alignment - 1)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 		return (unsigned long) -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	/* Align to configured alignment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	if (assure_empty(info, 2) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		return (unsigned long) -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 	blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	list_for_each(l, &info->free_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		blk = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 		if (size <= blk->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 			start = (blk->start + alignment - 1) & ~(alignment - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 			if (start + size <= blk->start + blk->size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 				break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 		blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	if (blk == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 		return (unsigned long) -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	/* Just fits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	if (blk->size == size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 		/* Move from free list to taken list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 		list_del(&blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		newblk = blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 		/* Fragment caused, split if needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 		/* Create block for fragment in the beginning */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 		sp_size = start - blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 		if (sp_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 			rh_block_t *spblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 			spblk = get_slot(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 			spblk->start = blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 			spblk->size = sp_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 			/* add before the blk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 			list_add(&spblk->list, blk->list.prev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 		newblk = get_slot(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 		newblk->start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 		newblk->size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 		/* blk still in free list, with updated start and size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 		 * for fragment in the end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 		blk->start = start + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 		blk->size -= sp_size + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 		/* No fragment in the end, remove blk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 		if (blk->size == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 			list_del(&blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 			release_slot(info, blk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	newblk->owner = owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	attach_taken_block(info, newblk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 	return start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) EXPORT_SYMBOL_GPL(rh_alloc_align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /* Allocate a block of memory at the default alignment.  The value returned is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)  * an offset into the buffer initialized by rh_init(), or a negative number if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)  * there is an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) unsigned long rh_alloc(rh_info_t * info, int size, const char *owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	return rh_alloc_align(info, size, info->alignment, owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) EXPORT_SYMBOL_GPL(rh_alloc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /* Allocate a block of memory at the given offset, rounded up to the default
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)  * alignment.  The value returned is an offset into the buffer initialized by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)  * rh_init(), or a negative number if there is an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size, const char *owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	rh_block_t *blk, *newblk1, *newblk2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	unsigned long s, e, m, bs = 0, be = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 	/* Validate size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	if (size <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		return (unsigned long) -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	/* The region must be aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	s = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	e = s + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	m = info->alignment - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	/* Round start up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	s = (s + m) & ~m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	/* Round end down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	e = e & ~m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	if (assure_empty(info, 2) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 		return (unsigned long) -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 	blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	list_for_each(l, &info->free_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 		blk = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 		/* The range must lie entirely inside one free block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 		bs = blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 		be = blk->start + blk->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 		if (s >= bs && e <= be)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 		blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	if (blk == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 		return (unsigned long) -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 	/* Perfect fit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 	if (bs == s && be == e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 		/* Move from free list to taken list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 		list_del(&blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 		blk->owner = owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 		start = blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 		attach_taken_block(info, blk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 		return start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 	/* blk still in free list, with updated start and/or size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 	if (bs == s || be == e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 		if (bs == s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 			blk->start += size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 		blk->size -= size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 		/* The front free fragment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 		blk->size = s - bs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 		/* The back free fragment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 		newblk2 = get_slot(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 		newblk2->start = e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 		newblk2->size = be - e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 		list_add(&newblk2->list, &blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	newblk1 = get_slot(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	newblk1->start = s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 	newblk1->size = e - s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	newblk1->owner = owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	start = newblk1->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	attach_taken_block(info, newblk1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	return start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) EXPORT_SYMBOL_GPL(rh_alloc_fixed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) /* Deallocate the memory previously allocated by one of the rh_alloc functions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)  * The return value is the size of the deallocated block, or a negative number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)  * if there is an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) int rh_free(rh_info_t * info, unsigned long start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 	rh_block_t *blk, *blk2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 	/* Linear search for block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 	blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 	list_for_each(l, &info->taken_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 		blk2 = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 		if (start < blk2->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 		blk = blk2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	if (blk == NULL || start > (blk->start + blk->size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	/* Remove from taken list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 	list_del(&blk->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 	/* Get size of freed block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 	size = blk->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 	attach_free_block(info, blk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 	return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) EXPORT_SYMBOL_GPL(rh_free);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 	rh_block_t *blk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 	struct list_head *h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 	int nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 	switch (what) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 	case RHGS_FREE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 		h = &info->free_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 	case RHGS_TAKEN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 		h = &info->taken_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 	/* Linear search for block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 	nr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	list_for_each(l, h) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 		blk = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 		if (stats != NULL && nr < max_stats) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 			stats->start = blk->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 			stats->size = blk->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 			stats->owner = blk->owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 			stats++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 		nr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 	return nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) EXPORT_SYMBOL_GPL(rh_get_stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 	rh_block_t *blk, *blk2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	struct list_head *l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 	/* Linear search for block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 	blk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 	list_for_each(l, &info->taken_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 		blk2 = list_entry(l, rh_block_t, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 		if (start < blk2->start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 		blk = blk2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	if (blk == NULL || start > (blk->start + blk->size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	blk->owner = owner;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 	size = blk->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	return size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) EXPORT_SYMBOL_GPL(rh_set_owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) void rh_dump(rh_info_t * info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 	static rh_stats_t st[32];	/* XXX maximum 32 blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 	int maxnr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 	int i, nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	maxnr = ARRAY_SIZE(st);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 	printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 	       "info @0x%p (%d slots empty / %d max)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 	       info, info->empty_slots, info->max_blocks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 	printk(KERN_INFO "  Free:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 	nr = rh_get_stats(info, RHGS_FREE, maxnr, st);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	if (nr > maxnr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 		nr = maxnr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 	for (i = 0; i < nr; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 		printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 		       "    0x%lx-0x%lx (%u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 		       st[i].start, st[i].start + st[i].size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 		       st[i].size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	printk(KERN_INFO "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 	printk(KERN_INFO "  Taken:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 	nr = rh_get_stats(info, RHGS_TAKEN, maxnr, st);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 	if (nr > maxnr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 		nr = maxnr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 	for (i = 0; i < nr; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 		printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 		       "    0x%lx-0x%lx (%u) %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 		       st[i].start, st[i].start + st[i].size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		       st[i].size, st[i].owner != NULL ? st[i].owner : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 	printk(KERN_INFO "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) EXPORT_SYMBOL_GPL(rh_dump);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 	printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 	       "blk @0x%p: 0x%lx-0x%lx (%u)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 	       blk, blk->start, blk->start + blk->size, blk->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) EXPORT_SYMBOL_GPL(rh_dump_blk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)