mmap.c 3.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 *  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
N
Nick Piggin 已提交
27 28
 * XXX: how are we excluding truncate/invalidate here? Maybe need to lock
 * page?
L
Linus Torvalds 已提交
29
 */
N
Nick Piggin 已提交
30 31
static int ncp_file_mmap_fault(struct vm_area_struct *area,
					struct vm_fault *vmf)
L
Linus Torvalds 已提交
32 33
{
	struct file *file = area->vm_file;
J
Josef Sipek 已提交
34
	struct dentry *dentry = file->f_path.dentry;
L
Linus Torvalds 已提交
35 36 37 38 39
	struct inode *inode = dentry->d_inode;
	char *pg_addr;
	unsigned int already_read;
	unsigned int count;
	int bufsize;
N
Nick Piggin 已提交
40
	int pos; /* XXX: loff_t ? */
L
Linus Torvalds 已提交
41

N
Nick Piggin 已提交
42 43 44 45 46 47 48 49 50
	/*
	 * 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;
L
Linus Torvalds 已提交
51 52

	count = PAGE_SIZE;
N
Nick Piggin 已提交
53
	if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
54
		WARN_ON(1); /* shouldn't happen? */
N
Nick Piggin 已提交
55
		count = area->vm_end - (unsigned long)vmf->virtual_address;
L
Linus Torvalds 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
	}
	/* 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);
N
Nick Piggin 已提交
90 91
	flush_dcache_page(vmf->page);
	kunmap(vmf->page);
L
Linus Torvalds 已提交
92 93 94 95 96 97

	/*
	 * If I understand ncp_read_kernel() properly, the above always
	 * fetches from the network, here the analogue of disk.
	 * -- wli
	 */
98
	count_vm_event(PGMAJFAULT);
N
Nick Piggin 已提交
99
	return VM_FAULT_MAJOR;
L
Linus Torvalds 已提交
100 101 102 103
}

static struct vm_operations_struct ncp_file_mmap =
{
104
	.fault = ncp_file_mmap_fault,
L
Linus Torvalds 已提交
105 106 107 108 109 110
};


/* This is used for a general mmap of a ncp file */
int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
J
Josef Sipek 已提交
111
	struct inode *inode = file->f_path.dentry->d_inode;
L
Linus Torvalds 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	
	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;
}