I bought a new (in 2017) 4 TB harddrive, so I expected it to have a 4096 physical sector size. Indeed,

$ hdparm -I /dev/sdh
  ...
  Logical  Sector size:                   512 bytes
  Physical Sector size:                  4096 bytes
  Logical Sector-0 offset:                  0 bytes
  device size with M = 1000*1000:     4000787 MBytes (4000 GB)

However, when I tried to partition it with parted, I got a physical block size of 512:

$ parted /dev/sdh print
Model:   (scsi)
Disk /dev/sdh: 4001GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt

The drive is on an USB 3 port in a dockingstation (iTec) behind a USB bridge (152d:0561, JMicron JMS55 chipset).

The block layer seems to have the wrong size, too:

$ cat /sys/block/sdh/queue/physical_block_size
512
$ cat /sys/block/sdh/queue/minimum_io_size 
512

An READ CAPACITY (16) SCSI commands reports the wrong size, too:

$ sudo sg_readcap --16 /dev/sdh
Read Capacity results:
  Protection: prot_en=0, p_type=0, p_i_exponent=0
  Logical block provisioning: lbpme=0, lbprz=0
  Last logical block address=7814037167 (0x1d1c0beaf),
  Number of logical blocks=7814037168
  Logical block length=512 bytes
  Logical blocks per physical block exponent=0
  Lowest aligned logical block address=0

instead of (from another drive)

  Logical blocks per physical block exponent=3 [so physical block length=4096 bytes]

On the other hand, blockdev reports

$ blockdev --report /dev/sdh
RO    RA   SSZ   BSZ   StartSec            Size   Device
rw   256   512  4096          0   4000787030016   /dev/sdh

Googling finds vague information about USB bridges that do "4k/512 sector emulation, to allow large harddisks to have a MBR partition table", but if I understand this correctly, then the logical sector size should be 4096 for these bridges, which is not the case for my bridge.

So what exactly is going on? And how can I fix it, i.e. convince the kernel that this drive has physical blocks of 4096 bytes size? The physical_block_size and minimum_io_size attributes are not writeable.

One possible explanation is that there's a bug in the firmware of the bridge, and it just copies the first 12 bytes of the READ CAPACITY (16) response, zeroing out the exponent in byte 13. But in that case, I'd still like to work around the bug somehow.


Edit

I now tested it in a different (older) USB enclosure. Connecting with eSATA, everything works as intended, and READ CAPACITY (16) reports 4096 bytes physical sector size. Connecting via USB (04fc:0c25 Sunplus SATALink SPIF225A) complains that READ CAPACITY (16) is not supported (so no physical sector size), but READ CAPACITY (10) is.

That confirms that at least for the Sunplus bridge, SCSI commands are not arbitrarily forwarded, and makes it seem more likely that the JMicron USB bridge has a bug in the firmware, zeroing out the READ CAPACITY (16) response.

But I still need to know how to work around that bug.

man blockdev

   --setbsz bytes
          Set blocksize. Note that the block size is specific to the  cur‐
          rent  file descriptor opening the block device, so the change of
          block size only persists for as long as blockdev has the  device
          open, and is lost once blockdev exits.

In block/ioctl.c:

case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
    return put_int(arg, block_size(bdev));
case BLKSSZGET: /* get block device logical block size */
    return put_int(arg, bdev_logical_block_size(bdev));
case BLKPBSZGET: /* get block device physical block size */
    return put_uint(arg, bdev_physical_block_size(bdev));

So BSZ reported by blockdev is neither logical nor physical block size. It is the "soft block size".

Looking at this code, the part about soft block size being specific to the file descriptor does not appear to make sense. Nor does wanting to set that with blockdev, given that no other option is documented in terms of blocks (only fixed-size 512 byte sectors).

In my own tests, what actually happens is that BSZ is preserved for as long as any process holds the block device open. It looks like it gets reset on the last close().

Parted got confused by this too some years ago

belay that. BLKBSZGET is the kernel's chosen block size it will use to access the device (for normal disks turns out this is 1k, for ata_ram this is 4k), which is not the underlying disk's logical block size. :-( So we will likely need another ioctl() to get the right value from the kernel, and BLKSSZGET may wind up being the disks's logical block size, while a new ioctl() exports the disk's physical sector size. ugh.

Another quirk:

On Wed, Apr 09, 2003 at 06:53:17PM +0200, Rob van Nieuwkerk wrote:

I get 4096 with BLKBSZGET on several unmounted partitions on my system (RH 2.4.18-27.7.x kernel). Some give 1024 .. Maybe it is because I had them mounted first and unmounted them for the test ?

That would be the most likely answer. When you unmount, I don't believe the filesystem bothers to set_blocksize(get_hardsect_size(dev)).

  • 1
    Ok, so BLKB*GET (whereever it sits in the block layer) is maybe bogus. Doesn't change the fact that the real physical blocksize of that disk is 4096, and doesn't help me to work around the fact that this is not correctly reported behind the USB bridge. Being able to set minimum_io_size somehow would already help . – dirkt Nov 11 '17 at 18:13
  • You might find there is less advantage than you think. AFAIK modern Linux partitioning tools will align to 1MB, whatever the drive says. All writes that go through the page cache will already happen to be forced to the page size i.e. 4K. I believe the ext* filesystems also use the page cache for some internal operations. I agree it does not seem ideal in the general case though. – sourcejedi Nov 11 '17 at 18:30
  • I agree with @sourcejedi that the physical block size is rather irrelevant. It only tells you that you had better align the structures on disk to 4k, or else you will suffer a performance penalty. For all other purposes the logical block size is the only thing that matters, and since the logical block size for the drive in question is 512, it works entirely like a traditional disk drive. – Johan Myréen Nov 11 '17 at 19:41
  • @JohanMyréen Surely it also means it wants caching to be implemented at a 4Kb granularity. Otherwise, when you go to write back a smaller data structure, the drive has to do a read/modify/write cycle. The difference is that the drive has a smaller cache than the host PC. Therefore it's more likely the PC can keep the whole physical sector in cache and avoid having to do extra reads. So the PC wants to know the physical sector size. – sourcejedi Nov 11 '17 at 20:12
  • 1
    @JohanMyréen (and sourcejedi): The discussion about "everything 'should' just work" is all very interesting, but it would still be easier to not rely on that and just set the gorram correct values. So that doesn't help, either. I perfectly know that in the worst case only performance will suffer. Still, if I can work around the bridge bug, I'd like to. – dirkt Nov 11 '17 at 20:51

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.