Commit 70a92e3a authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Fix UnionFs.TestDoubleOpen() content

- Pass PathNodeFs in FileSystem.Mount()

- Add Inode.Files(mask)

- Reopen all files with layer > 0 on promotion.
parent 83798dc7
......@@ -104,7 +104,7 @@ type FileSystem interface {
SetXAttr(name string, attr string, data []byte, flags int, context *Context) Status
// Called after mount.
Mount(connector *FileSystemConnector)
Mount(nodeFs *PathNodeFs, connector *FileSystemConnector)
Unmount()
// File handling. If opening for writing, the file's mtime
......@@ -150,7 +150,10 @@ type WithFlags struct {
File
// Put FOPEN_* flags here.
Flags uint32
FuseFlags uint32
// O_RDWR, O_TRUNCATE, etc.
OpenFlags uint32
}
// MountOptions contains time out options for a (Node)FileSystem. The
......
......@@ -21,7 +21,7 @@ func (me *cacheFs) Open(name string, flags uint32, context *Context) (fuseFile F
}
return &WithFlags{
File: f,
Flags: FOPEN_KEEP_CACHE,
FuseFlags: FOPEN_KEEP_CACHE,
}, c
}
......@@ -107,7 +107,7 @@ func (me *nonseekFs) Open(name string, flags uint32, context *Context) (fuseFile
f := NewReadOnlyFile(data)
return &WithFlags{
File: f,
Flags: FOPEN_NONSEEKABLE,
FuseFlags: FOPEN_NONSEEKABLE,
}, OK
}
......
......@@ -81,7 +81,7 @@ func (me *DefaultFileSystem) OpenDir(name string, context *Context) (stream chan
return nil, ENOSYS
}
func (me *DefaultFileSystem) Mount(conn *FileSystemConnector) {
func (me *DefaultFileSystem) Mount(nodeFs *PathNodeFs, conn *FileSystemConnector) {
}
func (me *DefaultFileSystem) Unmount() {
......
......@@ -13,14 +13,9 @@ var _ = log.Println
type openedFile struct {
Handled
// O_CREAT, O_TRUNC, etc.
OpenFlags uint32
// FOPEN_KEEP_CACHE and friends.
FuseFlags uint32
WithFlags
dir rawDir
file File
}
type fileSystemMount struct {
......@@ -96,14 +91,15 @@ func (me *fileSystemMount) registerFileHandle(node *Inode, dir rawDir, f File, f
defer node.openFilesMutex.Unlock()
b := &openedFile{
dir: dir,
file: f,
OpenFlags: flags,
WithFlags: WithFlags{
File: f,
OpenFlags: flags,
},
}
withFlags, ok := f.(*WithFlags)
if ok {
b.FuseFlags = withFlags.Flags
f = withFlags.File
b.WithFlags.FuseFlags = withFlags.FuseFlags
b.WithFlags.File = withFlags.File
}
node.openFiles = append(node.openFiles, b)
......
......@@ -87,7 +87,7 @@ func (me *FileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) (out
var f File
if input.Flags&FUSE_GETATTR_FH != 0 {
if opened := me.getOpenedFile(input.Fh); opened != nil {
f = opened.file
f = opened.WithFlags.File
}
}
......@@ -303,7 +303,7 @@ func (me *FileSystemConnector) Release(header *InHeader, input *ReleaseIn) {
func (me *FileSystemConnector) Flush(header *InHeader, input *FlushIn) Status {
node := me.getInodeData(header.NodeId)
opened := me.getOpenedFile(input.Fh)
return node.fsInode.Flush(opened.file, opened.OpenFlags, &header.Context)
return node.fsInode.Flush(opened.WithFlags.File, opened.WithFlags.OpenFlags, &header.Context)
}
func (me *FileSystemConnector) ReleaseDir(header *InHeader, input *ReleaseIn) {
......@@ -349,12 +349,12 @@ func (me *FileSystemConnector) ListXAttr(header *InHeader) (data []byte, code St
func (me *FileSystemConnector) Write(input *WriteIn, data []byte) (written uint32, code Status) {
opened := me.getOpenedFile(input.Fh)
return opened.file.Write(input, data)
return opened.WithFlags.File.Write(input, data)
}
func (me *FileSystemConnector) Read(input *ReadIn, bp BufferPool) ([]byte, Status) {
opened := me.getOpenedFile(input.Fh)
return opened.file.Read(input, bp)
return opened.WithFlags.File.Read(input, bp)
}
func (me *FileSystemConnector) StatFs() *StatfsOut {
......
......@@ -2,8 +2,10 @@ package fuse
import (
"fmt"
"log"
"sync"
)
var _ = log.Println
// The inode reflects the kernel's idea of the inode.
type Inode struct {
......@@ -61,8 +63,8 @@ func (me *Inode) AnyFile() (file File) {
defer me.openFilesMutex.Unlock()
for _, f := range me.openFiles {
if file == nil || f.OpenFlags&O_ANYWRITE != 0 {
file = f.file
if file == nil || f.WithFlags.OpenFlags&O_ANYWRITE != 0 {
file = f.WithFlags.File
}
}
return file
......@@ -83,14 +85,15 @@ func (me *Inode) FsNode() FsNode {
return me.fsInode
}
// Returns an open writable file for the given Inode.
func (me *Inode) WritableFiles() (files []File) {
// Files() returns an opens file that have bits in common with the
// give mask. Use mask==0 to return all files.
func (me *Inode) Files(mask uint32) (files []WithFlags) {
me.openFilesMutex.Lock()
defer me.openFilesMutex.Unlock()
log.Println("inod.files:", me.openFiles)
for _, f := range me.openFiles {
if f.OpenFlags&O_ANYWRITE != 0 {
files = append(files, f.file)
if mask == 0 || f.WithFlags.OpenFlags&mask != 0 {
files = append(files, f.WithFlags)
}
}
return files
......
......@@ -95,9 +95,9 @@ func (me *LockingFileSystem) OpenDir(name string, context *Context) (stream chan
return me.FileSystem.OpenDir(name, context)
}
func (me *LockingFileSystem) Mount(conn *FileSystemConnector) {
func (me *LockingFileSystem) Mount(nodeFs *PathNodeFs, conn *FileSystemConnector) {
defer me.locked()()
me.FileSystem.Mount(conn)
me.FileSystem.Mount(nodeFs, conn)
}
func (me *LockingFileSystem) Unmount() {
......
......@@ -114,9 +114,9 @@ func (me *LoggingFileSystem) OpenDir(name string, context *Context) (stream chan
return me.FileSystem.OpenDir(name, context)
}
func (me *LoggingFileSystem) Mount(conn *FileSystemConnector) {
func (me *LoggingFileSystem) Mount(nodeFs *PathNodeFs, conn *FileSystemConnector) {
me.Print("Mount", "")
me.FileSystem.Mount(conn)
me.FileSystem.Mount(nodeFs, conn)
}
func (me *LoggingFileSystem) Unmount() {
......
......@@ -4,6 +4,7 @@ import (
"log"
"os"
"path/filepath"
"strings"
)
var _ = log.Println
......@@ -17,13 +18,34 @@ func (me *PathNodeFs) Unmount() {
}
func (me *PathNodeFs) Mount(conn *FileSystemConnector) {
me.fs.Mount(conn)
me.fs.Mount(me, conn)
}
func (me *PathNodeFs) StatFs() *StatfsOut {
return me.fs.StatFs()
}
func (me *PathNodeFs) Node(name string) *Inode {
name = filepath.Clean(name)
comps := strings.Split(name, string(filepath.Separator))
node := me.root.Inode()
for _, c := range comps {
node = node.GetChild(c)
if node == nil {
break
}
}
return node
}
func (me *PathNodeFs) AllFiles(name string, mask uint32) []WithFlags {
n := me.Node(name)
if n == nil {
return nil
}
return n.Files(mask)
}
func NewPathNodeFs(fs FileSystem) *PathNodeFs {
root := new(pathInode)
root.fs = fs
......@@ -261,7 +283,7 @@ func (me *pathInode) GetAttr(file File, context *Context) (fi *os.FileInfo, code
}
func (me *pathInode) Chmod(file File, perms uint32, context *Context) (code Status) {
files := me.inode.WritableFiles()
files := me.inode.Files(O_ANYWRITE)
for _, f := range files {
// TODO - pass context
code = f.Chmod(perms)
......@@ -277,7 +299,7 @@ func (me *pathInode) Chmod(file File, perms uint32, context *Context) (code Stat
}
func (me *pathInode) Chown(file File, uid uint32, gid uint32, context *Context) (code Status) {
files := me.inode.WritableFiles()
files := me.inode.Files(O_ANYWRITE)
for _, f := range files {
// TODO - pass context
code = f.Chown(uid, gid)
......@@ -293,7 +315,7 @@ func (me *pathInode) Chown(file File, uid uint32, gid uint32, context *Context)
}
func (me *pathInode) Truncate(file File, size uint64, context *Context) (code Status) {
files := me.inode.WritableFiles()
files := me.inode.Files(O_ANYWRITE)
for _, f := range files {
// TODO - pass context
log.Println("truncating file", f)
......@@ -309,7 +331,7 @@ func (me *pathInode) Truncate(file File, size uint64, context *Context) (code St
}
func (me *pathInode) Utimens(file File, atime uint64, mtime uint64, context *Context) (code Status) {
files := me.inode.WritableFiles()
files := me.inode.Files(O_ANYWRITE)
for _, f := range files {
// TODO - pass context
code = f.Utimens(atime, mtime)
......
......@@ -69,8 +69,8 @@ func (me *ReadonlyFileSystem) OpenDir(name string, context *Context) (stream cha
return me.FileSystem.OpenDir(name, context)
}
func (me *ReadonlyFileSystem) Mount(conn *FileSystemConnector) {
me.FileSystem.Mount(conn)
func (me *ReadonlyFileSystem) Mount(nodeFs *PathNodeFs, conn *FileSystemConnector) {
me.FileSystem.Mount(nodeFs, conn)
}
func (me *ReadonlyFileSystem) Unmount() {
......
......@@ -196,9 +196,9 @@ func (me *SwitchFileSystem) OpenDir(name string, context *Context) (stream chan
return fs.FileSystem.OpenDir(name, context)
}
func (me *SwitchFileSystem) Mount(conn *FileSystemConnector) {
func (me *SwitchFileSystem) Mount(nodeFs *PathNodeFs, conn *FileSystemConnector) {
for _, fs := range me.fileSystems {
fs.FileSystem.Mount(conn)
fs.FileSystem.Mount(nodeFs, conn)
}
}
......
......@@ -135,9 +135,9 @@ func (me *TimingFileSystem) OpenDir(name string, context *Context) (stream chan
return me.FileSystem.OpenDir(name, context)
}
func (me *TimingFileSystem) Mount(conn *FileSystemConnector) {
func (me *TimingFileSystem) Mount(nodeFs *PathNodeFs, conn *FileSystemConnector) {
defer me.startTimer("Mount", "")()
me.FileSystem.Mount(conn)
me.FileSystem.Mount(nodeFs, conn)
}
func (me *TimingFileSystem) Unmount() {
......
......@@ -9,6 +9,6 @@ GOFILES=unionfs.go \
autounion.go \
create.go
DEPS=../fuse ../zipfs
DEPS=../fuse
include $(GOROOT)/src/Make.pkg
......@@ -65,7 +65,7 @@ func (me *AutoUnionFs) Name() string {
return fmt.Sprintf("AutoUnionFs(%s)", me.root)
}
func (me *AutoUnionFs) Mount(connector *fuse.FileSystemConnector) {
func (me *AutoUnionFs) Mount(nodeFs *fuse.PathNodeFs, connector *fuse.FileSystemConnector) {
me.connector = connector
if me.options.UpdateOnMount {
time.AfterFunc(0.1e9, func() { me.updateKnownFses() })
......
......@@ -2,7 +2,6 @@ package unionfs
import (
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/zipfs"
"os"
)
......@@ -17,9 +16,6 @@ func NewUnionFsFromRoots(roots []string, opts *UnionFsOptions, roCaching bool) (
if fi.IsDirectory() {
fs = fuse.NewLoopbackFileSystem(r)
}
if fs == nil {
fs, err = zipfs.NewArchiveFileSystem(r)
}
if fs == nil {
return nil, err
......
......@@ -70,6 +70,7 @@ type UnionFs struct {
branchCache *TimedCache
options *UnionFsOptions
nodeFs *fuse.PathNodeFs
}
type UnionFsOptions struct {
......@@ -102,6 +103,10 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs
return g
}
func (me *UnionFs) Mount(nodeFs *fuse.PathNodeFs, connector *fuse.FileSystemConnector) {
me.nodeFs = nodeFs
}
////////////////
// Deal with all the caches.
......@@ -259,6 +264,18 @@ func (me *UnionFs) Promote(name string, srcResult branchResult, context *fuse.Co
if srcResult.attr.IsRegular() {
code = fuse.CopyFile(sourceFs, writable, name, name, context)
files := me.nodeFs.AllFiles(name, 0)
log.Println("promote files", files, name)
for _, f := range files {
if !code.Ok() {
break
}
uf := f.File.(*UnionFsFile)
if uf.layer > 0 {
uf.layer = 0
uf.File, code = me.fileSystems[0].Open(name, f.OpenFlags, context)
}
}
} else if srcResult.attr.IsSymlink() {
link := ""
link, code = sourceFs.Readlink(name, context)
......@@ -865,7 +882,7 @@ func (me *UnionFs) Open(name string, flags uint32, context *fuse.Context) (fuseF
}
fuseFile, status = me.fileSystems[r.branch].Open(name, uint32(flags), context)
if fuseFile != nil {
fuseFile = &UnionFsFile{fuseFile}
fuseFile = &UnionFsFile{fuseFile, r.branch}
}
return fuseFile, status
}
......@@ -886,6 +903,7 @@ func (me *UnionFs) Name() string {
type UnionFsFile struct {
fuse.File
layer int
}
func (me *UnionFsFile) GetAttr() (*os.FileInfo, fuse.Status) {
......
......@@ -903,21 +903,18 @@ func TestDoubleOpen(t *testing.T) {
t.Errorf("After r/w truncation, r/o file should be empty too: %q", string(output))
}
disabled := true
if !disabled {
want := "hello"
_, err = rwFile.Write([]byte(want))
CheckSuccess(err)
want := "hello"
_, err = rwFile.Write([]byte(want))
CheckSuccess(err)
b := make([]byte, 100)
b := make([]byte, 100)
roFile.Seek(0, 0)
n, err := roFile.Read(b)
CheckSuccess(err)
b = b[:n]
roFile.Seek(0, 0)
n, err := roFile.Read(b)
CheckSuccess(err)
b = b[:n]
if string(b) != "hello" {
t.Errorf("r/w and r/o file are not synchronized: got %q want %q", string(b), want)
}
if string(b) != "hello" {
t.Errorf("r/w and r/o file are not synchronized: got %q want %q", string(b), want)
}
}
......@@ -63,8 +63,8 @@ func (me *memNode) Print(indent int) {
}
// We construct the tree at mount, so we never need to look anything up.
func (me *memNode) Lookup(name string) (fi *os.FileInfo, node FsNode, code Status) {
return nil, nil, ENOENT
func (me *memNode) Lookup(name string) (fi *os.FileInfo, node fuse.FsNode, code fuse.Status) {
return nil, nil, fuse.ENOENT
}
func (me *memNode) OpenDir(context *fuse.Context) (stream chan fuse.DirEntry, code fuse.Status) {
......
......@@ -49,7 +49,7 @@ func (me *MultiZipFs) Name() string {
return "MultiZipFs"
}
func (me *MultiZipFs) Mount(connector *fuse.FileSystemConnector) {
func (me *MultiZipFs) Mount(nodeFs *fuse.PathNodeFs, connector *fuse.FileSystemConnector) {
me.Connector = connector
}
......
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