--- ./drivers/char/mem.c.fix 2004-03-23 16:40:49.000000000 +0100 +++ ./drivers/char/mem.c 2004-03-25 20:01:05.000000000 +0100 @@ -105,35 +105,62 @@ static inline int valid_phys_addr_range( static ssize_t do_write_mem(void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) { - ssize_t written; - unsigned long copied; + ssize_t written = 0; + unsigned long uncopied; - written = 0; #if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU)) /* we don't have page 0 mapped on sparc and m68k.. */ if (realp < PAGE_SIZE) { - unsigned long sz = PAGE_SIZE-realp; - if (sz > count) sz = count; + unsigned long sz = PAGE_SIZE - realp; + if (sz > count) + sz = count; /* Hmm. Do something? */ - buf+=sz; - p+=sz; - count-=sz; - written+=sz; + buf += sz; + p += sz; + count -= sz; + written += sz; } #endif - copied = copy_from_user(p, buf, count); - if (copied) { - ssize_t ret = written + (count - copied); - - if (ret) - return ret; - return -EFAULT; + uncopied = copy_from_user(p, buf, count); + if (uncopied) { + ssize_t ret = written + (count - uncopied); + return ret ? ret : -EFAULT; } written += count; *ppos += written; return written; } +static ssize_t do_read_mem(void *p, unsigned long realp, + char * buf, size_t count, loff_t *ppos) +{ + ssize_t read = 0; + unsigned long uncopied; + +#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU)) + /* we don't have page 0 mapped on sparc and m68k.. */ + if (realp < PAGE_SIZE) { + size_t sz = PAGE_SIZE - realp; + if (sz > count) + sz = count; + if (clear_user(buf, sz)) + return -EFAULT; + buf += sz; + p += sz; + count -= sz; + read += sz; + } +#endif + uncopied = copy_to_user(buf, (char *)p, count); + if (uncopied) { + ssize_t ret = read + (count - uncopied); + return ret ? ret : -EFAULT; + } + read += count; + *ppos += read; + return read; +} + /* * This funcion reads the *physical* memory. The f_pos points directly to the @@ -143,32 +170,10 @@ static ssize_t read_mem(struct file * fi size_t count, loff_t *ppos) { unsigned long p = *ppos; - ssize_t read; if (!valid_phys_addr_range(p, &count)) return -EFAULT; - read = 0; -#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU)) - /* we don't have page 0 mapped on sparc and m68k.. */ - if (p < PAGE_SIZE) { - unsigned long sz = PAGE_SIZE-p; - if (sz > count) - sz = count; - if (sz > 0) { - if (clear_user(buf, sz)) - return -EFAULT; - buf += sz; - p += sz; - count -= sz; - read += sz; - } - } -#endif - if (copy_to_user(buf, __va(p), count)) - return -EFAULT; - read += count; - *ppos += read; - return read; + return do_read_mem(__va(p), p, buf, count, ppos); } static ssize_t write_mem(struct file * file, const char * buf, @@ -222,25 +227,14 @@ static ssize_t read_kmem(struct file *fi char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ if (p < (unsigned long) high_memory) { - read = count; + ssize_t toread = count; if (count > (unsigned long) high_memory - p) - read = (unsigned long) high_memory - p; + toread = (unsigned long) high_memory - p; + + read = do_read_mem((void*)p, p, buf, toread, ppos); + if (read != toread) + return read; -#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU)) - /* we don't have page 0 mapped on sparc and m68k.. */ - if (p < PAGE_SIZE && read > 0) { - size_t tmp = PAGE_SIZE - p; - if (tmp > read) tmp = read; - if (clear_user(buf, tmp)) - return -EFAULT; - buf += tmp; - p += tmp; - read -= tmp; - count -= tmp; - } -#endif - if (copy_to_user(buf, (char *)p, read)) - return -EFAULT; p += read; buf += read; count -= read; @@ -252,15 +246,20 @@ static ssize_t read_kmem(struct file *fi return -ENOMEM; while (count > 0) { int len = count; + ssize_t unwritten; if (len > PAGE_SIZE) len = PAGE_SIZE; len = vread(kbuf, (char *)p, len); if (!len) break; - if (copy_to_user(buf, kbuf, len)) { + unwritten = copy_to_user(buf, kbuf, len); + if (unwritten != 0) { + ssize_t ret; + free_page((unsigned long)kbuf); - return -EFAULT; + ret = read + virtr + (len - unwritten); + return ret ? ret : -EFAULT; } count -= len; buf += len; @@ -282,19 +281,19 @@ static ssize_t write_kmem(struct file * unsigned long p = *ppos; ssize_t wrote = 0; ssize_t virtr = 0; - ssize_t written; char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ if (p < (unsigned long) high_memory) { + ssize_t towrite; - wrote = count; + towrite = count; if (count > (unsigned long) high_memory - p) - wrote = (unsigned long) high_memory - p; + towrite = (unsigned long) high_memory - p; + + wrote = do_write_mem((void*)p, p, buf, towrite, ppos); + if (wrote != towrite) + return wrote; - written = do_write_mem((void*)p, p, buf, wrote, ppos); - if (written != wrote) - return written; - wrote = written; p += wrote; buf += wrote; count -= wrote; @@ -310,12 +309,12 @@ static ssize_t write_kmem(struct file * if (len > PAGE_SIZE) len = PAGE_SIZE; if (len) { - written = copy_from_user(kbuf, buf, len); - if (written != len) { + ssize_t unwritten = copy_from_user(kbuf, buf, len); + if (unwritten != 0) { ssize_t ret; free_page((unsigned long)kbuf); - ret = wrote + virtr + (len - written); + ret = wrote + virtr + (len - unwritten); return ret ? ret : -EFAULT; } }