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
7e917a7b
Commit
7e917a7b
authored
Mar 04, 2019
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nodefs: NotifyXxxx functions
parent
02502040
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
93 additions
and
12 deletions
+93
-12
nodefs/README.md
nodefs/README.md
+19
-7
nodefs/bridge.go
nodefs/bridge.go
+3
-1
nodefs/inode.go
nodefs/inode.go
+26
-0
nodefs/simple_test.go
nodefs/simple_test.go
+45
-4
No files found.
nodefs/README.md
View file @
7e917a7b
...
...
@@ -14,22 +14,31 @@ Decisions
*
Nodes can be "persistent", meaning their lifetime is not under
control of the kernel. This is useful for constructing FS trees
in advance.
in advance
, rather than driven by LOOKUP.
.
*
The NodeID for FS tree node must be defined on creation and are
immutable. By contrast, reusing NodeIds (eg. rsc/bazil FUSE, as
well as old go-fuse/fuse/nodefs) is racy when notify and FORGET
operations race.
*
The mode of an Inode is defined on creation. Files cannot change
type during their lifetime. This also prevents the common error
of forgetting to return the filetype in Lookup/GetAttr.
*
The NodeID (used for communicating with kernel) is equal to
Attr.Ino (value shown in Stat and Lstat return values.)
Attr.Ino (value shown in Stat and Lstat return values.)
.
*
No global treelock, to ensure scalability.
*
Immutable characteristics of the Inode are passed on
creation. These are {NodeID, Mode}. Files cannot change type
during their lifetime. It also prevents the common error of
forgetting to return the filetype in Lookup/GetAttr.
*
Support for hard links. libfuse doesn't support this in the
high-level API. Extra care for race conditions is needed when
looking up the same file different paths.
*
do not issue Notify{Entry,Delete} as part of
AddChild/RmChild/MvChild: because NodeIDs are unique and
immutable, there is no confusion about which nodes are
invalidated, and the notification doesn't have to happen under
lock.
To decide
=========
...
...
@@ -71,3 +80,6 @@ To decide
*
Should Operations.Lookup return
*
Inode or Operations ?
*
Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.?
nodefs/bridge.go
View file @
7e917a7b
...
...
@@ -23,6 +23,7 @@ type fileEntry struct {
type
rawBridge
struct
{
options
Options
root
*
Inode
server
*
fuse
.
Server
// mu protects the following data. Locks for inodes must be
// taken before rawBridge.mu
...
...
@@ -539,5 +540,6 @@ func (b *rawBridge) StatFs(input *fuse.InHeader, out *fuse.StatfsOut) (code fuse
return
}
func
(
b
*
rawBridge
)
Init
(
*
fuse
.
Server
)
{
func
(
b
*
rawBridge
)
Init
(
s
*
fuse
.
Server
)
{
b
.
server
=
s
}
nodefs/inode.go
View file @
7e917a7b
...
...
@@ -11,6 +11,8 @@ import (
"strings"
"sync"
"unsafe"
"github.com/hanwen/go-fuse/fuse"
)
var
_
=
log
.
Println
...
...
@@ -519,3 +521,27 @@ retry:
return
}
}
func
(
n
*
Inode
)
NotifyEntry
(
name
string
)
fuse
.
Status
{
return
n
.
bridge
.
server
.
EntryNotify
(
n
.
nodeID
.
Ino
,
name
)
}
// XXX DeleteNotify ?
func
(
n
*
Inode
)
NotifyDelete
(
name
string
,
child
*
Inode
)
fuse
.
Status
{
// XXX arg ordering?
return
n
.
bridge
.
server
.
DeleteNotify
(
n
.
nodeID
.
Ino
,
child
.
nodeID
.
Ino
,
name
)
}
func
(
n
*
Inode
)
NotifyContent
(
off
,
sz
int64
)
fuse
.
Status
{
return
n
.
bridge
.
server
.
InodeNotify
(
n
.
nodeID
.
Ino
,
off
,
sz
)
}
func
(
n
*
Inode
)
WriteCache
(
offset
int64
,
data
[]
byte
)
fuse
.
Status
{
return
n
.
bridge
.
server
.
InodeNotifyStoreCache
(
n
.
nodeID
.
Ino
,
offset
,
data
)
}
func
(
n
*
Inode
)
ReadCache
(
offset
int64
,
dest
[]
byte
)
(
count
int
,
code
fuse
.
Status
)
{
return
n
.
bridge
.
server
.
InodeRetrieveCache
(
n
.
nodeID
.
Ino
,
offset
,
dest
)
}
nodefs/simple_test.go
View file @
7e917a7b
...
...
@@ -10,6 +10,7 @@ import (
"log"
"os"
"path/filepath"
"reflect"
"runtime"
"sync"
"syscall"
...
...
@@ -31,8 +32,9 @@ type testCase struct {
origDir
string
mntDir
string
rawFS
fuse
.
RawFileSystem
server
*
fuse
.
Server
loopback
Operations
rawFS
fuse
.
RawFileSystem
server
*
fuse
.
Server
}
func
(
tc
*
testCase
)
writeOrig
(
path
,
content
string
,
mode
os
.
FileMode
)
{
...
...
@@ -65,10 +67,10 @@ func newTestCase(t *testing.T) *testCase {
t
.
Fatal
(
err
)
}
loopback
:
=
NewLoopback
(
tc
.
origDir
)
tc
.
loopback
=
NewLoopback
(
tc
.
origDir
)
_
=
time
.
Second
oneSec
:=
time
.
Second
tc
.
rawFS
=
NewNodeFS
(
loopback
,
&
Options
{
tc
.
rawFS
=
NewNodeFS
(
tc
.
loopback
,
&
Options
{
Debug
:
testutil
.
VerboseTest
(),
// NOSUBMIT - should run all tests without cache too
...
...
@@ -454,3 +456,42 @@ func TestLink(t *testing.T) {
t
.
Errorf
(
"Lstat after: got %d, want %d"
,
st
.
Ino
,
beforeIno
)
}
}
func
TestNotifyEntry
(
t
*
testing
.
T
)
{
tc
:=
newTestCase
(
t
)
defer
tc
.
Clean
()
orig
:=
tc
.
origDir
+
"/file"
fn
:=
tc
.
mntDir
+
"/file"
if
err
:=
ioutil
.
WriteFile
(
orig
,
[]
byte
(
"hello"
),
0644
);
err
!=
nil
{
t
.
Fatalf
(
"WriteFile: %v"
,
err
)
}
st
:=
syscall
.
Stat_t
{}
if
err
:=
syscall
.
Lstat
(
fn
,
&
st
);
err
!=
nil
{
t
.
Fatalf
(
"Lstat before: %v"
,
err
)
}
if
err
:=
os
.
Remove
(
orig
);
err
!=
nil
{
t
.
Fatalf
(
"Remove: %v"
,
err
)
}
after
:=
syscall
.
Stat_t
{}
if
err
:=
syscall
.
Lstat
(
fn
,
&
after
);
err
!=
nil
{
t
.
Fatalf
(
"Lstat after: %v"
,
err
)
}
else
if
!
reflect
.
DeepEqual
(
st
,
after
)
{
t
.
Fatalf
(
"got after %#v, want %#v"
,
after
,
st
)
}
if
code
:=
InodeOf
(
tc
.
loopback
)
.
NotifyEntry
(
"file"
);
!
code
.
Ok
()
{
t
.
Errorf
(
"notify failed: %v"
,
code
)
}
if
err
:=
syscall
.
Lstat
(
fn
,
&
after
);
err
!=
syscall
.
ENOENT
{
t
.
Fatalf
(
"Lstat after: got %v, want ENOENT"
,
err
)
}
}
// Test Notify() , but requires KEEP_CACHE.
// Test NotifyDelete?
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