/* * Iteratively remap one file's extents (and holes) to another's. */ STATIC int xfs_reflink_remap_blocks( struct xfs_inode *src, xfs_fileoff_t srcoff, struct xfs_inode *dest, xfs_fileoff_t destoff, xfs_filblks_t len, xfs_off_t new_isize) { struct xfs_bmbt_irec imap; int nimaps; int error = 0; xfs_filblks_t range_len; /* drange = (destoff, destoff + len); srange = (srcoff, srcoff + len) */ while (len) { trace_xfs_reflink_remap_blocks_loop(src, srcoff, len, dest, destoff); /* Read extent from the source file */ nimaps = 1; xfs_ilock(src, XFS_ILOCK_EXCL); error = xfs_bmapi_read(src, srcoff, len, &imap, &nimaps, 0); xfs_iunlock(src, XFS_ILOCK_EXCL); if (error) goto err; ASSERT(nimaps == 1); trace_xfs_reflink_remap_imap(src, srcoff, len, XFS_IO_OVERWRITE, &imap); /* Translate imap into the destination file. */ range_len = imap.br_startoff + imap.br_blockcount - srcoff; imap.br_startoff += destoff - srcoff; /* Clear dest from destoff to the end of imap and map it in. */ error = xfs_reflink_remap_extent(dest, &imap, destoff, new_isize); if (error) goto err; if (fatal_signal_pending(current)) { error = -EINTR; goto err; } /* Advance drange/srange */ srcoff += range_len; destoff += range_len; len -= range_len; } return 0; err: trace_xfs_reflink_remap_blocks_error(dest, error, _RET_IP_); return error; }
/* * Iteratively remap one file's extents (and holes) to another's. */ int xfs_reflink_remap_blocks( struct xfs_inode *src, loff_t pos_in, struct xfs_inode *dest, loff_t pos_out, loff_t remap_len, loff_t *remapped) { struct xfs_bmbt_irec imap; xfs_fileoff_t srcoff; xfs_fileoff_t destoff; xfs_filblks_t len; xfs_filblks_t range_len; xfs_filblks_t remapped_len = 0; xfs_off_t new_isize = pos_out + remap_len; int nimaps; int error = 0; destoff = XFS_B_TO_FSBT(src->i_mount, pos_out); srcoff = XFS_B_TO_FSBT(src->i_mount, pos_in); len = XFS_B_TO_FSB(src->i_mount, remap_len); /* drange = (destoff, destoff + len); srange = (srcoff, srcoff + len) */ while (len) { uint lock_mode; trace_xfs_reflink_remap_blocks_loop(src, srcoff, len, dest, destoff); /* Read extent from the source file */ nimaps = 1; lock_mode = xfs_ilock_data_map_shared(src); error = xfs_bmapi_read(src, srcoff, len, &imap, &nimaps, 0); xfs_iunlock(src, lock_mode); if (error) break; ASSERT(nimaps == 1); trace_xfs_reflink_remap_imap(src, srcoff, len, XFS_DATA_FORK, &imap); /* Translate imap into the destination file. */ range_len = imap.br_startoff + imap.br_blockcount - srcoff; imap.br_startoff += destoff - srcoff; /* Clear dest from destoff to the end of imap and map it in. */ error = xfs_reflink_remap_extent(dest, &imap, destoff, new_isize); if (error) break; if (fatal_signal_pending(current)) { error = -EINTR; break; } /* Advance drange/srange */ srcoff += range_len; destoff += range_len; len -= range_len; remapped_len += range_len; } if (error) trace_xfs_reflink_remap_blocks_error(dest, error, _RET_IP_); *remapped = min_t(loff_t, remap_len, XFS_FSB_TO_B(src->i_mount, remapped_len)); return error; }