ext4 block group descriptor implementation in disk layout package.

PiperOrigin-RevId: 254482180
This commit is contained in:
Ayush Ranjan 2019-06-21 15:41:42 -07:00 committed by gVisor bot
parent e806466fc5
commit 727375321f
5 changed files with 358 additions and 0 deletions

View File

@ -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"],
)

View File

@ -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 neednt 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,
}
}

View File

@ -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) }

View File

@ -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)
}

View File

@ -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)
}
}