mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
[go-marshal] Port ext codebase to use go marshal.
PiperOrigin-RevId: 334656292
This commit is contained in:
@@ -51,6 +51,8 @@ go_library(
|
||||
"//pkg/fd",
|
||||
"//pkg/fspath",
|
||||
"//pkg/log",
|
||||
"//pkg/marshal",
|
||||
"//pkg/marshal/primitive",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fs",
|
||||
@@ -86,9 +88,9 @@ go_test(
|
||||
library = ":ext",
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/binary",
|
||||
"//pkg/context",
|
||||
"//pkg/fspath",
|
||||
"//pkg/marshal/primitive",
|
||||
"//pkg/sentry/contexttest",
|
||||
"//pkg/sentry/fsimpl/ext/disklayout",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/marshal/primitive"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
)
|
||||
|
||||
@@ -34,19 +34,19 @@ type blockMapFile struct {
|
||||
|
||||
// directBlks are the direct blocks numbers. The physical blocks pointed by
|
||||
// these holds file data. Contains file blocks 0 to 11.
|
||||
directBlks [numDirectBlks]uint32
|
||||
directBlks [numDirectBlks]primitive.Uint32
|
||||
|
||||
// indirectBlk is the physical block which contains (blkSize/4) direct block
|
||||
// numbers (as uint32 integers).
|
||||
indirectBlk uint32
|
||||
indirectBlk primitive.Uint32
|
||||
|
||||
// doubleIndirectBlk is the physical block which contains (blkSize/4) indirect
|
||||
// block numbers (as uint32 integers).
|
||||
doubleIndirectBlk uint32
|
||||
doubleIndirectBlk primitive.Uint32
|
||||
|
||||
// tripleIndirectBlk is the physical block which contains (blkSize/4) doubly
|
||||
// indirect block numbers (as uint32 integers).
|
||||
tripleIndirectBlk uint32
|
||||
tripleIndirectBlk primitive.Uint32
|
||||
|
||||
// coverage at (i)th index indicates the amount of file data a node at
|
||||
// height (i) covers. Height 0 is the direct block.
|
||||
@@ -68,10 +68,12 @@ func newBlockMapFile(args inodeArgs) (*blockMapFile, error) {
|
||||
}
|
||||
|
||||
blkMap := file.regFile.inode.diskInode.Data()
|
||||
binary.Unmarshal(blkMap[:numDirectBlks*4], binary.LittleEndian, &file.directBlks)
|
||||
binary.Unmarshal(blkMap[numDirectBlks*4:(numDirectBlks+1)*4], binary.LittleEndian, &file.indirectBlk)
|
||||
binary.Unmarshal(blkMap[(numDirectBlks+1)*4:(numDirectBlks+2)*4], binary.LittleEndian, &file.doubleIndirectBlk)
|
||||
binary.Unmarshal(blkMap[(numDirectBlks+2)*4:(numDirectBlks+3)*4], binary.LittleEndian, &file.tripleIndirectBlk)
|
||||
for i := 0; i < numDirectBlks; i++ {
|
||||
file.directBlks[i].UnmarshalBytes(blkMap[i*4 : (i+1)*4])
|
||||
}
|
||||
file.indirectBlk.UnmarshalBytes(blkMap[numDirectBlks*4 : (numDirectBlks+1)*4])
|
||||
file.doubleIndirectBlk.UnmarshalBytes(blkMap[(numDirectBlks+1)*4 : (numDirectBlks+2)*4])
|
||||
file.tripleIndirectBlk.UnmarshalBytes(blkMap[(numDirectBlks+2)*4 : (numDirectBlks+3)*4])
|
||||
return file, nil
|
||||
}
|
||||
|
||||
@@ -117,16 +119,16 @@ func (f *blockMapFile) ReadAt(dst []byte, off int64) (int, error) {
|
||||
switch {
|
||||
case offset < dirBlksEnd:
|
||||
// Direct block.
|
||||
curR, err = f.read(f.directBlks[offset/f.regFile.inode.blkSize], offset%f.regFile.inode.blkSize, 0, dst[read:])
|
||||
curR, err = f.read(uint32(f.directBlks[offset/f.regFile.inode.blkSize]), offset%f.regFile.inode.blkSize, 0, dst[read:])
|
||||
case offset < indirBlkEnd:
|
||||
// Indirect block.
|
||||
curR, err = f.read(f.indirectBlk, offset-dirBlksEnd, 1, dst[read:])
|
||||
curR, err = f.read(uint32(f.indirectBlk), offset-dirBlksEnd, 1, dst[read:])
|
||||
case offset < doubIndirBlkEnd:
|
||||
// Doubly indirect block.
|
||||
curR, err = f.read(f.doubleIndirectBlk, offset-indirBlkEnd, 2, dst[read:])
|
||||
curR, err = f.read(uint32(f.doubleIndirectBlk), offset-indirBlkEnd, 2, dst[read:])
|
||||
default:
|
||||
// Triply indirect block.
|
||||
curR, err = f.read(f.tripleIndirectBlk, offset-doubIndirBlkEnd, 3, dst[read:])
|
||||
curR, err = f.read(uint32(f.tripleIndirectBlk), offset-doubIndirBlkEnd, 3, dst[read:])
|
||||
}
|
||||
|
||||
read += curR
|
||||
@@ -174,13 +176,13 @@ func (f *blockMapFile) read(curPhyBlk uint32, relFileOff uint64, height uint, ds
|
||||
read := 0
|
||||
curChildOff := relFileOff % childCov
|
||||
for i := startIdx; i < endIdx; i++ {
|
||||
var childPhyBlk uint32
|
||||
var childPhyBlk primitive.Uint32
|
||||
err := readFromDisk(f.regFile.inode.fs.dev, curPhyBlkOff+int64(i*4), &childPhyBlk)
|
||||
if err != nil {
|
||||
return read, err
|
||||
}
|
||||
|
||||
n, err := f.read(childPhyBlk, curChildOff, height-1, dst[read:])
|
||||
n, err := f.read(uint32(childPhyBlk), curChildOff, height-1, dst[read:])
|
||||
read += n
|
||||
if err != nil {
|
||||
return read, err
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/marshal/primitive"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/ext/disklayout"
|
||||
)
|
||||
|
||||
@@ -87,29 +87,33 @@ func blockMapSetUp(t *testing.T) (*blockMapFile, []byte) {
|
||||
mockDisk := make([]byte, mockBMDiskSize)
|
||||
var fileData []byte
|
||||
blkNums := newBlkNumGen()
|
||||
var data []byte
|
||||
off := 0
|
||||
data := make([]byte, (numDirectBlks+3)*(*primitive.Uint32)(nil).SizeBytes())
|
||||
|
||||
// Write the direct blocks.
|
||||
for i := 0; i < numDirectBlks; i++ {
|
||||
curBlkNum := blkNums.next()
|
||||
data = binary.Marshal(data, binary.LittleEndian, curBlkNum)
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, curBlkNum, 0, blkNums)...)
|
||||
curBlkNum := primitive.Uint32(blkNums.next())
|
||||
curBlkNum.MarshalBytes(data[off:])
|
||||
off += curBlkNum.SizeBytes()
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, uint32(curBlkNum), 0, blkNums)...)
|
||||
}
|
||||
|
||||
// Write to indirect block.
|
||||
indirectBlk := blkNums.next()
|
||||
data = binary.Marshal(data, binary.LittleEndian, indirectBlk)
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, indirectBlk, 1, blkNums)...)
|
||||
indirectBlk := primitive.Uint32(blkNums.next())
|
||||
indirectBlk.MarshalBytes(data[off:])
|
||||
off += indirectBlk.SizeBytes()
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, uint32(indirectBlk), 1, blkNums)...)
|
||||
|
||||
// Write to indirect block.
|
||||
doublyIndirectBlk := blkNums.next()
|
||||
data = binary.Marshal(data, binary.LittleEndian, doublyIndirectBlk)
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, doublyIndirectBlk, 2, blkNums)...)
|
||||
// Write to double indirect block.
|
||||
doublyIndirectBlk := primitive.Uint32(blkNums.next())
|
||||
doublyIndirectBlk.MarshalBytes(data[off:])
|
||||
off += doublyIndirectBlk.SizeBytes()
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, uint32(doublyIndirectBlk), 2, blkNums)...)
|
||||
|
||||
// Write to indirect block.
|
||||
triplyIndirectBlk := blkNums.next()
|
||||
data = binary.Marshal(data, binary.LittleEndian, triplyIndirectBlk)
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, triplyIndirectBlk, 3, blkNums)...)
|
||||
// Write to triple indirect block.
|
||||
triplyIndirectBlk := primitive.Uint32(blkNums.next())
|
||||
triplyIndirectBlk.MarshalBytes(data[off:])
|
||||
fileData = append(fileData, writeFileDataToBlock(mockDisk, uint32(triplyIndirectBlk), 3, blkNums)...)
|
||||
|
||||
args := inodeArgs{
|
||||
fs: &filesystem{
|
||||
@@ -142,9 +146,9 @@ func writeFileDataToBlock(disk []byte, blkNum uint32, height uint, blkNums *blkN
|
||||
|
||||
var fileData []byte
|
||||
for off := blkNum * mockBMBlkSize; off < (blkNum+1)*mockBMBlkSize; off += 4 {
|
||||
curBlkNum := blkNums.next()
|
||||
copy(disk[off:off+4], binary.Marshal(nil, binary.LittleEndian, curBlkNum))
|
||||
fileData = append(fileData, writeFileDataToBlock(disk, curBlkNum, height-1, blkNums)...)
|
||||
curBlkNum := primitive.Uint32(blkNums.next())
|
||||
curBlkNum.MarshalBytes(disk[off : off+4])
|
||||
fileData = append(fileData, writeFileDataToBlock(disk, uint32(curBlkNum), height-1, blkNums)...)
|
||||
}
|
||||
return fileData
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package ext
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
@@ -100,7 +99,7 @@ func newDirectory(args inodeArgs, newDirent bool) (*directory, error) {
|
||||
} else {
|
||||
curDirent.diskDirent = &disklayout.DirentOld{}
|
||||
}
|
||||
binary.Unmarshal(buf, binary.LittleEndian, curDirent.diskDirent)
|
||||
curDirent.diskDirent.UnmarshalBytes(buf)
|
||||
|
||||
if curDirent.diskDirent.Inode() != 0 && len(curDirent.diskDirent.FileName()) != 0 {
|
||||
// Inode number and name length fields being set to 0 is used to indicate
|
||||
|
||||
@@ -22,10 +22,11 @@ go_library(
|
||||
"superblock_old.go",
|
||||
"test_utils.go",
|
||||
],
|
||||
marshal = True,
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/binary",
|
||||
"//pkg/marshal",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/kernel/time",
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
package disklayout
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
)
|
||||
|
||||
// BlockGroup represents a Linux ext block group descriptor. An ext 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.
|
||||
@@ -30,6 +34,8 @@ package disklayout
|
||||
//
|
||||
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/globals.html#block-group-descriptors.
|
||||
type BlockGroup interface {
|
||||
marshal.Marshallable
|
||||
|
||||
// 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
|
||||
|
||||
@@ -17,6 +17,8 @@ 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 ext2, ext3 and
|
||||
// 32-bit ext4 filesystems. It implements BlockGroup interface.
|
||||
//
|
||||
// +marshal
|
||||
type BlockGroup32Bit struct {
|
||||
BlockBitmapLo uint32
|
||||
InodeBitmapLo uint32
|
||||
|
||||
@@ -18,6 +18,8 @@ package disklayout
|
||||
// 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.
|
||||
//
|
||||
// +marshal
|
||||
type BlockGroup64Bit struct {
|
||||
// We embed the 32-bit struct here because 64-bit version is just an extension
|
||||
// of the 32-bit version.
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
// TestBlockGroupSize tests that the block group descriptor structs are of the
|
||||
// correct size.
|
||||
func TestBlockGroupSize(t *testing.T) {
|
||||
assertSize(t, BlockGroup32Bit{}, 32)
|
||||
assertSize(t, BlockGroup64Bit{}, 64)
|
||||
var bgSmall BlockGroup32Bit
|
||||
assertSize(t, &bgSmall, 32)
|
||||
var bgBig BlockGroup64Bit
|
||||
assertSize(t, &bgBig, 64)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package disklayout
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
)
|
||||
|
||||
@@ -51,6 +52,8 @@ var (
|
||||
//
|
||||
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#linear-classic-directories.
|
||||
type Dirent interface {
|
||||
marshal.Marshallable
|
||||
|
||||
// Inode returns the absolute inode number of the underlying inode.
|
||||
// Inode number 0 signifies an unused dirent.
|
||||
Inode() uint32
|
||||
|
||||
@@ -29,12 +29,14 @@ import (
|
||||
// Note: This struct can be of variable size on disk. The one described below
|
||||
// is of maximum size and the FileName beyond NameLength bytes might contain
|
||||
// garbage.
|
||||
//
|
||||
// +marshal
|
||||
type DirentNew struct {
|
||||
InodeNumber uint32
|
||||
RecordLength uint16
|
||||
NameLength uint8
|
||||
FileTypeRaw uint8
|
||||
FileNameRaw [MaxFileName]byte
|
||||
FileNameRaw [MaxFileName]byte `marshal:"unaligned"`
|
||||
}
|
||||
|
||||
// Compiles only if DirentNew implements Dirent.
|
||||
|
||||
@@ -22,11 +22,13 @@ import "gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
// Note: This struct can be of variable size on disk. The one described below
|
||||
// is of maximum size and the FileName beyond NameLength bytes might contain
|
||||
// garbage.
|
||||
//
|
||||
// +marshal
|
||||
type DirentOld struct {
|
||||
InodeNumber uint32
|
||||
RecordLength uint16
|
||||
NameLength uint16
|
||||
FileNameRaw [MaxFileName]byte
|
||||
FileNameRaw [MaxFileName]byte `marshal:"unaligned"`
|
||||
}
|
||||
|
||||
// Compiles only if DirentOld implements Dirent.
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
// TestDirentSize tests that the dirent structs are of the correct
|
||||
// size.
|
||||
func TestDirentSize(t *testing.T) {
|
||||
assertSize(t, DirentOld{}, uintptr(DirentSize))
|
||||
assertSize(t, DirentNew{}, uintptr(DirentSize))
|
||||
var dOld DirentOld
|
||||
assertSize(t, &dOld, DirentSize)
|
||||
var dNew DirentNew
|
||||
assertSize(t, &dNew, DirentSize)
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@
|
||||
// escape analysis on an unknown implementation at compile time.
|
||||
//
|
||||
// Notes:
|
||||
// - All fields in these structs are exported because binary.Read would
|
||||
// panic otherwise.
|
||||
// - All structures on disk are in little-endian order. Only jbd2 (journal)
|
||||
// structures are in big-endian order.
|
||||
// - All OS dependent fields in these structures will be interpretted using
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
package disklayout
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
)
|
||||
|
||||
// Extents were introduced in ext4 and provide huge performance gains in terms
|
||||
// data locality and reduced metadata block usage. Extents are organized in
|
||||
// extent trees. The root node is contained in inode.BlocksRaw.
|
||||
@@ -64,6 +68,8 @@ type ExtentNode struct {
|
||||
// ExtentEntry represents an extent tree node entry. The entry can either be
|
||||
// an ExtentIdx or Extent itself. This exists to simplify navigation logic.
|
||||
type ExtentEntry interface {
|
||||
marshal.Marshallable
|
||||
|
||||
// FileBlock returns the first file block number covered by this entry.
|
||||
FileBlock() uint32
|
||||
|
||||
@@ -75,6 +81,8 @@ type ExtentEntry interface {
|
||||
// tree node begins with this and is followed by `NumEntries` number of:
|
||||
// - Extent if `Depth` == 0
|
||||
// - ExtentIdx otherwise
|
||||
//
|
||||
// +marshal
|
||||
type ExtentHeader struct {
|
||||
// Magic in the extent magic number, must be 0xf30a.
|
||||
Magic uint16
|
||||
@@ -96,6 +104,8 @@ type ExtentHeader struct {
|
||||
// internal nodes. Sorted in ascending order based on FirstFileBlock since
|
||||
// Linux does a binary search on this. This points to a block containing the
|
||||
// child node.
|
||||
//
|
||||
// +marshal
|
||||
type ExtentIdx struct {
|
||||
FirstFileBlock uint32
|
||||
ChildBlockLo uint32
|
||||
@@ -121,6 +131,8 @@ func (ei *ExtentIdx) PhysicalBlock() uint64 {
|
||||
// nodes. Sorted in ascending order based on FirstFileBlock since Linux does a
|
||||
// binary search on this. This points to an array of data blocks containing the
|
||||
// file data. It covers `Length` data blocks starting from `StartBlock`.
|
||||
//
|
||||
// +marshal
|
||||
type Extent struct {
|
||||
FirstFileBlock uint32
|
||||
Length uint16
|
||||
|
||||
@@ -21,7 +21,10 @@ import (
|
||||
// TestExtentSize tests that the extent structs are of the correct
|
||||
// size.
|
||||
func TestExtentSize(t *testing.T) {
|
||||
assertSize(t, ExtentHeader{}, ExtentHeaderSize)
|
||||
assertSize(t, ExtentIdx{}, ExtentEntrySize)
|
||||
assertSize(t, Extent{}, ExtentEntrySize)
|
||||
var h ExtentHeader
|
||||
assertSize(t, &h, ExtentHeaderSize)
|
||||
var i ExtentIdx
|
||||
assertSize(t, &i, ExtentEntrySize)
|
||||
var e Extent
|
||||
assertSize(t, &e, ExtentEntrySize)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package disklayout
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
)
|
||||
@@ -38,6 +39,8 @@ const (
|
||||
//
|
||||
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#index-nodes.
|
||||
type Inode interface {
|
||||
marshal.Marshallable
|
||||
|
||||
// Mode returns the linux file mode which is majorly used to extract
|
||||
// information like:
|
||||
// - File permissions (read/write/execute by user/group/others).
|
||||
|
||||
@@ -27,6 +27,8 @@ import "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
// are used to provide nanoscond precision. Hence, these timestamps will now
|
||||
// overflow in May 2446.
|
||||
// See https://www.kernel.org/doc/html/latest/filesystems/ext4/dynamic.html#inode-timestamps.
|
||||
//
|
||||
// +marshal
|
||||
type InodeNew struct {
|
||||
InodeOld
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ const (
|
||||
//
|
||||
// All fields representing time are in seconds since the epoch. Which means that
|
||||
// they will overflow in January 2038.
|
||||
//
|
||||
// +marshal
|
||||
type InodeOld struct {
|
||||
ModeRaw uint16
|
||||
UIDLo uint16
|
||||
|
||||
@@ -24,10 +24,12 @@ import (
|
||||
|
||||
// TestInodeSize tests that the inode structs are of the correct size.
|
||||
func TestInodeSize(t *testing.T) {
|
||||
assertSize(t, InodeOld{}, OldInodeSize)
|
||||
var iOld InodeOld
|
||||
assertSize(t, &iOld, OldInodeSize)
|
||||
|
||||
// This was updated from 156 bytes to 160 bytes in Oct 2015.
|
||||
assertSize(t, InodeNew{}, 160)
|
||||
var iNew InodeNew
|
||||
assertSize(t, &iNew, 160)
|
||||
}
|
||||
|
||||
// TestTimestampSeconds tests that the seconds part of [a/c/m] timestamps in
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user