Commit 7a4f0846 authored by Ritesh Harjani (IBM)'s avatar Ritesh Harjani (IBM) Committed by Madhavan Srinivasan
Browse files

pseries/papr-hvpipe: Fix race with interrupt handler



While executing ->ioctl handler or ->release handler, if an interrupt
fires on the same cpu, then we can enter into a deadlock.

This patch fixes both these handlers to take spin_lock_irq{save|restore}
versions of the lock to prevent this deadlock.

Cc: stable@vger.kernel.org
Fixes: 814ef095 ("powerpc/pseries: Add papr-hvpipe char driver for HVPIPE interfaces")
Signed-off-by: default avatarRitesh Harjani (IBM) <ritesh.list@gmail.com>
Signed-off-by: default avatarMadhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/e4ed435c44fc191f2eb23c7907ba6f72f193e6aa.1777606826.git.ritesh.list@gmail.com
parent 0342545a
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -444,13 +444,14 @@ static int papr_hvpipe_handle_release(struct inode *inode,
				struct file *file)
{
	struct hvpipe_source_info *src_info;
	unsigned long flags;

	/*
	 * Hold the lock, remove source from src_list, reset the
	 * hvpipe status and release the lock to prevent any race
	 * with message event IRQ.
	 */
	spin_lock(&hvpipe_src_list_lock);
	spin_lock_irqsave(&hvpipe_src_list_lock, flags);
	src_info = file->private_data;
	list_del(&src_info->list);
	file->private_data = NULL;
@@ -461,10 +462,10 @@ static int papr_hvpipe_handle_release(struct inode *inode,
	 */
	if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE) {
		src_info->hvpipe_status = 0;
		spin_unlock(&hvpipe_src_list_lock);
		spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
		hvpipe_rtas_recv_msg(NULL, 0);
	} else
		spin_unlock(&hvpipe_src_list_lock);
		spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);

	kfree(src_info);
	return 0;
@@ -480,20 +481,21 @@ static const struct file_operations papr_hvpipe_handle_ops = {
static int papr_hvpipe_dev_create_handle(u32 srcID)
{
	struct hvpipe_source_info *src_info __free(kfree) = NULL;
	unsigned long flags;

	spin_lock(&hvpipe_src_list_lock);
	spin_lock_irqsave(&hvpipe_src_list_lock, flags);
	/*
	 * Do not allow more than one process communicates with
	 * each source.
	 */
	src_info = hvpipe_find_source(srcID);
	if (src_info) {
		spin_unlock(&hvpipe_src_list_lock);
		spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
		pr_err("pid(%d) is already using the source(%d)\n",
				src_info->tsk->pid, srcID);
		return -EALREADY;
	}
	spin_unlock(&hvpipe_src_list_lock);
	spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);

	src_info = kzalloc_obj(*src_info, GFP_KERNEL_ACCOUNT);
	if (!src_info)
@@ -510,18 +512,18 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
		return fdf.err;

	retain_and_null_ptr(src_info);
	spin_lock(&hvpipe_src_list_lock);
	spin_lock_irqsave(&hvpipe_src_list_lock, flags);
	/*
	 * If two processes are executing ioctl() for the same
	 * source ID concurrently, prevent the second process to
	 * acquire FD.
	 */
	if (hvpipe_find_source(srcID)) {
		spin_unlock(&hvpipe_src_list_lock);
		spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
		return -EALREADY;
	}
	list_add(&src_info->list, &hvpipe_src_list);
	spin_unlock(&hvpipe_src_list_lock);
	spin_unlock_irqrestore(&hvpipe_src_list_lock, flags);
	return fd_publish(fdf);
}