]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Add ashift validation when adding devices to a pool
authorGeorge Wilson <george.wilson@delphix.com>
Fri, 29 Mar 2024 19:15:56 +0000 (15:15 -0400)
committerGitHub <noreply@github.com>
Fri, 29 Mar 2024 19:15:56 +0000 (13:15 -0600)
Currently, zpool add allows users to add top-level vdevs that have
different ashifts but doing so prevents users from being able to
perform a top-level vdev removal. Often times consumers may not realize
that they have mismatched ashifts until the top-level removal fails.

This feature adds ashift validation to the zpool add command and will
fail the operation if the sector size of the specified vdev does not
match the existing pool. This behavior can be disabled by using the -f
flag. In addition, new flags have been added to provide fine-grained
control to disable specific checks. These flags
are:

--allow-in-use
--allow-ashift-mismatch
--allow-replicaton-mismatch

The force flag will disable all of these checks.

Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Mark Maybee <mmaybee@delphix.com>
Signed-off-by: George Wilson <gwilson@delphix.com>
Closes #15509

21 files changed:
cmd/zpool/zpool_main.c
cmd/ztest.c
include/libzfs.h
include/sys/fs/zfs.h
include/sys/spa.h
lib/libzfs/libzfs.abi
lib/libzfs/libzfs_pool.c
lib/libzfs/libzfs_util.c
man/man8/zpool-add.8
module/zfs/spa.c
module/zfs/zfs_ioctl.c
tests/runfiles/common.run
tests/zfs-tests/tests/Makefile.am
tests/zfs-tests/tests/functional/cli_root/zpool_add/add-o_ashift.ksh
tests/zfs-tests/tests/functional/cli_root/zpool_add/add_prop_ashift.ksh
tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add--allow-ashift-mismatch.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_002_pos.ksh
tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh
tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_005_pos.ksh
tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_009_neg.ksh
tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_010_pos.ksh

index 987d4406286572368a50cc7c6977f02a32d447b4..c85a5f285154d217b4982954f71b59fed4fbe374 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
  * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
  * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
@@ -131,6 +131,13 @@ static int zpool_do_help(int argc, char **argv);
 static zpool_compat_status_t zpool_do_load_compat(
     const char *, boolean_t *);
 
+enum zpool_options {
+       ZPOOL_OPTION_POWER = 1024,
+       ZPOOL_OPTION_ALLOW_INUSE,
+       ZPOOL_OPTION_ALLOW_REPLICATION_MISMATCH,
+       ZPOOL_OPTION_ALLOW_ASHIFT_MISMATCH
+};
+
 /*
  * These libumem hooks provide a reasonable set of defaults for the allocator's
  * debugging facilities.
@@ -347,7 +354,7 @@ get_usage(zpool_help_t idx)
 {
        switch (idx) {
        case HELP_ADD:
-               return (gettext("\tadd [-fgLnP] [-o property=value] "
+               return (gettext("\tadd [-afgLnP] [-o property=value] "
                    "<pool> <vdev> ...\n"));
        case HELP_ATTACH:
                return (gettext("\tattach [-fsw] [-o property=value] "
@@ -1009,8 +1016,9 @@ add_prop_list_default(const char *propname, const char *propval,
 }
 
 /*
- * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
+ * zpool add [-afgLnP] [-o property=value] <pool> <vdev> ...
  *
+ *     -a      Disable the ashift validation checks
  *     -f      Force addition of devices, even if they appear in use
  *     -g      Display guid for individual vdev name.
  *     -L      Follow links when resolving vdev path name.
@@ -1026,8 +1034,11 @@ add_prop_list_default(const char *propname, const char *propval,
 int
 zpool_do_add(int argc, char **argv)
 {
-       boolean_t force = B_FALSE;
+       boolean_t check_replication = B_TRUE;
+       boolean_t check_inuse = B_TRUE;
        boolean_t dryrun = B_FALSE;
+       boolean_t check_ashift = B_TRUE;
+       boolean_t force = B_FALSE;
        int name_flags = 0;
        int c;
        nvlist_t *nvroot;
@@ -1038,8 +1049,18 @@ zpool_do_add(int argc, char **argv)
        nvlist_t *props = NULL;
        char *propval;
 
+       struct option long_options[] = {
+               {"allow-in-use", no_argument, NULL, ZPOOL_OPTION_ALLOW_INUSE},
+               {"allow-replication-mismatch", no_argument, NULL,
+                   ZPOOL_OPTION_ALLOW_REPLICATION_MISMATCH},
+               {"allow-ashift-mismatch", no_argument, NULL,
+                   ZPOOL_OPTION_ALLOW_ASHIFT_MISMATCH},
+               {0, 0, 0, 0}
+       };
+
        /* check options */
-       while ((c = getopt(argc, argv, "fgLno:P")) != -1) {
+       while ((c = getopt_long(argc, argv, "fgLno:P", long_options, NULL))
+           != -1) {
                switch (c) {
                case 'f':
                        force = B_TRUE;
@@ -1069,6 +1090,15 @@ zpool_do_add(int argc, char **argv)
                case 'P':
                        name_flags |= VDEV_NAME_PATH;
                        break;
+               case ZPOOL_OPTION_ALLOW_INUSE:
+                       check_inuse = B_FALSE;
+                       break;
+               case ZPOOL_OPTION_ALLOW_REPLICATION_MISMATCH:
+                       check_replication = B_FALSE;
+                       break;
+               case ZPOOL_OPTION_ALLOW_ASHIFT_MISMATCH:
+                       check_ashift = B_FALSE;
+                       break;
                case '?':
                        (void) fprintf(stderr, gettext("invalid option '%c'\n"),
                            optopt);
@@ -1089,6 +1119,19 @@ zpool_do_add(int argc, char **argv)
                usage(B_FALSE);
        }
 
+       if (force) {
+               if (!check_inuse || !check_replication || !check_ashift) {
+                       (void) fprintf(stderr, gettext("'-f' option is not "
+                           "allowed with '--allow-replication-mismatch', "
+                           "'--allow-ashift-mismatch', or "
+                           "'--allow-in-use'\n"));
+                       usage(B_FALSE);
+               }
+               check_inuse = B_FALSE;
+               check_replication = B_FALSE;
+               check_ashift = B_FALSE;
+       }
+
        poolname = argv[0];
 
        argc--;
@@ -1119,8 +1162,8 @@ zpool_do_add(int argc, char **argv)
        }
 
        /* pass off to make_root_vdev for processing */
-       nvroot = make_root_vdev(zhp, props, force, !force, B_FALSE, dryrun,
-           argc, argv);
+       nvroot = make_root_vdev(zhp, props, !check_inuse,
+           check_replication, B_FALSE, dryrun, argc, argv);
        if (nvroot == NULL) {
                zpool_close(zhp);
                return (1);
@@ -1224,7 +1267,7 @@ zpool_do_add(int argc, char **argv)
 
                ret = 0;
        } else {
-               ret = (zpool_add(zhp, nvroot) != 0);
+               ret = (zpool_add(zhp, nvroot, check_ashift) != 0);
        }
 
        nvlist_free(props);
@@ -7081,7 +7124,6 @@ zpool_do_split(int argc, char **argv)
        return (ret);
 }
 
-#define        POWER_OPT 1024
 
 /*
  * zpool online [--power] <pool> <device> ...
@@ -7099,7 +7141,7 @@ zpool_do_online(int argc, char **argv)
        int flags = 0;
        boolean_t is_power_on = B_FALSE;
        struct option long_options[] = {
-               {"power", no_argument, NULL, POWER_OPT},
+               {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
                {0, 0, 0, 0}
        };
 
@@ -7109,7 +7151,7 @@ zpool_do_online(int argc, char **argv)
                case 'e':
                        flags |= ZFS_ONLINE_EXPAND;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        is_power_on = B_TRUE;
                        break;
                case '?':
@@ -7222,7 +7264,7 @@ zpool_do_offline(int argc, char **argv)
        boolean_t is_power_off = B_FALSE;
 
        struct option long_options[] = {
-               {"power", no_argument, NULL, POWER_OPT},
+               {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
                {0, 0, 0, 0}
        };
 
@@ -7235,7 +7277,7 @@ zpool_do_offline(int argc, char **argv)
                case 't':
                        istmp = B_TRUE;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        is_power_off = B_TRUE;
                        break;
                case '?':
@@ -7335,7 +7377,7 @@ zpool_do_clear(int argc, char **argv)
        char *pool, *device;
 
        struct option long_options[] = {
-               {"power", no_argument, NULL, POWER_OPT},
+               {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
                {0, 0, 0, 0}
        };
 
@@ -7352,7 +7394,7 @@ zpool_do_clear(int argc, char **argv)
                case 'X':
                        xtreme_rewind = B_TRUE;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        is_power_on = B_TRUE;
                        break;
                case '?':
@@ -9208,7 +9250,7 @@ zpool_do_status(int argc, char **argv)
        char *cmd = NULL;
 
        struct option long_options[] = {
-               {"power", no_argument, NULL, POWER_OPT},
+               {"power", no_argument, NULL, ZPOOL_OPTION_POWER},
                {0, 0, 0, 0}
        };
 
@@ -9276,7 +9318,7 @@ zpool_do_status(int argc, char **argv)
                case 'x':
                        cb.cb_explain = B_TRUE;
                        break;
-               case POWER_OPT:
+               case ZPOOL_OPTION_POWER:
                        cb.cb_print_power = B_TRUE;
                        break;
                case '?':
index 1d414a9f6fd5ac8539ae409e4f9552b4da797ada..684ab586bb93469e23c0fa2998f4ac23cda0cd17 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2018 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
@@ -3375,7 +3375,7 @@ ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
                    "log" : NULL, raidz_children, zs->zs_mirrors,
                    1);
 
-               error = spa_vdev_add(spa, nvroot);
+               error = spa_vdev_add(spa, nvroot, B_FALSE);
                fnvlist_free(nvroot);
 
                switch (error) {
@@ -3438,7 +3438,7 @@ ztest_vdev_class_add(ztest_ds_t *zd, uint64_t id)
        nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
            class, raidz_children, zs->zs_mirrors, 1);
 
-       error = spa_vdev_add(spa, nvroot);
+       error = spa_vdev_add(spa, nvroot, B_FALSE);
        fnvlist_free(nvroot);
 
        if (error == ENOSPC)
@@ -3545,7 +3545,7 @@ ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id)
                 */
                nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL,
                    (ztest_opts.zo_vdev_size * 5) / 4, 0, NULL, 0, 0, 1);
-               error = spa_vdev_add(spa, nvroot);
+               error = spa_vdev_add(spa, nvroot, B_FALSE);
 
                switch (error) {
                case 0:
index 4f06b5d3c24cc148b5dbc2bc0ecbd657e986915c..2823b88458272f9d26aff1d466cef43419372661 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2022 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright Joyent, Inc.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2016, Intel Corporation.
@@ -158,6 +158,7 @@ typedef enum zfs_error {
        EZFS_RESUME_EXISTS,     /* Resume on existing dataset without force */
        EZFS_SHAREFAILED,       /* filesystem share failed */
        EZFS_RAIDZ_EXPAND_IN_PROGRESS,  /* a raidz is currently expanding */
+       EZFS_ASHIFT_MISMATCH,   /* can't add vdevs with different ashifts */
        EZFS_UNKNOWN
 } zfs_error_t;
 
@@ -261,7 +262,7 @@ _LIBZFS_H boolean_t zpool_skip_pool(const char *);
 _LIBZFS_H int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
     nvlist_t *, nvlist_t *);
 _LIBZFS_H int zpool_destroy(zpool_handle_t *, const char *);
-_LIBZFS_H int zpool_add(zpool_handle_t *, nvlist_t *);
+_LIBZFS_H int zpool_add(zpool_handle_t *, nvlist_t *, boolean_t check_ashift);
 
 typedef struct splitflags {
        /* do not split, but return the config that would be split off */
index 025567e2183f3ccc1bffb2b3b75c558eccccfe29..21f99bacccf32c91c149832608504ec4efb9dfd9 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2013, 2017 Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
@@ -1603,6 +1603,7 @@ typedef enum {
        ZFS_ERR_RESUME_EXISTS,
        ZFS_ERR_CRYPTO_NOTSUP,
        ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS,
+       ZFS_ERR_ASHIFT_MISMATCH,
 } zfs_errno_t;
 
 /*
index fb4c93431a31379b566f876f0b3f2be6e6593b08..b969f05afe48748a235b1ad30c07452312193d35 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2021 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  * Copyright 2013 Saso Kiselkov. All rights reserved.
@@ -785,7 +785,7 @@ extern int bpobj_enqueue_free_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx);
 #define        SPA_ASYNC_DETACH_SPARE                  0x4000
 
 /* device manipulation */
-extern int spa_vdev_add(spa_t *spa, nvlist_t *nvroot);
+extern int spa_vdev_add(spa_t *spa, nvlist_t *nvroot, boolean_t ashift_check);
 extern int spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot,
     int replacing, int rebuild);
 extern int spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid,
index cdd2f04c26290006167ef9b2ed3520b55ff5bdff..2bbaae6345abf6b0c1f38a4a65024c9e369e4d7a 100644 (file)
         <var-decl name='prev' type-id='b03eadb4' visibility='default'/>
       </data-member>
     </class-decl>
-    <class-decl name='list' size-in-bits='256' is-struct='yes' visibility='default' id='e824dae9'>
+    <class-decl name='list' size-in-bits='192' is-struct='yes' visibility='default' id='e824dae9'>
       <data-member access='public' layout-offset-in-bits='0'>
-        <var-decl name='list_size' type-id='b59d7dce' visibility='default'/>
-      </data-member>
-      <data-member access='public' layout-offset-in-bits='64'>
         <var-decl name='list_offset' type-id='b59d7dce' visibility='default'/>
       </data-member>
-      <data-member access='public' layout-offset-in-bits='128'>
+      <data-member access='public' layout-offset-in-bits='64'>
         <var-decl name='list_head' type-id='b0b5e45e' visibility='default'/>
       </data-member>
     </class-decl>
     </function-type>
   </abi-instr>
   <abi-instr address-size='64' path='lib/libzfs/libzfs_crypto.c' language='LANG_C99'>
+    <array-type-def dimensions='1' type-id='38b51b3c' size-in-bits='832' id='02b72c00'>
+      <subrange length='13' type-id='7359adad' id='487fded1'/>
+    </array-type-def>
     <array-type-def dimensions='1' type-id='fb7c6451' size-in-bits='256' id='64177143'>
       <subrange length='32' type-id='7359adad' id='ae5bde82'/>
     </array-type-def>
     <class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='a4036571'/>
     <class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='010ae0b9'/>
     <class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='79bd3751'/>
+    <class-decl name='__locale_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='23de8b96'/>
+    <array-type-def dimensions='1' type-id='80f4b756' size-in-bits='832' id='39e6f84a'>
+      <subrange length='13' type-id='7359adad' id='487fded1'/>
+    </array-type-def>
     <array-type-def dimensions='1' type-id='95e97e5e' size-in-bits='896' id='47394ee0'>
       <subrange length='28' type-id='7359adad' id='3db583d7'/>
     </array-type-def>
     <typedef-decl name='__clock_t' type-id='bd54fe1a' id='4d66c6d7'/>
     <typedef-decl name='__ssize_t' type-id='bd54fe1a' id='41060289'/>
     <typedef-decl name='FILE' type-id='ec1ed955' id='aa12d1ba'/>
+    <class-decl name='__locale_struct' size-in-bits='1856' is-struct='yes' visibility='default' id='90cc1ce3'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='__locales' type-id='02b72c00' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='832'>
+        <var-decl name='__ctype_b' type-id='31347b7a' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='896'>
+        <var-decl name='__ctype_tolower' type-id='6d60f45d' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='960'>
+        <var-decl name='__ctype_toupper' type-id='6d60f45d' visibility='default'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1024'>
+        <var-decl name='__names' type-id='39e6f84a' visibility='default'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='__locale_t' type-id='f01e1813' id='b7ac9b5f'/>
     <class-decl name='__sigset_t' size-in-bits='1024' is-struct='yes' naming-typedef-id='b9c97942' visibility='default' id='2616147f'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='__val' type-id='d2baa450' visibility='default'/>
       </data-member>
     </union-decl>
     <typedef-decl name='__sigval_t' type-id='a094b870' id='eabacd01'/>
+    <typedef-decl name='locale_t' type-id='b7ac9b5f' id='973a4f8d'/>
     <class-decl name='siginfo_t' size-in-bits='1024' is-struct='yes' naming-typedef-id='cb681f62' visibility='default' id='d8149419'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='si_signo' type-id='95e97e5e' visibility='default'/>
     <pointer-type-def type-id='bb4788fa' size-in-bits='64' id='cecf4ea7'/>
     <pointer-type-def type-id='010ae0b9' size-in-bits='64' id='e4c6fa61'/>
     <pointer-type-def type-id='79bd3751' size-in-bits='64' id='c65a1f29'/>
+    <pointer-type-def type-id='23de8b96' size-in-bits='64' id='38b51b3c'/>
+    <pointer-type-def type-id='90cc1ce3' size-in-bits='64' id='f01e1813'/>
     <qualified-type-def type-id='9b23c9ad' restrict='yes' id='8c85230f'/>
     <qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
     <pointer-type-def type-id='80f4b756' size-in-bits='64' id='7d3cd834'/>
+    <qualified-type-def type-id='95e97e5e' const='yes' id='2448a865'/>
+    <pointer-type-def type-id='2448a865' size-in-bits='64' id='6d60f45d'/>
     <qualified-type-def type-id='aca3bac8' const='yes' id='2498fd78'/>
     <pointer-type-def type-id='2498fd78' size-in-bits='64' id='eed6c816'/>
     <qualified-type-def type-id='eed6c816' restrict='yes' id='a431a9da'/>
     <class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='a4036571'/>
     <class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='010ae0b9'/>
     <class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='79bd3751'/>
+    <class-decl name='__locale_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='23de8b96'/>
     <function-decl name='zpool_get_prop_int' mangled-name='zpool_get_prop_int' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_get_prop_int'>
       <parameter type-id='4c81de99'/>
       <parameter type-id='5d0c23fb'/>
     <function-decl name='dlerror' visibility='default' binding='global' size-in-bits='64'>
       <return type-id='26a90f95'/>
     </function-decl>
+    <function-decl name='uselocale' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='973a4f8d'/>
+      <return type-id='973a4f8d'/>
+    </function-decl>
     <function-decl name='PKCS5_PBKDF2_HMAC_SHA1' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='80f4b756'/>
       <parameter type-id='95e97e5e'/>
       <parameter type-id='80f4b756'/>
       <return type-id='26a90f95'/>
     </function-decl>
-    <function-decl name='strerror' visibility='default' binding='global' size-in-bits='64'>
+    <function-decl name='strerror_l' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='95e97e5e'/>
+      <parameter type-id='973a4f8d'/>
       <return type-id='26a90f95'/>
     </function-decl>
     <function-decl name='tcgetattr' visibility='default' binding='global' size-in-bits='64'>
     <qualified-type-def type-id='9c313c2d' const='yes' id='c3b7ba7d'/>
     <pointer-type-def type-id='c3b7ba7d' size-in-bits='64' id='713a56f5'/>
     <pointer-type-def type-id='01a1b934' size-in-bits='64' id='566b3f52'/>
+    <qualified-type-def type-id='566b3f52' restrict='yes' id='c878edd6'/>
+    <pointer-type-def type-id='566b3f52' size-in-bits='64' id='82d4e9e8'/>
+    <qualified-type-def type-id='82d4e9e8' restrict='yes' id='aa19c230'/>
     <pointer-type-def type-id='7e291ce6' size-in-bits='64' id='ca64ff60'/>
     <pointer-type-def type-id='9da381c4' size-in-bits='64' id='cb785ebf'/>
     <pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/>
     <pointer-type-def type-id='8e0af06e' size-in-bits='64' id='053457bd'/>
     <pointer-type-def type-id='857bb57e' size-in-bits='64' id='75be733c'/>
     <pointer-type-def type-id='a63d15a3' size-in-bits='64' id='a195f4a3'/>
+    <qualified-type-def type-id='a195f4a3' restrict='yes' id='33518961'/>
+    <pointer-type-def type-id='a195f4a3' size-in-bits='64' id='e80ff3ab'/>
+    <qualified-type-def type-id='e80ff3ab' restrict='yes' id='8f2c7109'/>
     <pointer-type-def type-id='eae6431d' size-in-bits='64' id='0d41d328'/>
     <pointer-type-def type-id='7a6844eb' size-in-bits='64' id='18c91f9e'/>
     <pointer-type-def type-id='dddf6ca2' size-in-bits='64' id='d915a820'/>
       <parameter type-id='9d424d31'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='getgrnam' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='80f4b756'/>
-      <return type-id='566b3f52'/>
+    <function-decl name='getgrnam_r' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='c878edd6'/>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='b59d7dce'/>
+      <parameter type-id='aa19c230'/>
+      <return type-id='95e97e5e'/>
     </function-decl>
     <function-decl name='hasmntopt' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='48bea5ec'/>
       <parameter type-id='18c91f9e'/>
       <return type-id='95e97e5e'/>
     </function-decl>
-    <function-decl name='getpwnam' visibility='default' binding='global' size-in-bits='64'>
-      <parameter type-id='80f4b756'/>
-      <return type-id='a195f4a3'/>
+    <function-decl name='getpwnam_r' visibility='default' binding='global' size-in-bits='64'>
+      <parameter type-id='9d26089a'/>
+      <parameter type-id='33518961'/>
+      <parameter type-id='266fe297'/>
+      <parameter type-id='b59d7dce'/>
+      <parameter type-id='8f2c7109'/>
+      <return type-id='95e97e5e'/>
     </function-decl>
     <function-decl name='strtol' visibility='default' binding='global' size-in-bits='64'>
       <parameter type-id='9d26089a'/>
     <function-decl name='zpool_add' mangled-name='zpool_add' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_add'>
       <parameter type-id='4c81de99' name='zhp'/>
       <parameter type-id='5ce45b60' name='nvroot'/>
+      <parameter type-id='c19b74c3' name='ashift_check'/>
       <return type-id='95e97e5e'/>
     </function-decl>
     <function-decl name='zpool_export' mangled-name='zpool_export' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='zpool_export'>
       <enumerator name='LZC_SEND_FLAG_RAW' value='8'/>
       <enumerator name='LZC_SEND_FLAG_SAVED' value='16'/>
     </enum-decl>
-    <class-decl name='ddt_key' size-in-bits='320' is-struct='yes' visibility='default' id='e0a4a1cb'>
+    <class-decl name='ddt_key_t' size-in-bits='320' is-struct='yes' naming-typedef-id='67f6d2cf' visibility='default' id='5fae1718'>
       <data-member access='public' layout-offset-in-bits='0'>
         <var-decl name='ddk_cksum' type-id='39730d0b' visibility='default'/>
       </data-member>
         <var-decl name='ddk_prop' type-id='9c313c2d' visibility='default'/>
       </data-member>
     </class-decl>
-    <typedef-decl name='ddt_key_t' type-id='e0a4a1cb' id='67f6d2cf'/>
+    <typedef-decl name='ddt_key_t' type-id='5fae1718' id='67f6d2cf'/>
     <enum-decl name='dmu_object_type' id='04b3b0b9'>
       <underlying-type type-id='9cac1fee'/>
       <enumerator name='DMU_OT_NONE' value='0'/>
index 402c14a6baee85b7a7a6d4e8ca5f9c1eec374b57..b42e93e3db5d4c8dc9acf6c1245ec32526218fab 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  * Copyright (c) 2018 Datto Inc.
  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
@@ -1724,7 +1724,7 @@ zpool_discard_checkpoint(zpool_handle_t *zhp)
  * necessary verification to ensure that the vdev specification is well-formed.
  */
 int
-zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
+zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot, boolean_t check_ashift)
 {
        zfs_cmd_t zc = {"\0"};
        int ret;
@@ -1756,6 +1756,7 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
 
        zcmd_write_conf_nvlist(hdl, &zc, nvroot);
        (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_flags = check_ashift;
 
        if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
                switch (errno) {
index 8e70af2e5830a5ed519837ddb9ea62fae03430e1..73ae0950ccb639bfe090b76a4390d5a85e734d19 100644 (file)
@@ -22,7 +22,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2020 Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  * Copyright (c) 2017 Datto Inc.
  * Copyright (c) 2020 The FreeBSD Foundation
@@ -319,6 +319,9 @@ libzfs_error_description(libzfs_handle_t *hdl)
                    "dataset without force"));
        case EZFS_RAIDZ_EXPAND_IN_PROGRESS:
                return (dgettext(TEXT_DOMAIN, "raidz expansion in progress"));
+       case EZFS_ASHIFT_MISMATCH:
+               return (dgettext(TEXT_DOMAIN, "adding devices with "
+                   "different physical sector sizes is not allowed"));
        case EZFS_UNKNOWN:
                return (dgettext(TEXT_DOMAIN, "unknown error"));
        default:
@@ -768,6 +771,9 @@ zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
        case ZFS_ERR_RAIDZ_EXPAND_IN_PROGRESS:
                zfs_verror(hdl, EZFS_RAIDZ_EXPAND_IN_PROGRESS, fmt, ap);
                break;
+       case ZFS_ERR_ASHIFT_MISMATCH:
+               zfs_verror(hdl, EZFS_ASHIFT_MISMATCH, fmt, ap);
+               break;
        default:
                zfs_error_aux(hdl, "%s", zfs_strerror(error));
                zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
index 8ccdcccc7b06e8f69cdc55811a586815db651e7c..60b35f1a511a7a6a554a71d6b0ad04b67ac3440e 100644 (file)
@@ -24,8 +24,9 @@
 .\" Copyright (c) 2018 George Melikov. All Rights Reserved.
 .\" Copyright 2017 Nexenta Systems, Inc.
 .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
+.\" Copyright (c) 2024 by Delphix. All Rights Reserved.
 .\"
-.Dd March 16, 2022
+.Dd March 8, 2024
 .Dt ZPOOL-ADD 8
 .Os
 .
@@ -36,6 +37,7 @@
 .Nm zpool
 .Cm add
 .Op Fl fgLnP
+.Op Fl -allow-in-use -allow-replication-mismatch -allow-ashift-mismatch
 .Oo Fl o Ar property Ns = Ns Ar value Oc
 .Ar pool vdev Ns …
 .
@@ -56,7 +58,8 @@ subcommand.
 .It Fl f
 Forces use of
 .Ar vdev Ns s ,
-even if they appear in use or specify a conflicting replication level.
+even if they appear in use, have conflicting ashift values, or specify
+a conflicting replication level.
 Not all devices can be overridden in this manner.
 .It Fl g
 Display
@@ -91,6 +94,17 @@ See the
 manual page for a list of valid properties that can be set.
 The only property supported at the moment is
 .Sy ashift .
+.It Fl -allow-ashift-mismatch
+Disable the ashift validation which allows mismatched ashift values in the
+pool.
+Adding top-level
+.Ar vdev Ns s
+with different sector sizes will prohibit future device removal operations, see
+.Xr zpool-remove 8 .
+.It Fl -allow-in-use
+Allow vdevs to be added even if they might be in use in another pool.
+.It Fl -allow-replication-mismatch
+Allow vdevs with conflicting replication levels to be added to the pool.
 .El
 .
 .Sh EXAMPLES
index 30c528a53049935b20b893fdc067c6682d017058..3704ffd08820a9a155a72139956dff3ff39cb1e3 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright (c) 2018, Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  * Copyright 2013 Saso Kiselkov. All rights reserved.
@@ -7083,7 +7083,7 @@ spa_draid_feature_incr(void *arg, dmu_tx_t *tx)
  * Add a device to a storage pool.
  */
 int
-spa_vdev_add(spa_t *spa, nvlist_t *nvroot)
+spa_vdev_add(spa_t *spa, nvlist_t *nvroot, boolean_t check_ashift)
 {
        uint64_t txg, ndraid = 0;
        int error;
@@ -7174,6 +7174,16 @@ spa_vdev_add(spa_t *spa, nvlist_t *nvroot)
                }
        }
 
+       if (check_ashift && spa->spa_max_ashift == spa->spa_min_ashift) {
+               for (int c = 0; c < vd->vdev_children; c++) {
+                       tvd = vd->vdev_child[c];
+                       if (tvd->vdev_ashift != spa->spa_max_ashift) {
+                               return (spa_vdev_exit(spa, vd, txg,
+                                   ZFS_ERR_ASHIFT_MISMATCH));
+                       }
+               }
+       }
+
        for (int c = 0; c < vd->vdev_children; c++) {
                tvd = vd->vdev_child[c];
                vdev_remove_child(vd, tvd);
index b2b06881bdd4114f2fe68684ca4c573aaa109bac..dca15f4b826dacf49336cccda093ffa8e3de43e1 100644 (file)
@@ -27,7 +27,7 @@
  * Copyright (c) 2014, 2016 Joyent, Inc. All rights reserved.
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2024 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
@@ -1886,7 +1886,7 @@ zfs_ioc_vdev_add(zfs_cmd_t *zc)
        error = get_nvlist(zc->zc_nvlist_conf, zc->zc_nvlist_conf_size,
            zc->zc_iflags, &config);
        if (error == 0) {
-               error = spa_vdev_add(spa, config);
+               error = spa_vdev_add(spa, config, zc->zc_flags);
                nvlist_free(config);
        }
        spa_close(spa, FTAG);
index 502b4de2bae95756737cd8ab68158d2b19a0131f..d4c5a21828a155f3d43d297ff76c7d436ffbdc92 100644 (file)
@@ -372,7 +372,8 @@ tags = ['functional', 'cli_root', 'zpool']
 tests = ['zpool_add_001_pos', 'zpool_add_002_pos', 'zpool_add_003_pos',
     'zpool_add_004_pos', 'zpool_add_006_pos', 'zpool_add_007_neg',
     'zpool_add_008_neg', 'zpool_add_009_neg', 'zpool_add_010_pos',
-    'add-o_ashift', 'add_prop_ashift', 'zpool_add_dryrun_output']
+    'add-o_ashift', 'add_prop_ashift', 'zpool_add_dryrun_output',
+    'zpool_add--allow-ashift-mismatch']
 tags = ['functional', 'cli_root', 'zpool_add']
 
 [tests/functional/cli_root/zpool_attach]
index fe9c92108725dcf55b5d0a0e53dea42f6198579d..866ea5b9e7ecb237d92d00c8e40efa6bedf645ee 100644 (file)
@@ -988,6 +988,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
        functional/cli_root/zpool_add/add_prop_ashift.ksh \
        functional/cli_root/zpool_add/cleanup.ksh \
        functional/cli_root/zpool_add/setup.ksh \
+       functional/cli_root/zpool_add/zpool_add--allow-ashift-mismatch.ksh \
        functional/cli_root/zpool_add/zpool_add_001_pos.ksh \
        functional/cli_root/zpool_add/zpool_add_002_pos.ksh \
        functional/cli_root/zpool_add/zpool_add_003_pos.ksh \
index 7ecaf849e44bd749d507bb6efac17fdb2df2a8e6..51871934dd225eb0787d94f4e94867d386c2e893 100755 (executable)
@@ -22,7 +22,7 @@
 
 #
 # Copyright 2017, loli10K. All rights reserved.
-# Copyright (c) 2020 by Delphix. All rights reserved.
+# Copyright (c) 2020, 2024 by Delphix. All rights reserved.
 #
 
 . $STF_SUITE/include/libtest.shlib
@@ -60,12 +60,23 @@ log_must mkfile $SIZE $disk2
 logical_ashift=$(get_tunable VDEV_FILE_LOGICAL_ASHIFT)
 orig_ashift=$(get_tunable VDEV_FILE_PHYSICAL_ASHIFT)
 max_auto_ashift=$(get_tunable VDEV_MAX_AUTO_ASHIFT)
+opt=""
 
 typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16")
 for ashift in ${ashifts[@]}
 do
+       #
+       # Need to add the --allow-ashift-mismatch option to disable the
+       # ashift mismatch checks in zpool add.
+       #
+       if [[ $ashift -eq $orig_ashift ]]; then
+               opt=""
+       else
+               opt="--allow-ashift-mismatch"
+       fi
+
        log_must zpool create $TESTPOOL $disk1
-       log_must zpool add -o ashift=$ashift $TESTPOOL $disk2
+       log_must zpool add $opt -o ashift=$ashift $TESTPOOL $disk2
        log_must verify_ashift $disk2 $ashift
 
        # clean things for the next run
@@ -78,7 +89,7 @@ do
        #
        log_must zpool create $TESTPOOL $disk1
        log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $ashift
-       log_must zpool add $TESTPOOL $disk2
+       log_must zpool add $opt $TESTPOOL $disk2
        exp=$(( (ashift <= max_auto_ashift) ? ashift : logical_ashift ))
        log_must verify_ashift $disk2 $exp
 
index 228f62232aaeef77c30c8cc7856a97dd4ba3d251..6a3283d0618f196cceb077be5139b03f7a1ab865 100755 (executable)
@@ -22,7 +22,7 @@
 
 #
 # Copyright 2017, loli10K. All rights reserved.
-# Copyright (c) 2020 by Delphix. All rights reserved.
+# Copyright (c) 2020, 2024 by Delphix. All rights reserved.
 #
 
 . $STF_SUITE/include/libtest.shlib
@@ -68,8 +68,13 @@ log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT 16
 typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16")
 for ashift in ${ashifts[@]}
 do
+       if [ $ashift -eq $orig_ashift ];then
+               opt=""
+       else
+               opt="--allow-ashift-mismatch"
+       fi
        log_must zpool create -o ashift=$ashift $TESTPOOL $disk1
-       log_must zpool add $TESTPOOL $disk2
+       log_must zpool add $opt $TESTPOOL $disk2
        log_must verify_ashift $disk2 $ashift
 
        # clean things for the next run
@@ -82,8 +87,13 @@ for ashift in ${ashifts[@]}
 do
        for cmdval in ${ashifts[@]}
        do
+               if [ $ashift -eq $cmdval ];then
+                       opt=""
+               else
+                       opt="--allow-ashift-mismatch"
+               fi
                log_must zpool create -o ashift=$ashift $TESTPOOL $disk1
-               log_must zpool add -o ashift=$cmdval $TESTPOOL $disk2
+               log_must zpool add $opt -o ashift=$cmdval $TESTPOOL $disk2
                log_must verify_ashift $disk2 $cmdval
 
                # clean things for the next run
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add--allow-ashift-mismatch.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add--allow-ashift-mismatch.ksh
new file mode 100755 (executable)
index 0000000..e69de29
index c5c06f76340bc850f8b13b34ba83fe640ed8edf6..afee34a334693dab1e47f24c803b36de3022f650 100755 (executable)
@@ -65,4 +65,15 @@ log_mustnot vdevs_in_pool $TESTPOOL $DISK2
 log_must zpool add -f $TESTPOOL $DISK2
 log_must vdevs_in_pool $TESTPOOL $DISK2
 
+log_must zpool destroy $TESTPOOL
+
+create_pool $TESTPOOL mirror $DISK0 $DISK1
+log_must poolexists $TESTPOOL
+
+log_mustnot zpool add $TESTPOOL $DISK2
+log_mustnot vdevs_in_pool $TESTPOOL $DISK2
+
+log_must zpool add --allow-replication-mismatch $TESTPOOL $DISK2
+log_must vdevs_in_pool $TESTPOOL $DISK2
+
 log_pass "'zpool add -f <pool> <vdev> ...' executes successfully."
index 646edc1a4557c11e3dc70e2202d2f076ce01ecdd..cecda56ab125e429d248b114c7c73d13d4158cd2 100755 (executable)
@@ -70,7 +70,7 @@ if is_freebsd; then
        recursive=$(get_tunable VOL_RECURSIVE)
        log_must set_tunable64 VOL_RECURSIVE 1
 fi
-log_must zpool add $TESTPOOL $ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL
+log_must zpool add --allow-ashift-mismatch $TESTPOOL $ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL
 
 log_must vdevs_in_pool "$TESTPOOL" "$ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL"
 
index 4990ef9d29b0eed2c06834899bc6cbeee30a4e6b..0e9d9f5f030fcd98de7ed8ffdc0a053d7679cd78 100755 (executable)
@@ -75,7 +75,9 @@ log_must poolexists $TESTPOOL1
 
 unset NOINUSE_CHECK
 log_mustnot zpool add -f $TESTPOOL $DISK1
+log_mustnot zpool add --allow-in-use $TESTPOOL $DISK1
 log_mustnot zpool add -f $TESTPOOL $mnttab_dev
+log_mustnot zpool add --allow-in-use $TESTPOOL $mnttab_dev
 if is_linux; then
        log_mustnot zpool add $TESTPOOL $vfstab_dev
 else
index d7f3a900e8fd5f56e145f516ef4e25a011cf96b3..a13a27160e76b4def03f5069a71d62349a44cb51 100755 (executable)
@@ -64,7 +64,9 @@ log_mustnot zpool add -f $TESTPOOL $DISK0
 for type in "" "mirror" "raidz" "draid" "spare" "log" "dedup" "special" "cache"
 do
        log_mustnot zpool add -f $TESTPOOL $type $DISK0 $DISK1
+       log_mustnot zpool add --allow-in-use $TESTPOOL $type $DISK0 $DISK1
        log_mustnot zpool add -f $TESTPOOL $type $DISK1 $DISK1
+       log_mustnot zpool add --allow-in-use $TESTPOOL $type $DISK1 $DISK1
 done
 
 log_pass "'zpool add' get fail as expected if vdevs are the same or vdev is " \
index b8b25db1b9f92eaa3b6d65f692c685c5d3a0cc81..22860e9caf1d74a940fe6378d3b3650e1fe13482 100755 (executable)
@@ -138,7 +138,7 @@ function zpool_create_forced_add
                while ((j < ${#add_args[@]})); do
                        log_must zpool create $TESTPOOL1 ${create_args[$i]}
                        log_mustnot zpool add $TESTPOOL1 ${add_args[$j]}
-                       log_must zpool add -f $TESTPOOL1 ${add_args[$j]}
+                       log_must zpool add --allow-replication-mismatch $TESTPOOL1 ${add_args[$j]}
                        log_must zpool destroy -f $TESTPOOL1
 
                        ((j += 1))