From: Dietmar Maurer <dietmar@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH 04/11] tape: implement format/erase
Date: Wed, 7 Apr 2021 12:23:01 +0200 [thread overview]
Message-ID: <20210407102308.9750-5-dietmar@proxmox.com> (raw)
In-Reply-To: <20210407102308.9750-1-dietmar@proxmox.com>
---
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
next prev parent reply other threads:[~2021-04-07 10:24 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-04-07 10:22 [pbs-devel] [PATCH 00/11] Userspace tape driver Dietmar Maurer
2021-04-07 10:22 ` [pbs-devel] [PATCH 01/11] tape: introduce trait BlockRead Dietmar Maurer
2021-04-07 10:22 ` [pbs-devel] [PATCH 02/11] tape: introduce trait BlockWrite Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 03/11] tape: implement LTO userspace driver Dietmar Maurer
2021-04-07 10:23 ` Dietmar Maurer [this message]
2021-04-07 10:23 ` [pbs-devel] [PATCH 05/11] tape: fix LEOM handling Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 06/11] tape: make fsf/bsf driver specific Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 07/11] tape: make sure there is a filemark at the end of the tape Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 08/11] sgutils2: add scsi_mode_sense helper Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 09/11] tape: correctly set/display drive option Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 10/11] tape: pmt - re-implement fsr/bsr Dietmar Maurer
2021-04-07 10:23 ` [pbs-devel] [PATCH 11/11] tape: pmt - re-implement lock/unlock command Dietmar Maurer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210407102308.9750-5-dietmar@proxmox.com \
--to=dietmar@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.