|  | #include <vfs.h> | 
|  | #include <kfs.h> | 
|  | #include <slab.h> | 
|  | #include <kmalloc.h> | 
|  | #include <kref.h> | 
|  | #include <string.h> | 
|  | #include <stdio.h> | 
|  | #include <assert.h> | 
|  | #include <error.h> | 
|  | #include <cpio.h> | 
|  | #include <pmap.h> | 
|  | #include <smp.h> | 
|  |  | 
|  | enum { | 
|  | Hdrspc = 64,				/* leave room for high-level headers */ | 
|  | Bdead = 0x51494F42,	/* "QIOB" */ | 
|  | BLOCKALIGN = 32,	/* known to be good for all systems. */ | 
|  | }; | 
|  |  | 
|  | static atomic_t ialloc_bytes = 0; | 
|  |  | 
|  | static struct block *_allocb(int size) | 
|  | { | 
|  | struct block *b; | 
|  | uint8_t *p; | 
|  | int n; | 
|  |  | 
|  | n = BLOCKALIGN + ROUNDUP(size + Hdrspc, BLOCKALIGN) + sizeof(struct block); | 
|  | if ((p = kzmalloc(n, KMALLOC_WAIT)) == NULL) | 
|  | return NULL; | 
|  |  | 
|  | b = (struct block *)(p + n - sizeof(struct block));	/* block at end of allocated space */ | 
|  | b->base = p; | 
|  |  | 
|  | b->next = NULL; | 
|  | b->list = NULL; | 
|  | b->free = 0; | 
|  | b->flag = 0; | 
|  |  | 
|  | /* align base and bounds of data */ | 
|  | b->lim = (uint8_t *) ((uintptr_t) b & ~(BLOCKALIGN - 1)); | 
|  |  | 
|  | /* align start of writable data, leaving space below for added headers */ | 
|  | b->rp = b->lim - ROUNDUP(size, BLOCKALIGN); | 
|  | b->wp = b->rp; | 
|  |  | 
|  | if (b->rp < b->base || b->lim - b->rp < size) | 
|  | panic("_allocb"); | 
|  |  | 
|  | return b; | 
|  | } | 
|  |  | 
|  | struct block *allocb(int size) | 
|  | { | 
|  | struct block *b; | 
|  |  | 
|  | /* | 
|  | * Check in a process and wait until successful. | 
|  | * Can still error out of here, though. | 
|  | * should only be called from user context. | 
|  | */ | 
|  | if ((b = _allocb(size)) == NULL) { | 
|  | panic("allocb: no memory for %d bytes\n", size); | 
|  | } | 
|  |  | 
|  | return b; | 
|  | } | 
|  |  | 
|  | /* interrupt context allocb. */ | 
|  | struct block *iallocb(int size) | 
|  | { | 
|  | struct block *b; | 
|  | static int m1, m2, mp; | 
|  |  | 
|  | if ((b = _allocb(size)) == NULL) { | 
|  | if ((m2++ % 10000) == 0) { | 
|  | if (mp++ > 1000) { | 
|  | panic("iallocb"); | 
|  | } | 
|  | printd("iallocb: no memory \n"); | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  | b->flag = BINTR; | 
|  |  | 
|  | atomic_add(&ialloc_bytes, b->lim - b->base); | 
|  |  | 
|  | return b; | 
|  | } | 
|  |  | 
|  | void freeb(struct block *b) | 
|  | { | 
|  | void *dead = (void *)Bdead; | 
|  | uint8_t *p; | 
|  |  | 
|  | if (b == NULL) | 
|  | return; | 
|  |  | 
|  | /* | 
|  | * drivers which perform non cache coherent DMA manage their own buffer | 
|  | * pool of uncached buffers and provide their own free routine. | 
|  | */ | 
|  | if (b->free) { | 
|  | b->free(b); | 
|  | return; | 
|  | } | 
|  | if (b->flag & BINTR) { | 
|  | /* subtracting the size of b */ | 
|  | atomic_add(&ialloc_bytes, -(b->lim - b->base)); | 
|  | } | 
|  |  | 
|  | p = b->base; | 
|  |  | 
|  | /* poison the block in case someone is still holding onto it */ | 
|  | b->next = dead; | 
|  | b->rp = dead; | 
|  | b->wp = dead; | 
|  | b->lim = dead; | 
|  | b->base = dead; | 
|  |  | 
|  | kfree(p); | 
|  | } | 
|  |  | 
|  | void checkb(struct block *b, char *msg) | 
|  | { | 
|  | void *dead = (void *)Bdead; | 
|  |  | 
|  | if (b == dead) | 
|  | panic("checkb b %s %#p", msg, b); | 
|  | if (b->base == dead || b->lim == dead || b->next == dead | 
|  | || b->rp == dead || b->wp == dead) { | 
|  | printd("checkb: base %#p lim %#p next %#p\n", b->base, b->lim, b->next); | 
|  | printd("checkb: rp %#p wp %#p\n", b->rp, b->wp); | 
|  | panic("checkb dead: %s\n", msg); | 
|  | } | 
|  |  | 
|  | if (b->base > b->lim) | 
|  | panic("checkb 0 %s %#p %#p", msg, b->base, b->lim); | 
|  | if (b->rp < b->base) | 
|  | panic("checkb 1 %s %#p %#p", msg, b->base, b->rp); | 
|  | if (b->wp < b->base) | 
|  | panic("checkb 2 %s %#p %#p", msg, b->base, b->wp); | 
|  | if (b->rp > b->lim) | 
|  | panic("checkb 3 %s %#p %#p", msg, b->rp, b->lim); | 
|  | if (b->wp > b->lim) | 
|  | panic("checkb 4 %s %#p %#p", msg, b->wp, b->lim); | 
|  | } | 
|  |  | 
|  | void iallocsummary(void) | 
|  | { | 
|  | printd("ialloc %lu\n", atomic_read(&ialloc_bytes)); | 
|  | } |