From bb1158b92ed8a12ab9e9317ca6ddd97bc12447d3 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 17 May 2010 22:31:45 -0400 Subject: [PATCH] mke2fs: account for physical as well as logical sector size 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 Signed-off-by: "Theodore Ts'o" --- debian/e2fslibs.symbols | 1 + lib/ext2fs/ext2fs.h | 1 + lib/ext2fs/getsectsize.c | 35 +++++++++++++++++++++++++++++++++-- lib/ext2fs/tst_getsectsize.c | 14 ++++++++++---- misc/mke2fs.c | 34 ++++++++++++++++++++++++++++------ 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/debian/e2fslibs.symbols b/debian/e2fslibs.symbols index c203f02..c5a6a0b 100644 --- a/debian/e2fslibs.symbols +++ b/debian/e2fslibs.symbols @@ -163,6 +163,7 @@ libext2fs.so.2 e2fslibs #MINVER# ext2fs_get_blocks@Base 1.37 ext2fs_get_data_io@Base 1.37 ext2fs_get_device_sectsize@Base 1.37 + ext2fs_get_device_phys_sectsize@Base 1.41.12 ext2fs_get_device_size2@Base 1.41.4 ext2fs_get_device_size@Base 1.37 ext2fs_get_free_blocks@Base 1.37 diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index a3d3cd3..2674941 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -942,6 +942,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 09fb45c..64f42a6 100644 --- a/lib/ext2fs/getsectsize.c +++ b/lib/ext2fs/getsectsize.c @@ -26,15 +26,20 @@ #include #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 863cf64..5591b5d 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 5843ed4..ac87b8e 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -1130,7 +1130,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; @@ -1645,16 +1645,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); @@ -1665,12 +1674,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; fs_param.s_blocks_count /= 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) { -- 1.8.3.1