On Tue, Jul 09, 2024 at 12:10:25PM -0700, Wengang Wang wrote: > xfs_reflink_try_clear_inode_flag() takes very long in case file has huge number > of extents and none of the extents are shared. > > workaround: > share the first real extent so that xfs_reflink_try_clear_inode_flag() returns > quickly to save cpu times and speed up defrag significantly. > > Signed-off-by: Wengang Wang <wen.gang.wang@xxxxxxxxxx> > --- > spaceman/defrag.c | 174 +++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 172 insertions(+), 2 deletions(-) I had some insight on this late last night. The source of the issue is that both the kernel and the defrag algorithm are walking forwards across the file. Hence as we get t higher offsets in the file during defrag which unshares shared ranges, we are moving the first shared range to be higher in the file. Hence the act of unsharing the file in ascending offset order results in the ascending offset search for shared extents done by the kernel growing in time. The solution to this is to make defrag work backwards through the file, so it leaves the low offset shared extents intact for the kernel to find until the defrag process unshares them. At which point the kernel will clear the reflink flag and the searching stops. IOWs, we either need to change the kernel code to do reverse order shared extent searching, or change the defrag operation to work in reverse sequential order, and then the performance problem relating to unsharing having to determine if the file being defragged is still shared or not goes away. That said, I still think that the fact the defrag is completely unsharing the source file is wrong. If we leave shared extents intact as we defrag the file, then this problem doesn't need solving at all because xfs_reflink_try_clear_inode_flag() will hit the same shared extent near the front of the file every time... -Dave. -- Dave Chinner david@xxxxxxxxxxxxx