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 138D271175 for ; Wed, 7 Apr 2021 12:24:41 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id E96B9F381 for ; Wed, 7 Apr 2021 12:24:10 +0200 (CEST) Received: from elsa.proxmox.com (unknown [94.136.29.99]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2B088F345 for ; Wed, 7 Apr 2021 12:24:07 +0200 (CEST) Received: by elsa.proxmox.com (Postfix, from userid 0) id 15D58AEAF26; Wed, 7 Apr 2021 12:24:07 +0200 (CEST) From: Dietmar Maurer To: pbs-devel@lists.proxmox.com Date: Wed, 7 Apr 2021 12:23:04 +0200 Message-Id: <20210407102308.9750-8-dietmar@proxmox.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210407102308.9750-1-dietmar@proxmox.com> References: <20210407102308.9750-1-dietmar@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RDNS_NONE 1.274 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 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [proxmox-tape.rs, pmt.rs, mod.rs] Subject: [pbs-devel] [PATCH 07/11] tape: make sure there is a filemark at the end of the tape 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: Wed, 07 Apr 2021 10:24:41 -0000 --- src/bin/pmt.rs | 2 +- src/bin/proxmox-tape.rs | 2 +- src/tape/drive/lto/mod.rs | 8 ++-- src/tape/drive/lto/sg_tape.rs | 71 +++++++++++++++++++++++++++++----- src/tape/drive/mod.rs | 6 ++- src/tape/drive/virtual_tape.rs | 4 +- src/tape/pool_writer/mod.rs | 2 +- 7 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/bin/pmt.rs b/src/bin/pmt.rs index da0d4fd9..854364c7 100644 --- a/src/bin/pmt.rs +++ b/src/bin/pmt.rs @@ -383,7 +383,7 @@ fn eject(param: Value) -> Result<(), Error> { fn eod(param: Value) -> Result<(), Error> { let mut handle = get_tape_handle(¶m)?; - handle.move_to_eom()?; + handle.move_to_eom(false)?; Ok(()) } diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs index 2a784632..f1de6236 100644 --- a/src/bin/proxmox-tape.rs +++ b/src/bin/proxmox-tape.rs @@ -551,7 +551,7 @@ fn move_to_eom(mut param: Value) -> Result<(), Error> { let mut drive = open_drive(&config, &drive)?; - drive.move_to_eom()?; + drive.move_to_eom(false)?; Ok(()) } diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs index 25df897f..7fcef8a0 100644 --- a/src/tape/drive/lto/mod.rs +++ b/src/tape/drive/lto/mod.rs @@ -215,13 +215,15 @@ impl TapeDriver for LtoTapeHandle { } /// Go to the end of the recorded media (for appending files). - fn move_to_eom(&mut self) -> Result<(), Error> { - self.sg_tape.move_to_eom() + fn move_to_eom(&mut self, write_missing_eof: bool) -> Result<(), Error> { + self.sg_tape.move_to_eom(write_missing_eof) } fn move_to_last_file(&mut self) -> Result<(), Error> { - self.move_to_eom()?; + self.move_to_eom(false)?; + + self.sg_tape.check_filemark()?; let pos = self.current_file_number()?; diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs index fd1a067a..9af0eae3 100644 --- a/src/tape/drive/lto/sg_tape.rs +++ b/src/tape/drive/lto/sg_tape.rs @@ -190,8 +190,6 @@ impl SgTape { bail!("detecthed partitioned tape - not supported"); } - println!("DATA: {:?}", page); - Ok(page) } @@ -222,7 +220,35 @@ impl SgTape { Ok(()) } - pub fn move_to_eom(&mut self) -> Result<(), Error> { + /// Check if we are positioned after a filemark (or BOT) + pub fn check_filemark(&mut self) -> Result { + + let pos = self.position()?; + if pos.logical_object_number == 0 { + // at BOT, Ok (no filemark required) + return Ok(true); + } + + // Note: SPACE blocks returns Err at filemark + match self.space(-1, true) { + Ok(_) => { + self.space(1, true) // move back to end + .map_err(|err| format_err!("check_filemark failed (space forward) - {}", err))?; + Ok(false) + } + Err(ScsiError::Sense(SenseInfo { sense_key: 0, asc: 0, ascq: 1 })) => { + // Filemark detected - good + self.space(1, true) // move back to end + .map_err(|err| format_err!("check_filemark failed (space forward) - {}", err))?; + Ok(true) + } + Err(err) => { + bail!("check_filemark failed - {:?}", err); + } + } + } + + pub fn move_to_eom(&mut self, write_missing_eof: bool) -> Result<(), Error> { let mut sg_raw = SgRaw::new(&mut self.file, 16)?; sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); let mut cmd = Vec::new(); @@ -231,35 +257,60 @@ impl SgTape { sg_raw.do_command(&cmd) .map_err(|err| format_err!("move to EOD failed - {}", err))?; + if write_missing_eof { + if !self.check_filemark()? { + self.write_filemarks(1, false)?; + } + } + Ok(()) } - pub fn space_filemarks(&mut self, count: isize) -> Result<(), Error> { + fn space(&mut self, count: isize, blocks: bool) -> Result<(), ScsiError> { let mut sg_raw = SgRaw::new(&mut self.file, 16)?; sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); let mut cmd = Vec::new(); // Use short command if possible (supported by all drives) if (count <= 0x7fffff) && (count > -0x7fffff) { - cmd.extend(&[0x11, 0x01]); // SPACE(6) with filemarks + cmd.push(0x11); // SPACE(6) + if blocks { + cmd.push(0); // blocks + } else { + cmd.push(1); // filemarks + } cmd.push(((count >> 16) & 0xff) as u8); cmd.push(((count >> 8) & 0xff) as u8); cmd.push((count & 0xff) as u8); cmd.push(0); //control byte } else { - - cmd.extend(&[0x91, 0x01, 0, 0]); // SPACE(16) with filemarks + cmd.push(0x91); // SPACE(16) + if blocks { + cmd.push(0); // blocks + } else { + cmd.push(1); // filemarks + } + cmd.extend(&[0, 0]); // reserved let count: i64 = count as i64; cmd.extend(&count.to_be_bytes()); - cmd.extend(&[0, 0, 0, 0]); + cmd.extend(&[0, 0, 0, 0]); // reserved } - sg_raw.do_command(&cmd) - .map_err(|err| format_err!("space filemarks failed - {}", err))?; + sg_raw.do_command(&cmd)?; Ok(()) } + pub fn space_filemarks(&mut self, count: isize) -> Result<(), Error> { + self.space(count, false) + .map_err(|err| format_err!("space filemarks failed - {}", err)) + } + + pub fn space_blocks(&mut self, count: isize) -> Result<(), Error> { + self.space(count, true) + .map_err(|err| format_err!("space blocks failed - {}", err)) + } + pub fn eject(&mut self) -> Result<(), Error> { let mut sg_raw = SgRaw::new(&mut self.file, 16)?; sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT); diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index 28ff0a3a..cd02e16d 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -84,8 +84,10 @@ pub trait TapeDriver { /// Move to end of recorded data /// - /// We assume this flushes the tape write buffer. - fn move_to_eom(&mut self) -> Result<(), Error>; + /// We assume this flushes the tape write buffer. if + /// write_missing_eof is true, we verify that there is a filemark + /// at the end. If not, we write one. + fn move_to_eom(&mut self, write_missing_eof: bool) -> Result<(), Error>; /// Move to last file fn move_to_last_file(&mut self) -> Result<(), Error>; diff --git a/src/tape/drive/virtual_tape.rs b/src/tape/drive/virtual_tape.rs index bb4b4e3c..a852056a 100644 --- a/src/tape/drive/virtual_tape.rs +++ b/src/tape/drive/virtual_tape.rs @@ -249,7 +249,7 @@ impl TapeDriver for VirtualTapeHandle { /// Move to last file fn move_to_last_file(&mut self) -> Result<(), Error> { - self.move_to_eom()?; + self.move_to_eom(false)?; if self.current_file_number()? == 0 { bail!("move_to_last_file failed - media contains no data"); @@ -347,7 +347,7 @@ impl TapeDriver for VirtualTapeHandle { } } - fn move_to_eom(&mut self) -> Result<(), Error> { + fn move_to_eom(&mut self, _write_missing_eof: bool) -> Result<(), Error> { let mut status = self.load_status()?; match status.current_tape { Some(VirtualTapeStatus { ref name, ref mut pos }) => { diff --git a/src/tape/pool_writer/mod.rs b/src/tape/pool_writer/mod.rs index 05aa52a4..99fdb48c 100644 --- a/src/tape/pool_writer/mod.rs +++ b/src/tape/pool_writer/mod.rs @@ -297,7 +297,7 @@ impl PoolWriter { if !status.at_eom { worker.log(String::from("moving to end of media")); - status.drive.move_to_eom()?; + status.drive.move_to_eom(true)?; status.at_eom = true; } -- 2.20.1