Commit 8d47a84b authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher Committed by Han-Wen Nienhuys

nodefs: delay directory read till ReadDir

We used to read the directory already on OpenDir, which means that
we missed changes in the directory between a user's open() and
readdir() call.

https://github.com/hanwen/go-fuse/issues/252
parent 33711add
...@@ -53,13 +53,13 @@ func NewDirEntryList(data []byte, off uint64) *DirEntryList { ...@@ -53,13 +53,13 @@ func NewDirEntryList(data []byte, off uint64) *DirEntryList {
// AddDirEntry tries to add an entry, and reports whether it // AddDirEntry tries to add an entry, and reports whether it
// succeeded. // succeeded.
func (l *DirEntryList) AddDirEntry(e DirEntry) (bool, uint64) { func (l *DirEntryList) AddDirEntry(e DirEntry) bool {
return l.Add(0, e.Name, e.Ino, e.Mode) return l.Add(0, e.Name, e.Ino, e.Mode)
} }
// Add adds a direntry to the DirEntryList, returning whether it // Add adds a direntry to the DirEntryList, returning whether it
// succeeded. // succeeded.
func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (bool, uint64) { func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) bool {
if inode == 0 { if inode == 0 {
inode = FUSE_UNKNOWN_INO inode = FUSE_UNKNOWN_INO
} }
...@@ -69,7 +69,7 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) ( ...@@ -69,7 +69,7 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (
newLen := delta + oldLen newLen := delta + oldLen
if newLen > l.size { if newLen > l.size {
return false, l.offset return false
} }
l.buf = l.buf[:newLen] l.buf = l.buf[:newLen]
oldLen += prefix oldLen += prefix
...@@ -87,20 +87,20 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) ( ...@@ -87,20 +87,20 @@ func (l *DirEntryList) Add(prefix int, name string, inode uint64, mode uint32) (
} }
l.offset = dirent.Off l.offset = dirent.Off
return true, l.offset return true
} }
// AddDirLookupEntry is used for ReadDirPlus. It serializes a DirEntry // AddDirLookupEntry is used for ReadDirPlus. It serializes a DirEntry
// and returns the space for entry. If no space is left, returns a nil // and returns the space for entry. If no space is left, returns a nil
// pointer. // pointer.
func (l *DirEntryList) AddDirLookupEntry(e DirEntry) (*EntryOut, uint64) { func (l *DirEntryList) AddDirLookupEntry(e DirEntry) *EntryOut {
lastStart := len(l.buf) lastStart := len(l.buf)
ok, off := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name, ok := l.Add(int(unsafe.Sizeof(EntryOut{})), e.Name,
e.Ino, e.Mode) e.Ino, e.Mode)
if !ok { if !ok {
return nil, off return nil
} }
return (*EntryOut)(unsafe.Pointer(&l.buf[lastStart])), off return (*EntryOut)(unsafe.Pointer(&l.buf[lastStart]))
} }
func (l *DirEntryList) bytes() []byte { func (l *DirEntryList) bytes() []byte {
......
...@@ -13,33 +13,30 @@ import ( ...@@ -13,33 +13,30 @@ import (
type connectorDir struct { type connectorDir struct {
node Node node Node
inode *Inode
rawFS fuse.RawFileSystem rawFS fuse.RawFileSystem
// Protect stream and lastOffset. These are written in case // Protect stream and lastOffset. These are written in case
// there is a seek on the directory. // there is a seek on the directory.
mu sync.Mutex mu sync.Mutex
stream []fuse.DirEntry stream []fuse.DirEntry
// lastOffset stores the last offset for a readdir. This lets
// readdir pick up changes to the directory made after opening
// it.
lastOffset uint64
} }
func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) { func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) {
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory. // rewinddir() should be as if reopening directory.
// TODO - test this. // TODO - test this.
if d.lastOffset > 0 && input.Offset == 0 { if d.stream == nil || input.Offset == 0 {
d.stream, code = d.node.OpenDir(&input.Context) d.stream, code = d.node.OpenDir(&input.Context)
if !code.Ok() { if !code.Ok() {
return code return code
} }
d.stream = append(d.stream, d.inode.getMountDirEntries()...)
d.stream = append(d.stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
} }
if input.Offset > uint64(len(d.stream)) { if input.Offset > uint64(len(d.stream)) {
...@@ -53,8 +50,7 @@ func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code ...@@ -53,8 +50,7 @@ func (d *connectorDir) ReadDir(input *fuse.ReadIn, out *fuse.DirEntryList) (code
log.Printf("got empty directory entry, mode %o.", e.Mode) log.Printf("got empty directory entry, mode %o.", e.Mode)
continue continue
} }
ok, off := out.AddDirEntry(e) ok := out.AddDirEntry(e)
d.lastOffset = off
if !ok { if !ok {
break break
} }
...@@ -66,16 +62,16 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) ( ...@@ -66,16 +62,16 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (
d.mu.Lock() d.mu.Lock()
defer d.mu.Unlock() defer d.mu.Unlock()
if d.stream == nil {
return fuse.OK
}
// rewinddir() should be as if reopening directory. // rewinddir() should be as if reopening directory.
if d.lastOffset > 0 && input.Offset == 0 { if d.stream == nil || input.Offset == 0 {
d.stream, code = d.node.OpenDir(&input.Context) d.stream, code = d.node.OpenDir(&input.Context)
if !code.Ok() { if !code.Ok() {
return code return code
} }
d.stream = append(d.stream, d.inode.getMountDirEntries()...)
d.stream = append(d.stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
} }
if input.Offset > uint64(len(d.stream)) { if input.Offset > uint64(len(d.stream)) {
...@@ -91,7 +87,7 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) ( ...@@ -91,7 +87,7 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (
// we have to be sure entry will fit if we try to add // we have to be sure entry will fit if we try to add
// it, or we'll mess up the lookup counts. // it, or we'll mess up the lookup counts.
entryDest, off := out.AddDirLookupEntry(e) entryDest := out.AddDirLookupEntry(e)
if entryDest == nil { if entryDest == nil {
break break
} }
...@@ -106,10 +102,8 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) ( ...@@ -106,10 +102,8 @@ func (d *connectorDir) ReadDirPlus(input *fuse.ReadIn, out *fuse.DirEntryList) (
*entryDest = fuse.EntryOut{} *entryDest = fuse.EntryOut{}
d.rawFS.Lookup(&input.InHeader, e.Name, entryDest) d.rawFS.Lookup(&input.InHeader, e.Name, entryDest)
d.lastOffset = off
} }
return fuse.OK return fuse.OK
} }
type rawDir interface { type rawDir interface {
......
...@@ -161,16 +161,9 @@ func (c *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse ...@@ -161,16 +161,9 @@ func (c *rawBridge) GetAttr(input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse
func (c *rawBridge) OpenDir(input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) { func (c *rawBridge) OpenDir(input *fuse.OpenIn, out *fuse.OpenOut) (code fuse.Status) {
node := c.toInode(input.NodeId) node := c.toInode(input.NodeId)
stream, err := node.fsInode.OpenDir(&input.Context)
if err != fuse.OK {
return err
}
stream = append(stream, node.getMountDirEntries()...)
de := &connectorDir{ de := &connectorDir{
inode: node,
node: node.Node(), node: node.Node(),
stream: append(stream,
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."},
fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."}),
rawFS: c, rawFS: c,
} }
h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags) h, opened := node.mount.registerFileHandle(node, de, nil, input.Flags)
......
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