Merge pull request #2 from versity/ben/get-referring-entries

add support for get-referring-entries
This commit is contained in:
Ben McClelland
2023-08-28 14:35:21 -07:00
committed by GitHub
4 changed files with 191 additions and 8 deletions

View File

@@ -53,6 +53,8 @@ package scoutfs
// typedef struct scoutfs_ioctl_alloc_detail scoutfs_ioctl_alloc_detail_t;
// typedef struct scoutfs_ioctl_read_xattr_totals scoutfs_ioctl_read_xattr_totals_t;
// typedef struct scoutfs_ioctl_xattr_total scoutfs_ioctl_xattr_total_t;
// typedef struct scoutfs_ioctl_get_referring_entries scoutfs_ioctl_get_referring_entries_t;
// typedef struct scoutfs_ioctl_dirent scoutfs_ioctl_dirent_t;
//
// // Go doesnt handle bitfields in structs, so we need to override the scoutfs
// // struct definition here
@@ -81,6 +83,7 @@ const IOCDATAWAITERR = C.SCOUTFS_IOC_DATA_WAIT_ERR
const IOCALLOCDETAIL = C.SCOUTFS_IOC_ALLOC_DETAIL
const IOCMOVEBLOCKS = C.SCOUTFS_IOC_MOVE_BLOCKS
const IOCREADXATTRTOTALS = C.SCOUTFS_IOC_READ_XATTR_TOTALS
const IOCGETREFERRINGENTRIES = C.SCOUTFS_IOC_GET_REFERRING_ENTRIES
const QUERYINODESMETASEQ = C.SCOUTFS_IOC_WALK_INODES_META_SEQ
const QUERYINODESDATASEQ = C.SCOUTFS_IOC_WALK_INODES_DATA_SEQ
@@ -93,6 +96,8 @@ const SEARCHXATTRSOFLAGEND = C.SCOUTFS_SEARCH_XATTRS_OFLAG_END
const MBSTAGEFLG = C.SCOUTFS_IOC_MB_STAGE
const DIRENTFLAGLAST = C.SCOUTFS_IOCTL_DIRENT_FLAG_LAST
type InodesEntry C.scoutfs_ioctl_walk_inodes_entry_t
type queryInodes C.scoutfs_ioctl_walk_inodes_t
type inoPath C.scoutfs_ioctl_ino_path_t
@@ -111,6 +116,8 @@ type allocDetailEntry C.scoutfs_ioctl_alloc_detail_entry_t
type moveBlocks C.scoutfs_ioctl_move_blocks_t
type readXattrTotals C.scoutfs_ioctl_read_xattr_totals_t
type xattrTotal C.scoutfs_ioctl_xattr_total_t
type getReferringEntries C.scoutfs_ioctl_get_referring_entries_t
type scoutfsDirent C.scoutfs_ioctl_dirent_t
const sizeofstatfsMore = C.sizeof_scoutfs_ioctl_statfs_more_t
const sizeofxattrTotal = C.sizeof_scoutfs_ioctl_xattr_total_t

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2018 Versity Software, Inc.
//
// Use of this source code is governed by a BSD-3-Clause license
// that can be found in the LICENSE file in the root of the source
// tree.
package main
import (
"fmt"
"log"
"os"
"strconv"
scoutfs "github.com/versity/scoutfs-go"
)
func main() {
if len(os.Args) != 3 || os.Args[1] == "-h" {
fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "<scoutfs mount point> <inode>")
os.Exit(1)
}
f, err := os.Open(os.Args[1])
if err != nil {
log.Fatalln("error open mount:", err)
}
defer f.Close()
u, err := strconv.ParseUint(os.Args[2], 10, 64)
if err != nil {
log.Fatalln("error parsing inode:", err)
}
s, err := scoutfs.GetParents(f, u, nil)
if err != nil {
log.Fatalln("error get parents:", err)
}
fmt.Println(s)
}

View File

@@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"math"
@@ -23,13 +24,14 @@ import (
)
const (
max64 = 0xffffffffffffffff
max32 = 0xffffffff
pathmax = 4096
sysscoutfs = "/sys/fs/scoutfs/"
statusfile = "quorum/status"
listattrBufsize = 256 * 1024
scoutfsBS = 4096
max64 = 0xffffffffffffffff
max32 = 0xffffffff
pathmax = 4096
sysscoutfs = "/sys/fs/scoutfs/"
statusfile = "quorum/status"
listattrBufsize = 256 * 1024
getparentBufsize = 4096 * 1024
scoutfsBS = 4096
//leaderfile = "quorum/is_leader"
)
@@ -1019,3 +1021,116 @@ func (t *TotalsGroup) Reset() {
t.pos[1] = t.id2
t.pos[2] = 0
}
// Parent contains inode of parent and what the child inode is named within
// this parent
type Parent struct {
Ino uint64 // Parent inode
Pos uint64 // Entry directory position in parent
Type uint8 // Entry inode type matching DT_ enum values in readdir(3)
Ent string // Entry name as known by parent
}
// GetParents returns all parents for the given inode
// An open file within scoutfs is supplied for ioctls
// (usually just the base mount point directory)
// If passed in buffer is nil, call will allocate its own buffer.
func GetParents(dirfd *os.File, ino uint64, b []byte) ([]Parent, error) {
if b == nil {
b = make([]byte, getparentBufsize)
}
gre := getReferringEntries{}
gre.Entries_bytes = uint64(len(b))
gre.Entries_ptr = uint64(uintptr(unsafe.Pointer(&b[0])))
gre.Ino = ino
var parents []Parent
for {
n, err := scoutfsctl(dirfd, IOCGETREFERRINGENTRIES, unsafe.Pointer(&gre))
if err != nil {
return nil, err
}
if n == 0 {
break
}
ents, isLast, err := parseDents(b)
if err != nil {
return nil, err
}
parents = append(parents, ents...)
if isLast {
break
}
}
return parents, nil
}
func parseDents(b []byte) ([]Parent, bool, error) {
r := bytes.NewReader(b)
var parents []Parent
var isLast bool
for {
var err error
var parent Parent
parent, isLast, err = parseDent(r)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return nil, false, err
}
parents = append(parents, parent)
if isLast {
break
}
if r.Len() == 0 {
break
}
}
return parents, isLast, nil
}
type dirent struct {
Dir_ino uint64
Dir_pos uint64
Ino uint64
Entry_bytes uint16
Flags uint8
D_type uint8
Name_len uint8
}
func parseDent(r *bytes.Reader) (Parent, bool, error) {
var dent dirent
err := binary.Read(r, binary.LittleEndian, &dent)
if err != nil {
return Parent{}, false, err
}
b := new(strings.Builder)
_, err = io.CopyN(b, r, int64(dent.Name_len))
if err != nil {
return Parent{}, false, err
}
pad := int(dent.Entry_bytes) - int(unsafe.Sizeof(dent)) + int(dent.Name_len)
for i := 0; i < pad; i++ {
_, err = r.ReadByte()
if err != nil {
return Parent{}, false, err
}
}
return Parent{
Ino: dent.Dir_ino,
Pos: dent.Dir_pos,
Type: dent.D_type,
Ent: b.String(),
}, dent.Flags&DIRENTFLAGLAST == DIRENTFLAGLAST, nil
}

View File

@@ -1,5 +1,5 @@
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs /workspace/go/src/github.com/versity/scoutfs-go/c_defs_linux.go
// cgo -godefs c_defs_linux.go
package scoutfs
@@ -17,6 +17,7 @@ const IOCDATAWAITERR = 0x4030e80b
const IOCALLOCDETAIL = 0x4010e80c
const IOCMOVEBLOCKS = 0x4030e80d
const IOCREADXATTRTOTALS = 0x4028e80f
const IOCGETREFERRINGENTRIES = 0x4028e811
const QUERYINODESMETASEQ = 0x0
const QUERYINODESDATASEQ = 0x1
@@ -29,6 +30,8 @@ const SEARCHXATTRSOFLAGEND = 0x1
const MBSTAGEFLG = 0x1
const DIRENTFLAGLAST = 0x1
type InodesEntry struct {
Major uint64
Ino uint64
@@ -157,6 +160,23 @@ type xattrTotal struct {
Total uint64
Count uint64
}
type getReferringEntries struct {
Ino uint64
Dir_ino uint64
Dir_pos uint64
Entries_ptr uint64
Entries_bytes uint64
}
type scoutfsDirent struct {
Dir_ino uint64
Dir_pos uint64
Ino uint64
Entry_bytes uint16
Flags uint8
D_type uint8
Name_len uint8
Name [3]uint8
}
const sizeofstatfsMore = 0x30
const sizeofxattrTotal = 0x28