Message ID | 20210721104205.885115-3-damien.lemoal@wdc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Initial support for multi-actuator HDDs | expand |
Hi Damien, url: https://github.com/0day-ci/linux/commits/Damien-Le-Moal/Initial-support-for-multi-actuator-HDDs/20210721-185447 base: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git for-next config: x86_64-randconfig-m001-20210720 (attached as .config) compiler: gcc-10 (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> smatch warnings: drivers/scsi/sd.c:3204 sd_read_cpr() error: uninitialized symbol 'buffer'. vim +/buffer +3204 drivers/scsi/sd.c 331fc9cf44c011 Damien Le Moal 2021-07-21 3137 static void sd_read_cpr(struct scsi_disk *sdkp) 331fc9cf44c011 Damien Le Moal 2021-07-21 3138 { 331fc9cf44c011 Damien Le Moal 2021-07-21 3139 unsigned char *buffer, *desc; ^^^^^^ 331fc9cf44c011 Damien Le Moal 2021-07-21 3140 struct blk_cranges *cr = NULL; 331fc9cf44c011 Damien Le Moal 2021-07-21 3141 unsigned int nr_cpr = 0; 331fc9cf44c011 Damien Le Moal 2021-07-21 3142 int i, vpd_len, buf_len = SD_BUF_SIZE; 331fc9cf44c011 Damien Le Moal 2021-07-21 3143 331fc9cf44c011 Damien Le Moal 2021-07-21 3144 /* 331fc9cf44c011 Damien Le Moal 2021-07-21 3145 * We need to have the capacity set first for the block layer to be 331fc9cf44c011 Damien Le Moal 2021-07-21 3146 * able to check the ranges. 331fc9cf44c011 Damien Le Moal 2021-07-21 3147 */ 331fc9cf44c011 Damien Le Moal 2021-07-21 3148 if (sdkp->first_scan) 331fc9cf44c011 Damien Le Moal 2021-07-21 3149 return; 331fc9cf44c011 Damien Le Moal 2021-07-21 3150 331fc9cf44c011 Damien Le Moal 2021-07-21 3151 if (!sdkp->capacity) 331fc9cf44c011 Damien Le Moal 2021-07-21 3152 goto out; ^^^^^^^^^ This should just return probably? 331fc9cf44c011 Damien Le Moal 2021-07-21 3153 331fc9cf44c011 Damien Le Moal 2021-07-21 3154 /* 331fc9cf44c011 Damien Le Moal 2021-07-21 3155 * Concurrent Positioning Ranges VPD: there can be at most 256 ranges, 331fc9cf44c011 Damien Le Moal 2021-07-21 3156 * leading to a maximum page size of 64 + 256*32 bytes. 331fc9cf44c011 Damien Le Moal 2021-07-21 3157 */ 331fc9cf44c011 Damien Le Moal 2021-07-21 3158 buf_len = 64 + 256*32; 331fc9cf44c011 Damien Le Moal 2021-07-21 3159 buffer = kmalloc(buf_len, GFP_KERNEL); 331fc9cf44c011 Damien Le Moal 2021-07-21 3160 if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb9, buffer, buf_len)) 331fc9cf44c011 Damien Le Moal 2021-07-21 3161 goto out; 331fc9cf44c011 Damien Le Moal 2021-07-21 3162 331fc9cf44c011 Damien Le Moal 2021-07-21 3163 /* We must have at least a 64B header and one 32B range descriptor */ 331fc9cf44c011 Damien Le Moal 2021-07-21 3164 vpd_len = get_unaligned_be16(&buffer[2]) + 3; 331fc9cf44c011 Damien Le Moal 2021-07-21 3165 if (vpd_len > buf_len || vpd_len < 64 + 32 || (vpd_len & 31)) { 331fc9cf44c011 Damien Le Moal 2021-07-21 3166 sd_printk(KERN_ERR, sdkp, 331fc9cf44c011 Damien Le Moal 2021-07-21 3167 "Invalid Concurrent Positioning Ranges VPD page\n"); 331fc9cf44c011 Damien Le Moal 2021-07-21 3168 goto out; 331fc9cf44c011 Damien Le Moal 2021-07-21 3169 } 331fc9cf44c011 Damien Le Moal 2021-07-21 3170 331fc9cf44c011 Damien Le Moal 2021-07-21 3171 nr_cpr = (vpd_len - 64) / 32; 331fc9cf44c011 Damien Le Moal 2021-07-21 3172 if (nr_cpr == 1) { 331fc9cf44c011 Damien Le Moal 2021-07-21 3173 nr_cpr = 0; 331fc9cf44c011 Damien Le Moal 2021-07-21 3174 goto out; 331fc9cf44c011 Damien Le Moal 2021-07-21 3175 } 331fc9cf44c011 Damien Le Moal 2021-07-21 3176 331fc9cf44c011 Damien Le Moal 2021-07-21 3177 cr = blk_alloc_cranges(sdkp->disk, nr_cpr); 331fc9cf44c011 Damien Le Moal 2021-07-21 3178 if (!cr) { 331fc9cf44c011 Damien Le Moal 2021-07-21 3179 nr_cpr = 0; 331fc9cf44c011 Damien Le Moal 2021-07-21 3180 goto out; 331fc9cf44c011 Damien Le Moal 2021-07-21 3181 } 331fc9cf44c011 Damien Le Moal 2021-07-21 3182 331fc9cf44c011 Damien Le Moal 2021-07-21 3183 desc = &buffer[64]; 331fc9cf44c011 Damien Le Moal 2021-07-21 3184 for (i = 0; i < nr_cpr; i++, desc += 32) { 331fc9cf44c011 Damien Le Moal 2021-07-21 3185 if (desc[0] != i) { 331fc9cf44c011 Damien Le Moal 2021-07-21 3186 sd_printk(KERN_ERR, sdkp, 331fc9cf44c011 Damien Le Moal 2021-07-21 3187 "Invalid Concurrent Positioning Range number\n"); 331fc9cf44c011 Damien Le Moal 2021-07-21 3188 nr_cpr = 0; 331fc9cf44c011 Damien Le Moal 2021-07-21 3189 break; 331fc9cf44c011 Damien Le Moal 2021-07-21 3190 } 331fc9cf44c011 Damien Le Moal 2021-07-21 3191 331fc9cf44c011 Damien Le Moal 2021-07-21 3192 cr->ranges[i].sector = sd64_to_sectors(sdkp, desc + 8); 331fc9cf44c011 Damien Le Moal 2021-07-21 3193 cr->ranges[i].nr_sectors = sd64_to_sectors(sdkp, desc + 16); 331fc9cf44c011 Damien Le Moal 2021-07-21 3194 } 331fc9cf44c011 Damien Le Moal 2021-07-21 3195 331fc9cf44c011 Damien Le Moal 2021-07-21 3196 out: 331fc9cf44c011 Damien Le Moal 2021-07-21 3197 blk_queue_set_cranges(sdkp->disk, cr); 331fc9cf44c011 Damien Le Moal 2021-07-21 3198 if (nr_cpr && sdkp->nr_actuators != nr_cpr) { 331fc9cf44c011 Damien Le Moal 2021-07-21 3199 sd_printk(KERN_NOTICE, sdkp, 331fc9cf44c011 Damien Le Moal 2021-07-21 3200 "%u concurrent positioning ranges\n", nr_cpr); 331fc9cf44c011 Damien Le Moal 2021-07-21 3201 sdkp->nr_actuators = nr_cpr; 331fc9cf44c011 Damien Le Moal 2021-07-21 3202 } 331fc9cf44c011 Damien Le Moal 2021-07-21 3203 331fc9cf44c011 Damien Le Moal 2021-07-21 @3204 kfree(buffer); ^^^^^^^^^^^^^ 331fc9cf44c011 Damien Le Moal 2021-07-21 3205 } --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On 7/21/21 12:42 PM, Damien Le Moal wrote: > Add the sd_read_cpr() function to the sd scsi disk driver to discover > if a device has multiple concurrent positioning ranges (i.e. multiple > actuators on an HDD). This new function is called from > sd_revalidate_disk() and uses the block layer functions > blk_alloc_cranges() and blk_queue_set_cranges() to set a device > cranges according to the information retrieved from log page B9h, > if the device supports it. > > The format of the Concurrent Positioning Ranges VPD page B9h is defined > in section 6.6.6 of SBC-5. > > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > --- > drivers/scsi/sd.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ > drivers/scsi/sd.h | 1 + > 2 files changed, 81 insertions(+) > > diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c > index b8d55af763f9..b1e767a01b9f 100644 > --- a/drivers/scsi/sd.c > +++ b/drivers/scsi/sd.c > @@ -3125,6 +3125,85 @@ static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) > sdkp->security = 1; > } > > +static inline sector_t sd64_to_sectors(struct scsi_disk *sdkp, u8 *buf) > +{ > + return logical_to_sectors(sdkp->device, get_unaligned_be64(buf)); > +} > + > +/** > + * sd_read_cpr - Query concurrent positioning ranges > + * @sdkp: disk to query > + */ > +static void sd_read_cpr(struct scsi_disk *sdkp) > +{ > + unsigned char *buffer, *desc; > + struct blk_cranges *cr = NULL; > + unsigned int nr_cpr = 0; > + int i, vpd_len, buf_len = SD_BUF_SIZE; > + > + /* > + * We need to have the capacity set first for the block layer to be > + * able to check the ranges. > + */ > + if (sdkp->first_scan) > + return; > + > + if (!sdkp->capacity) > + goto out; > + > + /* > + * Concurrent Positioning Ranges VPD: there can be at most 256 ranges, > + * leading to a maximum page size of 64 + 256*32 bytes. > + */ > + buf_len = 64 + 256*32; > + buffer = kmalloc(buf_len, GFP_KERNEL); > + if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb9, buffer, buf_len)) > + goto out; > + > + /* We must have at least a 64B header and one 32B range descriptor */ > + vpd_len = get_unaligned_be16(&buffer[2]) + 3; > + if (vpd_len > buf_len || vpd_len < 64 + 32 || (vpd_len & 31)) { > + sd_printk(KERN_ERR, sdkp, > + "Invalid Concurrent Positioning Ranges VPD page\n"); > + goto out; > + } > + > + nr_cpr = (vpd_len - 64) / 32; > + if (nr_cpr == 1) { > + nr_cpr = 0; > + goto out; > + } > + > + cr = blk_alloc_cranges(sdkp->disk, nr_cpr); > + if (!cr) { > + nr_cpr = 0; > + goto out; > + } > + > + desc = &buffer[64]; > + for (i = 0; i < nr_cpr; i++, desc += 32) { > + if (desc[0] != i) { > + sd_printk(KERN_ERR, sdkp, > + "Invalid Concurrent Positioning Range number\n"); > + nr_cpr = 0; > + break; > + } > + > + cr->ranges[i].sector = sd64_to_sectors(sdkp, desc + 8); > + cr->ranges[i].nr_sectors = sd64_to_sectors(sdkp, desc + 16); > + } > + > +out: > + blk_queue_set_cranges(sdkp->disk, cr); See? We are _are_ creating a new set of ranges. So why bother updating the old ones? > + if (nr_cpr && sdkp->nr_actuators != nr_cpr) { > + sd_printk(KERN_NOTICE, sdkp, > + "%u concurrent positioning ranges\n", nr_cpr); > + sdkp->nr_actuators = nr_cpr; > + } > + > + kfree(buffer); > +} > + > /* > * Determine the device's preferred I/O size for reads and writes > * unless the reported value is unreasonably small, large, not a > @@ -3240,6 +3319,7 @@ static int sd_revalidate_disk(struct gendisk *disk) > sd_read_app_tag_own(sdkp, buffer); > sd_read_write_same(sdkp, buffer); > sd_read_security(sdkp, buffer); > + sd_read_cpr(sdkp); > } > > /* > diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h > index b59136c4125b..2e5932bde43d 100644 > --- a/drivers/scsi/sd.h > +++ b/drivers/scsi/sd.h > @@ -106,6 +106,7 @@ struct scsi_disk { > u8 protection_type;/* Data Integrity Field */ > u8 provisioning_mode; > u8 zeroing_mode; > + u8 nr_actuators; /* Number of actuators */ > unsigned ATO : 1; /* state of disk ATO bit */ > unsigned cache_override : 1; /* temp override of WCE,RCD */ > unsigned WCE : 1; /* state of disk WCE bit */ > Otherwise: Reviewed-by: Hannes Reinecke <hare@suse.de> Cheers, Hannes
On 2021/07/23 1:14, Hannes Reinecke wrote: > On 7/21/21 12:42 PM, Damien Le Moal wrote: >> Add the sd_read_cpr() function to the sd scsi disk driver to discover >> if a device has multiple concurrent positioning ranges (i.e. multiple >> actuators on an HDD). This new function is called from >> sd_revalidate_disk() and uses the block layer functions >> blk_alloc_cranges() and blk_queue_set_cranges() to set a device >> cranges according to the information retrieved from log page B9h, >> if the device supports it. >> >> The format of the Concurrent Positioning Ranges VPD page B9h is defined >> in section 6.6.6 of SBC-5. >> >> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> >> --- >> drivers/scsi/sd.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ >> drivers/scsi/sd.h | 1 + >> 2 files changed, 81 insertions(+) >> >> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c >> index b8d55af763f9..b1e767a01b9f 100644 >> --- a/drivers/scsi/sd.c >> +++ b/drivers/scsi/sd.c >> @@ -3125,6 +3125,85 @@ static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) >> sdkp->security = 1; >> } >> >> +static inline sector_t sd64_to_sectors(struct scsi_disk *sdkp, u8 *buf) >> +{ >> + return logical_to_sectors(sdkp->device, get_unaligned_be64(buf)); >> +} >> + >> +/** >> + * sd_read_cpr - Query concurrent positioning ranges >> + * @sdkp: disk to query >> + */ >> +static void sd_read_cpr(struct scsi_disk *sdkp) >> +{ >> + unsigned char *buffer, *desc; >> + struct blk_cranges *cr = NULL; >> + unsigned int nr_cpr = 0; >> + int i, vpd_len, buf_len = SD_BUF_SIZE; >> + >> + /* >> + * We need to have the capacity set first for the block layer to be >> + * able to check the ranges. >> + */ >> + if (sdkp->first_scan) >> + return; >> + >> + if (!sdkp->capacity) >> + goto out; >> + >> + /* >> + * Concurrent Positioning Ranges VPD: there can be at most 256 ranges, >> + * leading to a maximum page size of 64 + 256*32 bytes. >> + */ >> + buf_len = 64 + 256*32; >> + buffer = kmalloc(buf_len, GFP_KERNEL); >> + if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb9, buffer, buf_len)) >> + goto out; >> + >> + /* We must have at least a 64B header and one 32B range descriptor */ >> + vpd_len = get_unaligned_be16(&buffer[2]) + 3; >> + if (vpd_len > buf_len || vpd_len < 64 + 32 || (vpd_len & 31)) { >> + sd_printk(KERN_ERR, sdkp, >> + "Invalid Concurrent Positioning Ranges VPD page\n"); >> + goto out; >> + } >> + >> + nr_cpr = (vpd_len - 64) / 32; >> + if (nr_cpr == 1) { >> + nr_cpr = 0; >> + goto out; >> + } >> + >> + cr = blk_alloc_cranges(sdkp->disk, nr_cpr); >> + if (!cr) { >> + nr_cpr = 0; >> + goto out; >> + } >> + >> + desc = &buffer[64]; >> + for (i = 0; i < nr_cpr; i++, desc += 32) { >> + if (desc[0] != i) { >> + sd_printk(KERN_ERR, sdkp, >> + "Invalid Concurrent Positioning Range number\n"); >> + nr_cpr = 0; >> + break; >> + } >> + >> + cr->ranges[i].sector = sd64_to_sectors(sdkp, desc + 8); >> + cr->ranges[i].nr_sectors = sd64_to_sectors(sdkp, desc + 16); >> + } >> + >> +out: >> + blk_queue_set_cranges(sdkp->disk, cr); > > See? We are _are_ creating a new set of ranges. > So why bother updating the old ones? See my reply to my comments on patch 1. We do not update the old ones. The cases are: 1) This is the first call, q->cranges is NULL: cr will become q->cranges. 2) q->cranges is already set and cr has the same info as q->cranges (no change): cr will be freed by blk_queue_set_cranges(). 3) q->cranges is already set and cr is different from q-cranges: q->cranges will be completely dropped and cr become the new q->cranges. So we never directly update anything inside q->cranges. We just swap in a new full structure in case of change. >> + if (nr_cpr && sdkp->nr_actuators != nr_cpr) { >> + sd_printk(KERN_NOTICE, sdkp, >> + "%u concurrent positioning ranges\n", nr_cpr); >> + sdkp->nr_actuators = nr_cpr; >> + } >> + >> + kfree(buffer); >> +} >> + >> /* >> * Determine the device's preferred I/O size for reads and writes >> * unless the reported value is unreasonably small, large, not a >> @@ -3240,6 +3319,7 @@ static int sd_revalidate_disk(struct gendisk *disk) >> sd_read_app_tag_own(sdkp, buffer); >> sd_read_write_same(sdkp, buffer); >> sd_read_security(sdkp, buffer); >> + sd_read_cpr(sdkp); >> } >> >> /* >> diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h >> index b59136c4125b..2e5932bde43d 100644 >> --- a/drivers/scsi/sd.h >> +++ b/drivers/scsi/sd.h >> @@ -106,6 +106,7 @@ struct scsi_disk { >> u8 protection_type;/* Data Integrity Field */ >> u8 provisioning_mode; >> u8 zeroing_mode; >> + u8 nr_actuators; /* Number of actuators */ >> unsigned ATO : 1; /* state of disk ATO bit */ >> unsigned cache_override : 1; /* temp override of WCE,RCD */ >> unsigned WCE : 1; /* state of disk WCE bit */ >> > Otherwise: > > Reviewed-by: Hannes Reinecke <hare@suse.de> > > Cheers, > > Hannes >
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b8d55af763f9..b1e767a01b9f 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3125,6 +3125,85 @@ static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer) sdkp->security = 1; } +static inline sector_t sd64_to_sectors(struct scsi_disk *sdkp, u8 *buf) +{ + return logical_to_sectors(sdkp->device, get_unaligned_be64(buf)); +} + +/** + * sd_read_cpr - Query concurrent positioning ranges + * @sdkp: disk to query + */ +static void sd_read_cpr(struct scsi_disk *sdkp) +{ + unsigned char *buffer, *desc; + struct blk_cranges *cr = NULL; + unsigned int nr_cpr = 0; + int i, vpd_len, buf_len = SD_BUF_SIZE; + + /* + * We need to have the capacity set first for the block layer to be + * able to check the ranges. + */ + if (sdkp->first_scan) + return; + + if (!sdkp->capacity) + goto out; + + /* + * Concurrent Positioning Ranges VPD: there can be at most 256 ranges, + * leading to a maximum page size of 64 + 256*32 bytes. + */ + buf_len = 64 + 256*32; + buffer = kmalloc(buf_len, GFP_KERNEL); + if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb9, buffer, buf_len)) + goto out; + + /* We must have at least a 64B header and one 32B range descriptor */ + vpd_len = get_unaligned_be16(&buffer[2]) + 3; + if (vpd_len > buf_len || vpd_len < 64 + 32 || (vpd_len & 31)) { + sd_printk(KERN_ERR, sdkp, + "Invalid Concurrent Positioning Ranges VPD page\n"); + goto out; + } + + nr_cpr = (vpd_len - 64) / 32; + if (nr_cpr == 1) { + nr_cpr = 0; + goto out; + } + + cr = blk_alloc_cranges(sdkp->disk, nr_cpr); + if (!cr) { + nr_cpr = 0; + goto out; + } + + desc = &buffer[64]; + for (i = 0; i < nr_cpr; i++, desc += 32) { + if (desc[0] != i) { + sd_printk(KERN_ERR, sdkp, + "Invalid Concurrent Positioning Range number\n"); + nr_cpr = 0; + break; + } + + cr->ranges[i].sector = sd64_to_sectors(sdkp, desc + 8); + cr->ranges[i].nr_sectors = sd64_to_sectors(sdkp, desc + 16); + } + +out: + blk_queue_set_cranges(sdkp->disk, cr); + if (nr_cpr && sdkp->nr_actuators != nr_cpr) { + sd_printk(KERN_NOTICE, sdkp, + "%u concurrent positioning ranges\n", nr_cpr); + sdkp->nr_actuators = nr_cpr; + } + + kfree(buffer); +} + /* * Determine the device's preferred I/O size for reads and writes * unless the reported value is unreasonably small, large, not a @@ -3240,6 +3319,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_app_tag_own(sdkp, buffer); sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); + sd_read_cpr(sdkp); } /* diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index b59136c4125b..2e5932bde43d 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -106,6 +106,7 @@ struct scsi_disk { u8 protection_type;/* Data Integrity Field */ u8 provisioning_mode; u8 zeroing_mode; + u8 nr_actuators; /* Number of actuators */ unsigned ATO : 1; /* state of disk ATO bit */ unsigned cache_override : 1; /* temp override of WCE,RCD */ unsigned WCE : 1; /* state of disk WCE bit */
Add the sd_read_cpr() function to the sd scsi disk driver to discover if a device has multiple concurrent positioning ranges (i.e. multiple actuators on an HDD). This new function is called from sd_revalidate_disk() and uses the block layer functions blk_alloc_cranges() and blk_queue_set_cranges() to set a device cranges according to the information retrieved from log page B9h, if the device supports it. The format of the Concurrent Positioning Ranges VPD page B9h is defined in section 6.6.6 of SBC-5. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> --- drivers/scsi/sd.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/sd.h | 1 + 2 files changed, 81 insertions(+)