tape: correctly lock the tape device
This commit is contained in:
parent
b5c6088130
commit
25aa55b5f5
|
@ -15,10 +15,7 @@ use proxmox::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
task_log,
|
task_log,
|
||||||
config::{
|
config,
|
||||||
self,
|
|
||||||
drive::check_drive_exists,
|
|
||||||
},
|
|
||||||
backup::{
|
backup::{
|
||||||
DataStore,
|
DataStore,
|
||||||
BackupDir,
|
BackupDir,
|
||||||
|
@ -40,7 +37,10 @@ use crate::{
|
||||||
PoolWriter,
|
PoolWriter,
|
||||||
MediaPool,
|
MediaPool,
|
||||||
SnapshotReader,
|
SnapshotReader,
|
||||||
drive::media_changer,
|
drive::{
|
||||||
|
media_changer,
|
||||||
|
lock_tape_device,
|
||||||
|
},
|
||||||
changer::update_changer_online_status,
|
changer::update_changer_online_status,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -91,8 +91,9 @@ pub fn backup(
|
||||||
let pool_config: MediaPoolConfig = config.lookup("pool", &pool)?;
|
let pool_config: MediaPoolConfig = config.lookup("pool", &pool)?;
|
||||||
|
|
||||||
let (drive_config, _digest) = config::drive::config()?;
|
let (drive_config, _digest) = config::drive::config()?;
|
||||||
// early check before starting worker
|
|
||||||
check_drive_exists(&drive_config, &drive)?;
|
// early check/lock before starting worker
|
||||||
|
let drive_lock = lock_tape_device(&drive_config, &drive)?;
|
||||||
|
|
||||||
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
||||||
|
|
||||||
|
@ -105,6 +106,7 @@ pub fn backup(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
|
let _drive_lock = drive_lock; // keep lock guard
|
||||||
backup_worker(&worker, datastore, &drive, &pool_config, eject_media, export_media_set)?;
|
backup_worker(&worker, datastore, &drive, &pool_config, eject_media, export_media_set)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ use proxmox::{
|
||||||
sys::error::SysError,
|
sys::error::SysError,
|
||||||
api::{
|
api::{
|
||||||
api,
|
api,
|
||||||
|
section_config::SectionConfigData,
|
||||||
RpcEnvironment,
|
RpcEnvironment,
|
||||||
RpcEnvironmentType,
|
RpcEnvironmentType,
|
||||||
Router,
|
Router,
|
||||||
|
@ -20,10 +21,7 @@ use proxmox::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config,
|
||||||
self,
|
|
||||||
drive::check_drive_exists,
|
|
||||||
},
|
|
||||||
api2::{
|
api2::{
|
||||||
types::{
|
types::{
|
||||||
UPID_SCHEMA,
|
UPID_SCHEMA,
|
||||||
|
@ -59,9 +57,10 @@ use crate::{
|
||||||
LinuxTapeHandle,
|
LinuxTapeHandle,
|
||||||
Lp17VolumeStatistics,
|
Lp17VolumeStatistics,
|
||||||
open_linux_tape_device,
|
open_linux_tape_device,
|
||||||
media_changer,
|
media_changer,
|
||||||
required_media_changer,
|
required_media_changer,
|
||||||
open_drive,
|
open_drive,
|
||||||
|
lock_tape_device,
|
||||||
},
|
},
|
||||||
changer::update_changer_online_status,
|
changer::update_changer_online_status,
|
||||||
},
|
},
|
||||||
|
@ -205,7 +204,8 @@ pub fn erase_media(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
check_drive_exists(&config, &drive)?; // early check before starting worker
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
|
@ -217,6 +217,8 @@ pub fn erase_media(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |_worker| {
|
move |_worker| {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
drive.erase_media(fast.unwrap_or(true))?;
|
drive.erase_media(fast.unwrap_or(true))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -246,7 +248,8 @@ pub fn rewind(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
check_drive_exists(&config, &drive)?; // early check before starting worker
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
|
@ -258,6 +261,7 @@ pub fn rewind(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |_worker| {
|
move |_worker| {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
drive.rewind()?;
|
drive.rewind()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -287,7 +291,8 @@ pub fn eject_media(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
check_drive_exists(&config, &drive)?; // early check before starting worker
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
|
@ -299,7 +304,9 @@ pub fn eject_media(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |_worker| {
|
move |_worker| {
|
||||||
if let Some((mut changer, _)) = media_changer(&config, &drive)? {
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
|
if let Some((mut changer, _)) = media_changer(&config, &drive)? {
|
||||||
changer.unload_media(None)?;
|
changer.unload_media(None)?;
|
||||||
} else {
|
} else {
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
@ -355,6 +362,9 @@ pub fn label_media(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
||||||
|
|
||||||
let upid_str = WorkerTask::new_thread(
|
let upid_str = WorkerTask::new_thread(
|
||||||
|
@ -363,6 +373,7 @@ pub fn label_media(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
|
||||||
|
@ -479,7 +490,12 @@ pub async fn restore_key(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
|
||||||
let (_media_id, key_config) = drive.read_label()?;
|
let (_media_id, key_config) = drive.read_label()?;
|
||||||
|
@ -520,7 +536,12 @@ pub async fn read_label(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
|
||||||
let (media_id, _key_config) = drive.read_label()?;
|
let (media_id, _key_config) = drive.read_label()?;
|
||||||
|
@ -593,7 +614,8 @@ pub fn clean_drive(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
check_drive_exists(&config, &drive)?; // early check before starting worker
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
|
@ -605,6 +627,7 @@ pub fn clean_drive(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let (mut changer, _changer_name) = required_media_changer(&config, &drive)?;
|
let (mut changer, _changer_name) = required_media_changer(&config, &drive)?;
|
||||||
|
|
||||||
|
@ -649,7 +672,12 @@ pub async fn inventory(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let (mut changer, changer_name) = required_media_changer(&config, &drive)?;
|
let (mut changer, changer_name) = required_media_changer(&config, &drive)?;
|
||||||
|
|
||||||
let label_text_list = changer.online_media_label_texts()?;
|
let label_text_list = changer.online_media_label_texts()?;
|
||||||
|
@ -720,7 +748,8 @@ pub fn update_inventory(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
check_drive_exists(&config, &drive)?; // early check before starting worker
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
|
@ -732,6 +761,7 @@ pub fn update_inventory(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let (mut changer, changer_name) = required_media_changer(&config, &drive)?;
|
let (mut changer, changer_name) = required_media_changer(&config, &drive)?;
|
||||||
|
|
||||||
|
@ -822,6 +852,11 @@ pub fn barcode_label_media(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (drive_config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&drive_config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
||||||
|
@ -832,7 +867,8 @@ pub fn barcode_label_media(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
barcode_label_media_worker(worker, drive, pool)
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
barcode_label_media_worker(worker, drive, &drive_config, pool)
|
||||||
}
|
}
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -842,12 +878,11 @@ pub fn barcode_label_media(
|
||||||
fn barcode_label_media_worker(
|
fn barcode_label_media_worker(
|
||||||
worker: Arc<WorkerTask>,
|
worker: Arc<WorkerTask>,
|
||||||
drive: String,
|
drive: String,
|
||||||
|
drive_config: &SectionConfigData,
|
||||||
pool: Option<String>,
|
pool: Option<String>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (mut changer, changer_name) = required_media_changer(drive_config, &drive)?;
|
||||||
|
|
||||||
let (mut changer, changer_name) = required_media_changer(&config, &drive)?;
|
|
||||||
|
|
||||||
let label_text_list = changer.online_media_label_texts()?;
|
let label_text_list = changer.online_media_label_texts()?;
|
||||||
|
|
||||||
|
@ -855,7 +890,7 @@ fn barcode_label_media_worker(
|
||||||
|
|
||||||
let mut inventory = Inventory::load(state_path)?;
|
let mut inventory = Inventory::load(state_path)?;
|
||||||
|
|
||||||
update_changer_online_status(&config, &mut inventory, &changer_name, &label_text_list)?;
|
update_changer_online_status(drive_config, &mut inventory, &changer_name, &label_text_list)?;
|
||||||
|
|
||||||
if label_text_list.is_empty() {
|
if label_text_list.is_empty() {
|
||||||
bail!("changer device does not list any media labels");
|
bail!("changer device does not list any media labels");
|
||||||
|
@ -877,7 +912,7 @@ fn barcode_label_media_worker(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(drive_config, &drive)?;
|
||||||
drive.rewind()?;
|
drive.rewind()?;
|
||||||
|
|
||||||
match drive.read_next_file() {
|
match drive.read_next_file() {
|
||||||
|
@ -930,6 +965,8 @@ pub fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
let _lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
|
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
|
||||||
let mut handle = drive_config.open()?;
|
let mut handle = drive_config.open()?;
|
||||||
|
|
||||||
|
@ -953,6 +990,8 @@ pub fn volume_statistics(drive: String) -> Result<Lp17VolumeStatistics, Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
let _lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
|
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
|
||||||
let mut handle = drive_config.open()?;
|
let mut handle = drive_config.open()?;
|
||||||
|
|
||||||
|
@ -976,6 +1015,8 @@ pub fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
|
let _lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
|
let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?;
|
||||||
|
|
||||||
// Note: use open_linux_tape_device, because this also works if no medium loaded
|
// Note: use open_linux_tape_device, because this also works if no medium loaded
|
||||||
|
@ -1021,7 +1062,8 @@ pub fn catalog_media(
|
||||||
|
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
check_drive_exists(&config, &drive)?; // early check before starting worker
|
// early check/lock before starting worker
|
||||||
|
let lock_guard = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
|
|
||||||
|
@ -1033,6 +1075,7 @@ pub fn catalog_media(
|
||||||
auth_id,
|
auth_id,
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
|
let _lock_guard = lock_guard; // keep lock guard
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,7 @@ use crate::{
|
||||||
Authid,
|
Authid,
|
||||||
MediaPoolConfig,
|
MediaPoolConfig,
|
||||||
},
|
},
|
||||||
config::{
|
config,
|
||||||
self,
|
|
||||||
drive::check_drive_exists,
|
|
||||||
},
|
|
||||||
backup::{
|
backup::{
|
||||||
archive_type,
|
archive_type,
|
||||||
MANIFEST_BLOB_NAME,
|
MANIFEST_BLOB_NAME,
|
||||||
|
@ -71,7 +68,8 @@ use crate::{
|
||||||
drive::{
|
drive::{
|
||||||
TapeDriver,
|
TapeDriver,
|
||||||
request_and_load_media,
|
request_and_load_media,
|
||||||
}
|
lock_tape_device,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,8 +120,9 @@ pub fn restore(
|
||||||
let _pool_config: MediaPoolConfig = config.lookup("pool", &pool)?;
|
let _pool_config: MediaPoolConfig = config.lookup("pool", &pool)?;
|
||||||
|
|
||||||
let (drive_config, _digest) = config::drive::config()?;
|
let (drive_config, _digest) = config::drive::config()?;
|
||||||
// early check before starting worker
|
|
||||||
check_drive_exists(&drive_config, &drive)?;
|
// early check/lock before starting worker
|
||||||
|
let drive_lock = lock_tape_device(&drive_config, &drive)?;
|
||||||
|
|
||||||
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
let to_stdout = rpcenv.env_type() == RpcEnvironmentType::CLI;
|
||||||
|
|
||||||
|
@ -133,6 +132,7 @@ pub fn restore(
|
||||||
auth_id.clone(),
|
auth_id.clone(),
|
||||||
to_stdout,
|
to_stdout,
|
||||||
move |worker| {
|
move |worker| {
|
||||||
|
let _drive_lock = drive_lock; // keep lock guard
|
||||||
|
|
||||||
let _lock = MediaPool::lock(status_path, &pool)?;
|
let _lock = MediaPool::lock(status_path, &pool)?;
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,10 @@ use proxmox_backup::{
|
||||||
media_pool::complete_pool_name,
|
media_pool::complete_pool_name,
|
||||||
},
|
},
|
||||||
tape::{
|
tape::{
|
||||||
drive::open_drive,
|
drive::{
|
||||||
|
open_drive,
|
||||||
|
lock_tape_device,
|
||||||
|
},
|
||||||
complete_media_label_text,
|
complete_media_label_text,
|
||||||
complete_media_set_uuid,
|
complete_media_set_uuid,
|
||||||
file_formats::{
|
file_formats::{
|
||||||
|
@ -518,6 +521,9 @@ fn move_to_eom(param: Value) -> Result<(), Error> {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
let drive = lookup_drive_name(¶m, &config)?;
|
let drive = lookup_drive_name(¶m, &config)?;
|
||||||
|
|
||||||
|
let _lock = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
|
||||||
drive.move_to_eom()?;
|
drive.move_to_eom()?;
|
||||||
|
@ -544,6 +550,9 @@ fn debug_scan(param: Value) -> Result<(), Error> {
|
||||||
let (config, _digest) = config::drive::config()?;
|
let (config, _digest) = config::drive::config()?;
|
||||||
|
|
||||||
let drive = lookup_drive_name(¶m, &config)?;
|
let drive = lookup_drive_name(¶m, &config)?;
|
||||||
|
|
||||||
|
let _lock = lock_tape_device(&config, &drive)?;
|
||||||
|
|
||||||
let mut drive = open_drive(&config, &drive)?;
|
let mut drive = open_drive(&config, &drive)?;
|
||||||
|
|
||||||
println!("rewinding tape");
|
println!("rewinding tape");
|
||||||
|
|
|
@ -19,6 +19,8 @@ pub use linux_tape::*;
|
||||||
mod mam;
|
mod mam;
|
||||||
pub use mam::*;
|
pub use mam::*;
|
||||||
|
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use ::serde::{Deserialize};
|
use ::serde::{Deserialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
@ -27,6 +29,7 @@ use proxmox::{
|
||||||
tools::{
|
tools::{
|
||||||
Uuid,
|
Uuid,
|
||||||
io::ReadExt,
|
io::ReadExt,
|
||||||
|
fs::fchown,
|
||||||
},
|
},
|
||||||
api::section_config::SectionConfigData,
|
api::section_config::SectionConfigData,
|
||||||
};
|
};
|
||||||
|
@ -442,3 +445,54 @@ pub fn request_and_load_media(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Aquires an exclusive lock for the tape device
|
||||||
|
///
|
||||||
|
/// Basically calls lock_device_path() using the configured drive path.
|
||||||
|
pub fn lock_tape_device(
|
||||||
|
config: &SectionConfigData,
|
||||||
|
drive: &str,
|
||||||
|
) -> Result<DeviceLockGuard, Error> {
|
||||||
|
|
||||||
|
match config.sections.get(drive) {
|
||||||
|
Some((section_type_name, config)) => {
|
||||||
|
let path = match section_type_name.as_ref() {
|
||||||
|
"virtual" => {
|
||||||
|
VirtualTapeDrive::deserialize(config)?.path
|
||||||
|
}
|
||||||
|
"linux" => {
|
||||||
|
LinuxTapeDrive::deserialize(config)?.path
|
||||||
|
}
|
||||||
|
_ => bail!("unknown drive type '{}' - internal error"),
|
||||||
|
};
|
||||||
|
lock_device_path(&path)
|
||||||
|
.map_err(|err| format_err!("unable to lock drive '{}' - {}", drive, err))
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
bail!("no such drive '{}'", drive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DeviceLockGuard(std::fs::File);
|
||||||
|
|
||||||
|
// Aquires an exclusive lock on `device_path`
|
||||||
|
//
|
||||||
|
// Uses systemd escape_unit to compute a file name from `device_path`, the try
|
||||||
|
// to lock `/var/lock/<name>`.
|
||||||
|
fn lock_device_path(device_path: &str) -> Result<DeviceLockGuard, Error> {
|
||||||
|
|
||||||
|
let lock_name = crate::tools::systemd::escape_unit(device_path, true);
|
||||||
|
|
||||||
|
let mut path = std::path::PathBuf::from("/var/lock");
|
||||||
|
path.push(lock_name);
|
||||||
|
|
||||||
|
let timeout = std::time::Duration::new(10, 0);
|
||||||
|
let mut file = std::fs::OpenOptions::new().create(true).append(true).open(path)?;
|
||||||
|
proxmox::tools::fs::lock_file(&mut file, true, Some(timeout))?;
|
||||||
|
|
||||||
|
let backup_user = crate::backup::backup_user()?;
|
||||||
|
fchown(file.as_raw_fd(), Some(backup_user.uid), Some(backup_user.gid))?;
|
||||||
|
|
||||||
|
Ok(DeviceLockGuard(file))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue