]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devproc.c
kernel: make noswap flag exclude processes from killbig() if not eve, reset noswap...
[plan9front.git] / sys / src / 9 / port / devproc.c
1 #include        "u.h"
2 #include        <trace.h>
3 #include        "tos.h"
4 #include        "../port/lib.h"
5 #include        "mem.h"
6 #include        "dat.h"
7 #include        "fns.h"
8 #include        "../port/error.h"
9 #include        "ureg.h"
10 #include        "edf.h"
11
12 enum
13 {
14         Qdir,
15         Qtrace,
16         Qargs,
17         Qctl,
18         Qfd,
19         Qfpregs,
20         Qkregs,
21         Qmem,
22         Qnote,
23         Qnoteid,
24         Qnotepg,
25         Qns,
26         Qppid,
27         Qproc,
28         Qregs,
29         Qsegment,
30         Qstatus,
31         Qtext,
32         Qwait,
33         Qprofile,
34         Qsyscall,
35 };
36
37 enum
38 {
39         CMclose,
40         CMclosefiles,
41         CMfixedpri,
42         CMhang,
43         CMkill,
44         CMnohang,
45         CMnoswap,
46         CMpri,
47         CMprivate,
48         CMprofile,
49         CMstart,
50         CMstartstop,
51         CMstartsyscall,
52         CMstop,
53         CMwaitstop,
54         CMwired,
55         CMtrace,
56         CMinterrupt,
57         CMnointerrupt,
58         /* real time */
59         CMperiod,
60         CMdeadline,
61         CMcost,
62         CMsporadic,
63         CMdeadlinenotes,
64         CMadmit,
65         CMextra,
66         CMexpel,
67         CMevent,
68 };
69
70 enum{
71         Nevents = 0x4000,
72         Emask = Nevents - 1,
73 };
74
75 #define STATSIZE        (2*KNAMELEN+12+9*12)
76 /*
77  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
78  * particularly on shared servers.
79  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
80  */
81 Dirtab procdir[] =
82 {
83         "args",         {Qargs},        0,                      0660,
84         "ctl",          {Qctl},         0,                      0000,
85         "fd",           {Qfd},          0,                      0444,
86         "fpregs",       {Qfpregs},      sizeof(FPsave),         0000,
87         "kregs",        {Qkregs},       sizeof(Ureg),           0400,
88         "mem",          {Qmem},         0,                      0000,
89         "note",         {Qnote},        0,                      0000,
90         "noteid",       {Qnoteid},      0,                      0664,
91         "notepg",       {Qnotepg},      0,                      0000,
92         "ns",           {Qns},          0,                      0444,
93         "ppid",         {Qppid},        0,                      0444,
94         "proc",         {Qproc},        0,                      0400,
95         "regs",         {Qregs},        sizeof(Ureg),           0000,
96         "segment",      {Qsegment},     0,                      0444,
97         "status",       {Qstatus},      STATSIZE,               0444,
98         "text",         {Qtext},        0,                      0000,
99         "wait",         {Qwait},        0,                      0400,
100         "profile",      {Qprofile},     0,                      0400,
101         "syscall",      {Qsyscall},     0,                      0400,   
102 };
103
104 static
105 Cmdtab proccmd[] = {
106         CMclose,                "close",                2,
107         CMclosefiles,           "closefiles",           1,
108         CMfixedpri,             "fixedpri",             2,
109         CMhang,                 "hang",                 1,
110         CMnohang,               "nohang",               1,
111         CMnoswap,               "noswap",               1,
112         CMkill,                 "kill",                 1,
113         CMpri,                  "pri",                  2,
114         CMprivate,              "private",              1,
115         CMprofile,              "profile",              1,
116         CMstart,                "start",                1,
117         CMstartstop,            "startstop",            1,
118         CMstartsyscall,         "startsyscall",         1,
119         CMstop,                 "stop",                 1,
120         CMwaitstop,             "waitstop",             1,
121         CMwired,                "wired",                2,
122         CMtrace,                "trace",                0,
123         CMinterrupt,            "interrupt",            1,
124         CMnointerrupt,          "nointerrupt",          1,
125         CMperiod,               "period",               2,
126         CMdeadline,             "deadline",             2,
127         CMcost,                 "cost",                 2,
128         CMsporadic,             "sporadic",             1,
129         CMdeadlinenotes,        "deadlinenotes",        1,
130         CMadmit,                "admit",                1,
131         CMextra,                "extra",                1,
132         CMexpel,                "expel",                1,
133         CMevent,                "event",                1,
134 };
135
136 /* Segment type from portdat.h */
137 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
138
139 /*
140  * Qids are, in path:
141  *       4 bits of file type (qids above)
142  *      23 bits of process slot number + 1
143  *           in vers,
144  *      32 bits of pid, for consistency checking
145  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
146  */
147 #define QSHIFT  5       /* location in qid of proc slot # */
148
149 #define QID(q)          ((((ulong)(q).path)&0x0000001F)>>0)
150 #define SLOT(q)         (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
151 #define PID(q)          ((q).vers)
152 #define NOTEID(q)       ((q).vers)
153
154 void    procctlreq(Proc*, char*, int);
155 int     procctlmemio(Proc*, uintptr, int, void*, int);
156 Chan*   proctext(Chan*, Proc*);
157 int     procstopped(void*);
158 void    mntscan(Mntwalk*, Proc*);
159 ulong   procpagecount(Proc *);
160
161 static Traceevent *tevents;
162 static Lock tlock;
163 static int topens;
164 static int tproduced, tconsumed;
165 void (*proctrace)(Proc*, int, vlong);
166
167 extern int unfair;
168
169 static void
170 profclock(Ureg *ur, Timer *)
171 {
172         Tos *tos;
173
174         if(up == nil || up->state != Running)
175                 return;
176
177         /* user profiling clock */
178         if(userureg(ur)){
179                 tos = (Tos*)(USTKTOP-sizeof(Tos));
180                 tos->clock += TK2MS(1);
181                 segclock(ur->pc);
182         }
183 }
184
185 static int
186 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
187 {
188         Qid qid;
189         Proc *p;
190         char *ename;
191         Segment *q;
192         ulong pid, path, perm, len;
193
194         if(s == DEVDOTDOT){
195                 mkqid(&qid, Qdir, 0, QTDIR);
196                 devdir(c, qid, "#p", 0, eve, 0555, dp);
197                 return 1;
198         }
199
200         if(c->qid.path == Qdir){
201                 if(s == 0){
202                         strcpy(up->genbuf, "trace");
203                         mkqid(&qid, Qtrace, -1, QTFILE);
204                         devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
205                         return 1;
206                 }
207
208                 if(name != nil){
209                         /* ignore s and use name to find pid */
210                         pid = strtol(name, &ename, 10);
211                         if(pid==0 || ename[0]!='\0')
212                                 return -1;
213                         s = procindex(pid);
214                         if(s < 0)
215                                 return -1;
216                 }
217                 else if(--s >= conf.nproc)
218                         return -1;
219
220                 p = proctab(s);
221                 pid = p->pid;
222                 if(pid == 0)
223                         return 0;
224                 sprint(up->genbuf, "%lud", pid);
225                 /*
226                  * String comparison is done in devwalk so name must match its formatted pid
227                 */
228                 if(name != nil && strcmp(name, up->genbuf) != 0)
229                         return -1;
230                 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
231                 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
232                 return 1;
233         }
234         if(c->qid.path == Qtrace){
235                 strcpy(up->genbuf, "trace");
236                 mkqid(&qid, Qtrace, -1, QTFILE);
237                 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
238                 return 1;
239         }
240         if(s >= nelem(procdir))
241                 return -1;
242         if(tab)
243                 panic("procgen");
244
245         tab = &procdir[s];
246         path = c->qid.path&~(((1<<QSHIFT)-1));  /* slot component */
247
248         /* p->procmode determines default mode for files in /proc */
249         p = proctab(SLOT(c->qid));
250         perm = tab->perm;
251         if(perm == 0)
252                 perm = p->procmode;
253         else    /* just copy read bits */
254                 perm |= p->procmode & 0444;
255
256         len = tab->length;
257         switch(QID(c->qid)) {
258         case Qwait:
259                 len = p->nwait; /* incorrect size, but >0 means there's something to read */
260                 break;
261         case Qprofile:
262                 q = p->seg[TSEG];
263                 if(q != nil && q->profile != nil) {
264                         len = (q->top-q->base)>>LRESPROF;
265                         len *= sizeof(*q->profile);
266                 }
267                 break;
268         }
269
270         mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
271         devdir(c, qid, tab->name, len, p->user, perm, dp);
272         return 1;
273 }
274
275 static void
276 _proctrace(Proc* p, Tevent etype, vlong ts)
277 {
278         Traceevent *te;
279
280         if (p->trace == 0 || topens == 0 ||
281                 tproduced - tconsumed >= Nevents)
282                 return;
283
284         te = &tevents[tproduced&Emask];
285         te->pid = p->pid;
286         te->etype = etype;
287         if (ts == 0)
288                 te->time = todget(nil);
289         else
290                 te->time = ts;
291         tproduced++;
292 }
293
294 static void
295 procinit(void)
296 {
297         if(conf.nproc >= (1<<(16-QSHIFT))-1)
298                 print("warning: too many procs for devproc\n");
299         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
300 }
301
302 static Chan*
303 procattach(char *spec)
304 {
305         return devattach('p', spec);
306 }
307
308 static Walkqid*
309 procwalk(Chan *c, Chan *nc, char **name, int nname)
310 {
311         return devwalk(c, nc, name, nname, 0, 0, procgen);
312 }
313
314 static int
315 procstat(Chan *c, uchar *db, int n)
316 {
317         return devstat(c, db, n, 0, 0, procgen);
318 }
319
320 /*
321  *  none can't read or write state on other
322  *  processes.  This is to contain access of
323  *  servers running as none should they be
324  *  subverted by, for example, a stack attack.
325  */
326 static void
327 nonone(Proc *p)
328 {
329         if(p == up)
330                 return;
331         if(strcmp(up->user, "none") != 0)
332                 return;
333         if(iseve())
334                 return;
335         error(Eperm);
336 }
337
338 static Chan*
339 procopen(Chan *c, int omode)
340 {
341         Proc *p;
342         Pgrp *pg;
343         Chan *tc;
344         int pid;
345
346         if(c->qid.type & QTDIR)
347                 return devopen(c, omode, 0, 0, procgen);
348
349         if(QID(c->qid) == Qtrace){
350                 if (omode != OREAD) 
351                         error(Eperm);
352                 lock(&tlock);
353                 if (waserror()){
354                         topens--;
355                         unlock(&tlock);
356                         nexterror();
357                 }
358                 if (topens++ > 0)
359                         error("already open");
360                 if (tevents == nil){
361                         tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
362                         if(tevents == nil)
363                                 error(Enomem);
364                         tproduced = tconsumed = 0;
365                 }
366                 proctrace = _proctrace;
367                 unlock(&tlock);
368                 poperror();
369
370                 c->mode = openmode(omode);
371                 c->flag |= COPEN;
372                 c->offset = 0;
373                 return c;
374         }
375                 
376         p = proctab(SLOT(c->qid));
377         eqlock(&p->debug);
378         if(waserror()){
379                 qunlock(&p->debug);
380                 nexterror();
381         }
382         pid = PID(c->qid);
383         if(p->pid != pid)
384                 error(Eprocdied);
385
386         omode = openmode(omode);
387
388         switch(QID(c->qid)){
389         case Qtext:
390                 if(omode != OREAD)
391                         error(Eperm);
392                 tc = proctext(c, p);
393                 tc->offset = 0;
394                 qunlock(&p->debug);
395                 poperror();
396                 cclose(c);
397                 return tc;
398
399         case Qproc:
400         case Qkregs:
401         case Qsegment:
402         case Qprofile:
403         case Qfd:
404                 if(omode != OREAD)
405                         error(Eperm);
406                 break;
407
408         case Qnote:
409                 if(p->privatemem)
410                         error(Eperm);
411                 break;
412
413         case Qmem:
414         case Qctl:
415                 if(p->privatemem)
416                         error(Eperm);
417                 nonone(p);
418                 break;
419
420         case Qargs:
421         case Qnoteid:
422         case Qstatus:
423         case Qwait:
424         case Qregs:
425         case Qfpregs:
426         case Qsyscall:  
427         case Qppid:
428                 nonone(p);
429                 break;
430
431         case Qns:
432                 if(omode != OREAD)
433                         error(Eperm);
434                 c->aux = smalloc(sizeof(Mntwalk));
435                 break;
436
437         case Qnotepg:
438                 nonone(p);
439                 pg = p->pgrp;
440                 if(pg == nil)
441                         error(Eprocdied);
442                 if(omode!=OWRITE)
443                         error(Eperm);
444                 c->pgrpid.path = pg->pgrpid+1;
445                 c->pgrpid.vers = p->noteid;
446                 break;
447
448         default:
449                 print("procopen %#lux\n", QID(c->qid));
450                 error(Egreg);
451         }
452
453         /* Affix pid to qid */
454         if(p->state != Dead)
455                 c->qid.vers = p->pid;
456
457         /* make sure the process slot didn't get reallocated while we were playing */
458         coherence();
459         if(p->pid != pid)
460                 error(Eprocdied);
461
462         tc = devopen(c, omode, 0, 0, procgen);
463         qunlock(&p->debug);
464         poperror();
465
466         return tc;
467 }
468
469 static int
470 procwstat(Chan *c, uchar *db, int n)
471 {
472         Proc *p;
473         Dir *d;
474
475         if(c->qid.type&QTDIR)
476                 error(Eperm);
477
478         if(QID(c->qid) == Qtrace)
479                 return devwstat(c, db, n);
480                 
481         p = proctab(SLOT(c->qid));
482         nonone(p);
483         d = nil;
484
485         eqlock(&p->debug);
486         if(waserror()){
487                 qunlock(&p->debug);
488                 free(d);
489                 nexterror();
490         }
491
492         if(p->pid != PID(c->qid))
493                 error(Eprocdied);
494
495         if(strcmp(up->user, p->user) != 0 && !iseve())
496                 error(Eperm);
497
498         d = smalloc(sizeof(Dir)+n);
499         n = convM2D(db, n, &d[0], (char*)&d[1]);
500         if(n == 0)
501                 error(Eshortstat);
502         if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
503                 if(!iseve())
504                         error(Eperm);
505                 kstrdup(&p->user, d->uid);
506         }
507         /* p->procmode determines default mode for files in /proc */
508         if(d->mode != ~0UL)
509                 p->procmode = d->mode&0777;
510
511         qunlock(&p->debug);
512         poperror();
513         free(d);
514         return n;
515 }
516
517
518 static long
519 procoffset(long offset, char *va, int *np)
520 {
521         if(offset > 0) {
522                 offset -= *np;
523                 if(offset < 0) {
524                         memmove(va, va+*np+offset, -offset);
525                         *np = -offset;
526                 }
527                 else
528                         *np = 0;
529         }
530         return offset;
531 }
532
533 static int
534 procqidwidth(Chan *c)
535 {
536         char buf[32];
537
538         return sprint(buf, "%lud", c->qid.vers);
539 }
540
541 int
542 procfdprint(Chan *c, int fd, int w, char *s, int ns)
543 {
544         int n;
545
546         if(w == 0)
547                 w = procqidwidth(c);
548         n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
549                 fd,
550                 &"r w rw"[(c->mode&3)<<1],
551                 devtab[c->type]->dc, c->dev,
552                 c->qid.path, w, c->qid.vers, c->qid.type,
553                 c->iounit, c->offset, c->path->s);
554         return n;
555 }
556
557 static int
558 procfds(Proc *p, char *va, int count, long offset)
559 {
560         Fgrp *f;
561         Chan *c;
562         char buf[256];
563         int n, i, w, ww;
564         char *a;
565
566         /* print to buf to avoid holding fgrp lock while writing to user space */
567         if(count > sizeof buf)
568                 count = sizeof buf;
569         a = buf;
570
571         eqlock(&p->debug);
572         f = p->fgrp;
573         if(f == nil || p->dot == nil){
574                 qunlock(&p->debug);
575                 return 0;
576         }
577         lock(f);
578         if(waserror()){
579                 unlock(f);
580                 qunlock(&p->debug);
581                 nexterror();
582         }
583
584         n = readstr(0, a, count, p->dot->path->s);
585         n += snprint(a+n, count-n, "\n");
586         offset = procoffset(offset, a, &n);
587         /* compute width of qid.path */
588         w = 0;
589         for(i = 0; i <= f->maxfd; i++) {
590                 c = f->fd[i];
591                 if(c == nil)
592                         continue;
593                 ww = procqidwidth(c);
594                 if(ww > w)
595                         w = ww;
596         }
597         for(i = 0; i <= f->maxfd; i++) {
598                 c = f->fd[i];
599                 if(c == nil)
600                         continue;
601                 n += procfdprint(c, i, w, a+n, count-n);
602                 offset = procoffset(offset, a, &n);
603         }
604         unlock(f);
605         qunlock(&p->debug);
606         poperror();
607
608         /* copy result to user space, now that locks are released */
609         memmove(va, buf, n);
610
611         return n;
612 }
613
614 static void
615 procclose(Chan *c)
616 {
617         if(QID(c->qid) == Qtrace && (c->flag & COPEN) != 0){
618                 lock(&tlock);
619                 if(topens > 0)
620                         topens--;
621                 if(topens == 0)
622                         proctrace = nil;
623                 unlock(&tlock);
624         }
625         if(QID(c->qid) == Qns && c->aux != nil){
626                 free(c->aux);
627                 c->aux = nil;
628         }
629 }
630
631 static void
632 int2flag(int flag, char *s)
633 {
634         if(flag == 0){
635                 *s = '\0';
636                 return;
637         }
638         *s++ = '-';
639         if(flag & MAFTER)
640                 *s++ = 'a';
641         if(flag & MBEFORE)
642                 *s++ = 'b';
643         if(flag & MCREATE)
644                 *s++ = 'c';
645         if(flag & MCACHE)
646                 *s++ = 'C';
647         *s = '\0';
648 }
649
650 static int
651 procargs(Proc *p, char *buf, int nbuf)
652 {
653         int j, k, m;
654         char *a;
655         int n;
656
657         a = p->args;
658         if(p->setargs){
659                 snprint(buf, nbuf, "%s [%s]", p->text, p->args);
660                 return strlen(buf);
661         }
662         n = p->nargs;
663         for(j = 0; j < nbuf - 1; j += m){
664                 if(n <= 0)
665                         break;
666                 if(j != 0)
667                         buf[j++] = ' ';
668                 m = snprint(buf+j, nbuf-j, "%q",  a);
669                 k = strlen(a) + 1;
670                 a += k;
671                 n -= k;
672         }
673         return j;
674 }
675
676 static int
677 eventsavailable(void *)
678 {
679         return tproduced > tconsumed;
680 }
681
682 static int
683 prochaswaitq(void *x)
684 {
685         Chan *c;
686         Proc *p;
687
688         c = (Chan *)x;
689         p = proctab(SLOT(c->qid));
690         return p->pid != PID(c->qid) || p->waitq != nil;
691 }
692
693 /*
694  * userspace can't pass negative file offset for a
695  * 64 bit kernel address, so we use 63 bit and sign
696  * extend to 64 bit.
697  */
698 static uintptr
699 off2addr(vlong off)
700 {
701         off <<= 1;
702         off >>= 1;
703         return off;
704 }
705
706 static long
707 procread(Chan *c, void *va, long n, vlong off)
708 {
709         /* NSEG*32 was too small for worst cases */
710         char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
711         int i, j, m, navail, ne, rsize;
712         long l;
713         uchar *rptr;
714         uintptr addr;
715         ulong offset;
716         Confmem *cm;
717         Mntwalk *mw;
718         Proc *p;
719         Segment *sg, *s;
720         Ureg kur;
721         Waitq *wq;
722         
723         a = va;
724         offset = off;
725         if(c->qid.type & QTDIR)
726                 return devdirread(c, a, n, 0, 0, procgen);
727
728         if(QID(c->qid) == Qtrace){
729                 if(!eventsavailable(nil))
730                         return 0;
731
732                 rptr = (uchar*)va;
733                 navail = tproduced - tconsumed;
734                 if(navail > n / sizeof(Traceevent))
735                         navail = n / sizeof(Traceevent);
736                 while(navail > 0) {
737                         ne = ((tconsumed & Emask) + navail > Nevents)? 
738                                         Nevents - (tconsumed & Emask): navail;
739                         memmove(rptr, &tevents[tconsumed & Emask], 
740                                         ne * sizeof(Traceevent));
741
742                         tconsumed += ne;
743                         rptr += ne * sizeof(Traceevent);
744                         navail -= ne;
745                 }
746                 return rptr - (uchar*)va;
747         }
748
749         p = proctab(SLOT(c->qid));
750         if(p->pid != PID(c->qid))
751                 error(Eprocdied);
752
753         switch(QID(c->qid)){
754         case Qargs:
755                 eqlock(&p->debug);
756                 j = procargs(p, up->genbuf, sizeof up->genbuf);
757                 qunlock(&p->debug);
758                 if(offset >= j)
759                         return 0;
760                 if(offset+n > j)
761                         n = j-offset;
762                 memmove(a, &up->genbuf[offset], n);
763                 return n;
764         case Qsyscall:
765                 eqlock(&p->debug);
766                 if(waserror()){
767                         qunlock(&p->debug);
768                         nexterror();
769                 }
770                 if(p->pid != PID(c->qid))
771                         error(Eprocdied);
772                 if(p->syscalltrace != nil)
773                         n = readstr(offset, a, n, p->syscalltrace);
774                 else
775                         n = 0;
776                 qunlock(&p->debug);
777                 poperror();
778                 return n;
779
780         case Qmem:
781                 addr = off2addr(off);
782                 if(addr < KZERO)
783                         return procctlmemio(p, addr, n, va, 1);
784
785                 if(!iseve())
786                         error(Eperm);
787
788                 /* validate kernel addresses */
789                 if(addr < (uintptr)end) {
790                         if(addr+n > (uintptr)end)
791                                 n = (uintptr)end - addr;
792                         memmove(a, (char*)addr, n);
793                         return n;
794                 }
795                 for(i=0; i<nelem(conf.mem); i++){
796                         cm = &conf.mem[i];
797                         /* klimit-1 because klimit might be zero! */
798                         if(cm->kbase <= addr && addr <= cm->klimit-1){
799                                 if(addr+n >= cm->klimit-1)
800                                         n = cm->klimit - addr;
801                                 memmove(a, (char*)addr, n);
802                                 return n;
803                         }
804                 }
805                 error(Ebadarg);
806
807         case Qprofile:
808                 s = p->seg[TSEG];
809                 if(s == nil || s->profile == nil)
810                         error("profile is off");
811                 i = (s->top-s->base)>>LRESPROF;
812                 i *= sizeof(s->profile[0]);
813                 if(i < 0 || offset >= i)
814                         return 0;
815                 if(offset+n > i)
816                         n = i - offset;
817                 memmove(a, ((char*)s->profile)+offset, n);
818                 return n;
819
820         case Qnote:
821                 eqlock(&p->debug);
822                 if(waserror()){
823                         qunlock(&p->debug);
824                         nexterror();
825                 }
826                 if(p->pid != PID(c->qid))
827                         error(Eprocdied);
828                 if(n < 1)       /* must accept at least the '\0' */
829                         error(Etoosmall);
830                 if(p->nnote == 0)
831                         n = 0;
832                 else {
833                         m = strlen(p->note[0].msg) + 1;
834                         if(m > n)
835                                 m = n;
836                         memmove(va, p->note[0].msg, m-1);
837                         ((char*)va)[m-1] = '\0';
838                         p->nnote--;
839                         memmove(p->note, p->note+1, p->nnote*sizeof(Note));
840                         n = m;
841                 }
842                 if(p->nnote == 0)
843                         p->notepending = 0;
844                 poperror();
845                 qunlock(&p->debug);
846                 return n;
847
848         case Qproc:
849                 if(offset >= sizeof(Proc))
850                         return 0;
851                 if(offset+n > sizeof(Proc))
852                         n = sizeof(Proc) - offset;
853                 memmove(a, ((char*)p)+offset, n);
854                 return n;
855
856         case Qregs:
857                 rptr = (uchar*)p->dbgreg;
858                 rsize = sizeof(Ureg);
859                 goto regread;
860
861         case Qkregs:
862                 memset(&kur, 0, sizeof(Ureg));
863                 setkernur(&kur, p);
864                 rptr = (uchar*)&kur;
865                 rsize = sizeof(Ureg);
866                 goto regread;
867
868         case Qfpregs:
869                 rptr = (uchar*)&p->fpsave;
870                 rsize = sizeof(FPsave);
871         regread:
872                 if(rptr == nil)
873                         error(Enoreg);
874                 if(offset >= rsize)
875                         return 0;
876                 if(offset+n > rsize)
877                         n = rsize - offset;
878                 memmove(a, rptr+offset, n);
879                 return n;
880
881         case Qstatus:
882                 if(offset >= STATSIZE)
883                         return 0;
884                 if(offset+n > STATSIZE)
885                         n = STATSIZE - offset;
886
887                 sps = p->psstate;
888                 if(sps == nil)
889                         sps = statename[p->state];
890
891                 memset(statbuf, ' ', sizeof statbuf);
892                 readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
893                 readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
894                 readstr(0, statbuf+2*KNAMELEN, 11, sps);
895
896                 j = 2*KNAMELEN + 12;
897                 for(i = 0; i < 6; i++) {
898                         l = p->time[i];
899                         if(i == TReal)
900                                 l = MACHP(0)->ticks - l;
901                         l = TK2MS(l);
902                         readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
903                 }
904
905                 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, procpagecount(p)*BY2PG/1024, NUMSIZE);
906                 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
907                 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
908                 memmove(a, statbuf+offset, n);
909                 return n;
910
911         case Qsegment:
912                 j = 0;
913                 for(i = 0; i < NSEG; i++) {
914                         sg = p->seg[i];
915                         if(sg == nil)
916                                 continue;
917                         j += sprint(statbuf+j, "%-6s %c%c %8p %8p %4ld\n",
918                                 sname[sg->type&SG_TYPE],
919                                 sg->type&SG_RONLY ? 'R' : ' ',
920                                 sg->profile ? 'P' : ' ',
921                                 sg->base, sg->top, sg->ref);
922                 }
923                 if(offset >= j)
924                         return 0;
925                 if(offset+n > j)
926                         n = j-offset;
927                 if(n == 0 && offset == 0)
928                         exhausted("segments");
929                 memmove(a, &statbuf[offset], n);
930                 return n;
931
932         case Qwait:
933                 if(!canqlock(&p->qwaitr))
934                         error(Einuse);
935
936                 if(waserror()) {
937                         qunlock(&p->qwaitr);
938                         nexterror();
939                 }
940
941                 lock(&p->exl);
942                 while(p->waitq == nil && p->pid == PID(c->qid)) {
943                         if(up == p && p->nchild == 0) {
944                                 unlock(&p->exl);
945                                 error(Enochild);
946                         }
947                         unlock(&p->exl);
948                         sleep(&p->waitr, prochaswaitq, c);
949                         lock(&p->exl);
950                 }
951                 if(p->pid != PID(c->qid)){
952                         unlock(&p->exl);
953                         error(Eprocdied);
954                 }
955                 wq = p->waitq;
956                 p->waitq = wq->next;
957                 p->nwait--;
958                 unlock(&p->exl);
959
960                 qunlock(&p->qwaitr);
961                 poperror();
962                 n = snprint(a, n, "%d %lud %lud %lud %q",
963                         wq->w.pid,
964                         wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
965                         wq->w.msg);
966                 free(wq);
967                 return n;
968
969         case Qns:
970                 eqlock(&p->debug);
971                 if(waserror()){
972                         qunlock(&p->debug);
973                         nexterror();
974                 }
975                 if(p->pgrp == nil || p->dot == nil || p->pid != PID(c->qid))
976                         error(Eprocdied);
977                 mw = c->aux;
978                 if(mw->cddone){
979                         qunlock(&p->debug);
980                         poperror();
981                         return 0;
982                 }
983                 mntscan(mw, p);
984                 if(mw->mh == nil){
985                         mw->cddone = 1;
986                         i = snprint(a, n, "cd %s\n", p->dot->path->s);
987                         qunlock(&p->debug);
988                         poperror();
989                         return i;
990                 }
991                 int2flag(mw->cm->mflag, flag);
992                 if(strcmp(mw->cm->to->path->s, "#M") == 0){
993                         srv = srvname(mw->cm->to->mchan);
994                         i = snprint(a, n, "mount %s %s %s %s\n", flag,
995                                 srv==nil? mw->cm->to->mchan->path->s : srv,
996                                 mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
997                         free(srv);
998                 }else
999                         i = snprint(a, n, "bind %s %s %s\n", flag,
1000                                 mw->cm->to->path->s, mw->mh->from->path->s);
1001                 qunlock(&p->debug);
1002                 poperror();
1003                 return i;
1004
1005         case Qnoteid:
1006                 return readnum(offset, va, n, p->noteid, NUMSIZE);
1007         case Qppid:
1008                 return readnum(offset, va, n, p->parentpid, NUMSIZE);
1009         case Qfd:
1010                 return procfds(p, va, n, offset);
1011         }
1012         error(Egreg);
1013         return 0;               /* not reached */
1014 }
1015
1016 void
1017 mntscan(Mntwalk *mw, Proc *p)
1018 {
1019         Pgrp *pg;
1020         Mount *t;
1021         Mhead *f;
1022         int nxt, i;
1023         ulong last, bestmid;
1024
1025         pg = p->pgrp;
1026         rlock(&pg->ns);
1027
1028         nxt = 0;
1029         bestmid = ~0;
1030
1031         last = 0;
1032         if(mw->mh != nil)
1033                 last = mw->cm->mountid;
1034
1035         for(i = 0; i < MNTHASH; i++) {
1036                 for(f = pg->mnthash[i]; f != nil; f = f->hash) {
1037                         for(t = f->mount; t != nil; t = t->next) {
1038                                 if(mw->mh == nil ||
1039                                   (t->mountid > last && t->mountid < bestmid)) {
1040                                         mw->cm = t;
1041                                         mw->mh = f;
1042                                         bestmid = mw->cm->mountid;
1043                                         nxt = 1;
1044                                 }
1045                         }
1046                 }
1047         }
1048         if(nxt == 0)
1049                 mw->mh = nil;
1050
1051         runlock(&pg->ns);
1052 }
1053
1054 static long
1055 procwrite(Chan *c, void *va, long n, vlong off)
1056 {
1057         int id, m;
1058         Proc *p, *t, *et;
1059         char *a, *arg, buf[ERRMAX];
1060         ulong offset;
1061
1062         a = va;
1063         offset = off;
1064         if(c->qid.type & QTDIR)
1065                 error(Eisdir);
1066
1067         p = proctab(SLOT(c->qid));
1068
1069         /* Use the remembered noteid in the channel rather
1070          * than the process pgrpid
1071          */
1072         if(QID(c->qid) == Qnotepg) {
1073                 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1074                 return n;
1075         }
1076
1077         eqlock(&p->debug);
1078         if(waserror()){
1079                 qunlock(&p->debug);
1080                 nexterror();
1081         }
1082         if(p->pid != PID(c->qid))
1083                 error(Eprocdied);
1084
1085         switch(QID(c->qid)){
1086         case Qargs:
1087                 if(n == 0)
1088                         error(Eshort);
1089                 if(n >= ERRMAX)
1090                         error(Etoobig);
1091                 arg = malloc(n+1);
1092                 if(arg == nil)
1093                         error(Enomem);
1094                 memmove(arg, va, n);
1095                 m = n;
1096                 if(arg[m-1] != 0)
1097                         arg[m++] = 0;
1098                 free(p->args);
1099                 p->nargs = m;
1100                 p->args = arg;
1101                 p->setargs = 1;
1102                 break;
1103
1104         case Qmem:
1105                 if(p->state != Stopped)
1106                         error(Ebadctl);
1107                 n = procctlmemio(p, off2addr(off), n, va, 0);
1108                 break;
1109
1110         case Qregs:
1111                 if(offset >= sizeof(Ureg))
1112                         n = 0;
1113                 else if(offset+n > sizeof(Ureg))
1114                         n = sizeof(Ureg) - offset;
1115                 if(p->dbgreg == nil)
1116                         error(Enoreg);
1117                 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1118                 break;
1119
1120         case Qfpregs:
1121                 if(offset >= sizeof(FPsave))
1122                         n = 0;
1123                 else if(offset+n > sizeof(FPsave))
1124                         n = sizeof(FPsave) - offset;
1125                 memmove((uchar*)&p->fpsave+offset, va, n);
1126                 break;
1127
1128         case Qctl:
1129                 procctlreq(p, va, n);
1130                 break;
1131
1132         case Qnote:
1133                 if(p->kp)
1134                         error(Eperm);
1135                 if(n >= ERRMAX-1)
1136                         error(Etoobig);
1137                 memmove(buf, va, n);
1138                 buf[n] = 0;
1139                 if(!postnote(p, 0, buf, NUser))
1140                         error("note not posted");
1141                 break;
1142         case Qnoteid:
1143                 if(p->kp)
1144                         error(Eperm);
1145                 id = atoi(a);
1146                 if(id <= 0)
1147                         error(Ebadarg);
1148                 if(id == p->pid) {
1149                         p->noteid = id;
1150                         break;
1151                 }
1152                 t = proctab(0);
1153                 for(et = t+conf.nproc; t < et; t++) {
1154                         if(t->state == Dead || t->kp)
1155                                 continue;
1156                         if(id == t->noteid) {
1157                                 nonone(t);
1158                                 if(strcmp(p->user, t->user) != 0)
1159                                         error(Eperm);
1160                                 p->noteid = id;
1161                                 break;
1162                         }
1163                 }
1164                 if(p->noteid != id)
1165                         error(Ebadarg);
1166                 break;
1167         default:
1168                 print("unknown qid in procwrite\n");
1169                 error(Egreg);
1170         }
1171         poperror();
1172         qunlock(&p->debug);
1173         return n;
1174 }
1175
1176 Dev procdevtab = {
1177         'p',
1178         "proc",
1179
1180         devreset,
1181         procinit,
1182         devshutdown,
1183         procattach,
1184         procwalk,
1185         procstat,
1186         procopen,
1187         devcreate,
1188         procclose,
1189         procread,
1190         devbread,
1191         procwrite,
1192         devbwrite,
1193         devremove,
1194         procwstat,
1195 };
1196
1197 Chan*
1198 proctext(Chan *c, Proc *p)
1199 {
1200         Chan *tc;
1201         Image *i;
1202         Segment *s;
1203
1204         s = p->seg[TSEG];
1205         if(s == nil)
1206                 error(Enonexist);
1207         if(p->state==Dead)
1208                 error(Eprocdied);
1209
1210         i = s->image;
1211         if(i == nil)
1212                 error(Eprocdied);
1213
1214         lock(i);
1215         if(waserror()) {
1216                 unlock(i);
1217                 nexterror();
1218         }
1219
1220         if(i->s != s)
1221                 error(Eprocdied);
1222                 
1223         tc = i->c;
1224         if(tc == nil)
1225                 error(Eprocdied);
1226
1227         if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode != OREAD) {
1228                 cclose(tc);
1229                 error(Eprocdied);
1230         }
1231
1232         if(p->pid != PID(c->qid)) {
1233                 cclose(tc);
1234                 error(Eprocdied);
1235         }
1236
1237         unlock(i);
1238         poperror();
1239
1240         return tc;
1241 }
1242
1243 void
1244 procstopwait(Proc *p, int ctl)
1245 {
1246         int pid;
1247
1248         if(p->pdbg != nil)
1249                 error(Einuse);
1250         if(procstopped(p) || p->state == Broken)
1251                 return;
1252         pid = p->pid;
1253         if(pid == 0)
1254                 error(Eprocdied);
1255         if(ctl != 0)
1256                 p->procctl = ctl;
1257         p->pdbg = up;
1258         qunlock(&p->debug);
1259         up->psstate = "Stopwait";
1260         if(waserror()) {
1261                 p->pdbg = nil;
1262                 qlock(&p->debug);
1263                 nexterror();
1264         }
1265         sleep(&up->sleep, procstopped, p);
1266         poperror();
1267         qlock(&p->debug);
1268         if(p->pid != pid)
1269                 error(Eprocdied);
1270 }
1271
1272 void
1273 procctlclosefiles(Proc *p, int all, int fd)
1274 {
1275         Fgrp *f;
1276         Chan *c;
1277
1278         if(fd < 0)
1279                 error(Ebadfd);
1280         f = p->fgrp;
1281         if(f == nil)
1282                 error(Eprocdied);
1283
1284         incref(f);
1285         lock(f);
1286         while(fd <= f->maxfd){
1287                 c = f->fd[fd];
1288                 if(c != nil){
1289                         f->fd[fd] = nil;
1290                         unlock(f);
1291                         qunlock(&p->debug);
1292                         cclose(c);
1293                         qlock(&p->debug);
1294                         lock(f);
1295                 }
1296                 if(!all)
1297                         break;
1298                 fd++;
1299         }
1300         unlock(f);
1301         closefgrp(f);
1302 }
1303
1304 static char *
1305 parsetime(vlong *rt, char *s)
1306 {
1307         uvlong ticks;
1308         ulong l;
1309         char *e, *p;
1310         static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1311
1312         if (s == nil)
1313                 return("missing value");
1314         ticks=strtoul(s, &e, 10);
1315         if (*e == '.'){
1316                 p = e+1;
1317                 l = strtoul(p, &e, 10);
1318                 if(e-p > nelem(p10))
1319                         return "too many digits after decimal point";
1320                 if(e-p == 0)
1321                         return "ill-formed number";
1322                 l *= p10[e-p-1];
1323         }else
1324                 l = 0;
1325         if (*e == '\0' || strcmp(e, "s") == 0){
1326                 ticks = 1000000000 * ticks + l;
1327         }else if (strcmp(e, "ms") == 0){
1328                 ticks = 1000000 * ticks + l/1000;
1329         }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1330                 ticks = 1000 * ticks + l/1000000;
1331         }else if (strcmp(e, "ns") != 0)
1332                 return "unrecognized unit";
1333         *rt = ticks;
1334         return nil;
1335 }
1336
1337 void
1338 procctlreq(Proc *p, char *va, int n)
1339 {
1340         Segment *s;
1341         int npc, pri;
1342         Cmdbuf *cb;
1343         Cmdtab *ct;
1344         vlong time;
1345         char *e;
1346         void (*pt)(Proc*, int, vlong);
1347
1348         if(p->kp)       /* no ctl requests to kprocs */
1349                 error(Eperm);
1350
1351         cb = parsecmd(va, n);
1352         if(waserror()){
1353                 free(cb);
1354                 nexterror();
1355         }
1356
1357         ct = lookupcmd(cb, proccmd, nelem(proccmd));
1358
1359         switch(ct->index){
1360         case CMclose:
1361                 procctlclosefiles(p, 0, atoi(cb->f[1]));
1362                 break;
1363         case CMclosefiles:
1364                 procctlclosefiles(p, 1, 0);
1365                 break;
1366         case CMhang:
1367                 p->hang = 1;
1368                 break;
1369         case CMkill:
1370                 switch(p->state) {
1371                 case Broken:
1372                         unbreak(p);
1373                         break;
1374                 case Stopped:
1375                         p->procctl = Proc_exitme;
1376                         postnote(p, 0, "sys: killed", NExit);
1377                         ready(p);
1378                         break;
1379                 default:
1380                         p->procctl = Proc_exitme;
1381                         postnote(p, 0, "sys: killed", NExit);
1382                 }
1383                 break;
1384         case CMnohang:
1385                 p->hang = 0;
1386                 break;
1387         case CMnoswap:
1388                 p->noswap = 1;
1389                 break;
1390         case CMpri:
1391                 pri = atoi(cb->f[1]);
1392                 if(pri > PriNormal && !iseve())
1393                         error(Eperm);
1394                 procpriority(p, pri, 0);
1395                 break;
1396         case CMfixedpri:
1397                 pri = atoi(cb->f[1]);
1398                 if(pri > PriNormal && !iseve())
1399                         error(Eperm);
1400                 procpriority(p, pri, 1);
1401                 break;
1402         case CMprivate:
1403                 p->privatemem = 1;
1404                 break;
1405         case CMprofile:
1406                 s = p->seg[TSEG];
1407                 if(s == nil || (s->type&SG_TYPE) != SG_TEXT)
1408                         error(Ebadctl);
1409                 if(s->profile != nil)
1410                         free(s->profile);
1411                 npc = (s->top-s->base)>>LRESPROF;
1412                 s->profile = malloc(npc*sizeof(*s->profile));
1413                 if(s->profile == nil)
1414                         error(Enomem);
1415                 break;
1416         case CMstart:
1417                 if(p->state != Stopped)
1418                         error(Ebadctl);
1419                 ready(p);
1420                 break;
1421         case CMstartstop:
1422                 if(p->state != Stopped)
1423                         error(Ebadctl);
1424                 p->procctl = Proc_traceme;
1425                 ready(p);
1426                 procstopwait(p, Proc_traceme);
1427                 break;
1428         case CMstartsyscall:
1429                 if(p->state != Stopped)
1430                         error(Ebadctl);
1431                 p->procctl = Proc_tracesyscall;
1432                 ready(p);
1433                 procstopwait(p, Proc_tracesyscall);
1434                 break;
1435         case CMstop:
1436                 procstopwait(p, Proc_stopme);
1437                 break;
1438         case CMwaitstop:
1439                 procstopwait(p, 0);
1440                 break;
1441         case CMwired:
1442                 procwired(p, atoi(cb->f[1]));
1443                 break;
1444         case CMtrace:
1445                 switch(cb->nf){
1446                 case 1:
1447                         p->trace ^= 1;
1448                         break;
1449                 case 2:
1450                         p->trace = (atoi(cb->f[1]) != 0);
1451                         break;
1452                 default:
1453                         error("args");
1454                 }
1455                 break;
1456         case CMinterrupt:
1457                 postnote(p, 0, nil, NUser);
1458                 break;
1459         case CMnointerrupt:
1460                 if(p->nnote == 0)
1461                         p->notepending = 0;
1462                 else
1463                         error("notes pending");
1464                 break;
1465         /* real time */
1466         case CMperiod:
1467                 if(p->edf == nil)
1468                         edfinit(p);
1469                 if(e=parsetime(&time, cb->f[1]))        /* time in ns */
1470                         error(e);
1471                 edfstop(p);
1472                 p->edf->T = time/1000;  /* Edf times are in µs */
1473                 break;
1474         case CMdeadline:
1475                 if(p->edf == nil)
1476                         edfinit(p);
1477                 if(e=parsetime(&time, cb->f[1]))
1478                         error(e);
1479                 edfstop(p);
1480                 p->edf->D = time/1000;
1481                 break;
1482         case CMcost:
1483                 if(p->edf == nil)
1484                         edfinit(p);
1485                 if(e=parsetime(&time, cb->f[1]))
1486                         error(e);
1487                 edfstop(p);
1488                 p->edf->C = time/1000;
1489                 break;
1490         case CMsporadic:
1491                 if(p->edf == nil)
1492                         edfinit(p);
1493                 p->edf->flags |= Sporadic;
1494                 break;
1495         case CMdeadlinenotes:
1496                 if(p->edf == nil)
1497                         edfinit(p);
1498                 p->edf->flags |= Sendnotes;
1499                 break;
1500         case CMadmit:
1501                 if(p->edf == nil)
1502                         error("edf params");
1503                 if(e = edfadmit(p))
1504                         error(e);
1505                 break;
1506         case CMextra:
1507                 if(p->edf == nil)
1508                         edfinit(p);
1509                 p->edf->flags |= Extratime;
1510                 break;
1511         case CMexpel:
1512                 if(p->edf != nil)
1513                         edfstop(p);
1514                 break;
1515         case CMevent:
1516                 pt = proctrace;
1517                 if(up->trace && pt != nil)
1518                         pt(up, SUser, 0);
1519                 break;
1520         }
1521
1522         poperror();
1523         free(cb);
1524 }
1525
1526 int
1527 procstopped(void *a)
1528 {
1529         return ((Proc*)a)->state == Stopped;
1530 }
1531
1532 int
1533 procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
1534 {
1535         KMap *k;
1536         Pte *pte;
1537         Page *pg;
1538         Segment *s;
1539         uintptr soff;
1540         char *a, *b;
1541         int i, l;
1542
1543         /* Only one page at a time */
1544         l = BY2PG - (offset&(BY2PG-1));
1545         if(n > l)
1546                 n = l;
1547
1548         /*
1549          * Make temporary copy to avoid fault while we have
1550          * segment locked as we would deadlock when trying
1551          * to read the calling procs memory.
1552          */
1553         a = malloc(n);
1554         if(a == nil)
1555                 error(Enomem);
1556         if(waserror()) {
1557                 free(a);
1558                 nexterror();
1559         }
1560
1561         if(!read)
1562                 memmove(a, va, n);      /* can fault */
1563
1564         for(;;) {
1565                 s = seg(p, offset, 0);
1566                 if(s == nil)
1567                         error(Ebadarg);
1568
1569                 eqlock(&p->seglock);
1570                 if(waserror()) {
1571                         qunlock(&p->seglock);
1572                         nexterror();
1573                 }
1574
1575                 for(i = 0; i < NSEG; i++) {
1576                         if(p->seg[i] == s)
1577                                 break;
1578                 }
1579                 if(i == NSEG)
1580                         error(Egreg);   /* segment gone */
1581
1582                 eqlock(s);
1583                 if(waserror()){
1584                         qunlock(s);
1585                         nexterror();
1586                 }
1587                 if(!read && (s->type&SG_TYPE) == SG_TEXT) {
1588                         s = txt2data(s);
1589                         p->seg[i] = s;
1590                 }
1591                 incref(s);
1592                 qunlock(&p->seglock);
1593                 poperror();
1594                 poperror();
1595                 /* segment s still locked, fixfault() unlocks */
1596                 if(waserror()){
1597                         putseg(s);
1598                         nexterror();
1599                 }
1600                 if(fixfault(s, offset, read, 0) == 0)
1601                         break;
1602                 putseg(s);
1603                 poperror();
1604         }
1605
1606         /*
1607          * Only access the page while segment is locked
1608          * as the proc could segfree or relocate the pte
1609          * concurrently.
1610          */ 
1611         eqlock(s);
1612         if(waserror()){
1613                 qunlock(s);
1614                 nexterror();
1615         }
1616         if(offset+n >= s->top)
1617                 n = s->top-offset;
1618         soff = offset-s->base;
1619         pte = s->map[soff/PTEMAPMEM];
1620         if(pte == nil)
1621                 error(Egreg);   /* page gone, should retry? */
1622         pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1623         if(pagedout(pg))
1624                 error(Egreg);   /* page gone, should retry?  */
1625
1626         /* Map and copy the page */
1627         k = kmap(pg);
1628         b = (char*)VA(k);
1629         b += offset&(BY2PG-1);
1630         if(read)
1631                 memmove(a, b, n);
1632         else
1633                 memmove(b, a, n);
1634         kunmap(k);
1635
1636         /* Ensure the process sees text page changes */
1637         if(s->flushme)
1638                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1639
1640         if(!read)
1641                 p->newtlb = 1;
1642
1643         qunlock(s);
1644         poperror();
1645         putseg(s);
1646         poperror();
1647
1648         if(read)
1649                 memmove(va, a, n);      /* can fault */
1650
1651         free(a);
1652         poperror();
1653
1654         return n;
1655 }