Current code is based on the idea that the max number of SGL entries also determines the max size of an I/O request. While this idea was true in older versions of the storvsc driver when SGL entry length was limited to 4 Kbytes, commit 3d9c3dcc58e9 ("scsi: storvsc: Enable scatterlist entry lengths > 4Kbytes") removed that limitation. It's now theoretically possible for the block layer to send requests that exceed the maximum size supported by Hyper-V. This problem doesn't currently happen in practice because the block layer defaults to a 512 Kbyte maximum, while Hyper-V in Azure supports 2 Mbyte I/O sizes. But some future configuration of Hyper-V could have a smaller max I/O size, and the block layer could exceed that max. Fix this by correctly setting max_sectors as well as sg_tablesize to reflect the maximum I/O size that Hyper-V reports. While allowing I/O sizes larger than the block layer default of 512 Kbytes doesn’t provide any noticeable performance benefit in the tests we ran, it's still appropriate to report the correct underlying Hyper-V capabilities to the Linux block layer. Also tweak the virt_boundary_mask to reflect that the required alignment derives from Hyper-V communication using a 4 Kbyte page size, and not on the guest page size, which might be bigger (eg. ARM64).
Unified · Split
| @@ -1844,7 +1844,7 @@ static struct scsi_host_template scsi_driver = { · 1843 unmodified lines | ||
| 1844 | 1844 | .cmd_per_lun = 2048, |
| 1845 | 1845 | .this_id = -1, |
| 1846 | 1846 | /* Ensure there are no gaps in presented sgls */ |
| 1847 | − .virt_boundary_mask = PAGE_SIZE-1, | |
| 1847 | + .virt_boundary_mask = HV_HYP_PAGE_SIZE - 1, | |
| 1848 | 1848 | .no_write_same = 1, |
| 1849 | 1849 | .track_queue_depth = 1, |
| 1850 | 1850 | .change_queue_depth = storvsc_change_queue_depth, |
| @@ -1895,6 +1895,7 @@ static int storvsc_probe(struct hv_device *device, · 44 unmodified lines | ||
| 1895 | 1895 | int target = 0; |
| 1896 | 1896 | struct storvsc_device *stor_device; |
| 1897 | 1897 | int max_sub_channels = 0; |
| 1898 | + u32 max_xfer_bytes; | |
| 1898 | 1899 | |
| 1899 | 1900 | /* |
| 1900 | 1901 | * We support sub-channels for storage on SCSI and FC controllers. |
| @@ -1968,12 +1969,28 @@ static int storvsc_probe(struct hv_device *device, · 67 unmodified lines | ||
| 1968 | 1969 | } |
| 1969 | 1970 | /* max cmd length */ |
| 1970 | 1971 | host->max_cmd_len = STORVSC_MAX_CMD_LEN; |
| 1971 | − | |
| 1972 | 1972 | /* |
| 1973 | − * set the table size based on the info we got | |
| 1974 | − * from the host. | |
| 1973 | + * Any reasonable Hyper-V configuration should provide | |
| 1974 | + * max_transfer_bytes value aligning to HV_HYP_PAGE_SIZE, | |
| 1975 | + * protecting it from any weird value. | |
| 1976 | + */ | |
| 1977 | + max_xfer_bytes = round_down(stor_device->max_transfer_bytes, HV_HYP_PAGE_SIZE); | |
| 1978 | + /* max_hw_sectors_kb */ | |
| 1979 | + host->max_sectors = max_xfer_bytes >> 9; | |
| 1980 | + /* | |
| 1981 | + * There are 2 requirements for Hyper-V storvsc sgl segments, | |
| 1982 | + * based on which the below calculation for max segments is | |
| 1983 | + * done: | |
| 1984 | + * | |
| 1985 | + * 1. Except for the first and last sgl segment, all sgl segments | |
| 1986 | + * should be align to HV_HYP_PAGE_SIZE, that also means the | |
| 1987 | + * maximum number of segments in a sgl can be calculated by | |
| 1988 | + * dividing the total max transfer length by HV_HYP_PAGE_SIZE. | |
| 1989 | + * | |
| 1990 | + * 2. Except for the first and last, each entry in the SGL must | |
| 1991 | + * have an offset that is a multiple of HV_HYP_PAGE_SIZE. | |
| 1975 | 1992 | */ |
| 1976 | − host->sg_tablesize = (stor_device->max_transfer_bytes >> PAGE_SHIFT); | |
| 1993 | + host->sg_tablesize = (max_xfer_bytes >> HV_HYP_PAGE_SHIFT) + 1; | |
| 1977 | 1994 | /* |
| 1978 | 1995 | * For non-IDE disks, the host supports multiple channels. |
| 1979 | 1996 | * Set the number of HW queues we are supporting. |