Skip to content

Commit

Permalink
refactor: rewrite GPT library
Browse files Browse the repository at this point in the history
This replaces the serde package. The serialization/deserialization process was rigid and
made doing precision work on GPT impossible. This PR allows for serialization/deserialization
of specific fields of the GPT header and partitions.

Signed-off-by: Andrew Rynhard <[email protected]>
  • Loading branch information
andrewrynhard authored and talos-bot committed Nov 26, 2020
1 parent 2a1baad commit 98754ec
Show file tree
Hide file tree
Showing 24 changed files with 1,811 additions and 1,675 deletions.
12 changes: 5 additions & 7 deletions blockdevice/blkpg/blkpg_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,24 @@ package blkpg
import (
"fmt"
"os"

"github.com/talos-systems/go-blockdevice/blockdevice/table"
)

// InformKernelOfAdd invokes the BLKPG_ADD_PARTITION ioctl.
func InformKernelOfAdd(f *os.File, partition table.Partition) error {
func InformKernelOfAdd(f *os.File, first, length uint64, n int32) error {
return fmt.Errorf("not implemented")
}

// InformKernelOfResize invokes the BLKPG_RESIZE_PARTITION ioctl.
func InformKernelOfResize(f *os.File, partition table.Partition) error {
func InformKernelOfResize(f *os.File, first, length uint64, n int32) error {
return fmt.Errorf("not implemented")
}

// InformKernelOfDelete invokes the BLKPG_DEL_PARTITION ioctl.
func InformKernelOfDelete(f *os.File, partition table.Partition) error {
func InformKernelOfDelete(f *os.File, first, length uint64, n int32) error {
return fmt.Errorf("not implemented")
}

// GetKernelPartitions returns kernel state of partitions.
func GetKernelPartitions(f *os.File, devPath string) ([]KernelPartition, error) {
// GetKernelPartitions returns kernel partition table state.
func GetKernelPartitions(f *os.File) ([]KernelPartition, error) {
return nil, fmt.Errorf("not implemented")
}
44 changes: 22 additions & 22 deletions blockdevice/blkpg/blkpg_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,52 +19,51 @@ import (
"golang.org/x/sys/unix"

"github.com/talos-systems/go-blockdevice/blockdevice/lba"
"github.com/talos-systems/go-blockdevice/blockdevice/table"
"github.com/talos-systems/go-blockdevice/blockdevice/util"
)

// InformKernelOfAdd invokes the BLKPG_ADD_PARTITION ioctl.
func InformKernelOfAdd(f *os.File, partition table.Partition) error {
return inform(f, partition, unix.BLKPG_ADD_PARTITION)
func InformKernelOfAdd(f *os.File, first, length uint64, n int32) error {
return inform(f, first, length, n, unix.BLKPG_ADD_PARTITION)
}

// InformKernelOfResize invokes the BLKPG_RESIZE_PARTITION ioctl.
func InformKernelOfResize(f *os.File, partition table.Partition) error {
return inform(f, partition, unix.BLKPG_RESIZE_PARTITION)
func InformKernelOfResize(f *os.File, first, length uint64, n int32) error {
return inform(f, first, length, n, unix.BLKPG_RESIZE_PARTITION)
}

// InformKernelOfDelete invokes the BLKPG_DEL_PARTITION ioctl.
func InformKernelOfDelete(f *os.File, partition table.Partition) error {
return inform(f, partition, unix.BLKPG_DEL_PARTITION)
func InformKernelOfDelete(f *os.File, first, length uint64, n int32) error {
return inform(f, first, length, n, unix.BLKPG_DEL_PARTITION)
}

func inform(f *os.File, partition table.Partition, op int32) (err error) {
func inform(f *os.File, first, length uint64, n, op int32) (err error) {
var (
start int64
length int64
start int64
end int64
)

switch op {
case unix.BLKPG_DEL_PARTITION:
start = 0
length = 0
end = 0
default:
var l *lba.LogicalBlockAddresser
var l *lba.LBA

if l, err = lba.New(f); err != nil {
if l, err = lba.NewLBA(f); err != nil {
return err
}

blocksize := int64(l.LogicalBlockSize)
blocksize := l.LogicalBlockSize

start = partition.Start() * blocksize
length = partition.Length() * blocksize
start = int64(first) * blocksize
end = int64(length) * blocksize
}

data := &unix.BlkpgPartition{
Start: start,
Length: length,
Pno: partition.No(),
Length: end,
Pno: n,
}

arg := &unix.BlkpgIoctlArg{
Expand All @@ -82,7 +81,8 @@ func inform(f *os.File, partition table.Partition, op int32) (err error) {
)

if errno != 0 {
switch errno { //nolint: exhaustive
//nolint: exhaustive
switch errno {
case unix.EBUSY:
return retry.ExpectedError(errno)
default:
Expand All @@ -105,12 +105,12 @@ func inform(f *os.File, partition table.Partition, op int32) (err error) {
}

// GetKernelPartitions returns kernel partition table state.
func GetKernelPartitions(f *os.File, devPath string) ([]KernelPartition, error) {
func GetKernelPartitions(f *os.File) ([]KernelPartition, error) {
result := []KernelPartition{}

for i := 1; i <= 256; i++ {
partName := util.PartName(devPath, i)
partPath := filepath.Join("/sys/block", filepath.Base(devPath), partName)
partName := util.PartName(f.Name(), i)
partPath := filepath.Join("/sys/block", filepath.Base(f.Name()), partName)

_, err := os.Stat(partPath)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions blockdevice/blockdevice_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (
"fmt"
"os"

"github.com/talos-systems/go-blockdevice/blockdevice/table"
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
)

// BlockDevice represents a block device.
type BlockDevice struct {
table table.PartitionTable
table *gpt.GPT

f *os.File
}
Expand All @@ -30,7 +30,7 @@ func (bd *BlockDevice) Close() error {
}

// PartitionTable returns the block device partition table.
func (bd *BlockDevice) PartitionTable() (table.PartitionTable, error) {
func (bd *BlockDevice) PartitionTable() (*gpt.GPT, error) {
return nil, fmt.Errorf("not implemented")
}

Expand Down
43 changes: 16 additions & 27 deletions blockdevice/blockdevice_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import (
"github.com/talos-systems/go-retry/retry"
"golang.org/x/sys/unix"

"github.com/talos-systems/go-blockdevice/blockdevice/table"
"github.com/talos-systems/go-blockdevice/blockdevice/table/gpt"
"github.com/talos-systems/go-blockdevice/blockdevice/partition/gpt"
)

// Linux headers constants.
Expand All @@ -37,7 +36,7 @@ const (

// BlockDevice represents a block device.
type BlockDevice struct {
table table.PartitionTable
g *gpt.GPT

f *os.File
}
Expand Down Expand Up @@ -67,21 +66,16 @@ func Open(devname string, setters ...Option) (bd *BlockDevice, err error) {
if opts.CreateGPT {
var g *gpt.GPT

if g, err = gpt.NewGPT(devname, f); err != nil {
return nil, err
}

var pt table.PartitionTable

if pt, err = g.New(); err != nil {
g, err = gpt.New(f)
if err != nil {
return nil, err
}

if err = pt.Write(); err != nil {
if err = g.Write(); err != nil {
return nil, err
}

bd.table = pt
bd.g = g
} else {
buf := make([]byte, 1)
// PMBR protective entry starts at 446. The partition type is at offset
Expand All @@ -94,10 +88,10 @@ func Open(devname string, setters ...Option) (bd *BlockDevice, err error) {
// For GPT, the partition type should be 0xee (EFI GPT).
if bytes.Equal(buf, []byte{0xee}) {
var g *gpt.GPT
if g, err = gpt.NewGPT(devname, f); err != nil {
if g, err = gpt.Open(f); err != nil {
return nil, err
}
bd.table = g
bd.g = g
}
}

Expand All @@ -110,12 +104,12 @@ func (bd *BlockDevice) Close() error {
}

// PartitionTable returns the block device partition table.
func (bd *BlockDevice) PartitionTable() (table.PartitionTable, error) {
if bd.table == nil {
func (bd *BlockDevice) PartitionTable() (*gpt.GPT, error) {
if bd.g == nil {
return nil, ErrMissingPartitionTable
}

return bd.table, bd.table.Read()
return bd.g, bd.g.Read()
}

// RereadPartitionTable invokes the BLKRRPART ioctl to have the kernel read the
Expand Down Expand Up @@ -145,7 +139,8 @@ func (bd *BlockDevice) RereadPartitionTable() error {
if _, _, ret = unix.Syscall(unix.SYS_IOCTL, bd.f.Fd(), unix.BLKRRPART, 0); ret == 0 {
return nil
}
switch ret { //nolint: exhaustive
//nolint: exhaustive
switch ret {
case syscall.EBUSY:
return retry.ExpectedError(err)
default:
Expand Down Expand Up @@ -256,17 +251,11 @@ func (bd *BlockDevice) WipeRange(start, length uint64) (string, error) {
// Reset will reset a block device given a device name.
// Simply deletes partition table on device.
func (bd *BlockDevice) Reset() (err error) {
var pt table.PartitionTable

if pt, err = bd.PartitionTable(); err != nil {
return err
}

for _, p := range pt.Partitions() {
if err = pt.Delete(p); err != nil {
for _, p := range bd.g.Partitions().Items() {
if err = bd.g.Delete(p); err != nil {
return fmt.Errorf("failed to delete partition: %w", err)
}
}

return pt.Write()
return bd.g.Write()
}
59 changes: 59 additions & 0 deletions blockdevice/lba/lba.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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 lba

import (
"fmt"
"os"
)

// Buffer is an in-memory buffer for writing to byte slices in units of LBA.
type Buffer struct {
lba *LBA
b []byte
}

// NewBuffer intializes and returns a `Buffer`.
func NewBuffer(lba *LBA, b []byte) *Buffer {
return &Buffer{lba: lba, b: b}
}

// Read reads from a `Buffer`.
func (buf *Buffer) Read(off, length int64) (b []byte, err error) {
b = make([]byte, length)

n := copy(b, buf.b[off:off+length])

if n != len(buf.b[off:off+length]) {
return nil, fmt.Errorf("expected to write %d bytes, read %d", len(b), n)
}

return b, nil
}

// Write writes to a `Buffer`.
func (buf *Buffer) Write(b []byte, off int64) (err error) {
n := copy(buf.b[off:off+int64(len(b))], b)

if n != len(b) {
return fmt.Errorf("expected to write %d bytes, read %d", len(b), n)
}

return nil
}

// Bytes returns the buffer bytes.
func (buf *Buffer) Bytes() []byte {
return buf.b
}

// LBA represents logical block addressing.
type LBA struct {
PhysicalBlockSize int64
LogicalBlockSize int64
TotalSectors int64

f *os.File
}
34 changes: 8 additions & 26 deletions blockdevice/lba/lba_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,24 @@
// 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 lba provides a library for working with Logical Block Addresses.
package lba

import (
"fmt"
"os"
)

// Range represents a range of Logical Block Addresses.
type Range struct {
Start uint64
End uint64
}

// LogicalBlockAddresser represents Logical Block Addressing.
type LogicalBlockAddresser struct {
PhysicalBlockSize uint64
LogicalBlockSize uint64
}

// New initializes and returns a LogicalBlockAddresser.
func New(f *os.File) (lba *LogicalBlockAddresser, err error) {
// NewLBA initializes and returns an `LBA`.
func NewLBA(f *os.File) (lba *LBA, err error) {
return nil, fmt.Errorf("not implemented")
}

// Make returns a slice from a source slice in the the specified range inclusively.
func (lba *LogicalBlockAddresser) Make(size uint64) []byte {
return nil
}

// Copy copies from src to dst in the specified range.
func (lba *LogicalBlockAddresser) Copy(dst, src []byte, rng Range) (int, error) {
return 0, fmt.Errorf("not implemented")
// ReadAt reads from a file in units of LBA.
func (l *LBA) ReadAt(lba, off, length int64) (b []byte, err error) {
return nil, fmt.Errorf("not implemented")
}

// From returns a slice from a source slice in the the specified range inclusively.
func (lba *LogicalBlockAddresser) From(src []byte, rng Range) ([]byte, error) {
return nil, fmt.Errorf("not implemented")
// WriteAt writes to a file in units of LBA.
func (l *LBA) WriteAt(lba, off int64, b []byte) (err error) {
return fmt.Errorf("not implemented")
}
Loading

0 comments on commit 98754ec

Please sign in to comment.