Commit 244808e0 authored by Andrea Parri (Microsoft)'s avatar Andrea Parri (Microsoft) Committed by Martin K. Petersen
Browse files

scsi: storvsc: Resolve data race in storvsc_probe()

vmscsi_size_delta can be written concurrently by multiple instances of
storvsc_probe(), corresponding to multiple synthetic IDE/SCSI devices;
cf. storvsc_drv's probe_type == PROBE_PREFER_ASYNCHRONOUS.  Change the
global variable vmscsi_size_delta to per-synthetic-IDE/SCSI-device.

Link: https://lore.kernel.org/r/20201217203321.4539-3-parri.andrea@gmail.com


Cc: "James E.J. Bottomley" <jejb@linux.ibm.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Suggested-by: default avatarDexuan Cui <decui@microsoft.com>
Reviewed-by: default avatarDexuan Cui <decui@microsoft.com>
Reviewed-by: default avatarMichael Kelley <mikelley@microsoft.com>
Signed-off-by: default avatarAndrea Parri (Microsoft) <parri.andrea@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent ab548fd2
Loading
Loading
Loading
Loading
+25 −20
Original line number Diff line number Diff line
@@ -216,18 +216,6 @@ struct vmscsi_request {

} __attribute((packed));


/*
 * The size of the vmscsi_request has changed in win8. The
 * additional size is because of new elements added to the
 * structure. These elements are valid only when we are talking
 * to a win8 host.
 * Track the correction to size we need to apply. This value
 * will likely change during protocol negotiation but it is
 * valid to start by assuming pre-Win8.
 */
static int vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);

/*
 * The list of storage protocols in order of preference.
 */
@@ -450,6 +438,17 @@ struct storvsc_device {
	unsigned char path_id;
	unsigned char target_id;

	/*
	 * The size of the vmscsi_request has changed in win8. The
	 * additional size is because of new elements added to the
	 * structure. These elements are valid only when we are talking
	 * to a win8 host.
	 * Track the correction to size we need to apply. This value
	 * will likely change during protocol negotiation but it is
	 * valid to start by assuming pre-Win8.
	 */
	int vmscsi_size_delta;

	/*
	 * Max I/O, the device can support.
	 */
@@ -769,7 +768,7 @@ static void handle_multichannel_storage(struct hv_device *device, int max_chns)

	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       (sizeof(struct vstor_packet) -
			       vmscsi_size_delta),
			       stor_device->vmscsi_size_delta),
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -823,9 +822,14 @@ static int storvsc_execute_vstor_op(struct hv_device *device,
				    struct storvsc_cmd_request *request,
				    bool status_check)
{
	struct storvsc_device *stor_device;
	struct vstor_packet *vstor_packet;
	int ret, t;

	stor_device = get_out_stor_device(device);
	if (!stor_device)
		return -ENODEV;

	vstor_packet = &request->vstor_packet;

	init_completion(&request->wait_event);
@@ -833,7 +837,7 @@ static int storvsc_execute_vstor_op(struct hv_device *device,

	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       (sizeof(struct vstor_packet) -
			       vmscsi_size_delta),
			       stor_device->vmscsi_size_delta),
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -910,7 +914,7 @@ static int storvsc_channel_init(struct hv_device *device, bool is_fc)
			sense_buffer_size =
				vmstor_protocols[i].sense_buffer_size;

			vmscsi_size_delta =
			stor_device->vmscsi_size_delta =
				vmstor_protocols[i].vmscsi_size_delta;

			break;
@@ -1264,7 +1268,7 @@ static void storvsc_on_channel_callback(void *context)
		if (request == &stor_device->init_request ||
		    request == &stor_device->reset_request) {
			memcpy(&request->vstor_packet, packet,
			       (sizeof(struct vstor_packet) - vmscsi_size_delta));
			       (sizeof(struct vstor_packet) - stor_device->vmscsi_size_delta));
			complete(&request->wait_event);
		} else {
			storvsc_on_receive(stor_device, packet, request);
@@ -1482,7 +1486,7 @@ static int storvsc_do_io(struct hv_device *device,
	vstor_packet->flags |= REQUEST_COMPLETION_FLAG;

	vstor_packet->vm_srb.length = (sizeof(struct vmscsi_request) -
					vmscsi_size_delta);
					stor_device->vmscsi_size_delta);


	vstor_packet->vm_srb.sense_info_length = sense_buffer_size;
@@ -1499,12 +1503,12 @@ static int storvsc_do_io(struct hv_device *device,
				request->payload, request->payload_sz,
				vstor_packet,
				(sizeof(struct vstor_packet) -
				vmscsi_size_delta),
				stor_device->vmscsi_size_delta),
				(unsigned long)request);
	} else {
		ret = vmbus_sendpacket(outgoing_channel, vstor_packet,
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
				stor_device->vmscsi_size_delta),
			       (unsigned long)request,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -1609,7 +1613,7 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)

	ret = vmbus_sendpacket(device->channel, vstor_packet,
			       (sizeof(struct vstor_packet) -
				vmscsi_size_delta),
				stor_device->vmscsi_size_delta),
			       (unsigned long)&stor_device->reset_request,
			       VM_PKT_DATA_INBAND,
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
@@ -1959,6 +1963,7 @@ static int storvsc_probe(struct hv_device *device,
	init_waitqueue_head(&stor_device->waiting_to_drain);
	stor_device->device = device;
	stor_device->host = host;
	stor_device->vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
	spin_lock_init(&stor_device->lock);
	hv_set_drvdata(device, stor_device);