Merge pull request #9 from versity/ben/xattr_index

add xattr index query interfaces
This commit is contained in:
Ben McClelland
2024-06-14 15:47:17 -07:00
committed by GitHub
4 changed files with 179 additions and 2 deletions

View File

@@ -93,6 +93,7 @@ const IOCDELQUOTARULE = C.SCOUTFS_IOC_DEL_QUOTA_RULE
const IOCADDQUOTARULE = C.SCOUTFS_IOC_ADD_QUOTA_RULE
const IOCGETPROJECTID = C.SCOUTFS_IOC_GET_PROJECT_ID
const IOCSETPROJECTID = C.SCOUTFS_IOC_SET_PROJECT_ID
const IOCREADXATTRINDEX = C.SCOUTFS_IOC_READ_XATTR_INDEX
const QUERYINODESMETASEQ = C.SCOUTFS_IOC_WALK_INODES_META_SEQ
const QUERYINODESDATASEQ = C.SCOUTFS_IOC_WALK_INODES_DATA_SEQ

55
examples/xattridx/main.go Normal file
View File

@@ -0,0 +1,55 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/versity/scoutfs-go"
)
func main() {
// flags mount path name
mountPath := flag.String("mount", "", "mount path name")
// flags index type uint64
indexType := flag.Uint64("type", 0, "index type")
// flags index start uint64
indexStart := flag.Uint64("start", 0, "index start")
// flags index end uint64
indexEnd := flag.Uint64("end", 0, "index end")
// flags show filenames
resolveNames := flag.Bool("resolve", false, "show filenames")
flag.Parse()
f, err := os.Open(*mountPath)
if err != nil {
log.Fatalf("Error opening mount: %s", err)
}
defer f.Close()
idx := scoutfs.NewIndexSearch(f, *indexType, *indexStart, *indexEnd)
for {
ents, err := idx.Next()
if err != nil {
log.Fatalf("Error reading index: %v", err)
}
if ents == nil {
break
}
for _, e := range ents {
if *resolveNames {
name, err := scoutfs.InoToPath(f, e.Inode)
if err != nil {
log.Fatalf("Error resolving name for %v: %V", e.Inode, err)
continue
}
fmt.Println(name)
continue
}
fmt.Println(e.Inode, "=", e.Value)
}
}
}

View File

@@ -495,7 +495,7 @@ type XattrQuery struct {
// NewXattrQuery creates a new scoutfs Xattr Query
// Specify query xattr key
// and specify optinally batching with WithXBatchSize()
// and specify optionally batching with WithXBatchSize()
// An open file within scoutfs is supplied for ioctls
// (usually just the base mount point directory)
func NewXattrQuery(f *os.File, key string, opts ...XOption) *XattrQuery {
@@ -577,7 +577,9 @@ func (q *XattrQuery) Next() ([]uint64, error) {
}
q.next = e
q.next++
if q.next < math.MaxUint64 {
q.next++
}
return inodes, nil
}
@@ -1660,3 +1662,121 @@ func SetProjectID(f *os.File, projectid uint64) error {
_, err := scoutfsctl(f, IOCSETPROJECTID, unsafe.Pointer(&projectid))
return err
}
type IndexSearch struct {
// file handle for ioctls
f *os.File
// The index search end
end indexEntry
// last returned position
pos indexEntry
// max number of inodes to return per Next() call
batch uint64
// buffer for return results
buf []byte
}
const (
indexXattrBatch = 1024
)
func NewIndexSearch(f *os.File, key, start, end uint64, opts ...IOption) *IndexSearch {
i := &IndexSearch{
f: f,
pos: indexEntry{
A: key,
B: start,
},
end: indexEntry{
A: key,
B: end,
Ino: math.MaxUint64,
},
batch: indexXattrBatch,
}
for _, opt := range opts {
opt(i)
}
i.buf = make([]byte, int(unsafe.Sizeof(indexEntry{}))*indexXattrBatch)
return i
}
// IOption sets various options for NewIndexSearch
type IOption func(*IndexSearch)
// WithIBatchSize sets the max number of inodes to be returned at a time
func WithIBatchSize(size uint64) IOption {
return func(q *IndexSearch) {
q.batch = size
}
}
// WithIStartIno starts query at speficied inode
func WithIStartIno(ino uint64) IOption {
return func(q *IndexSearch) {
q.pos.Ino = ino
}
}
// WithIEndIno stop query at speficied inode
func WithIEndIno(ino uint64) IOption {
return func(q *IndexSearch) {
q.end.Ino = ino
}
}
// IndexEnt is type returned by index query Next() call
type IndexEnt struct {
Inode uint64
Value uint64
}
func (i *IndexSearch) Next() ([]IndexEnt, error) {
query := readXattrIndex{
First: i.pos,
Last: i.end,
Ptr: uint64(uintptr(unsafe.Pointer(&i.buf[0]))),
Nr: indexXattrBatch,
}
n, err := scoutfsctl(i.f, IOCREADXATTRINDEX, unsafe.Pointer(&query))
if err != nil {
return nil, err
}
if n == 0 {
return nil, nil
}
rbuf := bytes.NewReader(i.buf)
inodes := make([]IndexEnt, n)
var e indexEntry
for i := 0; i < n; i++ {
err := binary.Read(rbuf, binary.LittleEndian, &e)
if err != nil {
return nil, err
}
inodes[i].Inode = e.Ino
inodes[i].Value = e.B
}
i.pos = e.increment()
return inodes, nil
}
// increment returns the next seq entry position
func (i indexEntry) increment() indexEntry {
i.Ino++
if i.Ino == 0 {
i.B++
if i.B == 0 {
i.A++
}
}
return i
}

View File

@@ -23,6 +23,7 @@ const IOCDELQUOTARULE = 0x4030e816
const IOCADDQUOTARULE = 0x4030e815
const IOCGETPROJECTID = 0x8008e812
const IOCSETPROJECTID = 0x4008e813
const IOCREADXATTRINDEX = 0x8048e817
const QUERYINODESMETASEQ = 0x0
const QUERYINODESDATASEQ = 0x1