Currently, userdisk_init() iterates through disks and
checks whether DIOCGSECTORSIZE and DIOCGMEDIASIZE ioctls
are available for the device. If either ioctl fails, userdisk_init()
returns ENXIO with ud_info only partially initialized.
devinit() records the failure, but loader_main() ignores
devinit()'s return value, so later code may access an
uninitialized entry.
In certain cases this code can still boot from a disk even if
userdisk_init() returns ENXIO, for example, when the first of
two disks is valid and the second errors out.
To address this issue while not breaking the current behavior, do
the following:
- Extend the 'userdisk_info' struct with the boolean 'ud_usable' field, and mark disks that do not support the ioctls mentioned above with ud_usable = false.
- Update userdisk_print() not to print unusable disks.
- Update userdisk_open() to return EIO for unusable disks.
- Update extract_currdev() to pick the first usable disk instead of the first disk. Introduce userboot_disk_firstunit() for that.
Additionally, reset counters on ud_info allocation failure to prevent
accessing unallocated data.