[git commit] volume_id: improve handling of too-small (usually zero-byte or erroring) blockdevs
Denys Vlasenko
vda.linux at googlemail.com
Wed Feb 4 14:59:33 UTC 2026
commit: https://git.busybox.net/busybox/commit/?id=cdcb4ce314531bfea23b844be7df28ab8c0818da
branch: https://git.busybox.net/busybox/log/?h=master
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 <vda.linux at googlemail.com>
---
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(-)
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);
More information about the busybox-cvs
mailing list