xref: /plan9/sys/src/cmd/disk/kfs/devmulti.c (revision a84536681645e23c630ce4ef2e5c3b284d4c590b)
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 *
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
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
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
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
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
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
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
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
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
189 wrensuper(Device dev)
190 {
191 	USED(dev);
192 	return 1;
193 }
194 
195 long
196 wrenroot(Device dev)
197 {
198 	USED(dev);
199 	return 2;
200 }
201 
202 int
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
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