diff options
author | Tom Caputi <tcaputi@datto.com> | 2019-09-12 09:24:01 -0600 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-09-12 09:24:01 -0600 |
commit | 8bf394f116a79c011b8f9f3bd199e09b363742ef (patch) | |
tree | d4af1239b5f2ebb6537d08eea4e75d05d97d4ef2 | |
parent | 0237b6992139d8334d00225b8f228740703fbbdd (diff) | |
download | illumos-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.mf | 2 | ||||
-rw-r--r-- | usr/src/test/zfs-tests/runfiles/delphix.run | 3 | ||||
-rw-r--r-- | usr/src/test/zfs-tests/runfiles/omnios.run | 3 | ||||
-rw-r--r-- | usr/src/test/zfs-tests/runfiles/openindiana.run | 3 | ||||
-rw-r--r-- | usr/src/test/zfs-tests/runfiles/smartos.run | 3 | ||||
-rwxr-xr-x | usr/src/test/zfs-tests/tests/functional/upgrade/upgrade_readonly_pool.ksh | 68 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/dmu_objset.c | 6 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ioctl.c | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vfsops.c | 9 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zvol.c | 18 |
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; } |