Some devices, notably 4k sector drives, may have a 512 logical sector size, mapped onto a 4k physical sector size. When mke2fs is ratcheting down the blocksize for small filesystems, or when a blocksize is specified on the commandline, we should not willingly go below the physical sector size of the device. When a blocksize is specified, we -must- not go below the logical sector size of the device. Add a new library function, ext2fs_get_device_phys_sectsize() to get the physical sector size if possible, and adjust the logic in mke2fs to enforce the above rules. Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx> --- (V2: just forgot to update the subject after changing the patch) diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 213a819..9c06048 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -1086,6 +1086,7 @@ extern errcode_t ext2fs_get_device_size2(const char *file, int blocksize, /* getsectsize.c */ errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize); +errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize); /* i_block.c */ errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode, diff --git a/lib/ext2fs/getsectsize.c b/lib/ext2fs/getsectsize.c index ae9139d..0c7fa82 100644 --- a/lib/ext2fs/getsectsize.c +++ b/lib/ext2fs/getsectsize.c @@ -26,15 +26,20 @@ #include <linux/fd.h> #endif -#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET) +#if defined(__linux__) && defined(_IO) +#if !defined(BLKSSZGET) #define BLKSSZGET _IO(0x12,104)/* get block device sector size */ #endif +#if !defined(BLKPBSZGET) +#define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */ +#endif +#endif #include "ext2_fs.h" #include "ext2fs.h" /* - * Returns the number of blocks in a partition + * Returns the logical sector size of a device */ errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize) { @@ -58,3 +63,29 @@ errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize) close(fd); return 0; } + +/* + * Returns the physical sector size of a device + */ +errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize) +{ + int fd; + +#ifdef HAVE_OPEN64 + fd = open64(file, O_RDONLY); +#else + fd = open(file, O_RDONLY); +#endif + if (fd < 0) + return errno; + +#ifdef BLKPBSZGET + if (ioctl(fd, BLKPBSZGET, sectsize) >= 0) { + close(fd); + return 0; + } +#endif + *sectsize = 0; + close(fd); + return 0; +} diff --git a/lib/ext2fs/tst_getsectsize.c b/lib/ext2fs/tst_getsectsize.c index cb1b8c6..31599d2 100644 --- a/lib/ext2fs/tst_getsectsize.c +++ b/lib/ext2fs/tst_getsectsize.c @@ -27,7 +27,7 @@ int main(int argc, char **argv) { - int sectsize; + int lsectsize, psectsize; int retval; if (argc < 2) { @@ -35,13 +35,19 @@ int main(int argc, char **argv) exit(1); } - retval = ext2fs_get_device_sectsize(argv[1], §size); + retval = ext2fs_get_device_sectsize(argv[1], &lsectsize); if (retval) { com_err(argv[0], retval, "while calling ext2fs_get_device_sectsize"); exit(1); } - printf("Device %s has a hardware sector size of %d.\n", - argv[1], sectsize); + retval = ext2fs_get_device_phys_sectsize(argv[1], &psectsize); + if (retval) { + com_err(argv[0], retval, + "while calling ext2fs_get_device_phys_sectsize"); + exit(1); + } + printf("Device %s has logical/physical sector size of %d/%d.\n", + argv[1], lsectsize, psectsize); exit(0); } diff --git a/misc/mke2fs.c b/misc/mke2fs.c index 94b4c81..1a1307b 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -1068,7 +1068,7 @@ static void PRS(int argc, char *argv[]) int inode_size = 0; unsigned long flex_bg_size = 0; double reserved_ratio = 5.0; - int sector_size = 0; + int lsector_size = 0, psector_size = 0; int show_version_only = 0; unsigned long long num_inodes = 0; /* unsigned long long to catch too-large input */ errcode_t retval; @@ -1586,16 +1586,25 @@ got_size: ((tmp = getenv("MKE2FS_FIRST_META_BG")))) fs_param.s_first_meta_bg = atoi(tmp); - /* Get the hardware sector size, if available */ - retval = ext2fs_get_device_sectsize(device_name, §or_size); + /* Get the hardware sector sizes, if available */ + retval = ext2fs_get_device_sectsize(device_name, &lsector_size); if (retval) { com_err(program_name, retval, _("while trying to determine hardware sector size")); exit(1); } + retval = ext2fs_get_device_phys_sectsize(device_name, &psector_size); + if (retval) { + com_err(program_name, retval, + _("while trying to determine physical sector size")); + exit(1); + } + /* Older kernels may not have physical/logical distinction */ + if (!psector_size) + psector_size = lsector_size; if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL) - sector_size = atoi(tmp); + psector_size = atoi(tmp); if (blocksize <= 0) { use_bsize = get_int_from_profile(fs_types, "blocksize", 4096); @@ -1606,14 +1615,25 @@ got_size: (use_bsize > 4096)) use_bsize = 4096; } - if (sector_size && use_bsize < sector_size) - use_bsize = sector_size; + if (psector_size && use_bsize < psector_size) + use_bsize = psector_size; if ((blocksize < 0) && (use_bsize < (-blocksize))) use_bsize = -blocksize; blocksize = use_bsize; ext2fs_blocks_count_set(&fs_param, ext2fs_blocks_count(&fs_param) / (blocksize / 1024)); + } else { + if (blocksize < lsector_size || /* Impossible */ + (!force && (blocksize < psector_size))) { /* Suboptimal */ + com_err(program_name, EINVAL, + _("while setting blocksize; too small for device\n")); + exit(1); + } else if (blocksize < psector_size) { + fprintf(stderr, _("Warning: specified blocksize %d is " + "less than device physical sectorsize %d, " + "forced to continue\n"), blocksize, psector_size); + } } if (inode_ratio == 0) { -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html