/*
* 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 <u.h>
#include <libc.h>
#include <thread.h>
#include <fcall.h>
#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);
}
|