root/fs/nfs/mmap.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_mmap
  2. nfs_file_mmap_nopage

   1 /*
   2  *      fs/nfs/mmap.c   by Jon Tombs 15 Aug 1993
   3  *
   4  * This code is from
   5  *      linux/mm/mmap.c which was written by obz, Linus and Eric
   6  * and
   7  *      linux/mm/memory.c  by Linus Torvalds and others
   8  *
   9  *      Copyright (C) 1993
  10  *
  11  */
  12 #include <linux/stat.h>
  13 #include <linux/sched.h>
  14 #include <linux/kernel.h>
  15 #include <linux/mm.h>
  16 #include <linux/shm.h>
  17 #include <linux/errno.h>
  18 #include <linux/mman.h>
  19 #include <linux/string.h>
  20 #include <linux/malloc.h>
  21 #include <linux/nfs_fs.h>
  22 
  23 #include <asm/segment.h>
  24 #include <asm/system.h>
  25 
  26 extern int share_page(struct vm_area_struct * area, struct task_struct * tsk,
  27         struct inode * inode, unsigned long address, unsigned long error_code,
  28         unsigned long newpage);
  29 
  30 extern unsigned long put_page(struct task_struct * tsk,unsigned long page,
  31         unsigned long address,int prot);
  32 
  33 static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
  34                                 unsigned long address);
  35 
  36 extern void file_mmap_free(struct vm_area_struct * area);
  37 extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
  38                                 unsigned long address);
  39 
  40 struct vm_operations_struct nfs_file_mmap = {
  41         NULL,                   /* open */
  42         file_mmap_free,         /* close */
  43         nfs_file_mmap_nopage,   /* nopage */
  44         NULL,                   /* wppage */
  45         file_mmap_share,        /* share */
  46         NULL,                   /* unmap */
  47 };
  48 
  49 
  50 /* This is used for a general mmap of a nfs file */
  51 int nfs_mmap(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
  52         unsigned long addr, size_t len, int prot, unsigned long off)
  53 {
  54         struct vm_area_struct * mpnt;
  55 
  56         if (prot & PAGE_RW)     /* only PAGE_COW or read-only supported now */
  57                 return -EINVAL;
  58         if (off & (inode->i_sb->s_blocksize - 1))
  59                 return -EINVAL;
  60         if (!inode->i_sb || !S_ISREG(inode->i_mode))
  61                 return -EACCES;
  62         if (!IS_RDONLY(inode)) {
  63                 inode->i_atime = CURRENT_TIME;
  64                 inode->i_dirt = 1;
  65         }
  66 
  67         mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
  68         if (!mpnt)
  69                 return -ENOMEM;
  70 
  71         unmap_page_range(addr, len);
  72         mpnt->vm_task = current;
  73         mpnt->vm_start = addr;
  74         mpnt->vm_end = addr + len;
  75         mpnt->vm_page_prot = prot;
  76         mpnt->vm_flags = 0;
  77         mpnt->vm_share = NULL;
  78         mpnt->vm_inode = inode;
  79         inode->i_count++;
  80         mpnt->vm_offset = off;
  81         mpnt->vm_ops = &nfs_file_mmap;
  82         insert_vm_struct(current, mpnt);
  83         merge_segments(current->mm->mmap, NULL, NULL);
  84         return 0;
  85 }
  86 
  87 
  88 static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
     /* [previous][next][first][last][top][bottom][index][help] */
  89                                 unsigned long address)
  90 {
  91         struct inode * inode = area->vm_inode;
  92         unsigned int clear;
  93         unsigned long page;
  94         unsigned long tmp;
  95         int n;
  96         int i;
  97         int pos;
  98         struct nfs_fattr fattr;
  99 
 100         address &= PAGE_MASK;
 101         pos = address - area->vm_start + area->vm_offset;
 102 
 103         page = get_free_page(GFP_KERNEL);
 104         if (share_page(area, area->vm_task, inode, address, error_code, page)) {
 105                 ++area->vm_task->mm->min_flt;
 106                 return;
 107         }
 108 
 109         ++area->vm_task->mm->maj_flt;
 110         if (!page) {
 111                 oom(current);
 112                 put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
 113                 return;
 114         }
 115 
 116         clear = 0;
 117         if (address + PAGE_SIZE > area->vm_end) {
 118                 clear = address + PAGE_SIZE - area->vm_end;
 119         }
 120 
 121         n = NFS_SERVER(inode)->rsize; /* what we can read in one go */
 122 
 123         for (i = 0; i < (PAGE_SIZE - clear); i += n) {
 124                 int hunk, result;
 125 
 126                 hunk = PAGE_SIZE - i;
 127                 if (hunk > n)
 128                         hunk = n;
 129                 result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
 130                         pos, hunk, (char *) (page + i), &fattr);
 131                 if (result < 0)
 132                         break;
 133                 pos += result;
 134                 if (result < n) {
 135                         i += result;
 136                         break;
 137                 }
 138         }
 139 
 140 #ifdef doweneedthishere
 141         nfs_refresh_inode(inode, &fattr);
 142 #endif
 143 
 144         if (!(error_code & PAGE_RW)) {
 145                 if (share_page(area, area->vm_task, inode, address, error_code, page))
 146                         return;
 147         }
 148 
 149         tmp = page + PAGE_SIZE;
 150         while (clear--) {
 151                 *(char *)--tmp = 0;
 152         }
 153         if (put_page(area->vm_task,page,address,area->vm_page_prot))
 154                 return;
 155         free_page(page);
 156         oom(current);
 157 }

/* [previous][next][first][last][top][bottom][index][help] */