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
...
@@ -14,22 +14,31 @@ Decisions
*
Nodes can be "persistent", meaning their lifetime is not under
*
Nodes can be "persistent", meaning their lifetime is not under
control of the kernel. This is useful for constructing FS trees
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
*
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.
*
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
*
Support for hard links. libfuse doesn't support this in the
high-level API. Extra care for race conditions is needed when
high-level API. Extra care for race conditions is needed when
looking up the same file different paths.
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
To decide
=========
=========
...
@@ -71,3 +80,6 @@ To decide
...
@@ -71,3 +80,6 @@ To decide
*
Should Operations.Lookup return
*
Inode or Operations ?
*
Should Operations.Lookup return
*
Inode or Operations ?
*
Should bridge.Lookup() add the child, bridge.Unlink remove the child, etc.?
*
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 {
...
@@ -23,6 +23,7 @@ type fileEntry struct {
type
rawBridge
struct
{
type
rawBridge
struct
{
options
Options
options
Options
root
*
Inode
root
*
Inode
server
*
fuse
.
Server
// mu protects the following data. Locks for inodes must be
// mu protects the following data. Locks for inodes must be
// taken before rawBridge.mu
// taken before rawBridge.mu
...
@@ -539,5 +540,6 @@ func (b *rawBridge) StatFs(input *fuse.InHeader, out *fuse.StatfsOut) (code fuse
...
@@ -539,5 +540,6 @@ func (b *rawBridge) StatFs(input *fuse.InHeader, out *fuse.StatfsOut) (code fuse
return
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 (
...
@@ -11,6 +11,8 @@ import (
"strings"
"strings"
"sync"
"sync"
"unsafe"
"unsafe"
"github.com/hanwen/go-fuse/fuse"
)
)
var
_
=
log
.
Println
var
_
=
log
.
Println
...
@@ -519,3 +521,27 @@ retry:
...
@@ -519,3 +521,27 @@ retry:
return
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 (
...
@@ -10,6 +10,7 @@ import (
"log"
"log"
"os"
"os"
"path/filepath"
"path/filepath"
"reflect"
"runtime"
"runtime"
"sync"
"sync"
"syscall"
"syscall"
...
@@ -31,8 +32,9 @@ type testCase struct {
...
@@ -31,8 +32,9 @@ type testCase struct {
origDir
string
origDir
string
mntDir
string
mntDir
string
rawFS
fuse
.
RawFileSystem
loopback
Operations
server
*
fuse
.
Server
rawFS
fuse
.
RawFileSystem
server
*
fuse
.
Server
}
}
func
(
tc
*
testCase
)
writeOrig
(
path
,
content
string
,
mode
os
.
FileMode
)
{
func
(
tc
*
testCase
)
writeOrig
(
path
,
content
string
,
mode
os
.
FileMode
)
{
...
@@ -65,10 +67,10 @@ func newTestCase(t *testing.T) *testCase {
...
@@ -65,10 +67,10 @@ func newTestCase(t *testing.T) *testCase {
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
loopback
:
=
NewLoopback
(
tc
.
origDir
)
tc
.
loopback
=
NewLoopback
(
tc
.
origDir
)
_
=
time
.
Second
_
=
time
.
Second
oneSec
:=
time
.
Second
oneSec
:=
time
.
Second
tc
.
rawFS
=
NewNodeFS
(
loopback
,
&
Options
{
tc
.
rawFS
=
NewNodeFS
(
tc
.
loopback
,
&
Options
{
Debug
:
testutil
.
VerboseTest
(),
Debug
:
testutil
.
VerboseTest
(),
// NOSUBMIT - should run all tests without cache too
// NOSUBMIT - should run all tests without cache too
...
@@ -454,3 +456,42 @@ func TestLink(t *testing.T) {
...
@@ -454,3 +456,42 @@ func TestLink(t *testing.T) {
t
.
Errorf
(
"Lstat after: got %d, want %d"
,
st
.
Ino
,
beforeIno
)
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