add support for get-referring-entries

scoutfs now adds a new ioctl to get the parent id and some extra
info given an inode within the filesystem. This is less expensive
than the full path resolution for an inode, so can speed up cases
when the parent is all thats needed.
This commit is contained in:
Ben McClelland
2023-08-28 13:59:07 -07:00
parent 0474b14343
commit f019a234ab
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