Skip to content

Commit 5d000ed

Browse files
committed
hello world: fuse overlay is working!
Signed-off-by: vsoch <[email protected]>
0 parents  commit 5d000ed

File tree

12 files changed

+391
-0
lines changed

12 files changed

+391
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin
2+
vendor

COPYRIGHT

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Intellectual Property Notice
2+
----------------------------
3+
4+
HPCIC DevTools is licensed under the MIT license (LICENSE).
5+
6+
Copyrights and patents in this project are retained by
7+
contributors. No copyright assignment is required to contribute to
8+
HPCIC DevTools.
9+
10+
SPDX usage
11+
------------
12+
13+
Individual files contain SPDX tags instead of the full license text.
14+
This enables machine processing of license information based on the SPDX
15+
License Identifiers that are available here: https://spdx.org/licenses/

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022-2023 LLNS, LLC and other HPCIC DevTools Developers.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
COMMONENVVAR=GOOS=$(shell uname -s | tr A-Z a-z)
2+
CPP = $(shell which cpp)
3+
4+
.PHONY: all
5+
all: build
6+
7+
.PHONY: build
8+
build:
9+
mkdir -p ./bin
10+
go build -o ./bin/clib-gen cmd/gen/gen.go
11+
12+
13+
.PHONY: test
14+
test:
15+
bats -t test/bats/cli.bats

NOTICE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
This work was produced under the auspices of the U.S. Department of
2+
Energy by Lawrence Livermore National Laboratory under Contract
3+
DE-AC52-07NA27344.
4+
5+
This work was prepared as an account of work sponsored by an agency of
6+
the United States Government. Neither the United States Government nor
7+
Lawrence Livermore National Security, LLC, nor any of their employees
8+
makes any warranty, expressed or implied, or assumes any legal liability
9+
or responsibility for the accuracy, completeness, or usefulness of any
10+
information, apparatus, product, or process disclosed, or represents that
11+
its use would not infringe privately owned rights.
12+
13+
Reference herein to any specific commercial product, process, or service
14+
by trade name, trademark, manufacturer, or otherwise does not necessarily
15+
constitute or imply its endorsement, recommendation, or favoring by the
16+
United States Government or Lawrence Livermore National Security, LLC.
17+
18+
The views and opinions of authors expressed herein do not necessarily
19+
state or reflect those of the United States Government or Lawrence
20+
Livermore National Security, LLC, and shall not be used for advertising
21+
or product endorsement purposes.

README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Compat Lib
2+
3+
This is a library that prepares artifacts that describe the libraries needed (exposed via ldd) for a specific binary.
4+
We are going to do several experiments here (as I learn about the space).
5+
6+
## Compatibility Wrapper
7+
8+
If we wrap a binary, we can:
9+
10+
1. Parse the ELF to get sonames needed
11+
2. Generate a fuse overlay where everything will be found in one spot (no searching needed)
12+
3. Then execute the binary.
13+
14+
We would want to see that the exercise of not needing to do the search speeds up that loading time. If it does, it would make sense to pre-package this metadata with the binary for some registry to use.
15+
16+
17+
🚧️ Under Development! 🚧️
18+
19+
## Usage
20+
21+
Build the binary
22+
23+
```bash
24+
make
25+
```
26+
27+
Test running with a binary:
28+
29+
```bash
30+
./bin/clib-gen --binary /home/vanessa/Desktop/Code/spack/opt/spack/linux-ubuntu24.04-zen4/gcc-13.2.0/xz-5.4.6-klise22d77jjaoejkucrczlkvnm6f4au/bin/lzcat
31+
```
32+
33+
Work in progress! The above calls the custom open function, so now we can do a special case for the libraries.
34+
35+
36+
## License
37+
38+
HPCIC DevTools is distributed under the terms of the MIT license.
39+
All new contributions must be made under this license.
40+
41+
See [LICENSE](https://github.com/converged-computing/cloud-select/blob/main/LICENSE),
42+
[COPYRIGHT](https://github.com/converged-computing/cloud-select/blob/main/COPYRIGHT), and
43+
[NOTICE](https://github.com/converged-computing/cloud-select/blob/main/NOTICE) for details.
44+
45+
SPDX-License-Identifier: (MIT)
46+
47+
LLNL-CODE- 842614

cmd/gen/gen.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"log"
7+
"os"
8+
"os/signal"
9+
"syscall"
10+
11+
"github.com/compspec/compat-lib/pkg/fs"
12+
"github.com/compspec/compat-lib/pkg/generate"
13+
)
14+
15+
func main() {
16+
fmt.Println("⭐️ Compatibility Library Generator (clib-gen)")
17+
binary := flag.String("binary", "", "Binary to trace")
18+
19+
flag.Parse()
20+
path := *binary
21+
22+
fmt.Printf("Preparing to find shared libraries needed for %s\n", path)
23+
paths, err := generate.FindSharedLibs(path)
24+
if err != nil {
25+
log.Panicf("Error finding shared libraries for %s: %x", path, err)
26+
}
27+
for _, path := range paths {
28+
fmt.Println(path)
29+
}
30+
31+
// Generate the fusefs server
32+
compatFS, err := fs.NewCompatFS()
33+
if err != nil {
34+
log.Panicf("Cannot generate fuse server: %x", err)
35+
}
36+
37+
// Removes mount point directory when done
38+
defer compatFS.Cleanup()
39+
40+
c := make(chan os.Signal)
41+
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
42+
go func() {
43+
<-c
44+
compatFS.Server.Unmount()
45+
}()
46+
compatFS.Server.Wait()
47+
48+
}

go.mod

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module github.com/compspec/compat-lib
2+
3+
go 1.22
4+
5+
require (
6+
github.com/hanwen/go-fuse/v2 v2.6.1
7+
github.com/u-root/u-root v0.14.0
8+
)
9+
10+
require golang.org/x/sys v0.17.0 // indirect

go.sum

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
github.com/hanwen/go-fuse/v2 v2.6.1 h1:F3RUMbAuRhVTi3fvgf8HjMPvOm9xEv5wjuy/AXJtEwI=
2+
github.com/hanwen/go-fuse/v2 v2.6.1/go.mod h1:ugNaD/iv5JYyS1Rcvi57Wz7/vrLQJo10mmketmoef48=
3+
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
4+
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
5+
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
6+
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
7+
github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg=
8+
github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1WMluqE=
9+
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
10+
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

pkg/fs/fs.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package fs
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/hanwen/go-fuse/v2/fuse"
8+
)
9+
10+
// Keep these constants for now
11+
const (
12+
debug = true
13+
14+
// mount with -o allowother
15+
other = false
16+
17+
// Try to use "mount" syscall instead of fusermount
18+
directMount = false
19+
20+
// Allow to fall back to fusermount (probably doesn't matter given directMount false)
21+
directMountStrict = false
22+
23+
// original FS is for the loopback root
24+
originalFS = "/"
25+
)
26+
27+
type CompatFS struct {
28+
Server *fuse.Server
29+
MountPoint string
30+
}
31+
32+
// Cleanup removes the mountpoint directory
33+
func (c *CompatFS) Cleanup() {
34+
35+
// Clean up mount point directory
36+
fmt.Printf("Cleaning up %s...\n", c.MountPoint)
37+
os.RemoveAll(c.MountPoint)
38+
}
39+
40+
// NewCompatFS returns a new wrapper to a fuse.Server
41+
// We mount a fusefs to a temporary directory
42+
// The server returned (if not nil) needs to be
43+
// correctly handled - see how it is used here in the library
44+
func NewCompatFS() (*CompatFS, error) {
45+
46+
// Create a Compat Filesystem with defaults
47+
compat := CompatFS{}
48+
49+
// TODO keep track of cpu and memory profiles
50+
51+
mountPoint, err := os.MkdirTemp("", "compat-lib")
52+
if err != nil {
53+
return nil, err
54+
}
55+
fmt.Printf("Mount directory %s\n", mountPoint)
56+
compat.MountPoint = mountPoint
57+
58+
// TODO add cpu / memory monitor
59+
// fname := filepath.Join(dname, "file1")
60+
// err = os.WriteFile(fname, []byte{1, 2}, 0666)
61+
// check(err)
62+
server, err := NewLoopbackRoot(originalFS, mountPoint)
63+
if err != nil {
64+
return nil, err
65+
}
66+
compat.Server = server
67+
return &compat, nil
68+
}

pkg/fs/loopback.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package fs
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"os"
8+
"syscall"
9+
"time"
10+
11+
"github.com/hanwen/go-fuse/v2/fs"
12+
"github.com/hanwen/go-fuse/v2/fuse"
13+
)
14+
15+
// We need to implement a custom LoopbackNode Open function
16+
var _ = (fs.NodeOpener)((*CompatLoopbackNode)(nil))
17+
18+
type CompatLoopbackNode struct {
19+
fs.LoopbackNode
20+
}
21+
22+
func (n *CompatLoopbackNode) Open(ctx context.Context, flags uint32) (fs.FileHandle, uint32, syscall.Errno) {
23+
fmt.Println("CUSTOM OPEN FOR %s with flags %s\n", ctx, flags)
24+
fh, flags, errno := n.LoopbackNode.Open(ctx, flags)
25+
return fh, flags, errno
26+
}
27+
28+
func (n *CompatLoopbackNode) Create(ctx context.Context, name string, flags uint32, mode uint32, out *fuse.EntryOut) (*fs.Inode, fs.FileHandle, uint32, syscall.Errno) {
29+
fmt.Println("CUSTOM CREATE FOR %s with flags %s\n", name, flags)
30+
inode, fh, flags, errno := n.LoopbackNode.Create(ctx, name, flags, mode, out)
31+
return inode, fh, flags, errno
32+
}
33+
34+
func newNode(rootData *fs.LoopbackRoot, parent *fs.Inode, name string, st *syscall.Stat_t) fs.InodeEmbedder {
35+
n := &CompatLoopbackNode{
36+
LoopbackNode: fs.LoopbackNode{
37+
RootData: rootData,
38+
},
39+
}
40+
return n
41+
}
42+
43+
func NewLoopbackRoot(rootPath, mountPoint string) (*fuse.Server, error) {
44+
45+
rootData := &fs.LoopbackRoot{
46+
NewNode: newNode,
47+
Path: rootPath,
48+
}
49+
50+
// one second is compatible with libfuse defaults
51+
// https://man7.org/linux/man-pages/man8/mount.fuse3.8.html
52+
oneSecond := time.Second
53+
54+
// https://github.com/hanwen/go-fuse/blob/master/fs/api.go
55+
options := &fs.Options{
56+
AttrTimeout: &oneSecond,
57+
EntryTimeout: &oneSecond,
58+
// Leave file permissions on "000" files
59+
NullPermissions: true,
60+
MountOptions: fuse.MountOptions{
61+
AllowOther: other,
62+
Debug: debug,
63+
DirectMount: directMount,
64+
DirectMountStrict: directMountStrict,
65+
66+
// First column in "df -T": original dir
67+
FsName: originalFS,
68+
69+
// Second column in "df -T" will be shown as "fuse." + Name
70+
Name: "loopback",
71+
72+
// "read only"
73+
Options: []string{"ro"},
74+
Logger: log.New(os.Stderr, "", 0),
75+
},
76+
}
77+
78+
server, err := fs.Mount(mountPoint, newNode(rootData, nil, "", nil), options)
79+
if err != nil {
80+
return nil, err
81+
}
82+
return server, nil
83+
}

0 commit comments

Comments
 (0)