New: Removed Special Handling of Reflinks for BTRFS and ZFS

Closes #7946
This commit is contained in:
Mark McDowall 2025-12-24 09:56:47 -08:00
parent d70dcfed56
commit ee875ae654
5 changed files with 1 additions and 133 deletions

View file

@ -238,11 +238,6 @@ public void CloneFile(string source, string destination, bool overwrite = false)
throw new IOException(string.Format("Source and destination can't be the same {0}", source));
}
CloneFileInternal(source, destination, overwrite);
}
protected virtual void CloneFileInternal(string source, string destination, bool overwrite = false)
{
CopyFileInternal(source, destination, overwrite);
}
@ -308,11 +303,6 @@ public virtual bool TryRenameFile(string source, string destination)
public abstract bool TryCreateHardLink(string source, string destination);
public virtual bool TryCreateRefLink(string source, string destination)
{
return false;
}
public void DeleteFolder(string path, bool recursive)
{
Ensure.That(path, () => path).IsValidPath(PathValidationType.CurrentOs);

View file

@ -340,41 +340,15 @@ public TransferMode TransferFile(string sourcePath, string targetPath, TransferM
var targetDriveFormat = targetMount?.DriveFormat ?? string.Empty;
var isCifs = targetDriveFormat == "cifs";
var isBtrfs = sourceDriveFormat == "btrfs" && targetDriveFormat == "btrfs";
var isZfs = sourceDriveFormat == "zfs" && targetDriveFormat == "zfs";
if (mode.HasFlag(TransferMode.Copy))
{
if (isBtrfs || isZfs)
{
if (_diskProvider.TryCreateRefLink(sourcePath, targetPath))
{
return TransferMode.Copy;
}
}
TryCopyFileVerified(sourcePath, targetPath, originalSize);
return TransferMode.Copy;
}
if (mode.HasFlag(TransferMode.Move))
{
if (isBtrfs || isZfs)
{
if (isSameMount && _diskProvider.TryRenameFile(sourcePath, targetPath))
{
_logger.Trace("Renamed [{0}] to [{1}].", sourcePath, targetPath);
return TransferMode.Move;
}
if (_diskProvider.TryCreateRefLink(sourcePath, targetPath))
{
_logger.Trace("Reflink successful, deleting source [{0}].", sourcePath);
_diskProvider.DeleteFile(sourcePath);
return TransferMode.Move;
}
}
if (isCifs && !isSameMount)
{
_logger.Trace("On cifs mount. Starting verified copy [{0}] to [{1}].", sourcePath, targetPath);

View file

@ -34,7 +34,6 @@ public interface IDiskProvider
void MoveFolder(string source, string destination);
bool TryRenameFile(string source, string destination);
bool TryCreateHardLink(string source, string destination);
bool TryCreateRefLink(string source, string destination);
void DeleteFolder(string path, bool recursive);
string ReadAllText(string filePath);
void WriteAllText(string filename, string contents);

View file

@ -21,13 +21,11 @@ public class DiskProvider : DiskProviderBase
private readonly Logger _logger;
private readonly IProcMountProvider _procMountProvider;
private readonly ISymbolicLinkResolver _symLinkResolver;
private readonly ICreateRefLink _createRefLink;
public DiskProvider(IProcMountProvider procMountProvider, ISymbolicLinkResolver symLinkResolver, ICreateRefLink createRefLink, Logger logger)
public DiskProvider(IProcMountProvider procMountProvider, ISymbolicLinkResolver symLinkResolver, Logger logger)
{
_procMountProvider = procMountProvider;
_symLinkResolver = symLinkResolver;
_createRefLink = createRefLink;
_logger = logger;
}
@ -234,19 +232,6 @@ protected override bool IsSpecialMount(IMount mount)
return mount?.TotalSize;
}
protected override void CloneFileInternal(string source, string destination, bool overwrite)
{
if (!File.Exists(destination) && !UnixFileSystemInfo.GetFileSystemEntry(source).IsSymbolicLink)
{
if (_createRefLink.TryCreateRefLink(source, destination))
{
return;
}
}
CopyFileInternal(source, destination, overwrite);
}
protected override void CopyFileInternal(string source, string destination, bool overwrite)
{
var sourceInfo = UnixFileSystemInfo.GetFileSystemEntry(source);
@ -464,11 +449,6 @@ public override bool TryCreateHardLink(string source, string destination)
}
}
public override bool TryCreateRefLink(string source, string destination)
{
return _createRefLink.TryCreateRefLink(source, destination);
}
private uint GetUserId(string user)
{
if (user.IsNullOrWhiteSpace())

View file

@ -1,75 +0,0 @@
using System;
using Mono.Unix;
using Mono.Unix.Native;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Mono.Interop;
namespace NzbDrone.Mono.Disk
{
public interface ICreateRefLink
{
bool TryCreateRefLink(string srcPath, string linkPath);
}
public class RefLinkCreator : ICreateRefLink
{
private readonly Logger _logger;
private readonly bool _supported;
public RefLinkCreator(Logger logger)
{
_logger = logger;
// Only support x86_64 because we know the FICLONE value is valid for it
_supported = OsInfo.IsLinux && (Syscall.uname(out var results) == 0 && results.machine == "x86_64");
}
public bool TryCreateRefLink(string srcPath, string linkPath)
{
if (!_supported)
{
return false;
}
try
{
using (var srcHandle = NativeMethods.open(srcPath, OpenFlags.O_RDONLY))
{
if (srcHandle.IsInvalid)
{
_logger.Trace("Failed to create reflink at '{0}' to '{1}': Couldn't open source file", linkPath, srcPath);
return false;
}
using (var linkHandle = NativeMethods.open(linkPath, OpenFlags.O_WRONLY | OpenFlags.O_CREAT | OpenFlags.O_TRUNC))
{
if (linkHandle.IsInvalid)
{
_logger.Trace("Failed to create reflink at '{0}' to '{1}': Couldn't create new link file", linkPath, srcPath);
return false;
}
if (NativeMethods.clone_file(linkHandle, srcHandle) == -1)
{
var error = new UnixIOException();
linkHandle.Dispose();
Syscall.unlink(linkPath);
_logger.Trace("Failed to create reflink at '{0}' to '{1}': {2}", linkPath, srcPath, error.Message);
return false;
}
_logger.Trace("Created reflink at '{0}' to '{1}'", linkPath, srcPath);
return true;
}
}
}
catch (Exception ex)
{
Syscall.unlink(linkPath);
_logger.Trace(ex, "Failed to create reflink at '{0}' to '{1}'", linkPath, srcPath);
return false;
}
}
}
}