svn commit: r366557 - head/sys/kern

Rick Macklem rmacklem at FreeBSD.org
Fri Oct 9 01:04:29 UTC 2020


Author: rmacklem
Date: Fri Oct  9 01:04:28 2020
New Revision: 366557
URL: https://svnweb.freebsd.org/changeset/base/366557

Log:
  Make vn_generic_copy_file_range() interruptible via a signal.
  
  Without this patch, when vn_generic_copy_file_range() is
  doing a large copy, it will remain in the function for a
  considerable amount of time, delaying handling of any
  outstanding signals until the copy completes.
  
  This patch adds checks for signals that need to be
  processed after each successful data copy cycle.
  When sig_intr() returns non-zero, vn_generic_copy_file_range()
  will return.
  The check "if (len < savlen)" ensures that some data
  has been copied, so that progress will be made.
  
  Note that, since copy_file_range(2) is allowed to
  return fewer bytes copied than requested, it
  will never return EINTR/ERESTART when sig_intr()
  returns non-zero.
  
  Reviewed by:	kib, asomers
  Differential Revision:	https://reviews.freebsd.org/D26620

Modified:
  head/sys/kern/vfs_vnops.c

Modified: head/sys/kern/vfs_vnops.c
==============================================================================
--- head/sys/kern/vfs_vnops.c	Fri Oct  9 00:27:45 2020	(r366556)
+++ head/sys/kern/vfs_vnops.c	Fri Oct  9 01:04:28 2020	(r366557)
@@ -3017,7 +3017,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *
 	struct uio io;
 	off_t startoff, endoff, xfer, xfer2;
 	u_long blksize;
-	int error;
+	int error, interrupted;
 	bool cantseek, readzeros, eof, lastblock;
 	ssize_t aresid;
 	size_t copylen, len, rem, savlen;
@@ -3027,6 +3027,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *
 	holein = holeout = 0;
 	savlen = len = *lenp;
 	error = 0;
+	interrupted = 0;
 	dat = NULL;
 
 	error = vn_lock(invp, LK_SHARED);
@@ -3116,7 +3117,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *
 	 * support holes on the server, but do not support FIOSEEKHOLE.
 	 */
 	eof = false;
-	while (len > 0 && error == 0 && !eof) {
+	while (len > 0 && error == 0 && !eof && interrupted == 0) {
 		endoff = 0;			/* To shut up compilers. */
 		cantseek = true;
 		startoff = *inoffp;
@@ -3177,6 +3178,8 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *
 					*inoffp += xfer;
 					*outoffp += xfer;
 					len -= xfer;
+					if (len < savlen)
+						interrupted = sig_intr();
 				}
 			}
 			copylen = MIN(len, endoff - startoff);
@@ -3198,7 +3201,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *
 			xfer -= (*inoffp % blksize);
 		}
 		/* Loop copying the data block. */
-		while (copylen > 0 && error == 0 && !eof) {
+		while (copylen > 0 && error == 0 && !eof && interrupted == 0) {
 			if (copylen < xfer)
 				xfer = copylen;
 			error = vn_lock(invp, LK_SHARED);
@@ -3239,6 +3242,8 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *
 					*outoffp += xfer;
 					copylen -= xfer;
 					len -= xfer;
+					if (len < savlen)
+						interrupted = sig_intr();
 				}
 			}
 			xfer = blksize;


More information about the svn-src-all mailing list