^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)