kernels/linux-2.4.0/mm/shmem.c
/*
 * shmem_nopage - either get the page from swap or allocate a new one
 *
 * If we allocate a new one we do not mark it dirty. That's up to the
 * vm. If we swap it in we mark it dirty since we also free the swap
 * entry since a page cannot live in both the swap and page cache
 */
either get the page from swap or allocate a new one
If we allocate a new one we do not mark it dirty. That's up to the
vm. If we swap it in we mark it dirty since we also free the swap
entry since a page cannot live in both the swap and page cache
either get the page from swap or allocate a new one If we allocate a new one we do not mark it dirty . That ' s up to the vm . If we swap it in we mark it dirty since we also free the swap entry since a page cannot live in both the swap and page cache
struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share)
{
	unsigned long size;
	struct page * page;
	unsigned int idx;
	swp_entry_t *entry;
	struct inode * inode = vma->vm_file->f_dentry->d_inode;
	struct address_space * mapping = inode->i_mapping;
	struct shmem_inode_info *info;
	idx = (address - vma->vm_start) >> PAGE_SHIFT;
	idx += vma->vm_pgoff;
	down (&inode->i_sem);
	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
	page = NOPAGE_SIGBUS;
	if ((idx >= size) && (vma->vm_mm == current->mm))
		goto out;
	page = __find_lock_page(mapping, idx, page_hash (mapping, idx));
	if (page)
		goto cached_page;
	info = &inode->u.shmem_i;
	entry = shmem_swp_entry (info, idx);
	if (!entry)
		goto oom;
	if (entry->val) {
		unsigned long flags;
		page = lookup_swap_cache(*entry);
		if (!page) {
			lock_kernel();
			swapin_readahead(*entry);
			page = read_swap_cache(*entry);
			unlock_kernel();
			if (!page) 
				goto oom;
		}
		spin_lock (&info->lock);
		swap_free(*entry);
		lock_page(page);
		delete_from_swap_cache_nolock(page);
		*entry = (swp_entry_t) {0};
		flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1));
		page->flags = flags | (1 << PG_dirty);
		add_to_page_cache_locked(page, mapping, idx);
		info->swapped--;
		spin_unlock (&info->lock);
	} else {
		spin_lock (&inode->i_sb->u.shmem_sb.stat_lock);
		if (inode->i_sb->u.shmem_sb.free_blocks == 0)
			goto no_space;
		inode->i_sb->u.shmem_sb.free_blocks--;
		spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
		page = page_cache_alloc();
		if (!page)
			goto oom;
		clear_user_highpage(page, address);
		inode->i_blocks++;
		add_to_page_cache (page, mapping, idx);
	}
	SetPageUptodate (page);
cached_page:
	UnlockPage (page);
	up(&inode->i_sem);
	if (no_share) {
		struct page *new_page = page_cache_alloc();
		if (new_page) {
			copy_user_highpage(new_page, page, address);
			flush_page_to_ram(new_page);
		} else
			new_page = NOPAGE_OOM;
		page_cache_release(page);
		return new_page;
	}
	flush_page_to_ram (page);
	return(page);
no_space:
	spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
oom:
	page = NOPAGE_OOM;
out:
	up(&inode->i_sem);
	return page;
}
struct page * shmem_nopage ( struct vm_area_struct * vma , unsigned long address , int no_share ) { unsigned long size ; struct page * page ; unsigned int idx ; swp_entry_t * entry ; struct inode * inode = vma -> vm_file -> f_dentry -> d_inode ; struct address_space * mapping = inode -> i_mapping ; struct shmem_inode_info * info ; idx = ( address - vma -> vm_start ) >> PAGE_SHIFT ; idx += vma -> vm_pgoff ; down ( & inode -> i_sem ) ; size = ( inode -> i_size + PAGE_CACHE_SIZE - 1 ) >> PAGE_CACHE_SHIFT ; page = NOPAGE_SIGBUS ; if ( ( idx >= size ) && ( vma -> vm_mm == current -> mm ) ) goto out ; page = __find_lock_page ( mapping , idx , page_hash ( mapping , idx ) ) ; if ( page ) goto cached_page ; info = & inode -> u . shmem_i ; entry = shmem_swp_entry ( info , idx ) ; if ( ! entry ) goto oom ; if ( entry -> val ) { unsigned long flags ; page = lookup_swap_cache ( * entry ) ; if ( ! page ) { lock_kernel ( ) ; swapin_readahead ( * entry ) ; page = read_swap_cache ( * entry ) ; unlock_kernel ( ) ; if ( ! page ) goto oom ; } spin_lock ( & info -> lock ) ; swap_free ( * entry ) ; lock_page ( page ) ; delete_from_swap_cache_nolock ( page ) ; * entry = ( swp_entry_t ) { 0 } ; flags = page -> flags & ~ ( ( 1 << PG_uptodate ) | ( 1 << PG_error ) | ( 1 << PG_referenced ) | ( 1 << PG_arch_1 ) ) ; page -> flags = flags | ( 1 << PG_dirty ) ; add_to_page_cache_locked ( page , mapping , idx ) ; info -> swapped -- ; spin_unlock ( & info -> lock ) ; } else { spin_lock ( & inode -> i_sb -> u . shmem_sb . stat_lock ) ; if ( inode -> i_sb -> u . shmem_sb . free_blocks == 0 ) goto no_space ; inode -> i_sb -> u . shmem_sb . free_blocks -- ; spin_unlock ( & inode -> i_sb -> u . shmem_sb . stat_lock ) ; page = page_cache_alloc ( ) ; if ( ! page ) goto oom ; clear_user_highpage ( page , address ) ; inode -> i_blocks ++ ; add_to_page_cache ( page , mapping , idx ) ; } SetPageUptodate ( page ) ; cached_page : UnlockPage ( page ) ; up ( & inode -> i_sem ) ; if ( no_share ) { struct page * new_page = page_cache_alloc ( ) ; if ( new_page ) { copy_user_highpage ( new_page , page , address ) ; flush_page_to_ram ( new_page ) ; } else new_page = NOPAGE_OOM ; page_cache_release ( page ) ; return new_page ; } flush_page_to_ram ( page ) ; return ( page ) ; no_space : spin_unlock ( & inode -> i_sb -> u . shmem_sb . stat_lock ) ; oom : page = NOPAGE_OOM ; out : up ( & inode -> i_sem ) ; return page ; }
shmem_nopage - either get the page from swap or allocate a new one
 If we allocate a new one we do not mark it dirty.
shmem_nopage - either get the page from swap or allocate a new one If we allocate a new one we do not mark it dirty .
/* retry, we may have slept */ /* Look it up and read it in.. */ /* We have to this with page locked to prevent races */ /* Ok, get a new page */ /* We have the page */