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 @@
1libblockalloc -- block allocation library and ftrace-lite
2
3libblockalloc is a library that allows you to basically malloc and
4free blocks on a disk. It is able to sync data, keep track of the
5used and free blocks, and naively cache recently used data. This
6library is incomplete (needs a read, write, arb free, and arb malloc)
7but still might be useful.
8
9ftrace-lite is a quick hack to allow libblockalloc to compile on all
10plan 9/9front systems. ftrace-lite, when enabled, prints out some of
11whats happening inside of the library to help with debugging and
12streamlining. It isn't as good as the full ftrace (ftrace-lite isn't
13able to follow system calls into the kernel or blurt out mallocs and
14frees, only covers qlock, etc...) but it does some of the job.
15
16I didn't really test this library at all before releasing it. When
17you find bugs, bitch at me and mail me a patch.
18
19Love,
20Veety
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
6enum {
7 DISKCACHE = 1,
8 DISKAUTOSYNC = 2,
9 DISKCONSTSYNC = 4,
10 DISKDEBUG = 8,
11 DISKMAN = 3,
12};
13
14typedef struct Blockptr Blockptr;
15typedef struct Metablock Metablock;
16typedef struct Disk Disk;
17typedef struct Fn Fn;
18
19struct Fn {
20 char *name;
21 QLock l;
22 uint active;
23};
24
25struct 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
31struct 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
38struct 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 */
50u64int preadn(int,void*,u64int,u64int); // pread + readn
51u64int pwriten(int, void*,u64int,u64int); // wrapper around pwrite to make it match preadn
52int loadbptrs(Disk*);
53int syncbptrs(Disk*);
54u64int readbptr(Disk*, Blockptr*, u64int);
55u64int writebptr(Disk*, Blockptr*);
56u64int allocblock(Disk*,Blockptr*);
57int freeblock(Disk*,Blockptr*);
58u64int readblock(Disk*,Blockptr*,void*);
59u64int writeblock(Disk*,Blockptr*,void*);
60
61/* disks.c */
62int opendisk(char*,Disk*,uchar);
63int closedisk(Disk*);
64int fd2disk(int,Disk*,uchar);
65int disksyncer(Disk*);
66
67/* instru.c */
68void enableinstru(void);
69Fn* infn(char*);
70void action(Fn*,char*);
71void outfn(Fn*);
72void iqlock(Fn*,QLock*);
73void iqunlock(Fn*,QLock*);
disk.c+116−0
@@ -0,0 +1,116 @@
1#include <u.h>
2#include <libc.h>
3#include <blockalloc.h>
4
5void
6disksyncer1(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
19int
20disksyncer(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
34int
35opendisk(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
45int
46closedisk(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
76int
77fd2disk(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/*
6simple instrumentation library
7This is basically the ftrace-lite library. It doesn't have
8all the cool features or anything like that, but it kinda
9does the same thing.
10*/
11
12int enable_instru = 0;
13
14void
15initinstru(void)
16{
17 enable_instru = 1;
18}
19
20Fn*
21infn(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
35void
36action(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
47void
48outfn(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
71void
72iqlock(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
82void
83iqunlock(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
3LIB=/$objtype/lib/libblockalloc.a
4
5OFILES=\
6 disk.$O \
7 pointers.$O \
8 instru.$O \
9
10CFILES=\
11 disk.c \
12 pointers.c \
13 instru.c \
14
15HFILES=\
16 blockalloc.h \
17
18UPDATE=\
19 mkfile \
20 $LIB \
21 $CFILES \
22 $HFILES \
23
24all: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
5u64int
6preadn(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
15u64int
16pwriten(int fd, void *buf, u64int offset, u64int len)
17{
18 return (u64int)pwrite(fd,buf,(long) len, (vlong) offset);
19}
20
21int
22loadbptrs(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
40int
41syncbptrs(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
62u64int
63readbptr(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
81u64int
82writebptr(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
93u64int
94allocblock(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
133int
134freeblock(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
157u64int
158readblock(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
186u64int
187writeblock(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
2echo 'cp blockalloc.h /sys/include/blockalloc.h'
3cp blockalloc.h /sys/include/blockalloc.h
4exit ''