svn commit: r323918 - head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
Andriy Gapon
avg at FreeBSD.org
Fri Sep 22 08:27:28 UTC 2017
Author: avg
Date: Fri Sep 22 08:27:27 2017
New Revision: 323918
URL: https://svnweb.freebsd.org/changeset/base/323918
Log:
MFV r323917: 8648 Fix range locking in ZIL commit codepath
illumos/illumos-gate at 42b14111721da2ebd5159e7b45012a3eb0e3384c
https://github.com/illumos/illumos-gate/commit/42b14111721da2ebd5159e7b45012a3eb0e3384c
https://www.illumos.org/issues/8648
I'm opening this bug to track integration of the following ZFS on Linux
commit into illumos:
commit f763c3d1df569a8d6b60bcb5e95cf07aa7a189e6
Author: LOLi <loli10K at users.noreply.github.com>
Date: Mon Aug 21 17:59:48 2017 +0200
Fix range locking in ZIL commit codepath
Since OpenZFS 7578 (1b7c1e5) if we have a ZVOL with logbias=throughput
we will force WR_INDIRECT itxs in zvol_log_write() setting itx->itx_lr
offset and length to the offset and length of the BIO from
zvol_write()->zvol_log_write(): these offset and length are later used
to take a range lock in zillog->zl_get_data function: zvol_get_data().
Now suppose we have a ZVOL with blocksize=8K and push 4K writes to
offset 0: we will only be range-locking 0-4096. This means the
ASSERTion we make in dbuf_unoverride() is no longer valid because now
dmu_sync() is called from zilog's get_data functions holding a partial
lock on the dbuf.
Fix this by taking a range lock on the whole block in zvol_get_data().
Reviewed-by: Chunwei Chen <tuxoko at gmail.com>
Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
Signed-off-by: loli10K <ezomori.nozomu at gmail.com>
Reviewed by: Igor Kozhukhov <igor at dilos.org>
Reviewed by: Matt Ahrens <mahrens at delphix.com>
Reviewed by: Andriy Gapon <avg at FreeBSD.org>
Reviewed by: Alexander Motin <mav at FreeBSD.org>
Approved by: Robert Mustacchi <rm at joyent.com>
Author: LOLi <loli10K at users.noreply.github.com>
MFC after: 10 days
Modified:
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
Directory Properties:
head/sys/cddl/contrib/opensolaris/ (props changed)
Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Fri Sep 22 08:23:24 2017 (r323917)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Fri Sep 22 08:27:27 2017 (r323918)
@@ -1343,7 +1343,7 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio
} else { /* indirect write */
/*
* Have to lock the whole block to ensure when it's
- * written out and it's checksum is being calculated
+ * written out and its checksum is being calculated
* that no one can change the data. We need to re-check
* blocksize after we get the lock in case it's changed!
*/
Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c Fri Sep 22 08:23:24 2017 (r323917)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c Fri Sep 22 08:27:27 2017 (r323918)
@@ -1349,7 +1349,6 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, zi
zgd = kmem_zalloc(sizeof (zgd_t), KM_SLEEP);
zgd->zgd_zilog = zv->zv_zilog;
- zgd->zgd_rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_READER);
/*
* Write records come in two flavors: immediate and indirect.
@@ -1358,12 +1357,22 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, zi
* sync the data and get a pointer to it (indirect) so that
* we don't have to write the data twice.
*/
- if (buf != NULL) { /* immediate write */
+ if (buf != NULL) { /* immediate write */
+ zgd->zgd_rl = zfs_range_lock(&zv->zv_znode, offset, size,
+ RL_READER);
error = dmu_read(os, object, offset, size, buf,
DMU_READ_NO_PREFETCH);
- } else {
+ } else { /* indirect write */
+ /*
+ * Have to lock the whole block to ensure when it's written out
+ * and its checksum is being calculated that no one can change
+ * the data. Contrarily to zfs_get_data we need not re-check
+ * blocksize after we get the lock because it cannot be changed.
+ */
size = zv->zv_volblocksize;
offset = P2ALIGN(offset, size);
+ zgd->zgd_rl = zfs_range_lock(&zv->zv_znode, offset, size,
+ RL_READER);
error = dmu_buf_hold(os, object, offset, zgd, &db,
DMU_READ_NO_PREFETCH);
if (error == 0) {
More information about the svn-src-all
mailing list