Commit 29cc8f3c authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

fuse: drop outData from request structure

This saves a couple of bytes, and avoids a copy on serializing the
response header.

Add and document a hack for _OP_GETXATTR in serializeHeader.
parent 430cccea
......@@ -90,7 +90,8 @@ func doInit(server *Server, req *request) {
}
server.reqMu.Unlock()
out := &InitOut{
out := (*InitOut)(req.outData())
*out = InitOut{
Major: _FUSE_KERNEL_VERSION,
Minor: _OUR_MINOR_VERSION,
MaxReadAhead: input.MaxReadAhead,
......@@ -99,6 +100,7 @@ func doInit(server *Server, req *request) {
CongestionThreshold: uint16(server.opts.MaxBackground * 3 / 4),
MaxBackground: uint16(server.opts.MaxBackground),
}
if server.opts.MaxReadAhead != 0 && uint32(server.opts.MaxReadAhead) < out.MaxReadAhead {
out.MaxReadAhead = uint32(server.opts.MaxReadAhead)
}
......@@ -114,12 +116,11 @@ func doInit(server *Server, req *request) {
req.handler = &tweaked
}
req.outData = unsafe.Pointer(out)
req.status = OK
}
func doOpen(server *Server, req *request) {
out := (*OpenOut)(req.outData)
out := (*OpenOut)(req.outData())
status := server.fileSystem.Open((*OpenIn)(req.inData), out)
req.status = status
if status != OK {
......@@ -128,7 +129,7 @@ func doOpen(server *Server, req *request) {
}
func doCreate(server *Server, req *request) {
out := (*CreateOut)(req.outData)
out := (*CreateOut)(req.outData())
status := server.fileSystem.Create((*CreateIn)(req.inData), req.filenames[0], out)
req.status = status
}
......@@ -154,19 +155,19 @@ func doReadDirPlus(server *Server, req *request) {
}
func doOpenDir(server *Server, req *request) {
out := (*OpenOut)(req.outData)
out := (*OpenOut)(req.outData())
status := server.fileSystem.OpenDir((*OpenIn)(req.inData), out)
req.status = status
}
func doSetattr(server *Server, req *request) {
out := (*AttrOut)(req.outData)
out := (*AttrOut)(req.outData())
req.status = server.fileSystem.SetAttr((*SetAttrIn)(req.inData), out)
}
func doWrite(server *Server, req *request) {
n, status := server.fileSystem.Write((*WriteIn)(req.inData), req.arg)
o := (*WriteOut)(req.outData)
o := (*WriteOut)(req.outData())
o.Size = n
req.status = status
}
......@@ -193,7 +194,7 @@ func doGetXAttr(server *Server, req *request) {
input := (*GetXAttrIn)(req.inData)
if input.Size == 0 {
out := (*GetXAttrOut)(req.outData)
out := (*GetXAttrOut)(req.outData())
switch req.inHeader.Opcode {
case _OP_GETXATTR:
// TODO(hanwen): double check this. For getxattr, input.Size
......@@ -214,8 +215,6 @@ func doGetXAttr(server *Server, req *request) {
return
}
}
req.outData = nil
var data []byte
switch req.inHeader.Opcode {
case _OP_GETXATTR:
......@@ -239,7 +238,7 @@ func doGetXAttr(server *Server, req *request) {
}
func doGetAttr(server *Server, req *request) {
out := (*AttrOut)(req.outData)
out := (*AttrOut)(req.outData())
s := server.fileSystem.GetAttr((*GetAttrIn)(req.inData), out)
req.status = s
}
......@@ -284,20 +283,19 @@ func doReadlink(server *Server, req *request) {
}
func doLookup(server *Server, req *request) {
out := (*EntryOut)(req.outData)
out := (*EntryOut)(req.outData())
s := server.fileSystem.Lookup(req.inHeader, req.filenames[0], out)
req.status = s
req.outData = unsafe.Pointer(out)
}
func doMknod(server *Server, req *request) {
out := (*EntryOut)(req.outData)
out := (*EntryOut)(req.outData())
req.status = server.fileSystem.Mknod((*MknodIn)(req.inData), req.filenames[0], out)
}
func doMkdir(server *Server, req *request) {
out := (*EntryOut)(req.outData)
out := (*EntryOut)(req.outData())
req.status = server.fileSystem.Mkdir((*MkdirIn)(req.inData), req.filenames[0], out)
}
......@@ -310,7 +308,7 @@ func doRmdir(server *Server, req *request) {
}
func doLink(server *Server, req *request) {
out := (*EntryOut)(req.outData)
out := (*EntryOut)(req.outData())
req.status = server.fileSystem.Link((*LinkIn)(req.inData), req.filenames[0], out)
}
......@@ -361,7 +359,7 @@ func doAccess(server *Server, req *request) {
}
func doSymlink(server *Server, req *request) {
out := (*EntryOut)(req.outData)
out := (*EntryOut)(req.outData())
req.status = server.fileSystem.Symlink(req.inHeader, req.filenames[1], req.filenames[0], out)
}
......@@ -370,7 +368,7 @@ func doRename(server *Server, req *request) {
}
func doStatFs(server *Server, req *request) {
out := (*StatfsOut)(req.outData)
out := (*StatfsOut)(req.outData())
req.status = server.fileSystem.StatFs(req.inHeader, out)
if req.status == ENOSYS && runtime.GOOS == "darwin" {
// OSX FUSE requires Statfs to be implemented for the
......
......@@ -11,7 +11,7 @@ const pollHackInode = ^uint64(0)
func doPollHackLookup(ms *Server, req *request) {
switch req.inHeader.Opcode {
case _OP_CREATE:
out := (*CreateOut)(req.outData)
out := (*CreateOut)(req.outData())
out.EntryOut = EntryOut{
NodeId: pollHackInode,
Attr: Attr{
......@@ -25,7 +25,7 @@ func doPollHackLookup(ms *Server, req *request) {
}
req.status = OK
case _OP_LOOKUP:
out := (*EntryOut)(req.outData)
out := (*EntryOut)(req.outData())
*out = EntryOut{}
req.status = ENOENT
default:
......
......@@ -27,7 +27,6 @@ type request struct {
filenames []string // filename arguments
// Unstructured data, a pointer to the relevant XxxxOut struct.
outData unsafe.Pointer
status Status
flatData []byte
fdData *readResultFd
......@@ -65,7 +64,6 @@ func (r *request) clear() {
r.inData = nil
r.arg = nil
r.filenames = nil
r.outData = nil
r.status = OK
r.flatData = nil
r.fdData = nil
......@@ -96,8 +94,8 @@ func (r *request) InputDebug() string {
func (r *request) OutputDebug() string {
var dataStr string
if r.handler.DecodeOut != nil && r.outData != nil {
dataStr = Print(r.handler.DecodeOut(r.outData))
if r.handler.DecodeOut != nil && r.handler.OutputSize > 0 {
dataStr = Print(r.handler.DecodeOut(r.outData()))
}
max := 1024
......@@ -186,26 +184,33 @@ func (r *request) parse() {
copy(r.outBuf[:r.handler.OutputSize+sizeOfOutHeader],
zeroOutBuf[:r.handler.OutputSize+sizeOfOutHeader])
r.outData = unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
}
func (r *request) serializeHeader(dataSize int) (header []byte) {
func (r *request) outData() unsafe.Pointer {
return unsafe.Pointer(&r.outBuf[sizeOfOutHeader])
}
// serializeHeader serializes the response header. The header points
// to an internal buffer of the receiver.
func (r *request) serializeHeader(flatDataSize int) (header []byte) {
dataLength := r.handler.OutputSize
if r.outData == nil || r.status > OK {
if r.status > OK {
dataLength = 0
}
// GETXATTR is two opcodes in one: get xattr size (return
// structured GetXAttrOut, no flat data) and get xattr data
// (return no structured data, but only flat data)
if r.inHeader.Opcode == _OP_GETXATTR && flatDataSize > 0 {
dataLength = 0
}
sizeOfOutHeader := unsafe.Sizeof(OutHeader{})
header = r.outBuf[:sizeOfOutHeader+dataLength]
o := (*OutHeader)(unsafe.Pointer(&header[0]))
o.Unique = r.inHeader.Unique
o.Status = int32(-r.status)
o.Length = uint32(
int(sizeOfOutHeader) + int(dataLength) + dataSize)
var asSlice []byte
toSlice(&asSlice, r.outData, dataLength)
copy(header[sizeOfOutHeader:], asSlice)
int(sizeOfOutHeader) + int(dataLength) + flatDataSize)
return header
}
......
......@@ -14,7 +14,6 @@ import (
"sync"
"syscall"
"time"
"unsafe"
)
const (
......@@ -452,11 +451,6 @@ func (ms *Server) InodeNotify(node uint64, off int64, length int64) Status {
return ENOSYS
}
entry := &NotifyInvalInodeOut{
Ino: node,
Off: off,
Length: length,
}
req := request{
inHeader: &InHeader{
Opcode: _OP_NOTIFY_INODE,
......@@ -464,7 +458,11 @@ func (ms *Server) InodeNotify(node uint64, off int64, length int64) Status {
handler: operationHandlers[_OP_NOTIFY_INODE],
status: NOTIFY_INVAL_INODE,
}
req.outData = unsafe.Pointer(entry)
entry := (*NotifyInvalInodeOut)(req.outData())
entry.Ino = node
entry.Off = off
entry.Length = length
// Protect against concurrent close.
ms.writeMu.Lock()
......@@ -494,18 +492,17 @@ func (ms *Server) DeleteNotify(parent uint64, child uint64, name string) Status
handler: operationHandlers[_OP_NOTIFY_DELETE],
status: NOTIFY_INVAL_DELETE,
}
entry := &NotifyInvalDeleteOut{
Parent: parent,
Child: child,
NameLen: uint32(len(name)),
}
entry := (*NotifyInvalDeleteOut)(req.outData())
entry.Parent = parent
entry.Child = child
entry.NameLen = uint32(len(name))
// Many versions of FUSE generate stacktraces if the
// terminating null byte is missing.
nameBytes := make([]byte, len(name)+1)
copy(nameBytes, name)
nameBytes[len(nameBytes)-1] = '\000'
req.outData = unsafe.Pointer(entry)
req.flatData = nameBytes
// Protect against concurrent close.
......@@ -533,17 +530,15 @@ func (ms *Server) EntryNotify(parent uint64, name string) Status {
handler: operationHandlers[_OP_NOTIFY_ENTRY],
status: NOTIFY_INVAL_ENTRY,
}
entry := &NotifyInvalEntryOut{
Parent: parent,
NameLen: uint32(len(name)),
}
entry := (*NotifyInvalEntryOut)(req.outData())
entry.Parent = parent
entry.NameLen = uint32(len(name))
// Many versions of FUSE generate stacktraces if the
// terminating null byte is missing.
nameBytes := make([]byte, len(name)+1)
copy(nameBytes, name)
nameBytes[len(nameBytes)-1] = '\000'
req.outData = unsafe.Pointer(entry)
req.flatData = nameBytes
// Protect against concurrent close.
......
......@@ -60,7 +60,7 @@ func TestDefaultXAttr(t *testing.T) {
sz, err := syscall.Getxattr(filepath.Join(dir, "child"), "attr", data[:])
if err != nil {
t.Fatalf("Getxattr: %v", err)
} else if val := string(data[:sz]); val != "value" {
t.Fatalf("got %v, want 'value'", val)
} else if got, want := string(data[:sz]), "value"; got != want {
t.Fatalf("got %q, want %q", got, want)
}
}
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