From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 6FCA271682 for ; Tue, 29 Jun 2021 08:36:08 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 65C429FFC for ; Tue, 29 Jun 2021 08:36:08 +0200 (CEST) Received: from dev7.proxmox.com (unknown [94.136.29.99]) by firstgate.proxmox.com (Proxmox) with ESMTP id BA9819FEF for ; Tue, 29 Jun 2021 08:36:07 +0200 (CEST) Received: by dev7.proxmox.com (Postfix, from userid 0) id 9A336806C9; Tue, 29 Jun 2021 08:36:01 +0200 (CEST) From: Dietmar Maurer To: pbs-devel@lists.proxmox.com Date: Tue, 29 Jun 2021 08:35:55 +0200 Message-Id: <20210629063555.3132270-1-dietmar@proxmox.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.581 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [PATCH proxmox-backup v3] tape: fix LTO locate_file for HP drives X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 Jun 2021 06:36:08 -0000 Add test code to the first locate_file command, compute locate_offset. Subsequent locate_file commands use that offset. Signed-off-by: Dominik Csapak Signed-off-by: Dietmar Maurer --- This is based on Dominiks patches: [PATCH proxmox-backup v2 1/2] tape/drive: add 'set_locate_offset' to TapeDriver Trait [PATCH proxmox-backup v2 2/2] api2/tape/restore: use file offset to compensate for some tape drives Canges in v3: - Do not mofify the TapeDriver Trait. Instzead, do everything inside sg_tage.rs - Add special case for locate_file(1) src/tape/drive/lto/sg_tape.rs | 69 +++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs index 25c239a2..4508f6f3 100644 --- a/src/tape/drive/lto/sg_tape.rs +++ b/src/tape/drive/lto/sg_tape.rs @@ -3,6 +3,7 @@ use std::fs::{File, OpenOptions}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; use std::path::Path; +use std::convert::TryFrom; use anyhow::{bail, format_err, Error}; use endian_trait::Endian; @@ -122,6 +123,7 @@ pub struct LtoTapeStatus { pub struct SgTape { file: File, + locate_offset: Option, info: InquiryInfo, encryption_key_loaded: bool, } @@ -145,6 +147,7 @@ impl SgTape { file, info, encryption_key_loaded: false, + locate_offset: None, }) } @@ -300,26 +303,76 @@ impl SgTape { return self.rewind(); } - let position = position -1; + const SPACE_ONE_FILEMARK: &[u8] = &[0x11, 0x01, 0, 0, 1, 0]; + + // Special case for position 1, because LOCATE 0 does not work + if position == 1 { + self.rewind()?; + let mut sg_raw = SgRaw::new(&mut self.file, 16)?; + sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); + sg_raw.do_command(SPACE_ONE_FILEMARK) + .map_err(|err| format_err!("locate file {} (space) failed - {}", position, err))?; + return Ok(()); + } let mut sg_raw = SgRaw::new(&mut self.file, 16)?; sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); - let mut cmd = Vec::new(); + // Note: LOCATE(16) works for LTO4 or newer + // + // It seems the LOCATE command behaves slightly different across vendors + // e.g. for IBM drives, LOCATE 1 moves to File #2, but + // for HP drives, LOCATE 1 move to File #1 + + let fixed_position = if let Some(locate_offset) = self.locate_offset { + if locate_offset < 0 { + position.saturating_sub((-locate_offset) as u64) + } else { + position.saturating_add(locate_offset as u64) + } + } else { + position + }; + // always sub(1), so that it works for IBM drives without locate_offset + let fixed_position = fixed_position.saturating_sub(1); + + let mut cmd = Vec::new(); cmd.extend(&[0x92, 0b000_01_000, 0, 0]); // LOCATE(16) filemarks - cmd.extend(&position.to_be_bytes()); + cmd.extend(&fixed_position.to_be_bytes()); cmd.extend(&[0, 0, 0, 0]); sg_raw.do_command(&cmd) .map_err(|err| format_err!("locate file {} failed - {}", position, err))?; - // move to other side of filemark - cmd.truncate(0); - cmd.extend(&[0x11, 0x01, 0, 0, 1, 0]); // SPACE(6) one filemarks - - sg_raw.do_command(&cmd) + // LOCATE always position at the BOT side of the filemark, so + // we need to move to other side of filemark + sg_raw.do_command(SPACE_ONE_FILEMARK) .map_err(|err| format_err!("locate file {} (space) failed - {}", position, err))?; + if self.locate_offset.is_none() { + // check if we landed at correct position + let current_file = self.current_file_number()?; + if current_file != position { + let offset: i64 = + i64::try_from((position as i128) - (current_file as i128)).map_err(|err| { + format_err!( + "locate_file: offset between {} and {} invalid: {}", + position, + current_file, + err + ) + })?; + self.locate_offset = Some(offset); + self.locate_file(position)?; + let current_file = self.current_file_number()?; + if current_file != position { + bail!("locate_file: compensating offset did not work, aborting..."); + } + } else { + self.locate_offset = Some(0); + } + } + Ok(()) } -- 2.30.2