diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2011-04-07 04:29:20 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-04-19 16:59:58 -0700 |
commit | 7e5b58bcbcb3d7518389c1d82fb6e926f5a9f72c (patch) | |
tree | a4096c1355beb0bfcdc9ea8bb041c3a7da1149b2 /drivers/char | |
parent | 47296b1962ead8301488f0dbe8424c7db7eac635 (diff) |
printk: /dev/kmsg - properly support writev() to avoid interleaved printk() lines
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 <lennart@poettering.net>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/mem.c | 41 |
1 files changed, 26 insertions, 15 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 436a9901799..78923a9f534 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -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, }; |