aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2026-02-04 15:48:59 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2026-02-04 15:59:33 +0100
commitcdcb4ce314531bfea23b844be7df28ab8c0818da (patch)
treecfc26770de6d106955bb652cb0564860402f38a9
parent7310339e73d369e9636d1f44446234f58b4ca54e (diff)
downloadbusybox-w32-cdcb4ce314531bfea23b844be7df28ab8c0818da.tar.gz
busybox-w32-cdcb4ce314531bfea23b844be7df28ab8c0818da.tar.bz2
busybox-w32-cdcb4ce314531bfea23b844be7df28ab8c0818da.zip
volume_id: improve handling of too-small (usually zero-byte or erroring) blockdevsbusybox
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@googlemail.com>
-rw-r--r--util-linux/volume_id/util.c29
-rw-r--r--util-linux/volume_id/volume_id.c25
-rw-r--r--util-linux/volume_id/volume_id_internal.h16
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)
176 unsigned small_off; 176 unsigned small_off;
177 ssize_t read_len; 177 ssize_t read_len;
178 178
179 if (id->known_size != UNKNOWN_SIZE
180 && id->known_size < off + len
181 ) {
182 return NULL;
183 }
184
179 dbg("get buffer off 0x%llx(%llu), len 0x%zx", 185 dbg("get buffer off 0x%llx(%llu), len 0x%zx",
180 (unsigned long long) off, (unsigned long long) off, len); 186 (unsigned long long) off, (unsigned long long) off, len);
181 187
@@ -224,20 +230,29 @@ void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
224 do_read: 230 do_read:
225 if (lseek(id->fd, off, SEEK_SET) != off) { 231 if (lseek(id->fd, off, SEEK_SET) != off) {
226 dbg("seek(0x%llx) failed", (unsigned long long) off); 232 dbg("seek(0x%llx) failed", (unsigned long long) off);
233 off = lseek(id->fd, 0, SEEK_END);
234 if (off < 0)
235 off = 0;
227 goto err; 236 goto err;
228 } 237 }
229 read_len = full_read(id->fd, dst, len); 238 read_len = full_read(id->fd, dst, len);
230 if (read_len != len) { 239 if (read_len != len) {
231 dbg("requested 0x%x bytes, got 0x%x bytes", 240 dbg("requested 0x%x bytes, got 0x%x bytes",
232 (unsigned) len, (unsigned) read_len); 241 (unsigned) len, (unsigned) read_len);
242 if (read_len > 0)
243 off += read_len;
233 err: 244 err:
234 /* No filesystem can be this tiny. It's most likely 245 /* The image is definitely only OFF bytes large */
235 * non-associated loop device, empty drive and so on. 246 if (off < UNKNOWN_SIZE) {
236 * Flag it, avoiding future accesses. Rationale: 247 /* ...and OFF is small, we can use
237 * users complained of slow blkid due to empty floppy drives. 248 * that knowledge to skip future probes:
238 */ 249 * cases such as non-associated loop devices,
239 if (off <= 1024) 250 * empty (floppy) drives and so on.
240 id->error = 1; 251 * Record it, avoiding future accesses. Users
252 * complained of slow blkid due to empty floppys.
253 */
254 id->known_size = off;
255 }
241 /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. */ 256 /* id->seekbuf_len or id->sbbuf_len is wrong now! Fixing. */
242 volume_id_free_buffer(id); 257 volume_id_free_buffer(id);
243 return NULL; 258 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 = {
180 180
181int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size) 181int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size)
182{ 182{
183 int retval = 0;
183 unsigned i; 184 unsigned i;
184 185
185 /* probe for raid first, cause fs probes may be successful on raid members */ 186 /* 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
187 for (i = 0; i < ARRAY_SIZE(raid1); i++) { 188 for (i = 0; i < ARRAY_SIZE(raid1); i++) {
188 if (raid1[i](id, /*off,*/ size) == 0) 189 if (raid1[i](id, /*off,*/ size) == 0)
189 goto ret; 190 goto ret;
190 if (id->error) 191 //if (id->known_size < MIN_VALID_FS_SIZE)
191 goto ret; 192 // goto ret_bad;
193//Redundant? none of the subsequent probers will succeed
194//(or even attempt reads) if the above is true.
192 } 195 }
193 } 196 }
194 197
195 for (i = 0; i < ARRAY_SIZE(raid2); i++) { 198 for (i = 0; i < ARRAY_SIZE(raid2); i++) {
196 if (raid2[i](id /*,off*/) == 0) 199 if (raid2[i](id /*,off*/) == 0)
197 goto ret; 200 goto ret;
198 if (id->error) 201 //if (id->known_size < MIN_VALID_FS_SIZE)
199 goto ret; 202 // goto ret_bad;
200 } 203 }
201 204
202 /* signature in the first block, only small buffer needed */ 205 /* signature in the first block, only small buffer needed */
203 for (i = 0; i < ARRAY_SIZE(fs1); i++) { 206 for (i = 0; i < ARRAY_SIZE(fs1); i++) {
204 if (fs1[i](id /*,off*/) == 0) 207 if (fs1[i](id /*,off*/) == 0)
205 goto ret; 208 goto ret;
206 if (id->error) 209 //if (id->known_size < MIN_VALID_FS_SIZE)
207 goto ret; 210 // goto ret_bad;
208 } 211 }
209 212
210 /* fill buffer with maximum */ 213 /* fill buffer with maximum */
@@ -213,13 +216,14 @@ int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64
213 for (i = 0; i < ARRAY_SIZE(fs2); i++) { 216 for (i = 0; i < ARRAY_SIZE(fs2); i++) {
214 if (fs2[i](id /*,off*/) == 0) 217 if (fs2[i](id /*,off*/) == 0)
215 goto ret; 218 goto ret;
216 if (id->error) 219 //if (id->known_size < MIN_VALID_FS_SIZE)
217 goto ret; 220 // goto ret_bad;
218 } 221 }
219 222 //ret_bad:
223 retval = -1; /* "not found" */
220 ret: 224 ret:
221 volume_id_free_buffer(id); 225 volume_id_free_buffer(id);
222 return (- id->error); /* 0 or -1 */ 226 return retval;
223} 227}
224 228
225/* open volume by device node */ 229/* open volume by device node */
@@ -229,6 +233,7 @@ struct volume_id* FAST_FUNC volume_id_open_node(int fd)
229 233
230 id = xzalloc(sizeof(struct volume_id)); 234 id = xzalloc(sizeof(struct volume_id));
231 id->fd = fd; 235 id->fd = fd;
236 id->known_size = UNKNOWN_SIZE;
232 ///* close fd on device close */ 237 ///* close fd on device close */
233 //id->fd_close = 1; 238 //id->fd_close = 1;
234 return id; 239 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 {
60struct volume_id { 60struct volume_id {
61 int fd; 61 int fd;
62// int fd_close:1; 62// int fd_close:1;
63 int error; 63 /* UNKNOWN_SIZE: unknown, N: seek+read stopped at N prematurely */
64 unsigned known_size;
65#define UNKNOWN_SIZE UINT_MAX
64 size_t sbbuf_len; 66 size_t sbbuf_len;
65 size_t seekbuf_len; 67 size_t seekbuf_len;
66 uint8_t *sbbuf; 68 uint8_t *sbbuf;
@@ -85,6 +87,18 @@ struct volume_id {
85// const char *usage; 87// const char *usage;
86}; 88};
87 89
90// Technically, the tiniest possible linux FS image (romfs) with only "." and ".." is:
91//00000000 2D 72 6F 6D 31 66 73 2D 00 00 00 60 A1 27 1D 06 -rom1fs-...`.'..
92//00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
93//00000020 00 00 00 49 00 00 00 20 00 00 00 00 D1 FF FF 97 ...I... ........
94//00000030 2E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
95//00000040 00 00 00 00 00 00 00 20 00 00 00 00 D1 D1 FF E0 ....... ........
96//00000050 2E 2E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
97// but kernel won't mount it unless it's padded to 1K.
98// Stop trying new FS types in volume_id_probe_all() outright
99// if a previous probe had a read which stopped before 1K:
100#define MIN_VALID_FS_SIZE 1024
101
88struct volume_id* FAST_FUNC volume_id_open_node(int fd); 102struct volume_id* FAST_FUNC volume_id_open_node(int fd);
89int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size); 103int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size);
90void FAST_FUNC free_volume_id(struct volume_id *id); 104void FAST_FUNC free_volume_id(struct volume_id *id);