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