From: "Jan Beulich" The /dev/mem and /dev/kmem write handlers weren't fully POSIX compliant in that they wouldn't always force the file pointer to be updated when returning success status. The /dev/port write handler was inconsistent with the /dev/mem and /dev/kmem handlers in that when encountering a -EFAULT condition after already having written a number of items it would return -EFAULT rather than the number of bytes written. Signed-off-by: Jan Beulich Signed-off-by: Andrew Morton --- drivers/char/mem.c | 28 +++++++++++++--------------- 1 files changed, 13 insertions(+), 15 deletions(-) diff -puN drivers/char/mem.c~adjust-dev-kmemmemport-write-handlers drivers/char/mem.c --- devel/drivers/char/mem.c~adjust-dev-kmemmemport-write-handlers 2006-03-04 22:05:40.000000000 -0800 +++ devel-akpm/drivers/char/mem.c 2006-03-04 22:16:31.000000000 -0800 @@ -210,11 +210,9 @@ static ssize_t write_mem(struct file * f copied = copy_from_user(ptr, buf, sz); if (copied) { - ssize_t ret; - - ret = written + (sz - copied); - if (ret) - return ret; + written += sz - copied; + if (written) + break; return -EFAULT; } buf += sz; @@ -450,11 +448,9 @@ do_write_kmem(void *p, unsigned long rea copied = copy_from_user(ptr, buf, sz); if (copied) { - ssize_t ret; - - ret = written + (sz - copied); - if (ret) - return ret; + written += sz - copied; + if (written) + break; return -EFAULT; } buf += sz; @@ -508,11 +504,10 @@ static ssize_t write_kmem(struct file * if (len) { written = copy_from_user(kbuf, buf, len); if (written) { - ssize_t ret; - + if (wrote + virtr) + break; free_page((unsigned long)kbuf); - ret = wrote + virtr + (len - written); - return ret ? ret : -EFAULT; + return -EFAULT; } } len = vwrite(kbuf, (char *)p, len); @@ -557,8 +552,11 @@ static ssize_t write_port(struct file * return -EFAULT; while (count-- > 0 && i < 65536) { char c; - if (__get_user(c, tmp)) + if (__get_user(c, tmp)) { + if (tmp > buf) + break; return -EFAULT; + } outb(c,i); i++; tmp++; _