scsi: storvsc: Resolve data race in storvsc_probe()
authorAndrea Parri (Microsoft) <parri.andrea@gmail.com>
Thu, 17 Dec 2020 20:33:20 +0000 (21:33 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 8 Jan 2021 04:15:00 +0000 (23:15 -0500)
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>
drivers/scsi/storvsc_drv.c

index 2d9dd30..e221aba 100644 (file)
@@ -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.
  */
@@ -451,6 +439,17 @@ struct storvsc_device {
        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.
         */
        u32   max_transfer_bytes;
@@ -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 @@ found_channel:
        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 @@ found_channel:
                                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);