Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70576f90 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "leds: qpnp-flash: Fix possible race condition in debugfs"

parents 6ed191c5 f11ae3df
Loading
Loading
Loading
Loading
+57 −23
Original line number Diff line number Diff line
/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -225,6 +225,7 @@ struct flash_led_platform_data {
};

struct qpnp_flash_led_buffer {
	struct mutex debugfs_lock; /* Prevent thread concurrency */
	size_t rpos;
	size_t wpos;
	size_t len;
@@ -280,6 +281,7 @@ static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
	log->rpos = 0;
	log->wpos = 0;
	log->len = logbufsize - sizeof(*log);
	mutex_init(&log->debugfs_lock);
	led->log = log;

	led->buffer_cnt = 1;
@@ -301,20 +303,26 @@ static int flash_led_dfs_close(struct inode *inode, struct file *file)

	if (led && led->log) {
		file->private_data = NULL;
		mutex_destroy(&led->log->debugfs_lock);
		kfree(led->log);
	}

	return 0;
}

#define MIN_BUFFER_WRITE_LEN		20
static int print_to_log(struct qpnp_flash_led_buffer *log,
					const char *fmt, ...)
{
	va_list args;
	int cnt;
	char *log_buf = &log->data[log->wpos];
	char *log_buf;
	size_t size = log->len - log->wpos;

	if (size < MIN_BUFFER_WRITE_LEN)
		return 0;	/* not enough buffer left */

	log_buf = &log->data[log->wpos];
	va_start(args, fmt);
	cnt = vscnprintf(log_buf, size, fmt, args);
	va_end(args);
@@ -328,12 +336,14 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
	struct qpnp_flash_led *led = fp->private_data;
	struct qpnp_flash_led_buffer *log = led->log;
	u8 val;
	int rc;
	int rc = 0;
	size_t len;
	size_t ret;

	if (log->rpos >= log->wpos && led->buffer_cnt == 0)
		return 0;
	mutex_lock(&log->debugfs_lock);
	if ((log->rpos >= log->wpos && led->buffer_cnt == 0) ||
			((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
		goto unlock_mutex;

	rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
		led->spmi_dev->sid, INT_LATCHED_STS(led->base), &val, 1);
@@ -341,17 +351,17 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
		dev_err(&led->spmi_dev->dev,
				"Unable to read from address %x, rc(%d)\n",
				INT_LATCHED_STS(led->base), rc);
		return -EINVAL;
		goto unlock_mutex;
	}
	led->buffer_cnt--;

	rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
	if (rc == 0)
		return rc;
		goto unlock_mutex;

	rc = print_to_log(log, "0x%02X ", val);
	if (rc == 0)
		return rc;
		goto unlock_mutex;

	if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
		log->data[log->wpos - 1] = '\n';
@@ -361,36 +371,43 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
	ret = copy_to_user(buf, &log->data[log->rpos], len);
	if (ret) {
		pr_err("error copy register value to user\n");
		return -EFAULT;
		rc = -EFAULT;
		goto unlock_mutex;
	}

	len -= ret;
	*ppos += len;
	log->rpos += len;

	return len;
	rc = len;

unlock_mutex:
	mutex_unlock(&log->debugfs_lock);
	return rc;
}

static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
					size_t count, loff_t *ppos) {
	struct qpnp_flash_led *led = fp->private_data;
	struct qpnp_flash_led_buffer *log = led->log;
	int rc;
	int rc = 0;
	size_t len;
	size_t ret;

	if (log->rpos >= log->wpos && led->buffer_cnt == 0)
		return 0;
	mutex_lock(&log->debugfs_lock);
	if ((log->rpos >= log->wpos && led->buffer_cnt == 0) ||
			((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
		goto unlock_mutex;

	led->buffer_cnt--;

	rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
	if (rc == 0)
		return rc;
		goto unlock_mutex;

	rc = print_to_log(log, "0x%02X ", led->fault_reg);
	if (rc == 0)
		return rc;
		goto unlock_mutex;

	if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
		log->data[log->wpos - 1] = '\n';
@@ -400,14 +417,19 @@ static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
	ret = copy_to_user(buf, &log->data[log->rpos], len);
	if (ret) {
		pr_err("error copy register value to user\n");
		return -EFAULT;
		rc = -EFAULT;
		goto unlock_mutex;
	}

	len -= ret;
	*ppos += len;
	log->rpos += len;

	return len;
	rc = len;

unlock_mutex:
	mutex_unlock(&log->debugfs_lock);
	return rc;
}

static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
@@ -420,10 +442,14 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
	size_t ret = 0;

	struct qpnp_flash_led *led = file->private_data;
	char *kbuf = kmalloc(count + 1, GFP_KERNEL);
	char *kbuf;

	if (!kbuf)
		return -ENOMEM;
	mutex_lock(&led->log->debugfs_lock);
	kbuf = kmalloc(count + 1, GFP_KERNEL);
	if (!kbuf) {
		ret = -ENOMEM;
		goto unlock_mutex;
	}

	ret = copy_from_user(kbuf, buf, count);
	if (!ret) {
@@ -452,6 +478,8 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,

free_buf:
	kfree(kbuf);
unlock_mutex:
	mutex_unlock(&led->log->debugfs_lock);
	return ret;
}

@@ -464,10 +492,14 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
	int data;
	size_t ret = 0;
	struct qpnp_flash_led *led = file->private_data;
	char *kbuf = kmalloc(count + 1, GFP_KERNEL);
	char *kbuf;

	if (!kbuf)
		return -ENOMEM;
	mutex_lock(&led->log->debugfs_lock);
	kbuf = kmalloc(count + 1, GFP_KERNEL);
	if (!kbuf) {
		ret = -ENOMEM;
		goto unlock_mutex;
	}

	ret = copy_from_user(kbuf, buf, count);
	if (ret == count) {
@@ -495,6 +527,8 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,

free_buf:
	kfree(kbuf);
unlock_mutex:
	mutex_unlock(&led->log->debugfs_lock);
	return ret;
}