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

Split up handle map in 64 and 32 bits.

For 32 bit platforms, we don't want to generate 64 bit inode numbers,
as that will cause EOVERFLOW when running stat() and friends.
parent 382f4469
...@@ -7,23 +7,67 @@ import ( ...@@ -7,23 +7,67 @@ import (
) )
// HandleMap translates objects in Go space to 64-bit handles that can // HandleMap translates objects in Go space to 64-bit handles that can
// be given out to -say- the linux kernel. It uses the free bits // be given out to -say- the linux kernel. It uses the free bits on
// (16+3 on x64_64 and 32 on x86) to do an extra sanity check on the // x64_64 (16+3) to do an extra sanity check on the data. (Thanks to
// data. (Thanks to Russ Cox for this suggestion). In addition, it // Russ Cox for this suggestion). In addition, it stores the object
// stores the object in a map, so the Go runtime will not garbage // in a map, so the Go runtime will not garbage collect it.
// collect it. //
// The 32 bits version of this is a threadsafe wrapper around a map.
// //
// To use it, include Handled as first member of the structure // To use it, include Handled as first member of the structure
// you wish to export. // you wish to export.
// //
// This structure is thread-safe. // This structure is thread-safe.
type HandleMap struct { type HandleMap interface {
Register(obj *Handled) uint64
Count() int
Forget(uint64) *Handled
}
// TODO - store interface{} pointer to wrapped object.
type Handled struct {
check uint32
}
// 32 bits version of HandleMap
type int32HandleMap struct {
mutex sync.Mutex
handles map[uint32]*Handled
}
func (me *int32HandleMap) Register(obj *Handled) uint64 {
me.mutex.Lock()
defer me.mutex.Unlock()
handle := uint32(uintptr(unsafe.Pointer(obj)))
me.handles[handle] = obj
return uint64(handle)
}
func (me *int32HandleMap) Count() int {
me.mutex.Lock()
defer me.mutex.Unlock()
return len(me.handles)
}
func (me *int32HandleMap) Forget(handle uint64) *Handled {
val := DecodeHandle(handle)
me.mutex.Lock()
defer me.mutex.Unlock()
val.check = 0
me.handles[uint32(handle)] = nil, false
return val
}
// 64 bits version of HandleMap
type int64HandleMap struct {
mutex sync.Mutex mutex sync.Mutex
handles map[uint64]*Handled handles map[uint64]*Handled
nextFree uint32 nextFree uint32
} }
func (me *HandleMap) verify() { func (me *int64HandleMap) verify() {
if !paranoia { if !paranoia {
return return
} }
...@@ -37,31 +81,39 @@ func (me *HandleMap) verify() { ...@@ -37,31 +81,39 @@ func (me *HandleMap) verify() {
} }
} }
func NewHandleMap() *HandleMap { func NewHandleMap() (hm HandleMap) {
return &HandleMap{ var obj *Handled
switch unsafe.Sizeof(obj) {
case 8:
return &int64HandleMap{
handles: make(map[uint64]*Handled), handles: make(map[uint64]*Handled),
nextFree: 1, // to make tests easier. nextFree: 1, // to make tests easier.
} }
case 4:
return &int32HandleMap{
handles: make(map[uint32]*Handled),
}
}
return nil
} }
type Handled struct {
check uint32
}
func (me *HandleMap) Count() int { func (me *int64HandleMap) Count() int {
me.mutex.Lock() me.mutex.Lock()
defer me.mutex.Unlock() defer me.mutex.Unlock()
return len(me.handles) return len(me.handles)
} }
func (me *HandleMap) Register(obj *Handled) (handle uint64) { func (me *int64HandleMap) Register(obj *Handled) (handle uint64) {
defer me.verify()
me.mutex.Lock() me.mutex.Lock()
defer me.mutex.Unlock() defer me.mutex.Unlock()
handle = uint64(uintptr(unsafe.Pointer(obj))) handle = uint64(uintptr(unsafe.Pointer(obj)))
check := me.nextFree check := me.nextFree
me.nextFree++ me.nextFree++
if unsafe.Sizeof(obj) == 8 {
me.nextFree = me.nextFree & (1<<(64-48+3) - 1) me.nextFree = me.nextFree & (1<<(64-48+3) - 1)
rest := (handle &^ (1<<48 - 1)) rest := (handle &^ (1<<48 - 1))
...@@ -73,16 +125,7 @@ func (me *HandleMap) Register(obj *Handled) (handle uint64) { ...@@ -73,16 +125,7 @@ func (me *HandleMap) Register(obj *Handled) (handle uint64) {
} }
handle >>= 3 handle >>= 3
handle |= uint64(check) << (48 - 3) handle |= uint64(check) << (48 - 3)
}
if unsafe.Sizeof(obj) == 4 {
rest := (handle & 0x3)
if rest != 0 {
panic("unaligned ptr")
}
handle |= uint64(check) << 32
}
if obj.check != 0 { if obj.check != 0 {
panic("Object already has a handle.") panic("Object already has a handle.")
} }
...@@ -91,7 +134,9 @@ func (me *HandleMap) Register(obj *Handled) (handle uint64) { ...@@ -91,7 +134,9 @@ func (me *HandleMap) Register(obj *Handled) (handle uint64) {
return handle return handle
} }
func (me *HandleMap) Forget(handle uint64) (val *Handled) { func (me *int64HandleMap) Forget(handle uint64) (val *Handled) {
defer me.verify()
val = DecodeHandle(handle) val = DecodeHandle(handle)
me.mutex.Lock() me.mutex.Lock()
...@@ -109,7 +154,6 @@ func DecodeHandle(handle uint64) (val *Handled) { ...@@ -109,7 +154,6 @@ func DecodeHandle(handle uint64) (val *Handled) {
val = (*Handled)(unsafe.Pointer(ptrBits << 3)) val = (*Handled)(unsafe.Pointer(ptrBits << 3))
} }
if unsafe.Sizeof(val) == 4 { if unsafe.Sizeof(val) == 4 {
check = uint32(handle >> 32)
val = (*Handled)(unsafe.Pointer(uintptr(handle & ((1 << 32) - 1)))) val = (*Handled)(unsafe.Pointer(uintptr(handle & ((1 << 32) - 1))))
} }
if val.check != check { if val.check != check {
......
...@@ -19,6 +19,10 @@ func markSeen(substr string) { ...@@ -19,6 +19,10 @@ func markSeen(substr string) {
} }
func TestHandleMapDoubleRegister(t *testing.T) { func TestHandleMapDoubleRegister(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
log.Println("TestDoubleRegister") log.Println("TestDoubleRegister")
defer markSeen("already has a handle") defer markSeen("already has a handle")
hm := NewHandleMap() hm := NewHandleMap()
...@@ -30,6 +34,10 @@ func TestHandleMapDoubleRegister(t *testing.T) { ...@@ -30,6 +34,10 @@ func TestHandleMapDoubleRegister(t *testing.T) {
} }
func TestHandleMapUnaligned(t *testing.T) { func TestHandleMapUnaligned(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
hm := NewHandleMap() hm := NewHandleMap()
b := make([]byte, 100) b := make([]byte, 100)
...@@ -41,7 +49,8 @@ func TestHandleMapUnaligned(t *testing.T) { ...@@ -41,7 +49,8 @@ func TestHandleMapUnaligned(t *testing.T) {
} }
func TestHandleMapPointerLayout(t *testing.T) { func TestHandleMapPointerLayout(t *testing.T) {
if unsafe.Sizeof(t) == 4 { if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return return
} }
...@@ -55,6 +64,10 @@ func TestHandleMapPointerLayout(t *testing.T) { ...@@ -55,6 +64,10 @@ func TestHandleMapPointerLayout(t *testing.T) {
} }
func TestHandleMapBasic(t *testing.T) { func TestHandleMapBasic(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
v := new(Handled) v := new(Handled)
hm := NewHandleMap() hm := NewHandleMap()
h := hm.Register(v) h := hm.Register(v)
...@@ -72,6 +85,10 @@ func TestHandleMapBasic(t *testing.T) { ...@@ -72,6 +85,10 @@ func TestHandleMapBasic(t *testing.T) {
} }
func TestHandleMapMultiple(t *testing.T) { func TestHandleMapMultiple(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
hm := NewHandleMap() hm := NewHandleMap()
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
v := &Handled{} v := &Handled{}
...@@ -86,6 +103,10 @@ func TestHandleMapMultiple(t *testing.T) { ...@@ -86,6 +103,10 @@ func TestHandleMapMultiple(t *testing.T) {
} }
func TestHandleMapCheckFail(t *testing.T) { func TestHandleMapCheckFail(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
defer markSeen("check mismatch") defer markSeen("check mismatch")
v := new(Handled) v := new(Handled)
......
...@@ -55,7 +55,7 @@ type fileSystemMount struct { ...@@ -55,7 +55,7 @@ type fileSystemMount struct {
treeLock sync.RWMutex treeLock sync.RWMutex
// Manage filehandles of open files. // Manage filehandles of open files.
openFiles *HandleMap openFiles HandleMap
} }
func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile { func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
...@@ -306,7 +306,7 @@ type FileSystemConnector struct { ...@@ -306,7 +306,7 @@ type FileSystemConnector struct {
Debug bool Debug bool
inodeMap *HandleMap inodeMap HandleMap
rootNode *inode rootNode *inode
} }
...@@ -318,7 +318,6 @@ func (me *FileSystemConnector) verify() { ...@@ -318,7 +318,6 @@ func (me *FileSystemConnector) verify() {
if !paranoia { if !paranoia {
return return
} }
me.inodeMap.verify()
root := me.rootNode root := me.rootNode
root.verify(me.rootNode.mountPoint) root.verify(me.rootNode.mountPoint)
} }
......
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