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	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/error.h"
7
 
8
enum
9
{
10
	Qtopdir,
11
	Qsegdir,
12
	Qctl,
13
	Qdata,
14
 
15
	/* commands to kproc */
16
	Cnone=0,
17
	Cread,
18
	Cwrite,
19
	Cstart,
20
	Cdie,
21
};
22
 
23
#define TYPE(x) 	(int)( (c)->qid.path & 0x7 )
24
#define SEG(x)	 	( ((c)->qid.path >> 3) & 0x3f )
25
#define PATH(s, t) 	( ((s)<<3) | (t) )
26
 
27
typedef struct Globalseg Globalseg;
28
struct Globalseg
29
{
30
	Ref;
31
	Segment	*s;
32
 
33
	char	*name;
34
	char	*uid;
35
	vlong	length;
36
	long	perm;
37
 
38
	/* kproc to do reading and writing */
39
	QLock	l;		/* sync kproc access */
40
	Rendez	cmdwait;	/* where kproc waits */
41
	Rendez	replywait;	/* where requestor waits */
42
	Proc	*kproc;
43
	char	*data;
44
	long	off;
45
	int	dlen;
46
	int	cmd;	
47
	char	err[64];
48
};
49
 
50
static Globalseg *globalseg[100];
51
static Lock globalseglock;
52
 
53
 
54
	Segment* (*_globalsegattach)(Proc*, char*);
55
static	Segment* globalsegattach(Proc *p, char *name);
56
static	int	cmddone(void*);
57
static	void	segmentkproc(void*);
58
static	void	docmd(Globalseg *g, int cmd);
59
 
60
/*
61
 *  returns with globalseg incref'd
62
 */
63
static Globalseg*
64
getgseg(Chan *c)
65
{
66
	int x;
67
	Globalseg *g;
68
 
69
	x = SEG(c);
70
	lock(&globalseglock);
71
	if(x >= nelem(globalseg))
72
		panic("getgseg");
73
	g = globalseg[x];
74
	if(g != nil)
75
		incref(g);
76
	unlock(&globalseglock);
77
	if(g == nil)
78
		error("global segment disappeared");
79
	return g;
80
}
81
 
82
static void
83
putgseg(Globalseg *g)
84
{
85
	if(decref(g) > 0)
86
		return;
87
	if(g->s != nil)
88
		putseg(g->s);
89
	if(g->kproc)
90
		docmd(g, Cdie);
91
	free(g->name);
92
	free(g->uid);
93
	free(g);
94
}
95
 
96
static int
97
segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
98
{
99
	Qid q;
100
	Globalseg *g;
101
	ulong size;
102
 
103
	switch(TYPE(c)) {
104
	case Qtopdir:
105
		if(s == DEVDOTDOT){
106
			q.vers = 0;
107
			q.path = PATH(0, Qtopdir);
108
			q.type = QTDIR;
109
			devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
110
			break;
111
		}
112
 
113
		if(s >= nelem(globalseg))
114
			return -1;
115
 
116
		lock(&globalseglock);
117
		g = globalseg[s];
118
		if(g == nil){
119
			unlock(&globalseglock);
120
			return 0;
121
		}
122
		q.vers = 0;
123
		q.path = PATH(s, Qsegdir);
124
		q.type = QTDIR;
125
		devdir(c, q, g->name, 0, g->uid, DMDIR|0777, dp);
126
		unlock(&globalseglock);
127
 
128
		break;
129
	case Qsegdir:
130
		if(s == DEVDOTDOT){
131
			q.vers = 0;
132
			q.path = PATH(0, Qtopdir);
133
			q.type = QTDIR;
134
			devdir(c, q, "#g", 0, eve, DMDIR|0777, dp);
135
			break;
136
		}
137
		/* fall through */
138
	case Qctl:
139
	case Qdata:
140
		switch(s){
141
		case 0:
142
			g = getgseg(c);
143
			q.vers = 0;
144
			q.path = PATH(SEG(c), Qctl);
145
			q.type = QTFILE;
146
			devdir(c, q, "ctl", 0, g->uid, g->perm, dp);
147
			putgseg(g);
148
			break;
149
		case 1:
150
			g = getgseg(c);
151
			q.vers = 0;
152
			q.path = PATH(SEG(c), Qdata);
153
			q.type = QTFILE;
154
			if(g->s != nil)
155
				size = g->s->top - g->s->base;
156
			else
157
				size = 0;
158
			devdir(c, q, "data", size, g->uid, g->perm, dp);
159
			putgseg(g);
160
			break;
161
		default:
162
			return -1;
163
		}
164
		break;
165
	}
166
	return 1;
167
}
168
 
169
static void
170
segmentinit(void)
171
{
172
	_globalsegattach = globalsegattach;
173
}
174
 
175
static Chan*
176
segmentattach(char *spec)
177
{
178
	return devattach('g', spec);
179
}
180
 
181
static Walkqid*
182
segmentwalk(Chan *c, Chan *nc, char **name, int nname)
183
{
184
	return devwalk(c, nc, name, nname, 0, 0, segmentgen);
185
}
186
 
187
static int
188
segmentstat(Chan *c, uchar *db, int n)
189
{
190
	return devstat(c, db, n, 0, 0, segmentgen);
191
}
192
 
193
static int
194
cmddone(void *arg)
195
{
196
	Globalseg *g = arg;
197
 
198
	return g->cmd == Cnone;
199
}
200
 
201
static Chan*
202
segmentopen(Chan *c, int omode)
203
{
204
	Globalseg *g;
205
 
206
	switch(TYPE(c)){
207
	case Qtopdir:
208
	case Qsegdir:
209
		if(omode != 0)
210
			error(Eisdir);
211
		break;
212
	case Qctl:
213
		g = getgseg(c);
214
		if(waserror()){
215
			putgseg(g);
216
			nexterror();
217
		}
218
		devpermcheck(g->uid, g->perm, omode);
219
		c->aux = g;
220
		poperror();
221
		c->flag |= COPEN;
222
		break;
223
	case Qdata:
224
		g = getgseg(c);
225
		if(waserror()){
226
			putgseg(g);
227
			nexterror();
228
		}
229
		devpermcheck(g->uid, g->perm, omode);
230
		if(g->s == nil)
231
			error("segment not yet allocated");
232
		if(g->kproc == nil){
233
			qlock(&g->l);
234
			if(waserror()){
235
				qunlock(&g->l);
236
				nexterror();
237
			}
238
			if(g->kproc == nil){
239
				g->cmd = Cnone;
240
				kproc(g->name, segmentkproc, g);
241
				docmd(g, Cstart);
242
			}
243
			qunlock(&g->l);
244
			poperror();
245
		}
246
		c->aux = g;
247
		poperror();
248
		c->flag |= COPEN;
249
		break;
250
	default:
251
		panic("segmentopen");
252
	}
253
	c->mode = openmode(omode);
254
	c->offset = 0;
255
	return c;
256
}
257
 
258
static void
259
segmentclose(Chan *c)
260
{
261
	if(TYPE(c) == Qtopdir)
262
		return;
263
	if(c->flag & COPEN)
264
		putgseg(c->aux);
265
}
266
 
267
static void
268
segmentcreate(Chan *c, char *name, int omode, ulong perm)
269
{
270
	int x, xfree;
271
	Globalseg *g;
272
 
273
	if(TYPE(c) != Qtopdir)
274
		error(Eperm);
275
 
276
	if(isphysseg(name))
277
		error(Eexist);
278
 
279
	if((perm & DMDIR) == 0)
280
		error(Ebadarg);
281
 
282
	if(waserror()){
283
		unlock(&globalseglock);
284
		nexterror();
285
	}
286
	lock(&globalseglock);
287
	xfree = -1;
288
	for(x = 0; x < nelem(globalseg); x++){
289
		g = globalseg[x];
290
		if(g == nil){
291
			if(xfree < 0)
292
				xfree = x;
293
		} else {
294
			if(strcmp(g->name, name) == 0)
295
				error(Eexist);
296
		}
297
	}
298
	if(xfree < 0)
299
		error("too many global segments");
300
	g = smalloc(sizeof(Globalseg));
301
	g->ref = 1;
302
	kstrdup(&g->name, name);
303
	kstrdup(&g->uid, up->user);
304
	g->perm = 0660; 
305
	globalseg[xfree] = g;
306
	unlock(&globalseglock);
307
	poperror();
308
 
309
	c->qid.path = PATH(x, Qsegdir);
310
	c->qid.type = QTDIR;
311
	c->qid.vers = 0;
312
	c->mode = openmode(omode);
313
	c->mode = OWRITE;
314
}
315
 
316
static long
317
segmentread(Chan *c, void *a, long n, vlong voff)
318
{
319
	Globalseg *g;
320
	char buf[32];
321
 
322
	if(c->qid.type == QTDIR)
323
		return devdirread(c, a, n, (Dirtab *)0, 0L, segmentgen);
324
 
325
	switch(TYPE(c)){
326
	case Qctl:
327
		g = c->aux;
328
		if(g->s == nil)
329
			error("segment not yet allocated");
330
		snprint(buf, sizeof buf, "va %#lux %#lux\n", g->s->base,
331
			g->s->top-g->s->base);
332
		return readstr(voff, a, n, buf);
333
	case Qdata:
334
		g = c->aux;
335
		if(voff > g->s->top - g->s->base)
336
			error(Ebadarg);
337
		if(voff + n > g->s->top - g->s->base)
338
			n = g->s->top - g->s->base - voff;
339
		qlock(&g->l);
340
		g->off = voff + g->s->base;
341
		g->data = smalloc(n);
342
		if(waserror()){
343
			free(g->data);
344
			qunlock(&g->l);
345
			nexterror();
346
		}
347
		g->dlen = n;
348
		docmd(g, Cread);
349
		memmove(a, g->data, g->dlen);
350
		free(g->data);
351
		qunlock(&g->l);
352
		poperror();
353
		return g->dlen;
354
	default:
355
		panic("segmentread");
356
	}
357
	return 0;	/* not reached */
358
}
359
 
360
static long
361
segmentwrite(Chan *c, void *a, long n, vlong voff)
362
{
363
	Cmdbuf *cb;
364
	Globalseg *g;
365
	ulong va, len, top;
366
 
367
	if(c->qid.type == QTDIR)
368
		error(Eperm);
369
 
370
	switch(TYPE(c)){
371
	case Qctl:
372
		g = c->aux;
373
		cb = parsecmd(a, n);
374
		if(strcmp(cb->f[0], "va") == 0){
375
			if(g->s != nil)
376
				error("already has a virtual address");
377
			if(cb->nf < 3)
378
				error(Ebadarg);
379
			va = strtoul(cb->f[1], 0, 0);
380
			len = strtoul(cb->f[2], 0, 0);
381
			top = PGROUND(va + len);
382
			va = va&~(BY2PG-1);
383
			len = (top - va) / BY2PG;
384
			if(len == 0)
385
				error(Ebadarg);
386
			g->s = newseg(SG_SHARED, va, len);
387
		} else
388
			error(Ebadctl);
389
		break;
390
	case Qdata:
391
		g = c->aux;
392
		if(voff + n > g->s->top - g->s->base)
393
			error(Ebadarg);
394
		qlock(&g->l);
395
		g->off = voff + g->s->base;
396
		g->data = smalloc(n);
397
		if(waserror()){
398
			free(g->data);
399
			qunlock(&g->l);
400
			nexterror();
401
		}
402
		g->dlen = n;
403
		memmove(g->data, a, g->dlen);
404
		docmd(g, Cwrite);
405
		free(g->data);
406
		qunlock(&g->l);
407
		poperror();
408
		return g->dlen;
409
	default:
410
		panic("segmentwrite");
411
	}
412
	return 0;	/* not reached */
413
}
414
 
415
static int
416
segmentwstat(Chan *c, uchar *dp, int n)
417
{
418
	Globalseg *g;
419
	Dir *d;
420
 
421
	if(c->qid.type == QTDIR)
422
		error(Eperm);
423
 
424
	g = getgseg(c);
425
	if(waserror()){
426
		putgseg(g);
427
		nexterror();
428
	}
429
 
430
	if(strcmp(g->uid, up->user) && !iseve())
431
		error(Eperm);
432
	d = smalloc(sizeof(Dir)+n);
433
	n = convM2D(dp, n, &d[0], (char*)&d[1]);
434
	g->perm = d->mode & 0777;
435
 
436
	putgseg(g);
437
	poperror();
438
 
439
	free(d);
440
	return n;
441
}
442
 
443
static void
444
segmentremove(Chan *c)
445
{
446
	Globalseg *g;
447
	int x;
448
 
449
	if(TYPE(c) != Qsegdir)
450
		error(Eperm);
451
	lock(&globalseglock);
452
	x = SEG(c);
453
	g = globalseg[x];
454
	globalseg[x] = nil;
455
	unlock(&globalseglock);
456
	if(g != nil)
457
		putgseg(g);
458
}
459
 
460
/*
461
 *  called by segattach()
462
 */
463
static Segment*
464
globalsegattach(Proc *p, char *name)
465
{
466
	int x;
467
	Globalseg *g;
468
	Segment *s;
469
 
470
	g = nil;
471
	if(waserror()){
472
		unlock(&globalseglock);
473
		nexterror();
474
	}
475
	lock(&globalseglock);
476
	for(x = 0; x < nelem(globalseg); x++){
477
		g = globalseg[x];
478
		if(g != nil && strcmp(g->name, name) == 0)
479
			break;
480
	}
481
	if(x == nelem(globalseg)){
482
		unlock(&globalseglock);
483
		poperror();
484
		return nil;
485
	}
486
	devpermcheck(g->uid, g->perm, ORDWR);
487
	s = g->s;
488
	if(s == nil)
489
		error("global segment not assigned a virtual address");
490
	if(isoverlap(p, s->base, s->top - s->base) != nil)
491
		error("overlaps existing segment");
492
	incref(s);
493
	unlock(&globalseglock);
494
	poperror();
495
	return s;
496
}
497
 
498
static void
499
docmd(Globalseg *g, int cmd)
500
{
501
	g->err[0] = 0;
502
	g->cmd = cmd;
503
	wakeup(&g->cmdwait);
504
	sleep(&g->replywait, cmddone, g);
505
	if(g->err[0])
506
		error(g->err);
507
}
508
 
509
static int
510
cmdready(void *arg)
511
{
512
	Globalseg *g = arg;
513
 
514
	return g->cmd != Cnone;
515
}
516
 
517
static void
518
segmentkproc(void *arg)
519
{
520
	Globalseg *g = arg;
521
	int done;
522
	int sno;
523
 
524
	for(sno = 0; sno < NSEG; sno++)
525
		if(up->seg[sno] == nil && sno != ESEG)
526
			break;
527
	if(sno == NSEG)
528
		panic("segmentkproc");
529
	g->kproc = up;
530
 
531
	incref(g->s);
532
	up->seg[sno] = g->s;
533
 
534
	for(done = 0; !done;){
535
		sleep(&g->cmdwait, cmdready, g);
536
		if(waserror()){
537
			strncpy(g->err, up->errstr, sizeof(g->err));
538
		} else {
539
			switch(g->cmd){
540
			case Cstart:
541
				break;
542
			case Cdie:
543
				done = 1;
544
				break;
545
			case Cread:
546
				memmove(g->data, (char*)g->off, g->dlen);
547
				break;
548
			case Cwrite:
549
				memmove((char*)g->off, g->data, g->dlen);
550
				break;
551
			}
552
			poperror();
553
		}
554
		g->cmd = Cnone;
555
		wakeup(&g->replywait);
556
	}
557
}
558
 
559
Dev segmentdevtab = {
560
	'g',
561
	"segment",
562
 
563
	devreset,
564
	segmentinit,
565
	devshutdown,
566
	segmentattach,
567
	segmentwalk,
568
	segmentstat,
569
	segmentopen,
570
	segmentcreate,
571
	segmentclose,
572
	segmentread,
573
	devbread,
574
	segmentwrite,
575
	devbwrite,
576
	segmentremove,
577
	segmentwstat,
578
};
579