int mappedcopyout(void *f, void *t, size_t count) { void *fromp = f, *top = t; vaddr_t kva; paddr_t upa; size_t len; int off, alignable; pmap_t upmap; #define CADDR2 caddr1 #ifdef DEBUG if (mappedcopydebug & MDB_COPYOUT) printf("mappedcopyout(%p, %p, %lu), pid %d\n", fromp, top, (u_long)count, curproc->p_pid); mappedcopyoutcount++; #endif if (CADDR2 == 0) CADDR2 = (void *) uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY); kva = (vaddr_t) CADDR2; off = (int)((u_long)top & PAGE_MASK); alignable = (off == ((u_long)fromp & PAGE_MASK)); upmap = vm_map_pmap(&curproc->p_vmspace->vm_map); while (count > 0) { /* * First access of a page, use subyte to make sure * page is faulted in and write access allowed. */ if (subyte(top, *((char *)fromp)) == -1) return EFAULT; /* * Map in the page and memcpy data out to it */ if (pmap_extract(upmap, trunc_page((vaddr_t)top), &upa) == false) panic("mappedcopyout: null page frame"); len = min(count, (PAGE_SIZE - off)); pmap_enter(pmap_kernel(), kva, upa, VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); pmap_update(pmap_kernel()); if (len == PAGE_SIZE && alignable && off == 0) copypage(fromp, (void *)kva); else memcpy((void *)(kva + off), fromp, len); fromp += len; top += len; count -= len; off = 0; } pmap_remove(pmap_kernel(), kva, kva + PAGE_SIZE); pmap_update(pmap_kernel()); return 0; #undef CADDR2 }
static void writepages(void) { int i, j, k; /* loop indices */ /* * * Goes through the pages[] array, usually from the bottom up, and writes out all * the pages. Documents that print more than one form per page cause things to get * a little more complicated. Each physical page has to have its subpages printed * in the correct order, and we have to build a few dummy subpages for the last * (and now first) sheet of paper, otherwise things will only occasionally work. * */ fprintf(fp_out, "%s", endprolog); if ( noreverse == FALSE ) /* fill out the first page */ for ( i = (forms - next_page % forms) % forms; i > 0; i--, next_page++ ) pages[next_page].empty = TRUE; else forms = next_page; /* turns reversal off in next loop */ for ( i = next_page - forms; i >= 0; i -= forms ) for ( j = i, k = 0; k < forms; j++, k++ ) if ( pages[j].empty == TRUE ) { if ( ignoreversion == TRUE || version > 3.1 ) { fprintf(fp_out, "%s 0 0\n", PAGE); fprintf(fp_out, "/saveobj save def\n"); fprintf(fp_out, "showpage\n"); fprintf(fp_out, "saveobj restore\n"); fprintf(fp_out, "%s 0 0\n", ENDPAGE); } else { fprintf(fp_out, "%s 0 0\n", PAGE); fprintf(fp_out, "save showpage restore\n"); fprintf(fp_out, "%s 0 0\n", ENDPAGE); } /* End else */ } else copypage(pages[j].start, pages[j].stop); } /* End of writepages */
int fixfault(Segment *s, uintptr addr, int read, int doputmmu) { int type; int ref; Pte **p, *etp; uintptr mmuphys=0, soff; Page **pg, *lkp, *new; Page *(*fn)(Segment*, uintptr); addr &= ~(BY2PG-1); soff = addr-s->base; p = &s->map[soff/PTEMAPMEM]; if(*p == 0) *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 == 0) { new = newpage(1, &s, addr); if(s == 0) 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; } lkp = *pg; lock(lkp); if(lkp->image == &swapimage) ref = lkp->ref + swapcount(lkp->daddr); else ref = lkp->ref; if(ref == 1 && lkp->image){ /* save a copy of the original for the image cache */ duppage(lkp); ref = lkp->ref; } unlock(lkp); if(ref > 1){ new = newpage(0, &s, addr); if(s == 0) return -1; *pg = new; copypage(lkp, *pg); putpage(lkp); }
int duppage(Page *p) /* Always call with p locked */ { Proc *up = externup(); Pgsza *pa; Page *np; int color; int retries; retries = 0; retry: if(retries++ > dupretries){ print("duppage %d, up %#p\n", retries, up); dupretries += 100; if(dupretries > 100000) panic("duppage\n"); uncachepage(p); return 1; } /* don't dup pages with no image */ if(p->ref == 0 || p->image == nil || p->image->notext) return 0; /* * normal lock ordering is to call * lock(&pga.l) before lock(&p->l). * To avoid deadlock, we have to drop * our locks and try again. */ if(!canlock(&pga.l)){ unlock(&p->l); if(up) sched(); lock(&p->l); goto retry; } pa = &pga.pgsza[p->pgszi]; /* No freelist cache when memory is very low */ if(pa->freecount < Nminfree){ unlock(&pga.l); uncachepage(p); return 1; } color = p->color; for(np = pa->head; np; np = np->next) if(np->color == color) break; /* No page of the correct color */ if(np == 0){ unlock(&pga.l); uncachepage(p); return 1; } pageunchain(np); pagechaintail(np); /* * XXX - here's a bug? - np is on the freelist but it's not really free. * when we unlock palloc someone else can come in, decide to * use np, and then try to lock it. they succeed after we've * run copypage and cachepage and unlock(np). then what? * they call pageunchain before locking(np), so it's removed * from the freelist, but still in the cache because of * cachepage below. if someone else looks in the cache * before they remove it, the page will have a nonzero ref * once they finally lock(np). * * What I know is that not doing the pagechaintail, but * doing it at the end, to prevent the race, leads to a * deadlock, even following the pga, pg lock ordering. -nemo */ lock(&np->l); unlock(&pga.l); /* Cache the new version */ uncachepage(np); np->va = p->va; np->daddr = p->daddr; copypage(p, np); cachepage(np, p->image); unlock(&np->l); uncachepage(p); return 0; }
int duppage(Page *p) /* Always call with p locked */ { Page *np; int color; int retries; retries = 0; retry: if(retries++ > dupretries){ print("duppage %d, up %p\n", retries, up); dupretries += 100; if(dupretries > 100000) panic("duppage\n"); uncachepage(p); return 1; } /* don't dup pages with no image */ if(p->ref == 0 || p->image == nil || p->image->notext) return 0; /* * normal lock ordering is to call * lock(&palloc) before lock(p). * To avoid deadlock, we have to drop * our locks and try again. */ if(!canlock(&palloc)){ unlock(p); if(up) sched(); lock(p); goto retry; } /* No freelist cache when memory is very low */ if(palloc.freecount < swapalloc.highwater) { unlock(&palloc); uncachepage(p); return 1; } color = getpgcolor(p->va); for(np = palloc.head; np; np = np->next) if(np->color == color) break; /* No page of the correct color */ if(np == 0) { unlock(&palloc); uncachepage(p); return 1; } pageunchain(np); pagechaintail(np); /* * XXX - here's a bug? - np is on the freelist but it's not really free. * when we unlock palloc someone else can come in, decide to * use np, and then try to lock it. they succeed after we've * run copypage and cachepage and unlock(np). then what? * they call pageunchain before locking(np), so it's removed * from the freelist, but still in the cache because of * cachepage below. if someone else looks in the cache * before they remove it, the page will have a nonzero ref * once they finally lock(np). */ lock(np); unlock(&palloc); /* Cache the new version */ uncachepage(np); np->va = p->va; np->daddr = p->daddr; copypage(p, np); cachepage(np, p->image); unlock(np); uncachepage(p); return 0; }