Beispiel #1
0
static int do_swap_page(struct mm_struct * mm,
	struct vm_area_struct * vma, unsigned long address,
	pte_t * page_table, swp_entry_t entry, int write_access)
{
	struct page *page = lookup_swap_cache(entry);
	pte_t pte;

	if (!page) {
		lock_kernel();
		swapin_readahead(entry);
		page = read_swap_cache(entry);
		unlock_kernel();
		if (!page)
			return -1;

		flush_page_to_ram(page);
		flush_icache_page(vma, page);
	}

	mm->rss++;

	pte = mk_pte(page, vma->vm_page_prot);

	/*
	 * Freeze the "shared"ness of the page, ie page_count + swap_count.
	 * Must lock page before transferring our swap count to already
	 * obtained page count.
	 */
	lock_page(page);
	swap_free(entry);
	if (write_access && !is_page_shared(page))
		pte = pte_mkwrite(pte_mkdirty(pte));
	UnlockPage(page);

	set_pte(page_table, pte);
	/* No need to invalidate - it was non-present before */
	update_mmu_cache(vma, address, pte);
	return 1;	/* Minor fault */
}
Beispiel #2
0
static int unswap_by_move(unsigned short *map, unsigned long max,
			  unsigned long start, unsigned long n_pages)
{
	struct task_struct *p;
	unsigned long entry, rover = (start == 1) ? n_pages+1 : 1;
	unsigned long i, j;

	DPRINTK( "unswapping %lu..%lu by moving in swap\n",
			 start, start+n_pages-1 );
	
	/* can free the allocated pages by moving them to other swap pages */
	for( i = start; i < start+n_pages; ++i ) {
		if (!map[i]) {
			map[i] = SWAP_MAP_BAD;
			DPRINTK( "unswap: page %lu was free\n", i );
			continue;
		}
		else if (map[i] == SWAP_MAP_BAD) {
			printk( KERN_ERR "get_stram_region: page %lu already "
					"reserved??\n", i );
		}
		DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] );

		/* find a free page not in our region */
		for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) {
			if (j >= start && j < start+n_pages)
				continue;
			if (!map[j]) {
				rover = j+1;
				break;
			}
		}
		if (j == rover-1) {
			printk( KERN_ERR "get_stram_region: not enough free swap "
					"pages now??\n" );
			return( -ENOMEM );
		}
		DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n",
				 i, map[i], j, map[j], nr_swap_pages );
		
		--nr_swap_pages;
		entry = SWP_ENTRY( stram_swap_type, j );
		if (stram_swap_info->lowest_bit == j)
			stram_swap_info->lowest_bit++;
		if (stram_swap_info->highest_bit == j)
			stram_swap_info->highest_bit--;
		
		memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE );
#ifdef DO_PROC
		stat_swap_move++;
#endif

		while( map[i] ) {
			read_lock(&tasklist_lock);
			for_each_task(p) {
				if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ),
									entry, 1 )) {
					read_unlock(&tasklist_lock);
					map[j]++;
					goto repeat;
				}
			}
			read_unlock(&tasklist_lock);
			if (map[i] && map[i] != SWAP_MAP_MAX) {
				printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu "
						"not used by any process\n", i );
				/* quit while loop and overwrite bad map entry */
				break;
			}
			else if (!map[i]) {
				/* somebody else must have swapped in that page, so free the
				 * new one (we're moving to) */
				DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" );
				map[j] = 0;
			}
		  repeat:
		}

		DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n",
				 i, map[i], j, map[j], nr_swap_pages );
		map[i] = SWAP_MAP_BAD;
		if (stram_swap_info->lowest_bit == i)
			stram_swap_info->lowest_bit++;
		if (stram_swap_info->highest_bit == i)
			stram_swap_info->highest_bit--;
		--nr_swap_pages;
	}
	return( 0 );
}
#endif

static int unswap_by_read(unsigned short *map, unsigned long max,
			  unsigned long start, unsigned long n_pages)
{
	struct task_struct *p;
	unsigned long entry, page;
	unsigned long i;
	struct page *page_map;

	DPRINTK( "unswapping %lu..%lu by reading in\n",
			 start, start+n_pages-1 );

	for( i = start; i < start+n_pages; ++i ) {
		if (map[i] == SWAP_MAP_BAD) {
			printk( KERN_ERR "get_stram_region: page %lu already "
					"reserved??\n", i );
			continue;
		}

		if (map[i]) {
			entry = SWP_ENTRY(stram_swap_type, i);
			DPRINTK("unswap: map[i=%lu]=%u nr_swap=%u\n",
				i, map[i], nr_swap_pages);

			/* Get a page for the entry, using the existing
			   swap cache page if there is one.  Otherwise,
			   get a clean page and read the swap into it. */
			page_map = read_swap_cache(entry);
			if (page_map) {
				page = page_address(page_map);
				read_lock(&tasklist_lock);
				for_each_task(p)
					unswap_process(p->mm, entry, page
						       /* , 0 */);
				read_unlock(&tasklist_lock);
				shm_unuse(entry, page);
				/* Now get rid of the extra reference to
				   the temporary page we've been using. */
				if (PageSwapCache(page_map))
					delete_from_swap_cache(page_map);
				__free_page(page_map);
	#ifdef DO_PROC
				stat_swap_force++;
	#endif
			}
			else if (map[i])
				return -ENOMEM;
		}

		DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n",
				 i, map[i], nr_swap_pages );
		map[i] = SWAP_MAP_BAD;
		if (stram_swap_info->lowest_bit == i)
			stram_swap_info->lowest_bit++;
		if (stram_swap_info->highest_bit == i)
			stram_swap_info->highest_bit--;
		--nr_swap_pages;
	}

	return 0;
}

/*
 * reserve a region in ST-RAM swap space for an allocation
 */
static void *get_stram_region( unsigned long n_pages )
{
	unsigned short *map = stram_swap_info->swap_map;
	unsigned long max = stram_swap_info->max;
	unsigned long start, total_free, region_free;
	int err;
	void *ret = NULL;
	
	DPRINTK( "get_stram_region(n_pages=%lu)\n", n_pages );

	down(&stram_swap_sem);

	/* disallow writing to the swap device now */
	stram_swap_info->flags = SWP_USED;

	/* find a region of n_pages pages in the swap space including as much free
	 * pages as possible (and excluding any already-reserved pages). */
	if (!(start = find_free_region( n_pages, &total_free, &region_free )))
		goto end;
	DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n",
			 start, region_free );

#if 0
	err = ((total_free-region_free >= n_pages-region_free) ?
		   unswap_by_move( map, max, start, n_pages ) :
		   unswap_by_read( map, max, start, n_pages ));
#else
	err = unswap_by_read(map, max, start, n_pages);
#endif

	if (err)
		goto end;

	ret = SWAP_ADDR(start);
  end:
	/* allow using swap device again */
	stram_swap_info->flags = SWP_WRITEOK;
	up(&stram_swap_sem);
	DPRINTK( "get_stram_region: returning %p\n", ret );
	return( ret );
}