/* * Again because of the changes in page table walking, a 2.4 and 2.5 * version is supplied */ inline unsigned long forall_pte_pmd(struct mm_struct *mm, pmd_t *pmd, unsigned long start, unsigned long end, unsigned long *sched_count, void *data, unsigned long (*func)(pte_t *, unsigned long, void *)) { pte_t *ptep, pte; unsigned long pmd_end; unsigned long ret=0; if (pmd_none(*pmd)) return 0; pmd_end = (start + PMD_SIZE) & PMD_MASK; if (end > pmd_end) end = pmd_end; do { preempt_disable(); ptep = pte_offset_map(pmd, start); pte = *ptep; pte_unmap(ptep); preempt_enable(); /* Call the if a PTE is available */ if (!pte_none(pte)) { /* * Call schedule if necessary * Can func() block or be preempted? * It seems the sched_count won't be guarnateed * accurate. */ spin_unlock(&mm->page_table_lock); check_resched(sched_count); ret += func(&pte, start, data); spin_lock(&mm->page_table_lock); } start += PAGE_SIZE; } while (start && (start < end)); return ret; }
/** * * test_alloc_runtest - Allocate and free a number of pages from a ZONE_NORMAL * @params: Parameters read from the proc entry * @argc: Number of parameters actually entered * @procentry: Proc buffer to write to * * If pages is set to 0, pages will be allocated until the pages_high watermark * is hit * Returns * 0 on success * -1 on failure * */ int test_alloc_runtest(int *params, int argc, int procentry) { unsigned long order; /* Order of pages */ unsigned long numpages; /* Number of pages to allocate */ struct page **pages; /* Pages that were allocated */ unsigned long attempts=0; unsigned long alloced=0; unsigned long nextjiffies = jiffies; unsigned long lastjiffies = jiffies; unsigned long success=0; unsigned long fail=0; unsigned long resched_count=0; unsigned long aborted=0; unsigned long long start_cycles, cycles; unsigned long page_dma=0, page_dma32=0, page_normal=0, page_highmem=0, page_easyrclm=0; struct zone *zone; char finishString[60]; int timing_pages, pages_required; /* Set gfp_flags based on the module parameter */ if (gfp_highuser) { #ifdef GFP_RCLMUSER vmr_printk("Using highmem with GFP_RCLMUSER\n"); gfp_flags = GFP_RCLMUSER; #elif defined(GFP_HIGH_MOVABLE) vmr_printk("Using highmem with GFP_HIGH_MOVABLE\n"); gfp_flags = GFP_HIGH_MOVABLE; #elif defined(GFP_HIGHUSER_MOVABLE) vmr_printk("Using highmem with GFP_HIGHUSER_MOVABLE\n"); gfp_flags = GFP_HIGHUSER_MOVABLE; #else vmr_printk("Using highmem with GFP_HIGHUSER | __GFP_EASYRCLM\n"); gfp_flags = GFP_HIGHUSER | __GFP_EASYRCLM; #endif } else { vmr_printk("Using lowmem\n"); gfp_flags |= __GFP_EASYRCLM|__GFP_MOVABLE; } vmr_printk("__GFP_EASYRCLM is 0x%8X\n", __GFP_EASYRCLM); vmr_printk("__GFP_MOVABLE is 0x%8X\n", __GFP_MOVABLE); vmr_printk("gfp_flags = 0x%8X\n", gfp_flags); /* Get the parameters */ order = params[0]; numpages = params[1]; /* Make sure a buffer is available */ if (vmrproc_checkbuffer(testinfo[HIGHALLOC_REPORT])) BUG(); if (vmrproc_checkbuffer(testinfo[HIGHALLOC_TIMING])) BUG(); if (vmrproc_checkbuffer(testinfo[HIGHALLOC_BUDDYINFO])) BUG(); vmrproc_openbuffer(&testinfo[HIGHALLOC_REPORT]); vmrproc_openbuffer(&testinfo[HIGHALLOC_TIMING]); vmrproc_openbuffer(&testinfo[HIGHALLOC_BUDDYINFO]); /* Check parameters */ if (order < 0 || order >= MAX_ORDER) { vmr_printk("Order request of %lu makes no sense\n", order); return -1; } if (numpages < 0) { vmr_printk("Number of pages %lu makes no sense\n", numpages); return -1; } /* * Allocate memory to store pointers to pages. */ pages = __vmalloc((numpages+1) * sizeof(struct page **), GFP_KERNEL|__GFP_HIGHMEM|__GFP_KERNRCLM|__GFP_RECLAIMABLE, PAGE_KERNEL); if (pages == NULL) { printp("Failed to allocate space to store page pointers\n"); vmrproc_closebuffer(&testinfo[HIGHALLOC_REPORT]); vmrproc_closebuffer(&testinfo[HIGHALLOC_TIMING]); vmrproc_closebuffer(&testinfo[HIGHALLOC_BUDDYINFO]); return 0; } /* Setup proc buffer for timings */ timing_pages = testinfo[HIGHALLOC_TIMING].procbuf_size / PAGE_SIZE; pages_required = (numpages * 20) / PAGE_SIZE; if (pages_required > timing_pages) { vmrproc_growbuffer(pages_required - timing_pages, &testinfo[HIGHALLOC_TIMING]); } /* Setup proc buffer for highorder alloc */ timing_pages = testinfo[HIGHALLOC_BUDDYINFO].procbuf_size / PAGE_SIZE; pages_required = (numpages * ((256 + 30 + 15 * MAX_ORDER) * num_online_nodes())) / PAGE_SIZE; if (pages_required > timing_pages) { vmrproc_growbuffer(pages_required - timing_pages, &testinfo[HIGHALLOC_BUDDYINFO]); } #if defined(OOM_DISABLE) && (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19)) /* Disable OOM Killer */ vmr_printk("Disabling OOM killer for running process\n"); oomkilladj = current->oomkilladj; current->oomkilladj = OOM_DISABLE; #endif /* OOM_DISABLE */ /* * Attempt to allocate the requested number of pages */ while (attempts++ != numpages) { struct page *page; if (lastjiffies > jiffies) nextjiffies = jiffies; while (jiffies < nextjiffies) check_resched(resched_count); nextjiffies = jiffies + ( (HZ * ms_delay)/1000); /* Print message if this is taking a long time */ if (jiffies - lastjiffies > HZ) { printk("High order alloc test attempts: %lu (%lu)\n", attempts-1, alloced); } /* Print out a message every so often anyway */ if (attempts > 1 && (attempts-1) % 10 == 0) { printp_entry(HIGHALLOC_TIMING, "\n"); printk("High order alloc test attempts: %lu (%lu)\n", attempts-1, alloced); } lastjiffies = jiffies; start_cycles = read_clockcycles(); page = alloc_pages(gfp_flags | __GFP_NOWARN, order); cycles = read_clockcycles() - start_cycles; if (page) { printp_entry(HIGHALLOC_TIMING, "%-11llu ", cycles); printp_buddyinfo(testinfo, HIGHALLOC_BUDDYINFO, attempts, 1); success++; pages[alloced++] = page; /* Count what zone this is */ zone = page_zone(page); if (zone->name != NULL && !strcmp(zone->name, "EasyRclm")) page_easyrclm++; if (zone->name != NULL && !strcmp(zone->name, "Movable")) page_easyrclm++; if (zone->name != NULL && !strcmp(zone->name, "HighMem")) page_highmem++; if (zone->name != NULL && !strcmp(zone->name, "Normal")) page_normal++; if (zone->name != NULL && !strcmp(zone->name, "DMA32")) page_dma32++; if (zone->name != NULL && !strcmp(zone->name, "DMA")) page_dma++; /* Give up if it takes more than 60 seconds to allocate */ if (jiffies - lastjiffies > HZ * 600) { printk("Took more than 600 seconds to allocate a block, giving up"); aborted = attempts; attempts = numpages; break; } } else { printp_entry(HIGHALLOC_TIMING, "-%-10llu ", cycles); printp_buddyinfo(testinfo, HIGHALLOC_BUDDYINFO, attempts, 0); fail++; /* Give up if it takes more than 30 seconds to fail */ if (jiffies - lastjiffies > HZ * 1200) { printk("Took more than 1200 seconds and still failed to allocate, giving up"); aborted = attempts; attempts = numpages; break; } } } /* Re-enable OOM Killer state */ #ifdef OOM_DISABLED vmr_printk("Re-enabling OOM Killer status\n"); current->oomkilladj = oomkilladj; #endif vmr_printk("Test completed with %lu allocs, printing results\n", alloced); /* Print header */ printp("Order: %lu\n", order); printp("Allocation type: %s\n", gfp_highuser ? "HighMem" : "Normal"); printp("Attempted allocations: %lu\n", numpages); printp("Success allocs: %lu\n", success); printp("Failed allocs: %lu\n", fail); printp("DMA32 zone allocs: %lu\n", page_dma32); printp("DMA zone allocs: %lu\n", page_dma); printp("Normal zone allocs: %lu\n", page_normal); printp("HighMem zone allocs: %lu\n", page_highmem); printp("EasyRclm zone allocs: %lu\n", page_easyrclm); printp("%% Success: %lu\n", (success * 100) / (unsigned long)numpages); /* * Free up the pages */ vmr_printk("Test complete, freeing %lu pages\n", alloced); if (alloced > 0) { do { alloced--; if (pages[alloced] != NULL) __free_pages(pages[alloced], order); } while (alloced != 0); vfree(pages); } if (aborted == 0) strcpy(finishString, "Test completed successfully\n"); else sprintf(finishString, "Test aborted after %lu allocations due to delays\n", aborted); printp(finishString); vmr_printk("Test completed, closing buffer\n"); vmrproc_closebuffer(&testinfo[HIGHALLOC_REPORT]); vmrproc_closebuffer(&testinfo[HIGHALLOC_TIMING]); vmrproc_closebuffer(&testinfo[HIGHALLOC_BUDDYINFO]); vmr_printk("%s", finishString); return 0; }
/** * * test_fault_runtest - Allocate and free a number of pages from a zone * @params: Parameters read from the proc entry * @argc: Number of parameters actually entered * @procentry: Proc buffer to write to * * If pages is set to 0, pages will be allocated until the pages_high watermark * is hit * Returns * 0 on success * -1 on failure * */ int test_fault_runtest(int *params, int argc, int procentry) { unsigned long nopages; /* Number of pages to allocate */ int nopasses; /* Number of times to run test */ C_ZONE *zone; /* Zone been tested on */ unsigned long freelimit; /* The min no. free pages in zone */ unsigned long alloccount; /* Number of pages alloced */ unsigned long present; /* Number of pages present */ unsigned long addr=0; /* Address mapped area starts */ unsigned long len; /* Length of mapped area */ unsigned long sched_count; /* How many times schedule is called */ unsigned long start; /* Start of a test in jiffies */ int totalpasses; /* Total number of passes */ int failed=0; /* Failed mappings */ /* Get the parameters */ nopasses = params[0]; nopages = params[1]; /* Make sure a buffer is available */ if (vmrproc_checkbuffer(testinfo[procentry])) BUG(); vmrproc_openbuffer(&testinfo[procentry]); /* Make sure passes is valid */ if (nopasses <= 0) { vmr_printk("Cannot make 0 or negative number of passes\n"); return -1; } /* Print header */ printp("%s Test Results (" UTS_RELEASE ").\n\n", testinfo[procentry].name); /* Get the parameters for the test */ if (test_fault_calculate_parameters(procentry, &zone, &nopages, &freelimit) == -1) { printp("Test failed\n"); return -1; } len = nopages * PAGE_SIZE; /* * map a region of memory where our pages are going to be stored * This is the same as the system call to mmap * */ addr = do_mmap(NULL, /* No struct file */ 0, /* No starting address */ len, /* Length of address space */ PROT_WRITE | PROT_READ, /* Protection */ MAP_PRIVATE | MAP_ANONYMOUS, /* Private mapping */ 0); /* get_unmapped area has a horrible way of returning errors */ if (addr == -1) { printp("Failed to mmap"); return -1; } /* Print area information */ printp("Mapped Area Information\n"); printp("o address: 0x%lX\n", addr); printp("o length: %lu (%lu pages)\n", len, nopages); printp("\n"); /* Begin test */ printp("Test Parameters\n"); printp("o Passes: %d\n", nopasses); printp("o Starting Free pages: %lu\n", zone->free_pages); printp("o Free page limit: %lu\n", freelimit); printp("o References: %lu\n", nopages); printp("\n"); printp("Test Results\n"); printp("Pass Refd Present Time\n"); totalpasses = nopasses; /* Copy the string into every page once to alloc all ptes */ alloccount=0; start = jiffies; while (nopages-- > 0) { check_resched(sched_count); copy_to_user((unsigned long *)(addr + (nopages * PAGE_SIZE)), test_string, strlen(test_string)); alloccount++; } /* * Step through the page tables pass number of times swapping in * pages as necessary */ for (;;) { /* Count the number of pages present */ present = countpages_mm(current->mm, addr, len, &sched_count); /* Print test info */ printp("%-8d %8lu %8lu %8lums\n", totalpasses-nopasses, alloccount, present, jiffies_to_ms(start)); if (nopasses-- == 0) break; /* Touch all the pages in the mapped area */ start = jiffies; alloccount = forall_pte_mm(current->mm, addr, len, &sched_count, NULL, touch_pte); } printp("\nPost Test Information\n"); printp("o Finishing Free pages: %lu\n", zone->free_pages); printp("o Schedule() calls: %lu\n", sched_count); printp("o Failed mappings: %u\n", failed); printp("\n"); printp("Test completed successfully\n"); /* Print out a process map */ vmr_printmap(current->mm, addr, len, &sched_count, &testinfo[procentry]); /* Unmap the area */ if (do_munmap(current->mm, addr, len) == -1) { printp("WARNING: Failed to unmap memory area"); } vmrproc_closebuffer(&testinfo[procentry]); return 0; }