Commit ceac4073 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Add support for FUSE FOPEN flags (keep_cache, direct_io, etc.)

parent a0c52d0e
...@@ -87,6 +87,13 @@ type File interface { ...@@ -87,6 +87,13 @@ type File interface {
Ioctl(input *IoctlIn) (output *IoctlOut, data []byte, code Status) Ioctl(input *IoctlIn) (output *IoctlOut, data []byte, code Status)
} }
type WithFlags struct {
File
// Put FOPEN_* flags here.
Flags uint32
}
// MountOptions contains time out options for a FileSystem. The // MountOptions contains time out options for a FileSystem. The
// default copied from libfuse and set in NewMountOptions() is // default copied from libfuse and set in NewMountOptions() is
// (1s,1s,0s). // (1s,1s,0s).
......
package fuse
import (
"testing"
"os"
"io/ioutil"
)
type cacheFs struct {
*LoopbackFileSystem
}
func (me *cacheFs) Open(name string, flags uint32) (fuseFile File, status Status) {
f, c := me.LoopbackFileSystem.Open(name, flags)
if !c.Ok() {
return f, c
}
return &WithFlags{
File: f,
Flags: FOPEN_KEEP_CACHE,
}, c
}
func setupCacheTest() (string, func()) {
dir := MakeTempDir()
os.Mkdir(dir + "/mnt", 0755)
os.Mkdir(dir + "/orig", 0755)
fs := &cacheFs{
LoopbackFileSystem: NewLoopbackFileSystem(dir + "/orig"),
}
state, _, err := MountFileSystem(dir + "/mnt", fs, nil)
CheckSuccess(err)
go state.Loop(false)
return dir, func() {
err := state.Unmount()
if err == nil {
os.RemoveAll(dir)
}
}
}
func TestCacheFs(t *testing.T) {
wd, clean := setupCacheTest()
defer clean()
err := ioutil.WriteFile(wd + "/orig/file.txt", []byte("hello"), 0644)
CheckSuccess(err)
c, err := ioutil.ReadFile(wd + "/mnt/file.txt")
CheckSuccess(err)
if string(c) != "hello" {
t.Fatalf("expect 'hello' %q", string(c))
}
err = ioutil.WriteFile(wd + "/orig/file.txt", []byte("qqqqq"), 0644)
CheckSuccess(err)
c, err = ioutil.ReadFile(wd + "/mnt/file.txt")
CheckSuccess(err)
if string(c) != "hello" {
t.Fatalf("expect 'hello' %q", string(c))
}
}
...@@ -32,7 +32,12 @@ type openedFile struct { ...@@ -32,7 +32,12 @@ type openedFile struct {
Handled Handled
*fileSystemMount *fileSystemMount
*inode *inode
Flags uint32
// O_CREAT, O_TRUNC, etc.
OpenFlags uint32
// FOPEN_KEEP_CACHE and friends.
FuseFlags uint32
dir rawDir dir rawDir
file File file File
...@@ -74,7 +79,7 @@ func (me *fileSystemMount) unregisterFileHandle(node *inode, handle uint64) *ope ...@@ -74,7 +79,7 @@ func (me *fileSystemMount) unregisterFileHandle(node *inode, handle uint64) *ope
return opened return opened
} }
func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, flags uint32) uint64 { func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, flags uint32) (uint64, *openedFile) {
node.OpenCountMutex.Lock() node.OpenCountMutex.Lock()
defer node.OpenCountMutex.Unlock() defer node.OpenCountMutex.Unlock()
b := &openedFile{ b := &openedFile{
...@@ -82,10 +87,18 @@ func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, f ...@@ -82,10 +87,18 @@ func (me *fileSystemMount) registerFileHandle(node *inode, dir rawDir, f File, f
file: f, file: f,
inode: node, inode: node,
fileSystemMount: me, fileSystemMount: me,
Flags: flags, OpenFlags: flags,
}
withFlags, ok := f.(*WithFlags)
if ok {
b.FuseFlags = withFlags.Flags
f = withFlags.File
} }
node.OpenCount++ node.OpenCount++
return me.openFiles.Register(&b.Handled) handle := me.openFiles.Register(&b.Handled)
return handle, b
} }
//////////////// ////////////////
......
...@@ -152,9 +152,9 @@ func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags u ...@@ -152,9 +152,9 @@ func (me *FileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (flags u
extra: node.GetMountDirEntries(), extra: node.GetMountDirEntries(),
stream: stream, stream: stream,
} }
h := mount.registerFileHandle(node, de, nil, input.Flags) h, opened := mount.registerFileHandle(node, de, nil, input.Flags)
return 0, h, OK return opened.FuseFlags, h, OK
} }
func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) { func (me *FileSystemConnector) ReadDir(header *InHeader, input *ReadIn) (*DirEntryList, Status) {
...@@ -172,14 +172,15 @@ func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint ...@@ -172,14 +172,15 @@ func (me *FileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint
return 0, 0, ENOENT return 0, 0, ENOENT
} }
// TODO - how to handle return flags, the FUSE open flags?
f, err := mount.fs.Open(fullPath, input.Flags) f, err := mount.fs.Open(fullPath, input.Flags)
if err != OK { if err != OK {
return 0, 0, err return 0, 0, err
} }
h := mount.registerFileHandle(node, nil, f, input.Flags)
return 0, h, OK
h, opened := mount.registerFileHandle(node, nil, f, input.Flags)
return opened.FuseFlags, h, OK
} }
func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) { func (me *FileSystemConnector) SetAttr(header *InHeader, input *SetAttrIn) (out *AttrOut, code Status) {
...@@ -403,7 +404,8 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st ...@@ -403,7 +404,8 @@ func (me *FileSystemConnector) Create(header *InHeader, input *CreateIn, name st
msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v", fullPath) msg := fmt.Sprintf("Create succeded, but GetAttr returned no entry %v", fullPath)
panic(msg) panic(msg)
} }
return 0, mount.registerFileHandle(inode, nil, f, input.Flags), out, code handle, opened := mount.registerFileHandle(inode, nil, f, input.Flags)
return opened.FuseFlags, handle, out, code
} }
func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) { func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
...@@ -416,7 +418,7 @@ func (me *FileSystemConnector) Flush(input *FlushIn) Status { ...@@ -416,7 +418,7 @@ func (me *FileSystemConnector) Flush(input *FlushIn) Status {
opened := me.getOpenedFile(input.Fh) opened := me.getOpenedFile(input.Fh)
code := opened.file.Flush() code := opened.file.Flush()
if code.Ok() && opened.Flags&O_ANYWRITE != 0 { if code.Ok() && opened.OpenFlags&O_ANYWRITE != 0 {
// We only signal releases to the FS if the // We only signal releases to the FS if the
// open could have changed things. // open could have changed things.
var path string var path string
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment