mirror of
https://github.com/versity/scoutfs-go.git
synced 2026-09-04 07:07:17 +00:00
Pin all ioctl buffer addresses
ScoutFS ioctl structures store user buffer addresses as integers, so Go cannot update them if the backing memory moves. Pin every nested buffer before converting its pointer and unpin it after the ioctl completes.
This commit is contained in:
+56
-26
@@ -36,6 +36,12 @@ const (
|
||||
//leaderfile = "quorum/is_leader"
|
||||
)
|
||||
|
||||
// pinnedAddress pins a pointer before hiding it from the runtime in an ioctl field.
|
||||
func pinnedAddress[T any](pinner *runtime.Pinner, ptr *T) uint64 {
|
||||
pinner.Pin(ptr)
|
||||
return uint64(uintptr(unsafe.Pointer(ptr)))
|
||||
}
|
||||
|
||||
// Query to keep track of in-process query
|
||||
type Query struct {
|
||||
first InodesEntry
|
||||
@@ -104,15 +110,18 @@ func WithBatchSize(size uint32) Option {
|
||||
|
||||
// Next gets the next batch of inodes
|
||||
func (q *Query) Next() ([]InodesEntry, error) {
|
||||
var pin runtime.Pinner
|
||||
|
||||
query := queryInodes{
|
||||
First: q.first,
|
||||
Last: q.last,
|
||||
Entries_ptr: uint64(uintptr(unsafe.Pointer(&q.buf[0]))),
|
||||
Entries_ptr: pinnedAddress(&pin, &q.buf[0]),
|
||||
Nr_entries: q.batch,
|
||||
Index: q.index,
|
||||
}
|
||||
|
||||
n, err := scoutfsctl(q.fsfd, IOCQUERYINODES, unsafe.Pointer(&query))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -231,13 +240,11 @@ type inoPathResult struct {
|
||||
// (usually just the base mount point directory)
|
||||
func InoToPath(dirfd *os.File, ino uint64) (string, error) {
|
||||
var res inoPathResult
|
||||
// Result_ptr is an integer, so keep its target at a stable address.
|
||||
var pin runtime.Pinner
|
||||
pin.Pin(&res)
|
||||
defer pin.Unpin()
|
||||
ip := inoPath{
|
||||
Ino: ino,
|
||||
Result_ptr: uint64(uintptr(unsafe.Pointer(&res))),
|
||||
Result_ptr: pinnedAddress(&pin, &res),
|
||||
Result_bytes: uint16(unsafe.Sizeof(res)),
|
||||
}
|
||||
|
||||
@@ -256,13 +263,11 @@ func InoToPath(dirfd *os.File, ino uint64) (string, error) {
|
||||
// (usually just the base mount point directory)
|
||||
func InoToPaths(dirfd *os.File, ino uint64) ([]string, error) {
|
||||
var res inoPathResult
|
||||
// Result_ptr is an integer, so keep its target at a stable address.
|
||||
var pin runtime.Pinner
|
||||
pin.Pin(&res)
|
||||
defer pin.Unpin()
|
||||
ip := inoPath{
|
||||
Ino: ino,
|
||||
Result_ptr: uint64(uintptr(unsafe.Pointer(&res))),
|
||||
Result_ptr: pinnedAddress(&pin, &res),
|
||||
Result_bytes: uint16(unsafe.Sizeof(res)),
|
||||
}
|
||||
|
||||
@@ -380,9 +385,12 @@ func StageFile(path string, version, offset uint64, b []byte) (int, error) {
|
||||
|
||||
// FStageFile rehydrates offline file
|
||||
func FStageFile(f *os.File, version, offset uint64, b []byte) (int, error) {
|
||||
var pin runtime.Pinner
|
||||
defer pin.Unpin()
|
||||
|
||||
r := iocStage{
|
||||
Data_version: version,
|
||||
Buf_ptr: uint64(uintptr(unsafe.Pointer(&b[0]))),
|
||||
Buf_ptr: pinnedAddress(&pin, &b[0]),
|
||||
Offset: offset,
|
||||
Length: int32(len(b)),
|
||||
}
|
||||
@@ -430,14 +438,17 @@ func WithWaitersCount(size uint16) WOption {
|
||||
|
||||
// Next gets the next batch of data waiters, returns nil, nil if no waiters
|
||||
func (w *Waiters) Next() ([]DataWaitingEntry, error) {
|
||||
var pin runtime.Pinner
|
||||
|
||||
dataWaiting := dataWaiting{
|
||||
After_ino: w.ino,
|
||||
After_iblock: w.iblock,
|
||||
Ents_ptr: uint64(uintptr(unsafe.Pointer(&w.buf[0]))),
|
||||
Ents_ptr: pinnedAddress(&pin, &w.buf[0]),
|
||||
Ents_nr: w.batch,
|
||||
}
|
||||
|
||||
n, err := scoutfsctl(w.fsfd, IOCDATAWAITING, unsafe.Pointer(&dataWaiting))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -545,21 +556,24 @@ func WithXStartIno(ino uint64) XOption {
|
||||
|
||||
// Next gets the next batch of inodes
|
||||
func (q *XattrQuery) Next() ([]uint64, error) {
|
||||
name := []byte(q.key)
|
||||
query := searchXattrs{
|
||||
Next_ino: q.next,
|
||||
Last_ino: max64,
|
||||
Name_ptr: uint64(uintptr(unsafe.Pointer(&name[0]))),
|
||||
Inodes_ptr: uint64(uintptr(unsafe.Pointer(&q.buf[0]))),
|
||||
Name_bytes: uint16(len(name)),
|
||||
Nr_inodes: q.batch,
|
||||
}
|
||||
|
||||
if q.done {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
name := []byte(q.key)
|
||||
var pin runtime.Pinner
|
||||
|
||||
query := searchXattrs{
|
||||
Next_ino: q.next,
|
||||
Last_ino: max64,
|
||||
Name_ptr: pinnedAddress(&pin, &name[0]),
|
||||
Inodes_ptr: pinnedAddress(&pin, &q.buf[0]),
|
||||
Name_bytes: uint16(len(name)),
|
||||
Nr_inodes: q.batch,
|
||||
}
|
||||
|
||||
n, err := scoutfsctl(q.fsfd, IOCSEARCHXATTRS, unsafe.Pointer(&query))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -615,10 +629,13 @@ func NewListXattrHidden(f *os.File, b []byte) *ListXattrHidden {
|
||||
|
||||
// Next gets next set of results, complete when string slice is nil
|
||||
func (l *ListXattrHidden) Next() ([]string, error) {
|
||||
var pin runtime.Pinner
|
||||
|
||||
l.lxr.Buf_bytes = uint32(len(l.buf))
|
||||
l.lxr.Buf_ptr = uint64(uintptr(unsafe.Pointer(&l.buf[0])))
|
||||
l.lxr.Buf_ptr = pinnedAddress(&pin, &l.buf[0])
|
||||
|
||||
n, err := scoutfsctl(l.f, IOCLISTXATTRHIDDEN, unsafe.Pointer(l.lxr))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -764,12 +781,14 @@ func GetDF(f *os.File) (DiskUsage, error) {
|
||||
nr := dfBatchCount
|
||||
buf := make([]byte, int(unsafe.Sizeof(allocDetailEntry{}))*int(nr))
|
||||
var ret int
|
||||
var pin runtime.Pinner
|
||||
for {
|
||||
ad := allocDetail{
|
||||
Nr: nr,
|
||||
Ptr: uint64(uintptr(unsafe.Pointer(&buf[0]))),
|
||||
Ptr: pinnedAddress(&pin, &buf[0]),
|
||||
}
|
||||
ret, err = scoutfsctl(f, IOCALLOCDETAIL, unsafe.Pointer(&ad))
|
||||
pin.Unpin()
|
||||
if err == syscall.EOVERFLOW {
|
||||
nr = nr * 2
|
||||
buf = make([]byte, int(unsafe.Sizeof(allocDetailEntry{}))*int(nr))
|
||||
@@ -930,10 +949,12 @@ type XattrTotal struct {
|
||||
// ReadXattrTotals returns the XattrTotal for the given id
|
||||
func ReadXattrTotals(f *os.File, id1, id2, id3 uint64) (XattrTotal, error) {
|
||||
totls := make([]xattrTotal, 1)
|
||||
var pin runtime.Pinner
|
||||
defer pin.Unpin()
|
||||
|
||||
query := readXattrTotals{
|
||||
Pos_name: [3]uint64{id1, id2, id3},
|
||||
Totals_ptr: uint64(uintptr(unsafe.Pointer(&totls[0]))),
|
||||
Totals_ptr: pinnedAddress(&pin, &totls[0]),
|
||||
Totals_bytes: sizeofxattrTotal,
|
||||
}
|
||||
|
||||
@@ -985,14 +1006,16 @@ func (t *TotalsGroup) Next() ([]XattrTotal, error) {
|
||||
if t.done {
|
||||
return nil, nil
|
||||
}
|
||||
var pin runtime.Pinner
|
||||
|
||||
query := readXattrTotals{
|
||||
Pos_name: t.pos,
|
||||
Totals_ptr: uint64(uintptr(unsafe.Pointer(&t.totls[0]))),
|
||||
Totals_ptr: pinnedAddress(&pin, &t.totls[0]),
|
||||
Totals_bytes: sizeofxattrTotal * uint64(t.count),
|
||||
}
|
||||
|
||||
n, err := scoutfsctl(t.f, IOCREADXATTRTOTALS, unsafe.Pointer(&query))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1048,9 +1071,11 @@ func GetParents(dirfd *os.File, ino uint64, b []byte) ([]Parent, error) {
|
||||
}
|
||||
|
||||
gre := getReferringEntries{}
|
||||
var pin runtime.Pinner
|
||||
defer pin.Unpin()
|
||||
|
||||
gre.Entries_bytes = uint64(len(b))
|
||||
gre.Entries_ptr = uint64(uintptr(unsafe.Pointer(&b[0])))
|
||||
gre.Entries_ptr = pinnedAddress(&pin, &b[0])
|
||||
gre.Ino = ino
|
||||
|
||||
var parents []Parent
|
||||
@@ -1436,14 +1461,16 @@ func (q *Quotas) Next() ([]QuotaRule, error) {
|
||||
if q.done {
|
||||
return nil, nil
|
||||
}
|
||||
var pin runtime.Pinner
|
||||
|
||||
query := getQuotaRules{
|
||||
Iterator: q.iter,
|
||||
Ptr: uint64(uintptr(unsafe.Pointer(&q.rules[0]))),
|
||||
Ptr: pinnedAddress(&pin, &q.rules[0]),
|
||||
Nr: uint64(q.count),
|
||||
}
|
||||
|
||||
n, err := scoutfsctl(q.f, IOCGETQUOTARULES, unsafe.Pointer(&query))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1767,14 +1794,17 @@ type IndexEnt struct {
|
||||
}
|
||||
|
||||
func (i *IndexSearch) Next() ([]IndexEnt, error) {
|
||||
var pin runtime.Pinner
|
||||
|
||||
query := readXattrIndex{
|
||||
First: i.pos,
|
||||
Last: i.end,
|
||||
Ptr: uint64(uintptr(unsafe.Pointer(&i.buf[0]))),
|
||||
Ptr: pinnedAddress(&pin, &i.buf[0]),
|
||||
Nr: indexXattrBatch,
|
||||
}
|
||||
|
||||
n, err := scoutfsctl(i.f, IOCREADXATTRINDEX, unsafe.Pointer(&query))
|
||||
pin.Unpin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user