Hold the lock for longer when copying the kernel dmesg buffer.

This function would acquire and release a spinlock for every single byte.
If you used a large buffer size like 8MB, this could make the syslog()
function take more than a second to copy the data.  On our device it was 1.5
seconds; with this change it's reduced to 0.17 seconds.

Change-Id: If63befbe18e4fc215f2e89f5c02dce87ea9064f2

Conflicts:
	kernel/printk.c
diff --git a/kernel/printk.c b/kernel/printk.c
index 94c5fba..ad1a79b 100755
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -350,6 +350,7 @@
 }
 #endif
 
+#define COPY_SIZE 4096
 /*
  * Commands to do_syslog:
  *
@@ -367,6 +368,7 @@
  */
 int do_syslog(int type, char __user *buf, int len)
 {
+	char *copybuf;
 	unsigned i, j, limit, count;
 	int do_clear = 0;
 	char c;
@@ -426,6 +428,11 @@
 			error = -EFAULT;
 			goto out;
 		}
+		copybuf = kmalloc(COPY_SIZE, GFP_KERNEL);
+		if (!copybuf) {
+			error = -ENOMEM;
+			goto out;
+		}
 		count = len;
 		if (count > log_buf_len)
 			count = log_buf_len;
@@ -436,7 +443,7 @@
 			logged_chars = 0;
 		limit = log_end;
 		/*
-		 * __put_user() could sleep, and while we sleep
+		 * copy_to_user() could sleep, and while we sleep
 		 * printk() could overwrite the messages
 		 * we try to copy to user space. Therefore
 		 * the messages are copied in reverse. <manfreds>
@@ -446,14 +453,26 @@
 			if (j + log_buf_len < log_end)
 				break;
 			c = LOG_BUF(j);
-			spin_unlock_irq(&logbuf_lock);
-			error = __put_user(c,&buf[count-1-i]);
-			cond_resched();
-			spin_lock_irq(&logbuf_lock);
+			copybuf[COPY_SIZE-1-(i % COPY_SIZE)] = c;
+			if ((i+1) % COPY_SIZE == 0) {
+				spin_unlock_irq(&logbuf_lock);
+				error = copy_to_user(&buf[count-1-i],
+						copybuf, COPY_SIZE);
+				cond_resched();
+				spin_lock_irq(&logbuf_lock);
+			}
 		}
 		spin_unlock_irq(&logbuf_lock);
-		if (error)
-			break;
+		if (!error) {
+			/* in case copybuf was only partially filled */
+			error = copy_to_user(&buf[count-i],
+				copybuf + COPY_SIZE - (i % COPY_SIZE),
+				i % COPY_SIZE);
+		}
+		if (error) {
+			error = -EFAULT;
+			goto copy_done;
+		}
 		error = i;
 		if (i != count) {
 			int offset = count-error;
@@ -467,6 +486,8 @@
 				cond_resched();
 			}
 		}
+copy_done:
+		kfree(copybuf);
 		break;
 	case 5:		/* Clear ring buffer */
 		logged_chars = 0;