From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id A630D1FF13C for ; Thu, 05 Mar 2026 12:07:29 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 399F75739; Thu, 5 Mar 2026 12:08:35 +0100 (CET) Date: Thu, 05 Mar 2026 12:08:27 +0100 From: Fabian =?iso-8859-1?q?Gr=FCnbichler?= Subject: Re: [PATCH v1 proxmox-backup 11/11] tape: media catalog: use Flock wrapper instead of deprecated function To: pbs-devel@lists.proxmox.com, Robert Obkircher References: <20260226144033.211039-1-r.obkircher@proxmox.com> <20260226144033.211039-12-r.obkircher@proxmox.com> In-Reply-To: <20260226144033.211039-12-r.obkircher@proxmox.com> MIME-Version: 1.0 User-Agent: astroid/0.17.0 (https://github.com/astroidmail/astroid) Message-Id: <1772707888.l459trzwfo.astroid@yuna.none> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1772708883406 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.051 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: 2F5VMUL3FRMRIOINRXINWKJ334SUNSVM X-Message-ID-Hash: 2F5VMUL3FRMRIOINRXINWKJ334SUNSVM X-MailFrom: f.gruenbichler@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox Backup Server development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On February 26, 2026 3:40 pm, Robert Obkircher wrote: > Switch to the new wrapper type to fix the deprecation warnings. Panic > if unlock fails, because there is no easy way to return the File that > was temporarily moved out of the field. >=20 > An alternative to moving out of the optional field would be to use > `File::try_clone` but that isn't ideal either because duplicated file > descriptors share the same lock status. That also doesn't solve the > problem that propagating the error without leaking the locked file > descriptor requires unsafe code or a change to nix. >=20 > [1] https://lore.proxmox.com/pbs-devel/1763634535.5sqd1r4buu.astroid@yuna= .none/ >=20 > Signed-off-by: Robert Obkircher > --- > src/tape/media_catalog.rs | 49 +++++++++++++++++++++------------------ > 1 file changed, 27 insertions(+), 22 deletions(-) >=20 > diff --git a/src/tape/media_catalog.rs b/src/tape/media_catalog.rs > index 63329a65..372bf59d 100644 > --- a/src/tape/media_catalog.rs > +++ b/src/tape/media_catalog.rs > @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; > =20 > use anyhow::{bail, format_err, Error}; > use endian_trait::Endian; > +use nix::fcntl::{Flock, FlockArg}; > =20 > use proxmox_sys::fs::read_subdir; > =20 > @@ -194,7 +195,7 @@ impl MediaCatalog { > let me =3D proxmox_lang::try_block!({ > Self::create_basedir(base_path)?; > =20 > - let mut file =3D std::fs::OpenOptions::new() > + let file =3D std::fs::OpenOptions::new() > .read(true) > .write(write) > .create(create) > @@ -219,9 +220,10 @@ impl MediaCatalog { > }; > =20 > // Note: lock file, to get a consistent view with load_catal= og > - nix::fcntl::flock(file.as_raw_fd(), nix::fcntl::FlockArg::Lo= ckExclusive)?; > + let mut file =3D Flock::lock(file, FlockArg::LockExclusive) > + .map_err(|e| format_err!("flock failed: {e:?}"))?; > let result =3D me.load_catalog(&mut file, media_id.media_set= _label.as_ref()); > - nix::fcntl::flock(file.as_raw_fd(), nix::fcntl::FlockArg::Un= lock)?; > + let file =3D file.unlock().expect("shouldn't fail for valid = fd"); here we could just return an error instead of panicing? we only read from the file anyway, and bubbling up the error should be fine.. > =20 > let (found_magic_number, _) =3D result?; > =20 > @@ -367,27 +369,30 @@ impl MediaCatalog { > return Ok(()); > } > =20 > - match self.file { > - Some(ref mut file) =3D> { > - let pending =3D &self.pending; > - // Note: lock file, to get a consistent view with load_c= atalog > - nix::fcntl::flock(file.as_raw_fd(), nix::fcntl::FlockArg= ::LockExclusive)?; > - let result: Result<(), Error> =3D proxmox_lang::try_bloc= k!({ > - file.write_all(pending)?; > - file.flush()?; > - file.sync_data()?; > - Ok(()) > - }); > - nix::fcntl::flock(file.as_raw_fd(), nix::fcntl::FlockArg= ::Unlock)?; > - > - result?; > - } > - None =3D> bail!("media catalog not writable (opened read onl= y)"), > - } > + let Some(file) =3D self.file.take() else { > + bail!("media catalog not writable (opened read only)"); > + }; > + > + let mut file =3D Flock::lock(file, FlockArg::LockExclusive).map_= err(|(f, e)| { > + self.file =3D Some(f); > + format_err!("flock failed: {:?} - {e:?}", self.file) > + })?; > =20 > - self.pending =3D Vec::new(); > + let pending =3D &self.pending; > + // Note: lock file, to get a consistent view with load_catalog > + let result: Result<(), Error> =3D proxmox_lang::try_block!({ > + file.write_all(pending)?; > + file.flush()?; > + file.sync_data()?; > + Ok(()) > + }); > =20 > - Ok(()) > + self.file =3D Some(file.unlock().expect("shouldn't fail for vali= d fd")); here the situation is a bit more complicated, since we wrote to the file above.. but looking at the call graphs/error behaviour, it seems to me that we are often operating on temporary files (though we do not seem to clean them up in the error path?), or failure to commit herer would bubble up and abort writing to tape anyway.. triggering a panic here doesn't help in any case - the possibly inconsistent writes/reads have already happened, at best we could maybe (try to) invalidate the catalog as part of error handling to force re-reading it from tape? or we could bubble up the error to abort whatever operation is attempting to commit, and log the error prominently - taking down the whole PBS instance doesn't buy us anything AFAICT? > + > + if result.is_ok() { > + self.pending =3D Vec::new(); > + } > + result > } > =20 > /// Conditionally commit if in pending data is large (> 1Mb) > --=20 > 2.47.3 >=20 >=20 >=20 >=20 >=20 >=20