diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-07-14 06:02:21 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-07-14 06:02:21 +0200 |
commit | 655ec332a714d3e5cc6aace798daf832e17e001e (patch) | |
tree | 90234eaf806722bf1fc54b298226128ce50f2b91 /sys/src/9/port/fault.c | |
parent | e53511ef4c7d4db443543506e74e4de537da5475 (diff) |
devproc: fix proccrlmemio bugs
dont kill the calling process when demand load fails if fixfault()
is called from devproc. this happens when you delete the binary
of a running process and try to debug the process accessing uncached
pages thru /proc/$pid/mem file.
fixes to procctlmemio():
- fix missed unlock as txt2data() can error
- make sure the segment isnt freed by taking a reference (under p->seglock)
- access the page with segment locked (see comment)
- get rid of the segment stealer lock
other stuff:
- move txt2data() and data2txt() to segment.c
- add procpagecount() function
- make return type mcounseg() to ulong
Diffstat (limited to 'sys/src/9/port/fault.c')
-rw-r--r-- | sys/src/9/port/fault.c | 238 |
1 files changed, 119 insertions, 119 deletions
diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c index 54824e8ba..0fd6b2e97 100644 --- a/sys/src/9/port/fault.c +++ b/sys/src/9/port/fault.c @@ -58,7 +58,7 @@ fault(uintptr addr, int read) } static void -faulterror(char *s, Chan *c, int freemem) +faulterror(char *s, Chan *c, int isfatal) { char buf[ERRMAX]; @@ -67,123 +67,15 @@ faulterror(char *s, Chan *c, int freemem) s = buf; } if(up->nerrlab) { - postnote(up, 1, s, NDebug); + if(isfatal) + postnote(up, 1, s, NDebug); error(s); } - pexit(s, freemem); + pexit(s, 1); } -void (*checkaddr)(uintptr, Segment *, Page *); -uintptr addr2check; - -int -fixfault(Segment *s, uintptr addr, int read, int doputmmu) -{ - int type; - Pte **p, *etp; - uintptr soff, mmuphys=0; - Page **pg, *old, *new; - Page *(*fn)(Segment*, uintptr); - - addr &= ~(BY2PG-1); - soff = addr-s->base; - p = &s->map[soff/PTEMAPMEM]; - if(*p == nil) - *p = ptealloc(); - - etp = *p; - pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG]; - type = s->type&SG_TYPE; - - if(pg < etp->first) - etp->first = pg; - if(pg > etp->last) - etp->last = pg; - - switch(type) { - default: - panic("fault"); - break; - - case SG_TEXT: /* Demand load */ - if(pagedout(*pg)) - pio(s, addr, soff, pg); - - mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; - (*pg)->modref = PG_REF; - break; - - case SG_BSS: - case SG_SHARED: /* Zero fill on demand */ - case SG_STACK: - if(*pg == nil) { - new = newpage(1, &s, addr); - if(s == nil) - return -1; - *pg = new; - } - goto common; - - case SG_DATA: - common: /* Demand load/pagein/copy on write */ - if(pagedout(*pg)) - pio(s, addr, soff, pg); - - /* - * It's only possible to copy on write if - * we're the only user of the segment. - */ - if(read && conf.copymode == 0 && s->ref == 1) { - mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID; - (*pg)->modref |= PG_REF; - break; - } - - old = *pg; - if(old->image == &swapimage && (old->ref + swapcount(old->daddr)) == 1) - uncachepage(old); - if(old->ref > 1 || old->image != nil) { - new = newpage(0, &s, addr); - if(s == nil) - return -1; - *pg = new; - copypage(old, *pg); - putpage(old); - } - mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID; - (*pg)->modref = PG_MOD|PG_REF; - break; - - case SG_PHYSICAL: - if(*pg == nil) { - fn = s->pseg->pgalloc; - if(fn) - *pg = (*fn)(s, addr); - else { - new = smalloc(sizeof(Page)); - new->va = addr; - new->pa = s->pseg->pa+(addr-s->base); - new->ref = 1; - *pg = new; - } - } - - if (checkaddr && addr == addr2check) - (*checkaddr)(addr, s, *pg); - mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID; - (*pg)->modref = PG_MOD|PG_REF; - break; - } - qunlock(s); - - if(doputmmu) - putmmu(addr, mmuphys, *pg); - - return 0; -} - -void -pio(Segment *s, uintptr addr, uintptr soff, Page **p) +static void +pio(Segment *s, uintptr addr, uintptr soff, Page **p, int isfatal) { Page *new; KMap *k; @@ -227,22 +119,21 @@ retry: new = newpage(0, 0, addr); k = kmap(new); kaddr = (char*)VA(k); - while(waserror()) { - if(strcmp(up->errstr, Eintr) == 0) + if(isfatal && strcmp(up->errstr, Eintr) == 0) continue; kunmap(k); putpage(new); - faulterror(Eioload, c, 0); + faulterror(Eioload, c, isfatal); } n = devtab[c->type]->read(c, kaddr, ask, daddr); if(n != ask) - error(Eioload); + error(Eshort); if(ask < BY2PG) memset(kaddr+ask, 0, BY2PG-ask); - poperror(); kunmap(k); + qlock(s); if(loadrec == nil) { /* This is demand load */ /* @@ -299,6 +190,115 @@ done: memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl)); } +void (*checkaddr)(uintptr, Segment *, Page *); +uintptr addr2check; + +int +fixfault(Segment *s, uintptr addr, int read, int doputmmu) +{ + int type; + Pte **p, *etp; + uintptr soff, mmuphys=0; + Page **pg, *old, *new; + Page *(*fn)(Segment*, uintptr); + + addr &= ~(BY2PG-1); + soff = addr-s->base; + p = &s->map[soff/PTEMAPMEM]; + if(*p == nil) + *p = ptealloc(); + + etp = *p; + pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG]; + type = s->type&SG_TYPE; + + if(pg < etp->first) + etp->first = pg; + if(pg > etp->last) + etp->last = pg; + + switch(type) { + default: + panic("fault"); + break; + + case SG_TEXT: /* Demand load */ + if(pagedout(*pg)) + pio(s, addr, soff, pg, doputmmu); + + mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; + (*pg)->modref = PG_REF; + break; + + case SG_BSS: + case SG_SHARED: /* Zero fill on demand */ + case SG_STACK: + if(*pg == nil) { + new = newpage(1, &s, addr); + if(s == nil) + return -1; + *pg = new; + } + goto common; + + case SG_DATA: + common: /* Demand load/pagein/copy on write */ + if(pagedout(*pg)) + pio(s, addr, soff, pg, doputmmu); + + /* + * It's only possible to copy on write if + * we're the only user of the segment. + */ + if(read && conf.copymode == 0 && s->ref == 1) { + mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID; + (*pg)->modref |= PG_REF; + break; + } + + old = *pg; + if(old->image == &swapimage && (old->ref + swapcount(old->daddr)) == 1) + uncachepage(old); + if(old->ref > 1 || old->image != nil) { + new = newpage(0, &s, addr); + if(s == nil) + return -1; + *pg = new; + copypage(old, *pg); + putpage(old); + } + mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID; + (*pg)->modref = PG_MOD|PG_REF; + break; + + case SG_PHYSICAL: + if(*pg == nil) { + fn = s->pseg->pgalloc; + if(fn) + *pg = (*fn)(s, addr); + else { + new = smalloc(sizeof(Page)); + new->va = addr; + new->pa = s->pseg->pa+(addr-s->base); + new->ref = 1; + *pg = new; + } + } + + if (checkaddr && addr == addr2check) + (*checkaddr)(addr, s, *pg); + mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID; + (*pg)->modref = PG_MOD|PG_REF; + break; + } + qunlock(s); + + if(doputmmu) + putmmu(addr, mmuphys, *pg); + + return 0; +} + /* * Called only in a system call */ |