1 #include "all.h"
2
3 enum{
4 MAXWREN = 7,
5 };
6
7 static char WMAGIC[] = "kfs wren device\n";
8 static char MMAGIC[] = "kfs multi-wren device %4d/%4d\n";
9
10 typedef struct Wren Wren;
11
12 struct Wren{
13 QLock;
14 Device dev;
15 ulong nblocks;
16 int fd;
17 };
18
19 static char *wmagic = WMAGIC;
20 static Wren *wrens;
21 static int maxwren;
22 char *wrenfile;
23 int nwren;
24 int badmagic;
25
26 static Wren *
wren(Device dev)27 wren(Device dev)
28 {
29 int i;
30
31 for(i = 0; i < maxwren; i++)
32 if(devcmp(dev, wrens[i].dev) == 0)
33 return &wrens[i];
34 panic("can't find wren for %D", dev);
35 return 0;
36 }
37
38 /*
39 * find out the length of a file
40 * given the mesg version of a stat buffer
41 * we call this because convM2D is different
42 * for the file system than in the os
43 */
44 uvlong
statlen(char * ap)45 statlen(char *ap)
46 {
47 uchar *p;
48 ulong ll, hl;
49
50 p = (uchar*)ap;
51 p += 3*NAMELEN+5*4;
52 ll = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
53 hl = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
54 return ll | ((uvlong) hl << 32);
55 }
56
57 static void
wrenpartinit(Device dev,int k)58 wrenpartinit(Device dev, int k)
59 {
60 char buf[MAXBUFSIZE], d[DIRREC];
61 char file[128], magic[64];
62 Wren *w;
63 int fd, i, nmagic;
64
65 if(wrens == 0)
66 wrens = ialloc(MAXWREN * sizeof *wrens);
67 w = &wrens[maxwren];
68 if(nwren > 0)
69 sprint(file, "%s%d", wrenfile, k);
70 else
71 strcpy(file, wrenfile);
72 fd = open(file, ORDWR);
73 if(fd < 0)
74 panic("can't open %s", file);
75 if(fstat(fd, d) < 0)
76 panic("can't stat %s\n", file);
77 seek(fd, 0, 0);
78 i = read(fd, buf, sizeof buf);
79 if(i < sizeof buf)
80 panic("can't read %s", file);
81 badmagic = 0;
82 RBUFSIZE = 1024;
83 sprint(magic, wmagic, k, nwren);
84 nmagic = strlen(magic);
85 if(strncmp(buf+256, magic, nmagic) == 0){
86 RBUFSIZE = atol(buf+256+nmagic);
87 if(RBUFSIZE % 512){
88 fprint(2, "kfs: bad buffersize(%d): assuming 1k blocks\n", RBUFSIZE);
89 RBUFSIZE = 1024;
90 }
91 }else
92 badmagic = 1;
93 w->dev = dev;
94 w->nblocks = statlen(d)/RBUFSIZE;
95 if(k > 0)
96 w->nblocks -= 1; /* don't count magic */
97 w->fd = fd;
98 maxwren++;
99 }
100
101 void
wreninit(Device dev)102 wreninit(Device dev)
103 {
104 int i;
105
106 if(nwren > 0)
107 wmagic = MMAGIC;
108 i = 0;
109 do{
110 wrenpartinit(dev, i);
111 }while(++i < nwren);
112 }
113
114 static void
wrenpartream(Device dev,int k)115 wrenpartream(Device dev, int k)
116 {
117 Wren *w;
118 char buf[MAXBUFSIZE], magic[64];
119 int fd, i;
120
121 if(RBUFSIZE % 512)
122 panic("kfs: bad buffersize(%d): restart a multiple of 512\n", RBUFSIZE);
123 print("kfs: reaming the file system using %d byte blocks\n", RBUFSIZE);
124 w = wren(dev)+k;
125 fd = w->fd;
126 memset(buf, 0, sizeof buf);
127 sprint(magic, wmagic, k, nwren);
128 sprint(buf+256, "%s%d\n", magic, RBUFSIZE);
129 qlock(w);
130 i = seek(fd, 0, 0) < 0 || write(fd, buf, RBUFSIZE) != RBUFSIZE;
131 qunlock(w);
132 if(i < 0)
133 panic("can't ream disk");
134 }
135
136 void
wrenream(Device dev)137 wrenream(Device dev)
138 {
139 int i;
140
141 i = 0;
142 do{
143 wrenpartream(dev, i);
144 }while(++i < nwren);
145 }
146
147 static int
wrentag(char * p,int tag,long qpath)148 wrentag(char *p, int tag, long qpath)
149 {
150 Tag *t;
151
152 t = (Tag*)(p+BUFSIZE);
153 return t->tag != tag || (qpath&~QPDIR) != t->path;
154 }
155
156 int
wrencheck(Device dev)157 wrencheck(Device dev)
158 {
159 char buf[MAXBUFSIZE];
160
161 if(badmagic)
162 return 1;
163 if(RBUFSIZE > sizeof buf)
164 panic("bufsize too big");
165 if(wrenread(dev, wrensuper(dev), buf) || wrentag(buf, Tsuper, QPSUPER)
166 || wrenread(dev, wrenroot(dev), buf) || wrentag(buf, Tdir, QPROOT))
167 return 1;
168 if(((Dentry *)buf)[0].mode & DALLOC)
169 return 0;
170 return 1;
171 }
172
173 long
wrensize(Device dev)174 wrensize(Device dev)
175 {
176 Wren *w;
177 int i, nb;
178
179 w = wren(dev);
180 nb = 0;
181 i = 0;
182 do{
183 nb += w[i].nblocks;
184 }while(++i < nwren);
185 return nb;
186 }
187
188 long
wrensuper(Device dev)189 wrensuper(Device dev)
190 {
191 USED(dev);
192 return 1;
193 }
194
195 long
wrenroot(Device dev)196 wrenroot(Device dev)
197 {
198 USED(dev);
199 return 2;
200 }
201
202 int
wrenread(Device dev,long addr,void * b)203 wrenread(Device dev, long addr, void *b)
204 {
205 Wren *w;
206 int fd, i;
207
208 w = wren(dev);
209 for(i=0; i<nwren; i++){
210 if(addr < w->nblocks)
211 break;
212 addr -= w->nblocks;
213 ++w;
214 }
215 if(i > 0)
216 addr++;
217 fd = w->fd;
218 qlock(w);
219 i = seek(fd, (vlong)addr*RBUFSIZE, 0) == -1 || read(fd, b, RBUFSIZE) != RBUFSIZE;
220 qunlock(w);
221 return i;
222 }
223
224 int
wrenwrite(Device dev,long addr,void * b)225 wrenwrite(Device dev, long addr, void *b)
226 {
227 Wren *w;
228 int fd, i;
229
230 w = wren(dev);
231 for(i=0; i<nwren; i++){
232 if(addr < w->nblocks)
233 break;
234 addr -= w->nblocks;
235 ++w;
236 }
237 if(i > 0)
238 addr++;
239 fd = w->fd;
240 qlock(w);
241 i = seek(fd, (vlong)addr*RBUFSIZE, 0) == -1 || write(fd, b, RBUFSIZE) != RBUFSIZE;
242 qunlock(w);
243 return i;
244 }
245