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
Kirill Smelkov
go-fuse
Commits
94429a4b
Commit
94429a4b
authored
Sep 05, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split up pathfilesystem.go and pathops.go
parent
bad4ee66
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
315 additions
and
345 deletions
+315
-345
fuse/Makefile
fuse/Makefile
+4
-2
fuse/fsconnector.go
fuse/fsconnector.go
+15
-297
fuse/fsinode.go
fuse/fsinode.go
+1
-0
fuse/fsmount.go
fuse/fsmount.go
+109
-0
fuse/fsops.go
fuse/fsops.go
+18
-41
fuse/inode.go
fuse/inode.go
+168
-0
fuse/pathdebug.go
fuse/pathdebug.go
+0
-5
No files found.
fuse/Makefile
View file @
94429a4b
...
...
@@ -11,9 +11,12 @@ MANUAL_GOFILES=api.go \
defaultraw.go
\
direntry.go
\
files.go
\
fsmount.go
\
fsinode.go
\
fsconnector.go
\
fuse.go
\
handle.go
\
inode.go
\
latencymap.go
\
lockingfs.go
\
loggingfs.go
\
...
...
@@ -23,8 +26,7 @@ MANUAL_GOFILES=api.go \
mountstate.go
\
opcode.go
\
pathdebug.go
\
pathfilesystem.go
\
pathops.go
\
fsops.go
\
readonlyfs.go
\
request.go
\
switchfs.go
\
...
...
fuse/
pathfilesystem
.go
→
fuse/
fsconnector
.go
View file @
94429a4b
package
fuse
/*
FilesystemConnector is a lowlevel FUSE filesystem that translates
from inode numbers (as delivered by the kernel) to traditional path
names. The paths are then used as arguments for methods of
FileSystem instances.
FileSystemConnector supports mounts of different FileSystems
on top of each other's directories.
General todos:
- We are doing lookups (incurring GetAttr() costs) for internal
lookups (eg. after doing a symlink). We could probably do without
the GetAttr calls.
*/
// This file contains the internal logic of the
// FileSystemConnector. The functions for satisfying the raw interface are in
// fsops.go
import
(
"fmt"
"log"
"os"
"path/filepath"
"strings"
"sync"
"unsafe"
)
// openedFile stores either an open dir or an open file.
type
openedFile
struct
{
Handled
*
fileSystemMount
*
inode
// O_CREAT, O_TRUNC, etc.
OpenFlags
uint32
// FOPEN_KEEP_CACHE and friends.
FuseFlags
uint32
dir
rawDir
file
File
}
type
fileSystemMount
struct
{
// If non-nil the file system mounted here.
fs
FileSystem
// Node that we were mounted on.
mountInode
*
inode
options
*
FileSystemOptions
// Protects parent/child relations within the mount.
// treeLock should be acquired before openFilesLock
treeLock
sync
.
RWMutex
// Manage filehandles of open files.
openFiles
HandleMap
}
func
(
me
*
fileSystemMount
)
fileInfoToEntry
(
fi
*
os
.
FileInfo
,
out
*
EntryOut
)
{
SplitNs
(
me
.
options
.
EntryTimeout
,
&
out
.
EntryValid
,
&
out
.
EntryValidNsec
)
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
if
!
fi
.
IsDirectory
()
{
fi
.
Nlink
=
1
}
CopyFileInfo
(
fi
,
&
out
.
Attr
)
me
.
setOwner
(
&
out
.
Attr
)
}
func
(
me
*
fileSystemMount
)
fileInfoToAttr
(
fi
*
os
.
FileInfo
,
out
*
AttrOut
)
{
CopyFileInfo
(
fi
,
&
out
.
Attr
)
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
me
.
setOwner
(
&
out
.
Attr
)
}
func
(
me
*
FileSystemConnector
)
getOpenedFile
(
h
uint64
)
*
openedFile
{
b
:=
(
*
openedFile
)(
unsafe
.
Pointer
(
DecodeHandle
(
h
)))
return
b
}
func
(
me
*
fileSystemMount
)
unregisterFileHandle
(
handle
uint64
)
*
openedFile
{
obj
:=
me
.
openFiles
.
Forget
(
handle
)
opened
:=
(
*
openedFile
)(
unsafe
.
Pointer
(
obj
))
node
:=
opened
.
inode
node
.
OpenFilesMutex
.
Lock
()
defer
node
.
OpenFilesMutex
.
Unlock
()
idx
:=
-
1
for
i
,
v
:=
range
node
.
OpenFiles
{
if
v
==
opened
{
idx
=
i
break
}
}
l
:=
len
(
node
.
OpenFiles
)
node
.
OpenFiles
[
idx
]
=
node
.
OpenFiles
[
l
-
1
]
node
.
OpenFiles
=
node
.
OpenFiles
[
:
l
-
1
]
return
opened
}
func
(
me
*
fileSystemMount
)
registerFileHandle
(
node
*
inode
,
dir
rawDir
,
f
File
,
flags
uint32
)
(
uint64
,
*
openedFile
)
{
node
.
OpenFilesMutex
.
Lock
()
defer
node
.
OpenFilesMutex
.
Unlock
()
b
:=
&
openedFile
{
dir
:
dir
,
file
:
f
,
inode
:
node
,
fileSystemMount
:
me
,
OpenFlags
:
flags
,
}
withFlags
,
ok
:=
f
.
(
*
WithFlags
)
if
ok
{
b
.
FuseFlags
=
withFlags
.
Flags
f
=
withFlags
.
File
}
node
.
OpenFiles
=
append
(
node
.
OpenFiles
,
b
)
handle
:=
me
.
openFiles
.
Register
(
&
b
.
Handled
)
return
handle
,
b
}
////////////////
// Tests should set to true.
var
paranoia
=
false
// The inode reflects the kernel's idea of the inode.
type
inode
struct
{
Handled
// Constant during lifetime.
NodeId
uint64
// Number of open files and its protection.
OpenFilesMutex
sync
.
Mutex
OpenFiles
[]
*
openedFile
// treeLock is a pointer to me.mount.treeLock; we need store
// this mutex separately, since unmount may set me.mount = nil
// during Unmount(). Constant during lifetime.
//
// If multiple treeLocks must be acquired, the treeLocks
// closer to the root must be acquired first.
treeLock
*
sync
.
RWMutex
// All data below is protected by treeLock.
fsInode
*
fsInode
Children
map
[
string
]
*
inode
// Contains directories that function as mounts. The entries
// are duplicated in Children.
Mounts
map
[
string
]
*
fileSystemMount
LookupCount
int
// Non-nil if this is a mountpoint.
mountPoint
*
fileSystemMount
// The file system to which this node belongs. Is constant
// during the lifetime, except upon Unmount() when it is set
// to nil.
mount
*
fileSystemMount
}
// Must be called with treeLock for the mount held.
func
(
me
*
inode
)
addChild
(
name
string
,
child
*
inode
)
{
if
paranoia
{
ch
:=
me
.
Children
[
name
]
if
ch
!=
nil
{
panic
(
fmt
.
Sprintf
(
"Already have an inode with same name: %v: %v"
,
name
,
ch
))
}
}
me
.
Children
[
name
]
=
child
me
.
fsInode
.
addChild
(
name
,
child
.
fsInode
)
}
// Must be called with treeLock for the mount held.
func
(
me
*
inode
)
rmChild
(
name
string
)
(
ch
*
inode
)
{
ch
=
me
.
Children
[
name
]
if
ch
!=
nil
{
me
.
Children
[
name
]
=
nil
,
false
me
.
fsInode
.
rmChild
(
name
,
ch
.
fsInode
)
}
return
ch
}
// Can only be called on untouched inodes.
func
(
me
*
inode
)
mountFs
(
fs
FileSystem
,
opts
*
FileSystemOptions
)
{
me
.
mountPoint
=
&
fileSystemMount
{
fs
:
fs
,
openFiles
:
NewHandleMap
(
true
),
mountInode
:
me
,
options
:
opts
,
}
me
.
mount
=
me
.
mountPoint
me
.
treeLock
=
&
me
.
mountPoint
.
treeLock
}
// Must be called with treeLock held.
func
(
me
*
inode
)
canUnmount
()
bool
{
for
_
,
v
:=
range
me
.
Children
{
if
v
.
mountPoint
!=
nil
{
// This access may be out of date, but it is no
// problem to err on the safe side.
return
false
}
if
!
v
.
canUnmount
()
{
return
false
}
}
me
.
OpenFilesMutex
.
Lock
()
defer
me
.
OpenFilesMutex
.
Unlock
()
return
len
(
me
.
OpenFiles
)
==
0
}
// Must be called with treeLock held
func
(
me
*
inode
)
recursiveUnmount
()
{
for
_
,
v
:=
range
me
.
Children
{
v
.
recursiveUnmount
()
}
me
.
mount
=
nil
}
func
(
me
*
inode
)
IsDir
()
bool
{
return
me
.
Children
!=
nil
}
func
(
me
*
inode
)
getMountDirEntries
()
(
out
[]
DirEntry
)
{
me
.
treeLock
.
RLock
()
defer
me
.
treeLock
.
RUnlock
()
for
k
,
_
:=
range
me
.
Mounts
{
out
=
append
(
out
,
DirEntry
{
Name
:
k
,
Mode
:
S_IFDIR
,
})
}
return
out
}
// Returns any open file, preferably a r/w one.
func
(
me
*
inode
)
getAnyFile
()
(
file
File
)
{
me
.
OpenFilesMutex
.
Lock
()
defer
me
.
OpenFilesMutex
.
Unlock
()
for
_
,
f
:=
range
me
.
OpenFiles
{
if
file
==
nil
||
f
.
OpenFlags
&
O_ANYWRITE
!=
0
{
file
=
f
.
file
}
}
return
file
}
// Returns an open writable file for the given inode.
func
(
me
*
inode
)
getWritableFiles
()
(
files
[]
File
)
{
me
.
OpenFilesMutex
.
Lock
()
defer
me
.
OpenFilesMutex
.
Unlock
()
for
_
,
f
:=
range
me
.
OpenFiles
{
if
f
.
OpenFlags
&
O_ANYWRITE
!=
0
{
files
=
append
(
files
,
f
.
file
)
}
}
return
files
}
const
initDirSize
=
20
func
(
me
*
inode
)
verify
(
cur
*
fileSystemMount
)
{
if
me
.
mountPoint
!=
nil
{
if
me
!=
me
.
mountPoint
.
mountInode
{
panic
(
"mountpoint mismatch"
)
}
cur
=
me
.
mountPoint
}
if
me
.
mount
!=
cur
{
panic
(
fmt
.
Sprintf
(
"me.mount not set correctly %v %v"
,
me
.
mount
,
cur
))
}
for
name
,
m
:=
range
me
.
Mounts
{
if
m
.
mountInode
!=
me
.
Children
[
name
]
{
panic
(
fmt
.
Sprintf
(
"mountpoint parent mismatch: node:%v name:%v ch:%v"
,
me
.
mountPoint
,
name
,
me
.
Children
))
}
}
for
_
,
ch
:=
range
me
.
Children
{
if
ch
==
nil
{
panic
(
"Found nil child."
)
}
ch
.
verify
(
cur
)
}
}
func
NewFileSystemOptions
()
*
FileSystemOptions
{
return
&
FileSystemOptions
{
NegativeTimeout
:
0.0
,
...
...
@@ -312,6 +25,7 @@ func NewFileSystemOptions() *FileSystemOptions {
}
}
// FilesystemConnector is a raw FUSE filesystem that manages in-process mounts and inodes.
type
FileSystemConnector
struct
{
DefaultRawFileSystem
...
...
@@ -322,12 +36,17 @@ type FileSystemConnector struct {
rootNode
*
inode
}
func
(
me
*
FileSystemConnector
)
Init
(
fsInit
*
RawFsInit
)
{
me
.
fsInit
=
*
fsInit
}
func
(
me
*
FileSystemConnector
)
Statistics
()
string
{
return
fmt
.
Sprintf
(
"Inodes %20d
\n
"
,
me
.
inodeMap
.
Count
())
func
NewFileSystemConnector
(
fs
FileSystem
,
opts
*
FileSystemOptions
)
(
me
*
FileSystemConnector
)
{
me
=
new
(
FileSystemConnector
)
if
opts
==
nil
{
opts
=
NewFileSystemOptions
()
}
me
.
inodeMap
=
NewHandleMap
(
!
opts
.
SkipCheckHandles
)
me
.
rootNode
=
me
.
newInode
(
true
)
me
.
rootNode
.
NodeId
=
FUSE_ROOT_ID
me
.
verify
()
me
.
mountRoot
(
fs
,
opts
)
return
me
}
func
(
me
*
FileSystemConnector
)
verify
()
{
...
...
@@ -596,7 +315,6 @@ func (me *FileSystemConnector) Unmount(path string) Status {
return
EBUSY
}
mountInode
.
recursiveUnmount
()
mount
.
mountInode
=
nil
mountInode
.
mountPoint
=
nil
...
...
fuse/fsinode.go
View file @
94429a4b
package
fuse
import
(
"log"
"os"
...
...
fuse/fsmount.go
0 → 100644
View file @
94429a4b
package
fuse
import
(
"os"
"sync"
"unsafe"
)
// openedFile stores either an open dir or an open file.
type
openedFile
struct
{
Handled
// O_CREAT, O_TRUNC, etc.
OpenFlags
uint32
// FOPEN_KEEP_CACHE and friends.
FuseFlags
uint32
dir
rawDir
file
File
}
type
fileSystemMount
struct
{
// The file system we mounted here.
fs
FileSystem
// Node that we were mounted on.
mountInode
*
inode
// Options for the mount.
options
*
FileSystemOptions
// Protects Children hashmaps within the mount. treeLock
// should be acquired before openFilesLock
treeLock
sync
.
RWMutex
// Manage filehandles of open files.
openFiles
HandleMap
}
func
(
me
*
fileSystemMount
)
setOwner
(
attr
*
Attr
)
{
if
me
.
options
.
Owner
!=
nil
{
attr
.
Owner
=
*
me
.
options
.
Owner
}
}
func
(
me
*
fileSystemMount
)
fileInfoToEntry
(
fi
*
os
.
FileInfo
,
out
*
EntryOut
)
{
SplitNs
(
me
.
options
.
EntryTimeout
,
&
out
.
EntryValid
,
&
out
.
EntryValidNsec
)
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
if
!
fi
.
IsDirectory
()
{
fi
.
Nlink
=
1
}
CopyFileInfo
(
fi
,
&
out
.
Attr
)
me
.
setOwner
(
&
out
.
Attr
)
}
func
(
me
*
fileSystemMount
)
fileInfoToAttr
(
fi
*
os
.
FileInfo
,
out
*
AttrOut
)
{
CopyFileInfo
(
fi
,
&
out
.
Attr
)
SplitNs
(
me
.
options
.
AttrTimeout
,
&
out
.
AttrValid
,
&
out
.
AttrValidNsec
)
me
.
setOwner
(
&
out
.
Attr
)
}
func
(
me
*
FileSystemConnector
)
getOpenedFile
(
h
uint64
)
*
openedFile
{
b
:=
(
*
openedFile
)(
unsafe
.
Pointer
(
DecodeHandle
(
h
)))
return
b
}
func
(
me
*
fileSystemMount
)
unregisterFileHandle
(
handle
uint64
,
node
*
inode
)
*
openedFile
{
obj
:=
me
.
openFiles
.
Forget
(
handle
)
opened
:=
(
*
openedFile
)(
unsafe
.
Pointer
(
obj
))
node
.
OpenFilesMutex
.
Lock
()
defer
node
.
OpenFilesMutex
.
Unlock
()
idx
:=
-
1
for
i
,
v
:=
range
node
.
OpenFiles
{
if
v
==
opened
{
idx
=
i
break
}
}
l
:=
len
(
node
.
OpenFiles
)
node
.
OpenFiles
[
idx
]
=
node
.
OpenFiles
[
l
-
1
]
node
.
OpenFiles
=
node
.
OpenFiles
[
:
l
-
1
]
return
opened
}
func
(
me
*
fileSystemMount
)
registerFileHandle
(
node
*
inode
,
dir
rawDir
,
f
File
,
flags
uint32
)
(
uint64
,
*
openedFile
)
{
node
.
OpenFilesMutex
.
Lock
()
defer
node
.
OpenFilesMutex
.
Unlock
()
b
:=
&
openedFile
{
dir
:
dir
,
file
:
f
,
OpenFlags
:
flags
,
}
withFlags
,
ok
:=
f
.
(
*
WithFlags
)
if
ok
{
b
.
FuseFlags
=
withFlags
.
Flags
f
=
withFlags
.
File
}
node
.
OpenFiles
=
append
(
node
.
OpenFiles
,
b
)
handle
:=
me
.
openFiles
.
Register
(
&
b
.
Handled
)
return
handle
,
b
}
fuse/
path
ops.go
→
fuse/
fs
ops.go
View file @
94429a4b
//
Translation of raw operation to path based operations.
//
FileSystemConnector's implementation of RawFileSystem
package
fuse
...
...
@@ -11,39 +11,14 @@ import (
var
_
=
log
.
Println
func
NewFileSystemConnector
(
fs
FileSystem
,
opts
*
FileSystemOptions
)
(
me
*
FileSystemConnector
)
{
me
=
new
(
FileSystemConnector
)
if
opts
==
nil
{
opts
=
NewFileSystemOptions
()
}
me
.
inodeMap
=
NewHandleMap
(
!
opts
.
SkipCheckHandles
)
me
.
rootNode
=
me
.
newInode
(
true
)
me
.
rootNode
.
NodeId
=
FUSE_ROOT_ID
me
.
verify
()
me
.
mountRoot
(
fs
,
opts
)
return
me
}
func
(
me
*
FileSystemConnector
)
GetPath
(
nodeid
uint64
)
(
path
string
,
mount
*
fileSystemMount
,
node
*
inode
)
{
n
:=
me
.
getInodeData
(
nodeid
)
p
:=
n
.
fsInode
.
GetPath
()
return
p
,
n
.
mount
,
n
}
func
(
me
*
fileSystemMount
)
setOwner
(
attr
*
Attr
)
{
if
me
.
options
.
Owner
!=
nil
{
attr
.
Owner
=
*
me
.
options
.
Owner
}
func
(
me
*
FileSystemConnector
)
Init
(
fsInit
*
RawFsInit
)
{
me
.
fsInit
=
*
fsInit
}
func
(
me
*
FileSystemConnector
)
Lookup
(
header
*
InHeader
,
name
string
)
(
out
*
EntryOut
,
status
Status
)
{
parent
:=
me
.
getInodeData
(
header
.
NodeId
)
return
me
.
internalLookup
(
parent
,
name
,
1
,
&
header
.
Context
)
}
func
(
me
*
FileSystemConnector
)
internalLookup
(
parent
*
inode
,
name
string
,
lookupCount
int
,
context
*
Context
)
(
out
*
EntryOut
,
status
Status
)
{
out
,
status
,
_
=
me
.
internalLookupWithNode
(
parent
,
name
,
lookupCount
,
context
)
out
,
status
,
_
=
me
.
internalLookup
(
parent
,
name
,
1
,
&
header
.
Context
)
return
out
,
status
}
...
...
@@ -66,7 +41,7 @@ func (me *FileSystemConnector) internalMountLookup(mount *fileSystemMount, looku
return
out
,
OK
,
mount
.
mountInode
}
func
(
me
*
FileSystemConnector
)
internalLookup
WithNode
(
parent
*
inode
,
name
string
,
lookupCount
int
,
context
*
Context
)
(
out
*
EntryOut
,
status
Status
,
node
*
inode
)
{
func
(
me
*
FileSystemConnector
)
internalLookup
(
parent
*
inode
,
name
string
,
lookupCount
int
,
context
*
Context
)
(
out
*
EntryOut
,
status
Status
,
node
*
inode
)
{
if
mount
:=
me
.
lookupMount
(
parent
,
name
,
lookupCount
);
mount
!=
nil
{
return
me
.
internalMountLookup
(
mount
,
lookupCount
)
}
...
...
@@ -206,9 +181,9 @@ func (me *FileSystemConnector) Mknod(header *InHeader, input *MknodIn, name stri
n
:=
me
.
getInodeData
(
header
.
NodeId
)
code
=
n
.
fsInode
.
Mknod
(
name
,
input
.
Mode
,
uint32
(
input
.
Rdev
),
&
header
.
Context
)
if
code
.
Ok
()
{
return
me
.
internalLookup
(
n
,
name
,
1
,
&
header
.
Context
)
out
,
code
,
_
=
me
.
internalLookup
(
n
,
name
,
1
,
&
header
.
Context
)
}
return
nil
,
code
return
out
,
code
}
func
(
me
*
FileSystemConnector
)
Mkdir
(
header
*
InHeader
,
input
*
MkdirIn
,
name
string
)
(
out
*
EntryOut
,
code
Status
)
{
...
...
@@ -216,7 +191,7 @@ func (me *FileSystemConnector) Mkdir(header *InHeader, input *MkdirIn, name stri
code
=
parent
.
fsInode
.
Mkdir
(
name
,
input
.
Mode
,
&
header
.
Context
)
if
code
.
Ok
()
{
out
,
code
=
me
.
internalLookup
(
parent
,
name
,
1
,
&
header
.
Context
)
out
,
code
,
_
=
me
.
internalLookup
(
parent
,
name
,
1
,
&
header
.
Context
)
}
return
out
,
code
}
...
...
@@ -245,9 +220,9 @@ func (me *FileSystemConnector) Symlink(header *InHeader, pointedTo string, linkN
parent
:=
me
.
getInodeData
(
header
.
NodeId
)
code
=
parent
.
fsInode
.
Symlink
(
linkName
,
pointedTo
,
&
header
.
Context
)
if
code
.
Ok
()
{
return
me
.
internalLookup
(
parent
,
linkName
,
1
,
&
header
.
Context
)
out
,
code
,
_
=
me
.
internalLookup
(
parent
,
linkName
,
1
,
&
header
.
Context
)
}
return
nil
,
code
return
out
,
code
}
...
...
@@ -283,7 +258,8 @@ func (me *FileSystemConnector) Link(header *InHeader, input *LinkIn, filename st
return
nil
,
code
}
// TODO - revise this for real hardlinks?
return
me
.
internalLookup
(
parent
,
filename
,
1
,
&
header
.
Context
)
out
,
code
,
_
=
me
.
internalLookup
(
parent
,
filename
,
1
,
&
header
.
Context
)
return
out
,
code
}
func
(
me
*
FileSystemConnector
)
Access
(
header
*
InHeader
,
input
*
AccessIn
)
(
code
Status
)
{
...
...
@@ -298,7 +274,7 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
return
0
,
0
,
nil
,
code
}
out
,
code
,
inode
:=
me
.
internalLookup
WithNode
(
parent
,
name
,
1
,
&
header
.
Context
)
out
,
code
,
inode
:=
me
.
internalLookup
(
parent
,
name
,
1
,
&
header
.
Context
)
if
inode
==
nil
{
msg
:=
fmt
.
Sprintf
(
"Create succeded, but GetAttr returned no entry %v, %q. code %v"
,
header
.
NodeId
,
name
,
code
)
panic
(
msg
)
...
...
@@ -308,18 +284,19 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
}
func
(
me
*
FileSystemConnector
)
Release
(
header
*
InHeader
,
input
*
ReleaseIn
)
{
opened
:=
me
.
getOpenedFile
(
input
.
Fh
)
opened
.
inode
.
mount
.
unregisterFileHandle
(
input
.
Fh
)
node
:=
me
.
getInodeData
(
header
.
NodeId
)
node
.
mount
.
unregisterFileHandle
(
input
.
Fh
,
node
)
}
func
(
me
*
FileSystemConnector
)
Flush
(
header
*
InHeader
,
input
*
FlushIn
)
Status
{
node
:=
me
.
getInodeData
(
header
.
NodeId
)
opened
:=
me
.
getOpenedFile
(
input
.
Fh
)
return
opened
.
i
node
.
fsInode
.
Flush
(
opened
.
file
,
opened
.
OpenFlags
,
&
header
.
Context
)
return
node
.
fsInode
.
Flush
(
opened
.
file
,
opened
.
OpenFlags
,
&
header
.
Context
)
}
func
(
me
*
FileSystemConnector
)
ReleaseDir
(
header
*
InHeader
,
input
*
ReleaseIn
)
{
node
:=
me
.
getInodeData
(
header
.
NodeId
)
opened
:=
node
.
mount
.
unregisterFileHandle
(
input
.
Fh
)
opened
:=
node
.
mount
.
unregisterFileHandle
(
input
.
Fh
,
node
)
opened
.
dir
.
Release
()
me
.
considerDropInode
(
node
)
}
...
...
fuse/inode.go
0 → 100644
View file @
94429a4b
package
fuse
import
(
"fmt"
"sync"
)
// The inode reflects the kernel's idea of the inode.
type
inode
struct
{
Handled
// Constant during lifetime.
NodeId
uint64
// Number of open files and its protection.
OpenFilesMutex
sync
.
Mutex
OpenFiles
[]
*
openedFile
// treeLock is a pointer to me.mount.treeLock; we need store
// this mutex separately, since unmount may set me.mount = nil
// during Unmount(). Constant during lifetime.
//
// If multiple treeLocks must be acquired, the treeLocks
// closer to the root must be acquired first.
treeLock
*
sync
.
RWMutex
// All data below is protected by treeLock.
fsInode
*
fsInode
Children
map
[
string
]
*
inode
// Contains directories that function as mounts. The entries
// are duplicated in Children.
Mounts
map
[
string
]
*
fileSystemMount
LookupCount
int
// Non-nil if this is a mountpoint.
mountPoint
*
fileSystemMount
// The file system to which this node belongs. Is constant
// during the lifetime, except upon Unmount() when it is set
// to nil.
mount
*
fileSystemMount
}
// Must be called with treeLock for the mount held.
func
(
me
*
inode
)
addChild
(
name
string
,
child
*
inode
)
{
if
paranoia
{
ch
:=
me
.
Children
[
name
]
if
ch
!=
nil
{
panic
(
fmt
.
Sprintf
(
"Already have an inode with same name: %v: %v"
,
name
,
ch
))
}
}
me
.
Children
[
name
]
=
child
me
.
fsInode
.
addChild
(
name
,
child
.
fsInode
)
}
// Must be called with treeLock for the mount held.
func
(
me
*
inode
)
rmChild
(
name
string
)
(
ch
*
inode
)
{
ch
=
me
.
Children
[
name
]
if
ch
!=
nil
{
me
.
Children
[
name
]
=
nil
,
false
me
.
fsInode
.
rmChild
(
name
,
ch
.
fsInode
)
}
return
ch
}
// Can only be called on untouched inodes.
func
(
me
*
inode
)
mountFs
(
fs
FileSystem
,
opts
*
FileSystemOptions
)
{
me
.
mountPoint
=
&
fileSystemMount
{
fs
:
fs
,
openFiles
:
NewHandleMap
(
true
),
mountInode
:
me
,
options
:
opts
,
}
me
.
mount
=
me
.
mountPoint
me
.
treeLock
=
&
me
.
mountPoint
.
treeLock
}
// Must be called with treeLock held.
func
(
me
*
inode
)
canUnmount
()
bool
{
for
_
,
v
:=
range
me
.
Children
{
if
v
.
mountPoint
!=
nil
{
// This access may be out of date, but it is no
// problem to err on the safe side.
return
false
}
if
!
v
.
canUnmount
()
{
return
false
}
}
me
.
OpenFilesMutex
.
Lock
()
defer
me
.
OpenFilesMutex
.
Unlock
()
return
len
(
me
.
OpenFiles
)
==
0
}
func
(
me
*
inode
)
IsDir
()
bool
{
return
me
.
Children
!=
nil
}
func
(
me
*
inode
)
getMountDirEntries
()
(
out
[]
DirEntry
)
{
me
.
treeLock
.
RLock
()
defer
me
.
treeLock
.
RUnlock
()
for
k
,
_
:=
range
me
.
Mounts
{
out
=
append
(
out
,
DirEntry
{
Name
:
k
,
Mode
:
S_IFDIR
,
})
}
return
out
}
// Returns any open file, preferably a r/w one.
func
(
me
*
inode
)
getAnyFile
()
(
file
File
)
{
me
.
OpenFilesMutex
.
Lock
()
defer
me
.
OpenFilesMutex
.
Unlock
()
for
_
,
f
:=
range
me
.
OpenFiles
{
if
file
==
nil
||
f
.
OpenFlags
&
O_ANYWRITE
!=
0
{
file
=
f
.
file
}
}
return
file
}
// Returns an open writable file for the given inode.
func
(
me
*
inode
)
getWritableFiles
()
(
files
[]
File
)
{
me
.
OpenFilesMutex
.
Lock
()
defer
me
.
OpenFilesMutex
.
Unlock
()
for
_
,
f
:=
range
me
.
OpenFiles
{
if
f
.
OpenFlags
&
O_ANYWRITE
!=
0
{
files
=
append
(
files
,
f
.
file
)
}
}
return
files
}
const
initDirSize
=
20
func
(
me
*
inode
)
verify
(
cur
*
fileSystemMount
)
{
if
me
.
mountPoint
!=
nil
{
if
me
!=
me
.
mountPoint
.
mountInode
{
panic
(
"mountpoint mismatch"
)
}
cur
=
me
.
mountPoint
}
if
me
.
mount
!=
cur
{
panic
(
fmt
.
Sprintf
(
"me.mount not set correctly %v %v"
,
me
.
mount
,
cur
))
}
for
name
,
m
:=
range
me
.
Mounts
{
if
m
.
mountInode
!=
me
.
Children
[
name
]
{
panic
(
fmt
.
Sprintf
(
"mountpoint parent mismatch: node:%v name:%v ch:%v"
,
me
.
mountPoint
,
name
,
me
.
Children
))
}
}
for
_
,
ch
:=
range
me
.
Children
{
if
ch
==
nil
{
panic
(
"Found nil child."
)
}
ch
.
verify
(
cur
)
}
}
fuse/pathdebug.go
View file @
94429a4b
...
...
@@ -149,11 +149,6 @@ func (me *FileSystemDebug) AddMountState(state *MountState) {
func
()
[]
byte
{
return
[]
byte
(
state
.
BufferPoolStats
())
})
}
func
(
me
*
FileSystemDebug
)
AddFileSystemConnector
(
conn
*
FileSystemConnector
)
{
me
.
Add
(
"filesystemconnector-stats"
,
func
()
[]
byte
{
return
[]
byte
(
conn
.
Statistics
())
})
}
func
hotPaths
(
timing
*
TimingFileSystem
)
[]
byte
{
hot
:=
timing
.
HotPaths
(
"GetAttr"
)
unique
:=
len
(
hot
)
...
...
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