2005-04-17 02:20:36 +04:00
/*
* 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
2007-07-19 12:47:03 +04:00
* XXX : how are we excluding truncate / invalidate here ? Maybe need to lock
* page ?
2005-04-17 02:20:36 +04:00
*/
2007-07-19 12:47:03 +04:00
static int ncp_file_mmap_fault ( struct vm_area_struct * area ,
struct vm_fault * vmf )
2005-04-17 02:20:36 +04:00
{
struct file * file = area - > vm_file ;
2006-12-08 13:37:22 +03:00
struct dentry * dentry = file - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
char * pg_addr ;
unsigned int already_read ;
unsigned int count ;
int bufsize ;
2007-07-19 12:47:03 +04:00
int pos ; /* XXX: loff_t ? */
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:03 +04:00
/*
* ncpfs has nothing against high pages as long
* as recvmsg and memset works on it
*/
vmf - > page = alloc_page ( GFP_HIGHUSER ) ;
if ( ! vmf - > page )
return VM_FAULT_OOM ;
pg_addr = kmap ( vmf - > page ) ;
pos = vmf - > pgoff < < PAGE_SHIFT ;
2005-04-17 02:20:36 +04:00
count = PAGE_SIZE ;
/* 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 ) ;
2007-07-19 12:47:03 +04:00
flush_dcache_page ( vmf - > page ) ;
kunmap ( vmf - > page ) ;
2005-04-17 02:20:36 +04:00
/*
* If I understand ncp_read_kernel ( ) properly , the above always
* fetches from the network , here the analogue of disk .
* - - wli
*/
2006-06-30 12:55:45 +04:00
count_vm_event ( PGMAJFAULT ) ;
2007-07-19 12:47:03 +04:00
return VM_FAULT_MAJOR ;
2005-04-17 02:20:36 +04:00
}
static struct vm_operations_struct ncp_file_mmap =
{
2007-07-19 12:46:59 +04:00
. fault = ncp_file_mmap_fault ,
2005-04-17 02:20:36 +04:00
} ;
/* This is used for a general mmap of a ncp file */
int ncp_mmap ( struct file * file , struct vm_area_struct * vma )
{
2006-12-08 13:37:22 +03:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
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 4 GB . . . */
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 ;
}