/* * To avoid races, we repeat for each process after having * swapped something in. That gets rid of a few pesky races, * and "swapoff" isn't exactly timing critical. */ static int try_to_unuse(unsigned int type) { int nr; unsigned long page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; nr = 0; while (nr < NR_TASKS) { struct task_struct * p = task[nr]; if (p) { if (unuse_process(p->mm, type, page)) { page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; continue; } } nr++; } free_page(page); #ifdef CONFIG_SYSVIPC shm_unuse(type); #endif return 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, ®ion_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 ); }