Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jacobsa-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
jacobsa-fuse
Commits
13eb2958
Commit
13eb2958
authored
Jul 29, 2015
by
Aaron Jacobs
Browse files
Options
Browse Files
Download
Plain Diff
Added support for telling Linux not to abandon the page cache on open.
parents
9e84136e
eacbdb8d
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
241 additions
and
0 deletions
+241
-0
conversions.go
conversions.go
+4
-0
fuseops/ops.go
fuseops/ops.go
+16
-0
samples/cachingfs/caching_fs.go
samples/cachingfs/caching_fs.go
+33
-0
samples/cachingfs/caching_fs_test.go
samples/cachingfs/caching_fs_test.go
+188
-0
No files found.
conversions.go
View file @
13eb2958
...
@@ -512,6 +512,10 @@ func (c *Connection) kernelResponseForOp(
...
@@ -512,6 +512,10 @@ func (c *Connection) kernelResponseForOp(
out
:=
(
*
fusekernel
.
OpenOut
)(
m
.
Grow
(
unsafe
.
Sizeof
(
fusekernel
.
OpenOut
{})))
out
:=
(
*
fusekernel
.
OpenOut
)(
m
.
Grow
(
unsafe
.
Sizeof
(
fusekernel
.
OpenOut
{})))
out
.
Fh
=
uint64
(
o
.
Handle
)
out
.
Fh
=
uint64
(
o
.
Handle
)
if
o
.
KeepPageCache
{
out
.
OpenFlags
|=
uint32
(
fusekernel
.
OpenKeepCache
)
}
case
*
fuseops
.
ReadFileOp
:
case
*
fuseops
.
ReadFileOp
:
// convertInMessage already set up the destination buffer to be at the end
// convertInMessage already set up the destination buffer to be at the end
// of the out message. We need only shrink to the right size based on how
// of the out message. We need only shrink to the right size based on how
...
...
fuseops/ops.go
View file @
13eb2958
...
@@ -446,6 +446,22 @@ type OpenFileOp struct {
...
@@ -446,6 +446,22 @@ type OpenFileOp struct {
// file handle. The file system must ensure this ID remains valid until a
// file handle. The file system must ensure this ID remains valid until a
// later call to ReleaseFileHandle.
// later call to ReleaseFileHandle.
Handle
HandleID
Handle
HandleID
// By default, fuse invalidates the kernel's page cache for an inode when a
// new file handle is opened for that inode (cf. https://goo.gl/2rZ9uk). The
// intent appears to be to allow users to "see" content that has changed
// remotely on a networked file system by re-opening the file.
//
// For file systems where this is not a concern because all modifications for
// a particular inode go through the kernel, set this field to true to
// disable this behavior.
//
// (More discussion: http://goo.gl/cafzWF)
//
// Note that on OS X it appears that the behavior is always as if this field
// is set to true, regardless of its value, at least for files opened in the
// same mode. (Cf. https://github.com/osxfuse/osxfuse/issues/223)
KeepPageCache
bool
}
}
// Read data from a file previously opened with CreateFile or OpenFile.
// Read data from a file previously opened with CreateFile or OpenFile.
...
...
samples/cachingfs/caching_fs.go
View file @
13eb2958
...
@@ -15,7 +15,9 @@
...
@@ -15,7 +15,9 @@
package
cachingfs
package
cachingfs
import
(
import
(
"crypto/rand"
"fmt"
"fmt"
"io"
"os"
"os"
"time"
"time"
...
@@ -43,6 +45,10 @@ const (
...
@@ -43,6 +45,10 @@ const (
// inode entries and attributes to be cached, used when responding to fuse
// inode entries and attributes to be cached, used when responding to fuse
// requests. It also exposes methods for renumbering inodes and updating mtimes
// requests. It also exposes methods for renumbering inodes and updating mtimes
// that are useful in testing that these durations are honored.
// that are useful in testing that these durations are honored.
//
// Each file responds to reads with random contents. SetKeepCache can be used
// to control whether the response to OpenFileOp tells the kernel to keep the
// file's data in the page cache or not.
type
CachingFS
interface
{
type
CachingFS
interface
{
fuseutil
.
FileSystem
fuseutil
.
FileSystem
...
@@ -57,6 +63,10 @@ type CachingFS interface {
...
@@ -57,6 +63,10 @@ type CachingFS interface {
// Cause further queries for the attributes of inodes to use the supplied
// Cause further queries for the attributes of inodes to use the supplied
// time as the inode's mtime.
// time as the inode's mtime.
SetMtime
(
mtime
time
.
Time
)
SetMtime
(
mtime
time
.
Time
)
// Instruct the file system whether or not to reply to OpenFileOp with
// FOPEN_KEEP_CACHE set.
SetKeepCache
(
keep
bool
)
}
}
// Create a file system that issues cacheable responses according to the
// Create a file system that issues cacheable responses according to the
...
@@ -116,6 +126,9 @@ type cachingFS struct {
...
@@ -116,6 +126,9 @@ type cachingFS struct {
mu
syncutil
.
InvariantMutex
mu
syncutil
.
InvariantMutex
// GUARDED_BY(mu)
keepPageCache
bool
// The current ID of the lowest numbered non-root inode.
// The current ID of the lowest numbered non-root inode.
//
//
// INVARIANT: baseID > fuseops.RootInodeID
// INVARIANT: baseID > fuseops.RootInodeID
...
@@ -236,6 +249,14 @@ func (fs *cachingFS) SetMtime(mtime time.Time) {
...
@@ -236,6 +249,14 @@ func (fs *cachingFS) SetMtime(mtime time.Time) {
fs
.
mtime
=
mtime
fs
.
mtime
=
mtime
}
}
// LOCKS_EXCLUDED(fs.mu)
func
(
fs
*
cachingFS
)
SetKeepCache
(
keep
bool
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
fs
.
keepPageCache
=
keep
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// FileSystem methods
// FileSystem methods
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
...
@@ -335,5 +356,17 @@ func (fs *cachingFS) OpenDir(
...
@@ -335,5 +356,17 @@ func (fs *cachingFS) OpenDir(
func
(
fs
*
cachingFS
)
OpenFile
(
func
(
fs
*
cachingFS
)
OpenFile
(
ctx
context
.
Context
,
ctx
context
.
Context
,
op
*
fuseops
.
OpenFileOp
)
(
err
error
)
{
op
*
fuseops
.
OpenFileOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
op
.
KeepPageCache
=
fs
.
keepPageCache
return
}
func
(
fs
*
cachingFS
)
ReadFile
(
ctx
context
.
Context
,
op
*
fuseops
.
ReadFileOp
)
(
err
error
)
{
op
.
BytesRead
,
err
=
io
.
ReadFull
(
rand
.
Reader
,
op
.
Dst
)
return
return
}
}
samples/cachingfs/caching_fs_test.go
View file @
13eb2958
...
@@ -15,6 +15,8 @@
...
@@ -15,6 +15,8 @@
package
cachingfs_test
package
cachingfs_test
import
(
import
(
"bytes"
"io/ioutil"
"os"
"os"
"path"
"path"
"runtime"
"runtime"
...
@@ -531,3 +533,189 @@ func (t *AttributeCachingTest) StatRenumberMtimeStat_ViaFileDescriptor() {
...
@@ -531,3 +533,189 @@ func (t *AttributeCachingTest) StatRenumberMtimeStat_ViaFileDescriptor() {
ExpectThat
(
dirAfter
.
ModTime
(),
timeutil
.
TimeEq
(
newMtime
))
ExpectThat
(
dirAfter
.
ModTime
(),
timeutil
.
TimeEq
(
newMtime
))
ExpectThat
(
barAfter
.
ModTime
(),
timeutil
.
TimeEq
(
newMtime
))
ExpectThat
(
barAfter
.
ModTime
(),
timeutil
.
TimeEq
(
newMtime
))
}
}
////////////////////////////////////////////////////////////////////////
// Page cache
////////////////////////////////////////////////////////////////////////
type
PageCacheTest
struct
{
cachingFSTest
}
var
_
SetUpInterface
=
&
PageCacheTest
{}
func
init
()
{
RegisterTestSuite
(
&
PageCacheTest
{})
}
func
(
t
*
PageCacheTest
)
SetUp
(
ti
*
TestInfo
)
{
const
(
lookupEntryTimeout
=
0
getattrTimeout
=
0
)
t
.
cachingFSTest
.
setUp
(
ti
,
lookupEntryTimeout
,
getattrTimeout
)
}
func
(
t
*
PageCacheTest
)
SingleFileHandle_NoKeepCache
()
{
t
.
fs
.
SetKeepCache
(
false
)
// Open the file.
f
,
err
:=
os
.
Open
(
path
.
Join
(
t
.
Dir
,
"foo"
))
AssertEq
(
nil
,
err
)
defer
f
.
Close
()
// Read its contents once.
f
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c1
,
err
:=
ioutil
.
ReadAll
(
f
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c1
))
// And again.
f
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c2
,
err
:=
ioutil
.
ReadAll
(
f
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c2
))
// We should have seen the same contents each time.
ExpectTrue
(
bytes
.
Equal
(
c1
,
c2
))
}
func
(
t
*
PageCacheTest
)
SingleFileHandle_KeepCache
()
{
t
.
fs
.
SetKeepCache
(
true
)
// Open the file.
f
,
err
:=
os
.
Open
(
path
.
Join
(
t
.
Dir
,
"foo"
))
AssertEq
(
nil
,
err
)
defer
f
.
Close
()
// Read its contents once.
f
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c1
,
err
:=
ioutil
.
ReadAll
(
f
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c1
))
// And again.
f
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c2
,
err
:=
ioutil
.
ReadAll
(
f
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c2
))
// We should have seen the same contents each time.
ExpectTrue
(
bytes
.
Equal
(
c1
,
c2
))
}
func
(
t
*
PageCacheTest
)
TwoFileHandles_NoKeepCache
()
{
t
.
fs
.
SetKeepCache
(
false
)
// SetKeepCache(false) doesn't work on OS X. See the notes on
// OpenFileOp.KeepPageCache.
if
runtime
.
GOOS
==
"darwin"
{
return
}
// Open the file.
f1
,
err
:=
os
.
Open
(
path
.
Join
(
t
.
Dir
,
"foo"
))
AssertEq
(
nil
,
err
)
defer
f1
.
Close
()
// Read its contents once.
f1
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c1
,
err
:=
ioutil
.
ReadAll
(
f1
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c1
))
// Open a second handle.
f2
,
err
:=
os
.
Open
(
path
.
Join
(
t
.
Dir
,
"foo"
))
AssertEq
(
nil
,
err
)
defer
f2
.
Close
()
// We should see different contents if we read from that handle, due to the
// cache being invalidated at the time of opening.
f2
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c2
,
err
:=
ioutil
.
ReadAll
(
f2
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c2
))
ExpectFalse
(
bytes
.
Equal
(
c1
,
c2
))
// Another read from the second handle should give the same result as the
// first one from that handle.
f2
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c3
,
err
:=
ioutil
.
ReadAll
(
f2
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c3
))
ExpectTrue
(
bytes
.
Equal
(
c2
,
c3
))
// And another read from the first handle should give the same result yet
// again.
f1
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c4
,
err
:=
ioutil
.
ReadAll
(
f1
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c4
))
ExpectTrue
(
bytes
.
Equal
(
c2
,
c4
))
}
func
(
t
*
PageCacheTest
)
TwoFileHandles_KeepCache
()
{
t
.
fs
.
SetKeepCache
(
true
)
// Open the file.
f1
,
err
:=
os
.
Open
(
path
.
Join
(
t
.
Dir
,
"foo"
))
AssertEq
(
nil
,
err
)
defer
f1
.
Close
()
// Read its contents once.
f1
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c1
,
err
:=
ioutil
.
ReadAll
(
f1
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c1
))
// Open a second handle.
f2
,
err
:=
os
.
Open
(
path
.
Join
(
t
.
Dir
,
"foo"
))
AssertEq
(
nil
,
err
)
defer
f2
.
Close
()
// We should see the same contents when we read via the second handle.
f2
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c2
,
err
:=
ioutil
.
ReadAll
(
f2
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c2
))
ExpectTrue
(
bytes
.
Equal
(
c1
,
c2
))
// Ditto if we read again from the first.
f1
.
Seek
(
0
,
0
)
AssertEq
(
nil
,
err
)
c3
,
err
:=
ioutil
.
ReadAll
(
f1
)
AssertEq
(
nil
,
err
)
AssertEq
(
cachingfs
.
FooSize
,
len
(
c3
))
ExpectTrue
(
bytes
.
Equal
(
c1
,
c3
))
}
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