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: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Andrea Parri (Microsoft) 2020-12-17 21:33:20 +01:00 committed by Martin K. Petersen
parent ab548fd21e
commit 244808e030
1 changed files with 25 additions and 20 deletions

View File

@ -216,18 +216,6 @@ struct vmscsi_request {
} __attribute((packed)); } __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. * The list of storage protocols in order of preference.
*/ */
@ -450,6 +438,17 @@ struct storvsc_device {
unsigned char path_id; unsigned char path_id;
unsigned char target_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. * 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, ret = vmbus_sendpacket(device->channel, vstor_packet,
(sizeof(struct vstor_packet) - (sizeof(struct vstor_packet) -
vmscsi_size_delta), stor_device->vmscsi_size_delta),
(unsigned long)request, (unsigned long)request,
VM_PKT_DATA_INBAND, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 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, struct storvsc_cmd_request *request,
bool status_check) bool status_check)
{ {
struct storvsc_device *stor_device;
struct vstor_packet *vstor_packet; struct vstor_packet *vstor_packet;
int ret, t; int ret, t;
stor_device = get_out_stor_device(device);
if (!stor_device)
return -ENODEV;
vstor_packet = &request->vstor_packet; vstor_packet = &request->vstor_packet;
init_completion(&request->wait_event); 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, ret = vmbus_sendpacket(device->channel, vstor_packet,
(sizeof(struct vstor_packet) - (sizeof(struct vstor_packet) -
vmscsi_size_delta), stor_device->vmscsi_size_delta),
(unsigned long)request, (unsigned long)request,
VM_PKT_DATA_INBAND, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 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 = sense_buffer_size =
vmstor_protocols[i].sense_buffer_size; vmstor_protocols[i].sense_buffer_size;
vmscsi_size_delta = stor_device->vmscsi_size_delta =
vmstor_protocols[i].vmscsi_size_delta; vmstor_protocols[i].vmscsi_size_delta;
break; break;
@ -1264,7 +1268,7 @@ static void storvsc_on_channel_callback(void *context)
if (request == &stor_device->init_request || if (request == &stor_device->init_request ||
request == &stor_device->reset_request) { request == &stor_device->reset_request) {
memcpy(&request->vstor_packet, packet, 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); complete(&request->wait_event);
} else { } else {
storvsc_on_receive(stor_device, packet, request); storvsc_on_receive(stor_device, packet, request);
@ -1482,7 +1486,7 @@ found_channel:
vstor_packet->flags |= REQUEST_COMPLETION_FLAG; vstor_packet->flags |= REQUEST_COMPLETION_FLAG;
vstor_packet->vm_srb.length = (sizeof(struct vmscsi_request) - 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; vstor_packet->vm_srb.sense_info_length = sense_buffer_size;
@ -1499,12 +1503,12 @@ found_channel:
request->payload, request->payload_sz, request->payload, request->payload_sz,
vstor_packet, vstor_packet,
(sizeof(struct vstor_packet) - (sizeof(struct vstor_packet) -
vmscsi_size_delta), stor_device->vmscsi_size_delta),
(unsigned long)request); (unsigned long)request);
} else { } else {
ret = vmbus_sendpacket(outgoing_channel, vstor_packet, ret = vmbus_sendpacket(outgoing_channel, vstor_packet,
(sizeof(struct vstor_packet) - (sizeof(struct vstor_packet) -
vmscsi_size_delta), stor_device->vmscsi_size_delta),
(unsigned long)request, (unsigned long)request,
VM_PKT_DATA_INBAND, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 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, ret = vmbus_sendpacket(device->channel, vstor_packet,
(sizeof(struct vstor_packet) - (sizeof(struct vstor_packet) -
vmscsi_size_delta), stor_device->vmscsi_size_delta),
(unsigned long)&stor_device->reset_request, (unsigned long)&stor_device->reset_request,
VM_PKT_DATA_INBAND, VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 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); init_waitqueue_head(&stor_device->waiting_to_drain);
stor_device->device = device; stor_device->device = device;
stor_device->host = host; stor_device->host = host;
stor_device->vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
spin_lock_init(&stor_device->lock); spin_lock_init(&stor_device->lock);
hv_set_drvdata(device, stor_device); hv_set_drvdata(device, stor_device);