129 lines
		
	
	
	
		
			2.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			129 lines
		
	
	
	
		
			2.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  *  mmap.c | ||
|  |  * | ||
|  |  *  Copyright (C) 1995, 1996 by Volker Lendecke | ||
|  |  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache | ||
|  |  * | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <linux/stat.h>
 | ||
|  | #include <linux/time.h>
 | ||
|  | #include <linux/kernel.h>
 | ||
|  | #include <linux/mm.h>
 | ||
|  | #include <linux/shm.h>
 | ||
|  | #include <linux/errno.h>
 | ||
|  | #include <linux/mman.h>
 | ||
|  | #include <linux/string.h>
 | ||
|  | #include <linux/slab.h>
 | ||
|  | #include <linux/fcntl.h>
 | ||
|  | #include <linux/ncp_fs.h>
 | ||
|  | 
 | ||
|  | #include "ncplib_kernel.h"
 | ||
|  | #include <asm/uaccess.h>
 | ||
|  | #include <asm/system.h>
 | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * Fill in the supplied page for mmap | ||
|  |  */ | ||
|  | static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, | ||
|  | 				     unsigned long address, int *type) | ||
|  | { | ||
|  | 	struct file *file = area->vm_file; | ||
|  | 	struct dentry *dentry = file->f_dentry; | ||
|  | 	struct inode *inode = dentry->d_inode; | ||
|  | 	struct page* page; | ||
|  | 	char *pg_addr; | ||
|  | 	unsigned int already_read; | ||
|  | 	unsigned int count; | ||
|  | 	int bufsize; | ||
|  | 	int pos; | ||
|  | 
 | ||
|  | 	page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages
 | ||
|  | 	           as long as recvmsg and memset works on it */ | ||
|  | 	if (!page) | ||
|  | 		return page; | ||
|  | 	pg_addr = kmap(page); | ||
|  | 	address &= PAGE_MASK; | ||
|  | 	pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT); | ||
|  | 
 | ||
|  | 	count = PAGE_SIZE; | ||
|  | 	if (address + PAGE_SIZE > area->vm_end) { | ||
|  | 		count = area->vm_end - address; | ||
|  | 	} | ||
|  | 	/* what we can read in one go */ | ||
|  | 	bufsize = NCP_SERVER(inode)->buffer_size; | ||
|  | 
 | ||
|  | 	already_read = 0; | ||
|  | 	if (ncp_make_open(inode, O_RDONLY) >= 0) { | ||
|  | 		while (already_read < count) { | ||
|  | 			int read_this_time; | ||
|  | 			int to_read; | ||
|  | 
 | ||
|  | 			to_read = bufsize - (pos % bufsize); | ||
|  | 
 | ||
|  | 			to_read = min_t(unsigned int, to_read, count - already_read); | ||
|  | 
 | ||
|  | 			if (ncp_read_kernel(NCP_SERVER(inode), | ||
|  | 				     NCP_FINFO(inode)->file_handle, | ||
|  | 				     pos, to_read, | ||
|  | 				     pg_addr + already_read, | ||
|  | 				     &read_this_time) != 0) { | ||
|  | 				read_this_time = 0; | ||
|  | 			} | ||
|  | 			pos += read_this_time; | ||
|  | 			already_read += read_this_time; | ||
|  | 
 | ||
|  | 			if (read_this_time < to_read) { | ||
|  | 				break; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		ncp_inode_close(inode); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (already_read < PAGE_SIZE) | ||
|  | 		memset(pg_addr + already_read, 0, PAGE_SIZE - already_read); | ||
|  | 	flush_dcache_page(page); | ||
|  | 	kunmap(page); | ||
|  | 
 | ||
|  | 	/*
 | ||
|  | 	 * If I understand ncp_read_kernel() properly, the above always | ||
|  | 	 * fetches from the network, here the analogue of disk. | ||
|  | 	 * -- wli | ||
|  | 	 */ | ||
|  | 	if (type) | ||
|  | 		*type = VM_FAULT_MAJOR; | ||
|  | 	inc_page_state(pgmajfault); | ||
|  | 	return page; | ||
|  | } | ||
|  | 
 | ||
|  | static struct vm_operations_struct ncp_file_mmap = | ||
|  | { | ||
|  | 	.nopage	= ncp_file_mmap_nopage, | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | /* This is used for a general mmap of a ncp file */ | ||
|  | int ncp_mmap(struct file *file, struct vm_area_struct *vma) | ||
|  | { | ||
|  | 	struct inode *inode = file->f_dentry->d_inode; | ||
|  | 	 | ||
|  | 	DPRINTK("ncp_mmap: called\n"); | ||
|  | 
 | ||
|  | 	if (!ncp_conn_valid(NCP_SERVER(inode))) | ||
|  | 		return -EIO; | ||
|  | 
 | ||
|  | 	/* only PAGE_COW or read-only supported now */ | ||
|  | 	if (vma->vm_flags & VM_SHARED) | ||
|  | 		return -EINVAL; | ||
|  | 	/* we do not support files bigger than 4GB... We eventually 
 | ||
|  | 	   supports just 4GB... */ | ||
|  | 	if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff  | ||
|  | 	   > (1U << (32 - PAGE_SHIFT))) | ||
|  | 		return -EFBIG; | ||
|  | 
 | ||
|  | 	vma->vm_ops = &ncp_file_mmap; | ||
|  | 	file_accessed(file); | ||
|  | 	return 0; | ||
|  | } |