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

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