Commit f0c88414 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Use preallocated buffer for ReadDir.

parent 7ea8b832
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
) )
var _ = log.Print var _ = log.Print
var eightPadding [8]byte
// DirEntry is a type for PathFileSystem and NodeFileSystem to return // DirEntry is a type for PathFileSystem and NodeFileSystem to return
// directory contents in. // directory contents in.
...@@ -20,13 +21,17 @@ type DirEntry struct { ...@@ -20,13 +21,17 @@ type DirEntry struct {
} }
type DirEntryList struct { type DirEntryList struct {
buf bytes.Buffer buf *bytes.Buffer
offset uint64 offset uint64
maxSize int maxSize int
} }
func NewDirEntryList(max int, off uint64) *DirEntryList { func NewDirEntryList(data []byte, off uint64) *DirEntryList {
return &DirEntryList{maxSize: max, offset: off} return &DirEntryList{
buf: bytes.NewBuffer(data[:0]),
maxSize: len(data),
offset: off,
}
} }
func (l *DirEntryList) AddString(name string, inode uint64, mode uint32) bool { func (l *DirEntryList) AddString(name string, inode uint64, mode uint32) bool {
...@@ -38,31 +43,35 @@ func (l *DirEntryList) AddDirEntry(e DirEntry) bool { ...@@ -38,31 +43,35 @@ func (l *DirEntryList) AddDirEntry(e DirEntry) bool {
} }
func (l *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool { func (l *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool {
lastLen := l.buf.Len()
l.offset++
dirent := raw.Dirent{ dirent := raw.Dirent{
Off: l.offset, Off: l.offset+1,
Ino: inode, Ino: inode,
NameLen: uint32(len(name)), NameLen: uint32(len(name)),
Typ: ModeToType(mode), Typ: ModeToType(mode),
} }
padding := 8 - len(name)&7
if padding == 8 {
padding = 0
}
delta := padding + int(unsafe.Sizeof(raw.Dirent{})) + len(name)
newLen := delta + l.buf.Len()
if newLen > l.maxSize {
return false
}
_, err := l.buf.Write(asSlice(unsafe.Pointer(&dirent), unsafe.Sizeof(raw.Dirent{}))) _, err := l.buf.Write(asSlice(unsafe.Pointer(&dirent), unsafe.Sizeof(raw.Dirent{})))
if err != nil { if err != nil {
panic("Serialization of Dirent failed") panic("Serialization of Dirent failed")
} }
l.buf.Write(name) l.buf.Write(name)
if padding > 0 {
padding := 8 - len(name)&7 l.buf.Write(eightPadding[:padding])
if padding < 8 {
l.buf.Write(make([]byte, padding))
} }
l.offset = dirent.Off
if l.buf.Len() > l.maxSize { if l.buf.Len() != newLen {
l.buf.Truncate(lastLen) log.Panicf("newLen mismatch %d %d", l.buf.Len(), newLen)
l.offset--
return false
} }
return true return true
} }
......
...@@ -119,12 +119,11 @@ func doCreate(state *MountState, req *request) { ...@@ -119,12 +119,11 @@ func doCreate(state *MountState, req *request) {
func doReadDir(state *MountState, req *request) { func doReadDir(state *MountState, req *request) {
in := (*ReadIn)(req.inData) in := (*ReadIn)(req.inData)
entries := NewDirEntryList(int(in.Size), uint64(in.Offset)) buf := state.buffers.AllocBuffer(in.Size)
entries := NewDirEntryList(buf, uint64(in.Offset))
code := state.fileSystem.ReadDir(entries, req.inHeader, in) code := state.fileSystem.ReadDir(entries, req.inHeader, in)
if entries != nil {
req.flatData = entries.Bytes() req.flatData = entries.Bytes()
}
req.status = code req.status = code
} }
......
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