From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 76EE81FF38E for ; Tue, 14 May 2024 16:12:42 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 6611B8355; Tue, 14 May 2024 16:12:53 +0200 (CEST) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Tue, 14 May 2024 16:12:48 +0200 Message-Id: <20240514141248.1614306-2-d.csapak@proxmox.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20240514141248.1614306-1-d.csapak@proxmox.com> References: <20240514141248.1614306-1-d.csapak@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.016 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment 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 2/2] tape: write informational MAM attributes on tapes 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: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" namely: Vendor: Proxmox Name: Backup Server Version: current running package version User Label Text: the label text Media Pool: the current media pool write it on labeling and when writing a new media-set to a tape. While we currently don't use this info for anything, this can help users to identify tapes, even with different backup software. If we need it in the future, we can e.g. make decisions based on these fields (e.g. the version). On format, delete them again. Note that some VTLs don't correctly delete the attributes from the virtual tapes. Signed-off-by: Dominik Csapak --- pbs-tape/Cargo.toml | 1 + pbs-tape/src/sg_tape.rs | 39 ++++++++++++++++++++++ pbs-tape/src/sg_tape/mam.rs | 61 +++++++++++++++++++++++++++++++++- src/api2/tape/drive.rs | 2 ++ src/tape/drive/lto/mod.rs | 6 ++++ src/tape/drive/mod.rs | 5 +++ src/tape/drive/virtual_tape.rs | 4 +++ 7 files changed, 117 insertions(+), 1 deletion(-) diff --git a/pbs-tape/Cargo.toml b/pbs-tape/Cargo.toml index 970315b7a..f4110706b 100644 --- a/pbs-tape/Cargo.toml +++ b/pbs-tape/Cargo.toml @@ -34,4 +34,5 @@ proxmox-schema = { workspace = true, features = [ "api-macro" ] } proxmox-router = { workspace = true, features = ["cli", "server"] } pbs-api-types.workspace = true +pbs-buildcfg.workspace = true pbs-config.workspace = true diff --git a/pbs-tape/src/sg_tape.rs b/pbs-tape/src/sg_tape.rs index f30481b31..058c14ae9 100644 --- a/pbs-tape/src/sg_tape.rs +++ b/pbs-tape/src/sg_tape.rs @@ -295,6 +295,8 @@ impl SgTape { self.erase_media(fast)? } + self.clear_mam_attributes(); + Ok(()) } } @@ -1048,6 +1050,43 @@ impl SgTape { Ok(status) } + + /// Tries to write useful attributes to the MAM like Vendor/Application/Version + pub fn write_mam_attributes(&mut self, label: Option, pool: Option) { + let version = format!( + "{}-{}", + pbs_buildcfg::PROXMOX_PKG_VERSION, + pbs_buildcfg::PROXMOX_PKG_RELEASE + ); + let mut attribute_list: Vec<(u16, &[u8])> = vec![ + (0x08_00, b"Proxmox"), + (0x08_01, b"Backup Server"), + (0x08_02, version.as_bytes()), + ]; + if let Some(ref label) = label { + attribute_list.push((0x08_03, label.as_bytes())); + } + + if let Some(ref pool) = pool { + attribute_list.push((0x08_08, pool.as_bytes())); + } + + for (id, data) in attribute_list { + if let Err(err) = write_mam_attribute(&mut self.file, id, data) { + log::warn!("could not set MAM Attribute {id:x}: {err}"); + } + } + } + + // clear all custom set mam attributes + fn clear_mam_attributes(&mut self) { + for attr in [0x08_00, 0x08_01, 0x08_02, 0x08_03, 0x08_08] { + // ignore error + if let Err(err) = write_mam_attribute(&mut self.file, attr, b"") { + log::warn!("could not clear MAM attribute {attr:x}: {err}"); + } + } + } } pub struct SgTapeReader<'a> { diff --git a/pbs-tape/src/sg_tape/mam.rs b/pbs-tape/src/sg_tape/mam.rs index 74e09c6d6..4e995d0b9 100644 --- a/pbs-tape/src/sg_tape/mam.rs +++ b/pbs-tape/src/sg_tape/mam.rs @@ -8,7 +8,7 @@ use proxmox_io::ReadExt; use pbs_api_types::MamAttribute; -use crate::sgutils2::SgRaw; +use crate::sgutils2::{alloc_page_aligned_buffer, SgRaw}; use super::TapeAlertFlags; @@ -143,6 +143,65 @@ fn read_tape_mam(file: &mut F) -> Result, Error> { .map(|v| v.to_vec()) } +/// Write attribute to MAM +pub fn write_mam_attribute( + file: &mut F, + attribute_id: u16, + data: &[u8], +) -> Result<(), Error> { + let mut sg_raw = SgRaw::new(file, 0)?; + + let mut parameters = Vec::new(); + + let attribute = MAM_ATTRIBUTE_NAMES + .get(&attribute_id) + .ok_or_else(|| format_err!("MAM attribute '{attribute_id:x}' unknown"))?; + + let mut attr_data = Vec::new(); + attr_data.extend(attribute_id.to_be_bytes()); + attr_data.push(match attribute.format { + MamFormat::BINARY | MamFormat::DEC => 0x00, + MamFormat::ASCII => 0x01, + MamFormat::TEXT => 0x02, + }); + let len = if data.is_empty() { 0 } else { attribute.len }; + attr_data.extend(len.to_be_bytes()); + attr_data.extend(data); + if !data.is_empty() && data.len() < attribute.len as usize { + attr_data.resize(attr_data.len() - data.len() + attribute.len as usize, 0); + } else if data.len() > u16::MAX as usize { + bail!("data to long"); + } + + parameters.extend(attr_data); + + let mut data_out = alloc_page_aligned_buffer(parameters.len() + 4)?; + data_out[..4].copy_from_slice(&(parameters.len() as u32).to_be_bytes()); + data_out[4..].copy_from_slice(¶meters); + + let mut cmd = vec![ + 0x8d, // WRITE ATTRIBUTE CDB (8Dh) + 0x01, // WTC=1 + 0x00, // reserved + 0x00, // reserved + 0x00, // reserved + 0x00, // Volume Number + 0x00, // reserved + 0x00, // Partition Number + 0x00, // reserved + 0x00, // reserved + ]; + cmd.extend((data_out.len() as u32).to_be_bytes()); + cmd.extend([ + 0x00, // reserved + 0x00, // reserved + ]); + + sg_raw.do_out_command(&cmd, &data_out)?; + + Ok(()) +} + /// Read Medium auxiliary memory attributes (cartridge memory) using raw SCSI command. pub fn read_mam_attributes(file: &mut F) -> Result, Error> { let data = read_tape_mam(file)?; diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 7a791e09b..c6fc9f9c2 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -606,6 +606,8 @@ fn write_media_label( drive.rewind()?; + drive.write_additional_attributes(Some(media_id.label.label_text), pool); + Ok(()) } diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs index f3143c907..23e043ce6 100644 --- a/src/tape/drive/lto/mod.rs +++ b/src/tape/drive/lto/mod.rs @@ -225,6 +225,8 @@ impl TapeDriver for LtoTapeHandle { self.set_encryption(encrypt_fingerprint)?; + self.write_additional_attributes(None, Some(media_set_label.pool.clone())); + Ok(()) } @@ -272,6 +274,10 @@ impl TapeDriver for LtoTapeHandle { fn get_volume_statistics(&mut self) -> Result { self.volume_statistics() } + + fn write_additional_attributes(&mut self, label: Option, pool: Option) { + self.sg_tape.write_mam_attributes(label, pool) + } } fn run_sg_tape_cmd(subcmd: &str, args: &[&str], fd: RawFd) -> Result { diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index b21a62d20..b912b234d 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -245,6 +245,11 @@ pub trait TapeDriver { /// Returns volume statistics from a loaded tape fn get_volume_statistics(&mut self) -> Result; + + /// Writes additional attributes on the drive, like the vendor/application/etc. (e.g. on MAM) + /// + /// Since it's not fatal when it does not work, it only logs warnings in that case + fn write_additional_attributes(&mut self, label: Option, pool: Option); } /// A boxed implementor of [`MediaChange`]. diff --git a/src/tape/drive/virtual_tape.rs b/src/tape/drive/virtual_tape.rs index c183e2681..866e4d323 100644 --- a/src/tape/drive/virtual_tape.rs +++ b/src/tape/drive/virtual_tape.rs @@ -465,6 +465,10 @@ impl TapeDriver for VirtualTapeHandle { fn get_volume_statistics(&mut self) -> Result { Ok(Default::default()) } + + fn write_additional_attributes(&mut self, _label: Option, _pool: Option) { + // not implemented + } } impl MediaChange for VirtualTapeHandle { -- 2.39.2 _______________________________________________ pbs-devel mailing list pbs-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel