From f23f75433fccb556392ac04aeddf7da891d2771d Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Tue, 11 Aug 2020 10:50:39 +0200 Subject: [PATCH] backup: flock snapshot on backup start An flock on the snapshot dir itself is used in addition to the group dir lock. The lock is used to avoid races with forget and prune, while having more granularity than the group lock (i.e. the group lock is necessary to prevent more than one backup per group, but the snapshot lock still allows backups unrelated to the currently running to be forgotten/pruned). Signed-off-by: Stefan Reiter --- src/api2/backup.rs | 3 ++- src/backup/datastore.rs | 13 +++++++++---- src/client/pull.rs | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/api2/backup.rs b/src/api2/backup.rs index 4b019007..f541eb97 100644 --- a/src/api2/backup.rs +++ b/src/api2/backup.rs @@ -106,7 +106,7 @@ async move { } } - let (path, is_new) = datastore.create_backup_dir(&backup_dir)?; + let (path, is_new, _snap_guard) = datastore.create_locked_backup_dir(&backup_dir)?; if !is_new { bail!("backup directory already exists."); } WorkerTask::spawn("backup", Some(worker_id), userid.clone(), true, move |worker| { @@ -146,6 +146,7 @@ async move { async move { // keep flock until task ends let _group_guard = _group_guard; + let _snap_guard = _snap_guard; let res = select!{ req = req_fut => req, diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs index 71544d20..37f581bc 100644 --- a/src/backup/datastore.rs +++ b/src/backup/datastore.rs @@ -334,15 +334,20 @@ impl DataStore { /// Creates a new backup snapshot inside a BackupGroup /// /// The BackupGroup directory needs to exist. - pub fn create_backup_dir(&self, backup_dir: &BackupDir) -> Result<(PathBuf, bool), io::Error> { + pub fn create_locked_backup_dir(&self, backup_dir: &BackupDir) + -> Result<(PathBuf, bool, DirLockGuard), Error> + { let relative_path = backup_dir.relative_path(); let mut full_path = self.base_path(); full_path.push(&relative_path); + let lock = || + lock_dir_noblock(&full_path, "snapshot", "internal error - tried creating snapshot that's already in use"); + match std::fs::create_dir(&full_path) { - Ok(_) => Ok((relative_path, true)), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok((relative_path, false)), - Err(e) => Err(e) + Ok(_) => Ok((relative_path, true, lock()?)), + Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok((relative_path, false, lock()?)), + Err(e) => Err(e.into()) } } diff --git a/src/client/pull.rs b/src/client/pull.rs index 05b7c66c..2428051a 100644 --- a/src/client/pull.rs +++ b/src/client/pull.rs @@ -297,7 +297,7 @@ pub async fn pull_snapshot_from( snapshot: &BackupDir, ) -> Result<(), Error> { - let (_path, is_new) = tgt_store.create_backup_dir(&snapshot)?; + let (_path, is_new, _snap_lock) = tgt_store.create_locked_backup_dir(&snapshot)?; if is_new { worker.log(format!("sync snapshot {:?}", snapshot.relative_path()));