On 10/29/24 8:26 AM, Christoph Hellwig wrote:
Bart, btw: I think the current sd implementation is buggy as well, as
it assumes the permanent streams are ordered by their data temperature
in the IO Advise hints mode page, but I can't find anything in the
spec that requires a particular ordering.
How about modifying sd_read_io_hints() such that permanent stream
information is ignored if the order of the RELATIVE LIFETIME information
reported by the GET STREAM STATUS command does not match the permanent
stream order?
Thanks,
Bart.
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 41e2dfa2d67d..277035febd82 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -3192,7 +3192,12 @@ sd_read_cache_type(struct scsi_disk *sdkp,
unsigned char *buffer)
sdkp->DPOFUA = 0;
}
-static bool sd_is_perm_stream(struct scsi_disk *sdkp, unsigned int
stream_id)
+/*
+ * Returns the relative lifetime of a permanent stream. Returns -1 if the
+ * GET STREAM STATUS command fails or if the stream is not a permanent
stream.
+ */
+static int sd_perm_stream_rel_lifetime(struct scsi_disk *sdkp,
+ unsigned int stream_id)
{
u8 cdb[16] = { SERVICE_ACTION_IN_16, SAI_GET_STREAM_STATUS };
struct {
@@ -3212,14 +3217,16 @@ static bool sd_is_perm_stream(struct scsi_disk
*sdkp, unsigned int stream_id)
res = scsi_execute_cmd(sdev, cdb, REQ_OP_DRV_IN, &buf, sizeof(buf),
SD_TIMEOUT, sdkp->max_retries, &exec_args);
if (res < 0)
- return false;
+ return -1;
if (scsi_status_is_check_condition(res) && scsi_sense_valid(&sshdr))
sd_print_sense_hdr(sdkp, &sshdr);
if (res)
- return false;
+ return -1;
if (get_unaligned_be32(&buf.h.len) < sizeof(struct scsi_stream_status))
- return false;
- return buf.h.stream_status[0].perm;
+ return -1;
+ if (!buf.h.stream_status[0].perm)
+ return -1;
+ return buf.h.stream_status[0].rel_lifetime;
}
static void sd_read_io_hints(struct scsi_disk *sdkp, unsigned char
*buffer)
@@ -3247,9 +3254,17 @@ static void sd_read_io_hints(struct scsi_disk
*sdkp, unsigned char *buffer)
* should assign the lowest numbered stream identifiers to permanent
* streams.
*/
- for (desc = start; desc < end; desc++)
- if (!desc->st_enble || !sd_is_perm_stream(sdkp, desc - start))
+ int prev_rel_lifetime = -1;
+ for (desc = start; desc < end; desc++) {
+ int rel_lifetime;
+
+ if (!desc->st_enble)
break;
+ rel_lifetime = sd_perm_stream_rel_lifetime(sdkp, desc - start);
+ if (rel_lifetime < 0 || rel_lifetime < prev_rel_lifetime)
+ break;
+ prev_rel_lifetime = rel_lifetime;
+ }
permanent_stream_count_old = sdkp->permanent_stream_count;
sdkp->permanent_stream_count = desc - start;
if (sdkp->rscs && sdkp->permanent_stream_count < 2)