コード例 #1
0
ファイル: proc.c プロジェクト: baozich/scripts
/**
 * vmr_write_proc - Routine to call if proc entry is written to
 * @file: unused
 * @buffer: user buffer
 * @count: data len
 * @data:  Index into testinfo[] which is being written
 *
 * This function will only exist if NUMBER_PROC_WRITE_PARAMETERS is defined,
 * hence this function is wrapped around an #ifdef
 */
int vmr_write_proc (struct file *file, const char *buf, 
		    unsigned long count, void *data)
{
	char readbuf[MAX_PROC_WRITE];
	char *from = readbuf; 	/* Pointer to beginning of parameter */
	char *to;		/* Pointer to end of parameter */
	PARAM_TYPE params[NUMBER_PROC_WRITE_PARAMETERS]; /* Array of ints read */
	int noread=0;				  /* Number ints read */
	int procentry;

	/* Which proc buffer we are writing to is passed in with *data */
	procentry = *(int *)data;

	/* Clear parameters */
	memset(params, 0, sizeof(params));

	/* Read input */
	if (count >= MAX_PROC_WRITE) {
		vmr_printk("count >= MAX_PROC_WRITE\n");
		return -EINVAL;
	}
	if (copy_from_user(&readbuf, buf, count)) {
		vmr_printk("copy_from_user failed\n");
		return -EFAULT;
	}
	readbuf[count] = '\0';

	while (from && noread < NUMBER_PROC_WRITE_PARAMETERS) {
		/* Split input by the space char */
		to = strchr(from, ' ');
		if (to) *(to++)='\0';

		/* Convert this parameter */
		params[noread] = vmr_strtol(from, NULL, 10);
		
		/* Move to next parameter */
		from = to;
		noread++;
	}

#ifdef CHECK_PROC_PARAMETERS
	/* Sanity check parameters */
	CHECK_PROC_PARAMETERS(params, noread);
#endif

	/* Run the test */
	VMR_WRITE_CALLBACK(params, noread, procentry);

	return count;
}
コード例 #2
0
ファイル: testproc.c プロジェクト: kosaki/vmregress
/* Callback function for proc write. Allocate a procentry and get it filled */
void testproc_fillproc(int *params, int argc, int procentry) {
	int pages = params[0];

	/* Allocate a new buffer and replace it with the old one */
	if (vmrproc_allocbuffer(pages, &testinfo[procentry]) != 0) return;
	vmr_printk("%d pages allocated for proc buffer\n", pages);

	testproc_runtest(procentry);
}
コード例 #3
0
ファイル: testproc.c プロジェクト: kosaki/vmregress
/**
 * testproc_runtest - Get information for the proc entry and fill the buffer
 *
 * testproc_readproc needs a buffer to read from if the output is going to be 
 * more than one page in size. This function populates a large buffer for 
 * printing out
 */
void testproc_runtest(int procentry) {
	char *procBlock;	/* Small 100k block to write out */
	int i;
	int written=0, endwrite;

	/* Make sure a buffer is available */
	if (vmrproc_checkbuffer(testinfo[procentry])) {
		vmr_printk("Buffer is somehow invalid\n");
		return;
	}
	testproc_buf = testinfo[procentry].procbuf;
	testproc_size = testinfo[procentry].procbuf_size;

	/* malloc procBlock and fill it */
	procBlock = kmalloc(101, GFP_KERNEL);
	if (!procBlock) {
		vmr_printk("Failed to allocate memory for procBlock\n");
		return;
	}
	for (i=0;i<100;i++) procBlock[i] = '0' + (i % 10);
	procBlock[100] = '\0';

	/* Write almost two pages of data into buffer */
	written = sprintf(testproc_buf, "Testing proc interface \n\n");
	endwrite = testproc_size - 120 - strlen(PROCFOOTER);
	while (written < endwrite) {
		written += sprintf(&testproc_buf[written], "%d - %d: ", 
					written, 
					written+100);

		if (written < endwrite)
			written += sprintf(&testproc_buf[written], "%s\n", 
							procBlock);
	}
	
	/* Write out remainder */
	written += sprintf(&testproc_buf[written], PROCFOOTER, (int)(PAGE_ALIGN(testproc_size) / PAGE_SIZE));

	/* Free procBlock */
	kfree(procBlock);

	testinfo[procentry].written = written;
}
コード例 #4
0
ファイル: proc.c プロジェクト: baozich/scripts
/**
 * vmr_read_proc - Routine to call if a proc entry is read from userspace
 * 
 * @buf:    buffer to write to
 * @start:  Local allocated page used for printing large proc entries
 * @offset: Number of bytes read so far
 * @count:  Number of bytes to read
 * @eof:    EOF flag (returned)
 * @data:   Index into testinfo[] array that is being read
 */
int vmr_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data)
{
	off_t len;
	int procentry;

	/* The proc entry being read is stored in the private data pointer */
	procentry = *(int *)data;

#ifdef VMR_READ_PROC_CALLBACK
	/* Populate proc buffer */
	if (offset == 0) VMR_READ_PROC_CALLBACK(procentry);
#endif

	/* Sanity check */
	if (offset < 0) {
		vmr_printk("WARNING: Negative offset was passed in. Some sort of bug exists with proc handling\n");
		*eof = 1;
		return 0;
	}

	/* Set start */
	*start = buf;

	/* Get length of proc entry */
	len =  strlen(testinfo[procentry].procbuf);
	if (offset > len) {
		vmr_printk("WARNING: proc offset > buffer length\n");
		return 0;
	}

	/* Make sure we do not try and read off the end */
	if (offset + count > len) {
		count = len - offset;
	}

	/* Set the length that needs to be copied */
	len -= offset;

	/*
	 * Check if
	 *   o this read will be the last read
	 *   o if the reader would go past the buffer end
	 *   o that more than PAGE_SIZE was requested
	 *   o a negative length was asked for
	 */
	if (len <= count) *eof=1;
	if (len > count) len = count;
	if (len > PAGE_SIZE) len = PAGE_SIZE;
	if (len < 0) len = 0;

	/* Copy string into buffer */
	strncpy(buf, (testinfo[procentry].procbuf + offset), len);
	buf[len] = '\0';

#ifdef VMR_READ_PROC_CALLBACK
	if (*eof) vmrproc_closebuffer(&testinfo[procentry]);
#endif

#ifdef VMR_READ_PROC_ENDCALLBACK
	VMR_READ_PROC_ENDCALLBACK;
#endif
	return len;
}
コード例 #5
0
ファイル: highalloc.c プロジェクト: baozich/scripts
/**
 *
 * 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;
}
コード例 #6
0
ファイル: fault.c プロジェクト: kosaki/vmregress
/**
 *
 * 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;
}
コード例 #7
0
ファイル: pagetable.c プロジェクト: baozich/scripts
/**
 * 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;
}