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

Commit 0c2cfe5f authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Nicholas Bellinger
Browse files

target: fix list walking in transport_free_dev_tasks



list_for_each_entry_safe only protects against deletions from the list,
but not against any concurrent modifications.  Given that we drop
t_state_lock inside the loop it is not safe in transport_free_dev_tasks.

Instead of use a local dispose_list that we move all tasks that are
to be deleted to.  This is safe because we never do list_emptry checks
on t_list to check if a command is on the list anywhere.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent b7b8bef7
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -3585,23 +3585,26 @@ static void transport_free_dev_tasks(struct se_cmd *cmd)
{
	struct se_task *task, *task_tmp;
	unsigned long flags;
	LIST_HEAD(dispose_list);

	spin_lock_irqsave(&cmd->t_state_lock, flags);
	list_for_each_entry_safe(task, task_tmp,
				&cmd->t_task_list, t_list) {
		if (task->task_flags & TF_ACTIVE)
			continue;
		if (!(task->task_flags & TF_ACTIVE))
			list_move_tail(&task->t_list, &dispose_list);
	}
	spin_unlock_irqrestore(&cmd->t_state_lock, flags);

	while (!list_empty(&dispose_list)) {
		task = list_first_entry(&dispose_list, struct se_task, t_list);

		kfree(task->task_sg_bidi);
		kfree(task->task_sg);

		list_del(&task->t_list);

		spin_unlock_irqrestore(&cmd->t_state_lock, flags);
		cmd->se_dev->transport->free_task(task);
		spin_lock_irqsave(&cmd->t_state_lock, flags);
	}
	spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}

static inline void transport_free_sgl(struct scatterlist *sgl, int nents)