Skip to content

Commit d08d4b2

Browse files
committed
Add tinyfs.SliceBlockDev that will "partition" a block dev
This is useful to create a fixed-size BlockDevice from machine.Flash, which can vary when the firmware changes (and might require a format each time it crosses a page boundary). Tested with littlefs, it seems to be working fine.
1 parent 4a92500 commit d08d4b2

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

slice.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package tinyfs
2+
3+
import (
4+
"errors"
5+
"math/bits"
6+
)
7+
8+
var (
9+
ErrInvalidBlockSize = errors.New("tinyfs: write/erase block size too big or not aligned")
10+
ErrDeviceTooSmall = errors.New("tinyfs: requested device size is smaller than underlying device")
11+
)
12+
13+
type blockDevOffset struct {
14+
dev BlockDevice
15+
offset int64
16+
}
17+
18+
// Create a new virtual BlockDevice that is the upper part of the given full
19+
// BlockDevice, with the given size. This can be useful for example to use only
20+
// a fixed size machine.Flash object that won't change on firmware changes.
21+
func SliceBlockDev(full BlockDevice, size int64) (BlockDevice, error) {
22+
if bits.OnesCount16(uint16(full.WriteBlockSize())) != 1 || bits.OnesCount16(uint16(full.EraseBlockSize())) != 1 {
23+
// Check that the write/erase block size is a power of two.
24+
// This is normally the case, and makes the following calculations
25+
// easier.
26+
return nil, ErrInvalidBlockSize
27+
}
28+
29+
// Check whether the requested size can be used (is a multiple of the block
30+
// size).
31+
blockSize := max(full.EraseBlockSize(), full.WriteBlockSize())
32+
if size/blockSize*blockSize != size {
33+
return nil, ErrInvalidBlockSize
34+
}
35+
36+
fullSize := full.Size()
37+
if fullSize < size {
38+
// Not big enough to provide the expected device size.
39+
return nil, ErrDeviceTooSmall
40+
}
41+
if fullSize == size {
42+
// Shortcut: the requested size is exactly big enough.
43+
return full, nil
44+
}
45+
offset := fullSize - size
46+
return &blockDevOffset{
47+
dev: full,
48+
offset: offset,
49+
}, nil
50+
}
51+
52+
func (b *blockDevOffset) ReadAt(buf []byte, offset int64) (n int, err error) {
53+
return b.dev.ReadAt(buf, offset+b.offset)
54+
}
55+
56+
func (b *blockDevOffset) WriteAt(buf []byte, offset int64) (n int, err error) {
57+
return b.dev.WriteAt(buf, offset+b.offset)
58+
}
59+
60+
func (b *blockDevOffset) Size() int64 {
61+
return b.dev.Size() - b.offset
62+
}
63+
64+
func (b *blockDevOffset) EraseBlockSize() int64 {
65+
return b.dev.EraseBlockSize()
66+
}
67+
68+
func (b *blockDevOffset) WriteBlockSize() int64 {
69+
return b.dev.WriteBlockSize()
70+
}
71+
72+
func (b *blockDevOffset) EraseBlocks(start, len int64) error {
73+
blockOffset := b.offset / b.EraseBlockSize()
74+
return b.dev.EraseBlocks(start+blockOffset, len)
75+
}

0 commit comments

Comments
 (0)