diff options
author | Fabio Scaccabarozzi <[email protected]> | 2020-04-01 18:48:54 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-01 09:48:54 -0700 |
commit | c9e3efdb3a6111b9795becc6594b3c52ba004522 (patch) | |
tree | 2f30f12152f56253f8299d911eab3d7536cd2038 /module/os/linux | |
parent | 0929c4de398606f8305057ca540cf577e6771c30 (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.c | 9 |
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; } |