void freeb(struct block *b) { void *dead = (void *)Bdead; if (b == NULL) return; free_block_extra(b); /* * 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)); } /* 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(b); }
/* Frees a block, returning its size (len, not alloc) */ size_t freeb(struct block *b) { void *dead = (void *)Bdead; size_t ret; if (b == NULL) return 0; ret = BLEN(b); free_block_extra(b); /* * 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 ret; } /* 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(b); return ret; }
/* Adjust block @bp so that its size is exactly @len. * If the size is increased, fill in the new contents with zeros. * If the size is decreased, discard some of the old contents at the tail. */ struct block *adjustblock(struct block *bp, int len) { struct extra_bdata *ebd; void *buf; int i; if (len < 0) { freeb(bp); return NULL; } if (len == BLEN(bp)) return bp; /* Shrink within block main body. */ if (len <= BHLEN(bp)) { free_block_extra(bp); bp->wp = bp->rp + len; QDEBUG checkb(bp, "adjustblock 1"); return bp; } /* Need to grow. */ if (len > BLEN(bp)) { /* Grow within block main body. */ if (bp->extra_len == 0 && bp->rp + len <= bp->lim) { memset(bp->wp, 0, len - BLEN(bp)); bp->wp = bp->rp + len; QDEBUG checkb(bp, "adjustblock 2"); return bp; } /* Grow with extra data buffers. */ buf = kzmalloc(len - BLEN(bp), MEM_WAIT); block_append_extra(bp, (uintptr_t)buf, 0, len - BLEN(bp), MEM_WAIT); QDEBUG checkb(bp, "adjustblock 3"); return bp; } /* Shrink extra data buffers. * len is how much of ebd we need to keep. * extra_len is re-accumulated. */ assert(bp->extra_len > 0); len -= BHLEN(bp); bp->extra_len = 0; for (i = 0; i < bp->nr_extra_bufs; i++) { ebd = &bp->extra_data[i]; if (len <= ebd->len) break; len -= ebd->len; bp->extra_len += ebd->len; } /* If len becomes zero, extra_data[i] should be freed. */ if (len > 0) { ebd = &bp->extra_data[i]; ebd->len = len; bp->extra_len += ebd->len; i++; } for (; i < bp->nr_extra_bufs; i++) { ebd = &bp->extra_data[i]; if (ebd->base) kfree((void*)ebd->base); ebd->base = ebd->off = ebd->len = 0; } QDEBUG checkb(bp, "adjustblock 4"); return bp; }