summaryrefslogtreecommitdiffstats
path: root/module/os/linux
diff options
context:
space:
mode:
authorFabio Scaccabarozzi <[email protected]>2020-04-01 18:48:54 +0200
committerGitHub <[email protected]>2020-04-01 09:48:54 -0700
commitc9e3efdb3a6111b9795becc6594b3c52ba004522 (patch)
tree2f30f12152f56253f8299d911eab3d7536cd2038 /module/os/linux
parent0929c4de398606f8305057ca540cf577e6771c30 (diff)
Bugfix/fix uio partial copies
In zfs_write(), the loop continues to the next iteration without accounting for partial copies occurring in uiomove_iov when copy_from_user/__copy_from_user_inatomic return a non-zero status. This results in "zfs: accessing past end of object..." in the kernel log, and the write failing. Account for partial copies and update uio struct before returning EFAULT, leave a comment explaining the reason why this is done. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: ilbsmart <[email protected]> Signed-off-by: Fabio Scaccabarozzi <[email protected]> Closes #8673 Closes #10148
Diffstat (limited to 'module/os/linux')
-rw-r--r--module/os/linux/zfs/zfs_vnops.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/module/os/linux/zfs/zfs_vnops.c b/module/os/linux/zfs/zfs_vnops.c
index 4929c97e9..aba125f3b 100644
--- a/module/os/linux/zfs/zfs_vnops.c
+++ b/module/os/linux/zfs/zfs_vnops.c
@@ -829,6 +829,15 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
uio->uio_fault_disable = B_FALSE;
if (error == EFAULT) {
dmu_tx_commit(tx);
+ /*
+ * Account for partial writes before
+ * continuing the loop.
+ * Update needs to occur before the next
+ * uio_prefaultpages, or prefaultpages may
+ * error, and we may break the loop early.
+ */
+ if (tx_bytes != uio->uio_resid)
+ n -= tx_bytes - uio->uio_resid;
if (uio_prefaultpages(MIN(n, max_blksz), uio)) {
break;
}