All of lore.kernel.org
 help / color / mirror / Atom feed
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(&reg->lock);
> +}
> +
> +static inline void lcdreg_unlock(struct lcdreg *reg)
> +{
> +	mutex_unlock(&reg->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

  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.