Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <fcall.h>
5
#include <thread.h>
6
#include <9p.h>
7
 
8
typedef struct Part Part;
9
typedef struct Trip Trip;
10
typedef struct Dbl Dbl;
11
typedef struct Ind Ind;
12
 
13
/*
14
 * with 8192-byte blocks and 4-byte pointers,
15
 * double-indirect gets us 34 GB. 
16
 * triple-indirect gets us 70,368 GB.
17
 */
18
 
19
enum
20
{
21
	LOGBLKSZ = 13,
22
	BLKSZ = 1<<LOGBLKSZ,	/* 8192 */
23
	LOGNPTR = LOGBLKSZ-2,	/* assume sizeof(void*) == 4 */
24
	NPTR = 1<<LOGNPTR,
25
};
26
static uchar zero[BLKSZ];
27
 
28
struct Trip
29
{
30
	Dbl *dbl[NPTR];	
31
};
32
 
33
struct Dbl
34
{
35
	Ind *ind[NPTR];
36
};
37
 
38
struct Ind
39
{
40
	uchar *blk[NPTR];
41
};
42
 
43
Trip trip;
44
 
45
struct Part
46
{
47
	int inuse;
48
	int vers;
49
	ulong mode;
50
	char *name;
51
	vlong offset;	/* in sectors */
52
	vlong length;	/* in sectors */
53
};
54
 
55
enum
56
{
57
	Qroot = 0,
58
	Qdir,
59
	Qctl,
60
	Qpart,
61
};
62
 
63
Part tab[64];
64
int fd = -1;
65
char *sdname = "sdXX";
66
ulong ctlmode = 0666;
67
char *inquiry = "aux/disksim hard drive";
68
vlong nsect, sectsize, c, h, s;
69
ulong time0;
70
int rdonly;
71
 
72
char*
73
ctlstring(void)
74
{
75
	int i;
76
	Fmt fmt;
77
 
78
	fmtstrinit(&fmt);
79
	fmtprint(&fmt, "inquiry %s\n", inquiry);
80
	fmtprint(&fmt, "geometry %lld %lld %lld %lld %lld\n", nsect, sectsize, c, h, s);
81
	for(i=0; i<nelem(tab); i++)
82
		if(tab[i].inuse)
83
			fmtprint(&fmt, "part %s %lld %lld\n", tab[i].name, tab[i].offset, tab[i].length);
84
	return fmtstrflush(&fmt);
85
}
86
 
87
int
88
addpart(char *name, vlong start, vlong end)
89
{
90
	int i;
91
 
92
	if(start < 0 || start > end || end > nsect){
93
		werrstr("bad partition boundaries");
94
		return -1;
95
	}
96
 
97
	for(i=0; i<nelem(tab); i++)
98
		if(tab[i].inuse == 0)
99
			break;
100
	if(i == nelem(tab)){
101
		werrstr("no free partition slots");
102
		return -1;	
103
	}
104
 
105
	free(tab[i].name);
106
	tab[i].inuse = 1;
107
	tab[i].name = estrdup9p(name);
108
	tab[i].offset = start;
109
	tab[i].length = end - start;
110
	tab[i].mode = ctlmode;
111
	tab[i].vers++;
112
 
113
	return 0;
114
}
115
 
116
int
117
delpart(char *s)
118
{
119
	int i;
120
 
121
	for(i=0; i<nelem(tab); i++)
122
		if(tab[i].inuse && strcmp(tab[i].name, s) == 0)
123
			break;
124
	if(i==nelem(tab)){
125
		werrstr("partition not found");
126
		return -1;
127
	}
128
 
129
	tab[i].inuse = 0;
130
	free(tab[i].name);
131
	tab[i].name = 0;
132
	return 0;
133
}
134
 
135
void
136
ctlwrite(Req *r)
137
{
138
	int i;
139
	Cmdbuf *cb;
140
	vlong start, end;
141
 
142
	r->ofcall.count = r->ifcall.count;
143
	cb = parsecmd(r->ifcall.data, r->ifcall.count);
144
	if(cb->nf < 1){
145
		respond(r, "empty control message");
146
		free(cb);
147
		return;
148
	}
149
 
150
	if(strcmp(cb->f[0], "part") == 0){
151
		if(cb->nf != 4){
152
			respondcmderror(r, cb, "part takes 3 args");
153
			free(cb);
154
			return;
155
		}
156
		start = strtoll(cb->f[2], 0, 0);
157
		end = strtoll(cb->f[3], 0, 0);
158
		if(addpart(cb->f[1], start, end) < 0){
159
			respondcmderror(r, cb, "%r");
160
			free(cb);
161
			return;
162
		}
163
	}
164
	else if(strcmp(cb->f[0], "delpart") == 0){
165
		if(cb->nf != 2){
166
			respondcmderror(r, cb, "delpart takes 1 arg");
167
			free(cb);
168
			return;
169
		}
170
		if(delpart(cb->f[1]) < 0){
171
			respondcmderror(r, cb, "%r");
172
			free(cb);
173
			return;
174
		}
175
	}
176
	else if(strcmp(cb->f[0], "inquiry") == 0){
177
		if(cb->nf != 2){
178
			respondcmderror(r, cb, "inquiry takes 1 arg");
179
			free(cb);
180
			return;
181
		}
182
		free(inquiry);
183
		inquiry = estrdup9p(cb->f[1]);
184
	}
185
	else if(strcmp(cb->f[0], "geometry") == 0){
186
		if(cb->nf != 6){
187
			respondcmderror(r, cb, "geometry takes 5 args");
188
			free(cb);
189
			return;
190
		}
191
		nsect = strtoll(cb->f[1], 0, 0);
192
		sectsize = strtoll(cb->f[2], 0, 0);
193
		c = strtoll(cb->f[3], 0, 0);
194
		h = strtoll(cb->f[4], 0, 0);
195
		s = strtoll(cb->f[5], 0, 0);
196
		if(tab[0].inuse && strcmp(tab[0].name, "data") == 0 && tab[0].vers == 0){
197
			tab[0].offset = 0;
198
			tab[0].length = nsect;
199
		}
200
		for(i=0; i<nelem(tab); i++){
201
			if(tab[i].inuse && tab[i].offset+tab[i].length > nsect){
202
				tab[i].inuse = 0;
203
				free(tab[i].name);
204
				tab[i].name = 0;
205
			}
206
		}
207
	}
208
	else{
209
		respondcmderror(r, cb, "unknown control message");
210
		free(cb);
211
		return;
212
	}
213
 
214
	free(cb);
215
	respond(r, nil);
216
}
217
 
218
void*
219
allocblk(vlong addr)
220
{
221
	uchar *op;
222
	static uchar *p;
223
	static ulong n;
224
 
225
	if(n == 0){
226
		p = malloc(4*1024*1024);
227
		if(p == 0)
228
			sysfatal("out of memory");
229
		n = 4*1024*1024;
230
	}
231
	op = p;
232
	p += BLKSZ;
233
	n -= BLKSZ;
234
	memset(op, 0, BLKSZ);
235
	if(fd != -1 && addr != -1)
236
		pread(fd, op, BLKSZ, addr);
237
	return op;
238
}
239
 
240
uchar*
241
getblock(vlong addr, int alloc)
242
{
243
 	Dbl *p2;
244
	Ind *p1;
245
	uchar *p0;
246
	uint i0, i1, i2;
247
	vlong oaddr;
248
 
249
	if(fd >= 0)
250
		alloc = 1;
251
 
252
	addr >>= LOGBLKSZ;
253
	oaddr = addr<<LOGBLKSZ;
254
	i0 = addr & (NPTR-1);
255
	addr >>= LOGNPTR;
256
	i1 = addr & (NPTR-1);
257
	addr >>= LOGNPTR;
258
	i2 = addr & (NPTR-1);
259
	addr >>= LOGNPTR;
260
	assert(addr == 0);
261
 
262
	if((p2 = trip.dbl[i2]) == 0){
263
		if(!alloc)
264
			return zero;
265
		trip.dbl[i2] = p2 = allocblk(-1);
266
	}
267
 
268
	if((p1 = p2->ind[i1]) == 0){
269
		if(!alloc)
270
			return zero;
271
		p2->ind[i1] = p1 = allocblk(-1);
272
	}
273
 
274
	if((p0 = p1->blk[i0]) == 0){
275
		if(!alloc)
276
			return zero;
277
		p1->blk[i0] = p0 = allocblk(oaddr);
278
	}
279
	return p0;
280
}
281
 
282
void
283
dirty(vlong addr, uchar *buf)
284
{
285
	vlong oaddr;
286
 
287
	if(fd == -1 || rdonly)
288
		return;
289
	oaddr = addr&~((vlong)BLKSZ-1);
290
	if(pwrite(fd, buf, BLKSZ, oaddr) != BLKSZ)
291
		sysfatal("write: %r");
292
}
293
 
294
int
295
rootgen(int off, Dir *d, void*)
296
{
297
	memset(d, 0, sizeof *d);
298
	d->atime = time0;
299
	d->mtime = time0;
300
	if(off == 0){
301
		d->name = estrdup9p(sdname);
302
		d->mode = DMDIR|0777;
303
		d->qid.path = Qdir;
304
		d->qid.type = QTDIR;
305
		d->uid = estrdup9p("disksim");
306
		d->gid = estrdup9p("disksim");
307
		d->muid = estrdup9p("");
308
		return 0;
309
	}
310
	return -1;
311
}	
312
 
313
int
314
dirgen(int off, Dir *d, void*)
315
{
316
	int n, j;
317
 
318
	memset(d, 0, sizeof *d);
319
	d->atime = time0;
320
	d->mtime = time0;
321
	if(off == 0){
322
		d->name = estrdup9p("ctl");
323
		d->mode = ctlmode;
324
		d->qid.path = Qctl;
325
		goto Have;
326
	}
327
 
328
	off--;
329
	n = 0;
330
	for(j=0; j<nelem(tab); j++){
331
		if(tab[j].inuse==0)
332
			continue;
333
		if(n == off){
334
			d->name = estrdup9p(tab[j].name);
335
			d->length = tab[j].length*sectsize;
336
			d->mode = tab[j].mode;
337
			d->qid.path = Qpart+j;
338
			d->qid.vers = tab[j].vers;
339
			goto Have;
340
		}
341
		n++;
342
	}
343
	return -1;
344
 
345
Have:
346
	d->uid = estrdup9p("disksim");
347
	d->gid = estrdup9p("disksim");
348
	d->muid = estrdup9p("");
349
	return 0;
350
}
351
 
352
void*
353
evommem(void *a, void *b, ulong n)
354
{
355
	return memmove(b, a, n);
356
}
357
 
358
int
359
isnonzero(void *v, ulong n)
360
{
361
	uchar *a, *ea;
362
 
363
	a = v;
364
	ea = a+n;
365
	for(; a<ea; a++)
366
		if(*a)
367
			return 1;
368
	return 0;
369
}
370
 
371
int
372
rdwrpart(Req *r)
373
{
374
	int q, nonzero;
375
	Part *p;
376
	vlong offset;
377
	long count, tot, n, o;
378
	uchar *blk, *dat;
379
	void *(*move)(void*, void*, ulong);
380
 
381
	q = r->fid->qid.path-Qpart;
382
	if(q < 0 || q > nelem(tab) || !tab[q].inuse || tab[q].vers != r->fid->qid.vers){
383
		respond(r, "unknown partition");
384
		return -1;
385
	}
386
 
387
	p = &tab[q];
388
	offset = r->ifcall.offset;
389
	count = r->ifcall.count;
390
	if(offset < 0){
391
		respond(r, "negative offset");
392
		return -1;
393
	}
394
	if(count < 0){
395
		respond(r, "negative count");
396
		return -1;
397
	}
398
	if(offset > p->length*sectsize){
399
		respond(r, "offset past end of partition");
400
		return -1;
401
	}
402
	if(offset+count > p->length*sectsize)
403
		count = p->length*sectsize - offset;
404
	offset += p->offset*sectsize;
405
 
406
	if(r->ifcall.type == Tread)
407
		move = memmove;
408
	else
409
		move = evommem;
410
 
411
	tot = 0;
412
	nonzero = 1;
413
	if(r->ifcall.type == Tread)
414
		dat = (uchar*)r->ofcall.data;
415
	else{
416
		dat = (uchar*)r->ifcall.data;
417
		nonzero = isnonzero(dat, r->ifcall.count);
418
	}
419
	o = offset & (BLKSZ-1);
420
 
421
	/* left fringe block */
422
	if(o && count){
423
		blk = getblock(offset, r->ifcall.type==Twrite && nonzero);
424
		n = BLKSZ - o;
425
		if(n > count)
426
			n = count;
427
		if(r->ifcall.type != Twrite || blk != zero)
428
			(*move)(dat, blk+o, n);
429
		if(r->ifcall.type == Twrite)
430
			dirty(offset, blk);
431
		tot += n;
432
	}
433
	/* full and right fringe blocks */
434
	while(tot < count){
435
		blk = getblock(offset+tot, r->ifcall.type==Twrite && nonzero);
436
		n = BLKSZ;
437
		if(n > count-tot)
438
			n = count-tot;
439
		if(r->ifcall.type != Twrite || blk != zero)
440
			(*move)(dat+tot, blk, n);
441
		if(r->ifcall.type == Twrite)
442
			dirty(offset+tot, blk);
443
		tot += n;
444
	}
445
	r->ofcall.count = tot;
446
	respond(r, nil);
447
	return 0;
448
}
449
 
450
void
451
fsread(Req *r)
452
{
453
	char *s;
454
 
455
	switch((int)r->fid->qid.path){
456
	case Qroot:
457
		dirread9p(r, rootgen, nil);
458
		respond(r, nil);
459
		break;
460
 
461
	case Qdir:
462
		dirread9p(r, dirgen, nil);
463
		respond(r, nil);
464
		break;
465
 
466
	case Qctl:
467
		s = ctlstring();
468
		readstr(r, s);
469
		free(s);
470
		respond(r, nil);
471
		break;
472
 
473
	default:
474
		rdwrpart(r);
475
		break;
476
	}
477
}
478
 
479
void
480
fswrite(Req *r)
481
{
482
	switch((int)r->fid->qid.path){
483
	case Qroot:
484
	case Qdir:
485
		respond(r, "write to a directory?");
486
		break;
487
 
488
	case Qctl:
489
		ctlwrite(r);
490
		break;
491
 
492
	default:
493
		rdwrpart(r);
494
		break;
495
	}
496
}
497
 
498
void
499
fsopen(Req *r)
500
{
501
	if(r->ifcall.mode&ORCLOSE)
502
		respond(r, "cannot open ORCLOSE");
503
 
504
	switch((int)r->fid->qid.path){
505
	case Qroot:
506
	case Qdir:
507
		if(r->ifcall.mode != OREAD){
508
			respond(r, "bad mode for directory open");
509
			return;
510
		}
511
	}
512
 
513
	respond(r, nil);
514
}
515
 
516
void
517
fsstat(Req *r)
518
{
519
	int q;
520
	Dir *d;
521
	Part *p;
522
 
523
	d = &r->d;
524
	memset(d, 0, sizeof *d);
525
	d->qid = r->fid->qid;
526
	d->atime = d->mtime = time0;
527
	q = r->fid->qid.path;
528
	switch(q){
529
	case Qroot:
530
		d->name = estrdup9p("/");
531
		d->mode = DMDIR|0777;
532
		break;
533
 
534
	case Qdir:
535
		d->name = estrdup9p(sdname);
536
		d->mode = DMDIR|0777;
537
		break;
538
 
539
	default:
540
		q -= Qpart;
541
		if(q < 0 || q > nelem(tab) || tab[q].inuse==0 || r->fid->qid.vers != tab[q].vers){
542
			respond(r, "partition no longer exists");
543
			return;
544
		}
545
		p = &tab[q];
546
		d->name = estrdup9p(p->name);
547
		d->length = p->length * sectsize;
548
		d->mode = p->mode;
549
		break;
550
	}
551
 
552
	d->uid = estrdup9p("disksim");
553
	d->gid = estrdup9p("disksim");
554
	d->muid = estrdup9p("");
555
	respond(r, nil);
556
}
557
 
558
void
559
fsattach(Req *r)
560
{
561
	char *spec;
562
 
563
	spec = r->ifcall.aname;
564
	if(spec && spec[0]){
565
		respond(r, "invalid attach specifier");
566
		return;
567
	}
568
	r->ofcall.qid = (Qid){Qroot, 0, QTDIR};
569
	r->fid->qid = r->ofcall.qid;
570
	respond(r, nil);
571
}
572
 
573
char*
574
fswalk1(Fid *fid, char *name, Qid *qid)
575
{
576
	int i;
577
	switch((int)fid->qid.path){
578
	case Qroot:
579
		if(strcmp(name, sdname) == 0){
580
			fid->qid.path = Qdir;
581
			fid->qid.type = QTDIR;
582
			*qid = fid->qid;
583
			return nil;
584
		}
585
		break;
586
	case Qdir:
587
		if(strcmp(name, "ctl") == 0){
588
			fid->qid.path = Qctl;
589
			fid->qid.vers = 0;
590
			fid->qid.type = 0;
591
			*qid = fid->qid;
592
			return nil;
593
		}
594
		for(i=0; i<nelem(tab); i++){
595
			if(tab[i].inuse && strcmp(tab[i].name, name) == 0){
596
				fid->qid.path = i+Qpart;
597
				fid->qid.vers = tab[i].vers;
598
				fid->qid.type = 0;
599
				*qid = fid->qid;
600
				return nil;
601
			}
602
		}
603
		break;
604
	}
605
	return "file not found";
606
}
607
 
608
Srv fs = {
609
	.attach=	fsattach,
610
	.open=	fsopen,
611
	.read=	fsread,
612
	.write=	fswrite,
613
	.stat=	fsstat,
614
	.walk1=	fswalk1,
615
};
616
 
617
char *mtpt = "/dev";
618
char *srvname;
619
 
620
void
621
usage(void)
622
{
623
	fprint(2, "usage: aux/disksim [-D] [-f file] [-s srvname] [-m mtpt] [sdXX]\n");
624
	fprint(2, "\tdefault mtpt is /dev\n");
625
	exits("usage");
626
}
627
 
628
void
629
main(int argc, char **argv)
630
{
631
	char *file;
632
 
633
	file = nil;
634
	quotefmtinstall();
635
	time0 = time(0);
636
	if(NPTR != BLKSZ/sizeof(void*))
637
		sysfatal("unexpected pointer size");
638
 
639
	ARGBEGIN{
640
	case 'D':
641
		chatty9p++;
642
		break;
643
	case 'f':
644
		file = EARGF(usage());
645
		break;
646
	case 'r':
647
		rdonly = 1;
648
		break;
649
	case 's':
650
		srvname = EARGF(usage());
651
		break;
652
	case 'm':
653
		mtpt = EARGF(usage());
654
		break;
655
	default:
656
		usage();
657
	}ARGEND
658
 
659
	if(argc > 1)
660
		usage();
661
	if(argc == 1)
662
		sdname = argv[0];
663
 
664
	if(file){
665
		if((fd = open(file, rdonly ? OREAD : ORDWR)) < 0)
666
			sysfatal("open %s: %r", file);
667
	}
668
 
669
	inquiry = estrdup9p(inquiry);
670
	tab[0].name = estrdup9p("data");
671
	tab[0].inuse = 1;
672
	tab[0].mode = 0666;
673
 
674
	postmountsrv(&fs, srvname, mtpt, MBEFORE);
675
	exits(nil);
676
}