Skip to content

Commit

Permalink
Merge pull request #40 from AkihiroSuda/drop-libbtrfs
Browse files Browse the repository at this point in the history
Depend on kernel UAPI instead of libbtrfs; Bump up the package version to v2
  • Loading branch information
AkihiroSuda committed Feb 10, 2023
2 parents 78e9fa3 + 736bb75 commit f611cf1
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 31 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,9 @@ jobs:
- name: Build
working-directory: src/github.com/containerd/btrfs
run: |
sudo apt-get update && sudo apt-get install -y libbtrfs-dev
make vet binaries
- name: Build with an old version of kernel headers
working-directory: src/github.com/containerd/btrfs
run: |
DOCKER_BUILDKIT=1 docker build -f hack/Dockerfile.compilation-test .
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ Native Go bindings for btrfs.
These are in the early stages. We will try to maintain stability, but please
vendor if you are relying on these directly.

# Dependencies

## v2.x

Headers from kernel 4.12 or newer.
The package name is `linux-libc-dev` on Debian/Ubuntu, `kernel-headers` on Fedora and RHEL-like distros.

The headers are only required on compilation time, not on run time.

## v1.x

libbtrfs headers.
The package name is `libbtrfs-dev` on Debian/Ubuntu, `btrfs-progs-devel` on Fedora and CentOS 7.
The package is not available for Rocky Linux and AlmaLinux.

# Contribute

This package may not cover all the use cases for btrfs. If something you need
Expand Down
12 changes: 4 additions & 8 deletions btrfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,16 @@
limitations under the License.
*/

#include <stddef.h>
#include <linux/magic.h>
#include <btrfs/ioctl.h>
#include <btrfs/ctree.h>

#include <string.h>
#include "btrfs.h"

void unpack_root_item(struct gosafe_btrfs_root_item* dst, struct btrfs_root_item* src) {
memcpy(dst->uuid, src->uuid, BTRFS_UUID_SIZE);
memcpy(dst->parent_uuid, src->parent_uuid, BTRFS_UUID_SIZE);
memcpy(dst->received_uuid, src->received_uuid, BTRFS_UUID_SIZE);
dst->gen = btrfs_root_generation(src);
dst->ogen = btrfs_root_otransid(src);
dst->flags = btrfs_root_flags(src);
dst->generation = src->generation;
dst->otransid = src->otransid;
dst->flags = src->flags;
}

/* unpack_root_ref(struct gosafe_btrfs_root_ref* dst, struct btrfs_root_ref* src) { */
11 changes: 5 additions & 6 deletions btrfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
package btrfs

/*
#include <stddef.h>
#include <btrfs/ioctl.h>
#include <linux/magic.h>
#include "btrfs.h"
static char* get_name_btrfs_ioctl_vol_args_v2(struct btrfs_ioctl_vol_args_v2* btrfs_struct) {
Expand Down Expand Up @@ -154,13 +153,13 @@ func subvolMap(path string) (map[uint64]*Info, error) {
// get an entry of the objectid, with name, but the parent is
// the offset.

nname := C.btrfs_stack_root_ref_name_len(&rr)
nname := le16ToNative(rr.name_len)
name := string(buf[C.sizeof_struct_btrfs_root_ref : C.sizeof_struct_btrfs_root_ref+uintptr(nname)])

info.ID = uint64(sh.objectid)
info.ParentID = uint64(sh.offset)
info.Name = name
info.DirID = uint64(C.btrfs_stack_root_ref_dirid(&rr))
info.DirID = le64ToNative(rr.dirid)

subvolsByID[uint64(sh.objectid)] = info
} else if sh._type == C.BTRFS_ROOT_ITEM_KEY &&
Expand All @@ -185,8 +184,8 @@ func subvolMap(path string) (map[uint64]*Info, error) {
info.ParentUUID = uuidString(&gri.parent_uuid)
info.ReceivedUUID = uuidString(&gri.received_uuid)

info.Generation = uint64(gri.gen)
info.OriginalGeneration = uint64(gri.ogen)
info.Generation = le64ToNative(gri.generation)
info.OriginalGeneration = le64ToNative(gri.otransid)

subvolsByID[uint64(sh.objectid)] = info
}
Expand Down
22 changes: 12 additions & 10 deletions btrfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,25 @@
limitations under the License.
*/

#include <stddef.h>
#include <linux/magic.h>
#include <btrfs/ioctl.h>
#include <btrfs/ctree.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)
#error "Headers from kernel >= 4.12 are required on compilation time (not on run time)"
#endif
#include <linux/btrfs.h>
#include <linux/btrfs_tree.h>

// unfortunately, we need to define "alignment safe" C structs to populate for
// packed structs that aren't handled by cgo. Fields will be added here, as
// needed.

struct gosafe_btrfs_root_item {
u8 uuid[BTRFS_UUID_SIZE];
u8 parent_uuid[BTRFS_UUID_SIZE];
u8 received_uuid[BTRFS_UUID_SIZE];
__u8 uuid[BTRFS_UUID_SIZE];
__u8 parent_uuid[BTRFS_UUID_SIZE];
__u8 received_uuid[BTRFS_UUID_SIZE];

u64 gen;
u64 ogen;
u64 flags;
__le64 generation;
__le64 otransid;
__le64 flags;
};

void unpack_root_item(struct gosafe_btrfs_root_item* dst, struct btrfs_root_item* src);
Expand Down
2 changes: 1 addition & 1 deletion cmd/btrfs-test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"os"
"text/tabwriter"

"github.com/containerd/btrfs"
"github.com/containerd/btrfs/v2"
)

var (
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/containerd/btrfs
module github.com/containerd/btrfs/v2

go 1.19

require golang.org/x/sys v0.5.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18 changes: 18 additions & 0 deletions hack/Dockerfile.compilation-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Dockerfile for testing compilation with an old version of the kernel headers.

ARG GOLANG_VERSION=1.19
# LINUX_VERSION must be >= 4.12 (https://github.com/torvalds/linux/commit/fcc8487d477a3452a1d0ccbdd4c5e0e1e3cb8bed)
ARG LINUX_VERSION=4.12

FROM golang:${GOLANG_VERSION}
ARG LINUX_VERSION
RUN curl -sSL -O "https://mirrors.edge.kernel.org/pub/linux/kernel/v$(echo ${LINUX_VERSION} | cut -d. -f1).x/linux-${LINUX_VERSION}.tar.gz"
RUN tar Cxzf / "linux-${LINUX_VERSION}.tar.gz" && \
cd "/linux-${LINUX_VERSION}" && \
make headers_install INSTALL_HDR_PATH=/usr2 && \
for f in /usr2/include/*; do rm -rf "/usr/include/$(basename ${f})"; done && \
cp -a /usr2/include /usr

COPY . /go/src/github.com/containerd/btrfs
WORKDIR /go/src/github.com/containerd/btrfs
RUN make binaries
27 changes: 23 additions & 4 deletions helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@
package btrfs

/*
#include <stddef.h>
#include <btrfs/ioctl.h>
#include <btrfs/ctree.h>
#include "btrfs.h"
*/
import "C"

import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"os"
"strings"
"unsafe"

"golang.org/x/sys/cpu"
)

func subvolID(fd uintptr) (uint64, error) {
Expand All @@ -48,7 +49,7 @@ var (
zeros = zeroArray[:]
)

func uuidString(uuid *[C.BTRFS_UUID_SIZE]C.u8) string {
func uuidString(uuid *[C.BTRFS_UUID_SIZE]C.__u8) string {
b := (*[maxByteSliceSize]byte)(unsafe.Pointer(uuid))[:C.BTRFS_UUID_SIZE]

if bytes.Equal(b, zeros) {
Expand All @@ -58,6 +59,24 @@ func uuidString(uuid *[C.BTRFS_UUID_SIZE]C.u8) string {
return fmt.Sprintf("%x-%x-%x-%x-%x", b[:4], b[4:4+2], b[6:6+2], b[8:8+2], b[10:16])
}

func le16ToNative(le16 C.__le16) uint16 {
if cpu.IsBigEndian {
b := make([]byte, 2)
binary.LittleEndian.PutUint16(b, uint16(le16))
return binary.BigEndian.Uint16(b)
}
return uint16(le16)
}

func le64ToNative(le64 C.__le64) uint64 {
if cpu.IsBigEndian {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(le64))
return binary.BigEndian.Uint64(b)
}
return uint64(le64)
}

func findMountPoint(path string) (string, error) {
fp, err := os.Open("/proc/self/mounts")
if err != nil {
Expand Down

0 comments on commit f611cf1

Please sign in to comment.