History

initial commit

Matthew Veety committed 11 years ago

Commit e0c8c2eNo parent (first commit)7 files · +539 −0Browse files

Unified · Split

7 files
  1. README +20 −0
  2. blockalloc.h +73 −0
  3. disk.c +116 −0
  4. instru.c +91 −0
  5. mkfile +26 −0
  6. pointers.c +209 −0
  7. setup.rc +4 −0
README+20−0
@@ -0,0 +1,20 @@
1+libblockalloc -- block allocation library and ftrace-lite
2+
3+libblockalloc is a library that allows you to basically malloc and
4+free blocks on a disk. It is able to sync data, keep track of the
5+used and free blocks, and naively cache recently used data. This
6+library is incomplete (needs a read, write, arb free, and arb malloc)
7+but still might be useful.
8+
9+ftrace-lite is a quick hack to allow libblockalloc to compile on all
10+plan 9/9front systems. ftrace-lite, when enabled, prints out some of
11+whats happening inside of the library to help with debugging and
12+streamlining. It isn't as good as the full ftrace (ftrace-lite isn't
13+able to follow system calls into the kernel or blurt out mallocs and
14+frees, only covers qlock, etc...) but it does some of the job.
15+
16+I didn't really test this library at all before releasing it. When
17+you find bugs, bitch at me and mail me a patch.
18+
19+Love,
20+Veety
blockalloc.h+73−0
@@ -0,0 +1,73 @@
1+#pragma lib "libblockalloc.a"
2+
3+#define BPTRSIZE 9 // this is bytes
4+#define SYNCSLEEP 300 // in seconds
5+
6+enum {
7+ DISKCACHE = 1,
8+ DISKAUTOSYNC = 2,
9+ DISKCONSTSYNC = 4,
10+ DISKDEBUG = 8,
11+ DISKMAN = 3,
12+};
13+
14+typedef struct Blockptr Blockptr;
15+typedef struct Metablock Metablock;
16+typedef struct Disk Disk;
17+typedef struct Fn Fn;
18+
19+struct Fn {
20+ char *name;
21+ QLock l;
22+ uint active;
23+};
24+
25+struct Blockptr {
26+ uchar used; // is the block in use?
27+ u64int offset; // where is it from the start of the bitmap?
28+ void *buffer; // buffer for sync if blocks are cached
29+};
30+
31+struct Metablock { // information about the managed disk
32+ u64int blocksize; // how big is a block in the bitmap
33+ u64int ptrmapstart; // where are the pointers?
34+ u64int totalblocks; // how many blocks are there?
35+ u64int bitmapstart; // where are the blocks?
36+};
37+
38+struct Disk {
39+ int fd; // rw channel
40+ Metablock *meta; // the metadata block
41+ uint blocks_cached; // are the blocks cached?
42+ int syncpid;
43+ int debug;
44+ QLock syncing;
45+ QLock synclock;
46+ Blockptr *ptrs; // blockpointers if they're cached
47+};
48+
49+/* pointers.c */
50+u64int preadn(int,void*,u64int,u64int); // pread + readn
51+u64int pwriten(int, void*,u64int,u64int); // wrapper around pwrite to make it match preadn
52+int loadbptrs(Disk*);
53+int syncbptrs(Disk*);
54+u64int readbptr(Disk*, Blockptr*, u64int);
55+u64int writebptr(Disk*, Blockptr*);
56+u64int allocblock(Disk*,Blockptr*);
57+int freeblock(Disk*,Blockptr*);
58+u64int readblock(Disk*,Blockptr*,void*);
59+u64int writeblock(Disk*,Blockptr*,void*);
60+
61+/* disks.c */
62+int opendisk(char*,Disk*,uchar);
63+int closedisk(Disk*);
64+int fd2disk(int,Disk*,uchar);
65+int disksyncer(Disk*);
66+
67+/* instru.c */
68+void enableinstru(void);
69+Fn* infn(char*);
70+void action(Fn*,char*);
71+void outfn(Fn*);
72+void iqlock(Fn*,QLock*);
73+void iqunlock(Fn*,QLock*);
disk.c+116−0
@@ -0,0 +1,116 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <blockalloc.h>
4+
5+void
6+disksyncer1(Disk *d)
7+{
8+ Fn *f = infn("disk syncer");
9+ for(;;){
10+ sleep(SYNCSLEEP*1000);
11+ iqlock(f,&d->syncing);
12+ if(!syncbptrs(d))
13+ if(d->debug)
14+ print("blockalloc: error syncing block pointers\n");
15+ iqunlock(f,&d->syncing);
16+ }
17+}
18+
19+int
20+disksyncer(Disk* d)
21+{
22+ int pid;
23+ if((pid = rfork(RFPROC|RFMEM|RFNOWAIT)) == 0){
24+ disksyncer1(d);
25+ } else if (pid > 0) {
26+ d->syncpid = pid;
27+ return 0;
28+ } else {
29+ return -1;
30+ }
31+ return -1;
32+}
33+
34+int
35+opendisk(char* fname, Disk* d, uchar opts)
36+{
37+ int fd;
38+ if((fd = open(fname,OREAD|OWRITE)) < 0){
39+ d = nil;
40+ return -1;
41+ }
42+ return fd2disk(fd,d,opts);
43+}
44+
45+int
46+closedisk(Disk* d)
47+{
48+ if(d->blocks_cached){
49+ qlock(&d->syncing);
50+ syncbptrs(d);
51+ if(postnote(PNPROC,d->syncpid,"fucking die you cunt") == 0){
52+ free(d->ptrs);
53+ free(d->meta);
54+ close(d->fd);
55+ qunlock(&d->syncing);
56+ free(d);
57+ return 0;
58+ } else {
59+ print("blockalloc: unable to kill syncer process %d\n",d->syncpid);
60+ free(d->ptrs);
61+ free(d->meta);
62+ close(d->fd);
63+ return -1;
64+ }
65+ } else {
66+ if(d->ptrs != nil)
67+ free(d->ptrs);
68+ free(d->meta);
69+ close(d->fd);
70+ free(d);
71+ return 0;
72+ }
73+ return -2;
74+}
75+
76+int
77+fd2disk(int fd, Disk* d, uchar opts)
78+{
79+ Fn *f = infn("fd2disk");
80+ Disk *bf = malloc(sizeof(Disk));
81+ Metablock *m = malloc(sizeof(Metablock));
82+ bf->fd = fd;
83+ action(f,"preadn 1");
84+ if((preadn(bf->fd,m,2,sizeof(Metablock))) < sizeof(Metablock)){
85+ action(f,"short read");
86+ free(m);
87+ close(bf->fd);
88+ free(bf);
89+ d = nil;
90+ outfn(f);
91+ return -2;
92+ }
93+ bf->meta = m;
94+ if(opts == 1 || opts%2 == 1){
95+ action(f,"enabling disk caching");
96+ bf->blocks_cached = 1;
97+ if(loadbptrs(bf) == 0){
98+ if(disksyncer(bf) == 0){
99+ d = bf;
100+ outfn(f);
101+ return 0;
102+ }
103+ action(f,"syncer did not start (rfork error)");
104+ free(d->ptrs);
105+ bf->blocks_cached = 0;
106+ d = bf;
107+ outfn(f);
108+ return -3;
109+ }
110+ action(f,"failure to enable caching");
111+ }
112+ d = bf;
113+ outfn(f);
114+ return 0;
115+}
116+
instru.c+91−0
@@ -0,0 +1,91 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <blockalloc.h>
4+
5+/*
6+simple instrumentation library
7+This is basically the ftrace-lite library. It doesn't have
8+all the cool features or anything like that, but it kinda
9+does the same thing.
10+*/
11+
12+int enable_instru = 0;
13+
14+void
15+initinstru(void)
16+{
17+ enable_instru = 1;
18+}
19+
20+Fn*
21+infn(char* name)
22+{
23+ Fn *bf = malloc(sizeof(Fn));
24+ if(enable_instru){
25+ bf->active = 1;
26+ qlock(&bf->l);
27+ bf->name = name;
28+ fprint(2,"instru: infn: %s\n",name);
29+ return bf;
30+ }
31+ free(bf);
32+ return nil;
33+}
34+
35+void
36+action(Fn* f, char* c)
37+{
38+ if(f == nil || enable_instru == 0){
39+ return;
40+ } else if (f->active == 1 && !canqlock(&f->l)){
41+ fprint(2,"instru: %s: %s\n",f->name,c);
42+ } else if (canqlock(&f->l)) {
43+ fprint(2,"instru: error: action %s done outside of function\n",c);
44+ }
45+}
46+
47+void
48+outfn(Fn* f)
49+{
50+ if(f == nil || enable_instru == 0){
51+ return;
52+ } else if (f->active == 1 && !canqlock(&f->l)){
53+ fprint(2,"instru: outfn: %s\n",f->name);
54+ qunlock(&f->l);
55+ free(f->name);
56+ free(f);
57+ return;
58+ } else {
59+ if(f != nil){
60+ fprint(2,"instru: error: outfn done outside of function\n");
61+ if(!canqlock(&f->l))
62+ qunlock(&f->l);
63+ free(f->name);
64+ free(f);
65+ return;
66+ }
67+ fprint(2,"instru: error: something bad happened\n");
68+ }
69+}
70+
71+void
72+iqlock(Fn* f, QLock* l)
73+{
74+ if(f == nil || enable_instru == 0){
75+ qlock(l);
76+ } else if (f->active == 1 && !canqlock(&f->l)){
77+ qlock(l);
78+ fprint(2,"instru: %s: lock: %p\n",f->name,l);
79+ }
80+}
81+
82+void
83+iqunlock(Fn* f,QLock* l)
84+{
85+ if(f == nil || enable_instru == 0){
86+ qlock(l);
87+ } else if (f->active == 1 && !canqlock(&f->l)){
88+ qlock(l);
89+ fprint(2,"instru: %s: unlock: %p\n",f->name,l);
90+ }
91+}
mkfile+26−0
@@ -0,0 +1,26 @@
1+</$objtype/mkfile
2+
3+LIB=/$objtype/lib/libblockalloc.a
4+
5+OFILES=\
6+ disk.$O \
7+ pointers.$O \
8+ instru.$O \
9+
10+CFILES=\
11+ disk.c \
12+ pointers.c \
13+ instru.c \
14+
15+HFILES=\
16+ blockalloc.h \
17+
18+UPDATE=\
19+ mkfile \
20+ $LIB \
21+ $CFILES \
22+ $HFILES \
23+
24+all:V: $LIB
25+
26+</sys/src/cmd/mksyslib
pointers.c+209−0
@@ -0,0 +1,209 @@
1+#include <u.h>
2+#include <libc.h>
3+#include <blockalloc.h>
4+
5+u64int
6+preadn(int fd, void *buf, u64int offset, u64int len)
7+{
8+ int nfd = dup(fd,-1);
9+ seek(nfd, (vlong) offset, 0);
10+ u64int retval = (u64int) readn(nfd, buf, (vlong) len);
11+ close(nfd);
12+ return retval;
13+}
14+
15+u64int
16+pwriten(int fd, void *buf, u64int offset, u64int len)
17+{
18+ return (u64int)pwrite(fd,buf,(long) len, (vlong) offset);
19+}
20+
21+int
22+loadbptrs(Disk *d)
23+{
24+ Fn *f = infn("loadbptrs");
25+ int fd = d->fd;
26+ Metablock *m = d->meta;
27+ u64int ptrbitmapsize = m->totalblocks*BPTRSIZE;
28+ action(f,"preadn 1");
29+ if(preadn(fd, d->ptrs, m->ptrmapstart, ptrbitmapsize) < ptrbitmapsize){
30+ action(f,"failure");
31+ d->blocks_cached = 0;
32+ outfn(f);
33+ return -1;
34+ }
35+ d->blocks_cached = 1;
36+ outfn(f);
37+ return 0;
38+}
39+
40+int
41+syncbptrs(Disk *d)
42+{
43+ Fn *f = infn("syncbptrs");
44+ iqlock(f,&d->synclock);
45+ if(d->blocks_cached){
46+ for(u64int i = 0; i < d->meta->totalblocks; i++){
47+ writebptr(d,&d->ptrs[i]);
48+ if(&d->ptrs[i].buffer != nil){
49+ writeblock(d,&d->ptrs[i],&d->ptrs[i].buffer);
50+ free(&d->ptrs[i].buffer);
51+ }
52+ }
53+ iqunlock(f,&d->synclock);
54+ outfn(f);
55+ return 0;
56+ }
57+ iqunlock(f,&d->synclock);
58+ outfn(f);
59+ return -1;
60+}
61+
62+u64int
63+readbptr(Disk *d, Blockptr *b, u64int block)
64+{
65+ Fn *f = infn("readbptr");
66+ if(d->blocks_cached){
67+ iqlock(f,&d->synclock);
68+ b = &d->ptrs[block];
69+ iqunlock(f,&d->synclock);
70+ outfn(f);
71+ return BPTRSIZE;
72+ } else {
73+ action(f,"preadn 1");
74+ u64int retval = preadn(d->fd, b, d->meta->ptrmapstart+(BPTRSIZE*block),BPTRSIZE);
75+ b->buffer = nil;
76+ outfn(f);
77+ return retval;
78+ }
79+}
80+
81+u64int
82+writebptr(Disk *d, Blockptr *b)
83+{
84+ Fn *f = infn("writebptr");
85+ Metablock *m = d->meta;
86+ u64int blocksize = m->blocksize;
87+ u64int blockaddr = b->offset/blocksize;
88+ action(f,"pwriten 1 (retval)");
89+ outfn(f);
90+ return pwriten(d->fd,b,m->ptrmapstart+(BPTRSIZE*blockaddr),BPTRSIZE);
91+}
92+
93+u64int
94+allocblock(Disk *d, Blockptr *b)
95+{
96+ Fn *f = infn("allocblock");
97+ if(d->blocks_cached){
98+ iqlock(f,&d->synclock);
99+ for(u64int i = 0; i < d->meta->totalblocks; i++){
100+ if(d->ptrs[i].used == 0){
101+ b = &d->ptrs[i];
102+ iqunlock(f,&d->synclock);
103+ outfn(f);
104+ return i+1;
105+ }
106+ }
107+ iqunlock(f,&d->synclock);
108+ action(f,"retval -1");
109+ outfn(f);
110+ return -1;
111+ } else {
112+ Blockptr *bf = malloc(sizeof(Blockptr));
113+ action(f,smprint("allocated %p",bf));
114+ for(u64int i = 0 ; i < d->meta->totalblocks; i++){
115+ preadn(d->fd,bf,d->meta->ptrmapstart+(i*BPTRSIZE),BPTRSIZE);
116+ if(bf->used == 0){
117+ b = bf;
118+ outfn(f);
119+ return i;
120+ }
121+ }
122+ action(f,smprint("freeing %p",bf));
123+ free(bf);
124+ b = nil;
125+ outfn(f);
126+ return 0;
127+ }
128+ action(f,"retval -1");
129+ outfn(f);
130+ return -1;
131+}
132+
133+int
134+freeblock(Disk *d, Blockptr *b)
135+{
136+ Fn *f = infn("freeblock");
137+ if(d->blocks_cached){
138+ iqlock(f,&d->synclock);
139+ b->used = 0;
140+ iqunlock(f,&d->synclock);
141+ outfn(f);
142+ return 0;
143+ } else {
144+ b->used = 0;
145+ for(int i = 0; i < 10 ; i++){
146+ if(writebptr(d,b) >= BPTRSIZE){
147+ outfn(f);
148+ return 0;
149+ }
150+ }
151+ }
152+ action(f,"retval -1");
153+ outfn(f);
154+ return -1;
155+}
156+
157+u64int
158+readblock(Disk *d, Blockptr *b, void *buf)
159+{
160+ Fn *f = infn("readblock");
161+ int fd = d->fd;
162+ u64int bmapstart = d->meta->bitmapstart;
163+ u64int blocksize = d->meta->blocksize;
164+ u64int offset = b->offset+d->meta->blocksize;
165+ iqlock(f,&d->synclock);
166+ if(d->blocks_cached && b->buffer != nil){
167+ buf = b->buffer;
168+ iqunlock(f,&d->synclock);
169+ outfn(f);
170+ return blocksize;
171+ } else if (d->blocks_cached && b->buffer == nil){
172+ u64int retval = preadn(fd,b->buffer,offset,blocksize);
173+ buf = b->buffer;
174+ iqunlock(f,&d->synclock);
175+ outfn(f);
176+ return retval;
177+ } else {
178+ iqunlock(f,&d->synclock);
179+ outfn(f);
180+ return preadn(fd,buf,offset,blocksize);
181+ }
182+ outfn(f);
183+ return 0;
184+}
185+
186+u64int
187+writeblock(Disk *d, Blockptr *b, void *buf)
188+{
189+ Fn *f = infn("writeblock");
190+ int fd = d->fd;
191+ int syncing = 0;
192+ if(canqlock(&d->synclock)){
193+ syncing = 1;
194+ iqlock(f,&d->synclock);
195+ }
196+ u64int bmapstart = d->meta->bitmapstart;
197+ u64int blocksize = d->meta->blocksize;
198+ u64int offset = b->offset+d->meta->blocksize;
199+ if(d->blocks_cached && !syncing){
200+ memcpy(buf,b->buffer,blocksize);
201+ iqunlock(f,&d->synclock);
202+ action(f,"return (not syncing)");
203+ outfn(f);
204+ return blocksize;
205+ }
206+ action(f,"return (syncing)");
207+ outfn(f);
208+ return pwriten(fd,buf,offset,blocksize);
209+}
setup.rc+4−0
@@ -0,0 +1,4 @@
1+#!/bin/rc
2+echo 'cp blockalloc.h /sys/include/blockalloc.h'
3+cp blockalloc.h /sys/include/blockalloc.h
4+exit ''