summaryrefslogtreecommitdiff
path: root/cmd/btrfs-mount/subvol.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-07-05 12:26:45 -0600
committerLuke Shumaker <lukeshu@lukeshu.com>2022-07-08 00:15:09 -0600
commitb392ad64a8fd04d20b35ad21d2d4ea3ff2778e3f (patch)
treefea515cb26435c767320ecb7b07fe1fec01ce388 /cmd/btrfs-mount/subvol.go
parent08a2266c346edc20ad7bfdda62dc8f685f0be27d (diff)
wip file io
Diffstat (limited to 'cmd/btrfs-mount/subvol.go')
-rw-r--r--cmd/btrfs-mount/subvol.go207
1 files changed, 139 insertions, 68 deletions
diff --git a/cmd/btrfs-mount/subvol.go b/cmd/btrfs-mount/subvol.go
index e4e0460..4e741ad 100644
--- a/cmd/btrfs-mount/subvol.go
+++ b/cmd/btrfs-mount/subvol.go
@@ -7,8 +7,8 @@ import (
"sync"
"github.com/datawire/dlib/dcontext"
+ "github.com/datawire/dlib/derror"
"github.com/datawire/dlib/dlog"
- lru "github.com/hashicorp/golang-lru"
"github.com/jacobsa/fuse"
"github.com/jacobsa/fuse/fuseutil"
@@ -18,6 +18,28 @@ import (
"lukeshu.com/btrfs-tools/pkg/util"
)
+type bareInode struct {
+ Inode btrfs.ObjID
+ InodeItem *btrfsitem.Inode
+ Errs derror.MultiError
+}
+
+type fullInode struct {
+ bareInode
+ OtherItems []btrfs.Item
+}
+
+type dir struct {
+ fullInode
+ ChildrenByName map[string]btrfsitem.DirEntry
+ ChildrenByIndex map[uint64]btrfsitem.DirEntry
+}
+
+type file struct {
+ fullInode
+ // TODO
+}
+
type Subvolume struct {
FS *btrfs.FS
DeviceName string
@@ -28,8 +50,10 @@ type Subvolume struct {
rootVal btrfsitem.Root
rootErr error
- inodeCache *lru.ARCCache
- dirCache *lru.ARCCache
+ bareInodeCache LRUCache[btrfs.ObjID, *bareInode]
+ fullInodeCache LRUCache[btrfs.ObjID, *fullInode]
+ dirCache LRUCache[btrfs.ObjID, *dir]
+ fileCache LRUCache[btrfs.ObjID, *file]
subvolumeFUSE
}
@@ -79,11 +103,6 @@ func (sv *Subvolume) init() {
}
sv.rootVal = rootBody
-
- sv.inodeCache, _ = lru.NewARC(128)
- sv.dirCache, _ = lru.NewARC(128)
-
- sv.subvolumeFUSE.init()
})
}
@@ -97,73 +116,108 @@ func (sv *Subvolume) getFSTree() (btrfsvol.LogicalAddr, error) {
return sv.rootVal.ByteNr, sv.rootErr
}
-func (sv *Subvolume) loadInode(inode btrfs.ObjID) (btrfsitem.Inode, error) {
- tree, err := sv.getFSTree()
- if err != nil {
- return btrfsitem.Inode{}, nil
- }
- if ret, ok := sv.inodeCache.Get(inode); ok {
- return ret.(btrfsitem.Inode), nil
- }
- item, err := sv.FS.TreeLookup(tree, btrfs.Key{
- ObjectID: inode,
- ItemType: btrfsitem.INODE_ITEM_KEY,
- Offset: 0,
- })
- if err != nil {
- return btrfsitem.Inode{}, err
- }
+func (sv *Subvolume) loadBareInode(inode btrfs.ObjID) (*bareInode, error) {
+ val := sv.bareInodeCache.GetOrElse(inode, func() (val *bareInode) {
+ val = &bareInode{
+ Inode: inode,
+ }
+ tree, err := sv.getFSTree()
+ if err != nil {
+ val.Errs = append(val.Errs, err)
+ return
+ }
+ item, err := sv.FS.TreeLookup(tree, btrfs.Key{
+ ObjectID: inode,
+ ItemType: btrfsitem.INODE_ITEM_KEY,
+ Offset: 0,
+ })
+ if err != nil {
+ val.Errs = append(val.Errs, err)
+ return
+ }
- itemBody, ok := item.Body.(btrfsitem.Inode)
- if !ok {
- return btrfsitem.Inode{}, fmt.Errorf("malformed inode")
- }
+ itemBody, ok := item.Body.(btrfsitem.Inode)
+ if !ok {
+ val.Errs = append(val.Errs, fmt.Errorf("malformed inode"))
+ return
+ }
+ val.InodeItem = &itemBody
- sv.inodeCache.Add(inode, itemBody)
- return itemBody, nil
+ return
+ })
+ if val.InodeItem == nil {
+ return nil, val.Errs
+ }
+ return val, nil
}
-type dir struct {
- Inode btrfs.ObjID
- InodeDat *btrfsitem.Inode
- ChildrenByName map[string]btrfsitem.DirEntry
- ChildrenByIndex map[uint64]btrfsitem.DirEntry
- Errs []error
+func (sv *Subvolume) loadFullInode(inode btrfs.ObjID) (*fullInode, error) {
+ val := sv.fullInodeCache.GetOrElse(inode, func() (val *fullInode) {
+ val = &fullInode{
+ bareInode: bareInode{
+ Inode: inode,
+ },
+ }
+ tree, err := sv.getFSTree()
+ if err != nil {
+ val.Errs = append(val.Errs, err)
+ return
+ }
+ items, err := sv.FS.TreeSearchAll(tree, func(key btrfs.Key) int {
+ return util.CmpUint(inode, key.ObjectID)
+ })
+ if err != nil {
+ val.Errs = append(val.Errs, err)
+ if len(items) == 0 {
+ return
+ }
+ }
+ for _, item := range items {
+ switch item.Head.Key.ItemType {
+ case btrfsitem.INODE_ITEM_KEY:
+ itemBody := item.Body.(btrfsitem.Inode)
+ if val.InodeItem != nil {
+ if !reflect.DeepEqual(itemBody, *val.InodeItem) {
+ val.Errs = append(val.Errs, fmt.Errorf("multiple inodes"))
+ }
+ continue
+ }
+ val.InodeItem = &itemBody
+ default:
+ val.OtherItems = append(val.OtherItems, item)
+ }
+ }
+ return
+ })
+ if val.InodeItem == nil && val.OtherItems == nil {
+ return nil, val.Errs
+ }
+ return val, nil
}
func (sv *Subvolume) loadDir(inode btrfs.ObjID) (*dir, error) {
- tree, err := sv.getFSTree()
- if err != nil {
- return nil, err
- }
- if ret, ok := sv.dirCache.Get(inode); ok {
- return ret.(*dir), nil
- }
- ret := &dir{
- Inode: inode,
- ChildrenByName: make(map[string]btrfsitem.DirEntry),
- ChildrenByIndex: make(map[uint64]btrfsitem.DirEntry),
- }
- items, err := sv.FS.TreeSearchAll(tree, func(key btrfs.Key) int {
- return util.CmpUint(inode, key.ObjectID)
- })
- if err != nil {
- if len(items) == 0 {
- return nil, err
+ val := sv.dirCache.GetOrElse(inode, func() (val *dir) {
+ val = new(dir)
+ fullInode, err := sv.loadFullInode(inode)
+ if err != nil {
+ val.Errs = append(val.Errs, err)
+ return
}
- ret.Errs = append(ret.Errs, err)
+ val.fullInode = *fullInode
+ val.populate()
+ return
+ })
+ if val.Inode == 0 {
+ return nil, val.Errs
}
- for _, item := range items {
+ return val, nil
+}
+
+func (ret *dir) populate() {
+ ret.ChildrenByName = make(map[string]btrfsitem.DirEntry)
+ ret.ChildrenByIndex = make(map[uint64]btrfsitem.DirEntry)
+ for _, item := range ret.OtherItems {
switch item.Head.Key.ItemType {
- case btrfsitem.INODE_ITEM_KEY:
- itemBody := item.Body.(btrfsitem.Inode)
- if ret.InodeDat != nil {
- if !reflect.DeepEqual(itemBody, *ret.InodeDat) {
- ret.Errs = append(ret.Errs, fmt.Errorf("multiple inodes"))
- }
- continue
- }
- ret.InodeDat = &itemBody
case btrfsitem.INODE_REF_KEY:
// TODO
case btrfsitem.DIR_ITEM_KEY:
@@ -205,7 +259,7 @@ func (sv *Subvolume) loadDir(inode btrfs.ObjID) (*dir, error) {
}
//case btrfsitem.XATTR_ITEM_KEY:
default:
- ret.Errs = append(ret.Errs, fmt.Errorf("TODO: handle item type %v", item.Head.Key.ItemType))
+ panic(fmt.Errorf("TODO: handle item type %v", item.Head.Key.ItemType))
}
}
entriesWithIndexes := make(map[string]struct{})
@@ -230,6 +284,23 @@ func (sv *Subvolume) loadDir(inode btrfs.ObjID) (*dir, error) {
nextIndex++
}
}
- sv.dirCache.Add(inode, ret)
- return ret, nil
+ return
+}
+
+func (sv *Subvolume) loadFile(inode btrfs.ObjID) (*file, error) {
+ val := sv.fileCache.GetOrElse(inode, func() (val *file) {
+ val = new(file)
+ fullInode, err := sv.loadFullInode(inode)
+ if err != nil {
+ val.Errs = append(val.Errs, err)
+ return
+ }
+ val.fullInode = *fullInode
+ // TODO
+ return
+ })
+ if val.Inode == 0 {
+ return nil, val.Errs
+ }
+ return val, nil
}