From 4188fd59a06debfa8442ef4c1fde5bf1fc917559 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 19 Feb 2021 16:48:19 +0100 Subject: [PATCH] tape: cache changer state --- src/api2/tape/changer.rs | 12 ++++- src/bin/proxmox_tape/changer.rs | 6 +++ src/tape/changer/mod.rs | 76 +++++++++++++++++++++++++-- src/tape/changer/online_status_map.rs | 2 +- 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/api2/tape/changer.rs b/src/api2/tape/changer.rs index 212ca8eb..68a61f59 100644 --- a/src/api2/tape/changer.rs +++ b/src/api2/tape/changer.rs @@ -39,6 +39,11 @@ use crate::{ name: { schema: CHANGER_NAME_SCHEMA, }, + cache: { + description: "Use cached value.", + optional: true, + default: true, + }, }, }, returns: { @@ -50,14 +55,17 @@ use crate::{ }, )] /// Get tape changer status -pub async fn get_status(name: String) -> Result, Error> { +pub async fn get_status( + name: String, + cache: bool, +) -> Result, Error> { let (config, _digest) = config::drive::config()?; let mut changer_config: ScsiTapeChanger = config.lookup("changer", &name)?; let status = tokio::task::spawn_blocking(move || { - changer_config.status() + changer_config.status(cache) }).await??; let state_path = Path::new(TAPE_STATUS_DIR); diff --git a/src/bin/proxmox_tape/changer.rs b/src/bin/proxmox_tape/changer.rs index d5b6ede1..9f635dca 100644 --- a/src/bin/proxmox_tape/changer.rs +++ b/src/bin/proxmox_tape/changer.rs @@ -217,6 +217,12 @@ fn get_config( schema: CHANGER_NAME_SCHEMA, optional: true, }, + cache: { + description: "Use cached value.", + type: bool, + optional: true, + default: true, + }, }, }, )] diff --git a/src/tape/changer/mod.rs b/src/tape/changer/mod.rs index f9f9da98..e1dda621 100644 --- a/src/tape/changer/mod.rs +++ b/src/tape/changer/mod.rs @@ -11,12 +11,20 @@ mod online_status_map; pub use online_status_map::*; use std::collections::HashSet; +use std::path::PathBuf; use anyhow::{bail, Error}; use serde::{Serialize, Deserialize}; use serde_json::Value; -use proxmox::api::schema::parse_property_string; +use proxmox::{ + api::schema::parse_property_string, + tools::fs::{ + CreateOptions, + replace_file, + file_read_optional_string, + }, +}; use crate::api2::types::{ SLOT_ARRAY_SCHEMA, @@ -158,7 +166,7 @@ impl MtxStatus { /// Interface to SCSI changer devices pub trait ScsiMediaChange { - fn status(&mut self) -> Result; + fn status(&mut self, use_cache: bool) -> Result; fn load_slot(&mut self, from_slot: u64, drivenum: u64) -> Result<(), Error>; @@ -398,12 +406,29 @@ const USE_MTX: bool = false; impl ScsiMediaChange for ScsiTapeChanger { - fn status(&mut self) -> Result { - if USE_MTX { + fn status(&mut self, use_cache: bool) -> Result { + if use_cache { + if let Some(state) = load_changer_state_cache(&self.name)? { + return Ok(state); + } + } + + let status = if USE_MTX { mtx::mtx_status(&self) } else { sg_pt_changer::status(&self) + }; + + match &status { + Ok(status) => { + save_changer_state_cache(&self.name, status)?; + } + Err(_) => { + delete_changer_state_cache(&self.name); + } } + + status } fn load_slot(&mut self, from_slot: u64, drivenum: u64) -> Result<(), Error> { @@ -434,6 +459,47 @@ impl ScsiMediaChange for ScsiTapeChanger { } } +fn save_changer_state_cache( + changer: &str, + state: &MtxStatus, +) -> Result<(), Error> { + let mut path = PathBuf::from("/run/proxmox-backup/changer-state"); + std::fs::create_dir_all(&path)?; + path.push(changer); + + let backup_user = crate::backup::backup_user()?; + let mode = nix::sys::stat::Mode::from_bits_truncate(0o0644); + let options = CreateOptions::new() + .perm(mode) + .owner(backup_user.uid) + .group(backup_user.gid); + + let state = serde_json::to_string_pretty(state)?; + + replace_file(path, state.as_bytes(), options) +} + +fn delete_changer_state_cache(changer: &str) { + let mut path = PathBuf::from("/run/proxmox-backup/changer-state"); + path.push(changer); + + let _ = std::fs::remove_file(&path); // ignore errors +} + +fn load_changer_state_cache(changer: &str) -> Result, Error> { + let mut path = PathBuf::from("/run/proxmox-backup/changer-state"); + path.push(changer); + + let data = match file_read_optional_string(&path)? { + None => return Ok(None), + Some(data) => data, + }; + + let state = serde_json::from_str(&data)?; + + Ok(Some(state)) +} + /// Implements MediaChange using 'mtx' linux cli tool pub struct MtxMediaChanger { drive_name: String, // used for error messages @@ -469,7 +535,7 @@ impl MediaChange for MtxMediaChanger { } fn status(&mut self) -> Result { - self.config.status() + self.config.status(false) } fn transfer_media(&mut self, from: u64, to: u64) -> Result<(), Error> { diff --git a/src/tape/changer/online_status_map.rs b/src/tape/changer/online_status_map.rs index e80ba2f7..e30cd17b 100644 --- a/src/tape/changer/online_status_map.rs +++ b/src/tape/changer/online_status_map.rs @@ -142,7 +142,7 @@ pub fn update_online_status(state_path: &Path, changer: Option<&str>) -> Result< } found_changer = true; } - let status = match changer_config.status() { + let status = match changer_config.status(false) { Ok(status) => status, Err(err) => { eprintln!("unable to get changer '{}' status - {}", changer_config.name, err);