mirror of
https://github.com/versity/scoutfs-go.git
synced 2026-01-03 10:35:15 +00:00
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:
@@ -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
|
||||
|
||||
41
examples/getparents/main.go
Normal file
41
examples/getparents/main.go
Normal 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)
|
||||
}
|
||||
129
scoutfs.go
129
scoutfs.go
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user