FreeBSD/Linux Kernel Cross Reference
sys/port/devsegment.c
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 sprint(buf, "va %#lux %#lux\n", g->s->base, g->s->top-g->s->base);
331 return readstr(voff, a, n, buf);
332 case Qdata:
333 g = c->aux;
334 if(voff > g->s->top - g->s->base)
335 error(Ebadarg);
336 if(voff + n > g->s->top - g->s->base)
337 n = g->s->top - g->s->base - voff;
338 qlock(&g->l);
339 g->off = voff + g->s->base;
340 g->data = smalloc(n);
341 if(waserror()){
342 free(g->data);
343 qunlock(&g->l);
344 nexterror();
345 }
346 g->dlen = n;
347 docmd(g, Cread);
348 memmove(a, g->data, g->dlen);
349 free(g->data);
350 qunlock(&g->l);
351 poperror();
352 return g->dlen;
353 default:
354 panic("segmentread");
355 }
356 return 0; /* not reached */
357 }
358
359 static long
360 segmentwrite(Chan *c, void *a, long n, vlong voff)
361 {
362 Cmdbuf *cb;
363 Globalseg *g;
364 ulong va, len, top;
365
366 if(c->qid.type == QTDIR)
367 error(Eperm);
368
369 switch(TYPE(c)){
370 case Qctl:
371 g = c->aux;
372 cb = parsecmd(a, n);
373 if(strcmp(cb->f[0], "va") == 0){
374 if(g->s != nil)
375 error("already has a virtual address");
376 if(cb->nf < 3)
377 error(Ebadarg);
378 va = strtoul(cb->f[1], 0, 0);
379 len = strtoul(cb->f[2], 0, 0);
380 top = PGROUND(va + len);
381 va = va&~(BY2PG-1);
382 len = (top - va) / BY2PG;
383 if(len == 0)
384 error(Ebadarg);
385 g->s = newseg(SG_SHARED, va, len);
386 } else
387 error(Ebadctl);
388 break;
389 case Qdata:
390 g = c->aux;
391 if(voff + n > g->s->top - g->s->base)
392 error(Ebadarg);
393 qlock(&g->l);
394 g->off = voff + g->s->base;
395 g->data = smalloc(n);
396 if(waserror()){
397 free(g->data);
398 qunlock(&g->l);
399 nexterror();
400 }
401 g->dlen = n;
402 memmove(g->data, a, g->dlen);
403 docmd(g, Cwrite);
404 free(g->data);
405 qunlock(&g->l);
406 poperror();
407 return g->dlen;
408 default:
409 panic("segmentwrite");
410 }
411 return 0; /* not reached */
412 }
413
414 static int
415 segmentwstat(Chan *c, uchar *dp, int n)
416 {
417 Globalseg *g;
418 Dir *d;
419
420 if(c->qid.type == QTDIR)
421 error(Eperm);
422
423 g = getgseg(c);
424 if(waserror()){
425 putgseg(g);
426 nexterror();
427 }
428
429 if(strcmp(g->uid, up->user) && !iseve())
430 error(Eperm);
431 d = smalloc(sizeof(Dir)+n);
432 n = convM2D(dp, n, &d[0], (char*)&d[1]);
433 g->perm = d->mode & 0777;
434
435 putgseg(g);
436 poperror();
437
438 free(d);
439 return n;
440 }
441
442 static void
443 segmentremove(Chan *c)
444 {
445 Globalseg *g;
446 int x;
447
448 if(TYPE(c) != Qsegdir)
449 error(Eperm);
450 lock(&globalseglock);
451 x = SEG(c);
452 g = globalseg[x];
453 globalseg[x] = nil;
454 unlock(&globalseglock);
455 if(g != nil)
456 putgseg(g);
457 }
458
459 /*
460 * called by segattach()
461 */
462 static Segment*
463 globalsegattach(Proc *p, char *name)
464 {
465 int x;
466 Globalseg *g;
467 Segment *s;
468
469 g = nil;
470 if(waserror()){
471 unlock(&globalseglock);
472 nexterror();
473 }
474 lock(&globalseglock);
475 for(x = 0; x < nelem(globalseg); x++){
476 g = globalseg[x];
477 if(g != nil && strcmp(g->name, name) == 0)
478 break;
479 }
480 if(x == nelem(globalseg)){
481 unlock(&globalseglock);
482 poperror();
483 return nil;
484 }
485 devpermcheck(g->uid, g->perm, ORDWR);
486 s = g->s;
487 if(s == nil)
488 error("global segment not assigned a virtual address");
489 if(isoverlap(p, s->base, s->top - s->base) != nil)
490 error("overlaps existing segment");
491 incref(s);
492 unlock(&globalseglock);
493 poperror();
494 return s;
495 }
496
497 static void
498 docmd(Globalseg *g, int cmd)
499 {
500 g->err[0] = 0;
501 g->cmd = cmd;
502 wakeup(&g->cmdwait);
503 sleep(&g->replywait, cmddone, g);
504 if(g->err[0])
505 error(g->err);
506 }
507
508 static int
509 cmdready(void *arg)
510 {
511 Globalseg *g = arg;
512
513 return g->cmd != Cnone;
514 }
515
516 static void
517 segmentkproc(void *arg)
518 {
519 Globalseg *g = arg;
520 int done;
521 int sno;
522
523 for(sno = 0; sno < NSEG; sno++)
524 if(up->seg[sno] == nil && sno != ESEG)
525 break;
526 if(sno == NSEG)
527 panic("segmentkproc");
528 g->kproc = up;
529
530 incref(g->s);
531 up->seg[sno] = g->s;
532
533 for(done = 0; !done;){
534 sleep(&g->cmdwait, cmdready, g);
535 if(waserror()){
536 strncpy(g->err, up->errstr, sizeof(g->err));
537 } else {
538 switch(g->cmd){
539 case Cstart:
540 break;
541 case Cdie:
542 done = 1;
543 break;
544 case Cread:
545 memmove(g->data, (char*)g->off, g->dlen);
546 break;
547 case Cwrite:
548 memmove((char*)g->off, g->data, g->dlen);
549 break;
550 }
551 poperror();
552 }
553 g->cmd = Cnone;
554 wakeup(&g->replywait);
555 }
556 }
557
558 Dev segmentdevtab = {
559 'g',
560 "segment",
561
562 devreset,
563 segmentinit,
564 devshutdown,
565 segmentattach,
566 segmentwalk,
567 segmentstat,
568 segmentopen,
569 segmentcreate,
570 segmentclose,
571 segmentread,
572 devbread,
573 segmentwrite,
574 devbwrite,
575 segmentremove,
576 segmentwstat,
577 };
578
Cache object: 8d402d67b239a6124a3a84e6da9737e1
|