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

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