root/fs/proc/mem.c

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

DEFINITIONS

This source file includes following definitions.
  1. mem_read
  2. mem_write
  3. mem_lseek
  4. mem_mmap

   1 /*
   2  *  linux/fs/proc/mem.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/types.h>
   8 #include <linux/errno.h>
   9 #include <linux/sched.h>
  10 #include <linux/kernel.h>
  11 #include <linux/mm.h>
  12 
  13 #include <asm/page.h>
  14 #include <asm/segment.h>
  15 #include <asm/io.h>
  16 
  17 /*
  18  * mem_write isn't really a good idea right now. It needs
  19  * to check a lot more: if the process we try to write to 
  20  * dies in the middle right now, mem_write will overwrite
  21  * kernel memory.. This disables it altogether.
  22  */
  23 #define mem_write NULL
  24 
  25 static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  26 {
  27         struct task_struct * tsk;
  28         unsigned long addr, pid;
  29         char *tmp;
  30         unsigned long pte, page;
  31         int i;
  32 
  33         if (count < 0)
  34                 return -EINVAL;
  35         pid = inode->i_ino;
  36         pid >>= 16;
  37         tsk = NULL;
  38         for (i = 1 ; i < NR_TASKS ; i++)
  39                 if (task[i] && task[i]->pid == pid) {
  40                         tsk = task[i];
  41                         break;
  42                 }
  43         if (!tsk)
  44                 return -EACCES;
  45         addr = file->f_pos;
  46         tmp = buf;
  47         while (count > 0) {
  48                 if (current->signal & ~current->blocked)
  49                         break;
  50                 pte = *PAGE_DIR_OFFSET(tsk,addr);
  51                 if (!(pte & PAGE_PRESENT))
  52                         break;
  53                 pte &= PAGE_MASK;
  54                 pte += PAGE_PTR(addr);
  55                 page = *(unsigned long *) pte;
  56                 if (!(page & 1))
  57                         break;
  58                 page &= PAGE_MASK;
  59                 page += addr & ~PAGE_MASK;
  60                 i = PAGE_SIZE-(addr & ~PAGE_MASK);
  61                 if (i > count)
  62                         i = count;
  63                 memcpy_tofs(tmp,(void *) page,i);
  64                 addr += i;
  65                 tmp += i;
  66                 count -= i;
  67         }
  68         file->f_pos = addr;
  69         return tmp-buf;
  70 }
  71 
  72 #ifndef mem_write
  73 
  74 static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76         struct task_struct * tsk;
  77         unsigned long addr, pid;
  78         char *tmp;
  79         unsigned long pte, page;
  80         int i;
  81 
  82         if (count < 0)
  83                 return -EINVAL;
  84         addr = file->f_pos;
  85         pid = inode->i_ino;
  86         pid >>= 16;
  87         tsk = NULL;
  88         for (i = 1 ; i < NR_TASKS ; i++)
  89                 if (task[i] && task[i]->pid == pid) {
  90                         tsk = task[i];
  91                         break;
  92                 }
  93         if (!tsk)
  94                 return -EACCES;
  95         tmp = buf;
  96         while (count > 0) {
  97                 if (current->signal & ~current->blocked)
  98                         break;
  99                 pte = *PAGE_DIR_OFFSET(tsk,addr);
 100                 if (!(pte & PAGE_PRESENT))
 101                         break;
 102                 pte &= PAGE_MASK;
 103                 pte += PAGE_PTR(addr);
 104                 page = *(unsigned long *) pte;
 105                 if (!(page & PAGE_PRESENT))
 106                         break;
 107                 if (!(page & 2)) {
 108                         do_wp_page(0,addr,current,0);
 109                         continue;
 110                 }
 111                 page &= PAGE_MASK;
 112                 page += addr & ~PAGE_MASK;
 113                 i = PAGE_SIZE-(addr & ~PAGE_MASK);
 114                 if (i > count)
 115                         i = count;
 116                 memcpy_fromfs((void *) page,tmp,i);
 117                 addr += i;
 118                 tmp += i;
 119                 count -= i;
 120         }
 121         file->f_pos = addr;
 122         if (tmp != buf)
 123                 return tmp-buf;
 124         if (current->signal & ~current->blocked)
 125                 return -ERESTARTSYS;
 126         return 0;
 127 }
 128 
 129 #endif
 130 
 131 static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133         switch (orig) {
 134                 case 0:
 135                         file->f_pos = offset;
 136                         return file->f_pos;
 137                 case 1:
 138                         file->f_pos += offset;
 139                         return file->f_pos;
 140                 default:
 141                         return -EINVAL;
 142         }
 143 }
 144 
 145 int
 146 mem_mmap(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 147              struct vm_area_struct * vma)
 148 {
 149   struct task_struct *tsk;
 150   unsigned long *src_table, *dest_table, stmp, dtmp;
 151   struct vm_area_struct *src_vma = 0;
 152   int i;
 153 
 154   /* Get the source's task information */
 155 
 156   tsk = NULL;
 157   for (i = 1 ; i < NR_TASKS ; i++)
 158     if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
 159       tsk     = task[i];
 160       src_vma = task[i]->mm->mmap;
 161       break;
 162     }
 163 
 164   if (!tsk)
 165     return -EACCES;
 166 
 167 /* Ensure that we have a valid source area.  (Has to be mmap'ed and
 168    have valid page information.)  We can't map shared memory at the
 169    moment because working out the vm_area_struct & nattach stuff isn't
 170    worth it. */
 171 
 172   stmp = vma->vm_offset;
 173   while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
 174     while (src_vma && stmp > src_vma->vm_end)
 175       src_vma = src_vma->vm_next;
 176     if (!src_vma || (src_vma->vm_flags & VM_SHM))
 177       return -EINVAL;
 178 
 179     src_table = PAGE_DIR_OFFSET(tsk, stmp);
 180     if (!*src_table)
 181       return -EINVAL;
 182     src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
 183     if (!*src_table)
 184       return -EINVAL;
 185 
 186     if (stmp < src_vma->vm_start) {
 187       if (!(src_vma->vm_flags & VM_GROWSDOWN))
 188         return -EINVAL;
 189       if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
 190         return -EINVAL;
 191     }
 192     stmp += PAGE_SIZE;
 193   }
 194 
 195   src_vma = task[i]->mm->mmap;
 196   stmp    = vma->vm_offset;
 197   dtmp    = vma->vm_start;
 198 
 199   while (dtmp < vma->vm_end) {
 200     while (src_vma && stmp > src_vma->vm_end)
 201       src_vma = src_vma->vm_next;
 202 
 203     src_table = PAGE_DIR_OFFSET(tsk, stmp);
 204     src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
 205 
 206     dest_table = PAGE_DIR_OFFSET(current, dtmp);
 207 
 208     if (!*dest_table) {
 209       *dest_table = get_free_page(GFP_KERNEL);
 210       if (!*dest_table) { oom(current); *dest_table=BAD_PAGE; }
 211       else *dest_table |= PAGE_TABLE;
 212     }
 213     
 214     dest_table = (unsigned long *)((*dest_table & PAGE_MASK) + PAGE_PTR(dtmp));
 215 
 216     if (!(*src_table & PAGE_PRESENT)) 
 217       do_no_page(src_vma, stmp, PAGE_PRESENT);
 218 
 219     if ((vma->vm_flags & VM_WRITE) && !(*src_table & PAGE_RW))
 220       do_wp_page(src_vma, stmp, PAGE_RW | PAGE_PRESENT);
 221 
 222     *src_table |= PAGE_DIRTY;
 223     *dest_table = *src_table;
 224     mem_map[MAP_NR(*src_table)]++;
 225 
 226     stmp += PAGE_SIZE;
 227     dtmp += PAGE_SIZE;
 228   }
 229 
 230   invalidate();
 231   return 0;
 232 }
 233 
 234 static struct file_operations proc_mem_operations = {
 235         mem_lseek,
 236         mem_read,
 237         mem_write,
 238         NULL,           /* mem_readdir */
 239         NULL,           /* mem_select */
 240         NULL,           /* mem_ioctl */
 241         mem_mmap,       /* mmap */
 242         NULL,           /* no special open code */
 243         NULL,           /* no special release code */
 244         NULL            /* can't fsync */
 245 };
 246 
 247 struct inode_operations proc_mem_inode_operations = {
 248         &proc_mem_operations,   /* default base directory file-ops */
 249         NULL,                   /* create */
 250         NULL,                   /* lookup */
 251         NULL,                   /* link */
 252         NULL,                   /* unlink */
 253         NULL,                   /* symlink */
 254         NULL,                   /* mkdir */
 255         NULL,                   /* rmdir */
 256         NULL,                   /* mknod */
 257         NULL,                   /* rename */
 258         NULL,                   /* readlink */
 259         NULL,                   /* follow_link */
 260         NULL,                   /* bmap */
 261         NULL,                   /* truncate */
 262         NULL                    /* permission */
 263 };

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