implement Diskblocks; ## adapted from Acme's disk.b# include "sys.m"; sys: Sys; include "diskblocks.m"; init(){ sys = load Sys Sys->PATH;} tempfile(): ref Sys->FD{ user := "inferno"; fd := sys->open("/dev/user", Sys->OREAD); if(fd != nil){ b := array[Sys->NAMEMAX] of byte; n := sys->read(fd, b, len b); if(n > 0) user = string b[0:n]; } fd = nil; buf := sys->sprint("/tmp/X%d.%.4sblks", sys->pctl(0, nil), user); for(i:='A'; i<='Z'; i++){ buf[5] = i; if(sys->stat(buf).t0 == 0) continue; fd = sys->create(buf, Sys->ORDWR|Sys->ORCLOSE|Sys->OEXCL, 8r600); if(fd != nil) return fd; } return nil;} Disk.init(fd: ref Sys->FD, gran: int, maxblock: int): ref Disk{ d := ref Disk; if(gran == 0 || maxblock%gran != 0) return nil; d.maxblock = maxblock; d.gran = gran; d.free = array[maxblock/gran+1] of list of ref Block; d.addr = big 0; d.fd = fd; d.lock = chan[1] of int; return d;} ntosize(d: ref Disk, n: int): (int, int){ if (n > d.maxblock) return (-1, -1); size := n; if((size % d.gran) != 0) size += d.gran - size%d.gran; # last bucket holds blocks of exactly d.maxblock return (size, size/d.gran);} Disk.new(d: self ref Disk, n: int): ref Block{ (size, i) := ntosize(d, n); if(i < 0){ sys->werrstr("illegal Disk allocation"); return nil; } b: ref Block; d.lock <-= 1; if(d.free[i] != nil){ b = hd d.free[i]; d.free[i] = tl d.free[i]; }else{ b = ref Block(d.addr, 0); d.addr += big size; } <-d.lock; b.n = n; return b;} Disk.release(d: self ref Disk, b: ref Block){ (nil, i) := ntosize(d, b.n); d.lock <-= 1; d.free[i] = b :: d.free[i]; <-d.lock;} Disk.write(d: self ref Disk, b: ref Block, a: array of byte, n: int): ref Block{ if(b != nil){ (size, nil) := ntosize(d, b.n); (nsize, nil) := ntosize(d, n); if(size != nsize){ d.release(b); b = d.new(n); } }else b = d.new(n); if(b == nil) return nil; if(sys->pwrite(d.fd, a, n, b.addr) != n){ sys->werrstr(sys->sprint("Disk write error: %r")); return nil; } b.n = n; return b;} Disk.read(d: self ref Disk, b: ref Block, a: array of byte, n: int): int{ if(b == nil || n > b.n){ sys->werrstr("read request bigger than block"); return -1; } return sys->pread(d.fd, a, n, b.addr);}
implement Diskblocks;
#
# adapted from Acme's disk.b
#
include "sys.m";
sys: Sys;
include "diskblocks.m";
init()
{
sys = load Sys Sys->PATH;
}
tempfile(): ref Sys->FD
{
user := "inferno";
fd := sys->open("/dev/user", Sys->OREAD);
if(fd != nil){
b := array[Sys->NAMEMAX] of byte;
n := sys->read(fd, b, len b);
if(n > 0)
user = string b[0:n];
}
fd = nil;
buf := sys->sprint("/tmp/X%d.%.4sblks", sys->pctl(0, nil), user);
for(i:='A'; i<='Z'; i++){
buf[5] = i;
if(sys->stat(buf).t0 == 0)
continue;
fd = sys->create(buf, Sys->ORDWR|Sys->ORCLOSE|Sys->OEXCL, 8r600);
if(fd != nil)
return fd;
}
return nil;
}
Disk.init(fd: ref Sys->FD, gran: int, maxblock: int): ref Disk
{
d := ref Disk;
if(gran == 0 || maxblock%gran != 0)
return nil;
d.maxblock = maxblock;
d.gran = gran;
d.free = array[maxblock/gran+1] of list of ref Block;
d.addr = big 0;
d.fd = fd;
d.lock = chan[1] of int;
return d;
}
ntosize(d: ref Disk, n: int): (int, int)
{
if (n > d.maxblock)
return (-1, -1);
size := n;
if((size % d.gran) != 0)
size += d.gran - size%d.gran;
# last bucket holds blocks of exactly d.maxblock
return (size, size/d.gran);
}
Disk.new(d: self ref Disk, n: int): ref Block
{
(size, i) := ntosize(d, n);
if(i < 0){
sys->werrstr("illegal Disk allocation");
return nil;
}
b: ref Block;
d.lock <-= 1;
if(d.free[i] != nil){
b = hd d.free[i];
d.free[i] = tl d.free[i];
}else{
b = ref Block(d.addr, 0);
d.addr += big size;
}
<-d.lock;
b.n = n;
return b;
}
Disk.release(d: self ref Disk, b: ref Block)
{
(nil, i) := ntosize(d, b.n);
d.lock <-= 1;
d.free[i] = b :: d.free[i];
<-d.lock;
}
Disk.write(d: self ref Disk, b: ref Block, a: array of byte, n: int): ref Block
{
if(b != nil){
(size, nil) := ntosize(d, b.n);
(nsize, nil) := ntosize(d, n);
if(size != nsize){
d.release(b);
b = d.new(n);
}
}else
b = d.new(n);
if(b == nil)
return nil;
if(sys->pwrite(d.fd, a, n, b.addr) != n){
sys->werrstr(sys->sprint("Disk write error: %r"));
return nil;
}
b.n = n;
return b;
}
Disk.read(d: self ref Disk, b: ref Block, a: array of byte, n: int): int
{
if(b == nil || n > b.n){
sys->werrstr("read request bigger than block");
return -1;
}
return sys->pread(d.fd, a, n, b.addr);
}