diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-04 00:44:51 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-04 00:44:51 -0600 |
commit | e401e0b17034d59b48ad42c076705408415f00f7 (patch) | |
tree | 59c37b39c6e1e9b19dff260f5fc4caf35a4e9f06 | |
parent | 48019a4884b8936424a74c0a53798494c5c0cfc1 (diff) |
wip fuse
-rw-r--r-- | cmd/btrfs-mount/main.go | 190 | ||||
-rw-r--r-- | go.mod | 4 | ||||
-rw-r--r-- | go.sum | 8 |
3 files changed, 202 insertions, 0 deletions
diff --git a/cmd/btrfs-mount/main.go b/cmd/btrfs-mount/main.go new file mode 100644 index 0000000..8e07e77 --- /dev/null +++ b/cmd/btrfs-mount/main.go @@ -0,0 +1,190 @@ +package main + +import ( + "context" + "fmt" + "os" + "path/filepath" + "sync/atomic" + + "github.com/datawire/dlib/dcontext" + "github.com/datawire/dlib/dgroup" + "github.com/datawire/dlib/dlog" + "github.com/jacobsa/fuse" + "github.com/jacobsa/fuse/fuseops" + "github.com/jacobsa/fuse/fuseutil" + "github.com/sirupsen/logrus" + + "lukeshu.com/btrfs-tools/pkg/btrfs" + "lukeshu.com/btrfs-tools/pkg/btrfs/btrfsvol" + "lukeshu.com/btrfs-tools/pkg/btrfsmisc" +) + +func main() { + ctx := context.Background() + logger := logrus.New() + logger.SetLevel(logrus.TraceLevel) + ctx = dlog.WithLogger(ctx, dlog.WrapLogrus(logger)) + + grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{ + EnableSignalHandling: true, + }) + grp.Go("main", func(ctx context.Context) error { + return Main(ctx, os.Args[1], os.Args[2:]...) + }) + if err := grp.Wait(); err != nil { + fmt.Fprintf(os.Stderr, "%v: error: %v\n", os.Args[0], err) + os.Exit(1) + } +} + +func Main(ctx context.Context, mountpoint string, imgfilenames ...string) (err error) { + maybeSetErr := func(_err error) { + if _err != nil && err == nil { + err = _err + } + } + + fs, err := btrfsmisc.Open(os.O_RDONLY, imgfilenames...) + if err != nil { + return err + } + defer func() { + maybeSetErr(fs.Close()) + }() + + fsAdapter := &FSAdapter{ + fs: fs, + } + + devname, err := filepath.Abs(imgfilenames[0]) + if err != nil { + devname = imgfilenames[0] + } + mount, err := fuse.Mount( + mountpoint, + fuseutil.NewFileSystemServer(fsAdapter), + &fuse.MountConfig{ + OpContext: ctx, + ErrorLogger: dlog.StdLogger(ctx, dlog.LogLevelError), + DebugLogger: dlog.StdLogger(ctx, dlog.LogLevelDebug), + + FSName: devname, + Subtype: "btrfs", + + ReadOnly: true, + }) + if err != nil { + return err + } + + mounted := uint32(1) + grp := dgroup.NewGroup(ctx, dgroup.GroupConfig{ + ShutdownOnNonError: true, + }) + grp.Go("send-unmount", func(ctx context.Context) error { + <-ctx.Done() + if atomic.LoadUint32(&mounted) == 0 { + return nil + } + return fuse.Unmount(os.Args[1]) + }) + grp.Go("recv-unmount", func(ctx context.Context) error { + ret := mount.Join(dcontext.HardContext(ctx)) + atomic.StoreUint32(&mounted, 0) + return ret + }) + return grp.Wait() +} + +type FSAdapter struct { + fuseutil.NotImplementedFileSystem + + fs *btrfs.FS + + rootInodeOnce sync.Once + rootInodeVal btrfs.ObjID + rootInodeErr error + + inode2treeMu sync.Mutex + inode2tree map[btrfs.ObjID]btrfsvol.LogicalAddr +} + +func (a *FSAdapter) getRootInode() (btrfs.ObjID, error) { + a.rootInodeOnce.Do(func() { + a.rootInodeVal, a.rootInodeErr = func() (btrfs.ObjID, error) { + sb, err := a.fs.Superblock() + if err != nil { + return 0, err + } + + root, err := fs.TreeLookup(sb.Data.RootTree, btrfs.Key{ + ObjectID: btrfs.FS_TREE_OBJECTID, + ItemType: btrfsitem.ROOT_ITEM_KEY, + Offset: 0, + }) + if err != nil { + return 0, err + } + rootBody, ok := root.Body.(btrfsitem.Root) + if !ok { + return 0, fmt.Errorf("FS_TREE_ ROOT_ITEM has malformed body") + } + return rootBody.RootDirID, nil + }() + }) + return a.rootInodeVal, a.rootInodeErr +} + +func (a *FSAdapter) StatFS(_ context.Context, op *fuseops.StatFSOp) error { + // See linux.git/fs/btrfs/super.c:btrfs_statfs() + sb, err := a.fs.Superblock() + if err != nil { + return err + } + + op.IoSize = sb.Data.SectorSize + op.BlockSize = sb.Data.SectorSize + op.Blocks = sb.Data.TotalBytes / uint64(sb.Data.SectorSize) // TODO: adjust for RAID type + //op.BlocksFree = TODO + + // btrfs doesn't have a fixed number of inodes + op.Inodes = 0 + op.InodesFree = 0 + + // jacobsa/fuse doesn't expose namelen, instead hard-coding it + // to 255. Which is fine by us, because that's what it is for + // btrfs. + + return nil +} + +// func (a *FSAdapter) LookUpInode(_ context.Context, op *fuseops.LookUpInodeOp) error {} + +func (a *FSAdapter) GetInodeAttributes(ctx context.Context, op *fuseops.GetInodeAttributesOp) error { + sb, err := a.fs.Superblock() + if err != nil { + return err + } + + if op.Inode == fuseops.RootInodeID { + io.Inode, err = a.getRootInode() + if err != nil { + return err + } + } + +} + +// func (a *FSAdapter) ForgetInode(_ context.Context, op *fuseops.ForgetInodeOp) error {} +// func (a *FSAdapter) BatchForget(_ context.Context, op *fuseops.BatchForgetOp) error {} +// func (a *FSAdapter) OpenDir(_ context.Context, op *fuseops.OpenDirOp) error {} +// func (a *FSAdapter) ReadDir(_ context.Context, op *fuseops.ReadDirOp) error {} +// func (a *FSAdapter) ReleaseDirHandle(_ context.Context, op *fuseops.ReleaseDirHandleOp) error {} +// func (a *FSAdapter) OpenFile(_ context.Context, op *fuseops.OpenFileOp) error {} +// func (a *FSAdapter) ReadFile(_ context.Context, op *fuseops.ReadFileOp) error {} +// func (a *FSAdapter) ReleaseFileHandle(_ context.Context, op *fuseops.ReleaseFileHandleOp) error {} +// func (a *FSAdapter) ReadSymlink(_ context.Context, op *fuseops.ReadSymlinkOp) error {} +// func (a *FSAdapter) GetXattr(_ context.Context, op *fuseops.GetXattrOp) error {} +// func (a *FSAdapter) ListXattr(_ context.Context, op *fuseops.ListXattrOp) error {} +// func (a *FSAdapter) Destroy() {} @@ -5,13 +5,17 @@ go 1.18 require ( github.com/datawire/dlib v1.3.0 github.com/davecgh/go-spew v1.1.1 + github.com/jacobsa/fuse v0.0.0-20220702091825-13117049f383 + github.com/sirupsen/logrus v1.6.0 github.com/stretchr/testify v1.7.1 golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf golang.org/x/text v0.3.7 ) require ( + github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) @@ -3,16 +3,21 @@ github.com/datawire/dlib v1.3.0/go.mod h1:NiGDmetmbkBvtznpWSx6C0vA0s0LK9aHna3LJD github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jacobsa/fuse v0.0.0-20220702091825-13117049f383 h1:LmgK5WyqEu12BdEFkD5XxNxyK1SFk5Iz4TQsq96NxQM= +github.com/jacobsa/fuse v0.0.0-20220702091825-13117049f383/go.mod h1:liOmRdJd8oTwHCQ5M9JemRE3CebdlYcZWLk+ZjQeuq0= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -22,8 +27,11 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf h1:oXVg4h2qJDd9htKxb5SCpFBHLipW6hXmL3qpUixS2jw= golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= |