Repository: restic/restic
Pull request #4500 (2023-10-01 16:28:50)

Simplify issue template
<!--
Thank you very much for contributing code or documentation to restic! Please
fill out the following questions to make it easier for us to review your
changes.
-->

What does this PR change? What problem does it solve?
-----------------------------------------------------
The PR simplifies the issue template by merging the `Steps to reproduce the behavior` and `How did you run restic exactly?` sections. These are closely related such that the actual description either ends up in one of them (https://github.com/restic/restic/issues/4447) or is partially duplicated across both sections (https://github.com/restic/restic/issues/4477).

In addition, it removes the `Do you have an idea how to solve the issue?` section. A user who submits an issue, usually has no chance at all to make a useful suggestion. Consequently, there is usually no suggestion or I just end up ignoring it. As this increases friction for users that report an issue, let's just remove it.

<!--
Describe the changes and their purpose here, as detailed as needed.
-->

Was the change previously discussed in an issue or on the forum?
----------------------------------------------------------------
No.
<!--
Link issues and relevant forum posts here.

If this PR resolves an issue on GitHub, use "Closes #1234" so that the issue
is closed automatically when this PR is merged.
-->

Checklist
---------

<!--
You do not need to check all the boxes below all at once. Feel free to take
your time and add more commits. If you're done and ready for review, please
check the last box. Enable a checkbox by replacing [ ] with [x].
-->

- [x] I have read the [contribution guidelines](https://github.com/restic/restic/blob/master/CONTRIBUTING.md#providing-patches).
- [x] I have [enabled maintainer edits](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork).
- ~~[ ] I have added tests for all code changes.~~
- ~~[ ] I have added documentation for relevant changes (in the manual).~~
- ~~[ ] There's a new file in `changelog/unreleased/` that describes the changes for our users (see [template](https://github.com/restic/restic/blob/master/changelog/TEMPLATE)).~~
- [x] I have run `gofmt` on the code in all commits.
- [x] All commit messages are formatted in the same style as [the other commits in the repo](https://github.com/restic/restic/blob/master/CONTRIBUTING.md#git-commits).
- [x] I'm done! This pull request is ready for review.



Patch:
diff --git a/.github/ISSUE_TEMPLATE/Bug.md b/.github/ISSUE_TEMPLATE/Bug.md
index b0741e3f8..532983773 100644
--- a/.github/ISSUE_TEMPLATE/Bug.md
+++ b/.github/ISSUE_TEMPLATE/Bug.md
@@ -32,22 +32,29 @@ Output of `restic version`
 --------------------------
 
 
-How did you run restic exactly?
--------------------------------
+
+What backend/service did you use to store the repository?
+---------------------------------------------------------
+
+
+
+Problem description / Steps to reproduce
+----------------------------------------
 
 <!--
 This section should include at least:
 
+ * A description of the problem you are having with restic.
+
  * The complete command line and any environment variables you used to
    configure restic's backend access. Make sure to replace sensitive values!
 
  * The output of the commands, what restic prints gives may give us much
    information to diagnose the problem!
--->
-
-What backend/server/service did you use to store the repository?
-----------------------------------------------------------------
 
+ * The more time you spend describing an easy way to reproduce the behavior (if
+   this is possible), the easier it is for the project developers to fix it!
+-->
 
 
 Expected behavior
@@ -65,22 +72,12 @@ In this section, please try to concentrate on observations, so only describe
 what you observed directly.
 -->
 
-Steps to reproduce the behavior
--------------------------------
-
-<!--
-The more time you spend describing an easy way to reproduce the behavior (if
-this is possible), the easier it is for the project developers to fix it!
--->
-
 Do you have any idea what may have caused this?
 -----------------------------------------------
 
-
-
-Do you have an idea how to solve the issue?
--------------------------------------------
-
+<!--
+Did something noteworthy happen on your system, Internet connection, backend services, etc?
+-->
 
 
 Did restic help you today? Did it make you happy in any way?
diff --git a/changelog/unreleased/issue-4128 b/changelog/unreleased/issue-4128
deleted file mode 100644
index 7d331b6b3..000000000
--- a/changelog/unreleased/issue-4128
+++ /dev/null
@@ -1,8 +0,0 @@
-Enhancement: Automatically adjust GOMAXPROCS in resource-constrained containers
-
-When running restic in a Linux container with CPU-usage limits, restic now
-automatically adjusts GOMAXPROCS. This helps to reduce the memory consumption
-on hosts with many CPU cores.
-
-https://github.com/restic/restic/issues/4128
-https://github.com/restic/restic/pull/4485
diff --git a/changelog/unreleased/pull-299 b/changelog/unreleased/pull-299
deleted file mode 100644
index aae5c0e05..000000000
--- a/changelog/unreleased/pull-299
+++ /dev/null
@@ -1,6 +0,0 @@
-Enhancement: Show progress bar while loading the index
-
-Restic did not provide any feedback while loading index files. Now there is a progress bar for the index loading process. 
-
-https://github.com/restic/restic/issues/229
-https://github.com/restic/restic/pull/4419
diff --git a/changelog/unreleased/pull-4511 b/changelog/unreleased/pull-4511
deleted file mode 100644
index 60c5659b6..000000000
--- a/changelog/unreleased/pull-4511
+++ /dev/null
@@ -1,7 +0,0 @@
-Enhancement: Include inode numbers in JSON output for find and ls
-
-Restic used to omit the inode numbers in the JSON messages emitted for nodes by
-the `ls` command as well as for matches by the `find` command. It now includes
-those values whenever they are available.
-
-https://github.com/restic/restic/pull/4511
diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go
index e476ae7b8..6b5706855 100644
--- a/cmd/restic/cmd_backup.go
+++ b/cmd/restic/cmd_backup.go
@@ -546,10 +546,7 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
 	if !gopts.JSON {
 		progressPrinter.V("load index files")
 	}
-
-	bar := newIndexTerminalProgress(gopts.Quiet, gopts.JSON, term)
-
-	err = repo.LoadIndex(ctx, bar)
+	err = repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/restic/cmd_cat.go b/cmd/restic/cmd_cat.go
index 238614cd0..97789d271 100644
--- a/cmd/restic/cmd_cat.go
+++ b/cmd/restic/cmd_cat.go
@@ -169,8 +169,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
 		return err
 
 	case "blob":
-		bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-		err = repo.LoadIndex(ctx, bar)
+		err = repo.LoadIndex(ctx)
 		if err != nil {
 			return err
 		}
@@ -198,8 +197,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string) error {
 			return errors.Fatalf("could not find snapshot: %v\n", err)
 		}
 
-		bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-		err = repo.LoadIndex(ctx, bar)
+		err = repo.LoadIndex(ctx)
 		if err != nil {
 			return err
 		}
diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go
index 5f03c446b..3c4c9daa9 100644
--- a/cmd/restic/cmd_check.go
+++ b/cmd/restic/cmd_check.go
@@ -226,8 +226,7 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
 	}
 
 	Verbosef("load indexes\n")
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	hints, errs := chkr.LoadIndex(ctx, bar)
+	hints, errs := chkr.LoadIndex(ctx)
 
 	errorsFound := false
 	suggestIndexRebuild := false
diff --git a/cmd/restic/cmd_copy.go b/cmd/restic/cmd_copy.go
index f31c17adb..eaa0ef81a 100644
--- a/cmd/restic/cmd_copy.go
+++ b/cmd/restic/cmd_copy.go
@@ -99,13 +99,12 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
 	}
 
 	debug.Log("Loading source index")
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err := srcRepo.LoadIndex(ctx, bar); err != nil {
+	if err := srcRepo.LoadIndex(ctx); err != nil {
 		return err
 	}
-	bar = newIndexProgress(gopts.Quiet, gopts.JSON)
+
 	debug.Log("Loading destination index")
-	if err := dstRepo.LoadIndex(ctx, bar); err != nil {
+	if err := dstRepo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/cmd_debug.go b/cmd/restic/cmd_debug.go
index bf05c448d..a54200c45 100644
--- a/cmd/restic/cmd_debug.go
+++ b/cmd/restic/cmd_debug.go
@@ -134,7 +134,7 @@ func printPacks(ctx context.Context, repo *repository.Repository, wr io.Writer)
 }
 
 func dumpIndexes(ctx context.Context, repo restic.Repository, wr io.Writer) error {
-	return index.ForAllIndexes(ctx, repo.Backend(), repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
+	return index.ForAllIndexes(ctx, repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
 		Printf("index_id: %v\n", id)
 		if err != nil {
 			return err
@@ -469,8 +469,7 @@ func runDebugExamine(ctx context.Context, gopts GlobalOptions, args []string) er
 		}
 	}
 
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	err = repo.LoadIndex(ctx, bar)
+	err = repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go
index 125904068..accd55db2 100644
--- a/cmd/restic/cmd_diff.go
+++ b/cmd/restic/cmd_diff.go
@@ -363,8 +363,8 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
 	if !gopts.JSON {
 		Verbosef("comparing snapshot %v to %v:\n\n", sn1.ID().Str(), sn2.ID().Str())
 	}
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err = repo.LoadIndex(ctx, bar); err != nil {
+
+	if err = repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/cmd_dump.go b/cmd/restic/cmd_dump.go
index 8b9fa9624..325607017 100644
--- a/cmd/restic/cmd_dump.go
+++ b/cmd/restic/cmd_dump.go
@@ -152,8 +152,7 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
 		return errors.Fatalf("failed to find snapshot: %v", err)
 	}
 
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	err = repo.LoadIndex(ctx, bar)
+	err = repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go
index abcf4f829..181d8595d 100644
--- a/cmd/restic/cmd_find.go
+++ b/cmd/restic/cmd_find.go
@@ -126,6 +126,7 @@ func (s *statefulOutput) PrintPatternJSON(path string, node *restic.Node) {
 
 		// Make the following attributes disappear
 		Name               byte `json:"name,omitempty"`
+		Inode              byte `json:"inode,omitempty"`
 		ExtendedAttributes byte `json:"extended_attributes,omitempty"`
 		Device             byte `json:"device,omitempty"`
 		Content            byte `json:"content,omitempty"`
@@ -588,8 +589,8 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
 	if err != nil {
 		return err
 	}
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err = repo.LoadIndex(ctx, bar); err != nil {
+
+	if err = repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/cmd_list.go b/cmd/restic/cmd_list.go
index 5974da9ac..bd02cedc7 100644
--- a/cmd/restic/cmd_list.go
+++ b/cmd/restic/cmd_list.go
@@ -63,7 +63,7 @@ func runList(ctx context.Context, cmd *cobra.Command, gopts GlobalOptions, args
 	case "locks":
 		t = restic.LockFile
 	case "blobs":
-		return index.ForAllIndexes(ctx, repo.Backend(), repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
+		return index.ForAllIndexes(ctx, repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
 			if err != nil {
 				return err
 			}
diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go
index fa2f9fbc2..256c9e002 100644
--- a/cmd/restic/cmd_ls.go
+++ b/cmd/restic/cmd_ls.go
@@ -87,7 +87,6 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
 		ModTime     time.Time   `json:"mtime,omitempty"`
 		AccessTime  time.Time   `json:"atime,omitempty"`
 		ChangeTime  time.Time   `json:"ctime,omitempty"`
-		Inode       uint64      `json:"inode,omitempty"`
 		StructType  string      `json:"struct_type"` // "node"
 
 		size uint64 // Target for Size pointer.
@@ -103,7 +102,6 @@ func lsNodeJSON(enc *json.Encoder, path string, node *restic.Node) error {
 		ModTime:     node.ModTime,
 		AccessTime:  node.AccessTime,
 		ChangeTime:  node.ChangeTime,
-		Inode:       node.Inode,
 		StructType:  "node",
 	}
 	// Always print size for regular files, even when empty,
@@ -175,8 +173,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
 		return err
 	}
 
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err = repo.LoadIndex(ctx, bar); err != nil {
+	if err = repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go
index 04c072daf..ec3662d5c 100644
--- a/cmd/restic/cmd_mount.go
+++ b/cmd/restic/cmd_mount.go
@@ -130,8 +130,7 @@ func runMount(ctx context.Context, opts MountOptions, gopts GlobalOptions, args
 		}
 	}
 
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	err = repo.LoadIndex(ctx, bar)
+	err = repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/restic/cmd_prune.go b/cmd/restic/cmd_prune.go
index 638a0de5e..e4c2c7b29 100644
--- a/cmd/restic/cmd_prune.go
+++ b/cmd/restic/cmd_prune.go
@@ -187,8 +187,7 @@ func runPruneWithRepo(ctx context.Context, opts PruneOptions, gopts GlobalOption
 
 	Verbosef("loading indexes...\n")
 	// loading the index before the snapshots is ok, as we use an exclusive lock here
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	err := repo.LoadIndex(ctx, bar)
+	err := repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/restic/cmd_recover.go b/cmd/restic/cmd_recover.go
index 63084dd5f..85dcc23d7 100644
--- a/cmd/restic/cmd_recover.go
+++ b/cmd/restic/cmd_recover.go
@@ -58,8 +58,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error {
 	}
 
 	Verbosef("load index files\n")
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err = repo.LoadIndex(ctx, bar); err != nil {
+	if err = repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
@@ -74,7 +73,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions) error {
 	})
 
 	Verbosef("load %d trees\n", len(trees))
-	bar = newProgressMax(!gopts.Quiet, uint64(len(trees)), "trees loaded")
+	bar := newProgressMax(!gopts.Quiet, uint64(len(trees)), "trees loaded")
 	for id := range trees {
 		tree, err := restic.LoadTree(ctx, repo, id)
 		if err != nil {
diff --git a/cmd/restic/cmd_repair_index.go b/cmd/restic/cmd_repair_index.go
index 622c77801..b1905836a 100644
--- a/cmd/restic/cmd_repair_index.go
+++ b/cmd/restic/cmd_repair_index.go
@@ -88,7 +88,7 @@ func rebuildIndex(ctx context.Context, opts RepairIndexOptions, gopts GlobalOpti
 	} else {
 		Verbosef("loading indexes...\n")
 		mi := index.NewMasterIndex()
-		err := index.ForAllIndexes(ctx, repo.Backend(), repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
+		err := index.ForAllIndexes(ctx, repo, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
 			if err != nil {
 				Warnf("removing invalid index %v: %v\n", id, err)
 				obsoleteIndexes = append(obsoleteIndexes, id)
diff --git a/cmd/restic/cmd_repair_snapshots.go b/cmd/restic/cmd_repair_snapshots.go
index 720523762..03736795c 100644
--- a/cmd/restic/cmd_repair_snapshots.go
+++ b/cmd/restic/cmd_repair_snapshots.go
@@ -89,8 +89,7 @@ func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOpt
 		return err
 	}
 
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err := repo.LoadIndex(ctx, bar); err != nil {
+	if err := repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go
index 494c6b86a..9bce90a26 100644
--- a/cmd/restic/cmd_restore.go
+++ b/cmd/restic/cmd_restore.go
@@ -173,8 +173,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
 		return errors.Fatalf("failed to find snapshot: %v", err)
 	}
 
-	bar := newIndexTerminalProgress(gopts.Quiet, gopts.JSON, term)
-	err = repo.LoadIndex(ctx, bar)
+	err = repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/restic/cmd_rewrite.go b/cmd/restic/cmd_rewrite.go
index 9d9ab5d5d..c08797c48 100644
--- a/cmd/restic/cmd_rewrite.go
+++ b/cmd/restic/cmd_rewrite.go
@@ -212,8 +212,7 @@ func runRewrite(ctx context.Context, opts RewriteOptions, gopts GlobalOptions, a
 		return err
 	}
 
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err = repo.LoadIndex(ctx, bar); err != nil {
+	if err = repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go
index f16b59d3c..a7ecd438f 100644
--- a/cmd/restic/cmd_stats.go
+++ b/cmd/restic/cmd_stats.go
@@ -98,8 +98,8 @@ func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args
 	if err != nil {
 		return err
 	}
-	bar := newIndexProgress(gopts.Quiet, gopts.JSON)
-	if err = repo.LoadIndex(ctx, bar); err != nil {
+
+	if err = repo.LoadIndex(ctx); err != nil {
 		return err
 	}
 
diff --git a/cmd/restic/main.go b/cmd/restic/main.go
index 8b5e64f44..17b9c468d 100644
--- a/cmd/restic/main.go
+++ b/cmd/restic/main.go
@@ -9,13 +9,13 @@ import (
 	"runtime"
 	godebug "runtime/debug"
 
-	"github.com/spf13/cobra"
-	_ "go.uber.org/automaxprocs"
-
 	"github.com/restic/restic/internal/debug"
-	"github.com/restic/restic/internal/errors"
 	"github.com/restic/restic/internal/options"
 	"github.com/restic/restic/internal/restic"
+
+	"github.com/spf13/cobra"
+
+	"github.com/restic/restic/internal/errors"
 )
 
 // cmdRoot is the base command when no other command has been specified.
diff --git a/cmd/restic/progress.go b/cmd/restic/progress.go
index fe4f654d0..4b6025a54 100644
--- a/cmd/restic/progress.go
+++ b/cmd/restic/progress.go
@@ -29,12 +29,13 @@ func calculateProgressInterval(show bool, json bool) time.Duration {
 	return interval
 }
 
-// newTerminalProgressMax returns a progress.Counter that prints to stdout or terminal if provided.
-func newGenericProgressMax(show bool, max uint64, description string, print func(status string)) *progress.Counter {
+// newProgressMax returns a progress.Counter that prints to stdout.
+func newProgressMax(show bool, max uint64, description string) *progress.Counter {
 	if !show {
 		return nil
 	}
 	interval := calculateProgressInterval(show, false)
+	canUpdateStatus := stdoutCanUpdateStatus()
 
 	return progress.NewCounter(interval, max, func(v uint64, max uint64, d time.Duration, final bool) {
 		var status string
@@ -46,28 +47,14 @@ func newGenericProgressMax(show bool, max uint64, description string, print func
 				ui.FormatDuration(d), ui.FormatPercent(v, max), v, max, description)
 		}
 
-		print(status)
+		printProgress(status, canUpdateStatus)
 		if final {
 			fmt.Print("\n")
 		}
 	})
 }
 
-func newTerminalProgressMax(show bool, max uint64, description string, term *termstatus.Terminal) *progress.Counter {
-	return newGenericProgressMax(show, max, description, func(status string) {
-		term.SetStatus([]string{status})
-	})
-}
-
-// newProgressMax calls newTerminalProgress without a terminal (print to stdout)
-func newProgressMax(show bool, max uint64, description string) *progress.Counter {
-	return newGenericProgressMax(show, max, description, printProgress)
-}
-
-func printProgress(status string) {
-
-	canUpdateStatus := stdoutCanUpdateStatus()
-
+func printProgress(status string, canUpdateStatus bool) {
 	w := stdoutTerminalWidth()
 	if w > 0 {
 		if w < 3 {
@@ -96,11 +83,3 @@ func printProgress(status string) {
 
 	_, _ = os.Stdout.Write([]byte(clear + status + carriageControl))
 }
-
-func newIndexProgress(quiet bool, json bool) *progress.Counter {
-	return newProgressMax(!quiet && !json, 0, "index files loaded")
-}
-
-func newIndexTerminalProgress(quiet bool, json bool, term *termstatus.Terminal) *progress.Counter {
-	return newTerminalProgressMax(!quiet && !json, 0, "index files loaded", term)
-}
diff --git a/doc/075_scripting.rst b/doc/075_scripting.rst
index 71ecd4c2b..9b9d676a9 100644
--- a/doc/075_scripting.rst
+++ b/doc/075_scripting.rst
@@ -277,8 +277,6 @@ Match object
 +-----------------+----------------------------------------------+
 | ``group``       | Name of group                                |
 +-----------------+----------------------------------------------+
-| ``inode``       | Inode number                                 |
-+-----------------+----------------------------------------------+
 | ``mode``        | UNIX file mode, shorthand of ``permissions`` |
 +-----------------+----------------------------------------------+
 | ``device_id``   | OS specific device identifier                |
@@ -472,8 +470,6 @@ node
 +-----------------+--------------------------+
 | ``ctime``       | Node creation time       |
 +-----------------+--------------------------+
-| ``inode``       | Inode number of node     |
-+-----------------+--------------------------+
 
 
 restore
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 978da7960..ecc283f8a 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,7 +11,7 @@ RUN go run build.go
 
 FROM alpine:latest AS restic
 
-RUN apk add --no-cache ca-certificates fuse openssh-client tzdata jq
+RUN apk add --update --no-cache ca-certificates fuse openssh-client tzdata jq
 
 COPY --from=builder /go/src/github.com/restic/restic/restic /usr/bin
 
diff --git a/docker/Dockerfile.release b/docker/Dockerfile.release
index 42302f203..ccf80376a 100644
--- a/docker/Dockerfile.release
+++ b/docker/Dockerfile.release
@@ -13,6 +13,6 @@ RUN mv /output/restic_${TARGETOS}_${TARGETARCH} /output/restic
 FROM alpine:latest
 
 COPY --from=helper /output/restic /usr/bin
-RUN apk add --no-cache ca-certificates fuse openssh-client tzdata jq
+RUN apk add --update --no-cache ca-certificates fuse openssh-client tzdata jq
 
 ENTRYPOINT ["/usr/bin/restic"]
diff --git a/go.mod b/go.mod
index 9b230ca69..2b08fcbd3 100644
--- a/go.mod
+++ b/go.mod
@@ -12,6 +12,7 @@ require (
 	github.com/go-ole/go-ole v1.3.0
 	github.com/google/go-cmp v0.5.9
 	github.com/hashicorp/golang-lru/v2 v2.0.7
+	github.com/juju/ratelimit v1.0.2
 	github.com/klauspost/compress v1.16.7
 	github.com/kurin/blazer v0.5.4-0.20230113224640-3887e1ec64b5
 	github.com/minio/minio-go/v7 v7.0.61
@@ -24,7 +25,6 @@ require (
 	github.com/restic/chunker v0.4.0
 	github.com/spf13/cobra v1.7.0
 	github.com/spf13/pflag v1.0.5
-	go.uber.org/automaxprocs v1.5.3
 	golang.org/x/crypto v0.13.0
 	golang.org/x/net v0.15.0
 	golang.org/x/oauth2 v0.12.0
@@ -32,7 +32,6 @@ require (
 	golang.org/x/sys v0.12.0
 	golang.org/x/term v0.12.0
 	golang.org/x/text v0.13.0
-	golang.org/x/time v0.3.0
 	google.golang.org/api v0.138.0
 )
 
@@ -58,7 +57,6 @@ require (
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.5 // indirect
 	github.com/kr/fs v0.1.0 // indirect
-	github.com/kr/text v0.2.0 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
diff --git a/go.sum b/go.sum
index 64fc2af39..9aa9def92 100644
--- a/go.sum
+++ b/go.sum
@@ -44,7 +44,6 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -120,6 +119,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI=
+github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
 github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
 github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@@ -127,9 +128,6 @@ github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/q
 github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
 github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kurin/blazer v0.5.4-0.20230113224640-3887e1ec64b5 h1:OUlGa6AAolmjyPtILbMJ8vHayz5wd4wBUloheGcMhfA=
 github.com/kurin/blazer v0.5.4-0.20230113224640-3887e1ec64b5/go.mod h1:4FCXMUWo9DllR2Do4TtBd377ezyAJ51vB5uTBjt0pGU=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
@@ -159,7 +157,6 @@ github.com/pkg/xattr v0.4.10-0.20221120235825-35026bbbd013 h1:aqByeeNnF7NiEbXCi7
 github.com/pkg/xattr v0.4.10-0.20221120235825-35026bbbd013/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/restic/chunker v0.4.0 h1:YUPYCUn70MYP7VO4yllypp2SjmsRhRJaad3xKu1QFRw=
 github.com/restic/chunker v0.4.0/go.mod h1:z0cH2BejpW636LXw0R/BGyv+Ey8+m9QGiOanDHItzyw=
@@ -193,8 +190,6 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
-go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
-go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -269,8 +264,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -324,8 +317,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
 google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/backend/limiter/static_limiter.go b/internal/backend/limiter/static_limiter.go
index c09a12de0..9fb8fbf24 100644
--- a/internal/backend/limiter/static_limiter.go
+++ b/internal/backend/limiter/static_limiter.go
@@ -1,16 +1,15 @@
 package limiter
 
 import (
-	"context"
 	"io"
 	"net/http"
 
-	"golang.org/x/time/rate"
+	"github.com/juju/ratelimit"
 )
 
 type staticLimiter struct {
-	upstream   *rate.Limiter
-	downstream *rate.Limiter
+	upstream   *ratelimit.Bucket
+	downstream *ratelimit.Bucket
 }
 
 // Limits represents static upload and download limits.
@@ -24,16 +23,16 @@ type Limits struct {
 // download rate cap
 func NewStaticLimiter(l Limits) Limiter {
 	var (
-		upstreamBucket   *rate.Limiter
-		downstreamBucket *rate.Limiter
+		upstreamBucket   *ratelimit.Bucket
+		downstreamBucket *ratelimit.Bucket
 	)
 
 	if l.UploadKb > 0 {
-		upstreamBucket = rate.NewLimiter(rate.Limit(toByteRate(l.UploadKb)), int(toByteRate(l.UploadKb)))
+		upstreamBucket = ratelimit.NewBucketWithRate(toByteRate(l.UploadKb), int64(toByteRate(l.UploadKb)))
 	}
 
 	if l.DownloadKb > 0 {
-		downstreamBucket = rate.NewLimiter(rate.Limit(toByteRate(l.DownloadKb)), int(toByteRate(l.DownloadKb)))
+		downstreamBucket = ratelimit.NewBucketWithRate(toByteRate(l.DownloadKb), int64(toByteRate(l.DownloadKb)))
 	}
 
 	return staticLimiter{
@@ -96,55 +95,18 @@ func (l staticLimiter) Transport(rt http.RoundTripper) http.RoundTripper {
 	})
 }
 
-func (l staticLimiter) limitReader(r io.Reader, b *rate.Limiter) io.Reader {
+func (l staticLimiter) limitReader(r io.Reader, b *ratelimit.Bucket) io.Reader {
 	if b == nil {
 		return r
 	}
-	return &rateLimitedReader{r, b}
+	return ratelimit.Reader(r, b)
 }
 
-type rateLimitedReader struct {
-	reader io.Reader
-	bucket *rate.Limiter
-}
-
-func (r *rateLimitedReader) Read(p []byte) (int, error) {
-	n, err := r.reader.Read(p)
-	if err := consumeTokens(n, r.bucket); err != nil {
-		return n, err
-	}
-	return n, err
-}
-
-func (l staticLimiter) limitWriter(w io.Writer, b *rate.Limiter) io.Writer {
+func (l staticLimiter) limitWriter(w io.Writer, b *ratelimit.Bucket) io.Writer {
 	if b == nil {
 		return w
 	}
-	return &rateLimitedWriter{w, b}
-}
-
-type rateLimitedWriter struct {
-	writer io.Writer
-	bucket *rate.Limiter
-}
-
-func (w *rateLimitedWriter) Write(buf []byte) (int, error) {
-	if err := consumeTokens(len(buf), w.bucket); err != nil {
-		return 0, err
-	}
-	return w.writer.Write(buf)
-}
-
-func consumeTokens(tokens int, bucket *rate.Limiter) error {
-	// bucket allows waiting for at most Burst() tokens at once
-	maxWait := bucket.Burst()
-	for tokens > maxWait {
-		if err := bucket.WaitN(context.Background(), maxWait); err != nil {
-			return err
-		}
-		tokens -= maxWait
-	}
-	return bucket.WaitN(context.Background(), tokens)
+	return ratelimit.Writer(w, b)
 }
 
 func toByteRate(val int) float64 {
diff --git a/internal/checker/checker.go b/internal/checker/checker.go
index a5bb43731..b2512969e 100644
--- a/internal/checker/checker.go
+++ b/internal/checker/checker.go
@@ -113,42 +113,13 @@ func computePackTypes(ctx context.Context, idx restic.MasterIndex) map[restic.ID
 }
 
 // LoadIndex loads all index files.
-func (c *Checker) LoadIndex(ctx context.Context, p *progress.Counter) (hints []error, errs []error) {
+func (c *Checker) LoadIndex(ctx context.Context) (hints []error, errs []error) {
 	debug.Log("Start")
 
-	indexList, err := backend.MemorizeList(ctx, c.repo.Backend(), restic.IndexFile)
-	if err != nil {
-		// abort if an error occurs while listing the indexes
-		return hints, append(errs, err)
-	}
-
-	if p != nil {
-		var numIndexFiles uint64
-		err := indexList.List(ctx, restic.IndexFile, func(fi restic.FileInfo) error {
-			_, err := restic.ParseID(fi.Name)
-			if err != nil {
-				debug.Log("unable to parse %v as an ID", fi.Name)
-				return nil
-			}
-
-			numIndexFiles++
-			return nil
-		})
-		if err != nil {
-			return hints, append(errs, err)
-		}
-		p.SetMax(numIndexFiles)
-		defer p.Done()
-	}
-
 	packToIndex := make(map[restic.ID]restic.IDSet)
-	err = index.ForAllIndexes(ctx, indexList, c.repo, func(id restic.ID, index *index.Index, oldFormat bool, err error) error {
+	err := index.ForAllIndexes(ctx, c.repo, func(id restic.ID, index *index.Index, oldFormat bool, err error) error {
 		debug.Log("process index %v, err %v", id, err)
 
-		if p != nil {
-			p.Add(1)
-		}
-
 		if oldFormat {
 			debug.Log("index %v has old format", id)
 			hints = append(hints, &ErrOldIndexFormat{id})
diff --git a/internal/fuse/snapshots_dirstruct.go b/internal/fuse/snapshots_dirstruct.go
index a3cd11b14..3080d4de8 100644
--- a/internal/fuse/snapshots_dirstruct.go
+++ b/internal/fuse/snapshots_dirstruct.go
@@ -328,7 +328,7 @@ func (d *SnapshotsDirStructure) updateSnapshots(ctx context.Context) error {
 		return nil
 	}
 
-	err = d.root.repo.LoadIndex(ctx, nil)
+	err = d.root.repo.LoadIndex(ctx)
 	if err != nil {
 		return err
 	}
diff --git a/internal/index/index_parallel.go b/internal/index/index_parallel.go
index d505d756e..e7e46e88a 100644
--- a/internal/index/index_parallel.go
+++ b/internal/index/index_parallel.go
@@ -11,7 +11,7 @@ import (
 // ForAllIndexes loads all index files in parallel and calls the given callback.
 // It is guaranteed that the function is not run concurrently. If the callback
 // returns an error, this function is cancelled and also returns that error.
-func ForAllIndexes(ctx context.Context, lister restic.Lister, repo restic.Repository,
+func ForAllIndexes(ctx context.Context, repo restic.Repository,
 	fn func(id restic.ID, index *Index, oldFormat bool, err error) error) error {
 
 	// decoding an index can take quite some time such that this can be both CPU- or IO-bound
@@ -19,7 +19,7 @@ func ForAllIndexes(ctx context.Context, lister restic.Lister, repo restic.Reposi
 	workerCount := repo.Connections() + uint(runtime.GOMAXPROCS(0))
 
 	var m sync.Mutex
-	return restic.ParallelList(ctx, lister, restic.IndexFile, workerCount, func(ctx context.Context, id restic.ID, size int64) error {
+	return restic.ParallelList(ctx, repo.Backend(), restic.IndexFile, workerCount, func(ctx context.Context, id restic.ID, size int64) error {
 		var err error
 		var idx *Index
 		oldFormat := false
diff --git a/internal/repository/packer_manager.go b/internal/repository/packer_manager.go
index 2e2368aad..4422e3418 100644
--- a/internal/repository/packer_manager.go
+++ b/internal/repository/packer_manager.go
@@ -70,19 +70,14 @@ func (r *packerManager) SaveBlob(ctx context.Context, t restic.BlobType, id rest
 
 	var err error
 	packer := r.packer
-	// use separate packer if compressed length is larger than the packsize
-	// this speeds up the garbage collection of oversized blobs and reduces the cache size
-	// as the oversize blobs are only downloaded if necessary
-	if len(ciphertext) >= int(r.packSize) || r.packer == nil {
+	if r.packer == nil {
 		packer, err = r.newPacker()
 		if err != nil {
 			return 0, err
 		}
-		// don't store packer for oversized blob
-		if r.packer == nil {
-			r.packer = packer
-		}
 	}
+	// remember packer
+	r.packer = packer
 
 	// save ciphertext
 	// Add only appends bytes in memory to avoid being a scaling bottleneck
@@ -96,10 +91,8 @@ func (r *packerManager) SaveBlob(ctx context.Context, t restic.BlobType, id rest
 		debug.Log("pack is not full enough (%d bytes)", packer.Size())
 		return size, nil
 	}
-	if packer == r.packer {
-		// forget full packer
-		r.packer = nil
-	}
+	// forget full packer
+	r.packer = nil
 
 	// call while holding lock to prevent findPacker from creating new packers if the uploaders are busy
 	// else write the pack to the backend
diff --git a/internal/repository/repository.go b/internal/repository/repository.go
index 8ec3c598e..653c1f774 100644
--- a/internal/repository/repository.go
+++ b/internal/repository/repository.go
@@ -581,41 +581,15 @@ func (r *Repository) SetIndex(i restic.MasterIndex) error {
 }
 
 // LoadIndex loads all index files from the backend in parallel and stores them
-func (r *Repository) LoadIndex(ctx context.Context, p *progress.Counter) error {
+// in the master index. The first error that occurred is returned.
+func (r *Repository) LoadIndex(ctx context.Context) error {
 	debug.Log("Loading index")
 
-	indexList, err := backend.MemorizeList(ctx, r.Backend(), restic.IndexFile)
-	if err != nil {
-		return err
-	}
-
-	if p != nil {
-		var numIndexFiles uint64
-		err := indexList.List(ctx, restic.IndexFile, func(fi restic.FileInfo) error {
-			_, err := restic.ParseID(fi.Name)
-			if err != nil {
-				debug.Log("unable to parse %v as an ID", fi.Name)
-				return nil
-			}
-
-			numIndexFiles++
-			return nil
-		})
-		if err != nil {
-			return err
-		}
-		p.SetMax(numIndexFiles)
-		defer p.Done()
-	}
-
-	err = index.ForAllIndexes(ctx, indexList, r, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
+	err := index.ForAllIndexes(ctx, r, func(id restic.ID, idx *index.Index, oldFormat bool, err error) error {
 		if err != nil {
 			return err
 		}
 		r.idx.Insert(idx)
-		if p != nil {
-			p.Add(1)
-		}
 		return nil
 	})
 
diff --git a/internal/restic/repository.go b/internal/restic/repository.go
index a651f9906..6990200e4 100644
--- a/internal/restic/repository.go
+++ b/internal/restic/repository.go
@@ -24,7 +24,7 @@ type Repository interface {
 	Key() *crypto.Key
 
 	Index() MasterIndex
-	LoadIndex(context.Context, *progress.Counter) error
+	LoadIndex(context.Context) error
 	SetIndex(MasterIndex) error
 	LookupBlobSize(ID, BlobType) (uint, bool)
 


Test patch:
diff --git a/cmd/restic/cmd_backup_integration_test.go b/cmd/restic/cmd_backup_integration_test.go
index 76c227e3d..fb7bef633 100644
--- a/cmd/restic/cmd_backup_integration_test.go
+++ b/cmd/restic/cmd_backup_integration_test.go
@@ -252,7 +252,7 @@ func TestBackupTreeLoadError(t *testing.T) {
 
 	r, err := OpenRepository(context.TODO(), env.gopts)
 	rtest.OK(t, err)
-	rtest.OK(t, r.LoadIndex(context.TODO(), nil))
+	rtest.OK(t, r.LoadIndex(context.TODO()))
 	treePacks := restic.NewIDSet()
 	r.Index().Each(context.TODO(), func(pb restic.PackedBlob) {
 		if pb.Type == restic.TreeBlob {
diff --git a/cmd/restic/integration_helpers_test.go b/cmd/restic/integration_helpers_test.go
index 2afdbb938..b7cb5b333 100644
--- a/cmd/restic/integration_helpers_test.go
+++ b/cmd/restic/integration_helpers_test.go
@@ -258,7 +258,7 @@ func removePacksExcept(gopts GlobalOptions, t testing.TB, keep restic.IDSet, rem
 	rtest.OK(t, err)
 
 	// Get all tree packs
-	rtest.OK(t, r.LoadIndex(context.TODO(), nil))
+	rtest.OK(t, r.LoadIndex(context.TODO()))
 
 	treePacks := restic.NewIDSet()
 	r.Index().Each(context.TODO(), func(pb restic.PackedBlob) {
diff --git a/internal/backend/limiter/static_limiter_test.go b/internal/backend/limiter/static_limiter_test.go
index 8a839518f..564b6a00a 100644
--- a/internal/backend/limiter/static_limiter_test.go
+++ b/internal/backend/limiter/static_limiter_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 
 	"github.com/restic/restic/internal/test"
-	"golang.org/x/time/rate"
 )
 
 func TestLimiterWrapping(t *testing.T) {
@@ -34,38 +33,6 @@ func TestLimiterWrapping(t *testing.T) {
 	}
 }
 
-func TestReadLimiter(t *testing.T) {
-	reader := bytes.NewReader(make([]byte, 300))
-	limiter := rate.NewLimiter(rate.Limit(10000), int(100))
-	limReader := rateLimitedReader{reader, limiter}
-
-	n, err := limReader.Read([]byte{})
-	test.OK(t, err)
-	test.Equals(t, n, 0)
-
-	n, err = limReader.Read(make([]byte, 300))
-	test.OK(t, err)
-	test.Equals(t, n, 300)
-
-	n, err = limReader.Read([]byte{})
-	test.Equals(t, err, io.EOF)
-	test.Equals(t, n, 0)
-}
-
-func TestWriteLimiter(t *testing.T) {
-	writer := &bytes.Buffer{}
-	limiter := rate.NewLimiter(rate.Limit(10000), int(100))
-	limReader := rateLimitedWriter{writer, limiter}
-
-	n, err := limReader.Write([]byte{})
-	test.OK(t, err)
-	test.Equals(t, n, 0)
-
-	n, err = limReader.Write(make([]byte, 300))
-	test.OK(t, err)
-	test.Equals(t, n, 300)
-}
-
 type tracedReadCloser struct {
 	io.Reader
 	Closed bool
diff --git a/internal/checker/checker_test.go b/internal/checker/checker_test.go
index ee7e2867c..6405ecfbd 100644
--- a/internal/checker/checker_test.go
+++ b/internal/checker/checker_test.go
@@ -77,7 +77,7 @@ func TestCheckRepo(t *testing.T) {
 	repo := repository.TestOpenLocal(t, repodir)
 
 	chkr := checker.New(repo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -103,7 +103,7 @@ func TestMissingPack(t *testing.T) {
 	test.OK(t, repo.Backend().Remove(context.TODO(), packHandle))
 
 	chkr := checker.New(repo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -136,7 +136,7 @@ func TestUnreferencedPack(t *testing.T) {
 	test.OK(t, repo.Backend().Remove(context.TODO(), indexHandle))
 
 	chkr := checker.New(repo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -178,7 +178,7 @@ func TestUnreferencedBlobs(t *testing.T) {
 	sort.Sort(unusedBlobsBySnapshot)
 
 	chkr := checker.New(repo, true)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -258,7 +258,7 @@ func TestModifiedIndex(t *testing.T) {
 	}
 
 	chkr := checker.New(repo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) == 0 {
 		t.Fatalf("expected errors not found")
 	}
@@ -279,7 +279,7 @@ func TestDuplicatePacksInIndex(t *testing.T) {
 	repo := repository.TestOpenLocal(t, repodir)
 
 	chkr := checker.New(repo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(hints) == 0 {
 		t.Fatalf("did not get expected checker hints for duplicate packs in indexes")
 	}
@@ -347,7 +347,7 @@ func TestCheckerModifiedData(t *testing.T) {
 
 	chkr := checker.New(checkRepo, false)
 
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -408,7 +408,7 @@ func TestCheckerNoDuplicateTreeDecodes(t *testing.T) {
 	}
 
 	chkr := checker.New(checkRepo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -524,7 +524,7 @@ func TestCheckerBlobTypeConfusion(t *testing.T) {
 		delayRepo.Unblock()
 	}()
 
-	hints, errs := chkr.LoadIndex(ctx, nil)
+	hints, errs := chkr.LoadIndex(ctx)
 	if len(errs) > 0 {
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
 	}
@@ -553,7 +553,7 @@ func loadBenchRepository(t *testing.B) (*checker.Checker, restic.Repository, fun
 	repo := repository.TestOpenLocal(t, repodir)
 
 	chkr := checker.New(repo, false)
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) > 0 {
 		defer cleanup()
 		t.Fatalf("expected no errors, got %v: %v", len(errs), errs)
diff --git a/internal/checker/testing.go b/internal/checker/testing.go
index fe1679393..0668406d8 100644
--- a/internal/checker/testing.go
+++ b/internal/checker/testing.go
@@ -11,7 +11,7 @@ import (
 func TestCheckRepo(t testing.TB, repo restic.Repository) {
 	chkr := New(repo, true)
 
-	hints, errs := chkr.LoadIndex(context.TODO(), nil)
+	hints, errs := chkr.LoadIndex(context.TODO())
 	if len(errs) != 0 {
 		t.Fatalf("errors loading index: %v", errs)
 	}
diff --git a/internal/index/index_parallel_test.go b/internal/index/index_parallel_test.go
index 86be46473..760374510 100644
--- a/internal/index/index_parallel_test.go
+++ b/internal/index/index_parallel_test.go
@@ -29,7 +29,7 @@ func TestRepositoryForAllIndexes(t *testing.T) {
 	// check that all expected indexes are loaded without errors
 	indexIDs := restic.NewIDSet()
 	var indexErr error
-	rtest.OK(t, index.ForAllIndexes(context.TODO(), repo.Backend(), repo, func(id restic.ID, index *index.Index, oldFormat bool, err error) error {
+	rtest.OK(t, index.ForAllIndexes(context.TODO(), repo, func(id restic.ID, index *index.Index, oldFormat bool, err error) error {
 		if err != nil {
 			indexErr = err
 		}
@@ -42,7 +42,7 @@ func TestRepositoryForAllIndexes(t *testing.T) {
 	// must failed with the returned error
 	iterErr := errors.New("error to pass upwards")
 
-	err := index.ForAllIndexes(context.TODO(), repo.Backend(), repo, func(id restic.ID, index *index.Index, oldFormat bool, err error) error {
+	err := index.ForAllIndexes(context.TODO(), repo, func(id restic.ID, index *index.Index, oldFormat bool, err error) error {
 		return iterErr
 	})
 
diff --git a/internal/index/master_index_test.go b/internal/index/master_index_test.go
index bf8ec3f41..5260a11a0 100644
--- a/internal/index/master_index_test.go
+++ b/internal/index/master_index_test.go
@@ -357,7 +357,7 @@ func TestIndexSave(t *testing.T) {
 func testIndexSave(t *testing.T, version uint) {
 	repo := createFilledRepo(t, 3, version)
 
-	err := repo.LoadIndex(context.TODO(), nil)
+	err := repo.LoadIndex(context.TODO())
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -382,7 +382,7 @@ func testIndexSave(t *testing.T, version uint) {
 		t.Error(err)
 	}
 
-	hints, errs := checker.LoadIndex(context.TODO(), nil)
+	hints, errs := checker.LoadIndex(context.TODO())
 	for _, h := range hints {
 		t.Logf("hint: %v\n", h)
 	}
diff --git a/internal/repository/packer_manager_test.go b/internal/repository/packer_manager_test.go
index 8984073da..90f716e0d 100644
--- a/internal/repository/packer_manager_test.go
+++ b/internal/repository/packer_manager_test.go
@@ -89,24 +89,6 @@ func testPackerManager(t testing.TB) int64 {
 	return int64(bytes)
 }
 
-func TestPackerManagerWithOversizeBlob(t *testing.T) {
-	packFiles := int(0)
-	sizeLimit := uint(512 * 1024)
-	pm := newPackerManager(crypto.NewRandomKey(), restic.DataBlob, sizeLimit, func(ctx context.Context, tp restic.BlobType, p *Packer) error {
-		packFiles++
-		return nil
-	})
-
-	for _, i := range []uint{sizeLimit / 2, sizeLimit, sizeLimit / 3} {
-		_, err := pm.SaveBlob(context.TODO(), restic.DataBlob, restic.ID{}, make([]byte, i), 0)
-		test.OK(t, err)
-	}
-	test.OK(t, pm.Flush(context.TODO()))
-
-	// oversized blob must be stored in a separate packfile
-	test.Equals(t, packFiles, 2)
-}
-
 func BenchmarkPackerManager(t *testing.B) {
 	// Run testPackerManager if it hasn't run already, to set totalSize.
 	once.Do(func() {
diff --git a/internal/repository/repack_test.go b/internal/repository/repack_test.go
index c8570a9d4..bb31eba77 100644
--- a/internal/repository/repack_test.go
+++ b/internal/repository/repack_test.go
@@ -213,7 +213,7 @@ func reloadIndex(t *testing.T, repo restic.Repository) {
 		t.Fatal(err)
 	}
 
-	if err := repo.LoadIndex(context.TODO(), nil); err != nil {
+	if err := repo.LoadIndex(context.TODO()); err != nil {
 		t.Fatalf("error loading new index: %v", err)
 	}
 }
diff --git a/internal/repository/repository_test.go b/internal/repository/repository_test.go
index d362b0b5e..f26bf46f2 100644
--- a/internal/repository/repository_test.go
+++ b/internal/repository/repository_test.go
@@ -255,7 +255,7 @@ func TestRepositoryLoadIndex(t *testing.T) {
 	defer cleanup()
 
 	repo := repository.TestOpenLocal(t, repodir)
-	rtest.OK(t, repo.LoadIndex(context.TODO(), nil))
+	rtest.OK(t, repo.LoadIndex(context.TODO()))
 }
 
 // loadIndex loads the index id from backend and returns it.
@@ -324,7 +324,7 @@ func TestRepositoryLoadUnpackedRetryBroken(t *testing.T) {
 	err = repo.SearchKey(context.TODO(), rtest.TestPassword, 10, "")
 	rtest.OK(t, err)
 
-	rtest.OK(t, repo.LoadIndex(context.TODO(), nil))
+	rtest.OK(t, repo.LoadIndex(context.TODO()))
 }
 
 func BenchmarkLoadIndex(b *testing.B) {