diff -urN -X dontdiff linux/drivers/char/mem.c vwrite/drivers/char/mem.c --- linux/drivers/char/mem.c Sat Jun 24 12:44:26 2000 +++ vwrite/drivers/char/mem.c Fri Aug 11 15:39:40 2000 @@ -288,12 +288,54 @@ size_t count, loff_t *ppos) { unsigned long p = *ppos; + ssize_t write = 0; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ - if (p >= (unsigned long) high_memory) - return 0; - if (count > (unsigned long) high_memory - p) - count = (unsigned long) high_memory - p; - return do_write_mem(file, (void*)p, p, buf, count, ppos); + if (p < (unsigned long) high_memory) { + write = count; + if (count > (unsigned long) high_memory - p) + write = (unsigned long) high_memory - p; + +#if defined(__sparc__) || defined(__mc68000__) + /* we don't have page 0 mapped on sparc and m68k.. */ + if (p < PAGE_SIZE && write > 0) { + size_t tmp = PAGE_SIZE - p; + if (tmp > write) tmp = write; + buf += tmp; + p += tmp; + write -= tmp; + count -= tmp; + } +#endif + if (copy_from_user((char *)p, buf, write)) + return -EFAULT; + p += write; + buf += write; + count -= write; + } + + 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 + write; } #if !defined(__mc68000__) diff -urN -X dontdiff linux/include/linux/vmalloc.h vwrite/include/linux/vmalloc.h --- linux/include/linux/vmalloc.h Tue Jul 11 19:26:51 2000 +++ vwrite/include/linux/vmalloc.h Fri Aug 11 15:44:58 2000 @@ -22,6 +22,7 @@ extern void vfree(void * addr); extern void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot); extern long vread(char *buf, char *addr, unsigned long count); +extern long vwrite(char *buf, char *addr, unsigned long count); extern void vmfree_area_pages(unsigned long address, unsigned long size); extern int vmalloc_area_pages(unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot); diff -urN -X dontdiff linux/mm/vmalloc.c vwrite/mm/vmalloc.c --- linux/mm/vmalloc.c Thu Aug 10 06:51:12 2000 +++ vwrite/mm/vmalloc.c Fri Aug 11 15:39:40 2000 @@ -4,6 +4,7 @@ * Copyright (C) 1993 Linus Torvalds * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian , May 2000 + * vwrite for write_kmem, Amit S. Kale , May 2000 */ #include @@ -263,6 +264,43 @@ if (count == 0) goto finished; *buf = *addr; + buf++; + addr++; + count--; + } while (--n > 0); + } +finished: + read_unlock(&vmlist_lock); + 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--;