Re: bugs in memstick GPT table, and in gpart(8)
On Mon, 26 Dec 2016 19:39:23 -0800, Perry Hutchison wrote: > Ian Smith wrote: > > On Sun, 25 Dec 2016 17:03:46 -0800, Perry Hutchison wrote: > > > ... > > > The 10.3-RELEASE-i386-memstick has the smallest possible GPT table > > > (one sector), three GPT table entries (boot, rootfs, & swap), and > > > hdr_entries == 3 in the GPT header ... > > > > > > Since the GPT table is always a whole number of sectors, and each > > > sector has room for four GPT table entries, there's no reason for > > > hdr_entries not to be a multiple of 4. Whatever constructed the > > > 10.3-RELEASE-i386-memstick image should have rounded it up. > > > > That would be mkimg(1). Recall that the 10.3-R amd64 memstick.img still > > (or rather, again?) used the BSD scheme (daXa) rather than GPT, due to a > > some-BIOSes issue. In 11+ both use mkimg, both adding a 1MB 'vestigial' > > swap partition to keep some BIOSes happy (thanks to Glen who pointed me > > to the relevant r265017) > > There is something truly horrifying about a report that "some BIOSes" > require a FreeBSD-swap partition in order to boot. (I could understand > FreeBSD _itself_ insisting on having a swap partition, but the BIOS?) Sorry, my bad paraphrasing; I should have quoted Revision 265017: "loader's GPT support on BIOS does not seem to like the root filesystem being the last filesystem on the disk for some reason when made by this script. Add a vestigial swap partition to allow this to boot with QEMU BIOS." So being a swap partition, rather than any other type, is irrelevant and likely just the easiest to specify empty, as '-p freebsd-swap::1M' While visiting the littlest room, before breakfast and after reading and while pondering yours, it occurred to me that for your stated purpose of adding another partition for packages, you might get away - after using 'gpart recover' to make the rest of your memstick available - with just deleting that 1M swap partition, then adding your new partition? You'd still only have 3 partitions, so gpart should(?) be happy. Worth a try? If that works, it should also work on the amd64 stick with 4 partitions. [..] > > Have you checked this against an 11.0-RELEASE-i386-memstick.img ? > > I hadn't, because I don't generally deal with .0 releases :) > but I just checked and it still has gpt_hdr.hdr_entries == 3. That still seems odd (in both senses of the word :) [.. I may follow up on other stuff later, if sensible .. except: ] > IMO it should either have enforced the limit of 3 -- with an accurate > message (not FreeBSD 8's misleading "No space left on device") -- or > incremented it (that being possible in this case since there was room > to enlarge the table). However ... > > > It didn't even need to allocate another table sector, as going from > > 4 to 5 or more would. > > Allocating another sector would be a _very_ large and risky > operation if, as would usually be the case, the sector needed for > expansion of the primary table is part of an already-created (and, > in this case, not-empty) partition. Yes, that was a totally dumb idea, too late at night. I already knew the first (freebsd-boot) partition started at (the next) LBA 3 .. cheers, Ian ___ freebsd-stable@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-stable To unsubscribe, send any mail to "freebsd-stable-unsubscr...@freebsd.org"
Re: bugs in memstick GPT table, and in gpart(8)
Ian Smith wrote: > On Sun, 25 Dec 2016 17:03:46 -0800, Perry Hutchison wrote: > > ... > > The 10.3-RELEASE-i386-memstick has the smallest possible GPT table > > (one sector), three GPT table entries (boot, rootfs, & swap), and > > hdr_entries == 3 in the GPT header ... > > > > Since the GPT table is always a whole number of sectors, and each > > sector has room for four GPT table entries, there's no reason for > > hdr_entries not to be a multiple of 4. Whatever constructed the > > 10.3-RELEASE-i386-memstick image should have rounded it up. > > That would be mkimg(1). Recall that the 10.3-R amd64 memstick.img still > (or rather, again?) used the BSD scheme (daXa) rather than GPT, due to a > some-BIOSes issue. In 11+ both use mkimg, both adding a 1MB 'vestigial' > swap partition to keep some BIOSes happy (thanks to Glen who pointed me > to the relevant r265017) There is something truly horrifying about a report that "some BIOSes" require a FreeBSD-swap partition in order to boot. (I could understand FreeBSD _itself_ insisting on having a swap partition, but the BIOS?) > However in both cases, this is affected by a quite early commit to > mkimg.c: https://svnweb.freebsd.org/base?view=revision&revision=263382 > > "Also (...), remove the enforcement of creating a GPT table with at > least 128 entries. While this is generally advised as the default or > minimum, it's not actually a hard requirement. We now recreate a table > that's precisely enough (rounded of course)." > > So '3' definitely seems an unrounded result, long after this commit. > > Have you checked this against an 11.0-RELEASE-i386-memstick.img ? I hadn't, because I don't generally deal with .0 releases :) but I just checked and it still has gpt_hdr.hdr_entries == 3. > > The GPT support in the kernel and in gpart(8) should handle > > hdr_entries consistently: either always round it up to a multiple > > of four, or always take it at face value. It should not be possible > > for gpart(8) to create a partition which will effectively disappear > > the next time the provider is tasted. > > Agreed. I'm not sure, even after checking the _possibly somewhat_ > authoritative https://en.wikipedia.org/wiki/GUID_Partition_Table > whether this refers to the maximum (as I suspect) or the current > number of partitions, as listed in 'GPT header format': > > 72 (0x48) 8 bytes Starting LBA of array of partition entries ... > 80 (0x50) 4 bytes Number of partition entries in array > 84 (0x54) 4 bytes Size of a single partition entry (usually 80h or 128) > > Also from that, we're apparently disregarding: "The UEFI specification > stipulates that a minimum of 16,384 bytes, regardless of sector size, > be allocated for the Partition Entry Array." Ie, 128 entries. > > Which is probably just as well, though losing 16KB at the start and end > of a physical disk seems fairly minute these days, even on 1GB sticks, It won't matter, until someday when it makes the difference between an image fitting onto a stick of a given size or not :) I have no complaint with minimizing wasted space, but limiting the size to 3 when it necessarily occupies a multiple of 4 goes too far IMO. > Still, there are various references, as in mkimg(1) above, stating this > is not required. Similarly in gpart(8), optional for 'create' we have: > > -n entries The number of entries in the partition table ... > By default, partition tables are created with the > minimum number of entries. > > In none of the instances of use of gpart(8) I've seen in any /release is > that -n flag used. mkimg(1) doesn't take anything like the -n switch, > though perhaps it could / should? mkimg(1) seems to set the number of partitions created according to the number of -p switches provided on the command line -- but I'd think it ought to round up rather than leave part of a sector unused. > > The willingness of gpart(8) to add a partition exceeding the defined > > size of the GPT table is a recent regression (as well as, arguably, > > a buffer overrun): > > I'm surprised it didn't extend that '3' count (clearly bogus, not > at all rounded) to 4 when it added another partition. IMO it should either have enforced the limit of 3 -- with an accurate message (not FreeBSD 8's misleading "No space left on device") -- or incremented it (that being possible in this case since there was room to enlarge the table). However ... > It didn't even need to allocate another table sector, as going from > 4 to 5 or more would. Allocating another sector would be a _very_ large and risky operation if, as would usually be the case, the sector needed for expansion of the primary table is part of an already-created (and, in this case, not-empty) partition. Every partition up to the first unallocated sector on the stick would need to be moved, and interrupting that lengthy process would corrupt the partition being moved at the time. It gets even worse if one of the
Re: bugs in memstick GPT table, and in gpart(8)
On Sun, 25 Dec 2016 17:03:46 -0800, Perry Hutchison wrote: > Some months ago: > > > I dd'd FreeBSD-10.3-RELEASE-i386-memstick.img to a 4GB flash drive, > > and booted it into single-user mode where it appeared as da0. Then, > > to resize the GPT to the media (to make space for another partition): > > > > # gpart show da0 > > # gpart recover da0 > > # gpart show da0 > > > > which appeared to work ... [but] when I tried to create a 4th > > partition in that free space: > > > > # gpart show da0 # showed 3 partitions and about 3GB of free space > > # gpart add -t freebsd-ufs da0 # reported "da0p4 added" > > # gpart show da0 # showed 4 partitions including the new one, and > > # no free space -- as expected > > # shutdown -r now > > > > a "gpart show da0" after the reboot showed 3 partitions and about > > 3GB of free space, the same as before the "gpart add" operation. > > In other words, the new partition did not survive the reboot. > > I finally had time to track down what was going on, and it turns > out that both the 10.3 GPT support, and the construction of the > 10.3-RELEASE-i386-memstick, are buggy. > > Details: > > The 10.3-RELEASE-i386-memstick has the smallest possible GPT table > (one sector), three GPT table entries (boot, rootfs, & swap), and > hdr_entries == 3 in the GPT header. Despite that setting, the > "gpart add" operation did create a fourth table entry -- and the > new entry was (temporarily) available for the system to use (e.g. > I was able to run an apparently-successful newfs on it). > > A subsequent hexdump(1) of the GPT table sector showed that the new > entry had even been written to the device. However, after a reboot > (or, likely, any event causing the device to be tasted again), the > hdr_entries setting causes the new, fourth entry to be ignored: > only the three original entries are recognized. > > Bugs: > > Since the GPT table is always a whole number of sectors, and each > sector has room for four GPT table entries, there's no reason for > hdr_entries not to be a multiple of 4. Whatever constructed the > 10.3-RELEASE-i386-memstick image should have rounded it up. That would be mkimg(1). Recall that the 10.3-R amd64 memstick.img still (or rather, again?) used the BSD scheme (daXa) rather than GPT, due to a some-BIOSes issue. In 11+ both use mkimg, both adding a 1MB 'vestigial' swap partition to keep some BIOSes happy (thanks to Glen who pointed me to the relevant r265017) However in both cases, this is affected by a quite early commit to mkimg.c: https://svnweb.freebsd.org/base?view=revision&revision=263382 "Also (...), remove the enforcement of creating a GPT table with at least 128 entries. While this is generally advised as the default or minimum, it's not actually a hard requirement. We now recreate a table that's precisely enough (rounded of course)." So '3' definitely seems an unrounded result, long after this commit. Have you checked this against an 11.0-RELEASE-i386-memstick.img ? > The GPT support in the kernel and in gpart(8) should handle > hdr_entries consistently: either always round it up to a multiple > of four, or always take it at face value. It should not be possible > for gpart(8) to create a partition which will effectively disappear > the next time the provider is tasted. Agreed. I'm not sure, even after checking the _possibly somewhat_ authoritative https://en.wikipedia.org/wiki/GUID_Partition_Table whether this refers to the maximum (as I suspect) or the current number of partitions, as listed in 'GPT header format': 72 (0x48) 8 bytes Starting LBA of array of partition entries (always 2 in primary copy) 80 (0x50) 4 bytes Number of partition entries in array 84 (0x54) 4 bytes Size of a single partition entry (usually 80h or 128) Also from that, we're apparently disregarding: "The UEFI specification stipulates that a minimum of 16,384 bytes, regardless of sector size, be allocated for the Partition Entry Array." Ie, 128 entries. Which is probably just as well, though losing 16KB at the start and end of a physical disk seems fairly minute these days, even on 1GB sticks, Still, there are various references, as in mkimg(1) above, stating this is not required. Similarly in gpart(8), optional for 'create' we have: -n entries The number of entries in the partition table. Every partitioning scheme has a minimum and maximum number of entries. This option allows tables to be created with a number of entries that is within the limits. Some schemes have a maximum equal to the minimum and some schemes have a maximum large enough to be considered unlimited. By default, partition tables are
bugs in memstick GPT table, and in gpart(8)
Some months ago: > I dd'd FreeBSD-10.3-RELEASE-i386-memstick.img to a 4GB flash drive, > and booted it into single-user mode where it appeared as da0. Then, > to resize the GPT to the media (to make space for another partition): > > # gpart show da0 > # gpart recover da0 > # gpart show da0 > > which appeared to work ... [but] when I tried to create a 4th > partition in that free space: > > # gpart show da0 # showed 3 partitions and about 3GB of free space > # gpart add -t freebsd-ufs da0# reported "da0p4 added" > # gpart show da0 # showed 4 partitions including the new one, and > # no free space -- as expected > # shutdown -r now > > a "gpart show da0" after the reboot showed 3 partitions and about > 3GB of free space, the same as before the "gpart add" operation. > In other words, the new partition did not survive the reboot. I finally had time to track down what was going on, and it turns out that both the 10.3 GPT support, and the construction of the 10.3-RELEASE-i386-memstick, are buggy. Details: The 10.3-RELEASE-i386-memstick has the smallest possible GPT table (one sector), three GPT table entries (boot, rootfs, & swap), and hdr_entries == 3 in the GPT header. Despite that setting, the "gpart add" operation did create a fourth table entry -- and the new entry was (temporarily) available for the system to use (e.g. I was able to run an apparently-successful newfs on it). A subsequent hexdump(1) of the GPT table sector showed that the new entry had even been written to the device. However, after a reboot (or, likely, any event causing the device to be tasted again), the hdr_entries setting causes the new, fourth entry to be ignored: only the three original entries are recognized. Bugs: Since the GPT table is always a whole number of sectors, and each sector has room for four GPT table entries, there's no reason for hdr_entries not to be a multiple of 4. Whatever constructed the 10.3-RELEASE-i386-memstick image should have rounded it up. The GPT support in the kernel and in gpart(8) should handle hdr_entries consistently: either always round it up to a multiple of four, or always take it at face value. It should not be possible for gpart(8) to create a partition which will effectively disappear the next time the provider is tasted. The willingness of gpart(8) to add a partition exceeding the defined size of the GPT table is a recent regression (as well as, arguably, a buffer overrun): Under the same conditions the FreeBSD 8 version of gpart(8) complained "gpart: index '4': No space left on device". (The message is wrong -- it should be something like "Partition table full" -- but apart from the misleading message the situation seems to have been handled correctly.) Meanwhile even FreeBSD 8's gpart(8) is less helpful than its predecessor, gpt(8). Trying to perform this same operation on FreeBSD 6 produces: # gpt -r show da0 start size index contents 01 PMBR 11 Pri GPT header 21 Pri GPT table 3 32 1 GPT part - 83bd6b9d-7f41-11dc-be0b-001560b84f0f 35 1348832 2 GPT part - FreeBSD UFS/UFS2 1348867 2048 3 GPT part - FreeBSD swap 1350915 6460155 78110701 Sec GPT table 78110711 Sec GPT header # gpt add da0 gpt add: da0: error: no available table entries # gpt add -i 4 da0 gpt add: da0: error: index 4 out of range (3 max) ___ freebsd-stable@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/freebsd-stable To unsubscribe, send any mail to "freebsd-stable-unsubscr...@freebsd.org"