Commit a3245879 authored by Dave Jones's avatar Dave Jones Committed by Linus Torvalds

[PATCH] Support /dev/kmem access to vmalloc space (Marc Boucher)

From 2.4.17
parent 16d6f850
...@@ -273,6 +273,8 @@ static ssize_t read_kmem(struct file *file, char *buf, ...@@ -273,6 +273,8 @@ static ssize_t read_kmem(struct file *file, char *buf,
return virtr + read; return virtr + read;
} }
extern long vwrite(char *buf, char *addr, unsigned long count);
/* /*
* This function writes to the *virtual* memory as seen by the kernel. * This function writes to the *virtual* memory as seen by the kernel.
*/ */
...@@ -280,12 +282,46 @@ static ssize_t write_kmem(struct file * file, const char * buf, ...@@ -280,12 +282,46 @@ static ssize_t write_kmem(struct file * file, const char * buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
unsigned long p = *ppos; unsigned long p = *ppos;
ssize_t wrote = 0;
ssize_t virtr = 0;
char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
if (p >= (unsigned long) high_memory) if (p < (unsigned long) high_memory) {
return 0; wrote = count;
if (count > (unsigned long) high_memory - p) if (count > (unsigned long) high_memory - p)
count = (unsigned long) high_memory - p; wrote = (unsigned long) high_memory - p;
return do_write_mem(file, (void*)p, p, buf, count, ppos);
wrote = do_write_mem(file, (void*)p, p, buf, wrote, ppos);
p += wrote;
buf += wrote;
count -= wrote;
}
if (count > 0) {
kbuf = (char *)__get_free_page(GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
while (count > 0) {
int len = count;
if (len > PAGE_SIZE)
len = PAGE_SIZE;
if (len && copy_from_user(kbuf, buf, len)) {
free_page((unsigned long)kbuf);
return -EFAULT;
}
len = vwrite(kbuf, (char *)p, len);
count -= len;
buf += len;
virtr += len;
p += len;
}
free_page((unsigned long)kbuf);
}
*ppos = p;
return virtr + wrote;
} }
#if !defined(__mc68000__) #if !defined(__mc68000__)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000 * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian <tigran@veritas.com>, May 2000
*/ */
#include <linux/config.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -163,6 +164,7 @@ inline int vmalloc_area_pages (unsigned long address, unsigned long size, ...@@ -163,6 +164,7 @@ inline int vmalloc_area_pages (unsigned long address, unsigned long size,
ret = 0; ret = 0;
} while (address && (address < end)); } while (address && (address < end));
spin_unlock(&init_mm.page_table_lock); spin_unlock(&init_mm.page_table_lock);
flush_cache_all();
return ret; return ret;
} }
...@@ -282,3 +284,40 @@ long vread(char *buf, char *addr, unsigned long count) ...@@ -282,3 +284,40 @@ long vread(char *buf, char *addr, unsigned long count)
read_unlock(&vmlist_lock); read_unlock(&vmlist_lock);
return buf - buf_start; return buf - buf_start;
} }
long vwrite(char *buf, char *addr, unsigned long count)
{
struct vm_struct *tmp;
char *vaddr, *buf_start = buf;
unsigned long n;
/* Don't allow overflow */
if ((unsigned long) addr + count < count)
count = -(unsigned long) addr;
read_lock(&vmlist_lock);
for (tmp = vmlist; tmp; tmp = tmp->next) {
vaddr = (char *) tmp->addr;
if (addr >= vaddr + tmp->size - PAGE_SIZE)
continue;
while (addr < vaddr) {
if (count == 0)
goto finished;
buf++;
addr++;
count--;
}
n = vaddr + tmp->size - PAGE_SIZE - addr;
do {
if (count == 0)
goto finished;
*addr = *buf;
buf++;
addr++;
count--;
} while (--n > 0);
}
finished:
read_unlock(&vmlist_lock);
return buf - buf_start;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment