printk: /dev/kmsg - properly support writev() to avoid interleaved printk() lines
From: Kay Sievers <[email protected]>
printk: /dev/kmsg - properly support writev() to avoid interleaved printk lines
We should avoid calling printk() in a loop, when we pass a single string to /dev/kmsg with writev().
Cc Lennart Poettering <[email protected]>
Signed-off-by Kay Sievers <[email protected]>
--- mem.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-)
drivers/char/mem.c +26 -15
@@ -806,29 +806,40 @@ static const struct file_operations oldmem_fops = { };#endif -static ssize_t kmsg_write (struct file *file,const char __user *buf, -size_t count,loff_t *ppos) +static ssize_t kmsg_writev (struct kiocb *iocb,const struct iovec *iv, +unsigned long count,loff_t pos) { -char *tmp; -ssize_t ret; +char *line, *p; +int len, i; +ssize_t ret = -EFAULT ; - tmp =kmalloc (count +1 ,GFP_KERNEL ); -if (tmp ==NULL ) + len =iov_length (iv, count); + line = p =kmalloc (len +1 ,GFP_KERNEL ); +if (line ==NULL )return -ENOMEM ; - ret = -EFAULT ; -if (!copy_from_user (tmp, buf, count)) { - tmp[count] =0 ; - ret =printk ("%s" , tmp); -if (ret > count) -/* printk can add a prefix */ - ret = count; + +/* +* copy all vectors into a single string, to ensure we do +* not interleave our log line with other printk calls +*/ +for (i =0 ; i < count; i++) { +if (copy_from_user (p, iv[i].iov_base, iv[i].iov_len)) + goto out; + p += iv[i].iov_len; } -kfree (tmp); + p[0 ] ='\0' ; + + ret =printk ("%s" , line); +/* printk can add a prefix */ +if (ret > len) + ret = len; +out: +kfree (line);return ret; }static const struct file_operations kmsg_fops = { - .write = kmsg_write, + .aio_write = kmsg_writev, .llseek = noop_llseek, };
Quoted 56 lines · On Thu, 07 Apr 2011 04:29:20 +0200 Kay Sievers <[email protected]> wrote:
From: Kay Sievers <[email protected]>
printk:
/dev/kmsg- properly supportwritev()to avoid interleaved printk linesWe should avoid calling
printk()in a loop, when we pass a single string to/dev/kmsgwithwritev()....
drivers/char/mem.c +24
-14@@ -806,29 +806,40 @@ static const struct file_operations oldmem_fops = { };#endif -static ssize_t kmsg_write (struct file *file,const char __user *buf, -size_t count,loff_t *ppos) +static ssize_t kmsg_writev (struct kiocb *iocb,const struct iovec *iv, +unsigned long count,loff_t pos) { -char *tmp; -ssize_t ret; +char *line, *p; +int len, i; +ssize_t ret = -EFAULT ; - tmp =kmalloc (count +1 ,GFP_KERNEL ); -if (tmp ==NULL ) + len =iov_length (iv, count); + line = p =kmalloc (len +1 ,GFP_KERNEL ); +if (line ==NULL )return -ENOMEM ; - ret = -EFAULT ; -if (!copy_from_user (tmp, buf, count)) { - tmp[count] =0 ; - ret =printk ("%s" , tmp); -if (ret > count) -/* printk can add a prefix */ - ret = count; + +/* +* copy all vectors into a single string, to ensure we do +* not interleave our log line with other printk calls +*/ +for (i =0 ; i < count; i++) { +if (copy_from_user (p, iv[i].iov_base, iv[i].iov_len)) + goto out; + p += iv[i].iov_len; } -kfree (tmp); + p[0 ] ='\0' ; + + ret =printk ("%s" , line); +/* printk can add a prefix */ +if (ret > len) + ret = len; +out:
drivers/char/mem.c static const struct file_operations oldmem_fops = { · line 845
Quoted 10 lines
drivers/char/mem.c +2
-1+kfree (line);return ret; }static const struct file_operations kmsg_fops = { - .write = kmsg_write, + .aio_write = kmsg_writev, .llseek = noop_llseek, };
LGTM. Nitpicks:
From: Andrew Morton <[email protected]>
make `len' size_t, avoid multiple-assignments.
Cc Greg KH <[email protected]>
Cc Kay Sievers <[email protected]>
Cc Lennart Poettering <[email protected]>
Signed-off-by Andrew Morton <[email protected]>
---
drivers/char/mem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/char/mem.c renamed from drivers/char/mem.c~dev-kmsg-properly-support-writev-to-avoid-interleaved-printk-lines-fix +4 -3
@@ -810,11 +810,11 @@ static ssize_t kmsg_writev(struct kiocb unsigned long count, loff_t pos) { char *line, *p; -int len, i; +int i;ssize_t ret = -EFAULT ; +size_t len =iov_length (iv, count); - len =iov_length (iv, count); - line = p =kmalloc (len +1 ,GFP_KERNEL ); + line =kmalloc (len +1 ,GFP_KERNEL );if (line ==NULL )return -ENOMEM ;
@@ -822,6 +822,7 @@ static ssize_t kmsg_writev(struct kiocb* copy all vectors into a single string, to ensure we do * not interleave our log line with other printk calls */ + p = line;for (i =0 ; i < count; i++) {if (copy_from_user (p, iv[i].iov_base, iv[i].iov_len)) goto out;
_