summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Caputi <tcaputi@datto.com>2019-09-12 09:24:01 -0600
committerJerry Jelinek <jerry.jelinek@joyent.com>2019-09-12 09:24:01 -0600
commit8bf394f116a79c011b8f9f3bd199e09b363742ef (patch)
treed4af1239b5f2ebb6537d08eea4e75d05d97d4ef2
parent0237b6992139d8334d00225b8f228740703fbbdd (diff)
downloadillumos-joyent-8bf394f116a79c011b8f9f3bd199e09b363742ef.tar.gz
11650 ZFS user accounting fixes
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com> Portions contributed by: loli10K <ezomori.nozomu@gmail.com> Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed by: Alek Pinchuk <apinchuk@datto.com> Reviewed by: Igor Kozhukhov <igor@dilos.org> Reviewed by: Toomas Soome <tsoome@me.com> Reviewed by: Kody Kantor <kody.kantor@joyent.com> Approved by: Gordon Ross <gwr@nexenta.com>
-rw-r--r--usr/src/pkg/manifests/system-test-zfstest.mf2
-rw-r--r--usr/src/test/zfs-tests/runfiles/delphix.run3
-rw-r--r--usr/src/test/zfs-tests/runfiles/omnios.run3
-rw-r--r--usr/src/test/zfs-tests/runfiles/openindiana.run3
-rw-r--r--usr/src/test/zfs-tests/runfiles/smartos.run3
-rwxr-xr-xusr/src/test/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh68
-rw-r--r--usr/src/uts/common/fs/zfs/dmu_objset.c6
-rw-r--r--usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h2
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_ioctl.c2
-rw-r--r--usr/src/uts/common/fs/zfs/zfs_vfsops.c9
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c18
11 files changed, 97 insertions, 22 deletions
diff --git a/usr/src/pkg/manifests/system-test-zfstest.mf b/usr/src/pkg/manifests/system-test-zfstest.mf
index 3995d51adf..c05056e8b8 100644
--- a/usr/src/pkg/manifests/system-test-zfstest.mf
+++ b/usr/src/pkg/manifests/system-test-zfstest.mf
@@ -3048,6 +3048,8 @@ file path=opt/zfs-tests/tests/functional/upgrade/upgrade_common.kshlib \
mode=0444
file path=opt/zfs-tests/tests/functional/upgrade/upgrade_projectquota_001_pos \
mode=0555
+file path=opt/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool \
+ mode=0555
file path=opt/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/userquota/cleanup mode=0555
diff --git a/usr/src/test/zfs-tests/runfiles/delphix.run b/usr/src/test/zfs-tests/runfiles/delphix.run
index 8cdef49176..04e1714670 100644
--- a/usr/src/test/zfs-tests/runfiles/delphix.run
+++ b/usr/src/test/zfs-tests/runfiles/delphix.run
@@ -672,7 +672,8 @@ tags = ['functional', 'trim']
tests = ['truncate_001_pos', 'truncate_002_pos']
[/opt/zfs-tests/tests/functional/upgrade]
-tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos']
+tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos',
+ 'upgrade_readonly_pool']
[/opt/zfs-tests/tests/functional/userquota]
tests = [
diff --git a/usr/src/test/zfs-tests/runfiles/omnios.run b/usr/src/test/zfs-tests/runfiles/omnios.run
index 889a684635..a87db9a511 100644
--- a/usr/src/test/zfs-tests/runfiles/omnios.run
+++ b/usr/src/test/zfs-tests/runfiles/omnios.run
@@ -671,7 +671,8 @@ tags = ['functional', 'trim']
tests = ['truncate_001_pos', 'truncate_002_pos']
[/opt/zfs-tests/tests/functional/upgrade]
-tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos']
+tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos',
+ 'upgrade_readonly_pool']
[/opt/zfs-tests/tests/functional/userquota]
tests = [
diff --git a/usr/src/test/zfs-tests/runfiles/openindiana.run b/usr/src/test/zfs-tests/runfiles/openindiana.run
index 4a3b1bf950..6afcb0273b 100644
--- a/usr/src/test/zfs-tests/runfiles/openindiana.run
+++ b/usr/src/test/zfs-tests/runfiles/openindiana.run
@@ -671,7 +671,8 @@ tags = ['functional', 'trim']
tests = ['truncate_001_pos', 'truncate_002_pos']
[/opt/zfs-tests/tests/functional/upgrade]
-tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos']
+tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos',
+ 'upgrade_readonly_pool']
[/opt/zfs-tests/tests/functional/userquota]
tests = [
diff --git a/usr/src/test/zfs-tests/runfiles/smartos.run b/usr/src/test/zfs-tests/runfiles/smartos.run
index f4ed41fc55..e6020494b3 100644
--- a/usr/src/test/zfs-tests/runfiles/smartos.run
+++ b/usr/src/test/zfs-tests/runfiles/smartos.run
@@ -581,7 +581,8 @@ tags = ['functional', 'trim']
tests = ['truncate_001_pos', 'truncate_002_pos']
[/opt/zfs-tests/tests/functional/upgrade]
-tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos']
+tests = ['upgrade_userobj_001_pos', 'upgrade_projectquota_001_pos',
+ 'upgrade_readonly_pool']
[/opt/zfs-tests/tests/functional/userquota]
tests = [
diff --git a/usr/src/test/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh b/usr/src/test/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh
new file mode 100755
index 0000000000..45ec3a932a
--- /dev/null
+++ b/usr/src/test/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh
@@ -0,0 +1,68 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2019, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
+# Copyright 2019 Joyent, Inc.
+#
+
+. $STF_SUITE/tests/functional/upgrade/upgrade_common.kshlib
+
+#
+# DESCRIPTION:
+# User accounting upgrade should not be executed on readonly pool
+#
+# STRATEGY:
+# 1. Create a pool with the feature@userobj_accounting disabled to simulate
+# a legacy pool from a previous ZFS version.
+# 2. Create a file on the "legecy" dataset and store its checksum
+# 3. Enable feature@userobj_accounting on the pool and verify it is only
+# "enabled" and not "active": upgrading starts when the filesystem is mounted
+# 4. Export the pool and re-import is readonly, without mounting any filesystem
+# 5. Try to mount the root dataset manually without the "ro" option, then verify
+# filesystem status and the pool feature status (not "active") to ensure the
+# pool "readonly" status is enforced.
+#
+
+verify_runnable "global"
+
+TESTFILE="$TESTDIR/file.bin"
+
+log_assert "User accounting upgrade should not be executed on readonly pool"
+log_onexit cleanup_upgrade
+
+# 1. Create a pool with the feature@userobj_accounting disabled to simulate
+# a legacy pool from a previous ZFS version.
+log_must zpool create -d -m $TESTDIR $TESTPOOL $TMPDEV
+
+# 2. Create a file on the "legecy" dataset
+log_must touch $TESTDIR/file.bin
+
+# 3. Enable feature@userobj_accounting on the pool and verify it is only
+# "enabled" and not "active": upgrading starts when the filesystem is mounted
+log_must zpool set feature@userobj_accounting=enabled $TESTPOOL
+log_must test "enabled" == "$(get_pool_prop 'feature@userobj_accounting' $TESTPOOL)"
+
+# 4. Export the pool and re-import is readonly, without mounting any filesystem
+log_must zfs set mountpoint=legacy $TESTPOOL
+log_must zpool export $TESTPOOL
+log_must zpool import -o readonly=on -N -d "$(dirname $TMPDEV)" $TESTPOOL
+
+# 5. Try to mount the root dataset manually without the "ro" option, then verify
+# filesystem status and the pool feature status (not "active") to ensure the
+# pool "readonly" status is enforced.
+log_must mount -F zfs -o zfsutil $TESTPOOL $TESTDIR
+log_must stat "$TESTFILE"
+log_mustnot touch "$TESTFILE"
+log_must test "enabled" == "$(get_pool_prop 'feature@userobj_accounting' $TESTPOOL)"
+
+log_pass "User accounting upgrade is not executed on readonly pool"
diff --git a/usr/src/uts/common/fs/zfs/dmu_objset.c b/usr/src/uts/common/fs/zfs/dmu_objset.c
index 3e11d73cad..fb75ef3630 100644
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c
@@ -2051,6 +2051,9 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
if (os->os_encrypted && dmu_objset_is_receiving(os))
return;
+ if (tx->tx_txg <= os->os_spa->spa_claim_max_txg)
+ return;
+
/* Allocate the user/group/project used objects if necessary. */
if (DMU_USERUSED_DNODE(os)->dn_type == DMU_OT_NONE) {
VERIFY0(zap_create_claim(os,
@@ -2390,7 +2393,8 @@ dmu_objset_projectquota_upgradable(objset_t *os)
return (dmu_objset_type(os) == DMU_OST_ZFS &&
!dmu_objset_is_snapshot(os) &&
dmu_objset_projectquota_enabled(os) &&
- !dmu_objset_projectquota_present(os));
+ !dmu_objset_projectquota_present(os) &&
+ spa_writeable(dmu_objset_spa(os)));
}
void
diff --git a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
index 13be805ccd..199c8446ca 100644
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
@@ -155,7 +155,7 @@ extern boolean_t zfs_id_overobjquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
extern boolean_t zfs_id_overquota(zfsvfs_t *zfsvfs, uint64_t usedobj,
uint64_t id);
extern int zfs_set_version(zfsvfs_t *zfsvfs, uint64_t newvers);
-extern int zfsvfs_create(const char *name, zfsvfs_t **zfvp);
+extern int zfsvfs_create(const char *name, boolean_t readony, zfsvfs_t **zfvp);
extern int zfsvfs_create_impl(zfsvfs_t **zfvp, zfsvfs_t *zfsvfs, objset_t *os);
extern void zfsvfs_free(zfsvfs_t *zfsvfs);
extern int zfs_check_global_label(const char *dsname, const char *hexsl);
diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
index 821a923fea..13d3d56ed7 100644
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c
@@ -1490,7 +1490,7 @@ zfsvfs_hold(const char *name, void *tag, zfsvfs_t **zfvp, boolean_t writer)
int error = 0;
if (getzfsvfs(name, zfvp) != 0)
- error = zfsvfs_create(name, zfvp);
+ error = zfsvfs_create(name, B_FALSE, zfvp);
if (error == 0) {
rrm_enter(&(*zfvp)->z_teardown_lock, (writer) ? RW_WRITER :
RW_READER, tag);
diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
index 93339107c1..aad3855d98 100644
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c
@@ -1152,12 +1152,12 @@ zfsvfs_init(zfsvfs_t *zfsvfs, objset_t *os)
}
int
-zfsvfs_create(const char *osname, zfsvfs_t **zfvp)
+zfsvfs_create(const char *osname, boolean_t readonly, zfsvfs_t **zfvp)
{
objset_t *os;
zfsvfs_t *zfsvfs;
int error;
- boolean_t ro = (strchr(osname, '@') != NULL);
+ boolean_t ro = (readonly || (strchr(osname, '@') != NULL));
zfsvfs = kmem_zalloc(sizeof (zfsvfs_t), KM_SLEEP);
@@ -1345,11 +1345,12 @@ zfs_domount(vfs_t *vfsp, char *osname)
uint64_t recordsize, fsid_guid;
int error = 0;
zfsvfs_t *zfsvfs;
+ boolean_t readonly = vfsp->vfs_flag & VFS_RDONLY ? B_TRUE : B_FALSE;
ASSERT(vfsp);
ASSERT(osname);
- error = zfsvfs_create(osname, &zfsvfs);
+ error = zfsvfs_create(osname, readonly, &zfsvfs);
if (error)
return (error);
zfsvfs->z_vfs = vfsp;
@@ -2216,7 +2217,7 @@ zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
uint64_t fid_gen = 0;
uint64_t gen_mask;
uint64_t zp_gen;
- int i, err;
+ int i, err;
*vpp = NULL;
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index b61e000f9c..276cf84e0c 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -626,16 +626,16 @@ zvol_remove_minor(const char *name)
}
int
-zvol_first_open(zvol_state_t *zv)
+zvol_first_open(zvol_state_t *zv, boolean_t rdonly)
{
objset_t *os;
uint64_t volsize;
int error;
uint64_t readonly;
+ boolean_t ro;
- /* lie and say we're read-only */
- error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, B_TRUE, B_TRUE,
- zvol_tag, &os);
+ ro = (rdonly || (strchr(zv->zv_name, '@') != NULL));
+ error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, ro, B_TRUE, zv, &os);
if (error)
return (error);
@@ -901,17 +901,13 @@ zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr)
}
if (zv->zv_total_opens == 0)
- err = zvol_first_open(zv);
+ err = zvol_first_open(zv, !(flag & FWRITE));
if (err) {
mutex_exit(&zfsdev_state_lock);
return (err);
}
- /*
- * Check for a bad on-disk format version now since we
- * lied about owning the dataset readonly before.
- */
- if ((flag & FWRITE) && ((zv->zv_flags & ZVOL_RDONLY) ||
- dmu_objset_incompatible_encryption_version(zv->zv_objset))) {
+
+ if ((flag & FWRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
err = SET_ERROR(EROFS);
goto out;
}