Commit 588c83d1 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

fs: redeclare syscall.Dirent locally

syscall.Dirent declares a 256-byte "name" field. In reality, this
field is only as long as necessary to transmit the name, so more
entries can be packed in a page.

When casting the result to syscall.Dirent, the result might run over
the end of the byte buffer, which the race detector doesn't like.

Address this by using our own flavor of syscall.Dirent. All linux
flavors use the same structure layout, except for the amount of
padding at the end.

Change-Id: I618f7ef9e167894e1ab25b2113dcd20d7b76ceb4
parent be8e5f4a
...@@ -55,12 +55,26 @@ func (ds *loopbackDirStream) HasNext() bool { ...@@ -55,12 +55,26 @@ func (ds *loopbackDirStream) HasNext() bool {
return len(ds.todo) > 0 return len(ds.todo) > 0
} }
// Like syscall.Dirent, but without the [256]byte name.
type dirent struct {
Ino uint64
Off int64
Reclen uint16
Type uint8
Name [1]uint8 // align to 4 bytes for 32 bits.
}
func (ds *loopbackDirStream) Next() (fuse.DirEntry, syscall.Errno) { func (ds *loopbackDirStream) Next() (fuse.DirEntry, syscall.Errno) {
ds.mu.Lock() ds.mu.Lock()
defer ds.mu.Unlock() defer ds.mu.Unlock()
de := (*syscall.Dirent)(unsafe.Pointer(&ds.todo[0]))
nameBytes := ds.todo[unsafe.Offsetof(syscall.Dirent{}.Name):de.Reclen] // We can't use syscall.Dirent here, because it declares a
// [256]byte name, which may run beyond the end of ds.todo.
// when that happens in the race detector, it causes a panic
// "converted pointer straddles multiple allocations"
de := (*dirent)(unsafe.Pointer(&ds.todo[0]))
nameBytes := ds.todo[unsafe.Offsetof(dirent{}.Name):de.Reclen]
ds.todo = ds.todo[de.Reclen:] ds.todo = ds.todo[de.Reclen:]
// After the loop, l contains the index of the first '\0'. // After the loop, l contains the index of the first '\0'.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment