@@ -329,22 +329,6 @@ xfs_exchrange_mappings(
329329 * successfully but before locks are dropped.
330330 */
331331
332- /* Verify that we have security clearance to perform this operation. */
333- static int
334- xfs_exchange_range_verify_area (
335- struct xfs_exchrange * fxr )
336- {
337- int ret ;
338-
339- ret = remap_verify_area (fxr -> file1 , fxr -> file1_offset , fxr -> length ,
340- true);
341- if (ret )
342- return ret ;
343-
344- return remap_verify_area (fxr -> file2 , fxr -> file2_offset , fxr -> length ,
345- true);
346- }
347-
348332/*
349333 * Performs necessary checks before doing a range exchange, having stabilized
350334 * mutable inode attributes via i_rwsem.
@@ -355,11 +339,13 @@ xfs_exchange_range_checks(
355339 unsigned int alloc_unit )
356340{
357341 struct inode * inode1 = file_inode (fxr -> file1 );
342+ loff_t size1 = i_size_read (inode1 );
358343 struct inode * inode2 = file_inode (fxr -> file2 );
344+ loff_t size2 = i_size_read (inode2 );
359345 uint64_t allocmask = alloc_unit - 1 ;
360346 int64_t test_len ;
361347 uint64_t blen ;
362- loff_t size1 , size2 , tmp ;
348+ loff_t tmp ;
363349 int error ;
364350
365351 /* Don't touch certain kinds of inodes */
@@ -368,24 +354,25 @@ xfs_exchange_range_checks(
368354 if (IS_SWAPFILE (inode1 ) || IS_SWAPFILE (inode2 ))
369355 return - ETXTBSY ;
370356
371- size1 = i_size_read (inode1 );
372- size2 = i_size_read (inode2 );
373-
374357 /* Ranges cannot start after EOF. */
375358 if (fxr -> file1_offset > size1 || fxr -> file2_offset > size2 )
376359 return - EINVAL ;
377360
378- /*
379- * If the caller said to exchange to EOF, we set the length of the
380- * request large enough to cover everything to the end of both files.
381- */
382361 if (fxr -> flags & XFS_EXCHANGE_RANGE_TO_EOF ) {
362+ /*
363+ * If the caller said to exchange to EOF, we set the length of
364+ * the request large enough to cover everything to the end of
365+ * both files.
366+ */
383367 fxr -> length = max_t (int64_t , size1 - fxr -> file1_offset ,
384368 size2 - fxr -> file2_offset );
385-
386- error = xfs_exchange_range_verify_area (fxr );
387- if (error )
388- return error ;
369+ } else {
370+ /*
371+ * Otherwise we require both ranges to end within EOF.
372+ */
373+ if (fxr -> file1_offset + fxr -> length > size1 ||
374+ fxr -> file2_offset + fxr -> length > size2 )
375+ return - EINVAL ;
389376 }
390377
391378 /*
@@ -401,15 +388,6 @@ xfs_exchange_range_checks(
401388 check_add_overflow (fxr -> file2_offset , fxr -> length , & tmp ))
402389 return - EINVAL ;
403390
404- /*
405- * We require both ranges to end within EOF, unless we're exchanging
406- * to EOF.
407- */
408- if (!(fxr -> flags & XFS_EXCHANGE_RANGE_TO_EOF ) &&
409- (fxr -> file1_offset + fxr -> length > size1 ||
410- fxr -> file2_offset + fxr -> length > size2 ))
411- return - EINVAL ;
412-
413391 /*
414392 * Make sure we don't hit any file size limits. If we hit any size
415393 * limits such that test_length was adjusted, we abort the whole
@@ -747,6 +725,7 @@ xfs_exchange_range(
747725{
748726 struct inode * inode1 = file_inode (fxr -> file1 );
749727 struct inode * inode2 = file_inode (fxr -> file2 );
728+ loff_t check_len = fxr -> length ;
750729 int ret ;
751730
752731 BUILD_BUG_ON (XFS_EXCHANGE_RANGE_ALL_FLAGS &
@@ -779,14 +758,18 @@ xfs_exchange_range(
779758 return - EBADF ;
780759
781760 /*
782- * If we're not exchanging to EOF, we can check the areas before
783- * stabilizing both files' i_size.
761+ * If we're exchanging to EOF we can't calculate the length until taking
762+ * the iolock. Pass a 0 length to remap_verify_area similar to the
763+ * FICLONE and FICLONERANGE ioctls that support cloning to EOF as well.
784764 */
785- if (!(fxr -> flags & XFS_EXCHANGE_RANGE_TO_EOF )) {
786- ret = xfs_exchange_range_verify_area (fxr );
787- if (ret )
788- return ret ;
789- }
765+ if (fxr -> flags & XFS_EXCHANGE_RANGE_TO_EOF )
766+ check_len = 0 ;
767+ ret = remap_verify_area (fxr -> file1 , fxr -> file1_offset , check_len , true);
768+ if (ret )
769+ return ret ;
770+ ret = remap_verify_area (fxr -> file2 , fxr -> file2_offset , check_len , true);
771+ if (ret )
772+ return ret ;
790773
791774 /* Update cmtime if the fd/inode don't forbid it. */
792775 if (!(fxr -> file1 -> f_mode & FMODE_NOCMTIME ) && !IS_NOCMTIME (inode1 ))
0 commit comments