Author: avg Date: Fri Dec 1 11:14:13 2017 New Revision: 326428 URL: https://svnweb.freebsd.org/changeset/base/326428
Log: MFC r326070: zfs_write: fix problem with writes appearing to succeed when over quota The problem happens when the writes have offsets and sizes aligned with a filesystem's recordsize (maximum block size). In this scenario dmu_tx_assign() would fail because of being over the quota, but the uio would already be modified in the code path where we copy data from the uio into a borrowed ARC buffer. That makes an appearance of a partial write, so zfs_write() would return success and the uio would be modified consistently with writing a single block. That bug can result in a data loss because the writes over the quota would appear to succeed while the actual data is being discarded. This commit fixes the bug by ensuring that the uio is not changed until after all error checks are done. To achieve that the code now uses uiocopy() + uioskip() as in the original illumos design. We can do that now that uiocopy() has been updated in r326067 to use vn_io_fault_uiomove(). Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c ============================================================================== --- stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Fri Dec 1 11:13:58 2017 (r326427) +++ stable/10/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Fri Dec 1 11:14:13 2017 (r326428) @@ -1036,31 +1036,18 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t * holding up the transaction if the data copy hangs * up on a pagefault (e.g., from an NFS server mapping). */ -#ifdef illumos size_t cbytes; -#endif abuf = dmu_request_arcbuf(sa_get_db(zp->z_sa_hdl), max_blksz); ASSERT(abuf != NULL); ASSERT(arc_buf_size(abuf) == max_blksz); -#ifdef illumos if (error = uiocopy(abuf->b_data, max_blksz, UIO_WRITE, uio, &cbytes)) { dmu_return_arcbuf(abuf); break; } ASSERT(cbytes == max_blksz); -#else - ssize_t resid = uio->uio_resid; - error = vn_io_fault_uiomove(abuf->b_data, max_blksz, uio); - if (error != 0) { - uio->uio_offset -= resid - uio->uio_resid; - uio->uio_resid = resid; - dmu_return_arcbuf(abuf); - break; - } -#endif } /* @@ -1138,10 +1125,8 @@ zfs_write(vnode_t *vp, uio_t *uio, int ioflag, cred_t dmu_assign_arcbuf(sa_get_db(zp->z_sa_hdl), woff, abuf, tx); } -#ifdef illumos ASSERT(tx_bytes <= uio->uio_resid); uioskip(uio, tx_bytes); -#endif } if (tx_bytes && vn_has_cached_data(vp)) { update_pages(vp, woff, tx_bytes, zfsvfs->z_os, _______________________________________________ svn-src-stable-10@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10 To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"