Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -2770,6 +2770,60 @@ return (error); } +static int +sig_intr(struct thread *td) +{ + struct proc *p; + struct sigacts *ps; + int ret, sig; + + if ((td->td_flags & (TDF_NEEDSIGCHK | TDF_NEEDSUSPCHK)) == 0) + return (0); + + p = td->td_proc; + PROC_LOCK(p); + + if ((td->td_flags & TDF_NEEDSUSPCHK) != 0) { + ret = thread_suspend_check(1); + MPASS(ret == 0 || ret == EINTR || ret == ERESTART); + if (ret != 0) + goto out; + } + + ret = 0; + if ((td->td_flags & TDF_NEEDSIGCHK) != 0) { + ps = p->p_sigacts; + mtx_lock(&ps->ps_mtx); + sig = cursig(td); + if (sig == -1) { + mtx_unlock(&ps->ps_mtx); + KASSERT((td->td_flags & TDF_SBDRY) != 0, + ("lost TDF_SBDRY")); + KASSERT(TD_SBDRY_INTR(td), + ("lost TDF_SERESTART of TDF_SEINTR")); + KASSERT((td->td_flags & (TDF_SEINTR | TDF_SERESTART)) != + (TDF_SEINTR | TDF_SERESTART), + ("both TDF_SEINTR and TDF_SERESTART")); + ret = TD_SBDRY_ERRNO(td); + } else if (sig != 0) { + ret = SIGISMEMBER(ps->ps_sigintr, sig) ? EINTR : + ERESTART; + mtx_unlock(&ps->ps_mtx); + } else { + mtx_unlock(&ps->ps_mtx); + } + + if ((td->td_dbgflags & TDB_FSTP) != 0) { + if (ret == 0) + ret = EINTR; + td->td_dbgflags &= ~TDB_FSTP; + } + } +out: + PROC_UNLOCK(p); + return (ret); +} + /* * Copies a byte range from invp to outvp. Calls VOP_COPY_FILE_RANGE() * or vn_generic_copy_file_range() after rangelocking the byte ranges, @@ -3012,7 +3066,7 @@ 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; @@ -3022,6 +3076,7 @@ holein = holeout = 0; savlen = len = *lenp; error = 0; + interrupted = 0; dat = NULL; error = vn_lock(invp, LK_SHARED); @@ -3111,7 +3166,7 @@ * 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; @@ -3172,6 +3227,9 @@ *inoffp += xfer; *outoffp += xfer; len -= xfer; + if (len < savlen) + interrupted = + sig_intr(curthread); } } copylen = MIN(len, endoff - startoff); @@ -3193,7 +3251,7 @@ 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); @@ -3234,6 +3292,9 @@ *outoffp += xfer; copylen -= xfer; len -= xfer; + if (len < savlen) + interrupted = + sig_intr(curthread); } } xfer = blksize;