/* * Copyright (c) 2013, Coraid, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Coraid nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CORAID BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include <9p.h> #include "dat.h" enum { Falloc = 1, Ffree, }; typedef struct Freereq Freereq; struct Freereq { int req; uvlong blk; Channel *resp; }; static uvlong firstfree; static Channel *freechan; static void _allocblock(Freereq *r) { uchar *p, *tfree; vlong ff, fb, i; int blk, bit; int j, x; ff = firstfree; fb = firstfree / (8 * BlkSize); tfree = cbread(fb + super.freemap); blk = (firstfree / 8) % BlkSize; bit = firstfree & 7; tfree[blk] &= ~(1 << bit); cbwrite(fb + super.freemap); p = nil; /* make the compiler happy */ for(i = fb; i < super.nfreemap; ++i) { for(p = tfree; p < tfree + BlkSize && *p == 0; ++p) ; if(p < tfree + BlkSize) break; brelease(i + super.freemap); tfree = cbread(i + 1 + super.freemap); } if(i >= super.nfreemap) sysfatal("No free space"); brelease(i + super.freemap); for(j = 0, x = *p; j < 8 && (x&1) == 0; ++j, x >>= 1) ; firstfree = 8 * (i * BlkSize + (p - tfree)) + j; --super.nfree; send(r->resp, &ff); } static void _freeblock(Freereq *r) { uchar *tfree; vlong fb; int blk, bit; if(!ccanfree(r->blk)) { fprint(2, "wanting to free active block\n"); return; } blk = (r->blk / 8) % BlkSize; bit = r->blk & 7; fb = r->blk / (8 * BlkSize); tfree = cbread(fb + super.freemap); if(tfree == 0) { fprint(2, "invalid free block: fb:%lld freemap:%ulld\n", fb, super.freemap); return; } tfree[blk] |= 1 << bit; cbwrite(fb + super.freemap); brelease(fb + super.freemap); ++super.nfree; if(r->blk < firstfree) firstfree = r->blk; } static void handler(void *) { Freereq r; while(1) { if(recv(freechan, &r) == 0) { if(shutdown) threadexits(nil); continue; } switch(r.req) { case Falloc: _allocblock(&r); break; case Ffree: _freeblock(&r); break; } } } void initfree(void) { uchar *p, *tfree; vlong i; int j, x; p = nil; /* make the compiler happy */ tfree = nil; for(i = 0; i < super.nfreemap; ++i) { tfree = cbread(i + super.freemap); for(p = tfree; p < tfree + BlkSize && *p == 0; ++p) ; if(p < tfree + BlkSize) break; brelease(i + super.freemap); } if(i >= super.nfreemap) sysfatal("No free space"); for(j = 0, x = *p; j < 8 && (x&1) == 0; ++j, x >>= 1) ; firstfree = 8 * (i * BlkSize + (p - tfree)) + j; brelease(i + super.freemap); freechan = chancreate(sizeof(Freereq), 2); threadcreate(handler, nil, 8192); } void haltfree(void) { /* chanclose(freechan); */ } uvlong allocblock(void) { Freereq r; uvlong blk; r.req = Falloc; r.resp = chancreate(sizeof(uvlong), 0); send(freechan, &r); recv(r.resp, &blk); chanfree(r.resp); return blk; } void freeblock(uvlong block) { Freereq r; if(block < super.firstdat || block > super.nblk) { fprint(2, "Bogus block in free from %p: %ulld\n", getcallerpc(&block), block); return; } r.req = Ffree; r.blk = block; send(freechan, &r); }