From 7e5b58bcbcb3d7518389c1d82fb6e926f5a9f72c Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 7 Apr 2011 04:29:20 +0200 Subject: 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 Signed-off-by: Kay Sievers Cc: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 436a99017998..78923a9f5345 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, }; -- cgit v1.2.3-58-ga151 From 70a5f52165bd04cf3b33f30d5d234be28dcf29d4 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 12 Apr 2011 16:13:31 -0700 Subject: kmsg: properly support writev to avoid interleaved printk lines fix make `len' size_t, avoid multiple-assignments. Cc: Kay Sievers Cc: Lennart Poettering Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 78923a9f5345..8fc04b4f311f 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -810,11 +810,11 @@ static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, 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 *iocb, const struct iovec *iv, * 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; -- cgit v1.2.3-58-ga151 From 0078bff5283d1fd6417b840eda6dab912b7a5560 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 29 Apr 2011 00:24:29 +0200 Subject: Allow setting of number of raw devices as a module parameter Allow setting of maximal number of raw devices as a module parameter. This requires changing of static array into a vmalloced one (the array is going to be too large for kmalloc). Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- drivers/char/Kconfig | 2 +- drivers/char/raw.c | 33 +++++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ad59b4e0a9b5..49502bc5360a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -523,7 +523,7 @@ config RAW_DRIVER with the O_DIRECT flag. config MAX_RAW_DEVS - int "Maximum number of RAW devices to support (1-8192)" + int "Maximum number of RAW devices to support (1-65536)" depends on RAW_DRIVER default "256" help diff --git a/drivers/char/raw.c b/drivers/char/raw.c index b4b9d5a47885..6f9db621155a 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -30,10 +31,15 @@ struct raw_device_data { }; static struct class *raw_class; -static struct raw_device_data raw_devices[MAX_RAW_MINORS]; +static struct raw_device_data *raw_devices; static DEFINE_MUTEX(raw_mutex); static const struct file_operations raw_ctl_fops; /* forward declaration */ +static int max_raw_minors = MAX_RAW_MINORS; + +module_param(max_raw_minors, int, 0); +MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)"); + /* * Open/close code for raw IO. * @@ -125,7 +131,7 @@ static int bind_set(int number, u64 major, u64 minor) struct raw_device_data *rawdev; int err = 0; - if (number <= 0 || number >= MAX_RAW_MINORS) + if (number <= 0 || number >= max_raw_minors) return -EINVAL; if (MAJOR(dev) != major || MINOR(dev) != minor) @@ -312,12 +318,26 @@ static int __init raw_init(void) dev_t dev = MKDEV(RAW_MAJOR, 0); int ret; - ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw"); + if (max_raw_minors < 1 || max_raw_minors > 65536) { + printk(KERN_WARNING "raw: invalid max_raw_minors (must be" + " between 1 and 65536), using %d\n", MAX_RAW_MINORS); + max_raw_minors = MAX_RAW_MINORS; + } + + raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors); + if (!raw_devices) { + printk(KERN_ERR "Not enough memory for raw device structures\n"); + ret = -ENOMEM; + goto error; + } + memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors); + + ret = register_chrdev_region(dev, max_raw_minors, "raw"); if (ret) goto error; cdev_init(&raw_cdev, &raw_fops); - ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS); + ret = cdev_add(&raw_cdev, dev, max_raw_minors); if (ret) { kobject_put(&raw_cdev.kobj); goto error_region; @@ -336,8 +356,9 @@ static int __init raw_init(void) return 0; error_region: - unregister_chrdev_region(dev, MAX_RAW_MINORS); + unregister_chrdev_region(dev, max_raw_minors); error: + vfree(raw_devices); return ret; } @@ -346,7 +367,7 @@ static void __exit raw_exit(void) device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); class_destroy(raw_class); cdev_del(&raw_cdev); - unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); + unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors); } module_init(raw_init); -- cgit v1.2.3-58-ga151 From 9333744dc7dcd85531cff13cabf1d5d6baf18e7d Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 4 May 2011 05:19:34 -0400 Subject: RAW driver: Remove call to kobject_put(). If cdev_add() fails, there is no justification for subsequently calling kobject_put(). Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman --- drivers/char/raw.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/char') diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 6f9db621155a..b33e8ea314ed 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -339,7 +339,6 @@ static int __init raw_init(void) cdev_init(&raw_cdev, &raw_fops); ret = cdev_add(&raw_cdev, dev, max_raw_minors); if (ret) { - kobject_put(&raw_cdev.kobj); goto error_region; } -- cgit v1.2.3-58-ga151