fusefrontend: make dirCache work for "node itself"
"node itself" can be converted to node + child by ascending one level. Performance gains are spectacular, as will be seen in the next commit.
This commit is contained in:
parent
770c4deb71
commit
4a07d6598c
|
@ -2,7 +2,9 @@ package fusefrontend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/hanwen/go-fuse/v2/fs"
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
@ -82,13 +84,37 @@ func (n *Node) rootNode() *RootNode {
|
||||||
//
|
//
|
||||||
// If you pass a `child` file name, the (dirfd, cName) pair will refer to
|
// If you pass a `child` file name, the (dirfd, cName) pair will refer to
|
||||||
// a child of this node.
|
// a child of this node.
|
||||||
// If `child` is empty, the (dirfd, cName) pair refers to this node itself.
|
// If `child` is empty, the (dirfd, cName) pair refers to this node itself. For
|
||||||
|
// the root node, that means (dirfd, ".").
|
||||||
func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno syscall.Errno) {
|
func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno syscall.Errno) {
|
||||||
rn := n.rootNode()
|
rn := n.rootNode()
|
||||||
|
// all filesystem operations go through prepareAtSyscall(), so this is a
|
||||||
|
// good place to reset the idle marker.
|
||||||
|
atomic.StoreUint32(&rn.IsIdle, 0)
|
||||||
|
|
||||||
|
// root node itself is special
|
||||||
|
if child == "" && n.IsRoot() {
|
||||||
|
var err error
|
||||||
|
dirfd, cName, err = rn.openBackingDir("")
|
||||||
|
if err != nil {
|
||||||
|
errno = fs.ToErrno(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal node itself can be converted to child of parent node
|
||||||
|
if child == "" {
|
||||||
|
name, p1 := n.Parent()
|
||||||
|
if p1 == nil || name == "" {
|
||||||
|
return -1, "", syscall.ENOENT
|
||||||
|
}
|
||||||
|
p2 := toNode(p1.Operations())
|
||||||
|
return p2.prepareAtSyscall(name)
|
||||||
|
}
|
||||||
|
|
||||||
// Cache lookup
|
// Cache lookup
|
||||||
// TODO: also handle caching for root node & plaintextnames
|
// TODO make it work for plaintextnames as well?
|
||||||
cacheable := (child != "" && !rn.args.PlaintextNames)
|
cacheable := (!rn.args.PlaintextNames)
|
||||||
if cacheable {
|
if cacheable {
|
||||||
var iv []byte
|
var iv []byte
|
||||||
dirfd, iv = rn.dirCache.Lookup(n)
|
dirfd, iv = rn.dirCache.Lookup(n)
|
||||||
|
@ -102,10 +128,10 @@ func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno sy
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slowpath
|
// Slowpath
|
||||||
p := n.Path()
|
if child == "" {
|
||||||
if child != "" {
|
log.Panicf("BUG: child name is empty - this cannot happen")
|
||||||
p = filepath.Join(p, child)
|
|
||||||
}
|
}
|
||||||
|
p := filepath.Join(n.Path(), child)
|
||||||
if rn.isFiltered(p) {
|
if rn.isFiltered(p) {
|
||||||
errno = syscall.EPERM
|
errno = syscall.EPERM
|
||||||
return
|
return
|
||||||
|
@ -113,12 +139,12 @@ func (n *Node) prepareAtSyscall(child string) (dirfd int, cName string, errno sy
|
||||||
dirfd, cName, err := rn.openBackingDir(p)
|
dirfd, cName, err := rn.openBackingDir(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache store
|
// Cache store
|
||||||
// TODO: also handle caching for root node & plaintextnames
|
|
||||||
if cacheable {
|
if cacheable {
|
||||||
// TODO: openBackingDir already calls ReadDirIVAt(). Get the data out.
|
// TODO: openBackingDir already calls ReadDirIVAt(). Avoid duplicate work?
|
||||||
iv, err := nametransform.ReadDirIVAt(dirfd)
|
iv, err := nametransform.ReadDirIVAt(dirfd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
syscall.Close(dirfd)
|
syscall.Close(dirfd)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -127,8 +126,6 @@ func (rn *RootNode) reportMitigatedCorruption(item string) {
|
||||||
//
|
//
|
||||||
// Prevents name clashes with internal files when file names are not encrypted
|
// Prevents name clashes with internal files when file names are not encrypted
|
||||||
func (rn *RootNode) isFiltered(path string) bool {
|
func (rn *RootNode) isFiltered(path string) bool {
|
||||||
atomic.StoreUint32(&rn.IsIdle, 0)
|
|
||||||
|
|
||||||
if !rn.args.PlaintextNames {
|
if !rn.args.PlaintextNames {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue