summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyush Ranjan <ayushranjan@google.com>2019-06-21 15:41:42 -0700
committergVisor bot <gvisor-bot@google.com>2019-06-21 15:42:46 -0700
commit727375321f292878237ac6ace447e43ed393750c (patch)
tree5662a8374c10c19423e2cbc8c02ca75ad1d3c8cb
parente806466fc5a1331df1e643226297064e0eb31075 (diff)
ext4 block group descriptor implementation in disk layout package.
PiperOrigin-RevId: 254482180
-rw-r--r--pkg/sentry/fs/ext4/disklayout/BUILD21
-rw-r--r--pkg/sentry/fs/ext4/disklayout/block_group.go135
-rw-r--r--pkg/sentry/fs/ext4/disklayout/block_group_32.go75
-rw-r--r--pkg/sentry/fs/ext4/disklayout/block_group_64.go93
-rw-r--r--pkg/sentry/fs/ext4/disklayout/block_group_test.go34
5 files changed, 358 insertions, 0 deletions
diff --git a/pkg/sentry/fs/ext4/disklayout/BUILD b/pkg/sentry/fs/ext4/disklayout/BUILD
new file mode 100644
index 000000000..2fb1d5b37
--- /dev/null
+++ b/pkg/sentry/fs/ext4/disklayout/BUILD
@@ -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"],
+)
diff --git a/pkg/sentry/fs/ext4/disklayout/block_group.go b/pkg/sentry/fs/ext4/disklayout/block_group.go
new file mode 100644
index 000000000..7359df5b9
--- /dev/null
+++ b/pkg/sentry/fs/ext4/disklayout/block_group.go
@@ -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,
+ }
+}
diff --git a/pkg/sentry/fs/ext4/disklayout/block_group_32.go b/pkg/sentry/fs/ext4/disklayout/block_group_32.go
new file mode 100644
index 000000000..087f1fb4a
--- /dev/null
+++ b/pkg/sentry/fs/ext4/disklayout/block_group_32.go
@@ -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) }
diff --git a/pkg/sentry/fs/ext4/disklayout/block_group_64.go b/pkg/sentry/fs/ext4/disklayout/block_group_64.go
new file mode 100644
index 000000000..27de3990d
--- /dev/null
+++ b/pkg/sentry/fs/ext4/disklayout/block_group_64.go
@@ -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)
+}
diff --git a/pkg/sentry/fs/ext4/disklayout/block_group_test.go b/pkg/sentry/fs/ext4/disklayout/block_group_test.go
new file mode 100644
index 000000000..794ae99cc
--- /dev/null
+++ b/pkg/sentry/fs/ext4/disklayout/block_group_test.go
@@ -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)
+ }
+}