/** * vmr_printmap - Print out a map representing a memory range * @mm: The mm to print pages from * @addr: The starting address * @len: The len of the address space to print * @sched_count: A count of how many times schedule() was called * * This function is used when it is desirable to see what a memory area * looks like. Each character in the map has 8 bits. The lower four bits * are used to store information about 4 pages. The 5th and 6th bit is set to one. * This will guarentee that something printable will show up. Using the * whole character for 8 bits leads to unprintable data filled with escape * characters. */ unsigned long vmr_printmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long *sched_count, vmr_desc_t *testinfo) { int mapsize; /* Size of map */ int growsize; /* Number of pages to grow proc */ int *print_written; /* Number of bytes written see vmr_snprintf macro*/ int print_size; /* Size of proc buffer, see vmr_snprinf macro */ int present; /* Make sure we are the writer */ if (current->pid != testinfo->pid) return 0; print_written = &testinfo->written; print_size = testinfo->procbuf_size; /* Calculate if the current proc area needs to be grown * Each 8 pages is one character hence * (len / PAGE_SIZE) gives the number of pages * no. pages / 4 = number of chars (using only readable chars) */ mapsize = ((len / PAGE_SIZE) / 4); /* * check if we should grow the proc buffer * The additional 256 bytes is for the header and footer around * the map information * */ if (testinfo->procbuf_size - *print_written < mapsize + 256) { /* Proc buffer has to be grown */ growsize = PAGE_ALIGN(mapsize + 256) / PAGE_SIZE; vmr_printk("Growing proc buffer by %d pages for mapsize %d\n", growsize, mapsize); vmrproc_growbuffer(growsize, testinfo); print_size = testinfo->procbuf_size; } /* Zero out the map */ memset(&testinfo->procbuf[*print_written], 0, mapsize); /* Print out header for map (40 is for the actual message to print) */ vmr_snprintf(testinfo, &testinfo->procbuf[*print_written], testinfo->procbuf_size - *print_written - 40, "BEGIN PAGE MAP 0x%lX - 0x%lX\n", addr, addr + len); /* Set the 5th and 6th bit on the map */ memset(&testinfo->procbuf[*print_written], 48, mapsize); /* Print out the map */ testinfo->mapaddr = addr; present = forall_pte_mm(mm, addr, len, sched_count, testinfo, vmr_printpage); /* Print out footer (50 is for the message to print) */ *print_written += mapsize; vmr_snprintf(testinfo, &testinfo->procbuf[*print_written], testinfo->procbuf_size - *print_written - 50, "\nEND PAGE MAP - %d pages of %lu present\n", present, len / PAGE_SIZE); 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; }
/** * countpages_mm - Count how many pages are present in a mm * @mm: The mm to count pages in * @addr: The starting address * @len: The length of the address space to check * @sched_count: A count of how many times schedule() was called */ unsigned long countpages_mm(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long *sched_count) { return forall_pte_mm(mm, addr, len, sched_count, NULL, ispage_present); }