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
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
}
......
......@@ -49,15 +49,37 @@ func (self *PassThroughFuse) GetAttr(name string) (*fuse.Attr, fuse.Status) {
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
// directories?
f, err := os.Open(self.GetPath(name), os.O_RDONLY, 0)
if err != nil {
return nil, fuse.OsErrorToFuseError(err)
}
p := NewPassThroughDir(f)
return p, fuse.OK
output := make(chan fuse.DirEntry, 500)
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) {
......@@ -201,36 +223,3 @@ func NewPassThroughDir(file *os.File) *PassThroughDir {
}()
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
import (
"encoding/binary"
"fmt"
"bytes"
)
// Should make interface ?
// For PathFileSystemConnector. The connector determines inodes.
type DirEntry struct {
Mode uint32
Name string
}
type DirEntryList struct {
buf bytes.Buffer
offset uint64
maxSize int
}
func NewDirEntryList(max int) *DirEntryList {
return &DirEntryList{maxSize: max}
}
......@@ -55,3 +60,57 @@ func (de *DirEntryList) Add(name []byte, inode uint64, mode uint32) bool {
func (de *DirEntryList) Bytes() []byte {
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) {
}
}
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 {
key := inodeDataKey(nodeId, name)
data := self.lookup(key)
if data != nil {
return data
}
self.lock.Lock()
defer self.lock.Unlock()
key := inodeDataKey(nodeId, name)
data, ok := self.inodePathMap[key]
if !ok {
data = new(inodeData)
......@@ -160,7 +171,6 @@ func (self *PathFileSystemConnector) lookupUpdate(nodeId uint64, name string) *i
self.inodePathMap[key] = data
}
data.LookupCount++
return data
}
......@@ -404,6 +414,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
}
data := self.lookupUpdate(header.NodeId, name)
data.LookupCount++
data.Type = ModeToType(attr.Mode)
out = new(EntryOut)
......@@ -413,6 +424,7 @@ func (self *PathFileSystemConnector) Lookup(header *InHeader, name string) (out
SplitNs(self.options.EntryTimeout, &out.EntryValid, &out.EntryValidNsec)
SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
out.Attr = *attr
out.Attr.Ino = data.NodeId
return out, OK
}
......@@ -433,7 +445,7 @@ func (self *PathFileSystemConnector) GetAttr(header *InHeader, input *GetAttrIn)
out = new(AttrOut)
out.Attr = *attr
out.Attr.Ino = header.NodeId
SplitNs(self.options.AttrTimeout, &out.AttrValid, &out.AttrValidNsec)
return out, OK
......@@ -445,14 +457,19 @@ func (self *PathFileSystemConnector) OpenDir(header *InHeader, input *OpenIn) (f
return 0, nil, ENOENT
}
// 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 {
return 0, nil, err
}
// TODO - racy?
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) {
......
......@@ -571,7 +571,7 @@ type PathFilesystem interface {
// Unimplemented:
// 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?
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