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 (
)
// 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
// (16+3 on x64_64 and 32 on x86) to do an extra sanity check on the
// data. (Thanks to Russ Cox for this suggestion). In addition, it
// stores the object in a map, so the Go runtime will not garbage
// collect it.
// be given out to -say- the linux kernel. It uses the free bits on
// x64_64 (16+3) to do an extra sanity check on the data. (Thanks to
// Russ Cox for this suggestion). In addition, it stores the object
// in a map, so the Go runtime will not garbage 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
// you wish to export.
//
// 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
handles map[uint64]*Handled
nextFree uint32
}
func (me *HandleMap) verify() {
func (me *int64HandleMap) verify() {
if !paranoia {
return
}
......@@ -37,52 +81,51 @@ func (me *HandleMap) verify() {
}
}
func NewHandleMap() *HandleMap {
return &HandleMap{
handles: make(map[uint64]*Handled),
nextFree: 1, // to make tests easier.
func NewHandleMap() (hm HandleMap) {
var obj *Handled
switch unsafe.Sizeof(obj) {
case 8:
return &int64HandleMap{
handles: make(map[uint64]*Handled),
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()
defer me.mutex.Unlock()
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()
defer me.mutex.Unlock()
handle = uint64(uintptr(unsafe.Pointer(obj)))
check := me.nextFree
me.nextFree++
if unsafe.Sizeof(obj) == 8 {
me.nextFree = me.nextFree & (1<<(64-48+3) - 1)
rest := (handle &^ (1<<48 - 1))
if rest != 0 {
panic("more than 48 bits in address")
}
if handle&0x7 != 0 {
panic("unaligned ptr")
}
handle >>= 3
handle |= uint64(check) << (48 - 3)
}
me.nextFree = me.nextFree & (1<<(64-48+3) - 1)
if unsafe.Sizeof(obj) == 4 {
rest := (handle & 0x3)
if rest != 0 {
panic("unaligned ptr")
}
handle |= uint64(check) << 32
rest := (handle &^ (1<<48 - 1))
if rest != 0 {
panic("more than 48 bits in address")
}
if handle&0x7 != 0 {
panic("unaligned ptr")
}
handle >>= 3
handle |= uint64(check) << (48 - 3)
if obj.check != 0 {
panic("Object already has a handle.")
}
......@@ -91,7 +134,9 @@ func (me *HandleMap) Register(obj *Handled) (handle uint64) {
return handle
}
func (me *HandleMap) Forget(handle uint64) (val *Handled) {
func (me *int64HandleMap) Forget(handle uint64) (val *Handled) {
defer me.verify()
val = DecodeHandle(handle)
me.mutex.Lock()
......@@ -109,7 +154,6 @@ func DecodeHandle(handle uint64) (val *Handled) {
val = (*Handled)(unsafe.Pointer(ptrBits << 3))
}
if unsafe.Sizeof(val) == 4 {
check = uint32(handle >> 32)
val = (*Handled)(unsafe.Pointer(uintptr(handle & ((1 << 32) - 1))))
}
if val.check != check {
......
......@@ -19,6 +19,10 @@ func markSeen(substr string) {
}
func TestHandleMapDoubleRegister(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
log.Println("TestDoubleRegister")
defer markSeen("already has a handle")
hm := NewHandleMap()
......@@ -30,6 +34,10 @@ func TestHandleMapDoubleRegister(t *testing.T) {
}
func TestHandleMapUnaligned(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
hm := NewHandleMap()
b := make([]byte, 100)
......@@ -41,7 +49,8 @@ func TestHandleMapUnaligned(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
}
......@@ -55,6 +64,10 @@ func TestHandleMapPointerLayout(t *testing.T) {
}
func TestHandleMapBasic(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
v := new(Handled)
hm := NewHandleMap()
h := hm.Register(v)
......@@ -72,6 +85,10 @@ func TestHandleMapBasic(t *testing.T) {
}
func TestHandleMapMultiple(t *testing.T) {
if unsafe.Sizeof(t) < 8 {
t.Log("skipping test for 32 bits")
return
}
hm := NewHandleMap()
for i := 0; i < 10; i++ {
v := &Handled{}
......@@ -86,6 +103,10 @@ func TestHandleMapMultiple(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")
v := new(Handled)
......
......@@ -55,7 +55,7 @@ type fileSystemMount struct {
treeLock sync.RWMutex
// Manage filehandles of open files.
openFiles *HandleMap
openFiles HandleMap
}
func (me *FileSystemConnector) getOpenedFile(h uint64) *openedFile {
......@@ -306,7 +306,7 @@ type FileSystemConnector struct {
Debug bool
inodeMap *HandleMap
inodeMap HandleMap
rootNode *inode
}
......@@ -318,7 +318,6 @@ func (me *FileSystemConnector) verify() {
if !paranoia {
return
}
me.inodeMap.verify()
root := me.rootNode
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