brintos

brintos / linux-shallow public Read only

0
0
Text · 25.7 KiB · 75cb53f Raw
946 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */6#include "xfs.h"7#include "xfs_shared.h"8#include "xfs_format.h"9#include "xfs_log_format.h"10#include "xfs_trans_resv.h"11#include "xfs_mount.h"12#include "xfs_defer.h"13#include "xfs_inode.h"14#include "xfs_trans.h"15#include "xfs_quota.h"16#include "xfs_bmap_util.h"17#include "xfs_reflink.h"18#include "xfs_trace.h"19#include "xfs_exchrange.h"20#include "xfs_exchmaps.h"21#include "xfs_sb.h"22#include "xfs_icache.h"23#include "xfs_log.h"24#include "xfs_rtbitmap.h"25#include <linux/fsnotify.h>26 27/* Lock (and optionally join) two inodes for a file range exchange. */28void29xfs_exchrange_ilock(30	struct xfs_trans	*tp,31	struct xfs_inode	*ip1,32	struct xfs_inode	*ip2)33{34	if (ip1 != ip2)35		xfs_lock_two_inodes(ip1, XFS_ILOCK_EXCL,36				    ip2, XFS_ILOCK_EXCL);37	else38		xfs_ilock(ip1, XFS_ILOCK_EXCL);39	if (tp) {40		xfs_trans_ijoin(tp, ip1, 0);41		if (ip2 != ip1)42			xfs_trans_ijoin(tp, ip2, 0);43	}44 45}46 47/* Unlock two inodes after a file range exchange operation. */48void49xfs_exchrange_iunlock(50	struct xfs_inode	*ip1,51	struct xfs_inode	*ip2)52{53	if (ip2 != ip1)54		xfs_iunlock(ip2, XFS_ILOCK_EXCL);55	xfs_iunlock(ip1, XFS_ILOCK_EXCL);56}57 58/*59 * Estimate the resource requirements to exchange file contents between the two60 * files.  The caller is required to hold the IOLOCK and the MMAPLOCK and to61 * have flushed both inodes' pagecache and active direct-ios.62 */63int64xfs_exchrange_estimate(65	struct xfs_exchmaps_req	*req)66{67	int			error;68 69	xfs_exchrange_ilock(NULL, req->ip1, req->ip2);70	error = xfs_exchmaps_estimate(req);71	xfs_exchrange_iunlock(req->ip1, req->ip2);72	return error;73}74 75/*76 * Check that file2's metadata agree with the snapshot that we took for the77 * range commit request.78 *79 * This should be called after the filesystem has locked /all/ inode metadata80 * against modification.81 */82STATIC int83xfs_exchrange_check_freshness(84	const struct xfs_exchrange	*fxr,85	struct xfs_inode		*ip2)86{87	struct inode			*inode2 = VFS_I(ip2);88	struct timespec64		ctime = inode_get_ctime(inode2);89	struct timespec64		mtime = inode_get_mtime(inode2);90 91	trace_xfs_exchrange_freshness(fxr, ip2);92 93	/* Check that file2 hasn't otherwise been modified. */94	if (fxr->file2_ino != ip2->i_ino ||95	    fxr->file2_gen != inode2->i_generation ||96	    !timespec64_equal(&fxr->file2_ctime, &ctime) ||97	    !timespec64_equal(&fxr->file2_mtime, &mtime))98		return -EBUSY;99 100	return 0;101}102 103#define QRETRY_IP1	(0x1)104#define QRETRY_IP2	(0x2)105 106/*107 * Obtain a quota reservation to make sure we don't hit EDQUOT.  We can skip108 * this if quota enforcement is disabled or if both inodes' dquots are the109 * same.  The qretry structure must be initialized to zeroes before the first110 * call to this function.111 */112STATIC int113xfs_exchrange_reserve_quota(114	struct xfs_trans		*tp,115	const struct xfs_exchmaps_req	*req,116	unsigned int			*qretry)117{118	int64_t				ddelta, rdelta;119	int				ip1_error = 0;120	int				error;121 122	/*123	 * Don't bother with a quota reservation if we're not enforcing them124	 * or the two inodes have the same dquots.125	 */126	if (!XFS_IS_QUOTA_ON(tp->t_mountp) || req->ip1 == req->ip2 ||127	    (req->ip1->i_udquot == req->ip2->i_udquot &&128	     req->ip1->i_gdquot == req->ip2->i_gdquot &&129	     req->ip1->i_pdquot == req->ip2->i_pdquot))130		return 0;131 132	*qretry = 0;133 134	/*135	 * For each file, compute the net gain in the number of regular blocks136	 * that will be mapped into that file and reserve that much quota.  The137	 * quota counts must be able to absorb at least that much space.138	 */139	ddelta = req->ip2_bcount - req->ip1_bcount;140	rdelta = req->ip2_rtbcount - req->ip1_rtbcount;141	if (ddelta > 0 || rdelta > 0) {142		error = xfs_trans_reserve_quota_nblks(tp, req->ip1,143				ddelta > 0 ? ddelta : 0,144				rdelta > 0 ? rdelta : 0,145				false);146		if (error == -EDQUOT || error == -ENOSPC) {147			/*148			 * Save this error and see what happens if we try to149			 * reserve quota for ip2.  Then report both.150			 */151			*qretry |= QRETRY_IP1;152			ip1_error = error;153			error = 0;154		}155		if (error)156			return error;157	}158	if (ddelta < 0 || rdelta < 0) {159		error = xfs_trans_reserve_quota_nblks(tp, req->ip2,160				ddelta < 0 ? -ddelta : 0,161				rdelta < 0 ? -rdelta : 0,162				false);163		if (error == -EDQUOT || error == -ENOSPC)164			*qretry |= QRETRY_IP2;165		if (error)166			return error;167	}168	if (ip1_error)169		return ip1_error;170 171	/*172	 * For each file, forcibly reserve the gross gain in mapped blocks so173	 * that we don't trip over any quota block reservation assertions.174	 * We must reserve the gross gain because the quota code subtracts from175	 * bcount the number of blocks that we unmap; it does not add that176	 * quantity back to the quota block reservation.177	 */178	error = xfs_trans_reserve_quota_nblks(tp, req->ip1, req->ip1_bcount,179			req->ip1_rtbcount, true);180	if (error)181		return error;182 183	return xfs_trans_reserve_quota_nblks(tp, req->ip2, req->ip2_bcount,184			req->ip2_rtbcount, true);185}186 187/* Exchange the mappings (and hence the contents) of two files' forks. */188STATIC int189xfs_exchrange_mappings(190	const struct xfs_exchrange	*fxr,191	struct xfs_inode		*ip1,192	struct xfs_inode		*ip2)193{194	struct xfs_mount		*mp = ip1->i_mount;195	struct xfs_exchmaps_req		req = {196		.ip1			= ip1,197		.ip2			= ip2,198		.startoff1		= XFS_B_TO_FSBT(mp, fxr->file1_offset),199		.startoff2		= XFS_B_TO_FSBT(mp, fxr->file2_offset),200		.blockcount		= XFS_B_TO_FSB(mp, fxr->length),201	};202	struct xfs_trans		*tp;203	unsigned int			qretry;204	bool				retried = false;205	int				error;206 207	trace_xfs_exchrange_mappings(fxr, ip1, ip2);208 209	if (fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF)210		req.flags |= XFS_EXCHMAPS_SET_SIZES;211	if (fxr->flags & XFS_EXCHANGE_RANGE_FILE1_WRITTEN)212		req.flags |= XFS_EXCHMAPS_INO1_WRITTEN;213 214	/*215	 * Round the request length up to the nearest file allocation unit.216	 * The prep function already checked that the request offsets and217	 * length in @fxr are safe to round up.218	 */219	if (xfs_inode_has_bigrtalloc(ip2))220		req.blockcount = xfs_rtb_roundup_rtx(mp, req.blockcount);221 222	error = xfs_exchrange_estimate(&req);223	if (error)224		return error;225 226retry:227	/* Allocate the transaction, lock the inodes, and join them. */228	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, req.resblks, 0,229			XFS_TRANS_RES_FDBLKS, &tp);230	if (error)231		return error;232 233	xfs_exchrange_ilock(tp, ip1, ip2);234 235	trace_xfs_exchrange_before(ip2, 2);236	trace_xfs_exchrange_before(ip1, 1);237 238	error = xfs_exchmaps_check_forks(mp, &req);239	if (error)240		goto out_trans_cancel;241 242	/*243	 * Reserve ourselves some quota if any of them are in enforcing mode.244	 * In theory we only need enough to satisfy the change in the number245	 * of blocks between the two ranges being remapped.246	 */247	error = xfs_exchrange_reserve_quota(tp, &req, &qretry);248	if ((error == -EDQUOT || error == -ENOSPC) && !retried) {249		xfs_trans_cancel(tp);250		xfs_exchrange_iunlock(ip1, ip2);251		if (qretry & QRETRY_IP1)252			xfs_blockgc_free_quota(ip1, 0);253		if (qretry & QRETRY_IP2)254			xfs_blockgc_free_quota(ip2, 0);255		retried = true;256		goto retry;257	}258	if (error)259		goto out_trans_cancel;260 261	/* If we got this far on a dry run, all parameters are ok. */262	if (fxr->flags & XFS_EXCHANGE_RANGE_DRY_RUN)263		goto out_trans_cancel;264 265	/* Update the mtime and ctime of both files. */266	if (fxr->flags & __XFS_EXCHANGE_RANGE_UPD_CMTIME1)267		xfs_trans_ichgtime(tp, ip1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);268	if (fxr->flags & __XFS_EXCHANGE_RANGE_UPD_CMTIME2)269		xfs_trans_ichgtime(tp, ip2, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);270 271	xfs_exchange_mappings(tp, &req);272 273	/*274	 * Force the log to persist metadata updates if the caller or the275	 * administrator requires this.  The generic prep function already276	 * flushed the relevant parts of the page cache.277	 */278	if (xfs_has_wsync(mp) || (fxr->flags & XFS_EXCHANGE_RANGE_DSYNC))279		xfs_trans_set_sync(tp);280 281	error = xfs_trans_commit(tp);282 283	trace_xfs_exchrange_after(ip2, 2);284	trace_xfs_exchrange_after(ip1, 1);285 286	if (error)287		goto out_unlock;288 289	/*290	 * If the caller wanted us to exchange the contents of two complete291	 * files of unequal length, exchange the incore sizes now.  This should292	 * be safe because we flushed both files' page caches, exchanged all293	 * the mappings, and updated the ondisk sizes.294	 */295	if (fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF) {296		loff_t	temp;297 298		temp = i_size_read(VFS_I(ip2));299		i_size_write(VFS_I(ip2), i_size_read(VFS_I(ip1)));300		i_size_write(VFS_I(ip1), temp);301	}302 303out_unlock:304	xfs_exchrange_iunlock(ip1, ip2);305	return error;306 307out_trans_cancel:308	xfs_trans_cancel(tp);309	goto out_unlock;310}311 312/*313 * Generic code for exchanging ranges of two files via XFS_IOC_EXCHANGE_RANGE.314 * This part deals with struct file objects and byte ranges and does not deal315 * with XFS-specific data structures such as xfs_inodes and block ranges.  This316 * separation may some day facilitate porting to another filesystem.317 *318 * The goal is to exchange fxr.length bytes starting at fxr.file1_offset in319 * file1 with the same number of bytes starting at fxr.file2_offset in file2.320 * Implementations must call xfs_exchange_range_prep to prepare the two321 * files prior to taking locks; and they must update the inode change and mod322 * times of both files as part of the metadata update.  The timestamp update323 * and freshness checks must be done atomically as part of the data exchange324 * operation to ensure correctness of the freshness check.325 * xfs_exchange_range_finish must be called after the operation completes326 * successfully but before locks are dropped.327 */328 329/* Verify that we have security clearance to perform this operation. */330static int331xfs_exchange_range_verify_area(332	struct xfs_exchrange	*fxr)333{334	int			ret;335 336	ret = remap_verify_area(fxr->file1, fxr->file1_offset, fxr->length,337			true);338	if (ret)339		return ret;340 341	return remap_verify_area(fxr->file2, fxr->file2_offset, fxr->length,342			true);343}344 345/*346 * Performs necessary checks before doing a range exchange, having stabilized347 * mutable inode attributes via i_rwsem.348 */349static inline int350xfs_exchange_range_checks(351	struct xfs_exchrange	*fxr,352	unsigned int		alloc_unit)353{354	struct inode		*inode1 = file_inode(fxr->file1);355	struct inode		*inode2 = file_inode(fxr->file2);356	uint64_t		allocmask = alloc_unit - 1;357	int64_t			test_len;358	uint64_t		blen;359	loff_t			size1, size2, tmp;360	int			error;361 362	/* Don't touch certain kinds of inodes */363	if (IS_IMMUTABLE(inode1) || IS_IMMUTABLE(inode2))364		return -EPERM;365	if (IS_SWAPFILE(inode1) || IS_SWAPFILE(inode2))366		return -ETXTBSY;367 368	size1 = i_size_read(inode1);369	size2 = i_size_read(inode2);370 371	/* Ranges cannot start after EOF. */372	if (fxr->file1_offset > size1 || fxr->file2_offset > size2)373		return -EINVAL;374 375	/*376	 * If the caller said to exchange to EOF, we set the length of the377	 * request large enough to cover everything to the end of both files.378	 */379	if (fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF) {380		fxr->length = max_t(int64_t, size1 - fxr->file1_offset,381					     size2 - fxr->file2_offset);382 383		error = xfs_exchange_range_verify_area(fxr);384		if (error)385			return error;386	}387 388	/*389	 * The start of both ranges must be aligned to the file allocation390	 * unit.391	 */392	if (!IS_ALIGNED(fxr->file1_offset, alloc_unit) ||393	    !IS_ALIGNED(fxr->file2_offset, alloc_unit))394		return -EINVAL;395 396	/* Ensure offsets don't wrap. */397	if (check_add_overflow(fxr->file1_offset, fxr->length, &tmp) ||398	    check_add_overflow(fxr->file2_offset, fxr->length, &tmp))399		return -EINVAL;400 401	/*402	 * We require both ranges to end within EOF, unless we're exchanging403	 * to EOF.404	 */405	if (!(fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF) &&406	    (fxr->file1_offset + fxr->length > size1 ||407	     fxr->file2_offset + fxr->length > size2))408		return -EINVAL;409 410	/*411	 * Make sure we don't hit any file size limits.  If we hit any size412	 * limits such that test_length was adjusted, we abort the whole413	 * operation.414	 */415	test_len = fxr->length;416	error = generic_write_check_limits(fxr->file2, fxr->file2_offset,417			&test_len);418	if (error)419		return error;420	error = generic_write_check_limits(fxr->file1, fxr->file1_offset,421			&test_len);422	if (error)423		return error;424	if (test_len != fxr->length)425		return -EINVAL;426 427	/*428	 * If the user wanted us to exchange up to the infile's EOF, round up429	 * to the next allocation unit boundary for this check.  Do the same430	 * for the outfile.431	 *432	 * Otherwise, reject the range length if it's not aligned to an433	 * allocation unit.434	 */435	if (fxr->file1_offset + fxr->length == size1)436		blen = ALIGN(size1, alloc_unit) - fxr->file1_offset;437	else if (fxr->file2_offset + fxr->length == size2)438		blen = ALIGN(size2, alloc_unit) - fxr->file2_offset;439	else if (!IS_ALIGNED(fxr->length, alloc_unit))440		return -EINVAL;441	else442		blen = fxr->length;443 444	/* Don't allow overlapped exchanges within the same file. */445	if (inode1 == inode2 &&446	    fxr->file2_offset + blen > fxr->file1_offset &&447	    fxr->file1_offset + blen > fxr->file2_offset)448		return -EINVAL;449 450	/*451	 * Ensure that we don't exchange a partial EOF block into the middle of452	 * another file.453	 */454	if ((fxr->length & allocmask) == 0)455		return 0;456 457	blen = fxr->length;458	if (fxr->file2_offset + blen < size2)459		blen &= ~allocmask;460 461	if (fxr->file1_offset + blen < size1)462		blen &= ~allocmask;463 464	return blen == fxr->length ? 0 : -EINVAL;465}466 467/*468 * Check that the two inodes are eligible for range exchanges, the ranges make469 * sense, and then flush all dirty data.  Caller must ensure that the inodes470 * have been locked against any other modifications.471 */472static inline int473xfs_exchange_range_prep(474	struct xfs_exchrange	*fxr,475	unsigned int		alloc_unit)476{477	struct inode		*inode1 = file_inode(fxr->file1);478	struct inode		*inode2 = file_inode(fxr->file2);479	bool			same_inode = (inode1 == inode2);480	int			error;481 482	/* Check that we don't violate system file offset limits. */483	error = xfs_exchange_range_checks(fxr, alloc_unit);484	if (error || fxr->length == 0)485		return error;486 487	/* Wait for the completion of any pending IOs on both files */488	inode_dio_wait(inode1);489	if (!same_inode)490		inode_dio_wait(inode2);491 492	error = filemap_write_and_wait_range(inode1->i_mapping,493			fxr->file1_offset,494			fxr->file1_offset + fxr->length - 1);495	if (error)496		return error;497 498	error = filemap_write_and_wait_range(inode2->i_mapping,499			fxr->file2_offset,500			fxr->file2_offset + fxr->length - 1);501	if (error)502		return error;503 504	/*505	 * If the files or inodes involved require synchronous writes, amend506	 * the request to force the filesystem to flush all data and metadata507	 * to disk after the operation completes.508	 */509	if (((fxr->file1->f_flags | fxr->file2->f_flags) & O_SYNC) ||510	    IS_SYNC(inode1) || IS_SYNC(inode2))511		fxr->flags |= XFS_EXCHANGE_RANGE_DSYNC;512 513	return 0;514}515 516/*517 * Finish a range exchange operation, if it was successful.  Caller must ensure518 * that the inodes are still locked against any other modifications.519 */520static inline int521xfs_exchange_range_finish(522	struct xfs_exchrange	*fxr)523{524	int			error;525 526	error = file_remove_privs(fxr->file1);527	if (error)528		return error;529	if (file_inode(fxr->file1) == file_inode(fxr->file2))530		return 0;531 532	return file_remove_privs(fxr->file2);533}534 535/*536 * Check the alignment of an exchange request when the allocation unit size537 * isn't a power of two.  The generic file-level helpers use (fast)538 * bitmask-based alignment checks, but here we have to use slow long division.539 */540static int541xfs_exchrange_check_rtalign(542	const struct xfs_exchrange	*fxr,543	struct xfs_inode		*ip1,544	struct xfs_inode		*ip2,545	unsigned int			alloc_unit)546{547	uint64_t			length = fxr->length;548	uint64_t			blen;549	loff_t				size1, size2;550 551	size1 = i_size_read(VFS_I(ip1));552	size2 = i_size_read(VFS_I(ip2));553 554	/* The start of both ranges must be aligned to a rt extent. */555	if (!isaligned_64(fxr->file1_offset, alloc_unit) ||556	    !isaligned_64(fxr->file2_offset, alloc_unit))557		return -EINVAL;558 559	if (fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF)560		length = max_t(int64_t, size1 - fxr->file1_offset,561					size2 - fxr->file2_offset);562 563	/*564	 * If the user wanted us to exchange up to the infile's EOF, round up565	 * to the next rt extent boundary for this check.  Do the same for the566	 * outfile.567	 *568	 * Otherwise, reject the range length if it's not rt extent aligned.569	 * We already confirmed the starting offsets' rt extent block570	 * alignment.571	 */572	if (fxr->file1_offset + length == size1)573		blen = roundup_64(size1, alloc_unit) - fxr->file1_offset;574	else if (fxr->file2_offset + length == size2)575		blen = roundup_64(size2, alloc_unit) - fxr->file2_offset;576	else if (!isaligned_64(length, alloc_unit))577		return -EINVAL;578	else579		blen = length;580 581	/* Don't allow overlapped exchanges within the same file. */582	if (ip1 == ip2 &&583	    fxr->file2_offset + blen > fxr->file1_offset &&584	    fxr->file1_offset + blen > fxr->file2_offset)585		return -EINVAL;586 587	/*588	 * Ensure that we don't exchange a partial EOF rt extent into the589	 * middle of another file.590	 */591	if (isaligned_64(length, alloc_unit))592		return 0;593 594	blen = length;595	if (fxr->file2_offset + length < size2)596		blen = rounddown_64(blen, alloc_unit);597 598	if (fxr->file1_offset + blen < size1)599		blen = rounddown_64(blen, alloc_unit);600 601	return blen == length ? 0 : -EINVAL;602}603 604/* Prepare two files to have their data exchanged. */605STATIC int606xfs_exchrange_prep(607	struct xfs_exchrange	*fxr,608	struct xfs_inode	*ip1,609	struct xfs_inode	*ip2)610{611	struct xfs_mount	*mp = ip2->i_mount;612	unsigned int		alloc_unit = xfs_inode_alloc_unitsize(ip2);613	int			error;614 615	trace_xfs_exchrange_prep(fxr, ip1, ip2);616 617	/* Verify both files are either real-time or non-realtime */618	if (XFS_IS_REALTIME_INODE(ip1) != XFS_IS_REALTIME_INODE(ip2))619		return -EINVAL;620 621	/* Check non-power of two alignment issues, if necessary. */622	if (!is_power_of_2(alloc_unit)) {623		error = xfs_exchrange_check_rtalign(fxr, ip1, ip2, alloc_unit);624		if (error)625			return error;626 627		/*628		 * Do the generic file-level checks with the regular block629		 * alignment.630		 */631		alloc_unit = mp->m_sb.sb_blocksize;632	}633 634	error = xfs_exchange_range_prep(fxr, alloc_unit);635	if (error || fxr->length == 0)636		return error;637 638	if (fxr->flags & __XFS_EXCHANGE_RANGE_CHECK_FRESH2) {639		error = xfs_exchrange_check_freshness(fxr, ip2);640		if (error)641			return error;642	}643 644	/* Attach dquots to both inodes before changing block maps. */645	error = xfs_qm_dqattach(ip2);646	if (error)647		return error;648	error = xfs_qm_dqattach(ip1);649	if (error)650		return error;651 652	trace_xfs_exchrange_flush(fxr, ip1, ip2);653 654	/* Flush the relevant ranges of both files. */655	error = xfs_flush_unmap_range(ip2, fxr->file2_offset, fxr->length);656	if (error)657		return error;658	error = xfs_flush_unmap_range(ip1, fxr->file1_offset, fxr->length);659	if (error)660		return error;661 662	/*663	 * Cancel CoW fork preallocations for the ranges of both files.  The664	 * prep function should have flushed all the dirty data, so the only665	 * CoW mappings remaining should be speculative.666	 */667	if (xfs_inode_has_cow_data(ip1)) {668		error = xfs_reflink_cancel_cow_range(ip1, fxr->file1_offset,669				fxr->length, true);670		if (error)671			return error;672	}673 674	if (xfs_inode_has_cow_data(ip2)) {675		error = xfs_reflink_cancel_cow_range(ip2, fxr->file2_offset,676				fxr->length, true);677		if (error)678			return error;679	}680 681	return 0;682}683 684/*685 * Exchange contents of files.  This is the binding between the generic686 * file-level concepts and the XFS inode-specific implementation.687 */688STATIC int689xfs_exchrange_contents(690	struct xfs_exchrange	*fxr)691{692	struct inode		*inode1 = file_inode(fxr->file1);693	struct inode		*inode2 = file_inode(fxr->file2);694	struct xfs_inode	*ip1 = XFS_I(inode1);695	struct xfs_inode	*ip2 = XFS_I(inode2);696	struct xfs_mount	*mp = ip1->i_mount;697	int			error;698 699	if (!xfs_has_exchange_range(mp))700		return -EOPNOTSUPP;701 702	if (fxr->flags & ~(XFS_EXCHANGE_RANGE_ALL_FLAGS |703			   XFS_EXCHANGE_RANGE_PRIV_FLAGS))704		return -EINVAL;705 706	if (xfs_is_shutdown(mp))707		return -EIO;708 709	/* Lock both files against IO */710	error = xfs_ilock2_io_mmap(ip1, ip2);711	if (error)712		goto out_err;713 714	/* Prepare and then exchange file contents. */715	error = xfs_exchrange_prep(fxr, ip1, ip2);716	if (error)717		goto out_unlock;718 719	error = xfs_exchrange_mappings(fxr, ip1, ip2);720	if (error)721		goto out_unlock;722 723	/*724	 * Finish the exchange by removing special file privileges like any725	 * other file write would do.  This may involve turning on support for726	 * logged xattrs if either file has security capabilities.727	 */728	error = xfs_exchange_range_finish(fxr);729	if (error)730		goto out_unlock;731 732out_unlock:733	xfs_iunlock2_io_mmap(ip1, ip2);734out_err:735	if (error)736		trace_xfs_exchrange_error(ip2, error, _RET_IP_);737	return error;738}739 740/* Exchange parts of two files. */741static int742xfs_exchange_range(743	struct xfs_exchrange	*fxr)744{745	struct inode		*inode1 = file_inode(fxr->file1);746	struct inode		*inode2 = file_inode(fxr->file2);747	int			ret;748 749	BUILD_BUG_ON(XFS_EXCHANGE_RANGE_ALL_FLAGS &750		     XFS_EXCHANGE_RANGE_PRIV_FLAGS);751 752	/* Both files must be on the same mount/filesystem. */753	if (fxr->file1->f_path.mnt != fxr->file2->f_path.mnt)754		return -EXDEV;755 756	if (fxr->flags & ~(XFS_EXCHANGE_RANGE_ALL_FLAGS |757			 __XFS_EXCHANGE_RANGE_CHECK_FRESH2))758		return -EINVAL;759 760	/* Userspace requests only honored for regular files. */761	if (S_ISDIR(inode1->i_mode) || S_ISDIR(inode2->i_mode))762		return -EISDIR;763	if (!S_ISREG(inode1->i_mode) || !S_ISREG(inode2->i_mode))764		return -EINVAL;765 766	/* Both files must be opened for read and write. */767	if (!(fxr->file1->f_mode & FMODE_READ) ||768	    !(fxr->file1->f_mode & FMODE_WRITE) ||769	    !(fxr->file2->f_mode & FMODE_READ) ||770	    !(fxr->file2->f_mode & FMODE_WRITE))771		return -EBADF;772 773	/* Neither file can be opened append-only. */774	if ((fxr->file1->f_flags & O_APPEND) ||775	    (fxr->file2->f_flags & O_APPEND))776		return -EBADF;777 778	/*779	 * If we're not exchanging to EOF, we can check the areas before780	 * stabilizing both files' i_size.781	 */782	if (!(fxr->flags & XFS_EXCHANGE_RANGE_TO_EOF)) {783		ret = xfs_exchange_range_verify_area(fxr);784		if (ret)785			return ret;786	}787 788	/* Update cmtime if the fd/inode don't forbid it. */789	if (!(fxr->file1->f_mode & FMODE_NOCMTIME) && !IS_NOCMTIME(inode1))790		fxr->flags |= __XFS_EXCHANGE_RANGE_UPD_CMTIME1;791	if (!(fxr->file2->f_mode & FMODE_NOCMTIME) && !IS_NOCMTIME(inode2))792		fxr->flags |= __XFS_EXCHANGE_RANGE_UPD_CMTIME2;793 794	file_start_write(fxr->file2);795	ret = xfs_exchrange_contents(fxr);796	file_end_write(fxr->file2);797	if (ret)798		return ret;799 800	fsnotify_modify(fxr->file1);801	if (fxr->file2 != fxr->file1)802		fsnotify_modify(fxr->file2);803	return 0;804}805 806/* Collect exchange-range arguments from userspace. */807long808xfs_ioc_exchange_range(809	struct file			*file,810	struct xfs_exchange_range __user *argp)811{812	struct xfs_exchrange		fxr = {813		.file2			= file,814	};815	struct xfs_exchange_range	args;816	struct fd			file1;817	int				error;818 819	if (copy_from_user(&args, argp, sizeof(args)))820		return -EFAULT;821	if (memchr_inv(&args.pad, 0, sizeof(args.pad)))822		return -EINVAL;823	if (args.flags & ~XFS_EXCHANGE_RANGE_ALL_FLAGS)824		return -EINVAL;825 826	fxr.file1_offset	= args.file1_offset;827	fxr.file2_offset	= args.file2_offset;828	fxr.length		= args.length;829	fxr.flags		= args.flags;830 831	file1 = fdget(args.file1_fd);832	if (!fd_file(file1))833		return -EBADF;834	fxr.file1 = fd_file(file1);835 836	error = xfs_exchange_range(&fxr);837	fdput(file1);838	return error;839}840 841/* Opaque freshness blob for XFS_IOC_COMMIT_RANGE */842struct xfs_commit_range_fresh {843	xfs_fsid_t	fsid;		/* m_fixedfsid */844	__u64		file2_ino;	/* inode number */845	__s64		file2_mtime;	/* modification time */846	__s64		file2_ctime;	/* change time */847	__s32		file2_mtime_nsec; /* mod time, nsec */848	__s32		file2_ctime_nsec; /* change time, nsec */849	__u32		file2_gen;	/* inode generation */850	__u32		magic;		/* zero */851};852#define XCR_FRESH_MAGIC	0x444F524B	/* DORK */853 854/* Set up a commitrange operation by sampling file2's write-related attrs */855long856xfs_ioc_start_commit(857	struct file			*file,858	struct xfs_commit_range __user	*argp)859{860	struct xfs_commit_range		args = { };861	struct timespec64		ts;862	struct xfs_commit_range_fresh	*kern_f;863	struct xfs_commit_range_fresh	__user *user_f;864	struct inode			*inode2 = file_inode(file);865	struct xfs_inode		*ip2 = XFS_I(inode2);866	const unsigned int		lockflags = XFS_IOLOCK_SHARED |867						    XFS_MMAPLOCK_SHARED |868						    XFS_ILOCK_SHARED;869 870	BUILD_BUG_ON(sizeof(struct xfs_commit_range_fresh) !=871		     sizeof(args.file2_freshness));872 873	kern_f = (struct xfs_commit_range_fresh *)&args.file2_freshness;874 875	memcpy(&kern_f->fsid, ip2->i_mount->m_fixedfsid, sizeof(xfs_fsid_t));876 877	xfs_ilock(ip2, lockflags);878	ts = inode_get_ctime(inode2);879	kern_f->file2_ctime		= ts.tv_sec;880	kern_f->file2_ctime_nsec	= ts.tv_nsec;881	ts = inode_get_mtime(inode2);882	kern_f->file2_mtime		= ts.tv_sec;883	kern_f->file2_mtime_nsec	= ts.tv_nsec;884	kern_f->file2_ino		= ip2->i_ino;885	kern_f->file2_gen		= inode2->i_generation;886	kern_f->magic			= XCR_FRESH_MAGIC;887	xfs_iunlock(ip2, lockflags);888 889	user_f = (struct xfs_commit_range_fresh __user *)&argp->file2_freshness;890	if (copy_to_user(user_f, kern_f, sizeof(*kern_f)))891		return -EFAULT;892 893	return 0;894}895 896/*897 * Exchange file1 and file2 contents if file2 has not been written since the898 * start commit operation.899 */900long901xfs_ioc_commit_range(902	struct file			*file,903	struct xfs_commit_range __user	*argp)904{905	struct xfs_exchrange		fxr = {906		.file2			= file,907	};908	struct xfs_commit_range		args;909	struct xfs_commit_range_fresh	*kern_f;910	struct xfs_inode		*ip2 = XFS_I(file_inode(file));911	struct xfs_mount		*mp = ip2->i_mount;912	struct fd			file1;913	int				error;914 915	kern_f = (struct xfs_commit_range_fresh *)&args.file2_freshness;916 917	if (copy_from_user(&args, argp, sizeof(args)))918		return -EFAULT;919	if (args.flags & ~XFS_EXCHANGE_RANGE_ALL_FLAGS)920		return -EINVAL;921	if (kern_f->magic != XCR_FRESH_MAGIC)922		return -EBUSY;923	if (memcmp(&kern_f->fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)))924		return -EBUSY;925 926	fxr.file1_offset	= args.file1_offset;927	fxr.file2_offset	= args.file2_offset;928	fxr.length		= args.length;929	fxr.flags		= args.flags | __XFS_EXCHANGE_RANGE_CHECK_FRESH2;930	fxr.file2_ino		= kern_f->file2_ino;931	fxr.file2_gen		= kern_f->file2_gen;932	fxr.file2_mtime.tv_sec	= kern_f->file2_mtime;933	fxr.file2_mtime.tv_nsec	= kern_f->file2_mtime_nsec;934	fxr.file2_ctime.tv_sec	= kern_f->file2_ctime;935	fxr.file2_ctime.tv_nsec	= kern_f->file2_ctime_nsec;936 937	file1 = fdget(args.file1_fd);938	if (fd_empty(file1))939		return -EBADF;940	fxr.file1 = fd_file(file1);941 942	error = xfs_exchange_range(&fxr);943	fdput(file1);944	return error;945}946