From cdcb4ce314531bfea23b844be7df28ab8c0818da Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 4 Feb 2026 15:48:59 +0100 Subject: volume_id: improve handling of too-small (usually zero-byte or erroring) blockdevs function old new delta volume_id_get_buffer 327 372 +45 volume_id_open_node 17 24 +7 volume_id_probe_all 133 123 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 52/-10) Total: 42 bytes Signed-off-by: Denys Vlasenko --- util-linux/volume_id/util.c | 29 ++++++++++++++++++++++------- util-linux/volume_id/volume_id.c | 25 +++++++++++++++---------- util-linux/volume_id/volume_id_internal.h | 16 +++++++++++++++- 3 files changed, 52 insertions(+), 18 deletions(-) (limited to 'util-linux') diff --git a/util-linux/volume_id/util.c b/util-linux/volume_id/util.c index b154f9378..b59aa99b2 100644 --- a/util-linux/volume_id/util.c +++ b/util-linux/volume_id/util.c @@ -176,6 +176,12 @@ void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) unsigned small_off; ssize_t read_len; + if (id->known_size != UNKNOWN_SIZE + && id->known_size < off + len + ) { + return NULL; + } + dbg("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len); @@ -224,20 +230,29 @@ void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len) do_read: if (lseek(id->fd, off, SEEK_SET) != off) { dbg("seek(0x%llx) failed", (unsigned long long) off); + off = lseek(id->fd, 0, SEEK_END); + if (off < 0) + off = 0; goto err; } read_len = full_read(id->fd, dst, len); if (read_len != len) { dbg("requested 0x%x bytes, got 0x%x bytes", (unsigned) len, (unsigned) read_len); + if (read_len > 0) + off += read_len; err: - /* No filesystem can be this tiny. It's most likely - * non-associated loop device, empty drive and so on. - * Flag it, avoiding future accesses. Rationale: - * users complained of slow blkid due to empty floppy drives. - */ - if (off <= 1024) - id->error = 1; + /* The image is definitely only OFF bytes large */ + if (off < UNKNOWN_SIZE) { + /* ...and OFF is small, we can use + * that knowledge to skip future probes: + * cases such as non-associated loop devices, + * empty (floppy) drives and so on. + * Record it, avoiding future accesses. Users + * complained of slow blkid due to empty floppys. + */ + id->known_size = off; + } /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. */ volume_id_free_buffer(id); return NULL; diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c index 8ceb61bde..53715121b 100644 --- a/util-linux/volume_id/volume_id.c +++ b/util-linux/volume_id/volume_id.c @@ -180,6 +180,7 @@ static const probe_fptr fs2[] ALIGN_PTR = { int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size) { + int retval = 0; unsigned i; /* probe for raid first, cause fs probes may be successful on raid members */ @@ -187,24 +188,26 @@ int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64 for (i = 0; i < ARRAY_SIZE(raid1); i++) { if (raid1[i](id, /*off,*/ size) == 0) goto ret; - if (id->error) - goto ret; + //if (id->known_size < MIN_VALID_FS_SIZE) + // goto ret_bad; +//Redundant? none of the subsequent probers will succeed +//(or even attempt reads) if the above is true. } } for (i = 0; i < ARRAY_SIZE(raid2); i++) { if (raid2[i](id /*,off*/) == 0) goto ret; - if (id->error) - goto ret; + //if (id->known_size < MIN_VALID_FS_SIZE) + // goto ret_bad; } /* signature in the first block, only small buffer needed */ for (i = 0; i < ARRAY_SIZE(fs1); i++) { if (fs1[i](id /*,off*/) == 0) goto ret; - if (id->error) - goto ret; + //if (id->known_size < MIN_VALID_FS_SIZE) + // goto ret_bad; } /* fill buffer with maximum */ @@ -213,13 +216,14 @@ int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64 for (i = 0; i < ARRAY_SIZE(fs2); i++) { if (fs2[i](id /*,off*/) == 0) goto ret; - if (id->error) - goto ret; + //if (id->known_size < MIN_VALID_FS_SIZE) + // goto ret_bad; } - + //ret_bad: + retval = -1; /* "not found" */ ret: volume_id_free_buffer(id); - return (- id->error); /* 0 or -1 */ + return retval; } /* open volume by device node */ @@ -229,6 +233,7 @@ struct volume_id* FAST_FUNC volume_id_open_node(int fd) id = xzalloc(sizeof(struct volume_id)); id->fd = fd; + id->known_size = UNKNOWN_SIZE; ///* close fd on device close */ //id->fd_close = 1; return id; diff --git a/util-linux/volume_id/volume_id_internal.h b/util-linux/volume_id/volume_id_internal.h index b1e44481f..39699ef72 100644 --- a/util-linux/volume_id/volume_id_internal.h +++ b/util-linux/volume_id/volume_id_internal.h @@ -60,7 +60,9 @@ struct volume_id_partition { struct volume_id { int fd; // int fd_close:1; - int error; + /* UNKNOWN_SIZE: unknown, N: seek+read stopped at N prematurely */ + unsigned known_size; +#define UNKNOWN_SIZE UINT_MAX size_t sbbuf_len; size_t seekbuf_len; uint8_t *sbbuf; @@ -85,6 +87,18 @@ struct volume_id { // const char *usage; }; +// Technically, the tiniest possible linux FS image (romfs) with only "." and ".." is: +//00000000 2D 72 6F 6D 31 66 73 2D 00 00 00 60 A1 27 1D 06 -rom1fs-...`.'.. +//00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +//00000020 00 00 00 49 00 00 00 20 00 00 00 00 D1 FF FF 97 ...I... ........ +//00000030 2E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +//00000040 00 00 00 00 00 00 00 20 00 00 00 00 D1 D1 FF E0 ....... ........ +//00000050 2E 2E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +// but kernel won't mount it unless it's padded to 1K. +// Stop trying new FS types in volume_id_probe_all() outright +// if a previous probe had a read which stopped before 1K: +#define MIN_VALID_FS_SIZE 1024 + struct volume_id* FAST_FUNC volume_id_open_node(int fd); int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size); void FAST_FUNC free_volume_id(struct volume_id *id); -- cgit v1.2.3-55-g6feb