mirror of https://github.com/restic/restic.git
mount: Correctly return context.Canceled for interrupted syscalls
bazil/fuse expects us to return context.Canceled to signal that a syscall was successfully interrupted. Returning a wrapped version of that error however causes the fuse library to signal an EIO (input/output error). Thus unwrap context.Canceled errors before returning them.
This commit is contained in:
parent
f7808245aa
commit
a0c1ae9f90
|
@ -0,0 +1,11 @@
|
|||
Bugfix: Improve handling of interrupted syscalls in `mount` command
|
||||
|
||||
Accessing restic's fuse mount could result in "input / output" errors when
|
||||
using programs in which syscalls can be interrupted. This is for example the
|
||||
case for go programs.
|
||||
|
||||
We have corrected the error handling for interrupted syscalls.
|
||||
|
||||
https://github.com/restic/restic/issues/3567
|
||||
https://github.com/restic/restic/issues/3694
|
||||
https://github.com/restic/restic/pull/3875
|
|
@ -5,6 +5,7 @@ package fuse
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
@ -44,6 +45,16 @@ func newDir(ctx context.Context, root *Root, inode, parentInode uint64, node *re
|
|||
}, nil
|
||||
}
|
||||
|
||||
// returing a wrapped context.Canceled error will instead result in returing
|
||||
// an input / output error to the user. Thus unwrap the error to match the
|
||||
// expectations of bazil/fuse
|
||||
func unwrapCtxCanceled(err error) error {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return context.Canceled
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// replaceSpecialNodes replaces nodes with name "." and "/" by their contents.
|
||||
// Otherwise, the node is returned.
|
||||
func replaceSpecialNodes(ctx context.Context, repo restic.Repository, node *restic.Node) ([]*restic.Node, error) {
|
||||
|
@ -57,7 +68,7 @@ func replaceSpecialNodes(ctx context.Context, repo restic.Repository, node *rest
|
|||
|
||||
tree, err := restic.LoadTree(ctx, repo, *node.Subtree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, unwrapCtxCanceled(err)
|
||||
}
|
||||
|
||||
return tree.Nodes, nil
|
||||
|
@ -91,7 +102,7 @@ func (d *dir) open(ctx context.Context) error {
|
|||
tree, err := restic.LoadTree(ctx, d.root.repo, *d.node.Subtree)
|
||||
if err != nil {
|
||||
debug.Log(" error loading tree %v: %v", d.node.Subtree, err)
|
||||
return err
|
||||
return unwrapCtxCanceled(err)
|
||||
}
|
||||
items := make(map[string]*restic.Node)
|
||||
for _, n := range tree.Nodes {
|
||||
|
|
|
@ -105,7 +105,7 @@ func (f *openFile) getBlobAt(ctx context.Context, i int) (blob []byte, err error
|
|||
blob, err = f.root.repo.LoadBlob(ctx, restic.DataBlob, f.node.Content[i], nil)
|
||||
if err != nil {
|
||||
debug.Log("LoadBlob(%v, %v) failed: %v", f.node.Name, f.node.Content[i], err)
|
||||
return nil, err
|
||||
return nil, unwrapCtxCanceled(err)
|
||||
}
|
||||
|
||||
f.root.blobCache.Add(f.node.Content[i], blob)
|
||||
|
|
|
@ -58,7 +58,7 @@ func (d *SnapshotsDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
|||
// update snapshots
|
||||
meta, err := d.dirStruct.UpdatePrefix(ctx, d.prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, unwrapCtxCanceled(err)
|
||||
} else if meta == nil {
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ func (d *SnapshotsDir) Lookup(ctx context.Context, name string) (fs.Node, error)
|
|||
|
||||
meta, err := d.dirStruct.UpdatePrefix(ctx, d.prefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, unwrapCtxCanceled(err)
|
||||
} else if meta == nil {
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue