📄 stram.c
字号:
* __get_dma_pages() */ addr = (void *)__get_dma_pages(GFP_KERNEL, get_order(size)); flags = BLOCK_GFP; DPRINTK( "atari_stram_alloc: after mem_init, swapping off, " "get_pages=%p\n", addr ); } if (addr) { if (!(block = add_region( addr, size ))) { /* out of memory for BLOCK structure :-( */ DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " "freeing again\n" );#ifdef CONFIG_STRAM_SWAP if (flags == BLOCK_INSWAP) free_stram_region( SWAP_NR(addr), N_PAGES(size) ); else#endif free_pages((unsigned long)addr, get_order(size)); return( NULL ); } block->owner = owner; block->flags |= flags; } return( addr );}void atari_stram_free( void *addr ){ BLOCK *block; DPRINTK( "atari_stram_free(addr=%p)\n", addr ); if (!(block = find_region( addr ))) { printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " "from %p\n", addr, __builtin_return_address(0) ); return; } DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, " "flags=%02x\n", block, block->size, block->owner, block->flags ); #ifdef CONFIG_STRAM_SWAP if (!max_swap_size) {#endif if (block->flags & BLOCK_GFP) { DPRINTK("atari_stram_free: is kmalloced, order_size=%d\n", get_order(block->size)); free_pages((unsigned long)addr, get_order(block->size)); } else goto fail;#ifdef CONFIG_STRAM_SWAP } else if (block->flags & BLOCK_INSWAP) { DPRINTK( "atari_stram_free: is swap-alloced\n" ); free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) ); } else goto fail;#endif remove_region( block ); return; fail: printk( KERN_ERR "atari_stram_free: cannot free block at %p " "(called from %p)\n", addr, __builtin_return_address(0) );}#ifdef CONFIG_STRAM_SWAP/* ------------------------------------------------------------------------ *//* Main Swapping Functions *//* ------------------------------------------------------------------------ *//* * Initialize ST-RAM swap device * (lots copied and modified from sys_swapon() in mm/swapfile.c) */static int __init swap_init(void *start_mem, void *swap_data){ static struct dentry fake_dentry; static struct vfsmount fake_vfsmnt; struct swap_info_struct *p; struct inode swap_inode; unsigned int type; void *addr; int i, j, k, prev; DPRINTK("swap_init(start_mem=%p, swap_data=%p)\n", start_mem, swap_data); /* need at least one page for swapping to (and this also isn't very * much... :-) */ if (swap_end - swap_start < 2*PAGE_SIZE) { printk( KERN_WARNING "stram_swap_init: swap space too small\n" ); return( 0 ); } /* find free slot in swap_info */ for( p = swap_info, type = 0; type < nr_swapfiles; type++, p++ ) if (!(p->flags & SWP_USED)) break; if (type >= MAX_SWAPFILES) { printk( KERN_WARNING "stram_swap_init: max. number of " "swap devices exhausted\n" ); return( 0 ); } if (type >= nr_swapfiles) nr_swapfiles = type+1; stram_swap_info = p; stram_swap_type = type; /* fake some dir cache entries to give us some name in /dev/swaps */ fake_dentry.d_parent = &fake_dentry; fake_dentry.d_name.name = "stram (internal)"; fake_dentry.d_name.len = 16; fake_vfsmnt.mnt_parent = &fake_vfsmnt; p->flags = SWP_USED; p->swap_file = &fake_dentry; p->swap_vfsmnt = &fake_vfsmnt; p->swap_device = 0; p->swap_map = swap_data; p->cluster_nr = 0; p->next = -1; p->prio = 0x7ff0; /* a rather high priority, but not the higest * to give the user a chance to override */ /* call stram_open() directly, avoids at least the overhead in * constructing a dummy file structure... */ p->swap_device = MKDEV( STRAM_MAJOR, STRAM_MINOR ); swap_inode.i_rdev = p->swap_device; stram_open( &swap_inode, MAGIC_FILE_P ); p->max = SWAP_NR(swap_end); /* initialize swap_map: set regions that are already allocated or belong * to kernel data space to SWAP_MAP_BAD, otherwise to free */ j = 0; /* # of free pages */ k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */ p->lowest_bit = 0; p->highest_bit = 0; for( i = 1, addr = SWAP_ADDR(1); i < p->max; i++, addr += PAGE_SIZE ) { if (in_some_region( addr )) { p->swap_map[i] = SWAP_MAP_BAD; ++k; } else if (kernel_in_stram && addr < start_mem ) { p->swap_map[i] = SWAP_MAP_BAD; } else { p->swap_map[i] = 0; ++j; if (!p->lowest_bit) p->lowest_bit = i; p->highest_bit = i; } } /* first page always reserved (and doesn't really belong to swap space) */ p->swap_map[0] = SWAP_MAP_BAD; /* now swapping to this device ok */ p->pages = j + k; swap_list_lock(); nr_swap_pages += j; p->flags = SWP_WRITEOK; /* insert swap space into swap_list */ prev = -1; for (i = swap_list.head; i >= 0; i = swap_info[i].next) { if (p->prio >= swap_info[i].prio) { break; } prev = i; } p->next = i; if (prev < 0) { swap_list.head = swap_list.next = p - swap_info; } else { swap_info[prev].next = p - swap_info; } swap_list_unlock(); printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n", p->pages << 2, p->pages ); return( 1 );}/* * The swap entry has been read in advance, and we return 1 to indicate * that the page has been used or is no longer needed. * * Always set the resulting pte to be nowrite (the same as COW pages * after one process has exited). We don't know just how many PTEs will * share this swap entry, so be cautious and let do_wp_page work out * what to do if a write is requested later. */static inline void unswap_pte(struct vm_area_struct * vma, unsigned long address, pte_t *dir, swp_entry_t entry, struct page *page){ pte_t pte = *dir; if (pte_none(pte)) return; if (pte_present(pte)) { /* If this entry is swap-cached, then page must already hold the right address for any copies in physical memory */ if (pte_page(pte) != page) return; /* We will be removing the swap cache in a moment, so... */ set_pte(dir, pte_mkdirty(pte)); return; } if (pte_val(pte) != entry.val) return; DPRINTK("unswap_pte: replacing entry %08lx by new page %p", entry.val, page); set_pte(dir, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); swap_free(entry); get_page(page); ++vma->vm_mm->rss;}static inline void unswap_pmd(struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long size, unsigned long offset, swp_entry_t entry, struct page *page){ pte_t * pte; unsigned long end; if (pmd_none(*dir)) return; if (pmd_bad(*dir)) { pmd_ERROR(*dir); pmd_clear(dir); return; } pte = pte_offset(dir, address); offset += address & PMD_MASK; address &= ~PMD_MASK; end = address + size; if (end > PMD_SIZE) end = PMD_SIZE; do { unswap_pte(vma, offset+address-vma->vm_start, pte, entry, page); address += PAGE_SIZE; pte++; } while (address < end);}static inline void unswap_pgd(struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long size, swp_entry_t entry, struct page *page){ pmd_t * pmd; unsigned long offset, end; if (pgd_none(*dir)) return; if (pgd_bad(*dir)) { pgd_ERROR(*dir); pgd_clear(dir); return; } pmd = pmd_offset(dir, address); offset = address & PGDIR_MASK; address &= ~PGDIR_MASK; end = address + size; if (end > PGDIR_SIZE) end = PGDIR_SIZE; do { unswap_pmd(vma, pmd, address, end - address, offset, entry, page); address = (address + PMD_SIZE) & PMD_MASK; pmd++; } while (address < end);}static void unswap_vma(struct vm_area_struct * vma, pgd_t *pgdir, swp_entry_t entry, struct page *page){ unsigned long start = vma->vm_start, end = vma->vm_end; do { unswap_pgd(vma, pgdir, start, end - start, entry, page); start = (start + PGDIR_SIZE) & PGDIR_MASK; pgdir++; } while (start < end);}static void unswap_process(struct mm_struct * mm, swp_entry_t entry, struct page *page){ struct vm_area_struct* vma; /* * Go through process' page directory. */ if (!mm) return; for (vma = mm->mmap; vma; vma = vma->vm_next) { pgd_t * pgd = pgd_offset(mm, vma->vm_start); unswap_vma(vma, pgd, entry, page); }}static int unswap_by_read(unsigned short *map, unsigned long max, unsigned long start, unsigned long n_pages){ struct task_struct *p; struct page *page; swp_entry_t entry; unsigned long i; 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); swap_device_lock(stram_swap_info); map[i]++; swap_device_unlock(stram_swap_info); /* 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 = read_swap_cache(entry); if (!page) { swap_free(entry); return -ENOMEM; } read_lock(&tasklist_lock); for_each_task(p) unswap_process(p->mm, entry, page); 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)) delete_from_swap_cache(page); __free_page(page); #ifdef DO_PROC stat_swap_force++; #endif } DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", i, map[i], nr_swap_pages ); swap_list_lock(); swap_device_lock(stram_swap_info); 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; swap_device_unlock(stram_swap_info); swap_list_unlock(); } 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 ); err = unswap_by_read(map, max, start, n_pages); 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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -