From: Dan Carpenter <dan.carpenter@oracle.com>
To: "Noralf Trønnes" <noralf@tronnes.org>
Cc: gregkh@linuxfoundation.org, driverdev-devel@linuxdriverproject.org
Subject: Re: [RFC 1/7] staging: fbtft: add lcd register abstraction
Date: Mon, 2 Mar 2015 15:25:57 +0300 [thread overview]
Message-ID: <20150302122557.GI5386@mwanda> (raw)
In-Reply-To: <1425293669-15754-2-git-send-email-noralf@tronnes.org>
On Mon, Mar 02, 2015 at 11:54:23AM +0100, Noralf Trønnes wrote:
> diff --git a/drivers/staging/fbtft/lcdreg/lcdreg-debugfs.c b/drivers/staging/fbtft/lcdreg/lcdreg-debugfs.c
> new file mode 100644
> index 0000000..1cba4c2
> --- /dev/null
> +++ b/drivers/staging/fbtft/lcdreg/lcdreg-debugfs.c
> @@ -0,0 +1,272 @@
> +/*
> + * Copyright (C) 2015 Noralf Trønnes
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/debugfs.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +#include "lcdreg.h"
> +
> +static struct dentry *lcdreg_debugfs_root;
> +
> +static int lcdreg_userbuf_to_u32(const char __user *user_buf, size_t count,
> + u32 *dest, size_t dest_size)
> +{
> + char *buf, *start;
> + unsigned long value;
> + int ret = 0;
> + int i;
> +
> + buf = kmalloc(count, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + if (copy_from_user(buf, user_buf, count)) {
> + kfree(buf);
> + return -EFAULT;
> + }
> + buf[count] = 0;
Off-by-one overflow.
> + for (i = 0; i < count; i++)
> + if (buf[i] == ' ' || buf[i] == '\n')
> + buf[i] = 0;
> + i = 0;
> + start = buf;
> + while (start < buf + count) {
> + if (*start == 0) {
Use '\0' instead of 0.
if (*start == '\0')
> + start++;
> + continue;
> + }
> + if (i == dest_size) {
> + ret = -EFBIG;
> + break;
> + }
> + if (kstrtoul(start, 16, &value)) {
> + ret = -EINVAL;
> + break;
> + }
Consider changing this to:
ret = kstrtou32(start, 16, value);
if (ret)
break;
> + dest[i++] = value;
> + while (*start != 0)
> + start++;
This while loop is not needed because of the if statement earlier.
> + };
> + kfree(buf);
> + if (ret)
> + return ret;
> +
> + return i ? i : -EINVAL;
> +}
> +
> +static ssize_t lcdreg_debugfs_write_file(struct file *file,
> + const char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct lcdreg *reg = file->private_data;
> + int ret;
> + u32 txbuf[128];
> +
> + ret = lcdreg_userbuf_to_u32(user_buf, count, txbuf, ARRAY_SIZE(txbuf));
> + if (ret <= 0)
> + return -EINVAL;
This function can't return zero so preserve the error code.
if (ret < 0)
return ret;
> +
> + add_taint(TAINT_USER, LOCKDEP_STILL_OK);
> +
> + lcdreg_lock(reg);
> + ret = lcdreg_write_buf32(reg, txbuf[0], txbuf + 1, ret - 1);
> + lcdreg_unlock(reg);
> +
> + return ret ? ret : count;
> +}
> +
> +static const struct file_operations lcdreg_debugfs_write_fops = {
> + .open = simple_open,
> + .write = lcdreg_debugfs_write_file,
> + .llseek = default_llseek,
> +};
> +
> +static ssize_t lcdreg_debugfs_read_wr(struct file *file,
> + const char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct lcdreg *reg = file->private_data;
> + struct lcdreg_transfer tr = {
> + .index = (reg->quirks & LCDREG_INDEX0_ON_READ) ? 0 : 1,
> + .width = reg->debugfs_read_width,
> + .count = 1,
> + };
> + u32 txbuf[1];
> + char *buf = NULL;
> + int ret;
> +
> + ret = lcdreg_userbuf_to_u32(user_buf, count, txbuf, ARRAY_SIZE(txbuf));
> + if (ret != 1)
> + return -EINVAL;
> +
> + tr.buf = kmalloc(lcdreg_bytes_per_word(tr.width), GFP_KERNEL);
> + if (!tr.buf)
> + return -ENOMEM;
> +
> + add_taint(TAINT_USER, LOCKDEP_STILL_OK);
> +
> + lcdreg_lock(reg);
> + ret = lcdreg_read(reg, txbuf[0], &tr);
> + lcdreg_unlock(reg);
> + if (ret)
> + goto error_out;
> +
> + if (!reg->debugfs_read_result) {
> + reg->debugfs_read_result = kmalloc(16, GFP_KERNEL);
> + if (!reg->debugfs_read_result) {
> + ret = -ENOMEM;
> + goto error_out;
> + }
> + }
Allocating here is strange. We only free ->debugfs_read_result on
error so it's sort of buggy as well. Also is it racy if we have
multiple readers and writers at once?
> +
> + buf = reg->debugfs_read_result;
> +
> + switch (tr.width) {
> + case 8:
> + snprintf(buf, 16, "%02x\n", *(u8 *)tr.buf);
> + break;
> + case 16:
> + snprintf(buf, 16, "%04x\n", *(u16 *)tr.buf);
> + break;
> + case 24:
> + case 32:
> + snprintf(buf, 16, "%08x\n", *(u32 *)tr.buf);
> + break;
> + default:
> + ret = -EINVAL;
> + goto error_out;
> + }
> +
> +error_out:
> + kfree(tr.buf);
> + if (ret) {
> + kfree(reg->debugfs_read_result);
> + reg->debugfs_read_result = NULL;
> + return ret;
> + }
> +
> + return count;
It's often cleaner to separate error paths from the success paths. This
is almost an excption because we free (tr.buf) on both paths. But it
would like like this, if you decide to go that way:
kfree(tr.buf);
return 0;
err_free:
kfree(reg->debugfs_read_result);
reg->debugfs_read_result = NULL;
kfree(tr.buf);
return ret;
> +static inline void lcdreg_lock(struct lcdreg *reg)
> +{
> + mutex_lock(®->lock);
> +}
> +
> +static inline void lcdreg_unlock(struct lcdreg *reg)
> +{
> + mutex_unlock(®->lock);
> +}
Don't add abstraction around locking. Everyone hates that. Currently
we don't have any static analysis tools which do cross function locking
analysis correctly. (I am partly to blame for that, sorry). But also
we don't want to have to look it up to see if it a mutex or a spinlock.
> +#if defined(CONFIG_DYNAMIC_DEBUG)
> +
> +#define lcdreg_dbg_transfer_buf(transfer) \
> +do { \
> + int groupsize = lcdreg_bytes_per_word(transfer->width); \
> + size_t len = min_t(size_t, 32, transfer->count * groupsize); \
> + \
> + print_hex_dump_debug(" buf=", DUMP_PREFIX_NONE, 32, \
> + groupsize, transfer->buf, len, false); \
> +} while (0)
> +
> +#elif defined(DEBUG)
> +
> +#define lcdreg_dbg_transfer_buf(transfer) \
> +do { \
> + int groupsize = lcdreg_bytes_per_word(transfer->width); \
> + size_t len = min_t(size_t, 32, transfer->count * groupsize); \
> + \
> + print_hex_dump(KERN_DEBUG, " buf=", DUMP_PREFIX_NONE, 32, \
> + groupsize, transfer->buf, len, false); \
> +} while (0)
I don't understand this. Why can't we use print_hex_dump_debug() for
both? In other words:
#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
...
#else
Also can we make it an inline function?
regards,
dan carpenter
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
next prev parent reply other threads:[~2015-03-02 12:26 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-02 10:54 [RFC 0/7] staging: fbtft: minimize coupling to the fbdev subsystem Noralf Trønnes
2015-03-02 10:54 ` [RFC 1/7] staging: fbtft: add lcd register abstraction Noralf Trønnes
2015-03-02 12:25 ` Dan Carpenter [this message]
2015-03-03 12:19 ` Noralf Trønnes
2015-03-03 12:28 ` Dan Carpenter
2015-03-02 10:54 ` [RFC 2/7] staging: fbtft: lcdreg: add i2c support Noralf Trønnes
2015-03-02 10:54 ` [RFC 3/7] staging: fbtft: add lcd controller abstraction Noralf Trønnes
2015-03-02 11:48 ` Dan Carpenter
2015-03-03 11:57 ` Noralf Trønnes
2015-03-03 12:04 ` Dan Carpenter
2015-03-03 14:08 ` Noralf Trønnes
2015-03-02 10:54 ` [RFC 4/7] staging: fbtft: lcdctrl: add ssd1306 support Noralf Trønnes
2015-03-02 10:54 ` [RFC 5/7] staging: fbtft: don't require platform data Noralf Trønnes
2015-03-02 11:31 ` Dan Carpenter
2015-03-03 11:15 ` Noralf Trønnes
2015-03-02 10:54 ` [RFC 6/7] staging: fbtft: extend core to use lcdctrl Noralf Trønnes
2015-03-02 10:54 ` [RFC 7/7] staging: fbtft: add driver for Adafruit ssd1306 based displays Noralf Trønnes
2015-03-21 18:23 ` [RFC 0/7] staging: fbtft: minimize coupling to the fbdev subsystem Noralf Trønnes
2015-03-21 18:23 ` Noralf Trønnes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150302122557.GI5386@mwanda \
--to=dan.carpenter@oracle.com \
--cc=driverdev-devel@linuxdriverproject.org \
--cc=gregkh@linuxfoundation.org \
--cc=noralf@tronnes.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.