Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Sep 2017 08:23:24 +0000 (UTC)
From:      Andriy Gapon <avg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r323917 - vendor-sys/illumos/dist/uts/common/fs/zfs
Message-ID:  <201709220823.v8M8NORB026425@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avg
Date: Fri Sep 22 08:23:24 2017
New Revision: 323917
URL: https://svnweb.freebsd.org/changeset/base/323917

Log:
  8648 Fix range locking in ZIL commit codepath
  
  illumos/illumos-gate@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@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@gmail.com>
        Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
        Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
  
  Reviewed by: Igor Kozhukhov <igor@dilos.org>
  Reviewed by: Matt Ahrens <mahrens@delphix.com>
  Reviewed by: Andriy Gapon <avg@FreeBSD.org>
  Reviewed by: Alexander Motin <mav@FreeBSD.org>
  Approved by: Robert Mustacchi <rm@joyent.com>
  Author: LOLi <loli10K@users.noreply.github.com>

Modified:
  vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c
  vendor-sys/illumos/dist/uts/common/fs/zfs/zvol.c

Modified: vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c	Fri Sep 22 08:21:35 2017	(r323916)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/zfs_vnops.c	Fri Sep 22 08:23:24 2017	(r323917)
@@ -1101,7 +1101,7 @@ zfs_get_data(void *arg, lr_write_t *lr, char *buf, str
 	} 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: vendor-sys/illumos/dist/uts/common/fs/zfs/zvol.c
==============================================================================
--- vendor-sys/illumos/dist/uts/common/fs/zfs/zvol.c	Fri Sep 22 08:21:35 2017	(r323916)
+++ vendor-sys/illumos/dist/uts/common/fs/zfs/zvol.c	Fri Sep 22 08:23:24 2017	(r323917)
@@ -1003,7 +1003,6 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, st
 
 	zgd = kmem_zalloc(sizeof (zgd_t), KM_SLEEP);
 	zgd->zgd_lwb = lwb;
-	zgd->zgd_rl = zfs_range_lock(&zv->zv_znode, offset, size, RL_READER);
 
 	/*
 	 * Write records come in two flavors: immediate and indirect.
@@ -1012,12 +1011,22 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, st
 	 * 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) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201709220823.v8M8NORB026425>