]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Add options to zfs redundant_metadata property
authorAkash B <akash-b@hpe.com>
Thu, 20 Oct 2022 00:07:51 +0000 (05:37 +0530)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 1 Nov 2022 19:25:58 +0000 (12:25 -0700)
Currently, additional/extra copies are created for metadata in
addition to the redundancy provided by the pool(mirror/raidz/draid),
due to this 2 times more space is utilized per inode and this decreases
the total number of inodes that can be created in the filesystem. By
setting redundant_metadata to none, no additional copies of metadata
are created, hence can reduce the space consumed by the additional
metadata copies and increase the total number of inodes that can be
created in the filesystem.  Additionally, this can improve file create
performance due to the reduced amount of metadata which needs
to be written.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Dipak Ghosh <dipak.ghosh@hpe.com>
Signed-off-by: Akash B <akash-b@hpe.com>
Closes #13680

include/sys/dmu.h
include/sys/fs/zfs.h
man/man7/zfsprops.7
module/zcommon/zfs_prop.c
module/zfs/dmu.c
module/zfs/dmu_objset.c
module/zfs/dsl_prop.c
tests/zfs-tests/include/properties.shlib
tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh

index 070d27fde3a904676a79156e3ec4614bad8a3631..7bdd42e8bed4edc2ea347071faa289a91d019dcd 100644 (file)
@@ -27,6 +27,7 @@
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  * Copyright 2013 Saso Kiselkov. All rights reserved.
  * Copyright (c) 2017, Intel Corporation.
+ * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -142,6 +143,12 @@ typedef enum dmu_object_byteswap {
 #define        DMU_OT_IS_DDT(ot) \
        ((ot) == DMU_OT_DDT_ZAP)
 
+#define        DMU_OT_IS_CRITICAL(ot) \
+       (DMU_OT_IS_METADATA(ot) && \
+       (ot) != DMU_OT_DNODE && \
+       (ot) != DMU_OT_DIRECTORY_CONTENTS && \
+       (ot) != DMU_OT_SA)
+
 /* Note: ztest uses DMU_OT_UINT64_OTHER as a proxy for file blocks */
 #define        DMU_OT_IS_FILE(ot) \
        ((ot) == DMU_OT_PLAIN_FILE_CONTENTS || (ot) == DMU_OT_UINT64_OTHER)
index df1cc060130a52dd83e45c4eb50c88726c9beb72..f4dc2ab465364579123c9f3b259ef92a1e020772 100644 (file)
@@ -29,6 +29,7 @@
  * Copyright (c) 2019 Datto Inc.
  * Portions Copyright 2010 Robert Milkowski
  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
+ * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
  */
 
 #ifndef        _SYS_FS_ZFS_H
@@ -423,7 +424,9 @@ typedef enum {
 
 typedef enum {
        ZFS_REDUNDANT_METADATA_ALL,
-       ZFS_REDUNDANT_METADATA_MOST
+       ZFS_REDUNDANT_METADATA_MOST,
+       ZFS_REDUNDANT_METADATA_SOME,
+       ZFS_REDUNDANT_METADATA_NONE
 } zfs_redundant_metadata_type_t;
 
 typedef enum {
index b753ec321ad030e9f733b86be9d6211d7de2907b..1e2ca409f9cac3cc90ce8eda27bae1e60c7dbeec 100644 (file)
@@ -36,8 +36,9 @@
 .\" Copyright 2018 Nexenta Systems, Inc.
 .\" Copyright 2019 Joyent, Inc.
 .\" Copyright (c) 2019, Kjeld Schouten-Lebbing
+.\" Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
 .\"
-.Dd May 24, 2021
+.Dd July 21, 2022
 .Dt ZFSPROPS 7
 .Os
 .
@@ -1445,7 +1446,7 @@ affects only files created afterward; existing files are unaffected.
 .Pp
 This property can also be referred to by its shortened column name,
 .Sy recsize .
-.It Sy redundant_metadata Ns = Ns Sy all Ns | Ns Sy most
+.It Sy redundant_metadata Ns = Ns Sy all Ns | Ns Sy most Ns | Ns Sy some Ns | Ns Sy none
 Controls what types of metadata are stored redundantly.
 ZFS stores an extra copy of metadata, so that if a single block is corrupted,
 the amount of user data lost is limited.
@@ -1477,7 +1478,7 @@ When set to
 ZFS stores an extra copy of most types of metadata.
 This can improve performance of random writes, because less metadata must be
 written.
-In practice, at worst about 100 blocks
+In practice, at worst about 1000 blocks
 .Po of
 .Sy recordsize
 bytes each
@@ -1486,6 +1487,17 @@ of user data can be lost if a single on-disk block is corrupt.
 The exact behavior of which metadata blocks are stored redundantly may change in
 future releases.
 .Pp
+When set to
+.Sy some ,
+ZFS stores an extra copy of only critical metadata.
+This can improve file create performance since less metadata needs to be written.
+If a single on-disk block is corrupt, at worst a single user file can be lost.
+.Pp
+When set to
+.Sy none ,
+ZFS does not store any copies of metadata redundantly.
+If a single on-disk block is corrupt, an entire dataset can be lost.
+.Pp
 The default value is
 .Sy all .
 .It Sy refquota Ns = Ns Ar size Ns | Ns Sy none
index 5f88bd02089dc674c25e93dd410cd90a4c068bec..a33eb36ac19232412ca6af7f6d945e5f8c070764 100644 (file)
@@ -25,6 +25,7 @@
  * Copyright 2016, Joyent, Inc.
  * Copyright (c) 2019, Klara Inc.
  * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -371,6 +372,8 @@ zfs_prop_init(void)
        static zprop_index_t redundant_metadata_table[] = {
                { "all",        ZFS_REDUNDANT_METADATA_ALL },
                { "most",       ZFS_REDUNDANT_METADATA_MOST },
+               { "some",       ZFS_REDUNDANT_METADATA_SOME },
+               { "none",       ZFS_REDUNDANT_METADATA_NONE },
                { NULL }
        };
 
@@ -387,7 +390,7 @@ zfs_prop_init(void)
        zprop_register_index(ZFS_PROP_REDUNDANT_METADATA, "redundant_metadata",
            ZFS_REDUNDANT_METADATA_ALL,
            PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-           "all | most", "REDUND_MD",
+           "all | most | some | none", "REDUND_MD",
            redundant_metadata_table);
        zprop_register_index(ZFS_PROP_SYNC, "sync", ZFS_SYNC_STANDARD,
            PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
index e38c9b452a284e3ddfa97c385c196ac5cba13962..0832fbcfdf40848fd49794485ebe721fc6a51f0c 100644 (file)
@@ -28,6 +28,7 @@
  * Copyright (c) 2019 Datto Inc.
  * Copyright (c) 2019, Klara Inc.
  * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
  */
 
 #include <sys/dmu.h>
@@ -1988,12 +1989,22 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp)
                    ZCHECKSUM_FLAG_EMBEDDED))
                        checksum = ZIO_CHECKSUM_FLETCHER_4;
 
-               if (os->os_redundant_metadata == ZFS_REDUNDANT_METADATA_ALL ||
-                   (os->os_redundant_metadata ==
-                   ZFS_REDUNDANT_METADATA_MOST &&
-                   (level >= zfs_redundant_metadata_most_ditto_level ||
-                   DMU_OT_IS_METADATA(type) || (wp & WP_SPILL))))
+               switch (os->os_redundant_metadata) {
+               case ZFS_REDUNDANT_METADATA_ALL:
                        copies++;
+                       break;
+               case ZFS_REDUNDANT_METADATA_MOST:
+                       if (level >= zfs_redundant_metadata_most_ditto_level ||
+                           DMU_OT_IS_METADATA(type) || (wp & WP_SPILL))
+                               copies++;
+                       break;
+               case ZFS_REDUNDANT_METADATA_SOME:
+                       if (DMU_OT_IS_CRITICAL(type))
+                               copies++;
+                       break;
+               case ZFS_REDUNDANT_METADATA_NONE:
+                       break;
+               }
        } else if (wp & WP_NOFILL) {
                ASSERT(level == 0);
 
index a8975797e8af3304f7f6523c3719a665191eb2de..5ad3b2f269d65d5a1c68b28beaf41b31c87cdb8c 100644 (file)
@@ -32,6 +32,7 @@
  * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
  * Copyright (c) 2019, Klara Inc.
  * Copyright (c) 2019, Allan Jude
+ * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -287,7 +288,9 @@ redundant_metadata_changed_cb(void *arg, uint64_t newval)
         * Inheritance and range checking should have been done by now.
         */
        ASSERT(newval == ZFS_REDUNDANT_METADATA_ALL ||
-           newval == ZFS_REDUNDANT_METADATA_MOST);
+           newval == ZFS_REDUNDANT_METADATA_MOST ||
+           newval == ZFS_REDUNDANT_METADATA_SOME ||
+           newval == ZFS_REDUNDANT_METADATA_NONE);
 
        os->os_redundant_metadata = newval;
 }
index 0089edf8683affde2f1f4babaac8797648709230..d1c3ff543661e3e18ed78d1170712190542a3500 100644 (file)
@@ -23,6 +23,7 @@
  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Martin Matuska. All rights reserved.
  * Copyright 2019 Joyent, Inc.
+ * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
  */
 
 #include <sys/zfs_context.h>
@@ -41,6 +42,7 @@
 
 #define        ZPROP_INHERIT_SUFFIX "$inherit"
 #define        ZPROP_RECVD_SUFFIX "$recvd"
+#define        ZPROP_IUV_SUFFIX "$iuv"
 
 static int
 dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
@@ -69,6 +71,16 @@ dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
        return (0);
 }
 
+static int
+dsl_prop_known_index(zfs_prop_t prop, uint64_t value)
+{
+       const char *str = NULL;
+       if (zfs_prop_get_type(prop) == PROP_TYPE_INDEX)
+               return (!zfs_prop_index_to_string(prop, value, &str));
+
+       return (-1);
+}
+
 int
 dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
     int intsz, int numints, void *buf, char *setpoint, boolean_t snapshot)
@@ -81,6 +93,7 @@ dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
        boolean_t inheriting = B_FALSE;
        char *inheritstr;
        char *recvdstr;
+       char *iuvstr;
 
        ASSERT(dsl_pool_config_held(dd->dd_pool));
 
@@ -91,6 +104,7 @@ dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
        inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
        inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
        recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
+       iuvstr = kmem_asprintf("%s%s", propname, ZPROP_IUV_SUFFIX);
 
        /*
         * Note: dd may become NULL, therefore we shouldn't dereference it
@@ -105,6 +119,18 @@ dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
                        inheriting = B_TRUE;
                }
 
+               /* Check for a iuv value. */
+               err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
+                   iuvstr, intsz, numints, buf);
+               if (dsl_prop_known_index(zfs_name_to_prop(propname),
+                   *(uint64_t *)buf) != 1)
+                       err = ENOENT;
+               if (err != ENOENT) {
+                       if (setpoint != NULL && err == 0)
+                               dsl_dir_name(dd, setpoint);
+                       break;
+               }
+
                /* Check for a local value. */
                err = zap_lookup(mos, dsl_dir_phys(dd)->dd_props_zapobj,
                    propname, intsz, numints, buf);
@@ -155,6 +181,7 @@ dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
 
        kmem_strfree(inheritstr);
        kmem_strfree(recvdstr);
+       kmem_strfree(iuvstr);
 
        return (err);
 }
@@ -647,6 +674,45 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
        dsl_dir_rele(dd, FTAG);
 }
 
+
+/*
+ * For newer values in zfs index type properties, we add a new key
+ * propname$iuv (iuv = Ignore Unknown Values) to the properties zap object
+ * to store the new property value and store the default value in the
+ * existing prop key. So that the propname$iuv key is ignored by the older zfs
+ * versions and the default property value from the existing prop key is
+ * used.
+ */
+static void
+dsl_prop_set_iuv(objset_t *mos, uint64_t zapobj, const char *propname,
+    int intsz, int numints, const void *value, dmu_tx_t *tx)
+{
+       char *iuvstr = kmem_asprintf("%s%s", propname, ZPROP_IUV_SUFFIX);
+       boolean_t iuv = B_FALSE;
+       zfs_prop_t prop = zfs_name_to_prop(propname);
+
+       switch (prop) {
+       case ZFS_PROP_REDUNDANT_METADATA:
+               if (*(uint64_t *)value == ZFS_REDUNDANT_METADATA_SOME ||
+                   *(uint64_t *)value == ZFS_REDUNDANT_METADATA_NONE)
+                       iuv = B_TRUE;
+               break;
+       default:
+               break;
+       }
+
+       if (iuv) {
+               VERIFY0(zap_update(mos, zapobj, iuvstr, intsz, numints,
+                   value, tx));
+               uint64_t val = zfs_prop_default_numeric(prop);
+               VERIFY0(zap_update(mos, zapobj, propname, intsz, numints,
+                   &val, tx));
+       } else {
+               zap_remove(mos, zapobj, iuvstr, tx);
+       }
+       kmem_strfree(iuvstr);
+}
+
 void
 dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
     zprop_source_t source, int intsz, int numints, const void *value,
@@ -659,6 +725,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
        const char *valstr = NULL;
        char *inheritstr;
        char *recvdstr;
+       char *iuvstr;
        char *tbuf = NULL;
        int err;
        uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
@@ -692,6 +759,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 
        inheritstr = kmem_asprintf("%s%s", propname, ZPROP_INHERIT_SUFFIX);
        recvdstr = kmem_asprintf("%s%s", propname, ZPROP_RECVD_SUFFIX);
+       iuvstr = kmem_asprintf("%s%s", propname, ZPROP_IUV_SUFFIX);
 
        switch ((int)source) {
        case ZPROP_SRC_NONE:
@@ -709,11 +777,14 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
                /*
                 * remove propname$inherit
                 * set propname -> value
+                * set propname$iuv -> new property value
                 */
                err = zap_remove(mos, zapobj, inheritstr, tx);
                ASSERT(err == 0 || err == ENOENT);
                VERIFY0(zap_update(mos, zapobj, propname,
                    intsz, numints, value, tx));
+               (void) dsl_prop_set_iuv(mos, zapobj, propname, intsz,
+                   numints, value, tx);
                break;
        case ZPROP_SRC_INHERITED:
                /*
@@ -723,6 +794,8 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
                 */
                err = zap_remove(mos, zapobj, propname, tx);
                ASSERT(err == 0 || err == ENOENT);
+               err = zap_remove(mos, zapobj, iuvstr, tx);
+               ASSERT(err == 0 || err == ENOENT);
                if (version >= SPA_VERSION_RECVD_PROPS &&
                    dsl_prop_get_int_ds(ds, ZPROP_HAS_RECVD, &dummy) == 0) {
                        dummy = 0;
@@ -763,6 +836,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
 
        kmem_strfree(inheritstr);
        kmem_strfree(recvdstr);
+       kmem_strfree(iuvstr);
 
        /*
         * If we are left with an empty snap zap we can destroy it.
@@ -1012,6 +1086,14 @@ dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
 
                        propname = za.za_name;
                        source = setpoint;
+
+                       /* Skip if iuv entries are preset. */
+                       valstr = kmem_asprintf("%s%s", propname,
+                           ZPROP_IUV_SUFFIX);
+                       err = zap_contains(mos, propobj, valstr);
+                       kmem_strfree(valstr);
+                       if (err == 0)
+                               continue;
                } else if (strcmp(suffix, ZPROP_INHERIT_SUFFIX) == 0) {
                        /* Skip explicitly inherited entries. */
                        continue;
@@ -1044,6 +1126,16 @@ dsl_prop_get_all_impl(objset_t *mos, uint64_t propobj,
 
                        source = ((flags & DSL_PROP_GET_INHERITING) ?
                            setpoint : ZPROP_SOURCE_VAL_RECVD);
+               } else if (strcmp(suffix, ZPROP_IUV_SUFFIX) == 0) {
+                       (void) strlcpy(buf, za.za_name,
+                           MIN(sizeof (buf), suffix - za.za_name + 1));
+                       propname = buf;
+                       source = setpoint;
+                       prop = zfs_name_to_prop(propname);
+
+                       if (dsl_prop_known_index(prop,
+                           za.za_first_integer) != 1)
+                               continue;
                } else {
                        /*
                         * For backward compatibility, skip suffixes we don't
index 6d467b60051d706894df1851d9c36e58aedb9c2d..dcf3ab7ae455acbf23bb9fb40b32e2dba370ddaa 100644 (file)
@@ -11,6 +11,7 @@
 
 #
 # Copyright (c) 2012, 2016, Delphix. All rights reserved.
+# Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
 #
 
 . $STF_SUITE/include/libtest.shlib
@@ -27,7 +28,7 @@ typeset -a canmount_prop_vals=('on' 'off' 'noauto')
 typeset -a copies_prop_vals=('1' '2' '3')
 typeset -a logbias_prop_vals=('latency' 'throughput')
 typeset -a primarycache_prop_vals=('all' 'none' 'metadata')
-typeset -a redundant_metadata_prop_vals=('all' 'most')
+typeset -a redundant_metadata_prop_vals=('all' 'most' 'some' 'none')
 typeset -a secondarycache_prop_vals=('all' 'none' 'metadata')
 typeset -a snapdir_prop_vals=('hidden' 'visible')
 typeset -a sync_prop_vals=('standard' 'always' 'disabled')
index 7c5b81287736649dfe9c87458a574c147520b99d..5a5be3bd9bee0977800874d7bedaf34afe9abcd3 100755 (executable)
@@ -26,6 +26,7 @@
 
 #
 # Copyright (c) 2013, 2016 by Delphix. All rights reserved.
+# Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
 #
 
 . $STF_SUITE/include/libtest.shlib
@@ -380,7 +381,8 @@ set -A prop "checksum" "" \
        "sharenfs" "" \
        "recordsize" "recsize" \
        "snapdir" "" \
-       "readonly" ""
+       "readonly" "" \
+       "redundant_metadata" ""
 
 #
 # Note except for the mountpoint default value (which is handled in
@@ -391,12 +393,14 @@ set -A prop "checksum" "" \
 set -A def_val "on" "off" "on" \
        "off" "" \
        "hidden" \
-       "off"
+       "off" \
+       "all"
 
 set -A local_val "off" "on" "off" \
        "on" "" \
        "visible" \
-       "off"
+       "off" \
+       "none"
 
 #
 # Add system specific values