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

Add a portableHandleMap, and use it for assigning 32 bit inodes.

parent 3e88d4c7
......@@ -242,12 +242,12 @@ type RawFileSystem interface {
// File handling.
Create(header *InHeader, input *CreateIn, name string) (flags uint32, handle uint64, out *EntryOut, code Status)
Open(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status)
Read(*ReadIn, BufferPool) ([]byte, Status)
Read(*InHeader, *ReadIn, BufferPool) ([]byte, Status)
Release(header *InHeader, input *ReleaseIn)
Write(*WriteIn, []byte) (written uint32, code Status)
Write(*InHeader, *WriteIn, []byte) (written uint32, code Status)
Flush(header *InHeader, input *FlushIn) Status
Fsync(*FsyncIn) (code Status)
Fsync(*InHeader, *FsyncIn) (code Status)
// Directory handling
OpenDir(header *InHeader, input *OpenIn) (flags uint32, handle uint64, status Status)
......
......@@ -94,14 +94,14 @@ func (me *DefaultRawFileSystem) OpenDir(header *InHeader, input *OpenIn) (flags
return 0, 0, ENOSYS
}
func (me *DefaultRawFileSystem) Read(*ReadIn, BufferPool) ([]byte, Status) {
func (me *DefaultRawFileSystem) Read(header *InHeader, input *ReadIn, bp BufferPool) ([]byte, Status) {
return nil, ENOSYS
}
func (me *DefaultRawFileSystem) Release(header *InHeader, input *ReleaseIn) {
}
func (me *DefaultRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
func (me *DefaultRawFileSystem) Write(header *InHeader, input *WriteIn, data []byte) (written uint32, code Status) {
return 0, ENOSYS
}
......@@ -109,7 +109,7 @@ func (me *DefaultRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
return OK
}
func (me *DefaultRawFileSystem) Fsync(input *FsyncIn) (code Status) {
func (me *DefaultRawFileSystem) Fsync(header *InHeader, input *FsyncIn) (code Status) {
return ENOSYS
}
......
......@@ -50,7 +50,7 @@ func NewFileSystemConnector(nodeFs NodeFileSystem, opts *FileSystemOptions) (me
if opts == nil {
opts = NewFileSystemOptions()
}
me.inodeMap = NewHandleMap(!opts.SkipCheckHandles)
me.inodeMap = NewHandleMap(opts.SkipCheckHandles)
me.rootNode = newInode(true, nodeFs.Root())
// FUSE does not issue a LOOKUP for 1 (obviously), but it does
......@@ -105,7 +105,7 @@ func (me *FileSystemConnector) toInode(nodeid uint64) *Inode {
if nodeid == FUSE_ROOT_ID {
return me.rootNode
}
i := (*Inode)(unsafe.Pointer(DecodeHandle(nodeid)))
i := (*Inode)(unsafe.Pointer(me.inodeMap.Decode(nodeid)))
return i
}
......
......@@ -37,6 +37,8 @@ type fileSystemMount struct {
// Manage filehandles of open files.
openFiles HandleMap
Debug bool
}
// Must called with lock for parent held.
......@@ -74,8 +76,8 @@ func (me *fileSystemMount) fileInfoToAttr(fi *os.FileInfo, out *AttrOut) {
me.setOwner(&out.Attr)
}
func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
b := (*openedFile)(unsafe.Pointer(DecodeHandle(h)))
func (me *fileSystemMount) getOpenedFile(h uint64) *openedFile {
b := (*openedFile)(unsafe.Pointer(me.openFiles.Decode(h)))
if me.Debug {
log.Printf("File %d = %s", h, b.WithFlags.Description)
}
......
......@@ -117,7 +117,7 @@ func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out
var f File
if input.Flags&FUSE_GETATTR_FH != 0 {
if opened := me.getOpenedFile(input.Fh); opened != nil {
if opened := node.mount.getOpenedFile(input.Fh); opened != nil {
f = opened.WithFlags.File
}
}
......@@ -152,7 +152,8 @@ func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags u
}
func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
opened := me.getOpenedFile(input.Fh)
node := me.toInode(header.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
de, code := opened.dir.ReadDir(input)
if code != OK {
return nil, code
......@@ -171,13 +172,13 @@ func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint
}
func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
node := me.toInode(header.NodeId)
var f File
if input.Valid&FATTR_FH != 0 {
opened := me.getOpenedFile(input.Fh)
opened := node.mount.getOpenedFile(input.Fh)
f = opened.WithFlags.File
}
node := me.toInode(header.NodeId)
if code.Ok() && input.Valid&FATTR_MODE != 0 {
permissions := uint32(07777) & input.Mode
code = node.fsInode.Chmod(f, permissions, &header.Context)
......@@ -331,7 +332,7 @@ func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
func (me *FileSystemConnector) Flush(header *InHeader, input *FlushIn) Status {
node := me.toInode(header.NodeId)
opened := me.getOpenedFile(input.Fh)
opened := node.mount.getOpenedFile(input.Fh)
return node.fsInode.Flush(opened.WithFlags.File, opened.WithFlags.OpenFlags, &header.Context)
}
......@@ -376,13 +377,15 @@ func (me *FileSystemConnector) ListXAttr(header *InHeader) (data []byte, code St
////////////////
// files.
func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
opened := me.getOpenedFile(input.Fh)
func (me *FileSystemConnector) Write(header *InHeader, input *WriteIn, data []byte) (written uint32, code Status) {
node := me.toInode(header.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
return opened.WithFlags.File.Write(input, data)
}
func (me *FileSystemConnector) Read(input *ReadIn, bp BufferPool) ([]byte, Status) {
opened := me.getOpenedFile(input.Fh)
func (me *FileSystemConnector) Read(header *InHeader, input *ReadIn, bp BufferPool) ([]byte, Status) {
node := me.toInode(header.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
return opened.WithFlags.File.Read(input, bp)
}
......
......@@ -22,6 +22,7 @@ import (
type HandleMap interface {
Register(obj *Handled, asInt interface{}) uint64
Count() int
Decode(uint64) *Handled
Forget(uint64) *Handled
Has(uint64) bool
}
......@@ -31,6 +32,58 @@ type Handled struct {
object interface{}
}
const _ALREADY_MSG = "Object already has a handle"
////////////////////////////////////////////////////////////////
// portable version using 32 bit integers.
type portableHandleMap struct {
sync.RWMutex
nextFree uint32
handles map[uint64]*Handled
}
func (me *portableHandleMap) Register(obj *Handled, asInt interface{}) uint64 {
if obj.check != 0 {
panic(_ALREADY_MSG)
}
me.Lock()
defer me.Unlock()
h := uint64(me.nextFree)
me.nextFree++
me.handles[h] = obj
obj.check = 0xbaabbaab
return h
}
func (me *portableHandleMap) Count() int {
me.RLock()
defer me.RUnlock()
return len(me.handles)
}
func (me *portableHandleMap) Decode(h uint64) *Handled {
me.RLock()
defer me.RUnlock()
return me.handles[h]
}
func (me *portableHandleMap) Forget(h uint64) *Handled {
me.Lock()
defer me.Unlock()
v := me.handles[h]
v.check = 0
me.handles[h] = nil, false
return v
}
func (me *portableHandleMap) Has(h uint64) bool {
me.RLock()
defer me.RUnlock()
return me.handles[h] != nil
}
// 32 bits version of HandleMap
type int32HandleMap struct {
mutex sync.Mutex
......@@ -58,7 +111,7 @@ func (me *int32HandleMap) Count() int {
}
func (me *int32HandleMap) Forget(handle uint64) *Handled {
val := DecodeHandle(handle)
val := me.Decode(handle)
me.mutex.Lock()
defer me.mutex.Unlock()
......@@ -67,12 +120,17 @@ func (me *int32HandleMap) Forget(handle uint64) *Handled {
return val
}
func (me *int32HandleMap) Decode(handle uint64) *Handled {
val := (*Handled)(unsafe.Pointer(uintptr(handle & ((1 << 32) - 1))))
return val
}
// 64 bits version of HandleMap
type int64HandleMap struct {
mutex sync.Mutex
handles map[uint64]*Handled
nextFree uint32
addCheck bool
}
var baseAddress uint64
......@@ -85,7 +143,7 @@ func (me *int64HandleMap) verify() {
me.mutex.Lock()
defer me.mutex.Unlock()
for k, v := range me.handles {
if DecodeHandle(k) != v {
if me.Decode(k) != v {
panic("handle map out of sync")
}
}
......@@ -93,12 +151,18 @@ func (me *int64HandleMap) verify() {
// NewHandleMap creates a new HandleMap. If verify is given, we
// use remaining bits in the handle to store sanity check bits.
func NewHandleMap(verify bool) (hm HandleMap) {
func NewHandleMap(portable bool) (hm HandleMap) {
if portable {
return &portableHandleMap{
nextFree: 2,
handles: make(map[uint64]*Handled),
}
}
var obj *Handled
switch unsafe.Sizeof(obj) {
case 8:
return &int64HandleMap{
addCheck: verify,
handles: make(map[uint64]*Handled),
nextFree: 1, // to make tests easier.
}
......@@ -137,17 +201,15 @@ func (me *int64HandleMap) Register(obj *Handled, asInterface interface{}) (handl
handle -= baseAddress
handle >>= 3
if me.addCheck {
check := me.nextFree
me.nextFree++
me.nextFree = me.nextFree & (1<<(64-48+3) - 1)
handle |= uint64(check) << (48 - 3)
if obj.check != 0 {
panic("Object already has a handle.")
panic(_ALREADY_MSG)
}
obj.check = check
}
obj.object = asInterface
me.handles[handle] = obj
......@@ -157,7 +219,7 @@ func (me *int64HandleMap) Register(obj *Handled, asInterface interface{}) (handl
func (me *int64HandleMap) Forget(handle uint64) (val *Handled) {
defer me.verify()
val = DecodeHandle(handle)
val = me.Decode(handle)
me.mutex.Lock()
defer me.mutex.Unlock()
......@@ -172,16 +234,11 @@ func (me *int64HandleMap) Has(handle uint64) bool {
return me.handles[handle] != nil
}
func DecodeHandle(handle uint64) (val *Handled) {
var check uint32
if unsafe.Sizeof(val) == 8 {
func (me *int64HandleMap) Decode(handle uint64) (val *Handled) {
ptrBits := uintptr(handle & (1<<45 - 1))
check = uint32(handle >> 45)
check := uint32(handle >> 45)
val = (*Handled)(unsafe.Pointer(ptrBits<<3 + uintptr(baseAddress)))
}
if unsafe.Sizeof(val) == 4 {
val = (*Handled)(unsafe.Pointer(uintptr(handle & ((1 << 32) - 1))))
}
if val.check != check {
msg := fmt.Sprintf("handle check mismatch; handle has 0x%x, object has 0x%x: %v",
check, val.check, val.object)
......
......@@ -25,7 +25,7 @@ func TestHandleMapDoubleRegister(t *testing.T) {
}
log.Println("TestDoubleRegister")
defer markSeen("already has a handle")
hm := NewHandleMap(true)
hm := NewHandleMap(false)
obj := &Handled{}
hm.Register(obj, obj)
v := &Handled{}
......@@ -39,7 +39,7 @@ func TestHandleMapUnaligned(t *testing.T) {
t.Log("skipping test for 32 bits")
return
}
hm := NewHandleMap(true)
hm := NewHandleMap(false)
b := make([]byte, 100)
v := (*Handled)(unsafe.Pointer(&b[1]))
......@@ -55,7 +55,7 @@ func TestHandleMapPointerLayout(t *testing.T) {
return
}
hm := NewHandleMap(true)
hm := NewHandleMap(false)
bogus := uint64(1) << uint32((8 * (unsafe.Sizeof(t) - 1)))
p := uintptr(bogus)
v := (*Handled)(unsafe.Pointer(p))
......@@ -65,18 +65,15 @@ func TestHandleMapPointerLayout(t *testing.T) {
}
func TestHandleMapBasic(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
for _, portable := range []bool{true, false} {
v := new(Handled)
hm := NewHandleMap(true)
hm := NewHandleMap(portable)
h := hm.Register(v, v)
log.Printf("Got handle 0x%x", h)
if !hm.Has(h) {
t.Fatal("Does not have handle")
}
if DecodeHandle(h) != v {
if hm.Decode(h) != v {
t.Fatal("address mismatch")
}
if hm.Count() != 1 {
......@@ -92,19 +89,15 @@ func TestHandleMapBasic(t *testing.T) {
if v.check != 0 {
t.Errorf("forgotten object still has a check.")
}
}
}
func TestHandleMapMultiple(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
hm := NewHandleMap(true)
hm := NewHandleMap(false)
for i := 0; i < 10; i++ {
v := &Handled{}
h := hm.Register(v, v)
if DecodeHandle(h) != v {
if hm.Decode(h) != v {
t.Fatal("address mismatch")
}
if hm.Count() != i+1 {
......@@ -121,25 +114,9 @@ func TestHandleMapCheckFail(t *testing.T) {
defer markSeen("check mismatch")
v := new(Handled)
hm := NewHandleMap(true)
hm := NewHandleMap(false)
h := hm.Register(v, v)
DecodeHandle(h | (uint64(1) << 63))
hm.Decode(h | (uint64(1) << 63))
t.Error("Borked decode did not panic")
}
func TestHandleMapNoCheck(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
v := new(Handled)
hm := NewHandleMap(false)
h := hm.Register(v, v)
if h > uint64(0xffffffff) {
t.Errorf("handles should in 32 bit if verification switched off: %x", h)
}
v2 := DecodeHandle(h)
if v2 != v {
t.Errorf("Handle decode error.")
}
}
......@@ -185,7 +185,7 @@ func (me *Inode) rmChild(name string) (ch *Inode) {
func (me *Inode) mountFs(fs NodeFileSystem, opts *FileSystemOptions) {
me.mountPoint = &fileSystemMount{
fs: fs,
openFiles: NewHandleMap(true),
openFiles: NewHandleMap(false),
mountInode: me,
options: opts,
}
......
......@@ -269,14 +269,14 @@ func (me *LockingRawFileSystem) ReleaseDir(header *InHeader, h *ReleaseIn) {
me.RawFileSystem.ReleaseDir(header, h)
}
func (me *LockingRawFileSystem) Read(input *ReadIn, bp BufferPool) ([]byte, Status) {
func (me *LockingRawFileSystem) Read(header *InHeader, input *ReadIn, bp BufferPool) ([]byte, Status) {
defer me.locked()()
return me.RawFileSystem.Read(input, bp)
return me.RawFileSystem.Read(header, input, bp)
}
func (me *LockingRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
func (me *LockingRawFileSystem) Write(header *InHeader, input *WriteIn, data []byte) (written uint32, code Status) {
defer me.locked()()
return me.RawFileSystem.Write(input, data)
return me.RawFileSystem.Write(header, input, data)
}
func (me *LockingRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
......@@ -284,9 +284,9 @@ func (me *LockingRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
return me.RawFileSystem.Flush(header, input)
}
func (me *LockingRawFileSystem) Fsync(input *FsyncIn) (code Status) {
func (me *LockingRawFileSystem) Fsync(header *InHeader, input *FsyncIn) (code Status) {
defer me.locked()()
return me.RawFileSystem.Fsync(input)
return me.RawFileSystem.Fsync(header, input)
}
func (me *LockingRawFileSystem) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
......
......@@ -150,7 +150,7 @@ func doSetattr(state *MountState, req *request) {
}
func doWrite(state *MountState, req *request) {
n, status := state.fileSystem.Write((*WriteIn)(req.inData), req.arg)
n, status := state.fileSystem.Write(req.inHeader, (*WriteIn)(req.inData), req.arg)
o := &WriteOut{
Size: n,
}
......@@ -233,7 +233,7 @@ func doLink(state *MountState, req *request) {
}
func doRead(state *MountState, req *request) {
req.flatData, req.status = state.fileSystem.Read((*ReadIn)(req.inData), state.buffers)
req.flatData, req.status = state.fileSystem.Read(req.inHeader, (*ReadIn)(req.inData), state.buffers)
}
func doFlush(state *MountState, req *request) {
......@@ -245,7 +245,7 @@ func doRelease(state *MountState, req *request) {
}
func doFsync(state *MountState, req *request) {
req.status = state.fileSystem.Fsync((*FsyncIn)(req.inData))
req.status = state.fileSystem.Fsync(req.inHeader, (*FsyncIn)(req.inData))
}
func doReleaseDir(state *MountState, req *request) {
......
......@@ -136,14 +136,14 @@ func (me *TimingRawFileSystem) Release(header *InHeader, input *ReleaseIn) {
me.RawFileSystem.Release(header, input)
}
func (me *TimingRawFileSystem) Read(input *ReadIn, bp BufferPool) ([]byte, Status) {
func (me *TimingRawFileSystem) Read(header *InHeader, input *ReadIn, bp BufferPool) ([]byte, Status) {
defer me.startTimer("Read")()
return me.RawFileSystem.Read(input, bp)
return me.RawFileSystem.Read(header, input, bp)
}
func (me *TimingRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
func (me *TimingRawFileSystem) Write(header *InHeader, input *WriteIn, data []byte) (written uint32, code Status) {
defer me.startTimer("Write")()
return me.RawFileSystem.Write(input, data)
return me.RawFileSystem.Write(header, input, data)
}
func (me *TimingRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
......@@ -151,9 +151,9 @@ func (me *TimingRawFileSystem) Flush(header *InHeader, input *FlushIn) Status {
return me.RawFileSystem.Flush(header, input)
}
func (me *TimingRawFileSystem) Fsync(input *FsyncIn) (code Status) {
func (me *TimingRawFileSystem) Fsync(header *InHeader, input *FsyncIn) (code Status) {
defer me.startTimer("Fsync")()
return me.RawFileSystem.Fsync(input)
return me.RawFileSystem.Fsync(header, input)
}
func (me *TimingRawFileSystem) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
......
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