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

Use arrays for opcode dispatches.

parent 88b3aa85
// Code that handles the control loop, and en/decoding messages
// to/from the kernel. Dispatches calls into RawFileSystem.
package fuse package fuse
import ( import (
"bytes"
"fmt" "fmt"
"log" "log"
"os" "os"
...@@ -28,8 +30,9 @@ type request struct { ...@@ -28,8 +30,9 @@ type request struct {
inputBuf []byte inputBuf []byte
// These split up inputBuf. // These split up inputBuf.
inHeader *InHeader inHeader *InHeader // generic header
arg []byte inData unsafe.Pointer // per op data
arg []byte // flat data.
// Unstructured data, a pointer to the relevant XxxxOut struct. // Unstructured data, a pointer to the relevant XxxxOut struct.
data unsafe.Pointer data unsafe.Pointer
...@@ -46,6 +49,14 @@ type request struct { ...@@ -46,6 +49,14 @@ type request struct {
preWriteNs int64 preWriteNs int64
} }
func (me *request) filename() string {
return strings.TrimRight(string(me.arg), "\x00")
}
func (me *request) filenames(count int) []string {
return strings.Split(string(me.arg), "\x00", count)
}
type MountState struct { type MountState struct {
// Empty if unmounted. // Empty if unmounted.
mountPoint string mountPoint string
...@@ -252,6 +263,10 @@ func (me *MountState) handle(req *request) { ...@@ -252,6 +263,10 @@ func (me *MountState) handle(req *request) {
req.inHeader = (*InHeader)(unsafe.Pointer(&req.inputBuf[0])) req.inHeader = (*InHeader)(unsafe.Pointer(&req.inputBuf[0]))
req.arg = req.inputBuf[inHSize:] req.arg = req.inputBuf[inHSize:]
me.dispatch(req) me.dispatch(req)
// If we try to write OK, nil, we will get
// error: writer: Writev [[16 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0]]
// failed, err: writev: no such file or directory
if req.inHeader.Opcode != FUSE_FORGET { if req.inHeader.Opcode != FUSE_FORGET {
serialize(req, me.Debug) serialize(req, me.Debug)
req.preWriteNs = time.Nanoseconds() req.preWriteNs = time.Nanoseconds()
...@@ -260,165 +275,40 @@ func (me *MountState) handle(req *request) { ...@@ -260,165 +275,40 @@ func (me *MountState) handle(req *request) {
} }
func (me *MountState) dispatch(req *request) { func (me *MountState) dispatch(req *request) {
h := req.inHeader argSize, ok := inputSize(req.inHeader.Opcode)
argumentSize, ok := inputSizeMap[int(h.Opcode)]
if !ok { if !ok {
log.Println("Unknown opcode %d (input)", h.Opcode) log.Println("Unknown opcode %d (input)", req.inHeader.Opcode)
req.status = ENOSYS req.status = ENOSYS
return return
} }
if len(req.arg) < argumentSize {
log.Println("Short read for %v: %v", h.Opcode, req.arg) if len(req.arg) < argSize {
log.Println("Short read for %v: %v", req.inHeader.Opcode, req.arg)
req.status = EIO req.status = EIO
return return
} }
var inData unsafe.Pointer if argSize > 0 {
if argumentSize > 0 { req.inData = unsafe.Pointer(&req.arg[0])
inData = unsafe.Pointer(&req.arg[0]) req.arg = req.arg[argSize:]
}
data := req.arg[argumentSize:]
var status Status = OK
fs := me.fileSystem
filename := ""
// Perhaps a map is faster?
if h.Opcode == FUSE_UNLINK || h.Opcode == FUSE_RMDIR ||
h.Opcode == FUSE_LOOKUP || h.Opcode == FUSE_MKDIR ||
h.Opcode == FUSE_MKNOD || h.Opcode == FUSE_CREATE ||
h.Opcode == FUSE_LINK || h.Opcode == FUSE_GETXATTR ||
h.Opcode == FUSE_REMOVEXATTR {
filename = strings.TrimRight(string(data), "\x00")
}
if me.Debug {
nm := ""
if filename != "" {
nm = "n: '" + filename + "'"
}
if h.Opcode == FUSE_RENAME {
nm = "n: '" + string(data) + "'"
}
log.Printf("Dispatch: %v, NodeId: %v %s\n", operationName(h.Opcode), h.NodeId, nm)
} }
// Follow ordering of fuse_lowlevel.h. f := lookupOperation(req.inHeader.Opcode)
switch h.Opcode { if f == nil {
case FUSE_INIT: msg := fmt.Sprintf("Unsupported OpCode: %d=%v",
req.data, status = me.init(h, (*InitIn)(inData)) req.inHeader.Opcode, operationName(req.inHeader.Opcode))
case FUSE_DESTROY: me.Error(os.NewError(msg))
fs.Destroy(h, (*InitIn)(inData))
case FUSE_LOOKUP:
lookupOut, s := fs.Lookup(h, filename)
status = s
req.data = unsafe.Pointer(lookupOut)
case FUSE_FORGET:
fs.Forget(h, (*ForgetIn)(inData))
// If we try to write OK, nil, we will get
// error: writer: Writev [[16 0 0 0 0 0 0 0 17 0 0 0 0 0 0 0]]
// failed, err: writev: no such file or directory
return
case FUSE_GETATTR:
// TODO - if inData.Fh is set, do file.GetAttr
attrOut, s := fs.GetAttr(h, (*GetAttrIn)(inData))
status = s
req.data = unsafe.Pointer(attrOut)
case FUSE_SETATTR:
req.data, status = doSetattr(me, h, (*SetAttrIn)(inData))
case FUSE_READLINK:
req.flatData, status = fs.Readlink(h)
case FUSE_MKNOD:
entryOut, s := fs.Mknod(h, (*MknodIn)(inData), filename)
status = s
req.data = unsafe.Pointer(entryOut)
case FUSE_MKDIR:
entryOut, s := fs.Mkdir(h, (*MkdirIn)(inData), filename)
status = s
req.data = unsafe.Pointer(entryOut)
case FUSE_UNLINK:
status = fs.Unlink(h, filename)
case FUSE_RMDIR:
status = fs.Rmdir(h, filename)
case FUSE_SYMLINK:
filenames := strings.Split(string(data), "\x00", 3)
if len(filenames) >= 2 {
entryOut, s := fs.Symlink(h, filenames[1], filenames[0])
status = s
req.data = unsafe.Pointer(entryOut)
} else {
status = EIO
}
case FUSE_RENAME:
filenames := strings.Split(string(data), "\x00", 3)
if len(filenames) >= 2 {
status = fs.Rename(h, (*RenameIn)(inData), filenames[0], filenames[1])
} else {
status = EIO
}
case FUSE_LINK:
entryOut, s := fs.Link(h, (*LinkIn)(inData), filename)
status = s
req.data = unsafe.Pointer(entryOut)
case FUSE_OPEN:
req.data, status = doOpen(me, h, (*OpenIn)(inData))
case FUSE_READ:
req.flatData, status = me.fileSystem.Read((*ReadIn)(inData), me.buffers)
case FUSE_WRITE:
req.data, status = doWrite(me, h, (*WriteIn)(inData), data)
case FUSE_FLUSH:
status = me.fileSystem.Flush((*FlushIn)(inData))
case FUSE_RELEASE:
me.fileSystem.Release(h, (*ReleaseIn)(inData))
case FUSE_FSYNC:
status = me.fileSystem.Fsync((*FsyncIn)(inData))
case FUSE_OPENDIR:
req.data, status = doOpenDir(me, h, (*OpenIn)(inData))
case FUSE_READDIR:
req.flatData, status = doReadDir(me, h, (*ReadIn)(inData))
case FUSE_RELEASEDIR:
me.fileSystem.ReleaseDir(h, (*ReleaseIn)(inData))
case FUSE_FSYNCDIR:
status = me.fileSystem.FsyncDir(h, (*FsyncIn)(inData))
case FUSE_SETXATTR:
splits := bytes.Split(data, []byte{0}, 2)
status = fs.SetXAttr(h, (*SetXAttrIn)(inData), string(splits[0]), splits[1])
case FUSE_GETXATTR:
req.data, req.flatData, status = doGetXAttr(me, h, (*GetXAttrIn)(inData), filename, h.Opcode)
case FUSE_LISTXATTR:
req.data, req.flatData, status = doGetXAttr(me, h, (*GetXAttrIn)(inData), filename, h.Opcode)
case FUSE_REMOVEXATTR:
status = fs.RemoveXAttr(h, filename)
case FUSE_ACCESS:
status = fs.Access(h, (*AccessIn)(inData))
case FUSE_CREATE:
req.data, status = doCreate(me, h, (*CreateIn)(inData), filename)
// TODO - implement file locking.
// case FUSE_SETLK
// case FUSE_SETLKW
case FUSE_BMAP:
bmapOut, s := fs.Bmap(h, (*BmapIn)(inData))
status = s
req.data = unsafe.Pointer(bmapOut)
case FUSE_IOCTL:
ioctlOut, s := fs.Ioctl(h, (*IoctlIn)(inData))
status = s
req.data = unsafe.Pointer(ioctlOut)
case FUSE_POLL:
pollOut, s := fs.Poll(h, (*PollIn)(inData))
status = s
req.data = unsafe.Pointer(pollOut)
// TODO - figure out how to support this
// case FUSE_INTERRUPT
default:
me.Error(os.NewError(fmt.Sprintf("Unsupported OpCode: %d=%v", h.Opcode, operationName(h.Opcode))))
req.status = ENOSYS req.status = ENOSYS
return return
} }
req.status = status if me.Debug {
nm := ""
// TODO - reinstate filename printing.
log.Printf("Dispatch: %v, NodeId: %v %s\n",
operationName(req.inHeader.Opcode), req.inHeader.NodeId, nm)
}
f(me, req)
} }
// Thanks to Andrew Gerrand for this hack. // Thanks to Andrew Gerrand for this hack.
...@@ -428,7 +318,7 @@ func asSlice(ptr unsafe.Pointer, byteCount int) []byte { ...@@ -428,7 +318,7 @@ func asSlice(ptr unsafe.Pointer, byteCount int) []byte {
} }
func serialize(req *request, debug bool) { func serialize(req *request, debug bool) {
dataLength, ok := outputSizeMap[int(req.inHeader.Opcode)] dataLength, ok := outputSize(req.inHeader.Opcode)
if !ok { if !ok {
log.Println("Unknown opcode %d (output)", req.inHeader.Opcode) log.Println("Unknown opcode %d (output)", req.inHeader.Opcode)
req.status = ENOSYS req.status = ENOSYS
...@@ -487,92 +377,3 @@ func (me *MountState) init(h *InHeader, input *InitIn) (unsafe.Pointer, Status) ...@@ -487,92 +377,3 @@ func (me *MountState) init(h *InHeader, input *InitIn) (unsafe.Pointer, Status)
return unsafe.Pointer(out), OK return unsafe.Pointer(out), OK
} }
////////////////////////////////////////////////////////////////
// Handling files.
func doOpen(state *MountState, header *InHeader, input *OpenIn) (unsafe.Pointer, Status) {
flags, handle, status := state.fileSystem.Open(header, input)
if status != OK {
return nil, status
}
out := new(OpenOut)
out.Fh = handle
out.OpenFlags = flags
return unsafe.Pointer(out), status
}
func doCreate(state *MountState, header *InHeader, input *CreateIn, name string) (unsafe.Pointer, Status) {
flags, handle, entry, status := state.fileSystem.Create(header, input, name)
if status != OK {
return nil, status
}
out := new(CreateOut)
out.Entry = *entry
out.Open.Fh = handle
out.Open.OpenFlags = flags
return unsafe.Pointer(out), status
}
func doWrite(state *MountState, header *InHeader, input *WriteIn, data []byte) (out unsafe.Pointer, code Status) {
n, status := state.fileSystem.Write(input, data)
o := &WriteOut{
Size: n,
}
return unsafe.Pointer(o), status
}
func doSetattr(state *MountState, header *InHeader, input *SetAttrIn) (out unsafe.Pointer, code Status) {
// TODO - if Fh != 0, we should do a FSetAttr instead.
o, s := state.fileSystem.SetAttr(header, input)
return unsafe.Pointer(o), s
}
func doGetXAttr(state *MountState, header *InHeader, input *GetXAttrIn, attr string, opcode uint32) (out unsafe.Pointer, data []byte, code Status) {
if opcode == FUSE_GETXATTR {
data, code = state.fileSystem.GetXAttr(header, attr)
} else {
data, code = state.fileSystem.ListXAttr(header)
}
if code != OK {
return nil, nil, code
}
size := uint32(len(data))
if input.Size == 0 {
out := new(GetXAttrOut)
out.Size = size
return unsafe.Pointer(out), nil, OK
}
if size > input.Size {
return nil, nil, ERANGE
}
return nil, data, OK
}
////////////////////////////////////////////////////////////////
// Handling directories
func doOpenDir(state *MountState, header *InHeader, input *OpenIn) (unsafe.Pointer, Status) {
flags, handle, status := state.fileSystem.OpenDir(header, input)
if status != OK {
return nil, status
}
out := new(OpenOut)
out.Fh = handle
out.OpenFlags = flags
return unsafe.Pointer(out), status
}
func doReadDir(state *MountState, header *InHeader, input *ReadIn) (out []byte, code Status) {
entries, code := state.fileSystem.ReadDir(header, input)
if entries == nil {
return nil, code
}
return entries.Bytes(), code
}
...@@ -296,24 +296,6 @@ func (me *LockingRawFileSystem) Create(header *InHeader, input *CreateIn, name s ...@@ -296,24 +296,6 @@ func (me *LockingRawFileSystem) Create(header *InHeader, input *CreateIn, name s
return me.Original.Create(header, input, name) return me.Original.Create(header, input, name)
} }
func (me *LockingRawFileSystem) Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status) {
me.lock.Lock()
defer me.lock.Unlock()
return me.Original.Bmap(header, input)
}
func (me *LockingRawFileSystem) Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, code Status) {
me.lock.Lock()
defer me.lock.Unlock()
return me.Original.Ioctl(header, input)
}
func (me *LockingRawFileSystem) Poll(header *InHeader, input *PollIn) (out *PollOut, code Status) {
me.lock.Lock()
defer me.lock.Unlock()
return me.Original.Poll(header, input)
}
func (me *LockingRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags uint32, h uint64, status Status) { func (me *LockingRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags uint32, h uint64, status Status) {
me.lock.Lock() me.lock.Lock()
defer me.lock.Unlock() defer me.lock.Unlock()
......
...@@ -275,11 +275,11 @@ func (me *testCase) testSymlink() { ...@@ -275,11 +275,11 @@ func (me *testCase) testSymlink() {
func (me *testCase) testRename() { func (me *testCase) testRename() {
me.tester.Log("Testing rename.") me.tester.Log("Testing rename.")
me.writeOrigFile() me.writeOrigFile()
sd := me.mountPoint+"/testRename" sd := me.mountPoint + "/testRename"
err := os.MkdirAll(sd, 0777) err := os.MkdirAll(sd, 0777)
defer os.RemoveAll(sd) defer os.RemoveAll(sd)
subFile := sd+"/subfile" subFile := sd + "/subfile"
err = os.Rename(me.mountFile, subFile) err = os.Rename(me.mountFile, subFile)
CheckSuccess(err) CheckSuccess(err)
f, _ := os.Lstat(me.origFile) f, _ := os.Lstat(me.origFile)
...@@ -295,21 +295,21 @@ func (me *testCase) testRename() { ...@@ -295,21 +295,21 @@ func (me *testCase) testRename() {
func (me *testCase) testDelRename() { func (me *testCase) testDelRename() {
me.tester.Log("Testing del+rename.") me.tester.Log("Testing del+rename.")
sd := me.mountPoint+"/testDelRename" sd := me.mountPoint + "/testDelRename"
err := os.MkdirAll(sd, 0755) err := os.MkdirAll(sd, 0755)
CheckSuccess(err) CheckSuccess(err)
d := sd+"/dest" d := sd + "/dest"
err = ioutil.WriteFile(d, []byte("blabla"), 0644) err = ioutil.WriteFile(d, []byte("blabla"), 0644)
CheckSuccess(err) CheckSuccess(err)
f, err := os.Open(d) f, err := os.Open(d)
CheckSuccess(err) CheckSuccess(err)
err = os.Remove(d) err = os.Remove(d)
CheckSuccess(err) CheckSuccess(err)
s := sd+"/src" s := sd + "/src"
err = ioutil.WriteFile(s, []byte("blabla"), 0644) err = ioutil.WriteFile(s, []byte("blabla"), 0644)
CheckSuccess(err) CheckSuccess(err)
...@@ -322,15 +322,15 @@ func (me *testCase) testDelRename() { ...@@ -322,15 +322,15 @@ func (me *testCase) testDelRename() {
func (me *testCase) testOverwriteRename() { func (me *testCase) testOverwriteRename() {
me.tester.Log("Testing rename overwrite.") me.tester.Log("Testing rename overwrite.")
sd := me.mountPoint+"/testOverwriteRename" sd := me.mountPoint + "/testOverwriteRename"
err := os.MkdirAll(sd, 0755) err := os.MkdirAll(sd, 0755)
CheckSuccess(err) CheckSuccess(err)
d := sd+"/dest" d := sd + "/dest"
err = ioutil.WriteFile(d, []byte("blabla"), 0644) err = ioutil.WriteFile(d, []byte("blabla"), 0644)
CheckSuccess(err) CheckSuccess(err)
s := sd+"/src" s := sd + "/src"
err = ioutil.WriteFile(s, []byte("blabla"), 0644) err = ioutil.WriteFile(s, []byte("blabla"), 0644)
CheckSuccess(err) CheckSuccess(err)
......
package fuse package fuse
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"unsafe" "unsafe"
...@@ -13,7 +14,7 @@ func (code Status) String() string { ...@@ -13,7 +14,7 @@ func (code Status) String() string {
return fmt.Sprintf("%d=%v", int(code), os.Errno(code)) return fmt.Sprintf("%d=%v", int(code), os.Errno(code))
} }
func replyString(opcode uint32, ptr unsafe.Pointer) string { func replyString(opcode Opcode, ptr unsafe.Pointer) string {
var val interface{} var val interface{}
switch opcode { switch opcode {
case FUSE_LOOKUP: case FUSE_LOOKUP:
...@@ -27,95 +28,257 @@ func replyString(opcode uint32, ptr unsafe.Pointer) string { ...@@ -27,95 +28,257 @@ func replyString(opcode uint32, ptr unsafe.Pointer) string {
return "" return ""
} }
func operationName(opcode uint32) string { ////////////////////////////////////////////////////////////////
switch opcode {
case FUSE_LOOKUP: func doOpen(state *MountState, req *request) {
return "FUSE_LOOKUP" flags, handle, status := state.fileSystem.Open(req.inHeader, (*OpenIn)(req.inData))
case FUSE_FORGET: req.status = status
return "FUSE_FORGET" if status != OK {
case FUSE_GETATTR: return
return "FUSE_GETATTR" }
case FUSE_SETATTR:
return "FUSE_SETATTR" out := &OpenOut{
case FUSE_READLINK: Fh: handle,
return "FUSE_READLINK" OpenFlags: flags,
case FUSE_SYMLINK: }
return "FUSE_SYMLINK"
case FUSE_MKNOD: req.data = unsafe.Pointer(out)
return "FUSE_MKNOD" }
case FUSE_MKDIR:
return "FUSE_MKDIR"
case FUSE_UNLINK: func doCreate(state *MountState, req *request) {
return "FUSE_UNLINK" flags, handle, entry, status := state.fileSystem.Create(req.inHeader, (*CreateIn)(req.inData), req.filename())
case FUSE_RMDIR: req.status = status
return "FUSE_RMDIR" if status == OK {
case FUSE_RENAME: req.data = unsafe.Pointer(&CreateOut{
return "FUSE_RENAME" EntryOut: *entry,
case FUSE_LINK: OpenOut: OpenOut{
return "FUSE_LINK" Fh: handle,
case FUSE_OPEN: OpenFlags: flags,
return "FUSE_OPEN" },
case FUSE_READ: })
return "FUSE_READ" }
case FUSE_WRITE: }
return "FUSE_WRITE"
case FUSE_STATFS:
return "FUSE_STATFS" func doReadDir(state *MountState, req *request) {
case FUSE_RELEASE: entries, code := state.fileSystem.ReadDir(req.inHeader, (*ReadIn)(req.inData))
return "FUSE_RELEASE" if entries != nil {
case FUSE_FSYNC: req.flatData = entries.Bytes()
return "FUSE_FSYNC" }
case FUSE_SETXATTR: req.status = code
return "FUSE_SETXATTR" }
case FUSE_GETXATTR:
return "FUSE_GETXATTR"
case FUSE_LISTXATTR: func doOpenDir(state *MountState, req *request) {
return "FUSE_LISTXATTR" flags, handle, status := state.fileSystem.OpenDir(req.inHeader, (*OpenIn)(req.inData))
case FUSE_REMOVEXATTR: req.status = status
return "FUSE_REMOVEXATTR" if status == OK {
case FUSE_FLUSH: req.data = unsafe.Pointer(&OpenOut{
return "FUSE_FLUSH" Fh: handle,
case FUSE_INIT: OpenFlags: flags,
return "FUSE_INIT" })
case FUSE_OPENDIR: }
return "FUSE_OPENDIR" }
case FUSE_READDIR:
return "FUSE_READDIR" func doSetattr(state *MountState, req *request) {
case FUSE_RELEASEDIR: // TODO - if Fh != 0, we should do a FSetAttr instead.
return "FUSE_RELEASEDIR" o, s := state.fileSystem.SetAttr(req.inHeader, (*SetAttrIn)(req.inData))
case FUSE_FSYNCDIR: req.data = unsafe.Pointer(o)
return "FUSE_FSYNCDIR" req.status = s
case FUSE_GETLK: }
return "FUSE_GETLK"
case FUSE_SETLK: func doWrite(state *MountState, req *request) {
return "FUSE_SETLK" n, status := state.fileSystem.Write((*WriteIn)(req.inData), req.arg)
case FUSE_SETLKW: o := &WriteOut{
return "FUSE_SETLKW" Size: n,
case FUSE_ACCESS: }
return "FUSE_ACCESS" req.data = unsafe.Pointer(o)
case FUSE_CREATE: req.status = status
return "FUSE_CREATE" }
case FUSE_INTERRUPT:
return "FUSE_INTERRUPT"
case FUSE_BMAP: func doGetXAttr(state *MountState, req *request) {
return "FUSE_BMAP" input := (*GetXAttrIn)(req.inData)
case FUSE_DESTROY: var data []byte
return "FUSE_DESTROY" if req.inHeader.Opcode == FUSE_GETXATTR {
case FUSE_IOCTL: data, req.status = state.fileSystem.GetXAttr(req.inHeader, req.filename())
return "FUSE_IOCTL" } else {
case FUSE_POLL: data, req.status = state.fileSystem.ListXAttr(req.inHeader)
return "FUSE_POLL" }
}
return "UNKNOWN" if req.status != OK {
} return
}
size := uint32(len(data))
var inputSizeMap map[int]int if input.Size == 0 {
var outputSizeMap map[int]int out := &GetXAttrOut{
Size: size,
}
req.data = unsafe.Pointer(out)
}
if size > input.Size {
req.status = ERANGE
}
req.flatData = data
}
func doGetAttr(state *MountState, req *request) {
// TODO - if req.inData.Fh is set, do file.GetAttr
attrOut, s := state.fileSystem.GetAttr(req.inHeader, (*GetAttrIn)(req.inData))
req.status = s
req.data = unsafe.Pointer(attrOut)
}
func doForget(state *MountState, req *request) {
state.fileSystem.Forget(req.inHeader, (*ForgetIn)(req.inData))
}
func doReadlink(state *MountState, req *request) {
req.flatData, req.status = state.fileSystem.Readlink(req.inHeader)
}
func doInit(state *MountState, req *request) {
req.data, req.status = state.init(req.inHeader, (*InitIn)(req.inData))
}
func doDestroy(state *MountState, req *request) {
state.fileSystem.Destroy(req.inHeader, (*InitIn)(req.inData))
}
func doLookup(state *MountState, req *request) {
lookupOut, s := state.fileSystem.Lookup(req.inHeader, req.filename())
req.status = s
req.data = unsafe.Pointer(lookupOut)
}
func doMknod(state *MountState, req *request) {
entryOut, s := state.fileSystem.Mknod(req.inHeader, (*MknodIn)(req.inData), req.filename())
req.status = s
req.data = unsafe.Pointer(entryOut)
}
func doMkdir(state *MountState, req *request) {
entryOut, s := state.fileSystem.Mkdir(req.inHeader, (*MkdirIn)(req.inData), req.filename())
req.status = s
req.data = unsafe.Pointer(entryOut)
}
func doUnlink(state *MountState, req *request) {
req.status = state.fileSystem.Unlink(req.inHeader, req.filename())
}
func doRmdir(state *MountState, req *request) {
req.status = state.fileSystem.Rmdir(req.inHeader, req.filename())
}
func doLink(state *MountState, req *request) {
entryOut, s := state.fileSystem.Link(req.inHeader, (*LinkIn)(req.inData), req.filename())
req.status = s
req.data = unsafe.Pointer(entryOut)
}
func doRead(state *MountState, req *request) {
req.flatData, req.status = state.fileSystem.Read((*ReadIn)(req.inData), state.buffers)
}
func doFlush(state *MountState, req *request) {
req.status = state.fileSystem.Flush((*FlushIn)(req.inData))
}
func doRelease(state *MountState, req *request) {
state.fileSystem.Release(req.inHeader, (*ReleaseIn)(req.inData))
}
func doFsync(state *MountState, req *request) {
req.status = state.fileSystem.Fsync((*FsyncIn)(req.inData))
}
func doReleaseDir(state *MountState, req *request) {
state.fileSystem.ReleaseDir(req.inHeader, (*ReleaseIn)(req.inData))
}
func doFsyncDir(state *MountState, req *request) {
req.status = state.fileSystem.FsyncDir(req.inHeader, (*FsyncIn)(req.inData))
}
func doSetXAttr(state *MountState, req *request) {
splits := bytes.Split(req.arg, []byte{0}, 2)
req.status = state.fileSystem.SetXAttr(req.inHeader, (*SetXAttrIn)(req.inData), string(splits[0]), splits[1])
}
func doRemoveXAttr(state *MountState, req *request) {
req.status = state.fileSystem.RemoveXAttr(req.inHeader, req.filename())
}
func doAccess(state *MountState, req *request) {
req.status = state.fileSystem.Access(req.inHeader, (*AccessIn)(req.inData))
}
func doSymlink(state *MountState, req *request) {
filenames := req.filenames(3)
if len(filenames) >= 2 {
entryOut, s := state.fileSystem.Symlink(req.inHeader, filenames[1], filenames[0])
req.status = s
req.data = unsafe.Pointer(entryOut)
} else {
req.status = EIO
}
}
func doRename(state *MountState, req *request) {
filenames := req.filenames(3)
if len(filenames) >= 2 {
req.status = state.fileSystem.Rename(req.inHeader, (*RenameIn)(req.inData), filenames[0], filenames[1])
} else {
req.status = EIO
}
}
////////////////////////////////////////////////////////////////
var operationNames []string
var inputSizes []int
var outputSizes []int
type operation func(*MountState, *request)
var operationFuncs []operation
func operationName(opcode Opcode) string {
if opcode > OPCODE_COUNT {
return "unknown"
}
return operationNames[opcode]
}
func inputSize(o Opcode) (int, bool) {
return lookupSize(o, inputSizes)
}
func outputSize(o Opcode) (int, bool) {
return lookupSize(o, outputSizes)
}
func lookupSize(o Opcode, sMap []int) (int, bool) {
if o >= OPCODE_COUNT {
return -1, false
}
return sMap[int(o)], true
}
func lookupOperation(o Opcode) operation {
return operationFuncs[o]
}
func makeSizes(dict map[int]int) []int {
out := make([]int, OPCODE_COUNT)
for i, _ := range out {
out[i] = -1
}
for code, val := range dict {
out[code] = val
}
return out
}
func init() { func init() {
inputSizeMap = map[int]int{ inputSizes = makeSizes(map[int]int{
FUSE_LOOKUP: 0, FUSE_LOOKUP: 0,
FUSE_FORGET: unsafe.Sizeof(ForgetIn{}), FUSE_FORGET: unsafe.Sizeof(ForgetIn{}),
FUSE_GETATTR: unsafe.Sizeof(GetAttrIn{}), FUSE_GETATTR: unsafe.Sizeof(GetAttrIn{}),
...@@ -154,9 +317,9 @@ func init() { ...@@ -154,9 +317,9 @@ func init() {
FUSE_DESTROY: 0, FUSE_DESTROY: 0,
FUSE_IOCTL: unsafe.Sizeof(IoctlIn{}), FUSE_IOCTL: unsafe.Sizeof(IoctlIn{}),
FUSE_POLL: unsafe.Sizeof(PollIn{}), FUSE_POLL: unsafe.Sizeof(PollIn{}),
} })
outputSizeMap = map[int]int{ outputSizes = makeSizes(map[int]int{
FUSE_LOOKUP: unsafe.Sizeof(EntryOut{}), FUSE_LOOKUP: unsafe.Sizeof(EntryOut{}),
FUSE_FORGET: 0, FUSE_FORGET: 0,
FUSE_GETATTR: unsafe.Sizeof(AttrOut{}), FUSE_GETATTR: unsafe.Sizeof(AttrOut{}),
...@@ -196,5 +359,84 @@ func init() { ...@@ -196,5 +359,84 @@ func init() {
FUSE_DESTROY: 0, FUSE_DESTROY: 0,
FUSE_IOCTL: unsafe.Sizeof(IoctlOut{}), FUSE_IOCTL: unsafe.Sizeof(IoctlOut{}),
FUSE_POLL: unsafe.Sizeof(PollOut{}), FUSE_POLL: unsafe.Sizeof(PollOut{}),
})
operationNames = make([]string, OPCODE_COUNT)
for k, v := range map[int]string{
FUSE_LOOKUP: "FUSE_LOOKUP",
FUSE_FORGET: "FUSE_FORGET",
FUSE_GETATTR: "FUSE_GETATTR",
FUSE_SETATTR: "FUSE_SETATTR",
FUSE_READLINK: "FUSE_READLINK",
FUSE_SYMLINK: "FUSE_SYMLINK",
FUSE_MKNOD: "FUSE_MKNOD",
FUSE_MKDIR: "FUSE_MKDIR",
FUSE_UNLINK: "FUSE_UNLINK",
FUSE_RMDIR: "FUSE_RMDIR",
FUSE_RENAME: "FUSE_RENAME",
FUSE_LINK: "FUSE_LINK",
FUSE_OPEN: "FUSE_OPEN",
FUSE_READ: "FUSE_READ",
FUSE_WRITE: "FUSE_WRITE",
FUSE_STATFS: "FUSE_STATFS",
FUSE_RELEASE: "FUSE_RELEASE",
FUSE_FSYNC: "FUSE_FSYNC",
FUSE_SETXATTR: "FUSE_SETXATTR",
FUSE_GETXATTR: "FUSE_GETXATTR",
FUSE_LISTXATTR: "FUSE_LISTXATTR",
FUSE_REMOVEXATTR: "FUSE_REMOVEXATTR",
FUSE_FLUSH: "FUSE_FLUSH",
FUSE_INIT: "FUSE_INIT",
FUSE_OPENDIR: "FUSE_OPENDIR",
FUSE_READDIR: "FUSE_READDIR",
FUSE_RELEASEDIR: "FUSE_RELEASEDIR",
FUSE_FSYNCDIR: "FUSE_FSYNCDIR",
FUSE_GETLK: "FUSE_GETLK",
FUSE_SETLK: "FUSE_SETLK",
FUSE_SETLKW: "FUSE_SETLKW",
FUSE_ACCESS: "FUSE_ACCESS",
FUSE_CREATE: "FUSE_CREATE",
FUSE_INTERRUPT: "FUSE_INTERRUPT",
FUSE_BMAP: "FUSE_BMAP",
FUSE_DESTROY: "FUSE_DESTROY",
FUSE_IOCTL: "FUSE_IOCTL",
FUSE_POLL: "FUSE_POLL"} {
operationNames[k] = v
}
operationFuncs = make([]operation, OPCODE_COUNT)
for k, v := range map[Opcode]operation{
FUSE_OPEN: doOpen,
FUSE_READDIR: doReadDir,
FUSE_WRITE: doWrite,
FUSE_OPENDIR: doOpenDir,
FUSE_CREATE: doCreate,
FUSE_SETATTR: doSetattr,
FUSE_GETXATTR: doGetXAttr,
FUSE_LISTXATTR: doGetXAttr,
FUSE_GETATTR: doGetAttr,
FUSE_FORGET: doForget,
FUSE_READLINK: doReadlink,
FUSE_INIT: doInit,
FUSE_DESTROY: doDestroy,
FUSE_LOOKUP: doLookup,
FUSE_MKNOD: doMknod,
FUSE_MKDIR: doMkdir,
FUSE_UNLINK: doUnlink,
FUSE_RMDIR: doRmdir,
FUSE_LINK: doLink,
FUSE_READ: doRead,
FUSE_FLUSH: doFlush,
FUSE_RELEASE: doRelease,
FUSE_FSYNC: doFsync,
FUSE_RELEASEDIR: doReleaseDir,
FUSE_FSYNCDIR: doFsyncDir,
FUSE_SETXATTR: doSetXAttr,
FUSE_REMOVEXATTR: doRemoveXAttr,
FUSE_ACCESS: doAccess,
FUSE_SYMLINK: doSymlink,
FUSE_RENAME: doRename,
} {
operationFuncs[k] = v
} }
} }
package fuse package fuse
import ( import (
"fmt" "fmt"
) )
...@@ -12,7 +13,7 @@ type FileSystemDebug struct { ...@@ -12,7 +13,7 @@ type FileSystemDebug struct {
WrappingFileSystem WrappingFileSystem
} }
func (me *FileSystemDebug) Open(path string, flags uint32) (fuseFile File, status Status) { func (me *FileSystemDebug) Open(path string, flags uint32) (fuseFile File, status Status) {
if path == ".debug" && me.Connector != nil { if path == ".debug" && me.Connector != nil {
return NewReadOnlyFile([]byte(me.Connector.DebugString())), OK return NewReadOnlyFile([]byte(me.Connector.DebugString())), OK
} }
...@@ -24,8 +25,7 @@ func (me *FileSystemDebug) GetAttr(path string) (*Attr, Status) { ...@@ -24,8 +25,7 @@ func (me *FileSystemDebug) GetAttr(path string) (*Attr, Status) {
return &Attr{ return &Attr{
Mode: S_IFREG, Mode: S_IFREG,
Size: uint64(len(me.Connector.DebugString())), Size: uint64(len(me.Connector.DebugString())),
}, OK },OK
} }
return me.Original.GetAttr(path) return me.Original.GetAttr(path)
} }
...@@ -169,7 +169,7 @@ type FileSystemConnector struct { ...@@ -169,7 +169,7 @@ type FileSystemConnector struct {
func (me *FileSystemConnector) DebugString() string { func (me *FileSystemConnector) DebugString() string {
me.lock.RLock() me.lock.RLock()
defer me.lock.RUnlock() defer me.lock.RUnlock()
me.fileLock.RLock() me.fileLock.RLock()
defer me.fileLock.RUnlock() defer me.fileLock.RUnlock()
...@@ -237,14 +237,14 @@ func (me *FileSystemConnector) verify() { ...@@ -237,14 +237,14 @@ func (me *FileSystemConnector) verify() {
hiddenOpen += v.OpenCount hiddenOpen += v.OpenCount
} }
} }
root := me.inodeMap[FUSE_ROOT_ID] root := me.inodeMap[FUSE_ROOT_ID]
root.verify() root.verify()
open := root.totalOpenCount() open := root.totalOpenCount()
openFiles := len(me.openFiles) openFiles := len(me.openFiles)
mounted := root.totalMountCount() mounted := root.totalMountCount()
if open + hiddenOpen != openFiles + mounted { if open+hiddenOpen != openFiles+mounted {
panic(fmt.Sprintf("opencount mismatch totalOpen=%v openFiles=%v mounted=%v hidden=%v", open, openFiles, mounted, hiddenOpen)) panic(fmt.Sprintf("opencount mismatch totalOpen=%v openFiles=%v mounted=%v hidden=%v", open, openFiles, mounted, hiddenOpen))
} }
} }
...@@ -306,10 +306,10 @@ func (me *FileSystemConnector) considerDropInode(n *inode) { ...@@ -306,10 +306,10 @@ func (me *FileSystemConnector) considerDropInode(n *inode) {
n.mount.mutex.RLock() n.mount.mutex.RLock()
defer n.mount.mutex.RUnlock() defer n.mount.mutex.RUnlock()
} }
// TODO - this should probably not happen at all. // TODO - this should probably not happen at all.
if (n.LookupCount <= 0 && len(n.Children) == 0 && (n.mount == nil || n.mount.unmountPending) && if n.LookupCount <= 0 && len(n.Children) == 0 && (n.mount == nil || n.mount.unmountPending) &&
n.OpenCount <= 0) { n.OpenCount <= 0 {
n.setParent(nil) n.setParent(nil)
me.inodeMap[n.NodeId] = nil, false me.inodeMap[n.NodeId] = nil, false
} }
...@@ -328,7 +328,7 @@ func (me *FileSystemConnector) renameUpdate(oldParent *inode, oldName string, ne ...@@ -328,7 +328,7 @@ func (me *FileSystemConnector) renameUpdate(oldParent *inode, oldName string, ne
dest := newParent.Children[newName] dest := newParent.Children[newName]
if dest != nil { if dest != nil {
dest.setParent(nil) dest.setParent(nil)
} }
node.setParent(nil) node.setParent(nil)
node.Name = newName node.Name = newName
node.setParent(newParent) node.setParent(newParent)
...@@ -384,7 +384,7 @@ func EmptyFileSystemConnector() (out *FileSystemConnector) { ...@@ -384,7 +384,7 @@ func EmptyFileSystemConnector() (out *FileSystemConnector) {
out.options.AttrTimeout = 1.0 out.options.AttrTimeout = 1.0
out.options.EntryTimeout = 1.0 out.options.EntryTimeout = 1.0
out.verify() out.verify()
return out; return out
} }
func NewFileSystemConnector(fs FileSystem) (out *FileSystemConnector) { func NewFileSystemConnector(fs FileSystem) (out *FileSystemConnector) {
......
...@@ -151,21 +151,6 @@ func (me *TimingRawFileSystem) Create(header *InHeader, input *CreateIn, name st ...@@ -151,21 +151,6 @@ func (me *TimingRawFileSystem) Create(header *InHeader, input *CreateIn, name st
return me.Original.Create(header, input, name) return me.Original.Create(header, input, name)
} }
func (me *TimingRawFileSystem) Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status) {
defer me.startTimer("Bmap")()
return me.Original.Bmap(header, input)
}
func (me *TimingRawFileSystem) Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, code Status) {
defer me.startTimer("Ioctl")()
return me.Original.Ioctl(header, input)
}
func (me *TimingRawFileSystem) Poll(header *InHeader, input *PollIn) (out *PollOut, code Status) {
defer me.startTimer("Poll")()
return me.Original.Poll(header, input)
}
func (me *TimingRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) { func (me *TimingRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
defer me.startTimer("OpenDir")() defer me.startTimer("OpenDir")()
return me.Original.OpenDir(header, input) return me.Original.OpenDir(header, input)
......
...@@ -143,6 +143,8 @@ const ( ...@@ -143,6 +143,8 @@ const (
FUSE_IOCTL = 39 FUSE_IOCTL = 39
FUSE_POLL = 40 FUSE_POLL = 40
OPCODE_COUNT = 41
CUSE_INIT = 4096 CUSE_INIT = 4096
) )
...@@ -287,8 +289,8 @@ type OpenOut struct { ...@@ -287,8 +289,8 @@ type OpenOut struct {
} }
type CreateOut struct { type CreateOut struct {
Entry EntryOut EntryOut
Open OpenOut OpenOut
} }
type ReleaseIn struct { type ReleaseIn struct {
...@@ -456,7 +458,7 @@ type NotifyPollWakeupOut struct { ...@@ -456,7 +458,7 @@ type NotifyPollWakeupOut struct {
type InHeader struct { type InHeader struct {
Length uint32 Length uint32
Opcode uint32 Opcode
Unique uint64 Unique uint64
NodeId uint64 NodeId uint64
Identity Identity
...@@ -528,9 +530,13 @@ type RawFileSystem interface { ...@@ -528,9 +530,13 @@ type RawFileSystem interface {
RemoveXAttr(header *InHeader, attr string) (code Status) RemoveXAttr(header *InHeader, attr string) (code Status)
Access(header *InHeader, input *AccessIn) (code Status) Access(header *InHeader, input *AccessIn) (code Status)
Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status) Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status)
Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status)
Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, code Status) /*
Poll(header *InHeader, input *PollIn) (out *PollOut, code Status) // unimplemented.
Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status)
Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, code Status)
Poll(header *InHeader, input *PollIn) (out *PollOut, code Status)
*/
// File handling. // File handling.
Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status)
......
...@@ -189,18 +189,6 @@ func (me *WrappingRawFileSystem) Create(header *InHeader, input *CreateIn, name ...@@ -189,18 +189,6 @@ func (me *WrappingRawFileSystem) Create(header *InHeader, input *CreateIn, name
return me.Original.Create(header, input, name) return me.Original.Create(header, input, name)
} }
func (me *WrappingRawFileSystem) Bmap(header *InHeader, input *BmapIn) (out *BmapOut, code Status) {
return me.Original.Bmap(header, input)
}
func (me *WrappingRawFileSystem) Ioctl(header *InHeader, input *IoctlIn) (out *IoctlOut, code Status) {
return me.Original.Ioctl(header, input)
}
func (me *WrappingRawFileSystem) Poll(header *InHeader, input *PollIn) (out *PollOut, code Status) {
return me.Original.Poll(header, input)
}
func (me *WrappingRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) { func (me *WrappingRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status) {
return me.Original.OpenDir(header, input) return me.Original.OpenDir(header, input)
} }
......
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