Commit 2882eb9e authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Add a verify() method to PathFileSystemConnector.

Fix a corner cases with RENAME. Fix a inode leak with FORGET.
parent 703cbead
...@@ -39,7 +39,8 @@ type testCase struct { ...@@ -39,7 +39,8 @@ type testCase struct {
// Create and mount filesystem. // Create and mount filesystem.
func (me *testCase) Setup(t *testing.T) { func (me *testCase) Setup(t *testing.T) {
me.tester = t me.tester = t
paranoia = true
const name string = "hello.txt" const name string = "hello.txt"
const subdir string = "subdir" const subdir string = "subdir"
......
...@@ -33,6 +33,9 @@ func newMount(fs PathFilesystem) *mountData { ...@@ -33,6 +33,9 @@ func newMount(fs PathFilesystem) *mountData {
return &mountData{fs: fs} return &mountData{fs: fs}
} }
// Tests should set to true.
var paranoia = false
// TODO should rename to dentry? // TODO should rename to dentry?
type inodeData struct { type inodeData struct {
Parent *inodeData Parent *inodeData
...@@ -48,6 +51,19 @@ type inodeData struct { ...@@ -48,6 +51,19 @@ type inodeData struct {
mount *mountData mount *mountData
} }
func (me *inodeData) verify(c *PathFileSystemConnector) {
if me.Parent != nil {
k := inodeDataKey(me.Parent.NodeId, me.Name)
n := c.lookup(k)
if n != me {
panic(fmt.Sprintf("parent/child relation corrupted %v %v %v",
k, n, me))
}
} else {
// may both happen for deleted and root node.
}
}
// Should implement some hash table method instead? // Should implement some hash table method instead?
func inodeDataKey(parentInode uint64, name string) string { func inodeDataKey(parentInode uint64, name string) string {
return string(parentInode) + ":" + name return string(parentInode) + ":" + name
...@@ -129,6 +145,18 @@ type PathFileSystemConnector struct { ...@@ -129,6 +145,18 @@ type PathFileSystemConnector struct {
Debug bool Debug bool
} }
func (me *PathFileSystemConnector) verify() {
if !paranoia {
return
}
for k, v := range me.inodePathMapByInode {
if v.NodeId != k {
panic(fmt.Sprintf("Nodeid mismatch", k, v.NodeId, v))
}
v.verify(me)
}
}
// Must be called with lock held. // Must be called with lock held.
func (me *PathFileSystemConnector) setParent(data *inodeData, parentId uint64) { func (me *PathFileSystemConnector) setParent(data *inodeData, parentId uint64) {
newParent := me.inodePathMapByInode[parentId] newParent := me.inodePathMapByInode[parentId]
...@@ -165,6 +193,8 @@ func (me *PathFileSystemConnector) lookup(key string) *inodeData { ...@@ -165,6 +193,8 @@ func (me *PathFileSystemConnector) lookup(key string) *inodeData {
} }
func (me *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *inodeData { func (me *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *inodeData {
defer me.verify()
key := inodeDataKey(nodeId, name) key := inodeDataKey(nodeId, name)
data := me.lookup(key) data := me.lookup(key)
if data != nil { if data != nil {
...@@ -201,6 +231,7 @@ func (me *PathFileSystemConnector) getInodeData(nodeid uint64) *inodeData { ...@@ -201,6 +231,7 @@ func (me *PathFileSystemConnector) getInodeData(nodeid uint64) *inodeData {
} }
func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) { func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) {
defer me.verify()
me.lock.Lock() me.lock.Lock()
defer me.lock.Unlock() defer me.lock.Unlock()
...@@ -214,12 +245,14 @@ func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int) ...@@ -214,12 +245,14 @@ func (me *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int)
} }
if data.LookupCount <= 0 && data.RefCount <= 0 && (data.mount == nil || data.mount.unmountPending) { if data.LookupCount <= 0 && data.RefCount <= 0 && (data.mount == nil || data.mount.unmountPending) {
me.inodePathMapByInode[nodeId] = nil, false
me.inodePathMap[data.Key()] = nil, false me.inodePathMap[data.Key()] = nil, false
} }
} }
} }
func (me *PathFileSystemConnector) renameUpdate(oldParent uint64, oldName string, newParent uint64, newName string) { func (me *PathFileSystemConnector) renameUpdate(oldParent uint64, oldName string, newParent uint64, newName string) {
defer me.verify()
me.lock.Lock() me.lock.Lock()
defer me.lock.Unlock() defer me.lock.Unlock()
...@@ -259,11 +292,11 @@ func (me *PathFileSystemConnector) renameUpdate(oldParent uint64, oldName string ...@@ -259,11 +292,11 @@ func (me *PathFileSystemConnector) renameUpdate(oldParent uint64, oldName string
me.inodePathMap[target.Key()] = target me.inodePathMap[target.Key()] = target
} }
me.inodePathMap[data.Key()] = data me.inodePathMap[data.Key()] = data
} }
func (me *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) { func (me *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) {
defer me.verify()
me.lock.Lock() me.lock.Lock()
defer me.lock.Unlock() defer me.lock.Unlock()
...@@ -272,6 +305,7 @@ func (me *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) { ...@@ -272,6 +305,7 @@ func (me *PathFileSystemConnector) unlinkUpdate(nodeid uint64, name string) {
if data != nil { if data != nil {
me.inodePathMap[oldKey] = nil, false me.inodePathMap[oldKey] = nil, false
data.Parent = nil
me.unrefNode(data) me.unrefNode(data)
} }
} }
......
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