#include "ureg.h"
#include "edf.h"
+#include <pool.h>
+
enum
{
Qdir,
};
/* Segment type from portdat.h */
-static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
+static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", };
/*
* Qids are, in path:
#define NOTEID(q) ((q).vers)
void procctlreq(Proc*, char*, int);
-int procctlmemio(Proc*, uintptr, int, void*, int);
+long procctlmemio(Chan*, Proc*, uintptr, void*, long, int);
Chan* proctext(Chan*, Proc*);
int procstopped(void*);
-void mntscan(Mntwalk*, Proc*);
ulong procpagecount(Proc *);
static Traceevent *tevents;
static int tproduced, tconsumed;
void (*proctrace)(Proc*, int, vlong);
-extern int unfair;
-
static void
profclock(Ureg *ur, Timer *)
{
Tos *tos;
- if(up == 0 || up->state != Running)
+ if(up == nil || up->state != Running)
return;
/* user profiling clock */
case Qkregs:
case Qsegment:
case Qprofile:
+ case Qns:
case Qfd:
if(omode != OREAD)
error(Eperm);
nonone(p);
break;
- case Qns:
- if(omode != OREAD)
- error(Eperm);
- c->aux = smalloc(sizeof(Mntwalk));
- break;
-
case Qnotepg:
nonone(p);
pg = p->pgrp;
if(p->pid != PID(c->qid))
error(Eprocdied);
- if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
+ if(strcmp(up->user, p->user) != 0 && !iseve())
error(Eperm);
d = smalloc(sizeof(Dir)+n);
if(n == 0)
error(Eshortstat);
if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
- if(strcmp(up->user, eve) != 0)
+ if(!iseve())
error(Eperm);
- else
- kstrdup(&p->user, d->uid);
+ kstrdup(&p->user, d->uid);
}
/* p->procmode determines default mode for files in /proc */
if(d->mode != ~0UL)
return n;
}
-
-static long
-procoffset(long offset, char *va, int *np)
-{
- if(offset > 0) {
- offset -= *np;
- if(offset < 0) {
- memmove(va, va+*np+offset, -offset);
- *np = -offset;
- }
- else
- *np = 0;
- }
- return offset;
-}
-
-static int
-procqidwidth(Chan *c)
-{
- char buf[32];
-
- return sprint(buf, "%lud", c->qid.vers);
-}
-
-int
-procfdprint(Chan *c, int fd, int w, char *s, int ns)
-{
- int n;
-
- if(w == 0)
- w = procqidwidth(c);
- n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
- fd,
- &"r w rw"[(c->mode&3)<<1],
- devtab[c->type]->dc, c->dev,
- c->qid.path, w, c->qid.vers, c->qid.type,
- c->iounit, c->offset, c->path->s);
- return n;
-}
-
-static int
-procfds(Proc *p, char *va, int count, long offset)
-{
- Fgrp *f;
- Chan *c;
- char buf[256];
- int n, i, w, ww;
- char *a;
-
- /* print to buf to avoid holding fgrp lock while writing to user space */
- if(count > sizeof buf)
- count = sizeof buf;
- a = buf;
-
- eqlock(&p->debug);
- f = p->fgrp;
- if(f == nil || p->dot == nil){
- qunlock(&p->debug);
- return 0;
- }
- lock(f);
- if(waserror()){
- unlock(f);
- qunlock(&p->debug);
- nexterror();
- }
-
- n = readstr(0, a, count, p->dot->path->s);
- n += snprint(a+n, count-n, "\n");
- offset = procoffset(offset, a, &n);
- /* compute width of qid.path */
- w = 0;
- for(i = 0; i <= f->maxfd; i++) {
- c = f->fd[i];
- if(c == nil)
- continue;
- ww = procqidwidth(c);
- if(ww > w)
- w = ww;
- }
- for(i = 0; i <= f->maxfd; i++) {
- c = f->fd[i];
- if(c == nil)
- continue;
- n += procfdprint(c, i, w, a+n, count-n);
- offset = procoffset(offset, a, &n);
- }
- unlock(f);
- qunlock(&p->debug);
- poperror();
-
- /* copy result to user space, now that locks are released */
- memmove(va, buf, n);
-
- return n;
-}
-
static void
procclose(Chan *c)
{
- if(QID(c->qid) == Qtrace && (c->flag & COPEN) != 0){
+ Segio *sio;
+
+ if((c->flag & COPEN) == 0)
+ return;
+
+ switch(QID(c->qid)){
+ case Qtrace:
lock(&tlock);
if(topens > 0)
topens--;
if(topens == 0)
proctrace = nil;
unlock(&tlock);
- }
- if(QID(c->qid) == Qns && c->aux != 0){
- free(c->aux);
- c->aux = 0;
- }
-}
-
-static void
-int2flag(int flag, char *s)
-{
- if(flag == 0){
- *s = '\0';
+ return;
+ case Qmem:
+ sio = c->aux;
+ if(sio != nil){
+ c->aux = nil;
+ segio(sio, nil, nil, 0, 0, 0);
+ free(sio);
+ }
return;
}
- *s++ = '-';
- if(flag & MAFTER)
- *s++ = 'a';
- if(flag & MBEFORE)
- *s++ = 'b';
- if(flag & MCREATE)
- *s++ = 'c';
- if(flag & MCACHE)
- *s++ = 'C';
- *s = '\0';
}
static int
c = (Chan *)x;
p = proctab(SLOT(c->qid));
- return p->pid != PID(c->qid) || p->waitq != 0;
+ return p->pid != PID(c->qid) || p->waitq != nil;
+}
+
+static void
+int2flag(int flag, char *s)
+{
+ if(flag == 0){
+ *s = '\0';
+ return;
+ }
+ *s++ = '-';
+ if(flag & MAFTER)
+ *s++ = 'a';
+ if(flag & MBEFORE)
+ *s++ = 'b';
+ if(flag & MCREATE)
+ *s++ = 'c';
+ if(flag & MCACHE)
+ *s++ = 'C';
+ *s = '\0';
+}
+
+static int
+readns1(Chan *c, Proc *p, char *buf, int nbuf)
+{
+ Pgrp *pg;
+ Mount *t, *cm;
+ Mhead *f, *mh;
+ ulong minid, bestmid;
+ char flag[10], *srv;
+ int i;
+
+ pg = p->pgrp;
+ if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
+ error(Eprocdied);
+
+ bestmid = ~0;
+ minid = c->nrock;
+ if(minid == bestmid)
+ return 0;
+
+ rlock(&pg->ns);
+
+ mh = nil;
+ cm = nil;
+ for(i = 0; i < MNTHASH; i++) {
+ for(f = pg->mnthash[i]; f != nil; f = f->hash) {
+ for(t = f->mount; t != nil; t = t->next) {
+ if(t->mountid >= minid && t->mountid < bestmid) {
+ bestmid = t->mountid;
+ cm = t;
+ mh = f;
+ }
+ }
+ }
+ }
+
+ if(bestmid == ~0) {
+ c->nrock = bestmid;
+ i = snprint(buf, nbuf, "cd %s\n", p->dot->path->s);
+ } else {
+ c->nrock = bestmid+1;
+
+ int2flag(cm->mflag, flag);
+ if(strcmp(cm->to->path->s, "#M") == 0){
+ srv = srvname(cm->to->mchan);
+ i = snprint(buf, nbuf, "mount %s %s %s %s\n", flag,
+ srv==nil? cm->to->mchan->path->s : srv,
+ mh->from->path->s, cm->spec? cm->spec : "");
+ free(srv);
+ }else{
+ i = snprint(buf, nbuf, "bind %s %s %s\n", flag,
+ cm->to->path->s, mh->from->path->s);
+ }
+ }
+
+ runlock(&pg->ns);
+
+ return i;
+}
+
+int
+procfdprint(Chan *c, int fd, char *s, int ns)
+{
+ return snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %lud %.2ux) %5ld %8lld %s\n",
+ fd,
+ &"r w rw"[(c->mode&3)<<1],
+ devtab[c->type]->dc, c->dev,
+ c->qid.path, c->qid.vers, c->qid.type,
+ c->iounit, c->offset, c->path->s);
+}
+
+static int
+readfd1(Chan *c, Proc *p, char *buf, int nbuf)
+{
+ Fgrp *fg;
+ int n, i;
+
+ fg = p->fgrp;
+ if(fg == nil || p->dot == nil || p->pid != PID(c->qid))
+ return 0;
+
+ if(c->nrock == 0){
+ c->nrock = 1;
+ return snprint(buf, nbuf, "%s\n", p->dot->path->s);
+ }
+
+ lock(fg);
+ n = 0;
+ for(;;){
+ i = c->nrock-1;
+ if(i < 0 || i > fg->maxfd)
+ break;
+ c->nrock++;
+ if(fg->fd[i] != nil){
+ n = procfdprint(fg->fd[i], i, buf, nbuf);
+ break;
+ }
+ }
+ unlock(fg);
+
+ return n;
}
/*
static long
procread(Chan *c, void *va, long n, vlong off)
{
- /* NSEG*32 was too small for worst cases */
- char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
- int i, j, m, navail, ne, rsize;
- long l;
+ char *a, *sps, statbuf[1024];
+ int i, j, navail, ne, rsize;
+ ulong l;
uchar *rptr;
uintptr addr;
ulong offset;
Confmem *cm;
- Mntwalk *mw;
Proc *p;
Segment *sg, *s;
Ureg kur;
switch(QID(c->qid)){
case Qargs:
eqlock(&p->debug);
- j = procargs(p, up->genbuf, sizeof up->genbuf);
+ j = procargs(p, statbuf, sizeof(statbuf));
qunlock(&p->debug);
if(offset >= j)
return 0;
if(offset+n > j)
n = j-offset;
- memmove(a, &up->genbuf[offset], n);
+ statbufread:
+ memmove(a, statbuf+offset, n);
return n;
+
case Qsyscall:
eqlock(&p->debug);
- if(p->syscalltrace)
- n = readstr(offset, a, n, p->syscalltrace);
- else
- n = 0;
+ if(waserror()){
+ qunlock(&p->debug);
+ nexterror();
+ }
+ if(p->pid != PID(c->qid))
+ error(Eprocdied);
+ j = 0;
+ if(p->syscalltrace != nil)
+ j = readstr(offset, a, n, p->syscalltrace);
qunlock(&p->debug);
- return n;
+ poperror();
+ return j;
case Qmem:
addr = off2addr(off);
if(addr < KZERO)
- return procctlmemio(p, addr, n, va, 1);
+ return procctlmemio(c, p, addr, va, n, 1);
- if(!iseve())
+ if(!iseve() || poolisoverlap(secrmem, (uchar*)addr, n))
error(Eperm);
/* validate kernel addresses */
if(s == nil || s->profile == nil)
error("profile is off");
i = (s->top-s->base)>>LRESPROF;
- i *= sizeof(*s->profile);
- if(offset >= i)
+ i *= sizeof(s->profile[0]);
+ if(i < 0 || offset >= i)
return 0;
if(offset+n > i)
n = i - offset;
if(p->nnote == 0)
n = 0;
else {
- m = strlen(p->note[0].msg) + 1;
- if(m > n)
- m = n;
- memmove(va, p->note[0].msg, m-1);
- ((char*)va)[m-1] = '\0';
- p->nnote--;
+ i = strlen(p->note[0].msg) + 1;
+ if(i < n)
+ n = i;
+ memmove(a, p->note[0].msg, n-1);
+ a[n-1] = '\0';
+ if(--p->nnote == 0)
+ p->notepending = 0;
memmove(p->note, p->note+1, p->nnote*sizeof(Note));
- n = m;
}
- if(p->nnote == 0)
- p->notepending = 0;
poperror();
qunlock(&p->debug);
return n;
rptr = (uchar*)&p->fpsave;
rsize = sizeof(FPsave);
regread:
- if(rptr == 0)
+ if(rptr == nil)
error(Enoreg);
if(offset >= rsize)
return 0;
n = STATSIZE - offset;
sps = p->psstate;
- if(sps == 0)
+ if(sps == nil)
sps = statename[p->state];
memset(statbuf, ' ', sizeof statbuf);
l = p->time[i];
if(i == TReal)
l = MACHP(0)->ticks - l;
- l = TK2MS(l);
- readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
+ readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, tk2ms(l), NUMSIZE);
}
readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, procpagecount(p)*BY2PG/1024, NUMSIZE);
readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
- memmove(a, statbuf+offset, n);
- return n;
+ goto statbufread;
case Qsegment:
j = 0;
for(i = 0; i < NSEG; i++) {
sg = p->seg[i];
- if(sg == 0)
+ if(sg == nil)
continue;
j += sprint(statbuf+j, "%-6s %c%c %8p %8p %4ld\n",
sname[sg->type&SG_TYPE],
return 0;
if(offset+n > j)
n = j-offset;
- if(n == 0 && offset == 0)
- exhausted("segments");
- memmove(a, &statbuf[offset], n);
- return n;
+ goto statbufread;
case Qwait:
if(!canqlock(&p->qwaitr))
}
lock(&p->exl);
- while(p->waitq == 0 && p->pid == PID(c->qid)) {
+ while(p->waitq == nil && p->pid == PID(c->qid)) {
if(up == p && p->nchild == 0) {
unlock(&p->exl);
error(Enochild);
qunlock(&p->qwaitr);
poperror();
- n = snprint(a, n, "%d %lud %lud %lud %q",
+
+ j = snprint(statbuf, sizeof(statbuf), "%d %lud %lud %lud %q",
wq->w.pid,
wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
wq->w.msg);
free(wq);
- return n;
+ if(j < n)
+ n = j;
+ offset = 0;
+ goto statbufread;
case Qns:
+ case Qfd:
eqlock(&p->debug);
if(waserror()){
qunlock(&p->debug);
nexterror();
}
- if(p->pgrp == nil || p->dot == nil || p->pid != PID(c->qid))
- error(Eprocdied);
- mw = c->aux;
- if(mw->cddone){
- qunlock(&p->debug);
- poperror();
- return 0;
- }
- mntscan(mw, p);
- if(mw->mh == 0){
- mw->cddone = 1;
- i = snprint(a, n, "cd %s\n", p->dot->path->s);
- qunlock(&p->debug);
- poperror();
- return i;
- }
- int2flag(mw->cm->mflag, flag);
- if(strcmp(mw->cm->to->path->s, "#M") == 0){
- srv = srvname(mw->cm->to->mchan);
- i = snprint(a, n, "mount %s %s %s %s\n", flag,
- srv==nil? mw->cm->to->mchan->path->s : srv,
- mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
- free(srv);
- }else
- i = snprint(a, n, "bind %s %s %s\n", flag,
- mw->cm->to->path->s, mw->mh->from->path->s);
+ if(offset == 0 || offset != c->mrock)
+ c->nrock = c->mrock = 0;
+ do {
+ if(QID(c->qid) == Qns)
+ j = readns1(c, p, statbuf, sizeof(statbuf));
+ else
+ j = readfd1(c, p, statbuf, sizeof(statbuf));
+ if(j == 0)
+ break;
+ c->mrock += j;
+ } while(c->mrock <= offset);
+ i = c->mrock - offset;
qunlock(&p->debug);
poperror();
- return i;
+
+ if(i <= 0 || i > j)
+ return 0;
+ if(i < n)
+ n = i;
+ offset = j - i;
+ goto statbufread;
case Qnoteid:
return readnum(offset, va, n, p->noteid, NUMSIZE);
+
case Qppid:
return readnum(offset, va, n, p->parentpid, NUMSIZE);
- case Qfd:
- return procfds(p, va, n, offset);
+
}
error(Egreg);
return 0; /* not reached */
}
-void
-mntscan(Mntwalk *mw, Proc *p)
-{
- Pgrp *pg;
- Mount *t;
- Mhead *f;
- int nxt, i;
- ulong last, bestmid;
-
- pg = p->pgrp;
- rlock(&pg->ns);
-
- nxt = 0;
- bestmid = ~0;
-
- last = 0;
- if(mw->mh)
- last = mw->cm->mountid;
-
- for(i = 0; i < MNTHASH; i++) {
- for(f = pg->mnthash[i]; f; f = f->hash) {
- for(t = f->mount; t; t = t->next) {
- if(mw->mh == 0 ||
- (t->mountid > last && t->mountid < bestmid)) {
- mw->cm = t;
- mw->mh = f;
- bestmid = mw->cm->mountid;
- nxt = 1;
- }
- }
- }
- }
- if(nxt == 0)
- mw->mh = 0;
-
- runlock(&pg->ns);
-}
-
static long
procwrite(Chan *c, void *va, long n, vlong off)
{
case Qmem:
if(p->state != Stopped)
error(Ebadctl);
- n = procctlmemio(p, off2addr(off), n, va, 0);
+ n = procctlmemio(c, p, off2addr(off), va, n, 0);
break;
case Qregs:
n = 0;
else if(offset+n > sizeof(Ureg))
n = sizeof(Ureg) - offset;
- if(p->dbgreg == 0)
+ if(p->dbgreg == nil)
error(Enoreg);
setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
break;
unlock(i);
nexterror();
}
-
- if(i->s != s)
- error(Eprocdied);
tc = i->c;
if(tc == nil)
error(Eprocdied);
- if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
+ if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode != OREAD) {
cclose(tc);
error(Eprocdied);
}
{
int pid;
- if(p->pdbg)
+ if(p->pdbg != nil)
error(Einuse);
if(procstopped(p) || p->state == Broken)
return;
qunlock(&p->debug);
up->psstate = "Stopwait";
if(waserror()) {
- p->pdbg = 0;
qlock(&p->debug);
+ p->pdbg = nil;
nexterror();
}
sleep(&up->sleep, procstopped, p);
break;
case CMprofile:
s = p->seg[TSEG];
- if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
+ if(s == nil || (s->type&SG_TYPE) != SG_TEXT)
error(Ebadctl);
if(s->profile != nil)
free(s->profile);
p->edf->flags |= Sendnotes;
break;
case CMadmit:
- if(p->edf == 0)
+ if(p->edf == nil)
error("edf params");
if(e = edfadmit(p))
error(e);
p->edf->flags |= Extratime;
break;
case CMexpel:
- if(p->edf)
+ if(p->edf != nil)
edfstop(p);
break;
case CMevent:
pt = proctrace;
- if(up->trace && pt)
+ if(up->trace && pt != nil)
pt(up, SUser, 0);
break;
}
int
procstopped(void *a)
{
- Proc *p = a;
- return p->state == Stopped;
+ return ((Proc*)a)->state == Stopped;
}
-ulong
-procpagecount(Proc *p)
+long
+procctlmemio(Chan *c, Proc *p, uintptr offset, void *a, long n, int read)
{
+ Segio *sio;
Segment *s;
- ulong pages;
int i;
+ s = seg(p, offset, 0);
+ if(s == nil)
+ error(Ebadarg);
eqlock(&p->seglock);
- if(waserror()){
+ if(waserror()) {
qunlock(&p->seglock);
nexterror();
}
- pages = 0;
- for(i=0; i<NSEG; i++){
- if((s = p->seg[i]) != nil){
- eqlock(s);
- pages += mcountseg(s);
- qunlock(s);
- }
- }
- qunlock(&p->seglock);
- poperror();
-
- return pages;
-}
-
-int
-procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
-{
- KMap *k;
- Pte *pte;
- Page *pg;
- Segment *s;
- uintptr soff;
- char *a, *b;
- int i, l;
-
- /* Only one page at a time */
- l = BY2PG - (offset&(BY2PG-1));
- if(n > l)
- n = l;
-
- /*
- * Make temporary copy to avoid fault while we have
- * segment locked as we would deadlock when trying
- * to read the calling procs memory.
- */
- a = malloc(n);
- if(a == nil)
- error(Enomem);
- if(waserror()) {
- free(a);
- nexterror();
+ sio = c->aux;
+ if(sio == nil){
+ sio = smalloc(sizeof(Segio));
+ c->aux = sio;
}
-
- if(!read)
- memmove(a, va, n); /* can fault */
-
- for(;;) {
- s = seg(p, offset, 0);
- if(s == nil)
- error(Ebadarg);
-
- eqlock(&p->seglock);
- if(waserror()) {
- qunlock(&p->seglock);
- nexterror();
- }
-
- for(i = 0; i < NSEG; i++) {
- if(p->seg[i] == s)
- break;
- }
- if(i == NSEG)
- error(Egreg); /* segment gone */
-
- eqlock(s);
- if(waserror()){
- qunlock(s);
- nexterror();
- }
- if(!read && (s->type&SG_TYPE) == SG_TEXT) {
- s = txt2data(s);
- p->seg[i] = s;
- }
- incref(s);
- qunlock(&p->seglock);
- poperror();
- poperror();
- /* segment s still locked, fixfault() unlocks */
- if(!waserror()){
- if(fixfault(s, offset, read, 0) == 0)
- break;
- poperror();
- }
- putseg(s);
+ for(i = 0; i < NSEG; i++) {
+ if(p->seg[i] == s)
+ break;
}
-
- /*
- * Only access the page while segment is locked
- * as the proc could segfree or relocate the pte
- * concurrently.
- */
+ if(i == NSEG)
+ error(Egreg); /* segment gone */
eqlock(s);
if(waserror()){
qunlock(s);
nexterror();
}
- if(offset+n >= s->top)
- n = s->top-offset;
- soff = offset-s->base;
- pte = s->map[soff/PTEMAPMEM];
- if(pte == nil)
- error(Egreg); /* page gone, should retry? */
- pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
- if(pagedout(pg))
- error(Egreg); /* page gone, should retry? */
-
- /* Map and copy the page */
- k = kmap(pg);
- b = (char*)VA(k);
- b += offset&(BY2PG-1);
- if(read)
- memmove(a, b, n);
- else
- memmove(b, a, n);
- kunmap(k);
-
- /* Ensure the process sees text page changes */
- if(s->flushme)
- memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
-
- if(!read)
- p->newtlb = 1;
-
+ if(!read && (s->type&SG_TYPE) == SG_TEXT) {
+ s = txt2data(s);
+ p->seg[i] = s;
+ }
+ offset -= s->base;
+ incref(s); /* for us while we copy */
qunlock(s);
poperror();
- putseg(s);
+ qunlock(&p->seglock);
poperror();
- if(read)
- memmove(va, a, n); /* can fault */
-
- free(a);
+ if(waserror()) {
+ putseg(s);
+ nexterror();
+ }
+ n = segio(sio, s, a, n, offset, read);
+ putseg(s);
poperror();
+ if(!read)
+ p->newtlb = 1;
+
return n;
}