From a602a885afde4a1e36f9fc62f35508c82ae78af6 Mon Sep 17 00:00:00 2001 From: Gabriel Goller Date: Wed, 14 Feb 2024 10:52:01 +0100 Subject: [PATCH] fix #4975: client: ignore E2BIG error flag Some filesystems (f.e. zfs) support xattrs bigger than 64kB, sadly we can't get them because the kernel vfs limits us. The syscalls listxattr and getxattr will return a E2BIG error in this case. Added a flag --ignore-e2big-xattr to the client, this will ignore the metadata (but still backup the file) if this error occurs. Signed-off-by: Gabriel Goller Signed-off-by: Dietmar Maurer --- pbs-client/src/pxar/create.rs | 26 ++++++++++++++++++- proxmox-backup-client/src/main.rs | 8 ++++++ .../src/proxmox_restore_daemon/api.rs | 1 + pxar-bin/src/main.rs | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/pbs-client/src/pxar/create.rs b/pbs-client/src/pxar/create.rs index 3cf2b35a..75376c0c 100644 --- a/pbs-client/src/pxar/create.rs +++ b/pbs-client/src/pxar/create.rs @@ -41,6 +41,8 @@ pub struct PxarCreateOptions { pub entries_max: usize, /// Skip lost+found directory pub skip_lost_and_found: bool, + /// Skip xattrs of files that return E2BIG error + pub skip_e2big_xattr: bool, } fn detect_fs_type(fd: RawFd) -> Result { @@ -128,6 +130,7 @@ struct Archiver { device_set: Option>, hardlinks: HashMap, file_copy_buffer: Vec, + skip_e2big_xattr: bool, } type Encoder<'a, T> = pxar::encoder::aio::Encoder<'a, T>; @@ -158,6 +161,7 @@ where feature_flags & fs_feature_flags, fs_magic, &mut fs_feature_flags, + options.skip_e2big_xattr ) .context("failed to get metadata for source directory")?; @@ -192,6 +196,7 @@ where device_set, hardlinks: HashMap::new(), file_copy_buffer: vec::undefined(4 * 1024 * 1024), + skip_e2big_xattr: options.skip_e2big_xattr, }; archiver @@ -540,6 +545,7 @@ impl Archiver { self.flags(), self.fs_magic, &mut self.fs_feature_flags, + self.skip_e2big_xattr )?; let match_path = PathBuf::from("/").join(self.path.clone()); @@ -765,6 +771,7 @@ fn get_metadata( flags: Flags, fs_magic: i64, fs_feature_flags: &mut Flags, + skip_e2big_xattr: bool, ) -> Result { // required for some of these let proc_path = Path::new("/proc/self/fd/").join(fd.to_string()); @@ -780,7 +787,7 @@ fn get_metadata( ..Default::default() }; - get_xattr_fcaps_acl(&mut meta, fd, &proc_path, flags, fs_feature_flags)?; + get_xattr_fcaps_acl(&mut meta, fd, &proc_path, flags, fs_feature_flags, skip_e2big_xattr)?; get_chattr(&mut meta, fd)?; get_fat_attr(&mut meta, fd, fs_magic)?; get_quota_project_id(&mut meta, fd, flags, fs_magic)?; @@ -818,6 +825,7 @@ fn get_xattr_fcaps_acl( proc_path: &Path, flags: Flags, fs_feature_flags: &mut Flags, + skip_e2big_xattr: bool, ) -> Result<(), Error> { if !flags.contains(Flags::WITH_XATTRS) { return Ok(()); @@ -829,6 +837,14 @@ fn get_xattr_fcaps_acl( fs_feature_flags.remove(Flags::WITH_XATTRS); return Ok(()); } + Err(Errno::E2BIG) => { + match skip_e2big_xattr { + true => return Ok(()), + false => { + bail!("{} (try --skip-e2big-xattr)", Errno::E2BIG.to_string()); + } + }; + } Err(Errno::EBADF) => return Ok(()), // symlinks Err(err) => return Err(err).context("failed to read xattrs"), }; @@ -855,6 +871,14 @@ fn get_xattr_fcaps_acl( Err(Errno::ENODATA) => (), // it got removed while we were iterating... Err(Errno::EOPNOTSUPP) => (), // shouldn't be possible so just ignore this Err(Errno::EBADF) => (), // symlinks, shouldn't be able to reach this either + Err(Errno::E2BIG) => { + match skip_e2big_xattr { + true => return Ok(()), + false => { + bail!("{} (try --skip-e2big-xattr)", Errno::E2BIG.to_string()); + } + }; + } Err(err) => { return Err(err).context(format!("error reading extended attribute {attr:?}")) } diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs index e5caf87d..fdf43747 100644 --- a/proxmox-backup-client/src/main.rs +++ b/proxmox-backup-client/src/main.rs @@ -665,6 +665,12 @@ fn spawn_catalog_upload( optional: true, default: false, }, + "skip-e2big-xattr": { + type: Boolean, + description: "Ignore the E2BIG error when retrieving xattrs. This includes the file, but discards the metadata.", + optional: true, + default: false, + }, } } )] @@ -674,6 +680,7 @@ async fn create_backup( all_file_systems: bool, skip_lost_and_found: bool, dry_run: bool, + skip_e2big_xattr: bool, _info: &ApiMethod, _rpcenv: &mut dyn RpcEnvironment, ) -> Result { @@ -993,6 +1000,7 @@ async fn create_backup( patterns: pattern_list.clone(), entries_max: entries_max as usize, skip_lost_and_found, + skip_e2big_xattr }; let upload_options = UploadOptions { diff --git a/proxmox-restore-daemon/src/proxmox_restore_daemon/api.rs b/proxmox-restore-daemon/src/proxmox_restore_daemon/api.rs index c4e97d33..c2055222 100644 --- a/proxmox-restore-daemon/src/proxmox_restore_daemon/api.rs +++ b/proxmox-restore-daemon/src/proxmox_restore_daemon/api.rs @@ -352,6 +352,7 @@ fn extract( device_set: None, patterns, skip_lost_and_found: false, + skip_e2big_xattr: false, }; let pxar_writer = TokioWriter::new(writer); diff --git a/pxar-bin/src/main.rs b/pxar-bin/src/main.rs index bc044035..2bbe90e3 100644 --- a/pxar-bin/src/main.rs +++ b/pxar-bin/src/main.rs @@ -335,6 +335,7 @@ async fn create_archive( device_set, patterns, skip_lost_and_found: false, + skip_e2big_xattr: false, }; let source = PathBuf::from(source);