[pbs-devel] [PATCH 04/11] tape: implement format/erase
Dietmar Maurer
dietmar at proxmox.com
Wed Apr 7 12:23:01 CEST 2021
---
src/api2/tape/drive.rs | 28 ++++++++++-----------
src/bin/pmt.rs | 32 +++++++++++++++++++++++-
src/bin/proxmox-tape.rs | 10 ++++----
src/tape/drive/lto/mod.rs | 9 ++++---
src/tape/drive/lto/sg_tape.rs | 45 +++++++++++++++++++++++++++++++---
src/tape/drive/mod.rs | 6 ++---
src/tape/drive/virtual_tape.rs | 2 +-
www/Utils.js | 2 +-
www/tape/DriveStatus.js | 8 +++---
www/tape/window/Erase.js | 4 +--
10 files changed, 108 insertions(+), 38 deletions(-)
diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs
index 80d17a27..e354f4c0 100644
--- a/src/api2/tape/drive.rs
+++ b/src/api2/tape/drive.rs
@@ -321,8 +321,8 @@ pub fn unload(
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
},
)]
-/// Erase media. Check for label-text if given (cancels if wrong media).
-pub fn erase_media(
+/// Format media. Check for label-text if given (cancels if wrong media).
+pub fn format_media(
drive: String,
fast: Option<bool>,
label_text: Option<String>,
@@ -331,7 +331,7 @@ pub fn erase_media(
let upid_str = run_drive_worker(
rpcenv,
drive.clone(),
- "erase-media",
+ "format-media",
Some(drive.clone()),
move |worker, config| {
if let Some(ref label) = label_text {
@@ -350,15 +350,15 @@ pub fn erase_media(
}
/* assume drive contains no or unrelated data */
task_log!(worker, "unable to read media label: {}", err);
- task_log!(worker, "erase anyways");
- handle.erase_media(fast.unwrap_or(true))?;
+ task_log!(worker, "format anyways");
+ handle.format_media(fast.unwrap_or(true))?;
}
Ok((None, _)) => {
if let Some(label) = label_text {
bail!("expected label '{}', found empty tape", label);
}
- task_log!(worker, "found empty media - erase anyways");
- handle.erase_media(fast.unwrap_or(true))?;
+ task_log!(worker, "found empty media - format anyways");
+ handle.format_media(fast.unwrap_or(true))?;
}
Ok((Some(media_id), _key_config)) => {
if let Some(label_text) = label_text {
@@ -391,7 +391,7 @@ pub fn erase_media(
inventory.remove_media(&media_id.label.uuid)?;
};
- handle.erase_media(fast.unwrap_or(true))?;
+ handle.format_media(fast.unwrap_or(true))?;
}
}
@@ -503,7 +503,7 @@ pub fn eject_media(
/// Write a new media label to the media in 'drive'. The media is
/// assigned to the specified 'pool', or else to the free media pool.
///
-/// Note: The media need to be empty (you may want to erase it first).
+/// Note: The media need to be empty (you may want to format it first).
pub fn label_media(
drive: String,
pool: Option<String>,
@@ -528,7 +528,7 @@ pub fn label_media(
drive.rewind()?;
match drive.read_next_file() {
- Ok(Some(_file)) => bail!("media is not empty (erase first)"),
+ Ok(Some(_file)) => bail!("media is not empty (format it first)"),
Ok(None) => { /* EOF mark at BOT, assume tape is empty */ },
Err(err) => {
println!("TEST {:?}", err);
@@ -1092,7 +1092,7 @@ fn barcode_label_media_worker(
match drive.read_next_file() {
Ok(Some(_file)) => {
- worker.log(format!("media '{}' is not empty (erase first)", label_text));
+ worker.log(format!("media '{}' is not empty (format it first)", label_text));
continue;
}
Ok(None) => { /* EOF mark at BOT, assume tape is empty */ },
@@ -1100,7 +1100,7 @@ fn barcode_label_media_worker(
if err.is_errno(nix::errno::Errno::ENOSPC) || err.is_errno(nix::errno::Errno::EIO) {
/* assume tape is empty */
} else {
- worker.warn(format!("media '{}' read error (maybe not empty - erase first)", label_text));
+ worker.warn(format!("media '{}' read error (maybe not empty - format it first)", label_text));
continue;
}
}
@@ -1430,9 +1430,9 @@ pub const SUBDIRS: SubdirMap = &sorted!([
.post(&API_METHOD_EJECT_MEDIA)
),
(
- "erase-media",
+ "format-media",
&Router::new()
- .post(&API_METHOD_ERASE_MEDIA)
+ .post(&API_METHOD_FORMAT_MEDIA)
),
(
"export-media",
diff --git a/src/bin/pmt.rs b/src/bin/pmt.rs
index df3ad9ec..da0d4fd9 100644
--- a/src/bin/pmt.rs
+++ b/src/bin/pmt.rs
@@ -409,7 +409,7 @@ fn eod(param: Value) -> Result<(), Error> {
},
},
)]
-/// Erase media
+/// Erase media (from current position)
fn erase(fast: Option<bool>, param: Value) -> Result<(), Error> {
let mut handle = get_tape_handle(¶m)?;
@@ -418,6 +418,35 @@ fn erase(fast: Option<bool>, param: Value) -> Result<(), Error> {
Ok(())
}
+#[api(
+ input: {
+ properties: {
+ drive: {
+ schema: DRIVE_NAME_SCHEMA,
+ optional: true,
+ },
+ device: {
+ schema: LTO_DRIVE_PATH_SCHEMA,
+ optional: true,
+ },
+ fast: {
+ description: "Use fast erase.",
+ type: bool,
+ optional: true,
+ default: true,
+ },
+ },
+ },
+)]
+/// Format media, single partition
+fn format(fast: Option<bool>, param: Value) -> Result<(), Error> {
+
+ let mut handle = get_tape_handle(¶m)?;
+ handle.format_media(fast.unwrap_or(true))?;
+
+ Ok(())
+}
+
#[api(
input: {
properties: {
@@ -800,6 +829,7 @@ fn main() -> Result<(), Error> {
.insert("eject", std_cmd(&API_METHOD_EJECT))
.insert("eod", std_cmd(&API_METHOD_EOD))
.insert("erase", std_cmd(&API_METHOD_ERASE))
+ .insert("format", std_cmd(&API_METHOD_FORMAT))
.insert("fsf", std_cmd(&API_METHOD_FSF).arg_param(&["count"]))
.insert("fsfm", std_cmd(&API_METHOD_FSFM).arg_param(&["count"]))
.insert("fsr", std_cmd(&API_METHOD_FSR).arg_param(&["count"]))
diff --git a/src/bin/proxmox-tape.rs b/src/bin/proxmox-tape.rs
index cddac1b4..2a784632 100644
--- a/src/bin/proxmox-tape.rs
+++ b/src/bin/proxmox-tape.rs
@@ -115,8 +115,8 @@ pub fn extract_drive_name(
},
},
)]
-/// Erase media
-async fn erase_media(mut param: Value) -> Result<(), Error> {
+/// Format media
+async fn format_media(mut param: Value) -> Result<(), Error> {
let output_format = get_output_format(¶m);
@@ -126,7 +126,7 @@ async fn erase_media(mut param: Value) -> Result<(), Error> {
let mut client = connect_to_localhost()?;
- let path = format!("api2/json/tape/drive/{}/erase-media", drive);
+ let path = format!("api2/json/tape/drive/{}/format-media", drive);
let result = client.post(&path, Some(param)).await?;
view_task_result(&mut client, result, &output_format).await?;
@@ -992,8 +992,8 @@ fn main() {
.completion_cb("drive", complete_drive_name)
)
.insert(
- "erase",
- CliCommand::new(&API_METHOD_ERASE_MEDIA)
+ "format",
+ CliCommand::new(&API_METHOD_FORMAT_MEDIA)
.completion_cb("drive", complete_drive_name)
)
.insert(
diff --git a/src/tape/drive/lto/mod.rs b/src/tape/drive/lto/mod.rs
index becbad50..a4e0499e 100644
--- a/src/tape/drive/lto/mod.rs
+++ b/src/tape/drive/lto/mod.rs
@@ -179,6 +179,10 @@ impl LtoTapeHandle {
Ok(status)
}
+ pub fn erase_media(&mut self, fast: bool) -> Result<(), Error> {
+ self.sg_tape.erase_media(fast)
+ }
+
pub fn load(&mut self) -> Result<(), Error> {
self.sg_tape.load()
}
@@ -223,9 +227,8 @@ impl TapeDriver for LtoTapeHandle {
self.sg_tape.current_file_number()
}
- fn erase_media(&mut self, fast: bool) -> Result<(), Error> {
- self.rewind()?; // important - erase from BOT
- self.sg_tape.erase_media(fast)
+ fn format_media(&mut self, fast: bool) -> Result<(), Error> {
+ self.sg_tape.format_media(fast)
}
fn read_next_file<'a>(&'a mut self) -> Result<Option<Box<dyn TapeRead + 'a>>, std::io::Error> {
diff --git a/src/tape/drive/lto/sg_tape.rs b/src/tape/drive/lto/sg_tape.rs
index 802756fa..531acbee 100644
--- a/src/tape/drive/lto/sg_tape.rs
+++ b/src/tape/drive/lto/sg_tape.rs
@@ -100,9 +100,48 @@ impl SgTape {
scsi_inquiry(&mut self.file)
}
- pub fn erase_media(&mut self, _fast: bool) -> Result<(), Error> {
- // fixme:
- unimplemented!();
+ /// Erase medium.
+ ///
+ /// EOD is written at the current position, which marks it as end
+ /// of data. After the command is successfully completed, the
+ /// drive is positioned immediately before End Of Data (not End Of
+ /// Tape).
+ pub fn erase_media(&mut self, fast: 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();
+ cmd.push(0x19);
+ if fast {
+ cmd.push(0); // LONG=0
+ } else {
+ cmd.push(1); // LONG=1
+ }
+ cmd.extend(&[0, 0, 0, 0]);
+
+ sg_raw.do_command(&cmd)
+ .map_err(|err| format_err!("erase failed - {}", err))?;
+
+ Ok(())
+ }
+
+ /// Format media, single partition
+ pub fn format_media(&mut self, fast: bool) -> Result<(), Error> {
+
+ self.rewind()?;
+
+ let mut sg_raw = SgRaw::new(&mut self.file, 16)?;
+ sg_raw.set_timeout(Self::SCSI_TAPE_DEFAULT_TIMEOUT);
+ let mut cmd = Vec::new();
+ cmd.extend(&[0x04, 0, 0, 0, 0, 0]);
+
+ sg_raw.do_command(&cmd)
+ .map_err(|err| format_err!("erase failed - {}", err))?;
+
+ if !fast {
+ self.erase_media(false)?; // overwrite everything
+ }
+
+ Ok(())
}
pub fn rewind(&mut self) -> Result<(), Error> {
diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs
index 71f61642..061c1cfc 100644
--- a/src/tape/drive/mod.rs
+++ b/src/tape/drive/mod.rs
@@ -111,7 +111,7 @@ pub trait TapeDriver {
fn current_file_number(&mut self) -> Result<u64, Error>;
/// Completely erase the media
- fn erase_media(&mut self, fast: bool) -> Result<(), Error>;
+ fn format_media(&mut self, fast: bool) -> Result<(), Error>;
/// Read/Open the next file
fn read_next_file<'a>(&'a mut self) -> Result<Option<Box<dyn TapeRead + 'a>>, std::io::Error>;
@@ -122,11 +122,9 @@ pub trait TapeDriver {
/// Write label to tape (erase tape content)
fn label_tape(&mut self, label: &MediaLabel) -> Result<(), Error> {
- self.rewind()?;
-
self.set_encryption(None)?;
- self.erase_media(true)?;
+ self.format_media(true)?; // this rewinds the tape
let raw = serde_json::to_string_pretty(&serde_json::to_value(&label)?)?;
diff --git a/src/tape/drive/virtual_tape.rs b/src/tape/drive/virtual_tape.rs
index 54e0887f..e4d09c2f 100644
--- a/src/tape/drive/virtual_tape.rs
+++ b/src/tape/drive/virtual_tape.rs
@@ -360,7 +360,7 @@ impl TapeDriver for VirtualTapeHandle {
}
}
- fn erase_media(&mut self, _fast: bool) -> Result<(), Error> {
+ fn format_media(&mut self, _fast: bool) -> Result<(), Error> {
let mut status = self.load_status()?;
match status.current_tape {
Some(VirtualTapeStatus { ref name, ref mut pos }) => {
diff --git a/www/Utils.js b/www/Utils.js
index dc7e539f..b9012374 100644
--- a/www/Utils.js
+++ b/www/Utils.js
@@ -374,7 +374,7 @@ Ext.define('PBS.Utils', {
dircreate: [gettext('Directory Storage'), gettext('Create')],
dirremove: [gettext('Directory'), gettext('Remove')],
'eject-media': [gettext('Drive'), gettext('Eject Media')],
- 'erase-media': [gettext('Drive'), gettext('Erase Media')],
+ "format-media": [gettext('Drive'), gettext('Format media')],
garbage_collection: ['Datastore', gettext('Garbage Collect')],
'inventory-update': [gettext('Drive'), gettext('Inventory Update')],
'label-media': [gettext('Drive'), gettext('Label Media')],
diff --git a/www/tape/DriveStatus.js b/www/tape/DriveStatus.js
index 65197285..2bf05f88 100644
--- a/www/tape/DriveStatus.js
+++ b/www/tape/DriveStatus.js
@@ -84,11 +84,11 @@ Ext.define('PBS.TapeManagement.DriveStatus', {
}).show();
},
- erase: function() {
+ format: function() {
let me = this;
let view = me.getView();
let driveid = view.drive;
- PBS.Utils.driveCommand(driveid, 'erase-media', {
+ PBS.Utils.driveCommand(driveid, 'format-media', {
waitMsgTarget: view,
method: 'POST',
success: function(response) {
@@ -212,9 +212,9 @@ Ext.define('PBS.TapeManagement.DriveStatus', {
},
},
{
- text: gettext('Erase'),
+ text: gettext('Format'),
xtype: 'proxmoxButton',
- handler: 'erase',
+ handler: 'format',
iconCls: 'fa fa-trash-o',
dangerous: true,
confirmMsg: gettext('Are you sure you want to erase the inserted tape?'),
diff --git a/www/tape/window/Erase.js b/www/tape/window/Erase.js
index 61bd2130..1177dfeb 100644
--- a/www/tape/window/Erase.js
+++ b/www/tape/window/Erase.js
@@ -11,13 +11,13 @@ Ext.define('PBS.TapeManagement.EraseWindow', {
return {};
},
- title: gettext('Erase'),
+ title: gettext('Format/Erase'),
url: `/api2/extjs/tape/drive`,
showProgress: true,
submitUrl: function(url, values) {
let drive = values.drive;
delete values.drive;
- return `${url}/${drive}/erase-media`;
+ return `${url}/${drive}/format-media`;
},
method: 'POST',
--
2.20.1
More information about the pbs-devel
mailing list