svn commit: r353610 - vendor-sys/illumos/dist/uts/common/fs/zfs
Andriy Gapon
avg at FreeBSD.org
Wed Oct 16 06:11:12 UTC 2019
Author: avg
Date: Wed Oct 16 06:11:11 2019
New Revision: 353610
URL: https://svnweb.freebsd.org/changeset/base/353610
Log:
10230 zfs mishandles partial writes
illumos/illumos-gate at 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 at joyent.com>
Modified:
vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c
Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c Wed Oct 16 06:09:00 2019 (r353609)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c Wed Oct 16 06:11:11 2019 (r353610)
@@ -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
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
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
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;
More information about the svn-src-all
mailing list