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

Commit d6bbd448 authored by Andrey Markovytch's avatar Andrey Markovytch Committed by Gerrit - the friendly Code Review server
Browse files

ufs: add additional sync between ice work queue and pending request



Fixes the issue where the job could have been scheduled with request
that was about to be released thus causing crash with stale pointer.

Change-Id: I4ed1f08ed810303738c05d08f27a8ea21ba1e4f7
Signed-off-by: default avatarAndrey Markovytch <andreym@codeaurora.org>
parent 958e36a7
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -173,10 +173,19 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work)
	struct ice_data_setting ice_set;
	struct ufs_qcom_host *qcom_host =
		container_of(work, struct ufs_qcom_host, ice_cfg_work);
	struct request *req_pending = NULL;

	if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending)
	if (!qcom_host->ice.vops->config_start)
		return;

	spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
	req_pending = qcom_host->req_pending;
	if (!req_pending) {
		spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
		return;
	}
	spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);

	/*
	 * config_start is called again as previous attempt returned -EAGAIN,
	 * this call shall now take care of the necessary key setup.
@@ -263,6 +272,10 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,

	if (qcom_host->ice.vops->config_start) {
		memset(&ice_set, 0, sizeof(ice_set));

		spin_lock_irqsave(
			&qcom_host->ice_work_lock, flags);

		err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
			cmd->request, &ice_set, true);
		if (err) {
@@ -281,13 +294,11 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
					"%s: scheduling task for ice setup\n",
					__func__);

				spin_lock_irqsave(
					&qcom_host->ice_work_lock, flags);

				if (!qcom_host->req_pending) {
					ufshcd_scsi_block_requests(
						qcom_host->hba);
					qcom_host->req_pending = cmd->request;

					if (!schedule_work(
						&qcom_host->ice_cfg_work)) {
						qcom_host->req_pending = NULL;
@@ -302,9 +313,6 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
					}
				}

				spin_unlock_irqrestore(
					&qcom_host->ice_work_lock, flags);

			} else {
				if (err != -EBUSY)
					dev_err(qcom_host->hba->dev,
@@ -312,9 +320,14 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host,
						__func__, err);
			}

			spin_unlock_irqrestore(&qcom_host->ice_work_lock,
				flags);

			return err;
		}

		spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);

		if (ufs_qcom_is_data_cmd(cmd_op, true))
			*enable = !ice_set.encr_bypass;
		else if (ufs_qcom_is_data_cmd(cmd_op, false))
@@ -380,8 +393,13 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
		return -EINVAL;
	}

	memset(&ice_set, 0, sizeof(ice_set));

	if (qcom_host->ice.vops->config_start) {
		memset(&ice_set, 0, sizeof(ice_set));

		spin_lock_irqsave(
			&qcom_host->ice_work_lock, flags);

		err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
							req, &ice_set, true);
		if (err) {
@@ -401,9 +419,6 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
					"%s: scheduling task for ice setup\n",
					__func__);

				spin_lock_irqsave(
					&qcom_host->ice_work_lock, flags);

				if (!qcom_host->req_pending) {
					ufshcd_scsi_block_requests(
						qcom_host->hba);
@@ -422,9 +437,6 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
					}
				}

				spin_unlock_irqrestore(
					&qcom_host->ice_work_lock, flags);

			} else {
				if (err != -EBUSY)
					dev_err(qcom_host->hba->dev,
@@ -432,8 +444,14 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host,
						__func__, err);
			}

			spin_unlock_irqrestore(
				&qcom_host->ice_work_lock, flags);

			return err;
		}

		spin_unlock_irqrestore(
			&qcom_host->ice_work_lock, flags);
	}

	cmd_op = cmd->cmnd[0];