Skip to content

Commit

Permalink
fix: make extfs filesystem detection separate for ext2/3/4
Browse files Browse the repository at this point in the history
It's import to make sure detected names match the names in
`/proc/filesystems` for the actual mount call.

Part of siderolabs/talos#9746

Signed-off-by: Andrey Smirnov <[email protected]>
  • Loading branch information
smira committed Nov 20, 2024
1 parent 6d3b4b0 commit af28144
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 18 deletions.
66 changes: 60 additions & 6 deletions blkid/blkid_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,27 @@ func xfsSetup(t *testing.T, path string) {
require.NoError(t, cmd.Run())
}

func extfsSetup(t *testing.T, path string) {
func ext2Setup(t *testing.T, path string) {
t.Helper()

cmd := exec.Command("mkfs.ext2", "-L", "extlabel", path)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

require.NoError(t, cmd.Run())
}

func ext3Setup(t *testing.T, path string) {
t.Helper()

cmd := exec.Command("mkfs.ext3", "-L", "extlabel", path)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

require.NoError(t, cmd.Run())
}

func ext4Setup(t *testing.T, path string) {
t.Helper()

cmd := exec.Command("mkfs.ext4", "-L", "extlabel", path)
Expand Down Expand Up @@ -251,12 +271,46 @@ func TestProbePathFilesystems(t *testing.T) {
},
},
{
name: "extfs",
name: "ext2",

size: 500 * MiB,
setup: ext2Setup,

expectedName: "ext2",
expectedLabel: "extlabel",
expectUUID: true,

expectedBlockSize: []uint32{1024, 4096},
expectedFSBlockSize: []uint32{1024, 4096},
expectedFSSize: 500 * MiB,
expectedSignatures: []blkid.SignatureRange{
{Offset: 1080, Size: 2},
},
},
{
name: "ext3",

size: 500 * MiB,
setup: ext3Setup,

expectedName: "ext3",
expectedLabel: "extlabel",
expectUUID: true,

expectedBlockSize: []uint32{1024, 4096},
expectedFSBlockSize: []uint32{1024, 4096},
expectedFSSize: 500 * MiB,
expectedSignatures: []blkid.SignatureRange{
{Offset: 1080, Size: 2},
},
},
{
name: "ext4",

size: 500 * MiB,
setup: extfsSetup,
setup: ext4Setup,

expectedName: "extfs",
expectedName: "ext4",
expectedLabel: "extlabel",
expectUUID: true,

Expand Down Expand Up @@ -834,7 +888,7 @@ func setupNestedGPT(t *testing.T, path string) {
require.NoError(t, exec.Command("partprobe", path).Run())

vfatSetup(t, path+"p1")
extfsSetup(t, path+"p3")
ext4Setup(t, path+"p3")
xfsSetup(t, path+"p6")
}

Expand Down Expand Up @@ -949,7 +1003,7 @@ func TestProbePathNested(t *testing.T) {
assert.Equal(t, blkid.ProbeResult{}, info.Parts[1].ProbeResult)

// BOOT: ext4
assert.Equal(t, "extfs", info.Parts[2].Name)
assert.Equal(t, "ext4", info.Parts[2].Name)
assert.Contains(t, []uint32{1024, 4096}, info.Parts[2].BlockSize)
assert.Contains(t, []uint32{1024, 4096}, info.Parts[2].FilesystemBlockSize)
assert.EqualValues(t, 1000*MiB, info.Parts[2].ProbedSize)
Expand Down
4 changes: 3 additions & 1 deletion blkid/internal/chain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ func (chain Chain) MagicMatches(buf []byte) []probe.MagicMatch {
func Default() Chain {
return Chain{
&xfs.Probe{},
&ext.Probe{},
&ext.Probe4{},
&ext.Probe3{},
&ext.Probe2{},
&vfat.Probe{},
&swap.Probe{},
&lvm2.Probe{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ const sbOffset = 0x400
//
//nolint:stylecheck,revive
const (
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER = 0x0001
EXT2_FEATURE_RO_COMPAT_LARGE_FILE = 0x0002
EXT2_FEATURE_RO_COMPAT_BTREE_DIR = 0x0004
EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002
EXT2_FEATURE_INCOMPAT_META_BG = 0x0010

EXT3_FEATURE_INCOMPAT_RECOVER = 0x0004
EXT3_FEATURE_COMPAT_HAS_JOURNAL = 0x0004
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV = 0x0008

EXT2_FEATURE_RO_COMPAT_SUPP = EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | EXT2_FEATURE_RO_COMPAT_LARGE_FILE | EXT2_FEATURE_RO_COMPAT_BTREE_DIR
EXT2_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE | EXT2_FEATURE_INCOMPAT_META_BG
EXT2_FEATURE_INCOMPAT_UNSUPPORTED = ^uint32(EXT2_FEATURE_INCOMPAT_SUPP)
EXT2_FEATURE_RO_COMPAT_UNSUPPORTED = ^uint32(EXT2_FEATURE_RO_COMPAT_SUPP)

EXT3_FEATURE_RO_COMPAT_SUPP = EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | EXT2_FEATURE_RO_COMPAT_LARGE_FILE | EXT2_FEATURE_RO_COMPAT_BTREE_DIR
EXT3_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER | EXT2_FEATURE_INCOMPAT_META_BG
EXT3_FEATURE_INCOMPAT_UNSUPPORTED = ^uint32(EXT3_FEATURE_INCOMPAT_SUPP)
EXT3_FEATURE_RO_COMPAT_UNSUPPORTED = ^uint32(EXT3_FEATURE_RO_COMPAT_SUPP)

EXT4_FEATURE_RO_COMPAT_METADATA_CSUM = 0x0400
)

Expand All @@ -32,21 +52,14 @@ var extfsMagic = magic.Magic{
Value: []byte("\123\357"),
}

// Probe for the filesystem.
type Probe struct{}
type probeCommon struct{}

// Magic returns the magic value for the filesystem.
func (p *Probe) Magic() []*magic.Magic {
func (p *probeCommon) Magic() []*magic.Magic {
return []*magic.Magic{&extfsMagic}
}

// Name returns the name of the xfs filesystem.
func (p *Probe) Name() string {
return "extfs"
}

// Probe runs the further inspection and returns the result if successful.
func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
func (p *probeCommon) readSuperblock(r probe.Reader) (SuperBlock, error) {
buf := make([]byte, SUPERBLOCK_SIZE)

if _, err := r.ReadAt(buf, sbOffset); err != nil {
Expand All @@ -59,10 +72,14 @@ func (p *Probe) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
csum := utils.CRC32c(buf[:1020])

if csum != sb.Get_s_checksum() {
return nil, nil //nolint:nilnil
return nil, nil
}
}

return sb, nil
}

func (p *probeCommon) buildResult(sb SuperBlock) (*probe.Result, error) {
uuid, err := uuid.FromBytes(sb.Get_s_uuid())
if err != nil {
return nil, err
Expand Down
41 changes: 41 additions & 0 deletions blkid/internal/filesystems/ext/ext2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package ext

import (
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
)

// Probe2 for ext2.
type Probe2 struct {
probeCommon
}

// Name returns the name of the xfs filesystem.
func (p *Probe2) Name() string {
return "ext2"
}

// Probe runs the further inspection and returns the result if successful.
func (p *Probe2) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
sb, err := p.readSuperblock(r)
if err != nil || sb == nil {
return nil, err
}

// should not have a journal
if sb.Get_s_feature_compat()&EXT3_FEATURE_COMPAT_HAS_JOURNAL != 0 {
return nil, nil //nolint:nilnil
}

// ext2 should not have features it doesn't understand
if (sb.Get_s_feature_ro_compat()&EXT2_FEATURE_RO_COMPAT_UNSUPPORTED) != 0 ||
(sb.Get_s_feature_incompat()&EXT2_FEATURE_INCOMPAT_UNSUPPORTED) != 0 {
return nil, nil //nolint:nilnil
}

return p.buildResult(sb)
}
41 changes: 41 additions & 0 deletions blkid/internal/filesystems/ext/ext3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package ext

import (
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
)

// Probe3 for ext3.
type Probe3 struct {
probeCommon
}

// Name returns the name of the xfs filesystem.
func (p *Probe3) Name() string {
return "ext3"
}

// Probe runs the further inspection and returns the result if successful.
func (p *Probe3) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
sb, err := p.readSuperblock(r)
if err != nil || sb == nil {
return nil, err
}

// should have a journal
if sb.Get_s_feature_compat()&EXT3_FEATURE_COMPAT_HAS_JOURNAL == 0 {
return nil, nil //nolint:nilnil
}

// ext3 should not have features it doesn't understand
if (sb.Get_s_feature_ro_compat()&EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) != 0 ||
(sb.Get_s_feature_incompat()&EXT3_FEATURE_INCOMPAT_UNSUPPORTED) != 0 {
return nil, nil //nolint:nilnil
}

return p.buildResult(sb)
}
41 changes: 41 additions & 0 deletions blkid/internal/filesystems/ext/ext4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package ext

import (
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/magic"
"github.com/siderolabs/go-blockdevice/v2/blkid/internal/probe"
)

// Probe4 for ext4.
type Probe4 struct {
probeCommon
}

// Name returns the name of the xfs filesystem.
func (p *Probe4) Name() string {
return "ext4"
}

// Probe runs the further inspection and returns the result if successful.
func (p *Probe4) Probe(r probe.Reader, _ magic.Magic) (*probe.Result, error) {
sb, err := p.readSuperblock(r)
if err != nil || sb == nil {
return nil, err
}

// distinguish from jbd
if sb.Get_s_feature_incompat()&EXT3_FEATURE_INCOMPAT_JOURNAL_DEV != 0 {
return nil, nil //nolint:nilnil
}

// ext4 has at least one feature which ext3 doesn't understand
if (sb.Get_s_feature_ro_compat()&EXT3_FEATURE_RO_COMPAT_UNSUPPORTED) == 0 &&
(sb.Get_s_feature_incompat()&EXT3_FEATURE_INCOMPAT_UNSUPPORTED) == 0 {
return nil, nil //nolint:nilnil
}

return p.buildResult(sb)
}

0 comments on commit af28144

Please sign in to comment.