From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v2] api2/tape/restore: restore_snapshot_archive: only ignore tape errors
Date: Tue, 13 Apr 2021 14:05:37 +0200 [thread overview]
Message-ID: <20210413120537.13220-1-d.csapak@proxmox.com> (raw)
we sometimes want to ignore tape errors, e.g., if a file was incomplete,
so we must check those conditions only when the error really comes
from the tape side and not from the storage side.
Introduce a RestoreError where we then can decide if we want to handle
tape errors.
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
changes from v1:
* change type of inner of Disk to String (we do not need the exact error)
* add an 'Other' type that we use for worker.check_abort
* make the error types more explicit by using RestoreError::{TYPE} functions
src/api2/tape/restore.rs | 135 ++++++++++++++++++++++++---------------
1 file changed, 84 insertions(+), 51 deletions(-)
diff --git a/src/api2/tape/restore.rs b/src/api2/tape/restore.rs
index 9f79f06f..b5630524 100644
--- a/src/api2/tape/restore.rs
+++ b/src/api2/tape/restore.rs
@@ -646,6 +646,18 @@ fn restore_chunk_archive<'a>(
Ok(Some(chunks))
}
+// we want to differentiate between errors that come from disk and tape side,
+// so map anyhow::Error to tape and io::Error to disk
+#[derive(thiserror::Error, Debug)]
+pub enum RestoreError {
+ #[error("tape error: {0}")]
+ Tape(#[from] Error),
+ #[error("{0}")]
+ Disk(String),
+ #[error("{0}")]
+ Other(String),
+}
+
fn restore_snapshot_archive<'a>(
worker: &WorkerTask,
reader: Box<dyn 'a + TapeRead>,
@@ -655,7 +667,7 @@ fn restore_snapshot_archive<'a>(
let mut decoder = pxar::decoder::sync::Decoder::from_std(reader)?;
match try_restore_snapshot_archive(worker, &mut decoder, snapshot_path) {
Ok(()) => Ok(true),
- Err(err) => {
+ Err(RestoreError::Tape(err)) => {
let reader = decoder.input();
// check if this stream is marked incomplete
@@ -671,26 +683,28 @@ fn restore_snapshot_archive<'a>(
// else the archive is corrupt
Err(err)
}
+ Err(RestoreError::Other(err)) | Err(RestoreError::Disk(err)) => bail!(err),
}
}
+// we have to map the errors here according to RestoreError
fn try_restore_snapshot_archive<R: pxar::decoder::SeqRead>(
worker: &WorkerTask,
decoder: &mut pxar::decoder::sync::Decoder<R>,
snapshot_path: &Path,
-) -> Result<(), Error> {
+) -> Result<(), RestoreError> {
- let _root = match decoder.next() {
- None => bail!("missing root entry"),
- Some(root) => {
- let root = root?;
- match root.kind() {
- pxar::EntryKind::Directory => { /* Ok */ }
- _ => bail!("wrong root entry type"),
- }
- root
- }
- };
+ let root_res = decoder
+ .next()
+ .ok_or_else(|| RestoreError::Tape(format_err!("missing root entry")))?;
+
+ let root = root_res.map_err(|err| RestoreError::Tape(err.into()))?;
+
+ if !matches!(root.kind(), pxar::EntryKind::Directory) {
+ return Err(RestoreError::Tape(
+ format_err!("wrong root entry type").into(),
+ ));
+ }
let root_path = Path::new("/");
let manifest_file_name = OsStr::new(MANIFEST_BLOB_NAME);
@@ -698,33 +712,39 @@ fn try_restore_snapshot_archive<R: pxar::decoder::SeqRead>(
let mut manifest = None;
loop {
- worker.check_abort()?;
+ worker
+ .check_abort()
+ .map_err(|err| RestoreError::Other(format!("{}", err)))?;
let entry = match decoder.next() {
None => break,
- Some(entry) => entry?,
+ Some(entry) => entry.map_err(|err| RestoreError::Tape(err.into()))?,
};
+
let entry_path = entry.path();
- match entry.kind() {
- pxar::EntryKind::File { .. } => { /* Ok */ }
- _ => bail!("wrong entry type for {:?}", entry_path),
+ if !matches!(entry.kind(), pxar::EntryKind::File { .. }) {
+ return Err(RestoreError::Tape(format_err!(
+ "wrong entry type for {:?}",
+ entry_path
+ )));
}
- match entry_path.parent() {
- None => bail!("wrong parent for {:?}", entry_path),
- Some(p) => {
- if p != root_path {
- bail!("wrong parent for {:?}", entry_path);
- }
- }
+
+ let path = entry_path
+ .parent()
+ .ok_or_else(|| RestoreError::Tape(format_err!("wrong parent for {:?}", entry_path)))?;
+
+ if path != root_path {
+ return Err(RestoreError::Tape(format_err!(
+ "wrong parent for {:?}",
+ entry_path
+ )));
}
let filename = entry.file_name();
- let mut contents = match decoder.contents() {
- None => bail!("missing file content"),
- Some(contents) => contents,
- };
-
+ let mut contents = decoder
+ .contents()
+ .ok_or_else(|| RestoreError::Tape(format_err!("missing file content")))?;
let mut archive_path = snapshot_path.to_owned();
archive_path.push(&filename);
@@ -733,31 +753,37 @@ fn try_restore_snapshot_archive<R: pxar::decoder::SeqRead>(
if filename == manifest_file_name {
- let blob = DataBlob::load_from_reader(&mut contents)?;
+ let blob = DataBlob::load_from_reader(&mut contents).map_err(RestoreError::Tape)?;
let options = CreateOptions::new();
- replace_file(&tmp_path, blob.raw_data(), options)?;
+ replace_file(&tmp_path, blob.raw_data(), options)
+ .map_err(|err| RestoreError::Disk(err.to_string()))?;
- manifest = Some(BackupManifest::try_from(blob)?);
+ manifest = Some(BackupManifest::try_from(blob).map_err(RestoreError::Tape)?);
} else {
let mut tmpfile = std::fs::OpenOptions::new()
.write(true)
.create(true)
.read(true)
.open(&tmp_path)
- .map_err(|err| format_err!("restore {:?} failed - {}", tmp_path, err))?;
-
- std::io::copy(&mut contents, &mut tmpfile)?;
-
- if let Err(err) = std::fs::rename(&tmp_path, &archive_path) {
- bail!("Atomic rename file {:?} failed - {}", archive_path, err);
- }
+ .map_err(|err| {
+ RestoreError::Disk(format!("restore {:?} failed - {}", tmp_path, err))
+ })?;
+
+ // error type is a bit ambiguous, but err o safe side and assume
+ // a tape error
+ std::io::copy(&mut contents, &mut tmpfile)
+ .map_err(|err| RestoreError::Tape(err.into()))?;
+
+ std::fs::rename(&tmp_path, &archive_path).map_err(|err| {
+ RestoreError::Disk(format!(
+ "Atomic rename file {:?} failed - {}",
+ archive_path, err
+ ))
+ })?;
}
}
- let manifest = match manifest {
- None => bail!("missing manifest"),
- Some(manifest) => manifest,
- };
+ let manifest = manifest.ok_or_else(|| RestoreError::Tape(format_err!("missing manifest")))?;
for item in manifest.files() {
let mut archive_path = snapshot_path.to_owned();
@@ -765,18 +791,22 @@ fn try_restore_snapshot_archive<R: pxar::decoder::SeqRead>(
match archive_type(&item.filename)? {
ArchiveType::DynamicIndex => {
- let index = DynamicIndexReader::open(&archive_path)?;
+ let index = DynamicIndexReader::open(&archive_path)
+ .map_err(|err| RestoreError::Disk(err.to_string()))?;
let (csum, size) = index.compute_csum();
manifest.verify_file(&item.filename, &csum, size)?;
}
ArchiveType::FixedIndex => {
- let index = FixedIndexReader::open(&archive_path)?;
+ let index = FixedIndexReader::open(&archive_path)
+ .map_err(|err| RestoreError::Disk(err.to_string()))?;
let (csum, size) = index.compute_csum();
manifest.verify_file(&item.filename, &csum, size)?;
}
ArchiveType::Blob => {
- let mut tmpfile = std::fs::File::open(&archive_path)?;
- let (csum, size) = compute_file_csum(&mut tmpfile)?;
+ let mut tmpfile = std::fs::File::open(&archive_path)
+ .map_err(|err| RestoreError::Disk(err.to_string()))?;
+ let (csum, size) = compute_file_csum(&mut tmpfile)
+ .map_err(|err| RestoreError::Disk(err.to_string()))?;
manifest.verify_file(&item.filename, &csum, size)?;
}
}
@@ -788,9 +818,12 @@ fn try_restore_snapshot_archive<R: pxar::decoder::SeqRead>(
let mut tmp_manifest_path = manifest_path.clone();
tmp_manifest_path.set_extension("tmp");
- if let Err(err) = std::fs::rename(&tmp_manifest_path, &manifest_path) {
- bail!("Atomic rename manifest {:?} failed - {}", manifest_path, err);
- }
+ std::fs::rename(&tmp_manifest_path, &manifest_path).map_err(|err| {
+ RestoreError::Disk(format!(
+ "Atomic rename manifest {:?} failed - {}",
+ manifest_path, err
+ ))
+ })?;
Ok(())
}
--
2.20.1
next reply other threads:[~2021-04-13 12:05 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-13 12:05 Dominik Csapak [this message]
2021-04-14 8:41 ` Wolfgang Bumiller
2021-04-14 8:51 Dietmar Maurer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210413120537.13220-1-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal