Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Levin Zimmermann
go-fuse
Commits
153c7b5f
Commit
153c7b5f
authored
Dec 27, 2010
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add reference counting to the inodeDate in pathfilesystem.go
parent
559b73ca
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
68 additions
and
27 deletions
+68
-27
fuse/pathfilesystem.go
fuse/pathfilesystem.go
+68
-27
No files found.
fuse/pathfilesystem.go
View file @
153c7b5f
...
...
@@ -8,14 +8,17 @@ import (
"strings"
)
// TODO should rename to dentry?
type
inodeData
struct
{
Parent
*
inodeData
NodeId
uint64
Name
string
Count
int
LookupCount
int
// Number of inodeData that have this as parent.
RefCount
int
}
// Should implement some hash table method instead?
func
inodeDataKey
(
parentInode
uint64
,
name
string
)
string
{
// TODO - use something more efficient than Sprintf.
...
...
@@ -44,16 +47,57 @@ func (self *inodeData) GetPath() string {
return
fullPath
}
type
PathFileSystemConnector
struct
{
fileSystem
PathFilesystem
// Protects the hashmap, its contents and the nextFreeInode counter.
lock
sync
.
RWMutex
// Invariants
// - For all values, (RefCount > 0 || LookupCount > 0).
// - For all values, value = inodePathMap[value.Key()]
// - For all values, value = inodePathMapByInode[value.NodeId]
// fuse.c seems to have different lifetimes for the different
// hashtables, which could lead to the same directory entry
// existing twice with different generated inode numbers, if
// we have (FORGET, LOOKUP) on a directory entry with RefCount
// > 0.
inodePathMap
map
[
string
]
*
inodeData
inodePathMapByInode
map
[
uint64
]
*
inodeData
nextFreeInode
uint64
}
// Must be called with lock held.
func
(
self
*
PathFileSystemConnector
)
setParent
(
data
*
inodeData
,
parentId
uint64
)
{
newParent
:=
self
.
inodePathMapByInode
[
parentId
]
if
data
.
Parent
==
newParent
{
return
}
if
newParent
==
nil
{
panic
(
"Unknown parent"
)
}
oldParent
:=
data
.
Parent
if
oldParent
!=
nil
{
self
.
unrefNode
(
oldParent
)
}
data
.
Parent
=
newParent
if
newParent
!=
nil
{
newParent
.
RefCount
++
}
}
// Must be called with lock held.
func
(
self
*
PathFileSystemConnector
)
unrefNode
(
data
*
inodeData
)
{
data
.
RefCount
--
if
data
.
RefCount
<=
0
&&
data
.
LookupCount
<=
0
{
self
.
inodePathMapByInode
[
data
.
NodeId
]
=
nil
,
false
}
}
func
(
self
*
PathFileSystemConnector
)
lookupUpdate
(
nodeId
uint64
,
name
string
)
*
inodeData
{
self
.
lock
.
Lock
()
defer
self
.
lock
.
Unlock
()
...
...
@@ -62,18 +106,16 @@ func (self *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *i
data
,
ok
:=
self
.
inodePathMap
[
key
]
if
!
ok
{
data
=
new
(
inodeData
)
data
.
Parent
=
parent
self
.
setParent
(
data
,
nodeId
)
data
.
NodeId
=
self
.
nextFreeInode
data
.
Name
=
name
data
.
Count
=
0
self
.
nextFreeInode
++
self
.
inodePathMapByInode
[
data
.
NodeId
]
=
data
self
.
inodePathMap
[
key
]
=
data
}
data
.
Count
++
data
.
Lookup
Count
++
return
data
}
...
...
@@ -90,19 +132,18 @@ func (self *PathFileSystemConnector) forgetUpdate(nodeId uint64, forgetCount int
data
,
ok
:=
self
.
inodePathMapByInode
[
nodeId
]
if
ok
{
data
.
Count
-=
forgetCount
if
data
.
Count
<=
0
{
data
.
Lookup
Count
-=
forgetCount
if
data
.
LookupCount
<=
0
&&
data
.
Ref
Count
<=
0
{
self
.
inodePathMap
[
data
.
Key
()]
=
nil
,
false
self
.
inodePathMapByInode
[
h
.
NodeId
]
=
nil
,
false
}
}
}
func
(
self
*
PathFileSystemConnector
)
renameUpdate
(
old
Node
uint64
,
oldName
string
,
newNode
uint64
,
newName
string
)
{
func
(
self
*
PathFileSystemConnector
)
renameUpdate
(
old
Parent
uint64
,
oldName
string
,
newParent
uint64
,
newName
string
)
{
self
.
lock
.
Lock
()
defer
self
.
lock
.
Unlock
()
oldKey
=
inodeDataKey
(
oldNode
,
oldName
)
oldKey
:=
inodeDataKey
(
oldParent
,
oldName
)
data
:=
self
.
inodePathMap
[
oldKey
]
if
data
==
nil
{
// This can happen if a rename raced with an unlink or
...
...
@@ -116,14 +157,11 @@ func (self *PathFileSystemConnector) renameUpdate(oldNode uint64, oldName strin
self
.
inodePathMap
[
oldKey
]
=
nil
,
false
data
.
Parent
=
self
.
inodePathMapByInode
[
input
.
Newdir
]
self
.
setParent
(
data
,
newParent
)
data
.
Name
=
newName
newKey
:=
data
.
Key
()
if
data
.
Parent
==
nil
{
panic
(
"Moved to unknown node."
)
}
target
:=
self
.
inodePathMap
[
data
.
Key
()]
target
:=
self
.
inodePathMap
[
newKey
]
if
target
!=
nil
{
// This could happen if some other thread creates a
// file in the destination position.
...
...
@@ -131,30 +169,30 @@ func (self *PathFileSystemConnector) renameUpdate(oldNode uint64, oldName strin
// TODO - Does the VFS layer allow this?
//
// fuse.c just removes the node from its internal
// tables, which
will break things if it is already
//
referenced as a parent object.
// tables, which
might lead to paths being both directories
//
(parents) and normal files?
self
.
inodePathMap
[
newKey
]
=
nil
,
false
target
.
Parent
=
self
.
inodePathMapByInode
[
FUSE_ROOT_ID
]
target
.
Name
=
fmt
.
Sprintf
(
"overwrittenByRename%d"
,
nextFreeInode
)
nextFreeInode
++
;
self
.
setParent
(
target
,
FUSE_ROOT_ID
)
target
.
Name
=
fmt
.
Sprintf
(
"overwrittenByRename%d"
,
self
.
nextFreeInode
)
self
.
nextFreeInode
++
;
self
.
inodePathMap
[
target
.
Key
()]
=
target
}
self
.
inodePathMap
[
newKey
]
=
data
self
.
inodePathMap
[
data
.
Key
()
]
=
data
}
func
(
self
*
PathFileSystemConnector
)
unlinkUpdate
(
nodeid
uint64
,
name
string
)
{
self
.
lock
.
Lock
()
defer
self
.
lock
.
Unlock
()
oldKey
=
inodeDataKey
(
nodeid
,
name
)
oldKey
:
=
inodeDataKey
(
nodeid
,
name
)
data
:=
self
.
inodePathMap
[
oldKey
]
if
data
!=
nil
{
self
.
inodePathMap
[
oldKey
]
=
nil
,
false
self
.
inodePathMapByInode
[
data
.
NodeId
]
=
nil
,
false
self
.
unrefNode
(
data
)
}
}
...
...
@@ -170,7 +208,6 @@ func NewPathFileSystemConnector(fs PathFilesystem) (out *PathFileSystemConnector
out
.
fileSystem
=
fs
rootData
:=
new
(
inodeData
)
rootData
.
Count
=
1
rootData
.
NodeId
=
FUSE_ROOT_ID
out
.
inodePathMap
[
rootData
.
Key
()]
=
rootData
...
...
@@ -198,13 +235,17 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
panic
(
"Parent inode unknown."
)
}
// Hmm. - fuse.c has special case code for name == "." and "..".
// Should we have it too?
fullPath
:=
path
.
Join
(
parent
.
GetPath
(),
name
)
attr
,
err
:=
self
.
fileSystem
.
GetAttr
(
fullPath
)
if
err
!=
OK
{
// TODO - set a EntryValid timeout on ENOENT.
return
nil
,
err
}
data
:=
lookupUpdate
(
header
.
NodeId
,
name
)
data
:=
self
.
lookupUpdate
(
header
.
NodeId
,
name
)
out
=
new
(
EntryOut
)
out
.
NodeId
=
data
.
NodeId
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment