Commit 65c034b5 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Revise readdir and inode handling for PathFileSystemConnector.

* Always return synthetic inode numbers in Lookup/Getattr

* Always return FUSE_UNKNOWN_INO in Readdir

* Use (chan DirEntry) interface for Readdir in
  PathFileSystem.OpenDir
parent d40d36be
...@@ -197,7 +197,7 @@ func (self *DummyPathFuse) Open(name string, flags uint32) (file fuse.RawFuseFil ...@@ -197,7 +197,7 @@ func (self *DummyPathFuse) Open(name string, flags uint32) (file fuse.RawFuseFil
return nil, fuse.ENOSYS return nil, fuse.ENOSYS
} }
func (self *DummyPathFuse) OpenDir(name string) (dir fuse.RawFuseDir, code fuse.Status) { func (self *DummyPathFuse) OpenDir(name string) (stream chan fuse.DirEntry, status fuse.Status) {
return nil, fuse.ENOSYS return nil, fuse.ENOSYS
} }
......
...@@ -49,15 +49,37 @@ func (self *PassThroughFuse) GetAttr(name string) (*fuse.Attr, fuse.Status) { ...@@ -49,15 +49,37 @@ func (self *PassThroughFuse) GetAttr(name string) (*fuse.Attr, fuse.Status) {
return out, fuse.OK return out, fuse.OK
} }
func (self *PassThroughFuse) OpenDir(name string) (fuseFile fuse.RawFuseDir, status fuse.Status) { func (self *PassThroughFuse) OpenDir(name string) (stream chan fuse.DirEntry, status fuse.Status) {
// What other ways beyond O_RDONLY are there to open // What other ways beyond O_RDONLY are there to open
// directories? // directories?
f, err := os.Open(self.GetPath(name), os.O_RDONLY, 0) f, err := os.Open(self.GetPath(name), os.O_RDONLY, 0)
if err != nil { if err != nil {
return nil, fuse.OsErrorToFuseError(err) return nil, fuse.OsErrorToFuseError(err)
} }
p := NewPassThroughDir(f) output := make(chan fuse.DirEntry, 500)
return p, fuse.OK go func() {
for {
want := 500
infos, err := f.Readdir(want)
for i, _ := range infos {
output <- fuse.DirEntry{
Name: infos[i].Name,
Mode: infos[i].Mode,
}
}
if len(infos) < want {
break
}
if err != nil {
// TODO - how to signal error
break
}
}
close(output)
f.Close()
}()
return output, fuse.OK
} }
func (self *PassThroughFuse) Open(name string, flags uint32) (fuseFile fuse.RawFuseFile, status fuse.Status) { func (self *PassThroughFuse) Open(name string, flags uint32) (fuseFile fuse.RawFuseFile, status fuse.Status) {
...@@ -201,36 +223,3 @@ func NewPassThroughDir(file *os.File) *PassThroughDir { ...@@ -201,36 +223,3 @@ func NewPassThroughDir(file *os.File) *PassThroughDir {
}() }()
return self return self
} }
func (self *PassThroughDir) ReadDir(input *fuse.ReadIn) (*fuse.DirEntryList, fuse.Status) {
list := fuse.NewDirEntryList(int(input.Size))
if self.leftOver != nil {
success := list.AddString(self.leftOver.Name, fuse.FUSE_UNKNOWN_INO, self.leftOver.Mode)
self.exported++
if !success {
panic("No space for single entry.")
}
self.leftOver = nil
}
for {
fi := <-self.directoryChannel
if fi == nil {
break
}
if !list.AddString(fi.Name, fuse.FUSE_UNKNOWN_INO, fi.Mode) {
self.leftOver = fi
break
}
}
return list, fuse.OsErrorToFuseError(self.directoryError)
}
func (self *PassThroughDir) ReleaseDir() {
close(self.directoryChannel)
}
func (self *PassThroughDir) FsyncDir(input *fuse.FsyncIn) (code fuse.Status) {
return fuse.ENOSYS
}
...@@ -4,17 +4,22 @@ package fuse ...@@ -4,17 +4,22 @@ package fuse
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"bytes" "bytes"
) )
// Should make interface ? // For PathFileSystemConnector. The connector determines inodes.
type DirEntry struct {
Mode uint32
Name string
}
type DirEntryList struct { type DirEntryList struct {
buf bytes.Buffer buf bytes.Buffer
offset uint64 offset uint64
maxSize int maxSize int
} }
func NewDirEntryList(max int) *DirEntryList { func NewDirEntryList(max int) *DirEntryList {
return &DirEntryList{maxSize: max} return &DirEntryList{maxSize: max}
} }
...@@ -55,3 +60,57 @@ func (de *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool { ...@@ -55,3 +60,57 @@ func (de *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool {
func (de *DirEntryList) Bytes() []byte { func (de *DirEntryList) Bytes() []byte {
return de.buf.Bytes() return de.buf.Bytes()
} }
////////////////////////////////////////////////////////////////
type FuseDir struct {
stream chan DirEntry
leftOver DirEntry
connector *PathFileSystemConnector
parentIno uint64
}
func (me *FuseDir) inode(name string) uint64 {
// We could also return
// me.connector.lookupUpdate(me.parentIno, name).NodeId but it
// appears FUSE will issue a LOOKUP afterwards for the entry
// anyway, so we skip hash table update here.
return FUSE_UNKNOWN_INO
}
func (me *FuseDir) ReadDir(input *ReadIn) (*DirEntryList, Status) {
list := NewDirEntryList(int(input.Size))
if me.leftOver.Name != "" {
n := me.leftOver.Name
i := me.inode(n)
success := list.AddString(n, i, me.leftOver.Mode)
if !success {
panic("No space for single entry.")
}
me.leftOver.Name = ""
}
for {
d := <-me.stream
if d.Name == "" {
break
}
i := me.inode(d.Name)
if !list.AddString(d.Name, i, d.Mode) {
me.leftOver = d
break
}
}
fmt.Println("OFF", list.offset)
return list, OK
}
func (me *FuseDir) ReleaseDir() {
close(me.stream)
}
func (me *FuseDir) FsyncDir(input *FsyncIn) (code Status) {
return ENOSYS
}
...@@ -143,11 +143,22 @@ func (self *PathFileSystemConnector) unrefNode(data *inodeData) { ...@@ -143,11 +143,22 @@ func (self *PathFileSystemConnector) unrefNode(data *inodeData) {
} }
} }
func (self *PathFileSystemConnector) lookup(key string) *inodeData {
self.lock.RLock()
defer self.lock.RUnlock()
return self.inodePathMap[key]
}
func (self *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *inodeData { func (self *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *inodeData {
key := inodeDataKey(nodeId, name)
data := self.lookup(key)
if data != nil {
return data
}
self.lock.Lock() self.lock.Lock()
defer self.lock.Unlock() defer self.lock.Unlock()
key := inodeDataKey(nodeId, name)
data, ok := self.inodePathMap[key] data, ok := self.inodePathMap[key]
if !ok { if !ok {
data = new(inodeData) data = new(inodeData)
...@@ -160,7 +171,6 @@ func (self *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *i ...@@ -160,7 +171,6 @@ func (self *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *i
self.inodePathMap[key] = data self.inodePathMap[key] = data
} }
data.LookupCount++
return data return data
} }
...@@ -404,6 +414,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out ...@@ -404,6 +414,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
} }
data := self.lookupUpdate(header.NodeId, name) data := self.lookupUpdate(header.NodeId, name)
data.LookupCount++
data.Type = ModeToType(attr.Mode) data.Type = ModeToType(attr.Mode)
out = new(EntryOut) out = new(EntryOut)
...@@ -413,6 +424,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out ...@@ -413,6 +424,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
SplitNs(self.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec) SplitNs(self.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec) SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
out.Attr = *attr out.Attr = *attr
out.Attr.Ino = data.NodeId
return out, OK return out, OK
} }
...@@ -433,7 +445,7 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn) ...@@ -433,7 +445,7 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn)
out = new(AttrOut) out = new(AttrOut)
out.Attr = *attr out.Attr = *attr
out.Attr.Ino = header.NodeId
SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec) SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
return out, OK return out, OK
...@@ -445,14 +457,19 @@ func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (f ...@@ -445,14 +457,19 @@ func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (f
return 0, nil, ENOENT return 0, nil, ENOENT
} }
// TODO - how to handle return flags, the FUSE open flags? // TODO - how to handle return flags, the FUSE open flags?
f, err := mount.fs.OpenDir(fullPath) stream, err := mount.fs.OpenDir(fullPath)
if err != OK { if err != OK {
return 0, nil, err return 0, nil, err
} }
// TODO - racy? // TODO - racy?
mount.openDirs++ mount.openDirs++
return 0, f, OK
de := new(FuseDir)
de.connector = self
de.parentIno = header.NodeId
de.stream = stream
return 0, de, OK
} }
func (self *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) { func (self *PathFileSystemConnector) Open(header *InHeader, input *OpenIn) (flags uint32, fuseFile RawFuseFile, status Status) {
......
...@@ -571,7 +571,7 @@ type PathFilesystem interface { ...@@ -571,7 +571,7 @@ type PathFilesystem interface {
// Unimplemented: // Unimplemented:
// RemoveXAttr, SetXAttr, GetXAttr, ListXAttr. // RemoveXAttr, SetXAttr, GetXAttr, ListXAttr.
OpenDir(name string) (dir RawFuseDir, code Status) OpenDir(name string) (stream chan DirEntry, code Status)
// TODO - what is a good interface? // TODO - what is a good interface?
Mount(connector *PathFileSystemConnector) Status Mount(connector *PathFileSystemConnector) Status
......
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