diff options
Diffstat (limited to 'drivers/char/tpm/tpm-dev-common.c')
| -rw-r--r-- | drivers/char/tpm/tpm-dev-common.c | 40 | 
1 files changed, 18 insertions, 22 deletions
diff --git a/drivers/char/tpm/tpm-dev-common.c b/drivers/char/tpm/tpm-dev-common.c index 230b99288024..e4a04b2d3c32 100644 --- a/drivers/char/tpm/tpm-dev-common.c +++ b/drivers/char/tpm/tpm-dev-common.c @@ -37,7 +37,7 @@ static void timeout_work(struct work_struct *work)  	struct file_priv *priv = container_of(work, struct file_priv, work);  	mutex_lock(&priv->buffer_mutex); -	atomic_set(&priv->data_pending, 0); +	priv->data_pending = 0;  	memset(priv->data_buffer, 0, sizeof(priv->data_buffer));  	mutex_unlock(&priv->buffer_mutex);  } @@ -46,7 +46,6 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,  		     struct file_priv *priv)  {  	priv->chip = chip; -	atomic_set(&priv->data_pending, 0);  	mutex_init(&priv->buffer_mutex);  	timer_setup(&priv->user_read_timer, user_reader_timeout, 0);  	INIT_WORK(&priv->work, timeout_work); @@ -58,29 +57,24 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,  			size_t size, loff_t *off)  {  	struct file_priv *priv = file->private_data; -	ssize_t ret_size; -	ssize_t orig_ret_size; +	ssize_t ret_size = 0;  	int rc;  	del_singleshot_timer_sync(&priv->user_read_timer);  	flush_work(&priv->work); -	ret_size = atomic_read(&priv->data_pending); -	if (ret_size > 0) {	/* relay data */ -		orig_ret_size = ret_size; -		if (size < ret_size) -			ret_size = size; +	mutex_lock(&priv->buffer_mutex); -		mutex_lock(&priv->buffer_mutex); +	if (priv->data_pending) { +		ret_size = min_t(ssize_t, size, priv->data_pending);  		rc = copy_to_user(buf, priv->data_buffer, ret_size); -		memset(priv->data_buffer, 0, orig_ret_size); +		memset(priv->data_buffer, 0, priv->data_pending);  		if (rc)  			ret_size = -EFAULT; -		mutex_unlock(&priv->buffer_mutex); +		priv->data_pending = 0;  	} -	atomic_set(&priv->data_pending, 0); - +	mutex_unlock(&priv->buffer_mutex);  	return ret_size;  } @@ -91,17 +85,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,  	size_t in_size = size;  	ssize_t out_size; +	if (in_size > TPM_BUFSIZE) +		return -E2BIG; + +	mutex_lock(&priv->buffer_mutex); +  	/* Cannot perform a write until the read has cleared either via  	 * tpm_read or a user_read_timer timeout. This also prevents split  	 * buffered writes from blocking here.  	 */ -	if (atomic_read(&priv->data_pending) != 0) +	if (priv->data_pending != 0) { +		mutex_unlock(&priv->buffer_mutex);  		return -EBUSY; - -	if (in_size > TPM_BUFSIZE) -		return -E2BIG; - -	mutex_lock(&priv->buffer_mutex); +	}  	if (copy_from_user  	    (priv->data_buffer, (void __user *) buf, in_size)) { @@ -132,7 +128,7 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,  		return out_size;  	} -	atomic_set(&priv->data_pending, out_size); +	priv->data_pending = out_size;  	mutex_unlock(&priv->buffer_mutex);  	/* Set a timeout by which the reader must come claim the result */ @@ -149,5 +145,5 @@ void tpm_common_release(struct file *file, struct file_priv *priv)  	del_singleshot_timer_sync(&priv->user_read_timer);  	flush_work(&priv->work);  	file->private_data = NULL; -	atomic_set(&priv->data_pending, 0); +	priv->data_pending = 0;  }  |