.. _linux_ssd_partition_alignment: ===================== Linux SSD分区对齐 ===================== .. note:: 本文是探寻为何新购买的USB SSD磁盘起始扇区不是常规的 ``2048`` 而是 ``65535`` ,并且使用了 ``parted`` 强制手段来对齐到 ``2048`` ( ``1MiB`` )。 不过,虽然可以强制对齐 ``2048`` ,但是考虑到 ``USB-to-SATA`` 控制器的参数是厂商提供的,应该有其优化原因(例如大数据块读写)。所以,最终并没有采用本文强制对齐 ``2048`` 扇区( ``1MiB`` ),而是按照 ``parted`` 默认对齐优化方式分区。所以会和之前SSD磁盘分区有些差异,对使用来说没有区别。 本文仅供参考。 正如 `Linux SSD partition alignment – problems with external USB-to-SATA controllers – I `_ 开头所说: 当你尝试解决一个问题,就会发现你从来没有意料的新问题出现。 奇怪的65535起始扇区 ======================= 我在构建 :ref:`edge_cloud` 的树莓派集群,选购的 :ref:`wd_passport_ssd` ,在第三次购买的西数Passport SSD虽然 ``fdisk -l /dev/sda`` 显示有:: Disk /dev/sda: 931.51 GiB, 1000204886016 bytes, 1953525168 sectors Disk model: ssport Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes Disklabel type: dos Disk identifier: 0x221a87f7 Device Boot Start End Sectors Size Id Type /dev/sda1 2048 1953521663 1953519616 931.5G 7 HPFS/NTFS/exFAT 但是我发现不管怎样使用 ``fdisk`` 创建分区,默认都只能从 ``65535`` 扇区开始:: Welcome to fdisk (util-linux 2.36.1). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Command (m for help): p Disk /dev/sda: 931.51 GiB, 1000204886016 bytes, 1953525168 sectors Disk model: ssport Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes Disklabel type: dos Disk identifier: 0xcb6a7256 Command (m for help): n Partition type p primary (0 primary, 0 extended, 4 free) e extended (container for logical partitions) Select (default p): p Partition number (1-4, default 1): First sector (65535-1953525167, default 65535): Last sector, +/-sectors or +/-size{K,M,G,T,P} (65535-1953525167, default 1953525167): +256MB Created a new partition 1 of type 'Linux' and of size 256 MiB. Command (m for help): p Disk /dev/sda: 931.51 GiB, 1000204886016 bytes, 1953525168 sectors Disk model: ssport Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes Disklabel type: dos Disk identifier: 0xcb6a7256 Device Boot Start End Sectors Size Id Type /dev/sda1 65535 589814 524280 256M 83 Linux Partition 1 does not start on physical sector boundary. 可以看到分区开始位置并不是物理扇区边界 ``Partition 1 does not start on physical sector boundary.`` 我注意到我前2次购买到 ``Disk model: My Passport 25F3`` 设备的 ``Sector size`` 和 ``I/O size (logical/physical)`` 和第3次购买的设备不同,原先是:: Disk /dev/sda: 953.86 GiB, 1024175636480 bytes, 2000343040 sectors Disk model: My Passport 25F3 Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 1048576 bytes Disklabel type: dos Disk identifier: 0xab86aefd Device Boot Start End Sectors Size Id Type /dev/sda1 * 2048 526335 524288 256M c W95 FAT32 (LBA) /dev/sda2 526336 67635199 67108864 32G 83 Linux 为什么第3次购买的设备:: Disk model: ssport ... Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes 而之前2次购买的设备sector不同:: Disk model: My Passport 25F3 ... Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 1048576 bytes 物理扇区从 ``4096`` 字节变成了 ``512`` 字节,而优化I/O大小从原先的 1MB (1048576/1024.0=1024.0) 更改成了约 32MB (33553920/1024.0/1024.0=31.99951171875) `How to fix “Partition does not start on physical sector boundary” warning? `_ 提到了西部数据 `Advanced_Format `_ 使用了4096字节的物理扇区取代陈旧的每个扇区512字节。并且西数还提供了一个 `Advanced Format Hard Drive Download Utility `_ 介绍了在旧设备上启用Advanced Formatting提高性 能。 Western Digital Dashboard ---------------------------- 西部数据提供了 `Western Digital Dashboard `_ 帮助用户分析磁盘(包括磁盘型号,容量,firmware版本和SMART属性)以及firmware更新 `Western Digital Dashboard `_ 提供了Windows版本,我部署使用 :ref:`alpine_extended` ,通过 :ref:`kvm` 运行Windows虚拟机来测试SSD 磁盘,验证和排查为何最新购买的SSD磁盘使用了较小的物理扇区(512字节sector) 1 MiB-alignment ==================== 对于SSD磁盘,通常会希望Linux使用 ``1 MiB-alignment`` ,也就是以 ``512`` 字节的逻辑扇区,共计 ``2048`` 个扇区,磁盘的第一个分区会对齐在 ``2048 * 512 = 1024 * 1024 = 1 (MiB) = 256 * 4096`` 。 这个第一分区的起始扇区也就是称为具备原生4k支持的AF磁盘,不论磁盘底层使用 ``512`` 字节还是 ``4096`` 字节,都能保证 ``1 MiB-alignment`` 能够对齐物理扇区。 - 磁盘通过 ``lsblk`` 检查:: # lsblk /dev/sde NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sde 8:64 0 931.5G 0 disk 可以看到上述存在比较奇怪问题的 :ref:`wd_passport_ssd` 规格是 ``931.5G`` 。而我另外购买的2快同样型号 :ref:`wd_passport_ssd` 使用 ``lsblk`` 检查却是 ``953.8G`` :: # lsblk /dev/sda NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 953.8G 0 disk ├─sda1 8:1 0 256M 0 part /media/sda1 └─sda2 8:2 0 32G 0 part / - 当使用 ``fdisk`` 或者 ``pated`` 分区,就会看到第一个分区始终只能建立在从 ``65535`` 扇区开始,而这个 ``65535`` 扇区不是 ``2048`` 的倍数 .. literalinclude:: linux_ssd_partition_alignment/fdisk.txt :language: bash :caption: fdisk和parted分区显示从 65535 开始 `Linux SSD partition alignment – problems with external USB-to-SATA controllers – I `_ 的作者做了一个测试,将SSD移动硬盘从USB外接上拆下来,直接连接到主机的SATA控制器,则再次使用 ``fdisk`` 划分分区就会从 ``2048`` 扇区开始。这说明: - 通过外接的 ``USB-to-Sata-controller bus`` ,磁盘的起始扇区会从 ``65535`` 的倍数开始 Linux如何搜集和报告磁盘属性 ============================= 从 RedHat 的网站上可以找到 `io-limits.txt `_ 说明了 "I/O Limits" 是基于 ``sysfs`` 和 ``块设备`` 的 ``ioctl`` 接口( 如 ``libblkid`` )获取信息: - ``sysfs interface`` :: /sys/block//alignment_offset /sys/block///alignment_offset /sys/block//queue/physical_block_size /sys/block//queue/logical_block_size /sys/block//queue/minimum_io_size /sys/block//queue/optimal_io_size 我们检查这个存在问题的磁盘就可以看到: .. literalinclude:: linux_ssd_partition_alignment/sysfs_block_sde.txt :language: bash :caption: 起始扇区65535的磁盘 I/O Limits信息 而之前正常磁盘的信息 .. literalinclude:: linux_ssd_partition_alignment/sysfs_block_sda.txt :language: bash :caption: 起始扇区2048的磁盘 I/O Limits信息 上述信息称为 "I/O Limits" 数据 通过 ``lsblk`` 命令,我们可以看出上述数据:: lsblk -o NAME,ALIGNMENT,MIN-IO,OPT-IO,PHY-SEC,LOG-SEC 此时输出对比就可以看到,那块起始扇区异常位于 ``65535`` 扇区的USB外接SSD磁盘输出如下:: NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC sde 0 4096 33553920 512 512 而正常输出则是:: NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC sda 0 4096 1048576 4096 512 此外,对比直接连接在SATA接口上的SSD磁盘,会看到这个 ``optimal_io_size`` 显示是 ``0`` ,例如,以下是一块intel 内置2.5" SSD固态硬盘:: NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC sda 0 512 0 512 512 将SSD移动硬盘直接接在SATA接口上,则 ``optimal_io_size`` 显示是 ``0`` ,而我购买的 :ref:`wd_passport_ssd` 接在USB接口上显示有2种值,一种是比较正常的:: NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC sda 0 4096 1048576 4096 512 另一种是比较异常的:: NAME ALIGNMENT MIN-IO OPT-IO PHY-SEC LOG-SEC sde 0 4096 33553920 512 512 导致不同对齐的原因 ===================== Linux分区工具,例如 ``parted`` 使用 ``libblkid`` 的输出信息,而 Linux 则是基于磁盘的属性数据( ``I/O Limits`` )来 ``启发`` 对齐决策,根据: `io-limits.txt `_ 所谓的启发分区:: "The heuristic parted uses is: 1) Always use the reported 'alignment_offset' as the offset for the start of the first primary partition. 2a) If 'optimal_io_size' is defined (not 0) align all partitions on an 'optimal_io_size' boundary. 2b) If 'optimal_io_size' is undefined (0) and 'alignment_offset' is 0 and 'minimum_io_size' is a power of 2: use a 1MB default alignment. - as you can see this is the catch all for "legacy" devices which don't appear to provide "I/O hints"; so in the default case all partitions will align on a 1MB boundary. - NOTE: we can't distinguish between a "legacy" device and modern device that provides "I/O hints" with alignment_offset=0 and optimal_io_size=0. Such a device might be a single SAS 4K device. So worst case we lose < 1MB of space at the start of the disk." 由于异常磁盘报告: ``optimal_io_size: 33553920 (bytes)`` (32MB),则 ``33553920 / 512 = 65535`` ,所以就会把磁盘分区的起始扇区决定为 **65535** 而正常的磁盘报告: ``optimal_io_size: 1048576 (bytes)`` (1MB),则 ``1048576 / 512 = 2048`` ,则把磁盘分区的起始扇区决定为 **2048** 注意,对于直接通过SATA接口连接的intel SSD磁盘,报告的 ``optimal_io_size: 0`` ,则Linux内核自动把扇区对齐到 1MB 位置。 .. note:: 为什么我最近购买的 :ref:`wd_passport_ssd` 会报告一个非常高的 ``optimal_io_value`` ,高达 32MiB ? parted忽略 ``heuristic`` ========================= 由于Linux的分区工具,是通过 ``libblkid`` 库来监测磁盘拓扑参数(I/O limits),通过 ``heuristic rules`` (启发式规则)来决定对齐,这就导致了SSD磁盘接在内置SATA磁盘接口和USB转换SATA外置接口不同的参数,引发不同的对齐策略。 虽然 ``fdisk`` 和 ``prated`` 都是使用 ``libblkid`` 库,导致磁盘起始扇区没有实现 ``1MiB-alignment`` ,但是,如果使用 ``gdisk`` 则会忽略这个问题,即使通过外接 ``USB-to-SATA-controller`` 依然会执行 ``1MiB-alignment`` 。 此外,虽然 ``fdisk`` 不能忽略 ``65535`` 的起始扇区,但是 ``parted`` 却提供了强制创建分区(忽略对齐 ``65535`` ):: # parted /dev/sde mkpart primary fat32 1MiB 257MiB Warning: The resulting partition is not properly aligned for best performance: 4000000s % 65535s != 0s Ignore/Cancel? i Information: You may need to update /etc/fstab. 可以看到,上面 ``parted`` 命令强制创建分区从 ``1MiB`` 开始,也就是 ``2048`` 扇区开始,同时结束是 ``257MiB`` ,则分区空间就是 256 MB。 然后通过 ``fdisk -l /dev/sde`` 命令可以检查:: Disk /dev/sde: 931.53 GiB, 1000204886016 bytes, 1953525168 sectors Disk model: ssport Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes Disklabel type: dos Disk identifier: 0xd7882f4e Device Boot Start End Sectors Size Id Type /dev/sde1 2048 526335 524288 256M c W95 FAT32 (LBA) 然后再添加第二个分区:: parted /dev/sde mkpart primary ext4 257MiB 32GiB 不过,我发现 ``parted`` 划分的分区只能指定 ``start`` 和 ``end`` ,所以实际划分的分区大小和之前使用 ``fdisk`` 划分分区使用 ``+32G`` 获得的分区大小有一点点区别。所以最终第2个分区我是使用 ``fdisk`` 来添加的。使用 ``fdisk`` 命令添加分区可以直接指定扇区或分区大小(只有第一个分区受到 ``65535`` 影响无法指定 ``2048`` ,第二个分区已经超出 ``65535`` 就还是可以使用 ``fdisk`` 来管理分配的) 使用 ``fdisk /dev/sde`` 划分第二个分区步骤如下: .. literalinclude:: linux_ssd_partition_alignment/fdisk_sde2.txt :language: bash :caption: 在parted强制划分第一个分区从2048扇区开始,再用fdisk添加第二个扇区 完成后可以看到,分区的扇区和之前 :ref:`alpine_install_pi_usb_boot` 完全一致。 然后就可以完成 :ref:`alpine_pi_usb_boot_clone` - 不过,上述强制分区对齐到 ``1MiB`` 上,使用 ``parted`` 检查分区是显示不对齐的:: Disk /dev/sde: 931.53 GiB, 1000204886016 bytes, 1953525168 sectors Disk model: ssport Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4096 bytes / 33553920 bytes Disklabel type: dos Disk identifier: 0xd7882f4e Device Boot Start End Sectors Size Id Type /dev/sde1 2048 526335 524288 256M c W95 FAT32 (LBA) /dev/sde2 526336 67635199 67108864 32G 83 Linux 检查命令显示如下:: # parted /dev/sde align-check opt 1 1 not aligned: 2048s % 65535s != 0s # parted /dev/sde align-check opt 2 2 not aligned: 526336s % 65535s != 0s 参考 ====== - `Linux SSD partition alignment – problems with external USB-to-SATA controllers – I `_ - `Why does fdisk insist on starting the first partition at sector 65535 (MiB 31.9995...) `_