ext4 block group descriptor implementation in disk layout package.
PiperOrigin-RevId: 254482180
This commit is contained in:
parent
e806466fc5
commit
727375321f
|
@ -0,0 +1,21 @@
|
|||
package(licenses = ["notice"])
|
||||
|
||||
load("//tools/go_stateify:defs.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "disklayout",
|
||||
srcs = [
|
||||
"block_group.go",
|
||||
"block_group_32.go",
|
||||
"block_group_64.go",
|
||||
],
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/fs/ext4/disklayout",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "disklayout_test",
|
||||
size = "small",
|
||||
srcs = ["block_group_test.go"],
|
||||
embed = [":disklayout"],
|
||||
deps = ["//pkg/binary"],
|
||||
)
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package disklayout provides ext4 disk level structures which can be directly
|
||||
// filled with bytes from the underlying device. All structures on disk are in
|
||||
// little-endian order. Only jbd2 (journal) structures are in big-endian order.
|
||||
// Structs aim to emulate structures `exactly` how they are layed out on disk.
|
||||
//
|
||||
// Note: All fields in these structs are exported because binary.Read would
|
||||
// panic otherwise.
|
||||
package disklayout
|
||||
|
||||
// BlockGroup represents Linux struct ext4_group_desc which is internally
|
||||
// called a block group descriptor. An ext4 file system is split into a series
|
||||
// of block groups. This provides an access layer to information needed to
|
||||
// access and use a block group.
|
||||
//
|
||||
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/globals.html#block-group-descriptors.
|
||||
type BlockGroup interface {
|
||||
// InodeTable returns the absolute block number of the block containing the
|
||||
// inode table. This points to an array of Inode structs. Inode tables are
|
||||
// statically allocated at mkfs time. The superblock records the number of
|
||||
// inodes per group (length of this table).
|
||||
InodeTable() uint64
|
||||
|
||||
// BlockBitmap returns the absolute block number of the block containing the
|
||||
// block bitmap. This bitmap tracks the usage of data blocks within this block
|
||||
// group and has its own checksum.
|
||||
BlockBitmap() uint64
|
||||
|
||||
// InodeBitmap returns the absolute block number of the block containing the
|
||||
// inode bitmap. This bitmap tracks the usage of this group's inode table
|
||||
// entries and has its own checksum.
|
||||
InodeBitmap() uint64
|
||||
|
||||
// ExclusionBitmap returns the absolute block number of the snapshot exclusion
|
||||
// bitmap.
|
||||
ExclusionBitmap() uint64
|
||||
|
||||
// FreeBlocksCount returns the number of free blocks in the group.
|
||||
FreeBlocksCount() uint32
|
||||
|
||||
// FreeInodesCount returns the number of free inodes in the group.
|
||||
FreeInodesCount() uint32
|
||||
|
||||
// DirectoryCount returns the number of inodes that represent directories
|
||||
// under this block group.
|
||||
DirectoryCount() uint32
|
||||
|
||||
// UnusedInodeCount returns the number of unused inodes beyond the last used
|
||||
// inode in this group's inode table. As a result, we needn’t scan past the
|
||||
// (InodesPerGroup - UnusedInodeCount())th entry in the inode table.
|
||||
UnusedInodeCount() uint32
|
||||
|
||||
// BlockBitmapChecksum returns the block bitmap checksum. This is calculated
|
||||
// using crc32c(FS UUID + group number + entire bitmap).
|
||||
BlockBitmapChecksum() uint32
|
||||
|
||||
// InodeBitmapChecksum returns the inode bitmap checksum. This is calculated
|
||||
// using crc32c(FS UUID + group number + entire bitmap).
|
||||
InodeBitmapChecksum() uint32
|
||||
|
||||
// Checksum returns this block group's checksum.
|
||||
//
|
||||
// If RO_COMPAT_METADATA_CSUM feature is set:
|
||||
// - checksum is crc32c(FS UUID + group number + group descriptor
|
||||
// structure) & 0xFFFF.
|
||||
//
|
||||
// If RO_COMPAT_GDT_CSUM feature is set:
|
||||
// - checksum is crc16(FS UUID + group number + group descriptor
|
||||
// structure).
|
||||
//
|
||||
// RO_COMPAT_METADATA_CSUM and RO_COMPAT_GDT_CSUM should not be both set.
|
||||
// If they are, Linux warns and asks to run fsck.
|
||||
Checksum() uint16
|
||||
|
||||
// Flags returns BGFlags which represents the block group flags.
|
||||
Flags() BGFlags
|
||||
}
|
||||
|
||||
// These are the different block group flags.
|
||||
const (
|
||||
// BgInodeUninit indicates that inode table and bitmap are not initialized.
|
||||
BgInodeUninit uint16 = 0x1
|
||||
|
||||
// BgBlockUninit indicates that block bitmap is not initialized.
|
||||
BgBlockUninit uint16 = 0x2
|
||||
|
||||
// BgInodeZeroed indicates that inode table is zeroed.
|
||||
BgInodeZeroed uint16 = 0x4
|
||||
)
|
||||
|
||||
// BGFlags represents all the different combinations of block group flags.
|
||||
type BGFlags struct {
|
||||
InodeUninit bool
|
||||
BlockUninit bool
|
||||
InodeZeroed bool
|
||||
}
|
||||
|
||||
// ToInt converts a BGFlags struct back to its 16-bit representation.
|
||||
func (f BGFlags) ToInt() uint16 {
|
||||
var res uint16
|
||||
|
||||
if f.InodeUninit {
|
||||
res |= BgInodeUninit
|
||||
}
|
||||
if f.BlockUninit {
|
||||
res |= BgBlockUninit
|
||||
}
|
||||
if f.InodeZeroed {
|
||||
res |= BgInodeZeroed
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// BGFlagsFromInt converts the 16-bit flag representation to a BGFlags struct.
|
||||
func BGFlagsFromInt(flags uint16) BGFlags {
|
||||
return BGFlags{
|
||||
InodeUninit: (flags & BgInodeUninit) > 0,
|
||||
BlockUninit: (flags & BgBlockUninit) > 0,
|
||||
InodeZeroed: (flags & BgInodeZeroed) > 0,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package disklayout
|
||||
|
||||
// BlockGroup32Bit emulates the first half of struct ext4_group_desc in
|
||||
// fs/ext4/ext4.h. It is the block group descriptor struct for 32-bit ext4
|
||||
// filesystems. It implements BlockGroup interface.
|
||||
//
|
||||
// The suffix `Lo` here stands for lower bits because this is also used in the
|
||||
// 64-bit version where these fields represent the lower half of the fields.
|
||||
// The suffix `Raw` has been added to indicate that the field does not have a
|
||||
// counterpart in the 64-bit version and to resolve name collision with the
|
||||
// interface.
|
||||
type BlockGroup32Bit struct {
|
||||
BlockBitmapLo uint32
|
||||
InodeBitmapLo uint32
|
||||
InodeTableLo uint32
|
||||
FreeBlocksCountLo uint16
|
||||
FreeInodesCountLo uint16
|
||||
UsedDirsCountLo uint16
|
||||
FlagsRaw uint16
|
||||
ExcludeBitmapLo uint32
|
||||
BlockBitmapChecksumLo uint16
|
||||
InodeBitmapChecksumLo uint16
|
||||
ItableUnusedLo uint16
|
||||
ChecksumRaw uint16
|
||||
}
|
||||
|
||||
// InodeTable implements BlockGroup.InodeTable.
|
||||
func (bg *BlockGroup32Bit) InodeTable() uint64 { return uint64(bg.InodeTableLo) }
|
||||
|
||||
// BlockBitmap implements BlockGroup.BlockBitmap.
|
||||
func (bg *BlockGroup32Bit) BlockBitmap() uint64 { return uint64(bg.BlockBitmapLo) }
|
||||
|
||||
// InodeBitmap implements BlockGroup.InodeBitmap.
|
||||
func (bg *BlockGroup32Bit) InodeBitmap() uint64 { return uint64(bg.InodeBitmapLo) }
|
||||
|
||||
// ExclusionBitmap implements BlockGroup.ExclusionBitmap.
|
||||
func (bg *BlockGroup32Bit) ExclusionBitmap() uint64 { return uint64(bg.ExcludeBitmapLo) }
|
||||
|
||||
// FreeBlocksCount implements BlockGroup.FreeBlocksCount.
|
||||
func (bg *BlockGroup32Bit) FreeBlocksCount() uint32 { return uint32(bg.FreeBlocksCountLo) }
|
||||
|
||||
// FreeInodesCount implements BlockGroup.FreeInodesCount.
|
||||
func (bg *BlockGroup32Bit) FreeInodesCount() uint32 { return uint32(bg.FreeInodesCountLo) }
|
||||
|
||||
// DirectoryCount implements BlockGroup.DirectoryCount.
|
||||
func (bg *BlockGroup32Bit) DirectoryCount() uint32 { return uint32(bg.UsedDirsCountLo) }
|
||||
|
||||
// UnusedInodeCount implements BlockGroup.UnusedInodeCount.
|
||||
func (bg *BlockGroup32Bit) UnusedInodeCount() uint32 { return uint32(bg.ItableUnusedLo) }
|
||||
|
||||
// BlockBitmapChecksum implements BlockGroup.BlockBitmapChecksum.
|
||||
func (bg *BlockGroup32Bit) BlockBitmapChecksum() uint32 { return uint32(bg.BlockBitmapChecksumLo) }
|
||||
|
||||
// InodeBitmapChecksum implements BlockGroup.InodeBitmapChecksum.
|
||||
func (bg *BlockGroup32Bit) InodeBitmapChecksum() uint32 { return uint32(bg.InodeBitmapChecksumLo) }
|
||||
|
||||
// Checksum implements BlockGroup.Checksum.
|
||||
func (bg *BlockGroup32Bit) Checksum() uint16 { return bg.ChecksumRaw }
|
||||
|
||||
// Flags implements BlockGroup.Flags.
|
||||
func (bg *BlockGroup32Bit) Flags() BGFlags { return BGFlagsFromInt(bg.FlagsRaw) }
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package disklayout
|
||||
|
||||
// BlockGroup64Bit emulates struct ext4_group_desc in fs/ext4/ext4.h.
|
||||
// It is the block group descriptor struct for 64-bit ext4 filesystems.
|
||||
// It implements BlockGroup interface. It is an extension of the 32-bit
|
||||
// version of BlockGroup.
|
||||
//
|
||||
// The suffix `Hi` here stands for upper bits because they represent the upper
|
||||
// half of the fields.
|
||||
type BlockGroup64Bit struct {
|
||||
// We embed the 32-bit struct here because 64-bit version is just an extension
|
||||
// of the 32-bit version.
|
||||
BlockGroup32Bit
|
||||
|
||||
// 64-bit specific fields.
|
||||
BlockBitmapHi uint32
|
||||
InodeBitmapHi uint32
|
||||
InodeTableHi uint32
|
||||
FreeBlocksCountHi uint16
|
||||
FreeInodesCountHi uint16
|
||||
UsedDirsCountHi uint16
|
||||
ItableUnusedHi uint16
|
||||
ExcludeBitmapHi uint32
|
||||
BlockBitmapChecksumHi uint16
|
||||
InodeBitmapChecksumHi uint16
|
||||
_ uint32 // Padding to 64 bytes.
|
||||
}
|
||||
|
||||
// Methods to override. Checksum() and Flags() are not overridden.
|
||||
|
||||
// InodeTable implements BlockGroup.InodeTable.
|
||||
func (bg *BlockGroup64Bit) InodeTable() uint64 {
|
||||
return (uint64(bg.InodeTableHi) << 32) | uint64(bg.InodeTableLo)
|
||||
}
|
||||
|
||||
// BlockBitmap implements BlockGroup.BlockBitmap.
|
||||
func (bg *BlockGroup64Bit) BlockBitmap() uint64 {
|
||||
return (uint64(bg.BlockBitmapHi) << 32) | uint64(bg.BlockBitmapLo)
|
||||
}
|
||||
|
||||
// InodeBitmap implements BlockGroup.InodeBitmap.
|
||||
func (bg *BlockGroup64Bit) InodeBitmap() uint64 {
|
||||
return (uint64(bg.InodeBitmapHi) << 32) | uint64(bg.InodeBitmapLo)
|
||||
}
|
||||
|
||||
// ExclusionBitmap implements BlockGroup.ExclusionBitmap.
|
||||
func (bg *BlockGroup64Bit) ExclusionBitmap() uint64 {
|
||||
return (uint64(bg.ExcludeBitmapHi) << 32) | uint64(bg.ExcludeBitmapLo)
|
||||
}
|
||||
|
||||
// FreeBlocksCount implements BlockGroup.FreeBlocksCount.
|
||||
func (bg *BlockGroup64Bit) FreeBlocksCount() uint32 {
|
||||
return (uint32(bg.FreeBlocksCountHi) << 16) | uint32(bg.FreeBlocksCountLo)
|
||||
}
|
||||
|
||||
// FreeInodesCount implements BlockGroup.FreeInodesCount.
|
||||
func (bg *BlockGroup64Bit) FreeInodesCount() uint32 {
|
||||
return (uint32(bg.FreeInodesCountHi) << 16) | uint32(bg.FreeInodesCountLo)
|
||||
}
|
||||
|
||||
// DirectoryCount implements BlockGroup.DirectoryCount.
|
||||
func (bg *BlockGroup64Bit) DirectoryCount() uint32 {
|
||||
return (uint32(bg.UsedDirsCountHi) << 16) | uint32(bg.UsedDirsCountLo)
|
||||
}
|
||||
|
||||
// UnusedInodeCount implements BlockGroup.UnusedInodeCount.
|
||||
func (bg *BlockGroup64Bit) UnusedInodeCount() uint32 {
|
||||
return (uint32(bg.ItableUnusedHi) << 16) | uint32(bg.ItableUnusedLo)
|
||||
}
|
||||
|
||||
// BlockBitmapChecksum implements BlockGroup.BlockBitmapChecksum.
|
||||
func (bg *BlockGroup64Bit) BlockBitmapChecksum() uint32 {
|
||||
return (uint32(bg.BlockBitmapChecksumHi) << 16) | uint32(bg.BlockBitmapChecksumLo)
|
||||
}
|
||||
|
||||
// InodeBitmapChecksum implements BlockGroup.InodeBitmapChecksum.
|
||||
func (bg *BlockGroup64Bit) InodeBitmapChecksum() uint32 {
|
||||
return (uint32(bg.InodeBitmapChecksumHi) << 16) | uint32(bg.InodeBitmapChecksumLo)
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package disklayout
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
)
|
||||
|
||||
// TestBlockGroupSize tests the fact that the block group struct for
|
||||
// 32-bit ext filesystems should be exactly 32 bytes big and for 64-bit fs it
|
||||
// should be 64 bytes.
|
||||
func TestBlockGroupSize(t *testing.T) {
|
||||
if got, want := int(binary.Size(BlockGroup32Bit{})), 32; got != want {
|
||||
t.Errorf("BlockGroup32Bit should be exactly 32 bytes but is %d bytes", got)
|
||||
}
|
||||
|
||||
if got, want := int(binary.Size(BlockGroup64Bit{})), 64; got != want {
|
||||
t.Errorf("BlockGroup64Bit should be exactly 64 bytes but is %d bytes", got)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue