[pbs-devel] [PATCH 07/11] tape: make sure there is a filemark at the end of the tape

Dietmar Maurer dietmar at proxmox.com
Wed Apr 7 12:23:04 CEST 2021


---
 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(&param)?;
-    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<bool, Error> {
+
+        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





More information about the pbs-devel mailing list