]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
sd: Fix excessive capacity printing on devices with blocks bigger than 512 bytes
authorMartin K. Petersen <martin.petersen@oracle.com>
Tue, 29 Mar 2016 01:18:56 +0000 (21:18 -0400)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 30 Apr 2016 22:06:07 +0000 (00:06 +0200)
commit f08bb1e0dbdd0297258d0b8cd4dbfcc057e57b2a upstream.

During revalidate we check whether device capacity has changed before we
decide whether to output disk information or not.

The check for old capacity failed to take into account that we scaled
sdkp->capacity based on the reported logical block size. And therefore
the capacity test would always fail for devices with sectors bigger than
512 bytes and we would print several copies of the same discovery
information.

Avoid scaling sdkp->capacity and instead adjust the value on the fly
when setting the block device capacity and generating fake C/H/S
geometry.

Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Reported-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Hannes Reinicke <hare@suse.de>
Reviewed-by: Ewan Milne <emilne@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
[bwh: Backported to 3.16:
 - logical_to_sectors() is a new function
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/scsi/sd.c
drivers/scsi/sd.h

index 4856d585dd3ed55e5709b90be5a2bb5f270ce9f6..b3831236a1477854ca8e5cdcb202da91d6b0788c 100644 (file)
@@ -1230,18 +1230,19 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
        struct scsi_device *sdp = sdkp->device;
        struct Scsi_Host *host = sdp->host;
+       sector_t capacity = logical_to_sectors(sdp, sdkp->capacity);
        int diskinfo[4];
 
        /* default to most commonly used values */
-        diskinfo[0] = 0x40;    /* 1 << 6 */
-               diskinfo[1] = 0x20;     /* 1 << 5 */
-               diskinfo[2] = sdkp->capacity >> 11;
-       
+       diskinfo[0] = 0x40;     /* 1 << 6 */
+       diskinfo[1] = 0x20;     /* 1 << 5 */
+       diskinfo[2] = capacity >> 11;
+
        /* override with calculated, extended default, or driver values */
        if (host->hostt->bios_param)
-               host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);
+               host->hostt->bios_param(sdp, bdev, capacity, diskinfo);
        else
-               scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+               scsicam_bios_param(bdev, capacity, diskinfo);
 
        geo->heads = diskinfo[0];
        geo->sectors = diskinfo[1];
@@ -2220,14 +2221,6 @@ got_data:
 
        sdp->use_16_for_rw = (sdkp->capacity > 0xffffffff);
 
-       /* Rescale capacity to 512-byte units */
-       if (sector_size == 4096)
-               sdkp->capacity <<= 3;
-       else if (sector_size == 2048)
-               sdkp->capacity <<= 2;
-       else if (sector_size == 1024)
-               sdkp->capacity <<= 1;
-
        blk_queue_physical_block_size(sdp->request_queue,
                                      sdkp->physical_block_size);
        sdkp->device->sector_size = sector_size;
@@ -2751,7 +2744,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
 
        blk_queue_flush(sdkp->disk->queue, flush);
 
-       set_capacity(disk, sdkp->capacity);
+       set_capacity(disk, logical_to_sectors(sdp, sdkp->capacity));
        sd_config_write_same(sdkp);
        kfree(buffer);
 
index 620871efbf0a38e4cb496ef80b16c7bf1c9d1f5a..3b38766966038e954b80d31ed0259651ccf2988b 100644 (file)
@@ -63,7 +63,7 @@ struct scsi_disk {
        struct device   dev;
        struct gendisk  *disk;
        atomic_t        openers;
-       sector_t        capacity;       /* size in 512-byte sectors */
+       sector_t        capacity;       /* size in logical blocks */
        u32             max_ws_blocks;
        u32             max_unmap_blocks;
        u32             unmap_granularity;
@@ -142,6 +142,11 @@ static inline int scsi_medium_access_command(struct scsi_cmnd *scmd)
        return 0;
 }
 
+static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blocks)
+{
+       return blocks << (ilog2(sdev->sector_size) - 9);
+}
+
 /*
  * A DIF-capable target device can be formatted with different
  * protection schemes.  Currently 0 through 3 are defined: