aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndriy Gapon <avg@FreeBSD.org>2019-10-16 06:11:11 +0000
committerAndriy Gapon <avg@FreeBSD.org>2019-10-16 06:11:11 +0000
commitc4dff1c2563b495ebe757f50c160425a576d9abf (patch)
tree9f8dada30c045d9d16feefc6a438892a3d6c7c73
parentb75b64ae4b5f90dc68ba6e65ef683d62650d40ba (diff)
downloadsrc-c4dff1c2563b495ebe757f50c160425a576d9abf.tar.gz
src-c4dff1c2563b495ebe757f50c160425a576d9abf.zip
10230 zfs mishandles partial writes
illumos/illumos-gate@b0ef425652e5cfce27df9fa5826a9cd64cee110a https://github.com/illumos/illumos-gate/commit/b0ef425652e5cfce27df9fa5826a9cd64cee110a https://www.illumos.org/issues/10230 The trinity fuzzer calls pwritev with an iovec that has one or more entries which point to some initial valid data and then the rest point to addresses which are not mapped. This yields EFAULT once the write hits the invalid address, but we do successfully complete some amount of writing. The zfs_write code does not handle this properly. It loses track of the error return from dmu_write_uio_dbuf and it has an invalid ASSERT which does not account for the partial write case. Author: Jerry Jelinek <jerry.jelinek@joyent.com>
Notes
Notes: svn path=/vendor-sys/illumos/dist/; revision=353610
-rw-r--r--uts/common/fs/zfs/zfs_vnops.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/uts/common/fs/zfs/zfs_vnops.c b/uts/common/fs/zfs/zfs_vnops.c
index c57982d9b4a2..a68fc3dd3417 100644
--- a/uts/common/fs/zfs/zfs_vnops.c
+++ b/uts/common/fs/zfs/zfs_vnops.c
@@ -23,7 +23,7 @@
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
- * Copyright 2015 Joyent, Inc.
+ * Copyright 2019 Joyent, Inc.
* Copyright 2017 Nexenta Systems, Inc.
*/
@@ -665,6 +665,7 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
ssize_t n, nbytes;
int max_blksz = zfsvfs->z_max_blksz;
int error = 0;
+ int prev_error;
arc_buf_t *abuf;
iovec_t *aiov = NULL;
xuio_t *xuio = NULL;
@@ -972,7 +973,6 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
while ((end_size = zp->z_size) < uio->uio_loffset) {
(void) atomic_cas_64(&zp->z_size, end_size,
uio->uio_loffset);
- ASSERT(error == 0);
}
/*
* If we are replaying and eof is non zero then force
@@ -982,12 +982,17 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cr, caller_context_t *ct)
if (zfsvfs->z_replay && zfsvfs->z_replay_eof != 0)
zp->z_size = zfsvfs->z_replay_eof;
+ /*
+ * Keep track of a possible pre-existing error from a partial
+ * write via dmu_write_uio_dbuf above.
+ */
+ prev_error = error;
error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
zfs_log_write(zilog, tx, TX_WRITE, zp, woff, tx_bytes, ioflag);
dmu_tx_commit(tx);
- if (error != 0)
+ if (prev_error != 0 || error != 0)
break;
ASSERT(tx_bytes == nbytes);
n -= nbytes;