patch-2.4.17 linux/drivers/char/mem.c

Next file: linux/drivers/char/pcmcia/serial_cs.c
Previous file: linux/drivers/char/joystick/pcigame.c
Back to the patch index
Back to the overall index

diff -Naur -X /home/marcelo/lib/dontdiff linux-2.4.16/drivers/char/mem.c linux/drivers/char/mem.c
@@ -272,6 +272,8 @@
  	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.
  */
@@ -279,12 +281,46 @@
 			  size_t count, loff_t *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) {
+		wrote = count;
+		if (count > (unsigned long) high_memory - p)
+			wrote = (unsigned long) high_memory - p;
+
+		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);
+	}
 
-	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);
+ 	*ppos = p;
+ 	return virtr + wrote;
 }
 
 #if !defined(__mc68000__)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)