Re: bugs in memstick GPT table, and in gpart(8)

2016-12-26 Thread Ian Smith
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)

2016-12-26 Thread Perry Hutchison
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=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 

Re: bugs in memstick GPT table, and in gpart(8)

2016-12-26 Thread Ian Smith
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=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)

2016-12-25 Thread Perry Hutchison
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"