mirror of
https://github.com/restic/restic.git
synced 2025-12-12 08:31:51 +00:00
fuse: forget fs.Node instances on request by the kernel
Forget fs.Node instances once the kernel frees the corresponding nodeId. This ensures that restic does not run out of memory on large snapshots.
This commit is contained in:
@@ -20,12 +20,14 @@ import (
|
||||
|
||||
// Statically ensure that *dir implement those interface
|
||||
var _ = fs.HandleReadDirAller(&dir{})
|
||||
var _ = fs.NodeForgetter(&dir{})
|
||||
var _ = fs.NodeGetxattrer(&dir{})
|
||||
var _ = fs.NodeListxattrer(&dir{})
|
||||
var _ = fs.NodeStringLookuper(&dir{})
|
||||
|
||||
type dir struct {
|
||||
root *Root
|
||||
forget forgetFn
|
||||
items map[string]*restic.Node
|
||||
inode uint64
|
||||
parentInode uint64
|
||||
@@ -38,11 +40,12 @@ func cleanupNodeName(name string) string {
|
||||
return filepath.Base(name)
|
||||
}
|
||||
|
||||
func newDir(root *Root, inode, parentInode uint64, node *restic.Node) (*dir, error) {
|
||||
func newDir(root *Root, forget forgetFn, inode, parentInode uint64, node *restic.Node) (*dir, error) {
|
||||
debug.Log("new dir for %v (%v)", node.Name, node.Subtree)
|
||||
|
||||
return &dir{
|
||||
root: root,
|
||||
forget: forget,
|
||||
node: node,
|
||||
inode: inode,
|
||||
parentInode: parentInode,
|
||||
@@ -79,10 +82,11 @@ func replaceSpecialNodes(ctx context.Context, repo restic.BlobLoader, node *rest
|
||||
return tree.Nodes, nil
|
||||
}
|
||||
|
||||
func newDirFromSnapshot(root *Root, inode uint64, snapshot *restic.Snapshot) (*dir, error) {
|
||||
func newDirFromSnapshot(root *Root, forget forgetFn, inode uint64, snapshot *restic.Snapshot) (*dir, error) {
|
||||
debug.Log("new dir for snapshot %v (%v)", snapshot.ID(), snapshot.Tree)
|
||||
return &dir{
|
||||
root: root,
|
||||
root: root,
|
||||
forget: forget,
|
||||
node: &restic.Node{
|
||||
AccessTime: snapshot.Time,
|
||||
ModTime: snapshot.Time,
|
||||
@@ -213,7 +217,7 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d.cache.lookupOrCreate(name, func() (fs.Node, error) {
|
||||
return d.cache.lookupOrCreate(name, func(forget forgetFn) (fs.Node, error) {
|
||||
node, ok := d.items[name]
|
||||
if !ok {
|
||||
debug.Log(" Lookup(%v) -> not found", name)
|
||||
@@ -222,13 +226,13 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
inode := inodeFromNode(d.inode, node)
|
||||
switch node.Type {
|
||||
case restic.NodeTypeDir:
|
||||
return newDir(d.root, inode, d.inode, node)
|
||||
return newDir(d.root, forget, inode, d.inode, node)
|
||||
case restic.NodeTypeFile:
|
||||
return newFile(d.root, inode, node)
|
||||
return newFile(d.root, forget, inode, node)
|
||||
case restic.NodeTypeSymlink:
|
||||
return newLink(d.root, inode, node)
|
||||
return newLink(d.root, forget, inode, node)
|
||||
case restic.NodeTypeDev, restic.NodeTypeCharDev, restic.NodeTypeFifo, restic.NodeTypeSocket:
|
||||
return newOther(d.root, inode, node)
|
||||
return newOther(d.root, forget, inode, node)
|
||||
default:
|
||||
debug.Log(" node %v has unknown type %v", name, node.Type)
|
||||
return nil, syscall.ENOENT
|
||||
@@ -244,3 +248,7 @@ func (d *dir) Listxattr(_ context.Context, req *fuse.ListxattrRequest, resp *fus
|
||||
func (d *dir) Getxattr(_ context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error {
|
||||
return nodeGetXattr(d.node, req, resp)
|
||||
}
|
||||
|
||||
func (d *dir) Forget() {
|
||||
d.forget()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user