From d9ac17a57f66bdbd482ab09ab238cb941821e13f Mon Sep 17 00:00:00 2001 From: Umer Saleem Date: Mon, 26 Sep 2022 18:40:43 +0500 Subject: [PATCH 001/126] Expose libzutil error info in libpc_handle_t In libzutil, for zpool_search_import and zpool_find_config, we use libpc_handle_t internally, which does not maintain error code and it is not exposed in the interface. Due to this, the error information is not propagated to the caller. Instead, an error message is printed on stderr. This commit adds lpc_error field in libpc_handle_t and exposes it in the interface, which can be used by the users of libzutil to get the appropriate error information and handle it accordingly. Users of the API can also control if they want to print the error message on stderr. Reviewed-by: Brian Behlendorf Reviewed-by: Ryan Moeller Signed-off-by: Umer Saleem Closes #13969 --- cmd/zdb/zdb.c | 8 +++- cmd/zhack.c | 8 +++- cmd/zpool/zpool_main.c | 9 +++- cmd/ztest.c | 8 +++- include/libzutil.h | 27 +++++++++-- lib/libzfs/libzfs.abi | 32 +++++++++++-- lib/libzutil/zutil_import.c | 92 ++++++++++++++++++++++--------------- lib/libzutil/zutil_import.h | 15 ------ 8 files changed, 130 insertions(+), 69 deletions(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 96db9c4b9a76..18a94da1f744 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -8778,8 +8778,12 @@ main(int argc, char **argv) args.path = searchdirs; args.can_be_active = B_TRUE; - error = zpool_find_config(NULL, target_pool, &cfg, &args, - &libzpool_config_ops); + libpc_handle_t lpch = { + .lpc_lib_handle = NULL, + .lpc_ops = &libzpool_config_ops, + .lpc_printerr = B_TRUE + }; + error = zpool_find_config(&lpch, target_pool, &cfg, &args); if (error == 0) { diff --git a/cmd/zhack.c b/cmd/zhack.c index 8797a53e4763..a1063ab147e2 100644 --- a/cmd/zhack.c +++ b/cmd/zhack.c @@ -140,8 +140,12 @@ zhack_import(char *target, boolean_t readonly) g_importargs.can_be_active = readonly; g_pool = strdup(target); - error = zpool_find_config(NULL, target, &config, &g_importargs, - &libzpool_config_ops); + libpc_handle_t lpch = { + .lpc_lib_handle = NULL, + .lpc_ops = &libzpool_config_ops, + .lpc_printerr = B_TRUE + }; + error = zpool_find_config(&lpch, target, &config, &g_importargs); if (error) fatal(NULL, FTAG, "cannot import '%s'", target); diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 39ea615f6319..8a4f3dd16271 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -3773,7 +3773,12 @@ zpool_do_import(int argc, char **argv) idata.scan = do_scan; idata.policy = policy; - pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops); + libpc_handle_t lpch = { + .lpc_lib_handle = g_zfs, + .lpc_ops = &libzfs_config_ops, + .lpc_printerr = B_TRUE + }; + pools = zpool_search_import(&lpch, &idata); if (pools != NULL && pool_exists && (argc == 1 || strcmp(argv[0], argv[1]) == 0)) { @@ -3829,7 +3834,7 @@ zpool_do_import(int argc, char **argv) */ idata.scan = B_TRUE; nvlist_free(pools); - pools = zpool_search_import(g_zfs, &idata, &libzfs_config_ops); + pools = zpool_search_import(&lpch, &idata); err = import_pools(pools, props, mntopts, flags, argc >= 1 ? argv[0] : NULL, diff --git a/cmd/ztest.c b/cmd/ztest.c index e630d3353187..668a267b66a2 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -7471,8 +7471,12 @@ ztest_import_impl(void) args.path = searchdirs; args.can_be_active = B_FALSE; - VERIFY0(zpool_find_config(NULL, ztest_opts.zo_pool, &cfg, &args, - &libzpool_config_ops)); + libpc_handle_t lpch = { + .lpc_lib_handle = NULL, + .lpc_ops = &libzpool_config_ops, + .lpc_printerr = B_TRUE + }; + VERIFY0(zpool_find_config(&lpch, ztest_opts.zo_pool, &cfg, &args)); VERIFY0(spa_import(ztest_opts.zo_pool, cfg, NULL, flags)); fnvlist_free(cfg); } diff --git a/include/libzutil.h b/include/libzutil.h index 0b4075c16016..617dd0cd1715 100644 --- a/include/libzutil.h +++ b/include/libzutil.h @@ -59,6 +59,15 @@ typedef const struct pool_config_ops { _LIBZUTIL_H pool_config_ops_t libzfs_config_ops; _LIBZUTIL_H pool_config_ops_t libzpool_config_ops; +typedef enum lpc_error { + LPC_SUCCESS = 0, /* no error -- success */ + LPC_BADCACHE = 2000, /* out of memory */ + LPC_BADPATH, /* must be an absolute path */ + LPC_NOMEM, /* out of memory */ + LPC_EACCESS, /* some devices require root privileges */ + LPC_UNKNOWN +} lpc_error_t; + typedef struct importargs { char **path; /* a list of paths to search */ int paths; /* number of paths to search */ @@ -70,10 +79,20 @@ typedef struct importargs { nvlist_t *policy; /* load policy (max txg, rewind, etc.) */ } importargs_t; -_LIBZUTIL_H nvlist_t *zpool_search_import(void *, importargs_t *, - pool_config_ops_t *); -_LIBZUTIL_H int zpool_find_config(void *, const char *, nvlist_t **, - importargs_t *, pool_config_ops_t *); +typedef struct libpc_handle { + int lpc_error; + boolean_t lpc_printerr; + boolean_t lpc_open_access_error; + boolean_t lpc_desc_active; + char lpc_desc[1024]; + pool_config_ops_t *lpc_ops; + void *lpc_lib_handle; +} libpc_handle_t; + +_LIBZUTIL_H const char *libpc_error_description(libpc_handle_t *); +_LIBZUTIL_H nvlist_t *zpool_search_import(libpc_handle_t *, importargs_t *); +_LIBZUTIL_H int zpool_find_config(libpc_handle_t *, const char *, nvlist_t **, + importargs_t *); _LIBZUTIL_H const char * const * zpool_default_search_paths(size_t *count); _LIBZUTIL_H int zpool_read_label(int, nvlist_t **, int *); diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 3471bcac9412..87b65a4cfe5a 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -191,6 +191,7 @@ + @@ -4569,7 +4570,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -4578,17 +4604,15 @@ - + - - + - diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index e3f1c8942564..fbf390587f07 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -71,6 +71,30 @@ #include "zutil_import.h" +const char * +libpc_error_description(libpc_handle_t *hdl) +{ + if (hdl->lpc_desc[0] != '\0') + return (hdl->lpc_desc); + + switch (hdl->lpc_error) { + case LPC_BADCACHE: + return (dgettext(TEXT_DOMAIN, "invalid or missing cache file")); + case LPC_BADPATH: + return (dgettext(TEXT_DOMAIN, "must be an absolute path")); + case LPC_NOMEM: + return (dgettext(TEXT_DOMAIN, "out of memory")); + case LPC_EACCESS: + return (dgettext(TEXT_DOMAIN, "some devices require root " + "privileges")); + case LPC_UNKNOWN: + return (dgettext(TEXT_DOMAIN, "unknown error")); + default: + assert(hdl->lpc_error == 0); + return (dgettext(TEXT_DOMAIN, "no error")); + } +} + static __attribute__((format(printf, 2, 3))) void zutil_error_aux(libpc_handle_t *hdl, const char *fmt, ...) { @@ -85,28 +109,27 @@ zutil_error_aux(libpc_handle_t *hdl, const char *fmt, ...) } static void -zutil_verror(libpc_handle_t *hdl, const char *error, const char *fmt, +zutil_verror(libpc_handle_t *hdl, lpc_error_t error, const char *fmt, va_list ap) { char action[1024]; (void) vsnprintf(action, sizeof (action), fmt, ap); + hdl->lpc_error = error; if (hdl->lpc_desc_active) hdl->lpc_desc_active = B_FALSE; else hdl->lpc_desc[0] = '\0'; - if (hdl->lpc_printerr) { - if (hdl->lpc_desc[0] != '\0') - error = hdl->lpc_desc; - - (void) fprintf(stderr, "%s: %s\n", action, error); - } + if (hdl->lpc_printerr) + (void) fprintf(stderr, "%s: %s\n", action, + libpc_error_description(hdl)); } static __attribute__((format(printf, 3, 4))) int -zutil_error_fmt(libpc_handle_t *hdl, const char *error, const char *fmt, ...) +zutil_error_fmt(libpc_handle_t *hdl, lpc_error_t error, + const char *fmt, ...) { va_list ap; @@ -120,7 +143,7 @@ zutil_error_fmt(libpc_handle_t *hdl, const char *error, const char *fmt, ...) } static int -zutil_error(libpc_handle_t *hdl, const char *error, const char *msg) +zutil_error(libpc_handle_t *hdl, lpc_error_t error, const char *msg) { return (zutil_error_fmt(hdl, error, "%s", msg)); } @@ -128,7 +151,7 @@ zutil_error(libpc_handle_t *hdl, const char *error, const char *msg) static int zutil_no_memory(libpc_handle_t *hdl) { - zutil_error(hdl, EZFS_NOMEM, "internal error"); + zutil_error(hdl, LPC_NOMEM, "internal error"); exit(1); } @@ -1244,8 +1267,8 @@ zpool_find_import_scan_dir(libpc_handle_t *hdl, pthread_mutex_t *lock, return (0); zutil_error_aux(hdl, "%s", strerror(error)); - (void) zutil_error_fmt(hdl, EZFS_BADPATH, dgettext( - TEXT_DOMAIN, "cannot resolve path '%s'"), dir); + (void) zutil_error_fmt(hdl, LPC_BADPATH, dgettext(TEXT_DOMAIN, + "cannot resolve path '%s'"), dir); return (error); } @@ -1253,8 +1276,8 @@ zpool_find_import_scan_dir(libpc_handle_t *hdl, pthread_mutex_t *lock, if (dirp == NULL) { error = errno; zutil_error_aux(hdl, "%s", strerror(error)); - (void) zutil_error_fmt(hdl, EZFS_BADPATH, - dgettext(TEXT_DOMAIN, "cannot open '%s'"), path); + (void) zutil_error_fmt(hdl, LPC_BADPATH, dgettext(TEXT_DOMAIN, + "cannot open '%s'"), path); return (error); } @@ -1315,8 +1338,8 @@ zpool_find_import_scan_path(libpc_handle_t *hdl, pthread_mutex_t *lock, } zutil_error_aux(hdl, "%s", strerror(error)); - (void) zutil_error_fmt(hdl, EZFS_BADPATH, dgettext( - TEXT_DOMAIN, "cannot resolve path '%s'"), dir); + (void) zutil_error_fmt(hdl, LPC_BADPATH, dgettext(TEXT_DOMAIN, + "cannot resolve path '%s'"), dir); goto out; } @@ -1353,7 +1376,7 @@ zpool_find_import_scan(libpc_handle_t *hdl, pthread_mutex_t *lock, continue; zutil_error_aux(hdl, "%s", strerror(error)); - (void) zutil_error_fmt(hdl, EZFS_BADPATH, dgettext( + (void) zutil_error_fmt(hdl, LPC_BADPATH, dgettext( TEXT_DOMAIN, "cannot resolve path '%s'"), dir[i]); goto error; } @@ -1574,16 +1597,16 @@ zpool_find_import_cached(libpc_handle_t *hdl, importargs_t *iarg) if ((fd = open(iarg->cachefile, O_RDONLY | O_CLOEXEC)) < 0) { zutil_error_aux(hdl, "%s", strerror(errno)); - (void) zutil_error(hdl, EZFS_BADCACHE, - dgettext(TEXT_DOMAIN, "failed to open cache file")); + (void) zutil_error(hdl, LPC_BADCACHE, dgettext(TEXT_DOMAIN, + "failed to open cache file")); return (NULL); } if (fstat64(fd, &statbuf) != 0) { zutil_error_aux(hdl, "%s", strerror(errno)); (void) close(fd); - (void) zutil_error(hdl, EZFS_BADCACHE, - dgettext(TEXT_DOMAIN, "failed to get size of cache file")); + (void) zutil_error(hdl, LPC_BADCACHE, dgettext(TEXT_DOMAIN, + "failed to get size of cache file")); return (NULL); } @@ -1595,8 +1618,7 @@ zpool_find_import_cached(libpc_handle_t *hdl, importargs_t *iarg) if (read(fd, buf, statbuf.st_size) != statbuf.st_size) { (void) close(fd); free(buf); - (void) zutil_error(hdl, EZFS_BADCACHE, - dgettext(TEXT_DOMAIN, + (void) zutil_error(hdl, LPC_BADCACHE, dgettext(TEXT_DOMAIN, "failed to read cache file contents")); return (NULL); } @@ -1605,8 +1627,7 @@ zpool_find_import_cached(libpc_handle_t *hdl, importargs_t *iarg) if (nvlist_unpack(buf, statbuf.st_size, &raw, 0) != 0) { free(buf); - (void) zutil_error(hdl, EZFS_BADCACHE, - dgettext(TEXT_DOMAIN, + (void) zutil_error(hdl, LPC_BADCACHE, dgettext(TEXT_DOMAIN, "invalid or corrupt cache file contents")); return (NULL); } @@ -1777,25 +1798,20 @@ zpool_find_import(libpc_handle_t *hdl, importargs_t *iarg) nvlist_t * -zpool_search_import(void *hdl, importargs_t *import, pool_config_ops_t *pco) +zpool_search_import(libpc_handle_t *hdl, importargs_t *import) { - libpc_handle_t handle = { 0 }; nvlist_t *pools = NULL; - handle.lpc_lib_handle = hdl; - handle.lpc_ops = pco; - handle.lpc_printerr = B_TRUE; - verify(import->poolname == NULL || import->guid == 0); if (import->cachefile != NULL) - pools = zpool_find_import_cached(&handle, import); + pools = zpool_find_import_cached(hdl, import); else - pools = zpool_find_import(&handle, import); + pools = zpool_find_import(hdl, import); if ((pools == NULL || nvlist_empty(pools)) && - handle.lpc_open_access_error && geteuid() != 0) { - (void) zutil_error(&handle, EZFS_EACESS, dgettext(TEXT_DOMAIN, + hdl->lpc_open_access_error && geteuid() != 0) { + (void) zutil_error(hdl, LPC_EACCESS, dgettext(TEXT_DOMAIN, "no pools found")); } @@ -1819,8 +1835,8 @@ pool_match(nvlist_t *cfg, char *tgt) } int -zpool_find_config(void *hdl, const char *target, nvlist_t **configp, - importargs_t *args, pool_config_ops_t *pco) +zpool_find_config(libpc_handle_t *hdl, const char *target, nvlist_t **configp, + importargs_t *args) { nvlist_t *pools; nvlist_t *match = NULL; @@ -1834,7 +1850,7 @@ zpool_find_config(void *hdl, const char *target, nvlist_t **configp, if ((sepp = strpbrk(targetdup, "/@")) != NULL) *sepp = '\0'; - pools = zpool_search_import(hdl, args, pco); + pools = zpool_search_import(hdl, args); if (pools != NULL) { nvpair_t *elem = NULL; diff --git a/lib/libzutil/zutil_import.h b/lib/libzutil/zutil_import.h index 482315e44130..f851a91132ce 100644 --- a/lib/libzutil/zutil_import.h +++ b/lib/libzutil/zutil_import.h @@ -28,26 +28,11 @@ #ifndef _LIBZUTIL_ZUTIL_IMPORT_H_ #define _LIBZUTIL_ZUTIL_IMPORT_H_ -#define EZFS_BADCACHE "invalid or missing cache file" -#define EZFS_BADPATH "must be an absolute path" -#define EZFS_NOMEM "out of memory" -#define EZFS_EACESS "some devices require root privileges" - #define IMPORT_ORDER_PREFERRED_1 1 #define IMPORT_ORDER_PREFERRED_2 2 #define IMPORT_ORDER_SCAN_OFFSET 10 #define IMPORT_ORDER_DEFAULT 100 -typedef struct libpc_handle { - boolean_t lpc_printerr; - boolean_t lpc_open_access_error; - boolean_t lpc_desc_active; - char lpc_desc[1024]; - pool_config_ops_t *lpc_ops; - void *lpc_lib_handle; -} libpc_handle_t; - - int label_paths(libpc_handle_t *hdl, nvlist_t *label, char **path, char **devid); int zpool_find_import_blkid(libpc_handle_t *hdl, pthread_mutex_t *lock, From 383c3eb33db8f8fbdea665b1f34c681428e90ace Mon Sep 17 00:00:00 2001 From: Umer Saleem Date: Fri, 30 Sep 2022 00:12:57 +0500 Subject: [PATCH 002/126] Add membar_sync abi change It appears membar_sync was not present in libzfs.abi with other membar_* functions. This commit updates libzfs.abi for membar_sync. Reviewed-by: Brian Behlendorf Reviewed-by: Ryan Moeller Signed-off-by: Umer Saleem Closes #13969 --- lib/libzfs/libzfs.abi | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 87b65a4cfe5a..061a060b6697 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -235,6 +235,7 @@ + From 6694ca5539c9b1d274db68d775963352e73b267c Mon Sep 17 00:00:00 2001 From: Finix1979 Date: Wed, 5 Oct 2022 01:55:35 +0800 Subject: [PATCH 003/126] Avoid unnecessary metaslab_check_free calling The metaslab_check_free() function only needs to be called in the GANG|DEDUP|etc case because zio_free_sync() will internally call metaslab_check_free(). Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Signed-off-by: Finix1979 Closes #13977 --- module/zfs/zio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/zio.c b/module/zfs/zio.c index c2e3c6169fa3..dce94b7b29c2 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -1203,7 +1203,6 @@ zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp) */ if (BP_IS_EMBEDDED(bp)) return; - metaslab_check_free(spa, bp); /* * Frees that are for the currently-syncing txg, are not going to be @@ -1220,6 +1219,7 @@ zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp) txg != spa->spa_syncing_txg || (spa_sync_pass(spa) >= zfs_sync_pass_deferred_free && !spa_feature_is_active(spa, SPA_FEATURE_LOG_SPACEMAP))) { + metaslab_check_free(spa, bp); bplist_append(&spa->spa_free_bplist[txg & TXG_MASK], bp); } else { VERIFY3P(zio_free_sync(NULL, spa, txg, bp, 0), ==, NULL); From 062d3d056bf2b721f3db68f5c368b1c722ac8585 Mon Sep 17 00:00:00 2001 From: shodanshok Date: Tue, 4 Oct 2022 20:00:02 +0200 Subject: [PATCH 004/126] Remove ambiguity on demand vs prefetch stats reported by arc_summary arc_summary currently list prefetch stats as "demand prefetch" However, a hit/miss can be due to demand or prefetch, not both. To remove any confusion, this patch removes the "Demand" word from the affected lines. Reviewed-by: Richard Yao Reviewed-by: Alexander Motin Reviewed-by: George Melikov Signed-off-by: Gionatan Danti Closes #13985 --- cmd/arc_summary | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/arc_summary b/cmd/arc_summary index 4f275813d973..9d0c2d30ddd6 100755 --- a/cmd/arc_summary +++ b/cmd/arc_summary @@ -678,9 +678,9 @@ def section_archits(kstats_dict): print() print('Cache hits by data type:') dt_todo = (('Demand data:', arc_stats['demand_data_hits']), - ('Demand prefetch data:', arc_stats['prefetch_data_hits']), + ('Prefetch data:', arc_stats['prefetch_data_hits']), ('Demand metadata:', arc_stats['demand_metadata_hits']), - ('Demand prefetch metadata:', + ('Prefetch metadata:', arc_stats['prefetch_metadata_hits'])) for title, value in dt_todo: @@ -689,10 +689,10 @@ def section_archits(kstats_dict): print() print('Cache misses by data type:') dm_todo = (('Demand data:', arc_stats['demand_data_misses']), - ('Demand prefetch data:', + ('Prefetch data:', arc_stats['prefetch_data_misses']), ('Demand metadata:', arc_stats['demand_metadata_misses']), - ('Demand prefetch metadata:', + ('Prefetch metadata:', arc_stats['prefetch_metadata_misses'])) for title, value in dm_todo: From 4b629d04a5b8d26122ce6b0bf2eb9d1d78b382b0 Mon Sep 17 00:00:00 2001 From: Jorgen Lundman Date: Thu, 6 Oct 2022 09:07:50 +0900 Subject: [PATCH 005/126] Avoid calling rw_destroy() on uninitialized rwlock First the function `memset(&key, 0, ...)` but any call to "goto error;" would call zio_crypt_key_destroy(key) which calls `rw_destroy()`. The `rw_init()` is moved up to be right after the memset. This way the rwlock can be released. The ctx does allocate memory, but that is handled by the memset to 0 and icp skips NULL ptrs. Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Signed-off-by: Jorgen Lundman Closes #13976 --- module/os/linux/zfs/zio_crypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/os/linux/zfs/zio_crypt.c b/module/os/linux/zfs/zio_crypt.c index 671300932384..2bc1482e91ec 100644 --- a/module/os/linux/zfs/zio_crypt.c +++ b/module/os/linux/zfs/zio_crypt.c @@ -231,6 +231,7 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key) keydata_len = zio_crypt_table[crypt].ci_keylen; memset(key, 0, sizeof (zio_crypt_key_t)); + rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL); /* fill keydata buffers and salt with random data */ ret = random_get_bytes((uint8_t *)&key->zk_guid, sizeof (uint64_t)); @@ -282,7 +283,6 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key) key->zk_crypt = crypt; key->zk_version = ZIO_CRYPT_KEY_CURRENT_VERSION; key->zk_salt_count = 0; - rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL); return (0); From 2ba240f3583e421e87ca3c5be0fb6146bf9c3f07 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Wed, 5 Oct 2022 20:09:24 -0400 Subject: [PATCH 006/126] PAM: Fix unchecked return value from zfs_key_config_load() 9a49c6b782443ba6e627f2261c45f082ad843094 was intended to fix this issue, but I had missed the case in pam_sm_open_session(). Clang's static analyzer had not reported it and I forgot to look for other cases. Interestingly, GCC gcc-12.1.1_p20220625's static analyzer had caught this as multiple double-free bugs, since another failure after the failure in zfs_key_config_load() will cause us to attempt to free the memory that zfs_key_config_load() was supposed to allocate, but had cleaned up upon failure. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #13978 --- contrib/pam_zfs_key/pam_zfs_key.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/pam_zfs_key/pam_zfs_key.c b/contrib/pam_zfs_key/pam_zfs_key.c index 8c59fc7eb716..e3fa9e9b2553 100644 --- a/contrib/pam_zfs_key/pam_zfs_key.c +++ b/contrib/pam_zfs_key/pam_zfs_key.c @@ -754,7 +754,10 @@ pam_sm_open_session(pam_handle_t *pamh, int flags, return (PAM_SUCCESS); } zfs_key_config_t config; - zfs_key_config_load(pamh, &config, argc, argv); + if (zfs_key_config_load(pamh, &config, argc, argv) != 0) { + return (PAM_SESSION_ERR); + } + if (config.uid < 1000) { zfs_key_config_free(&config); return (PAM_SUCCESS); From 72c99dc95961c1a91a1504173fd447f92f73ad50 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 6 Oct 2022 20:18:40 -0400 Subject: [PATCH 007/126] Handle possible null pointers from malloc/strdup/strndup() GCC 12.1.1_p20220625's static analyzer caught these. Of the two in the btree test, one had previously been caught by Coverity and Smatch, but GCC flagged it as a false positive. Upon examining how other test cases handle this, the solution was changed from `ASSERT3P(node, !=, NULL);` to using `perror()` to be consistent with the fixes to the other fixes done to the ZTS code. That approach was also used in ZED since I did not see a better way of handling this there. Also, upon inspection, additional unchecked pointers from malloc()/calloc()/strdup() were found in ZED, so those were handled too. In other parts of the code, the existing methods to avoid issues from memory allocators returning NULL were used, such as using `umem_alloc(size, UMEM_NOFAIL)` or returning `ENOMEM`. Reviewed-by: Brian Behlendorf Reviewed-by: Tony Hutter Signed-off-by: Richard Yao Closes #13979 --- cmd/zed/agents/fmd_serd.c | 19 +++++++++++++++++++ cmd/zed/agents/zfs_mod.c | 10 ++++++++++ cmd/zed/zed_exec.c | 4 ++++ cmd/ztest.c | 9 +++++---- lib/libzfs/libzfs_sendrecv.c | 5 +++-- lib/libzutil/zutil_import.c | 3 +++ tests/zfs-tests/cmd/badsend.c | 4 ++++ tests/zfs-tests/cmd/btree_test.c | 9 ++++++++- tests/zfs-tests/cmd/file/largest_file.c | 2 ++ tests/zfs-tests/cmd/nvlist_to_lua.c | 5 +++++ 10 files changed, 63 insertions(+), 7 deletions(-) diff --git a/cmd/zed/agents/fmd_serd.c b/cmd/zed/agents/fmd_serd.c index 763ecb9589e7..0bb2c535f094 100644 --- a/cmd/zed/agents/fmd_serd.c +++ b/cmd/zed/agents/fmd_serd.c @@ -74,9 +74,18 @@ fmd_serd_eng_alloc(const char *name, uint64_t n, hrtime_t t) fmd_serd_eng_t *sgp; sgp = malloc(sizeof (fmd_serd_eng_t)); + if (sgp == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } memset(sgp, 0, sizeof (fmd_serd_eng_t)); sgp->sg_name = strdup(name); + if (sgp->sg_name == NULL) { + perror("strdup"); + exit(EXIT_FAILURE); + } + sgp->sg_flags = FMD_SERD_DIRTY; sgp->sg_n = n; sgp->sg_t = t; @@ -123,6 +132,12 @@ fmd_serd_hash_create(fmd_serd_hash_t *shp) shp->sh_hashlen = FMD_STR_BUCKETS; shp->sh_hash = calloc(shp->sh_hashlen, sizeof (void *)); shp->sh_count = 0; + + if (shp->sh_hash == NULL) { + perror("calloc"); + exit(EXIT_FAILURE); + } + } void @@ -241,6 +256,10 @@ fmd_serd_eng_record(fmd_serd_eng_t *sgp, hrtime_t hrt) fmd_serd_eng_discard(sgp, list_tail(&sgp->sg_list)); sep = malloc(sizeof (fmd_serd_elem_t)); + if (sep == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } sep->se_hrt = hrt; list_insert_head(&sgp->sg_list, sep); diff --git a/cmd/zed/agents/zfs_mod.c b/cmd/zed/agents/zfs_mod.c index 53d9ababded9..e149c27ee025 100644 --- a/cmd/zed/agents/zfs_mod.c +++ b/cmd/zed/agents/zfs_mod.c @@ -133,6 +133,11 @@ zfs_unavail_pool(zpool_handle_t *zhp, void *data) if (zfs_toplevel_state(zhp) < VDEV_STATE_DEGRADED) { unavailpool_t *uap; uap = malloc(sizeof (unavailpool_t)); + if (uap == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + uap->uap_zhp = zhp; list_insert_tail((list_t *)data, uap); } else { @@ -411,6 +416,11 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) * completed. */ device = malloc(sizeof (pendingdev_t)); + if (device == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + (void) strlcpy(device->pd_physpath, physpath, sizeof (device->pd_physpath)); list_insert_tail(&g_device_list, device); diff --git a/cmd/zed/zed_exec.c b/cmd/zed/zed_exec.c index 51c292d41ccc..e45acfb2c69f 100644 --- a/cmd/zed/zed_exec.c +++ b/cmd/zed/zed_exec.c @@ -175,6 +175,10 @@ _zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog, node->pid = pid; node->eid = eid; node->name = strdup(prog); + if (node->name == NULL) { + perror("strdup"); + exit(EXIT_FAILURE); + } avl_add(&_launched_processes, node); } diff --git a/cmd/ztest.c b/cmd/ztest.c index 668a267b66a2..25f12f96750e 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -3512,7 +3512,8 @@ ztest_split_pool(ztest_ds_t *zd, uint64_t id) VERIFY0(nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child, &children)); - schild = malloc(rvd->vdev_children * sizeof (nvlist_t *)); + schild = umem_alloc(rvd->vdev_children * sizeof (nvlist_t *), + UMEM_NOFAIL); for (c = 0; c < children; c++) { vdev_t *tvd = rvd->vdev_child[c]; nvlist_t **mchild; @@ -3546,7 +3547,7 @@ ztest_split_pool(ztest_ds_t *zd, uint64_t id) for (c = 0; c < schildren; c++) fnvlist_free(schild[c]); - free(schild); + umem_free(schild, rvd->vdev_children * sizeof (nvlist_t *)); fnvlist_free(split); spa_config_exit(spa, SCL_VDEV, FTAG); @@ -6663,7 +6664,7 @@ join_strings(char **strings, const char *sep) } size_t buflen = totallen + 1; - char *o = malloc(buflen); /* trailing 0 byte */ + char *o = umem_alloc(buflen, UMEM_NOFAIL); /* trailing 0 byte */ o[0] = '\0'; for (char **sp = strings; *sp != NULL; sp++) { size_t would; @@ -6925,7 +6926,7 @@ ztest_run_zdb(const char *pool) pool); ASSERT3U(would, <, len); - free(set_gvars_args_joined); + umem_free(set_gvars_args_joined, strlen(set_gvars_args_joined) + 1); if (ztest_opts.zo_verbose >= 5) (void) printf("Executing %s\n", zdb); diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index d63a9e1a4e0a..bf93ac9bac18 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -4387,7 +4387,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, * prepend a path separator. */ int len = strlen(drrb->drr_toname); - cp = malloc(len + 2); + cp = umem_alloc(len + 2, UMEM_NOFAIL); cp[0] = '/'; (void) strcpy(&cp[1], drrb->drr_toname); chopprefix = cp; @@ -4440,7 +4440,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, */ (void) strlcpy(destsnap, tosnap, sizeof (destsnap)); (void) strlcat(destsnap, chopprefix, sizeof (destsnap)); - free(cp); + if (cp != NULL) + umem_free(cp, strlen(cp) + 1); if (!zfs_name_valid(destsnap, ZFS_TYPE_SNAPSHOT)) { err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf); goto out; diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index fbf390587f07..e7a755dcbd97 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -1845,6 +1845,9 @@ zpool_find_config(libpc_handle_t *hdl, const char *target, nvlist_t **configp, int count = 0; char *targetdup = strdup(target); + if (targetdup == NULL) + return (ENOMEM); + *configp = NULL; if ((sepp = strpbrk(targetdup, "/@")) != NULL) diff --git a/tests/zfs-tests/cmd/badsend.c b/tests/zfs-tests/cmd/badsend.c index 48d05bd3fd4c..7a54532fb28d 100644 --- a/tests/zfs-tests/cmd/badsend.c +++ b/tests/zfs-tests/cmd/badsend.c @@ -76,6 +76,10 @@ main(int argc, char const * const argv[]) tosnap = p + 1; fsname = strndup(tofull, p - tofull); + if (fsname == NULL) { + perror("strndup"); + exit(EXIT_FAILURE); + } if (strncmp(fsname, fromfull, p - tofull) != 0) usage(argv[0]); diff --git a/tests/zfs-tests/cmd/btree_test.c b/tests/zfs-tests/cmd/btree_test.c index 4e2023003b0e..ab8967b22b22 100644 --- a/tests/zfs-tests/cmd/btree_test.c +++ b/tests/zfs-tests/cmd/btree_test.c @@ -242,7 +242,10 @@ drain_tree(zfs_btree_t *bt, char *why) zfs_btree_add_idx(bt, &randval, &bt_idx); node = malloc(sizeof (int_node_t)); - ASSERT3P(node, !=, NULL); + if (node == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } node->data = randval; if ((ret = avl_find(&avl, node, &avl_idx)) != NULL) { @@ -319,6 +322,10 @@ stress_tree(zfs_btree_t *bt, char *why) uint64_t randval = random() % tree_limit; node = malloc(sizeof (*node)); + if (node == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } node->data = randval; max = randval > max ? randval : max; diff --git a/tests/zfs-tests/cmd/file/largest_file.c b/tests/zfs-tests/cmd/file/largest_file.c index 8545bb7eea42..d7252556b3cf 100644 --- a/tests/zfs-tests/cmd/file/largest_file.c +++ b/tests/zfs-tests/cmd/file/largest_file.c @@ -78,6 +78,8 @@ main(int argc, char **argv) return (errno); testfile = strdup(argv[1]); + if (testfile == NULL) + return (errno); fd = open(testfile, O_CREAT | O_RDWR, mode); if (fd < 0) { diff --git a/tests/zfs-tests/cmd/nvlist_to_lua.c b/tests/zfs-tests/cmd/nvlist_to_lua.c index b65b3fd269d9..3da69397a993 100644 --- a/tests/zfs-tests/cmd/nvlist_to_lua.c +++ b/tests/zfs-tests/cmd/nvlist_to_lua.c @@ -129,6 +129,11 @@ run_tests(void) /* Note: maximum nvlist key length is 32KB */ int len = 1024 * 31; char *bigstring = malloc(len); + if (bigstring == NULL) { + perror("malloc"); + exit(EXIT_FAILURE); + } + for (int i = 0; i < len; i++) bigstring[i] = 'a' + i % 26; bigstring[len - 1] = '\0'; From e5646c5e372621be3b17a07c378512b502888925 Mon Sep 17 00:00:00 2001 From: Serapheim Dimitropoulos Date: Tue, 11 Oct 2022 12:12:04 -0700 Subject: [PATCH 008/126] zvol_wait logic may terminate prematurely Setups that have a lot of zvols may see zvol_wait terminate prematurely even though the script is still making progress. For example, we have a customer that called zvol_wait for ~7100 zvols and by the last iteration of that script it was still waiting on ~2900. Similarly another one called zvol_wait for 2200 and by the time the script terminated there were only 50 left. This patch adjusts the logic to stay within the outer loop of the script if we are making any progress whatsoever. Reviewed-by: George Wilson Reviewed-by: Pavel Zakharov Reviewed-by: Don Brady Signed-off-by: Serapheim Dimitropoulos Closes #13998 --- cmd/zvol_wait | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmd/zvol_wait b/cmd/zvol_wait index f1fa42e27dc9..0b2a8a3e60c3 100755 --- a/cmd/zvol_wait +++ b/cmd/zvol_wait @@ -109,6 +109,13 @@ while [ "$outer_loop" -lt 20 ]; do exit 0 fi fi + + # + # zvol_count made some progress - let's stay in this loop. + # + if [ "$old_zvols_count" -gt "$zvols_count" ]; then + outer_loop=$((outer_loop - 1)) + fi done echo "Timed out waiting on zvol links" From 70248b82e8229c00531c1618814ca5fa9bc82a98 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 11 Oct 2022 15:24:36 -0400 Subject: [PATCH 009/126] Fix uninitialized value read in vdev_prop_set() If no errors are encountered, we read an uninitialized error value. Clang's static analyzer complained about this. Reviewed-by: Tino Reichardt Reviewed-by: Ryan Moeller Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14007 --- module/zfs/vdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 66cec052b669..52265d960c63 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -5648,7 +5648,7 @@ vdev_prop_set(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) nvpair_t *elem = NULL; uint64_t vdev_guid; nvlist_t *nvprops; - int error; + int error = 0; ASSERT(vd != NULL); From 4dcc2bde9c8347fd7969871b69e72cba0b6d4ef7 Mon Sep 17 00:00:00 2001 From: Serapheim Dimitropoulos Date: Tue, 11 Oct 2022 12:27:41 -0700 Subject: [PATCH 010/126] Stop ganging due to past vdev write errors = Problem While examining a customer's system we noticed unreasonable space usage from a few snapshots due to gang blocks. Under some further analysis we discovered that the pool would create gang blocks because all its disks had non-zero write error counts and they'd be skipped for normal metaslab allocations due to the following if-clause in `metaslab_alloc_dva()`: ``` /* * Avoid writing single-copy data to a failing, * non-redundant vdev, unless we've already tried all * other vdevs. */ if ((vd->vdev_stat.vs_write_errors > 0 || vd->vdev_state < VDEV_STATE_HEALTHY) && d == 0 && !try_hard && vd->vdev_children == 0) { metaslab_trace_add(zal, mg, NULL, psize, d, TRACE_VDEV_ERROR, allocator); goto next; } ``` = Proposed Solution Get rid of the predicate in the if-clause that checks the past write errors of the selected vdev. We still try to allocate from HEALTHY vdevs anyway by checking vdev_state so the past write errors doesn't seem to help us (quite the opposite - it can cause issues in long-lived pools like the one from our customer). = Testing I first created a pool with 3 vdevs: ``` $ zpool list -v volpool NAME SIZE ALLOC FREE volpool 22.5G 117M 22.4G xvdb 7.99G 40.2M 7.46G xvdc 7.99G 39.1M 7.46G xvdd 7.99G 37.8M 7.46G ``` And used `zinject` like so with each one of them: ``` $ sudo zinject -d xvdb -e io -T write -f 0.1 volpool ``` And got the vdevs to the following state: ``` $ zpool status volpool pool: volpool state: ONLINE status: One or more devices has experienced an unrecoverable error. ..... action: Determine if the device needs to be replaced, and clear the ..... config: NAME STATE READ WRITE CKSUM volpool ONLINE 0 0 0 xvdb ONLINE 0 1 0 xvdc ONLINE 0 1 0 xvdd ONLINE 0 4 0 ``` I also double-checked their write error counters with sdb: ``` sdb> spa volpool | vdev | member vdev_stat.vs_write_errors (uint64_t)0 # <---- this is the root vdev (uint64_t)2 (uint64_t)1 (uint64_t)1 ``` Then I checked that I the problem was reproduced in my VM as I the gang count was growing in zdb as I was writting more data: ``` $ sudo zdb volpool | grep gang ganged count: 1384 $ sudo zdb volpool | grep gang ganged count: 1393 $ sudo zdb volpool | grep gang ganged count: 1402 $ sudo zdb volpool | grep gang ganged count: 1414 ``` Then I updated my bits with this patch and the gang count stayed the same. Reviewed-by: Mark Maybee Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Serapheim Dimitropoulos Closes #14003 --- module/zfs/metaslab.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c index efcfeecd778e..cf853a42de07 100644 --- a/module/zfs/metaslab.c +++ b/module/zfs/metaslab.c @@ -5201,12 +5201,11 @@ metaslab_alloc_dva(spa_t *spa, metaslab_class_t *mc, uint64_t psize, ASSERT(mg->mg_initialized); /* - * Avoid writing single-copy data to a failing, + * Avoid writing single-copy data to an unhealthy, * non-redundant vdev, unless we've already tried all * other vdevs. */ - if ((vd->vdev_stat.vs_write_errors > 0 || - vd->vdev_state < VDEV_STATE_HEALTHY) && + if (vd->vdev_state < VDEV_STATE_HEALTHY && d == 0 && !try_hard && vd->vdev_children == 0) { metaslab_trace_add(zal, mg, NULL, psize, d, TRACE_VDEV_ERROR, allocator); From ed566bf1cd0bdbf85e8c63c1c119e3d2ef5db1f6 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 11 Oct 2022 15:29:55 -0400 Subject: [PATCH 011/126] FreeBSD: Fix a pair of bugs in zfs_fhtovp() - Add a zfs_exit() call in an error path, otherwise a lock is leaked. - Remove the fid_gen > 1 check. That appears to be Linux-specific: zfsctl_snapdir_fid() sets fid_gen to 0 or 1 depending on whether the snapshot directory is mounted. On FreeBSD it fails, making snapshot dirs inaccessible via NFS. Reviewed-by: Alexander Motin Reviewed-by: Ryan Moeller Reviewed-by: Andriy Gapon Signed-off-by: Mark Johnston Fixes: 43dbf8817808 ("FreeBSD: vfsops: use setgen for error case") Closes #14001 Closes #13974 --- module/os/freebsd/zfs/zfs_vfsops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index c65be4c134d5..4cb7f63b5230 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -1818,7 +1818,8 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, int flags, vnode_t **vpp) return (SET_ERROR(EINVAL)); } - if (fidp->fid_len == LONG_FID_LEN && (fid_gen > 1 || setgen != 0)) { + if (fidp->fid_len == LONG_FID_LEN && setgen != 0) { + zfs_exit(zfsvfs, FTAG); dprintf("snapdir fid: fid_gen (%llu) and setgen (%llu)\n", (u_longlong_t)fid_gen, (u_longlong_t)setgen); return (SET_ERROR(EINVAL)); From bfaa1d98f4cef71938bdbde4fd01d2db2559fccb Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 11 Oct 2022 15:32:07 -0400 Subject: [PATCH 012/126] scripts/enum-extract.pl should not hard code perl path This is a portability issue. The issue had already been fixed for scripts/cstyle.pl by 2dbf1bf8296f66f24d5e404505c991bfbeec7808. scripts/enum-extract.pl was added to the repository the following year without this portability fix. Michael Bishop informed me that this broke his attempt to build ZFS 2.1.6 on NixOS, since he was building manually outside of their package manager (that usually rewrites the shebangs to NixOS' unusual paths). NixOS puts all of the paths into $PATH, so scripts that portably rely on env to find the interpreter still work. Reviewed-by: Tino Reichardt Reviewed-by: George Melikov Reviewed-by: Ryan Moeller Signed-off-by: Richard Yao Closes #14012 --- scripts/enum-extract.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/enum-extract.pl b/scripts/enum-extract.pl index 5112cc807f67..5dc2e3455145 100755 --- a/scripts/enum-extract.pl +++ b/scripts/enum-extract.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl my $usage = < Date: Wed, 12 Oct 2022 14:25:18 -0400 Subject: [PATCH 013/126] Add defensive assertions Coverity complains about possible bugs involving referencing NULL return values and division by zero. The division by zero bugs require that a block pointer be corrupt, either from in-memory corruption, or on-disk corruption. The NULL return value complaints are only bugs if assumptions that we make about the state of data structures are wrong. Some seem impossible to be wrong and thus are false positives, while others are hard to analyze. Rather than dismiss these as false positives by assuming we know better, we add defensive assertions to let us know when our assumptions are wrong. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #13972 --- cmd/zdb/zdb_il.c | 1 + module/os/freebsd/zfs/zfs_acl.c | 1 + module/os/linux/zfs/zfs_acl.c | 1 + module/zfs/arc.c | 1 + module/zfs/dbuf.c | 2 ++ module/zfs/dmu_traverse.c | 1 + module/zfs/dsl_deadlist.c | 1 + module/zfs/dsl_scan.c | 1 + module/zfs/mmp.c | 4 +++- module/zfs/range_tree.c | 1 + module/zfs/spa_log_spacemap.c | 1 + module/zfs/vdev_indirect.c | 1 + module/zfs/vdev_queue.c | 1 + module/zfs/zil.c | 1 + 14 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cmd/zdb/zdb_il.c b/cmd/zdb/zdb_il.c index 4de7619e4bde..02cc10fb7817 100644 --- a/cmd/zdb/zdb_il.c +++ b/cmd/zdb/zdb_il.c @@ -182,6 +182,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg) return; } + ASSERT3U(BP_GET_LSIZE(bp), !=, 0); SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os), lr->lr_foid, ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp)); diff --git a/module/os/freebsd/zfs/zfs_acl.c b/module/os/freebsd/zfs/zfs_acl.c index 963102f3b62a..a85d4c24178b 100644 --- a/module/os/freebsd/zfs/zfs_acl.c +++ b/module/os/freebsd/zfs/zfs_acl.c @@ -1133,6 +1133,7 @@ zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, cb->cb_acl_node); } + ASSERT3P(cb->cb_acl_node, !=, NULL); *dataptr = cb->cb_acl_node->z_acldata; *length = cb->cb_acl_node->z_size; } diff --git a/module/os/linux/zfs/zfs_acl.c b/module/os/linux/zfs/zfs_acl.c index 5935403b49d0..d5cd5de890ab 100644 --- a/module/os/linux/zfs/zfs_acl.c +++ b/module/os/linux/zfs/zfs_acl.c @@ -1163,6 +1163,7 @@ zfs_acl_data_locator(void **dataptr, uint32_t *length, uint32_t buflen, cb->cb_acl_node = list_next(&cb->cb_aclp->z_acl, cb->cb_acl_node); } + ASSERT3P(cb->cb_acl_node, !=, NULL); *dataptr = cb->cb_acl_node->z_acldata; *length = cb->cb_acl_node->z_size; } diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 33865f715b0f..9254d8b84902 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -8539,6 +8539,7 @@ l2arc_dev_get_next(void) else if (next == first) break; + ASSERT3P(next, !=, NULL); } while (vdev_is_dead(next->l2ad_vdev) || next->l2ad_rebuild || next->l2ad_trim_all); diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index db1123d37d98..85de95baf61a 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -2687,6 +2687,7 @@ dbuf_override_impl(dmu_buf_impl_t *db, const blkptr_t *bp, dmu_tx_t *tx) dbuf_dirty_record_t *dr; dr = list_head(&db->db_dirty_records); + ASSERT3P(dr, !=, NULL); ASSERT3U(dr->dr_txg, ==, tx->tx_txg); dl = &dr->dt.dl; dl->dr_overridden_by = *bp; @@ -2748,6 +2749,7 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data, dmu_buf_will_not_fill(dbuf, tx); dr = list_head(&db->db_dirty_records); + ASSERT3P(dr, !=, NULL); ASSERT3U(dr->dr_txg, ==, tx->tx_txg); dl = &dr->dt.dl; encode_embedded_bp_compressed(&dl->dr_overridden_by, diff --git a/module/zfs/dmu_traverse.c b/module/zfs/dmu_traverse.c index 2ed75640f68d..d712133cd789 100644 --- a/module/zfs/dmu_traverse.c +++ b/module/zfs/dmu_traverse.c @@ -111,6 +111,7 @@ traverse_zil_record(zilog_t *zilog, const lr_t *lrc, void *arg, if (claim_txg == 0 || bp->blk_birth < claim_txg) return (0); + ASSERT3U(BP_GET_LSIZE(bp), !=, 0); SET_BOOKMARK(&zb, td->td_objset, lr->lr_foid, ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp)); diff --git a/module/zfs/dsl_deadlist.c b/module/zfs/dsl_deadlist.c index 1ecae0fe3865..031be59e31cc 100644 --- a/module/zfs/dsl_deadlist.c +++ b/module/zfs/dsl_deadlist.c @@ -542,6 +542,7 @@ dsl_deadlist_remove_key(dsl_deadlist_t *dl, uint64_t mintxg, dmu_tx_t *tx) dle = avl_find(&dl->dl_tree, &dle_tofind, NULL); ASSERT3P(dle, !=, NULL); dle_prev = AVL_PREV(&dl->dl_tree, dle); + ASSERT3P(dle_prev, !=, NULL); dle_enqueue_subobj(dl, dle_prev, dle->dle_bpobj.bpo_object, tx); diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index f0cd1feaf55b..09e271395cc4 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -1470,6 +1470,7 @@ dsl_scan_zil_record(zilog_t *zilog, const lr_t *lrc, void *arg, if (claim_txg == 0 || bp->blk_birth < claim_txg) return (0); + ASSERT3U(BP_GET_LSIZE(bp), !=, 0); SET_BOOKMARK(&zb, zh->zh_log.blk_cksum.zc_word[ZIL_ZC_OBJSET], lr->lr_foid, ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp)); diff --git a/module/zfs/mmp.c b/module/zfs/mmp.c index 92fd6c422330..b6d71aa8a458 100644 --- a/module/zfs/mmp.c +++ b/module/zfs/mmp.c @@ -303,8 +303,10 @@ mmp_next_leaf(spa_t *spa) do { leaf = list_next(&spa->spa_leaf_list, leaf); - if (leaf == NULL) + if (leaf == NULL) { leaf = list_head(&spa->spa_leaf_list); + ASSERT3P(leaf, !=, NULL); + } /* * We skip unwritable, offline, detached, and dRAID spare diff --git a/module/zfs/range_tree.c b/module/zfs/range_tree.c index a2923d1664c7..894c30fcae16 100644 --- a/module/zfs/range_tree.c +++ b/module/zfs/range_tree.c @@ -369,6 +369,7 @@ range_tree_add_impl(void *arg, uint64_t start, uint64_t size, uint64_t fill) * invalid as soon as we do any mutating btree operations. */ rs_after = zfs_btree_find(&rt->rt_root, &tmp, &where_after); + ASSERT3P(rs_after, !=, NULL); rs_set_start_raw(rs_after, rt, before_start); rs_set_fill(rs_after, rt, after_fill + before_fill + fill); rs = rs_after; diff --git a/module/zfs/spa_log_spacemap.c b/module/zfs/spa_log_spacemap.c index 4ecce8214f6a..5ce60bf212f1 100644 --- a/module/zfs/spa_log_spacemap.c +++ b/module/zfs/spa_log_spacemap.c @@ -507,6 +507,7 @@ void spa_log_summary_decrement_blkcount(spa_t *spa, uint64_t blocks_gone) { log_summary_entry_t *e = list_head(&spa->spa_log_summary); + ASSERT3P(e, !=, NULL); if (e->lse_txgcount > 0) e->lse_txgcount--; for (; e != NULL; e = list_head(&spa->spa_log_summary)) { diff --git a/module/zfs/vdev_indirect.c b/module/zfs/vdev_indirect.c index 0ca0c245e952..b0bd71c58e69 100644 --- a/module/zfs/vdev_indirect.c +++ b/module/zfs/vdev_indirect.c @@ -1319,6 +1319,7 @@ vdev_indirect_io_start(zio_t *zio) vdev_indirect_gather_splits, zio); indirect_split_t *first = list_head(&iv->iv_splits); + ASSERT3P(first, !=, NULL); if (first->is_size == zio->io_size) { /* * This is not a split block; we are pointing to the entire diff --git a/module/zfs/vdev_queue.c b/module/zfs/vdev_queue.c index 1acb89cea393..f4e8d1427d7c 100644 --- a/module/zfs/vdev_queue.c +++ b/module/zfs/vdev_queue.c @@ -756,6 +756,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) do { dio = nio; nio = AVL_NEXT(t, dio); + ASSERT3P(dio, !=, NULL); zio_add_child(dio, aio); vdev_queue_io_remove(vq, dio); diff --git a/module/zfs/zil.c b/module/zfs/zil.c index dc5b8018e16e..075bac832f06 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -339,6 +339,7 @@ zil_read_log_data(zilog_t *zilog, const lr_write_t *lr, void *wbuf) if (wbuf == NULL) zio_flags |= ZIO_FLAG_RAW; + ASSERT3U(BP_GET_LSIZE(bp), !=, 0); SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os), lr->lr_foid, ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp)); From 4bbd7a0fbe6711a9987e6c3608a93fc6cecc206f Mon Sep 17 00:00:00 2001 From: George Melikov Date: Tue, 11 Oct 2022 22:59:06 +0300 Subject: [PATCH 014/126] CI: bump actions/checkout to v3 Reviewed-by: Brian Behlendorf Signed-off-by: George Melikov Closes #14018 --- .github/workflows/checkstyle.yaml | 2 +- .github/workflows/zfs-tests-functional.yml | 2 +- .github/workflows/zfs-tests-sanity.yml | 2 +- .github/workflows/zloop.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checkstyle.yaml b/.github/workflows/checkstyle.yaml index 8dafdcf07fed..d7aff6bd62c4 100644 --- a/.github/workflows/checkstyle.yaml +++ b/.github/workflows/checkstyle.yaml @@ -8,7 +8,7 @@ jobs: checkstyle: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - name: Install dependencies diff --git a/.github/workflows/zfs-tests-functional.yml b/.github/workflows/zfs-tests-functional.yml index 0273610af045..71815a562fe1 100644 --- a/.github/workflows/zfs-tests-functional.yml +++ b/.github/workflows/zfs-tests-functional.yml @@ -12,7 +12,7 @@ jobs: os: [18.04, 20.04] runs-on: ubuntu-${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - name: Reclaim disk space diff --git a/.github/workflows/zfs-tests-sanity.yml b/.github/workflows/zfs-tests-sanity.yml index 73606f909e10..3e0b0f62a01f 100644 --- a/.github/workflows/zfs-tests-sanity.yml +++ b/.github/workflows/zfs-tests-sanity.yml @@ -8,7 +8,7 @@ jobs: tests: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - name: Reclaim disk space diff --git a/.github/workflows/zloop.yml b/.github/workflows/zloop.yml index d49eeae1653c..1ec8bf480d2b 100644 --- a/.github/workflows/zloop.yml +++ b/.github/workflows/zloop.yml @@ -10,7 +10,7 @@ jobs: env: TEST_DIR: /var/tmp/zloop steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - name: Install dependencies From 87d5ff8ecd30f427fdfbfa91124fa4e8d9ac146f Mon Sep 17 00:00:00 2001 From: George Melikov Date: Wed, 12 Oct 2022 09:33:38 +0300 Subject: [PATCH 015/126] CI: bump actions/upload-artifact to v3 Reviewed-by: Brian Behlendorf Signed-off-by: George Melikov Closes #14018 --- .github/workflows/checkstyle.yaml | 2 +- .github/workflows/zfs-tests-functional.yml | 2 +- .github/workflows/zfs-tests-sanity.yml | 2 +- .github/workflows/zloop.yml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/checkstyle.yaml b/.github/workflows/checkstyle.yaml index d7aff6bd62c4..2e593e0a5669 100644 --- a/.github/workflows/checkstyle.yaml +++ b/.github/workflows/checkstyle.yaml @@ -49,7 +49,7 @@ jobs: if: failure() && steps.CheckABI.outcome == 'failure' run: | find -name *.abi | tar -cf abi_files.tar -T - - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() && steps.CheckABI.outcome == 'failure' with: name: New ABI files (use only if you're sure about interface changes) diff --git a/.github/workflows/zfs-tests-functional.yml b/.github/workflows/zfs-tests-functional.yml index 71815a562fe1..1c2b2b804064 100644 --- a/.github/workflows/zfs-tests-functional.yml +++ b/.github/workflows/zfs-tests-functional.yml @@ -72,7 +72,7 @@ jobs: sudo chmod +r $RESULTS_PATH/* # Replace ':' in dir names, actions/upload-artifact doesn't support it for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() with: name: Test logs Ubuntu-${{ matrix.os }} diff --git a/.github/workflows/zfs-tests-sanity.yml b/.github/workflows/zfs-tests-sanity.yml index 3e0b0f62a01f..ace046ad1c12 100644 --- a/.github/workflows/zfs-tests-sanity.yml +++ b/.github/workflows/zfs-tests-sanity.yml @@ -68,7 +68,7 @@ jobs: sudo chmod +r $RESULTS_PATH/* # Replace ':' in dir names, actions/upload-artifact doesn't support it for f in $(find /var/tmp/test_results -name '*:*'); do mv "$f" "${f//:/__}"; done - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() with: name: Test logs Ubuntu-${{ matrix.os }} diff --git a/.github/workflows/zloop.yml b/.github/workflows/zloop.yml index 1ec8bf480d2b..807a1bc46123 100644 --- a/.github/workflows/zloop.yml +++ b/.github/workflows/zloop.yml @@ -45,7 +45,7 @@ jobs: if: failure() run: | sudo chmod +r -R $TEST_DIR/ - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() with: name: Logs @@ -53,7 +53,7 @@ jobs: /var/tmp/zloop/*/ !/var/tmp/zloop/*/vdev/ if-no-files-found: ignore - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() with: name: Pool files From 4e195e825468a0f067d7465c16a23f8e4a962f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Thu, 13 Oct 2022 00:27:55 +0200 Subject: [PATCH 016/126] etc: mask zfs-load-key.service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, systemd-sysv-generator will generate a service equivalent that breaks the boot: under systemd this is covered by zfs-mount-generator We already do this for zfs-import.service, and other init scripts are suppressed automatically by the "actual" .service files Fixes: commit f04b97620059d08b37d9e80ada397e742bb2f311 ("Add init script to load keys") Reviewed-by: George Melikov Reviewed-by: Brian Behlendorf Signed-off-by: Ahelenia ZiemiaƄska Closes #14010 Closes #14019 --- etc/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/Makefile.am b/etc/Makefile.am index b4b3ae1f5798..7187762d3802 100644 --- a/etc/Makefile.am +++ b/etc/Makefile.am @@ -74,6 +74,7 @@ INSTALL_DATA_HOOKS += systemd-install-data-hook systemd-install-data-hook: $(MKDIR_P) "$(DESTDIR)$(systemdunitdir)" ln -sf /dev/null "$(DESTDIR)$(systemdunitdir)/zfs-import.service" + ln -sf /dev/null "$(DESTDIR)$(systemdunitdir)/zfs-load-key.service" systemdgenerator_PROGRAMS = \ From ff7a0a108fb58cb4284898603af4a02a4c029be8 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 8 Oct 2022 21:29:54 -0400 Subject: [PATCH 017/126] Linux: Remove ZFS_AC_KERNEL_SRC_MODULE_PARAM_CALL_CONST autotools check On older kernels, the definition for `module_param_call()` typecasts function pointers to `(void *)`, which triggers -Werror, causing the check to return false when it should return true. Fixing this breaks the build process on some older kernels because they define a `__check_old_set_param()` function in their headers that checks for a non-constified `->set()`. We workaround that through the c preprocessor by defining `__check_old_set_param(set)` to `(set)`, which prevents the build failures. However, it is now apparent that all kernels that we support have adopted the GRSecurity change, so there is no need to have an explicit autotools check for it anymore. We therefore remove the autotools check, while adding the workaround to our headers for the build time non-constified `->set()` check done by older kernel headers. Reviewed-by: Brian Behlendorf Reviewed-by: Jorgen Lundman Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Signed-off-by: Richard Yao Closes #13984 Closes #14004 --- config/kernel-mod-param.m4 | 33 ---------------------- config/kernel.m4 | 2 -- include/os/linux/kernel/linux/mod_compat.h | 14 +++++---- 3 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 config/kernel-mod-param.m4 diff --git a/config/kernel-mod-param.m4 b/config/kernel-mod-param.m4 deleted file mode 100644 index e00f19d61e7d..000000000000 --- a/config/kernel-mod-param.m4 +++ /dev/null @@ -1,33 +0,0 @@ -dnl # -dnl # Grsecurity kernel API change -dnl # constified parameters of module_param_call() methods -dnl # -AC_DEFUN([ZFS_AC_KERNEL_SRC_MODULE_PARAM_CALL_CONST], [ - ZFS_LINUX_TEST_SRC([module_param_call], [ - #include - #include - - int param_get(char *b, const struct kernel_param *kp) - { - return (0); - } - - int param_set(const char *b, const struct kernel_param *kp) - { - return (0); - } - - module_param_call(p, param_set, param_get, NULL, 0644); - ],[]) -]) - -AC_DEFUN([ZFS_AC_KERNEL_MODULE_PARAM_CALL_CONST], [ - AC_MSG_CHECKING([whether module_param_call() is hardened]) - ZFS_LINUX_TEST_RESULT([module_param_call], [ - AC_MSG_RESULT(yes) - AC_DEFINE(MODULE_PARAM_CALL_CONST, 1, - [hardened module_param_call]) - ],[ - AC_MSG_RESULT(no) - ]) -]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 6aad2cf88e02..8a5c9296ad7b 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -122,7 +122,6 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_FMODE_T ZFS_AC_KERNEL_SRC_KUIDGID_T ZFS_AC_KERNEL_SRC_KUID_HELPERS - ZFS_AC_KERNEL_SRC_MODULE_PARAM_CALL_CONST ZFS_AC_KERNEL_SRC_RENAME ZFS_AC_KERNEL_SRC_CURRENT_TIME ZFS_AC_KERNEL_SRC_USERNS_CAPABILITIES @@ -243,7 +242,6 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_FMODE_T ZFS_AC_KERNEL_KUIDGID_T ZFS_AC_KERNEL_KUID_HELPERS - ZFS_AC_KERNEL_MODULE_PARAM_CALL_CONST ZFS_AC_KERNEL_RENAME ZFS_AC_KERNEL_CURRENT_TIME ZFS_AC_KERNEL_USERNS_CAPABILITIES diff --git a/include/os/linux/kernel/linux/mod_compat.h b/include/os/linux/kernel/linux/mod_compat.h index a091bbfe179d..1b15f9c6e043 100644 --- a/include/os/linux/kernel/linux/mod_compat.h +++ b/include/os/linux/kernel/linux/mod_compat.h @@ -30,12 +30,16 @@ #include #include -/* Grsecurity kernel API change */ -#ifdef MODULE_PARAM_CALL_CONST +/* + * Despite constifying struct kernel_param_ops, some older kernels define a + * `__check_old_set_param()` function in their headers that checks for a + * non-constified `->set()`. This has long been fixed in Linux mainline, but + * since we support older kernels, we workaround it by using a preprocessor + * definition to disable it. + */ +#define __check_old_set_param(_) (0) + typedef const struct kernel_param zfs_kernel_param_t; -#else -typedef struct kernel_param zfs_kernel_param_t; -#endif #define ZMOD_RW 0644 #define ZMOD_RD 0444 From ab8d9c1783c4fe51f3ef8518f560fedd2c6fab19 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 3 Oct 2022 15:06:54 -0400 Subject: [PATCH 018/126] Cleanup: 64-bit kernel module parameters should use fixed width types Various module parameters such as `zfs_arc_max` were originally `uint64_t` on OpenSolaris/Illumos, but were changed to `unsigned long` for Linux compatibility because Linux's kernel default module parameter implementation did not support 64-bit types on 32-bit platforms. This caused problems when porting OpenZFS to Windows because its LLP64 memory model made `unsigned long` a 32-bit type on 64-bit, which created the undesireable situation that parameters that should accept 64-bit values could not on 64-bit Windows. Upon inspection, it turns out that the Linux kernel module parameter interface is extensible, such that we are allowed to define our own types. Rather than maintaining the original type change via hacks to to continue shrinking module parameters on 32-bit Linux, we implement support for 64-bit module parameters on Linux. After doing a review of all 64-bit kernel parameters (found via the man page and also proposed changes by Andrew Innes), the kernel module parameters fell into a few groups: Parameters that were originally 64-bit on Illumos: * dbuf_cache_max_bytes * dbuf_metadata_cache_max_bytes * l2arc_feed_min_ms * l2arc_feed_secs * l2arc_headroom * l2arc_headroom_boost * l2arc_write_boost * l2arc_write_max * metaslab_aliquot * metaslab_force_ganging * zfetch_array_rd_sz * zfs_arc_max * zfs_arc_meta_limit * zfs_arc_meta_min * zfs_arc_min * zfs_async_block_max_blocks * zfs_condense_max_obsolete_bytes * zfs_condense_min_mapping_bytes * zfs_deadman_checktime_ms * zfs_deadman_synctime_ms * zfs_initialize_chunk_size * zfs_initialize_value * zfs_lua_max_instrlimit * zfs_lua_max_memlimit * zil_slog_bulk Parameters that were originally 32-bit on Illumos: * zfs_per_txg_dirty_frees_percent Parameters that were originally `ssize_t` on Illumos: * zfs_immediate_write_sz Note that `ssize_t` is `int32_t` on 32-bit and `int64_t` on 64-bit. It has been upgraded to 64-bit. Parameters that were `long`/`unsigned long` because of Linux/FreeBSD influence: * l2arc_rebuild_blocks_min_l2size * zfs_key_max_salt_uses * zfs_max_log_walking * zfs_max_logsm_summary_length * zfs_metaslab_max_size_cache_sec * zfs_min_metaslabs_to_flush * zfs_multihost_interval * zfs_unflushed_log_block_max * zfs_unflushed_log_block_min * zfs_unflushed_log_block_pct * zfs_unflushed_max_mem_amt * zfs_unflushed_max_mem_ppm New parameters that do not exist in Illumos: * l2arc_trim_ahead * vdev_file_logical_ashift * vdev_file_physical_ashift * zfs_arc_dnode_limit * zfs_arc_dnode_limit_percent * zfs_arc_dnode_reduce_percent * zfs_arc_meta_limit_percent * zfs_arc_sys_free * zfs_deadman_ziotime_ms * zfs_delete_blocks * zfs_history_output_max * zfs_livelist_max_entries * zfs_max_async_dedup_frees * zfs_max_nvlist_src_size * zfs_rebuild_max_segment * zfs_rebuild_vdev_limit * zfs_unflushed_log_txg_max * zfs_vdev_max_auto_ashift * zfs_vdev_min_auto_ashift * zfs_vnops_read_chunk_size * zvol_max_discard_blocks Rather than clutter the lists with commentary, the module parameters that need comments are repeated below. A few parameters were defined in Linux/FreeBSD specific code, where the use of ulong/long is not an issue for portability, so we leave them alone: * zfs_delete_blocks * zfs_key_max_salt_uses * zvol_max_discard_blocks The documentation for a few parameters was found to be incorrect: * zfs_deadman_checktime_ms - incorrectly documented as int * zfs_delete_blocks - not documented as Linux only * zfs_history_output_max - incorrectly documented as int * zfs_vnops_read_chunk_size - incorrectly documented as long * zvol_max_discard_blocks - incorrectly documented as ulong The documentation for these has been fixed, alongside the changes to document the switch to fixed width types. In addition, several kernel module parameters were percentages or held ashift values, so being 64-bit never made sense for them. They have been downgraded to 32-bit: * vdev_file_logical_ashift * vdev_file_physical_ashift * zfs_arc_dnode_limit_percent * zfs_arc_dnode_reduce_percent * zfs_arc_meta_limit_percent * zfs_per_txg_dirty_frees_percent * zfs_unflushed_log_block_pct * zfs_vdev_max_auto_ashift * zfs_vdev_min_auto_ashift Of special note are `zfs_vdev_max_auto_ashift` and `zfs_vdev_min_auto_ashift`, which were already defined as `uint64_t`, and passed to the kernel as `ulong`. This is inherently buggy on big endian 32-bit Linux, since the values would not be written to the correct locations. 32-bit FreeBSD was unaffected because its sysctl code correctly treated this as a `uint64_t`. Lastly, a code comment suggests that `zfs_arc_sys_free` is Linux-specific, but there is nothing to indicate to me that it is Linux-specific. Nothing was done about that. Reviewed-by: Brian Behlendorf Reviewed-by: Jorgen Lundman Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Original-patch-by: Andrew Innes Original-patch-by: Jorgen Lundman Signed-off-by: Richard Yao Closes #13984 Closes #14004 --- cmd/ztest.c | 6 +- include/os/freebsd/spl/sys/mod_os.h | 18 +-- include/os/linux/kernel/linux/mod_compat.h | 55 ++++++-- include/sys/arc_impl.h | 6 +- include/sys/dmu_zfetch.h | 2 +- include/sys/dsl_deadlist.h | 2 +- include/sys/dsl_pool.h | 8 +- include/sys/mmp.h | 2 +- include/sys/spa.h | 6 +- include/sys/vdev_impl.h | 4 +- include/sys/zcp.h | 4 +- include/sys/zfs_ioctl_impl.h | 2 +- man/man4/zfs.4 | 117 +++++++++--------- module/os/freebsd/zfs/sysctl_os.c | 30 ++--- module/os/freebsd/zfs/vdev_file.c | 8 +- module/os/linux/spl/spl-generic.c | 24 ++++ module/os/linux/zfs/arc_os.c | 8 +- module/os/linux/zfs/mmp_os.c | 2 +- module/os/linux/zfs/spa_misc_os.c | 4 +- module/os/linux/zfs/vdev_disk.c | 12 +- module/os/linux/zfs/vdev_file.c | 8 +- module/zfs/arc.c | 76 ++++++------ module/zfs/dbuf.c | 8 +- module/zfs/dmu.c | 4 +- module/zfs/dmu_zfetch.c | 4 +- module/zfs/dsl_deadlist.c | 4 +- module/zfs/dsl_pool.c | 16 +-- module/zfs/dsl_scan.c | 16 +-- module/zfs/metaslab.c | 12 +- module/zfs/mmp.c | 4 +- module/zfs/spa.c | 4 +- module/zfs/spa_checkpoint.c | 4 +- module/zfs/spa_log_spacemap.c | 36 +++--- module/zfs/spa_misc.c | 12 +- module/zfs/vdev.c | 8 +- module/zfs/vdev_indirect.c | 8 +- module/zfs/vdev_initialize.c | 18 +-- module/zfs/vdev_rebuild.c | 8 +- module/zfs/zcp.c | 8 +- module/zfs/zfs_ioctl.c | 8 +- module/zfs/zfs_log.c | 4 +- module/zfs/zfs_vnops.c | 4 +- module/zfs/zil.c | 4 +- .../cli_root/zpool_add/add-o_ashift.ksh | 6 +- .../cli_root/zpool_add/add_prop_ashift.ksh | 4 +- .../cli_root/zpool_attach/attach-o_ashift.ksh | 4 +- .../zpool_replace/replace-o_ashift.ksh | 4 +- .../zpool_replace/replace_prop_ashift.ksh | 4 +- .../cli_root/zpool_set/zpool_set_ashift.ksh | 4 +- 49 files changed, 338 insertions(+), 286 deletions(-) diff --git a/cmd/ztest.c b/cmd/ztest.c index 25f12f96750e..b89cdde9eda3 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -252,7 +252,7 @@ static const ztest_shared_opts_t ztest_opts_defaults = { extern uint64_t metaslab_force_ganging; extern uint64_t metaslab_df_alloc_threshold; -extern unsigned long zfs_deadman_synctime_ms; +extern uint64_t zfs_deadman_synctime_ms; extern uint_t metaslab_preload_limit; extern int zfs_compressed_arc_enabled; extern int zfs_abd_scatter_enabled; @@ -7119,9 +7119,9 @@ ztest_deadman_thread(void *arg) */ if (spa_suspended(spa) || spa->spa_root_vdev == NULL) { fatal(B_FALSE, - "aborting test after %lu seconds because " + "aborting test after %llu seconds because " "pool has transitioned to a suspended state.", - zfs_deadman_synctime_ms / 1000); + (u_longlong_t)zfs_deadman_synctime_ms / 1000); } vdev_deadman(spa->spa_root_vdev, FTAG); diff --git a/include/os/freebsd/spl/sys/mod_os.h b/include/os/freebsd/spl/sys/mod_os.h index e2815ce9e543..48e8a2adb8d2 100644 --- a/include/os/freebsd/spl/sys/mod_os.h +++ b/include/os/freebsd/spl/sys/mod_os.h @@ -52,17 +52,17 @@ #define ZFS_MODULE_VIRTUAL_PARAM_CALL ZFS_MODULE_PARAM_CALL -#define param_set_arc_long_args(var) \ - CTLTYPE_ULONG, &var, 0, param_set_arc_long, "LU" +#define param_set_arc_u64_args(var) \ + CTLTYPE_U64, &var, 0, param_set_arc_u64, "QU" #define param_set_arc_int_args(var) \ CTLTYPE_INT, &var, 0, param_set_arc_int, "I" #define param_set_arc_min_args(var) \ - CTLTYPE_ULONG, NULL, 0, param_set_arc_min, "LU" + CTLTYPE_U64, NULL, 0, param_set_arc_min, "QU" #define param_set_arc_max_args(var) \ - CTLTYPE_ULONG, NULL, 0, param_set_arc_max, "LU" + CTLTYPE_U64, NULL, 0, param_set_arc_max, "QU" #define param_set_arc_free_target_args(var) \ CTLTYPE_UINT, NULL, 0, param_set_arc_free_target, "IU" @@ -74,22 +74,22 @@ CTLTYPE_STRING, NULL, 0, param_set_deadman_failmode, "A" #define param_set_deadman_synctime_args(var) \ - CTLTYPE_ULONG, NULL, 0, param_set_deadman_synctime, "LU" + CTLTYPE_U64, NULL, 0, param_set_deadman_synctime, "QU" #define param_set_deadman_ziotime_args(var) \ - CTLTYPE_ULONG, NULL, 0, param_set_deadman_ziotime, "LU" + CTLTYPE_U64, NULL, 0, param_set_deadman_ziotime, "QU" #define param_set_multihost_interval_args(var) \ - CTLTYPE_ULONG, NULL, 0, param_set_multihost_interval, "LU" + CTLTYPE_U64, NULL, 0, param_set_multihost_interval, "QU" #define param_set_slop_shift_args(var) \ CTLTYPE_INT, NULL, 0, param_set_slop_shift, "I" #define param_set_min_auto_ashift_args(var) \ - CTLTYPE_U64, NULL, 0, param_set_min_auto_ashift, "QU" + CTLTYPE_UINT, NULL, 0, param_set_min_auto_ashift, "IU" #define param_set_max_auto_ashift_args(var) \ - CTLTYPE_U64, NULL, 0, param_set_max_auto_ashift, "QU" + CTLTYPE_UINT, NULL, 0, param_set_max_auto_ashift, "IU" #define fletcher_4_param_set_args(var) \ CTLTYPE_STRING, NULL, 0, fletcher_4_param, "A" diff --git a/include/os/linux/kernel/linux/mod_compat.h b/include/os/linux/kernel/linux/mod_compat.h index 1b15f9c6e043..67b4fc90653c 100644 --- a/include/os/linux/kernel/linux/mod_compat.h +++ b/include/os/linux/kernel/linux/mod_compat.h @@ -44,14 +44,6 @@ typedef const struct kernel_param zfs_kernel_param_t; #define ZMOD_RW 0644 #define ZMOD_RD 0444 -#define INT int -#define LONG long -/* BEGIN CSTYLED */ -#define UINT uint -#define ULONG ulong -/* END CSTYLED */ -#define STRING charp - enum scope_prefix_types { zfs, zfs_arc, @@ -84,6 +76,50 @@ enum scope_prefix_types { zfs_zil }; +/* + * While we define our own s64/u64 types, there is no reason to reimplement the + * existing Linux kernel types, so we use the preprocessor to remap our + * "custom" implementations to the kernel ones. This is done because the CPP + * does not allow us to write conditional definitions. The fourth definition + * exists because the CPP will not allow us to replace things like INT with int + * before string concatenation. + */ + +#define spl_param_set_int param_set_int +#define spl_param_get_int param_get_int +#define spl_param_ops_int param_ops_int +#define spl_param_ops_INT param_ops_int + +#define spl_param_set_long param_set_long +#define spl_param_get_long param_get_long +#define spl_param_ops_long param_ops_long +#define spl_param_ops_LONG param_ops_long + +#define spl_param_set_uint param_set_uint +#define spl_param_get_uint param_get_uint +#define spl_param_ops_uint param_ops_uint +#define spl_param_ops_UINT param_ops_uint + +#define spl_param_set_ulong param_set_ulong +#define spl_param_get_ulong param_get_ulong +#define spl_param_ops_ulong param_ops_ulong +#define spl_param_ops_ULONG param_ops_ulong + +#define spl_param_set_charp param_set_charp +#define spl_param_get_charp param_get_charp +#define spl_param_ops_charp param_ops_charp +#define spl_param_ops_STRING param_ops_charp + +int spl_param_set_s64(const char *val, zfs_kernel_param_t *kp); +extern int spl_param_get_s64(char *buffer, zfs_kernel_param_t *kp); +extern const struct kernel_param_ops spl_param_ops_s64; +#define spl_param_ops_S64 spl_param_ops_s64 + +extern int spl_param_set_u64(const char *val, zfs_kernel_param_t *kp); +extern int spl_param_get_u64(char *buffer, zfs_kernel_param_t *kp); +extern const struct kernel_param_ops spl_param_ops_u64; +#define spl_param_ops_U64 spl_param_ops_u64 + /* * Declare a module parameter / sysctl node * @@ -116,7 +152,8 @@ enum scope_prefix_types { _Static_assert( \ sizeof (scope_prefix) == sizeof (enum scope_prefix_types), \ "" #scope_prefix " size mismatch with enum scope_prefix_types"); \ - module_param(name_prefix ## name, type, perm); \ + module_param_cb(name_prefix ## name, &spl_param_ops_ ## type, \ + &name_prefix ## name, perm); \ MODULE_PARM_DESC(name_prefix ## name, desc) /* diff --git a/include/sys/arc_impl.h b/include/sys/arc_impl.h index 0f2cd956eb64..03eebafa9952 100644 --- a/include/sys/arc_impl.h +++ b/include/sys/arc_impl.h @@ -985,8 +985,8 @@ extern arc_state_t ARC_mfu; extern arc_state_t ARC_mru; extern uint_t zfs_arc_pc_percent; extern uint_t arc_lotsfree_percent; -extern unsigned long zfs_arc_min; -extern unsigned long zfs_arc_max; +extern uint64_t zfs_arc_min; +extern uint64_t zfs_arc_max; extern void arc_reduce_target_size(int64_t to_free); extern boolean_t arc_reclaim_needed(void); @@ -1003,7 +1003,7 @@ extern void arc_tuning_update(boolean_t); extern void arc_register_hotplug(void); extern void arc_unregister_hotplug(void); -extern int param_set_arc_long(ZFS_MODULE_PARAM_ARGS); +extern int param_set_arc_u64(ZFS_MODULE_PARAM_ARGS); extern int param_set_arc_int(ZFS_MODULE_PARAM_ARGS); extern int param_set_arc_min(ZFS_MODULE_PARAM_ARGS); extern int param_set_arc_max(ZFS_MODULE_PARAM_ARGS); diff --git a/include/sys/dmu_zfetch.h b/include/sys/dmu_zfetch.h index ad3bc040756c..0fbc3bacffb9 100644 --- a/include/sys/dmu_zfetch.h +++ b/include/sys/dmu_zfetch.h @@ -36,7 +36,7 @@ extern "C" { #endif -extern unsigned long zfetch_array_rd_sz; +extern uint64_t zfetch_array_rd_sz; struct dnode; /* so we can reference dnode */ diff --git a/include/sys/dsl_deadlist.h b/include/sys/dsl_deadlist.h index a94bba56ff7a..3feb3bbf062f 100644 --- a/include/sys/dsl_deadlist.h +++ b/include/sys/dsl_deadlist.h @@ -84,7 +84,7 @@ typedef struct livelist_condense_entry { boolean_t cancelled; } livelist_condense_entry_t; -extern unsigned long zfs_livelist_max_entries; +extern uint64_t zfs_livelist_max_entries; extern int zfs_livelist_min_percent_shared; typedef int deadlist_iter_t(void *args, dsl_deadlist_entry_t *dle); diff --git a/include/sys/dsl_pool.h b/include/sys/dsl_pool.h index 9364106d94b7..abcdc77a4b96 100644 --- a/include/sys/dsl_pool.h +++ b/include/sys/dsl_pool.h @@ -57,13 +57,13 @@ struct dsl_scan; struct dsl_crypto_params; struct dsl_deadlist; -extern unsigned long zfs_dirty_data_max; -extern unsigned long zfs_dirty_data_max_max; -extern unsigned long zfs_wrlog_data_max; +extern uint64_t zfs_dirty_data_max; +extern uint64_t zfs_dirty_data_max_max; +extern uint64_t zfs_wrlog_data_max; extern uint_t zfs_dirty_data_max_percent; extern uint_t zfs_dirty_data_max_max_percent; extern uint_t zfs_delay_min_dirty_percent; -extern unsigned long zfs_delay_scale; +extern uint64_t zfs_delay_scale; /* These macros are for indexing into the zfs_all_blkstats_t. */ #define DMU_OT_DEFERRED DMU_OT_NONE diff --git a/include/sys/mmp.h b/include/sys/mmp.h index ce9c4496a04f..1023334098d8 100644 --- a/include/sys/mmp.h +++ b/include/sys/mmp.h @@ -64,7 +64,7 @@ extern void mmp_signal_all_threads(void); /* Global tuning */ extern int param_set_multihost_interval(ZFS_MODULE_PARAM_ARGS); -extern ulong_t zfs_multihost_interval; +extern uint64_t zfs_multihost_interval; extern uint_t zfs_multihost_fail_intervals; extern uint_t zfs_multihost_import_intervals; diff --git a/include/sys/spa.h b/include/sys/spa.h index 3e68cb8c6511..8dcd8895ba22 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -1218,9 +1218,9 @@ int param_set_deadman_failmode(ZFS_MODULE_PARAM_ARGS); extern spa_mode_t spa_mode_global; extern int zfs_deadman_enabled; -extern unsigned long zfs_deadman_synctime_ms; -extern unsigned long zfs_deadman_ziotime_ms; -extern unsigned long zfs_deadman_checktime_ms; +extern uint64_t zfs_deadman_synctime_ms; +extern uint64_t zfs_deadman_ziotime_ms; +extern uint64_t zfs_deadman_checktime_ms; extern kmem_cache_t *zio_buf_cache[]; extern kmem_cache_t *zio_data_buf_cache[]; diff --git a/include/sys/vdev_impl.h b/include/sys/vdev_impl.h index b789d2c05d59..bfa8fe093de2 100644 --- a/include/sys/vdev_impl.h +++ b/include/sys/vdev_impl.h @@ -649,8 +649,8 @@ uint64_t vdev_best_ashift(uint64_t logical, uint64_t a, uint64_t b); /* * Vdev ashift optimization tunables */ -extern uint64_t zfs_vdev_min_auto_ashift; -extern uint64_t zfs_vdev_max_auto_ashift; +extern uint_t zfs_vdev_min_auto_ashift; +extern uint_t zfs_vdev_max_auto_ashift; int param_set_min_auto_ashift(ZFS_MODULE_PARAM_ARGS); int param_set_max_auto_ashift(ZFS_MODULE_PARAM_ARGS); diff --git a/include/sys/zcp.h b/include/sys/zcp.h index f0a78f9cb5c4..6301cc08e7ea 100644 --- a/include/sys/zcp.h +++ b/include/sys/zcp.h @@ -33,8 +33,8 @@ extern "C" { #define ZCP_RUN_INFO_KEY "runinfo" -extern unsigned long zfs_lua_max_instrlimit; -extern unsigned long zfs_lua_max_memlimit; +extern uint64_t zfs_lua_max_instrlimit; +extern uint64_t zfs_lua_max_memlimit; int zcp_argerror(lua_State *, int, const char *, ...); diff --git a/include/sys/zfs_ioctl_impl.h b/include/sys/zfs_ioctl_impl.h index 0bf9fa6ff193..cb852c5577fd 100644 --- a/include/sys/zfs_ioctl_impl.h +++ b/include/sys/zfs_ioctl_impl.h @@ -24,7 +24,7 @@ #define _ZFS_IOCTL_IMPL_H_ extern kmutex_t zfsdev_state_lock; -extern unsigned long zfs_max_nvlist_src_size; +extern uint64_t zfs_max_nvlist_src_size; typedef int zfs_ioc_legacy_func_t(zfs_cmd_t *); typedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *); diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index da1aa9c34287..2bfa3601fbcd 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -26,7 +26,7 @@ .Sh DESCRIPTION The ZFS module supports these parameters: .Bl -tag -width Ds -.It Sy dbuf_cache_max_bytes Ns = Ns Sy ULONG_MAX Ns B Pq ulong +.It Sy dbuf_cache_max_bytes Ns = Ns Sy UINT64_MAX Ns B Pq u64 Maximum size in bytes of the dbuf cache. The target size is determined by the MIN versus .No 1/2^ Ns Sy dbuf_cache_shift Pq 1/32nd @@ -36,7 +36,7 @@ can be observed via the .Pa /proc/spl/kstat/zfs/dbufstats kstat. . -.It Sy dbuf_metadata_cache_max_bytes Ns = Ns Sy ULONG_MAX Ns B Pq ulong +.It Sy dbuf_metadata_cache_max_bytes Ns = Ns Sy UINT64_MAX Ns B Pq u64 Maximum size in bytes of the metadata dbuf cache. The target size is determined by the MIN versus .No 1/2^ Ns Sy dbuf_metadata_cache_shift Pq 1/64th @@ -88,16 +88,16 @@ Alias for Turbo L2ARC warm-up. When the L2ARC is cold the fill interval will be set as fast as possible. . -.It Sy l2arc_feed_min_ms Ns = Ns Sy 200 Pq ulong +.It Sy l2arc_feed_min_ms Ns = Ns Sy 200 Pq u64 Min feed interval in milliseconds. Requires .Sy l2arc_feed_again Ns = Ns Ar 1 and only applicable in related situations. . -.It Sy l2arc_feed_secs Ns = Ns Sy 1 Pq ulong +.It Sy l2arc_feed_secs Ns = Ns Sy 1 Pq u64 Seconds between L2ARC writing. . -.It Sy l2arc_headroom Ns = Ns Sy 2 Pq ulong +.It Sy l2arc_headroom Ns = Ns Sy 2 Pq u64 How far through the ARC lists to search for L2ARC cacheable content, expressed as a multiplier of .Sy l2arc_write_max . @@ -106,7 +106,7 @@ by setting this parameter to .Sy 0 , allowing the full length of ARC lists to be searched for cacheable content. . -.It Sy l2arc_headroom_boost Ns = Ns Sy 200 Ns % Pq ulong +.It Sy l2arc_headroom_boost Ns = Ns Sy 200 Ns % Pq u64 Scales .Sy l2arc_headroom by this percentage when L2ARC contents are being successfully compressed @@ -162,7 +162,7 @@ too many headers on a system with an irrationally large L2ARC can render it slow or unusable. This parameter limits L2ARC writes and rebuilds to achieve the target. . -.It Sy l2arc_trim_ahead Ns = Ns Sy 0 Ns % Pq ulong +.It Sy l2arc_trim_ahead Ns = Ns Sy 0 Ns % Pq u64 Trims ahead of the current write size .Pq Sy l2arc_write_max on L2ARC devices by this percentage of write size if we have filled the device. @@ -200,12 +200,12 @@ to enable caching/reading prefetches to/from L2ARC. .It Sy l2arc_norw Ns = Ns Sy 0 Ns | Ns 1 Pq int No reads during writes. . -.It Sy l2arc_write_boost Ns = Ns Sy 8388608 Ns B Po 8 MiB Pc Pq ulong +.It Sy l2arc_write_boost Ns = Ns Sy 8388608 Ns B Po 8 MiB Pc Pq u64 Cold L2ARC devices will have .Sy l2arc_write_max increased by this amount while they remain cold. . -.It Sy l2arc_write_max Ns = Ns Sy 8388608 Ns B Po 8 MiB Pc Pq ulong +.It Sy l2arc_write_max Ns = Ns Sy 8388608 Ns B Po 8 MiB Pc Pq u64 Max write bytes per interval. . .It Sy l2arc_rebuild_enabled Ns = Ns Sy 1 Ns | Ns 0 Pq int @@ -215,7 +215,7 @@ or attaching an L2ARC device (e.g. the L2ARC device is slow in reading stored log metadata, or the metadata has become somehow fragmented/unusable). . -.It Sy l2arc_rebuild_blocks_min_l2size Ns = Ns Sy 1073741824 Ns B Po 1 GiB Pc Pq ulong +.It Sy l2arc_rebuild_blocks_min_l2size Ns = Ns Sy 1073741824 Ns B Po 1 GiB Pc Pq u64 Mininum size of an L2ARC device required in order to write log blocks in it. The log blocks are used upon importing the pool to rebuild the persistent L2ARC. .Pp @@ -224,7 +224,7 @@ For L2ARC devices less than 1 GiB, the amount of data evicts is significant compared to the amount of restored L2ARC data. In this case, do not write log blocks in L2ARC in order not to waste space. . -.It Sy metaslab_aliquot Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq ulong +.It Sy metaslab_aliquot Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64 Metaslab granularity, in bytes. This is roughly similar to what would be referred to as the "stripe size" in traditional RAID arrays. @@ -235,11 +235,11 @@ before moving on to the next top-level vdev. Enable metaslab group biasing based on their vdevs' over- or under-utilization relative to the pool. . -.It Sy metaslab_force_ganging Ns = Ns Sy 16777217 Ns B Po 16 MiB + 1 B Pc Pq ulong +.It Sy metaslab_force_ganging Ns = Ns Sy 16777217 Ns B Po 16 MiB + 1 B Pc Pq u64 Make some blocks above a certain size be gang blocks. This option is used by the test suite to facilitate testing. . -.It Sy zfs_history_output_max Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq int +.It Sy zfs_history_output_max Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64 When attempting to log an output nvlist of an ioctl in the on-disk history, the output will not be stored if it is larger than this size (in bytes). This must be less than @@ -299,7 +299,7 @@ this tunable controls which segment is used. If set, we will use the largest free segment. If unset, we will use a segment of at least the requested size. . -.It Sy zfs_metaslab_max_size_cache_sec Ns = Ns Sy 3600 Ns s Po 1 hour Pc Pq ulong +.It Sy zfs_metaslab_max_size_cache_sec Ns = Ns Sy 3600 Ns s Po 1 hour Pc Pq u64 When we unload a metaslab, we cache the size of the largest free chunk. We use that cached size to determine whether or not to load a metaslab for a given allocation. @@ -353,14 +353,14 @@ When a vdev is added, target this number of metaslabs per top-level vdev. .It Sy zfs_vdev_default_ms_shift Ns = Ns Sy 29 Po 512 MiB Pc Pq uint Default limit for metaslab size. . -.It Sy zfs_vdev_max_auto_ashift Ns = Ns Sy 14 Pq ulong +.It Sy zfs_vdev_max_auto_ashift Ns = Ns Sy 14 Pq uint Maximum ashift used when optimizing for logical \[->] physical sector size on new top-level vdevs. May be increased up to .Sy ASHIFT_MAX Po 16 Pc , but this may negatively impact pool space efficiency. . -.It Sy zfs_vdev_min_auto_ashift Ns = Ns Sy ASHIFT_MIN Po 9 Pc Pq ulong +.It Sy zfs_vdev_min_auto_ashift Ns = Ns Sy ASHIFT_MIN Po 9 Pc Pq uint Minimum ashift used when creating new top-level vdevs. . .It Sy zfs_vdev_min_ms_count Ns = Ns Sy 16 Pq uint @@ -481,10 +481,10 @@ The default value here was chosen to align with which is a similar concept when doing regular reads (but there's no reason it has to be the same). . -.It Sy vdev_file_logical_ashift Ns = Ns Sy 9 Po 512 B Pc Pq ulong +.It Sy vdev_file_logical_ashift Ns = Ns Sy 9 Po 512 B Pc Pq u64 Logical ashift for file-based devices. . -.It Sy vdev_file_physical_ashift Ns = Ns Sy 9 Po 512 B Pc Pq ulong +.It Sy vdev_file_physical_ashift Ns = Ns Sy 9 Po 512 B Pc Pq u64 Physical ashift for file-based devices. . .It Sy zap_iterate_prefetch Ns = Ns Sy 1 Ns | Ns 0 Pq int @@ -493,7 +493,7 @@ prefetch the entire object (all leaf blocks). However, this is limited by .Sy dmu_prefetch_max . . -.It Sy zfetch_array_rd_sz Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq ulong +.It Sy zfetch_array_rd_sz Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64 If prefetching is enabled, disable prefetching for reads larger than this size. . .It Sy zfetch_min_distance Ns = Ns Sy 4194304 Ns B Po 4 MiB Pc Pq uint @@ -537,7 +537,7 @@ depends on kernel configuration. This is the minimum allocation size that will use scatter (page-based) ABDs. Smaller allocations will use linear ABDs. . -.It Sy zfs_arc_dnode_limit Ns = Ns Sy 0 Ns B Pq ulong +.It Sy zfs_arc_dnode_limit Ns = Ns Sy 0 Ns B Pq u64 When the number of bytes consumed by dnodes in the ARC exceeds this number of bytes, try to unpin some of it in response to demand for non-metadata. This value acts as a ceiling to the amount of dnode metadata, and defaults to @@ -553,14 +553,14 @@ when the amount of metadata in the ARC exceeds .Sy zfs_arc_meta_limit rather than in response to overall demand for non-metadata. . -.It Sy zfs_arc_dnode_limit_percent Ns = Ns Sy 10 Ns % Pq ulong +.It Sy zfs_arc_dnode_limit_percent Ns = Ns Sy 10 Ns % Pq u64 Percentage that can be consumed by dnodes of ARC meta buffers. .Pp See also .Sy zfs_arc_dnode_limit , which serves a similar purpose but has a higher priority if nonzero. . -.It Sy zfs_arc_dnode_reduce_percent Ns = Ns Sy 10 Ns % Pq ulong +.It Sy zfs_arc_dnode_reduce_percent Ns = Ns Sy 10 Ns % Pq u64 Percentage of ARC dnodes to try to scan in response to demand for non-metadata when the number of bytes consumed by dnodes exceeds .Sy zfs_arc_dnode_limit . @@ -613,7 +613,7 @@ Setting this value to .Sy 0 will disable the throttle. . -.It Sy zfs_arc_max Ns = Ns Sy 0 Ns B Pq ulong +.It Sy zfs_arc_max Ns = Ns Sy 0 Ns B Pq u64 Max size of ARC in bytes. If .Sy 0 , @@ -642,7 +642,7 @@ the free buffers in order to stay below the This value should not need to be tuned but is available to facilitate performance analysis. . -.It Sy zfs_arc_meta_limit Ns = Ns Sy 0 Ns B Pq ulong +.It Sy zfs_arc_meta_limit Ns = Ns Sy 0 Ns B Pq u64 The maximum allowed size in bytes that metadata buffers are allowed to consume in the ARC. When this limit is reached, metadata buffers will be reclaimed, @@ -658,14 +658,14 @@ of the ARC may be used for metadata. This value my be changed dynamically, except that must be set to an explicit value .Pq cannot be set back to Sy 0 . . -.It Sy zfs_arc_meta_limit_percent Ns = Ns Sy 75 Ns % Pq ulong +.It Sy zfs_arc_meta_limit_percent Ns = Ns Sy 75 Ns % Pq u64 Percentage of ARC buffers that can be used for metadata. .Pp See also .Sy zfs_arc_meta_limit , which serves a similar purpose but has a higher priority if nonzero. . -.It Sy zfs_arc_meta_min Ns = Ns Sy 0 Ns B Pq ulong +.It Sy zfs_arc_meta_min Ns = Ns Sy 0 Ns B Pq u64 The minimum allowed size in bytes that metadata buffers may consume in the ARC. . @@ -691,7 +691,7 @@ additional data buffers may be evicted if required to evict the required number of metadata buffers. .El . -.It Sy zfs_arc_min Ns = Ns Sy 0 Ns B Pq ulong +.It Sy zfs_arc_min Ns = Ns Sy 0 Ns B Pq u64 Min size of ARC in bytes. .No If set to Sy 0 , arc_c_min will default to consuming the larger of @@ -718,7 +718,7 @@ but that was not proven to be useful. Number of missing top-level vdevs which will be allowed during pool import (only in read-only mode). . -.It Sy zfs_max_nvlist_src_size Ns = Sy 0 Pq ulong +.It Sy zfs_max_nvlist_src_size Ns = Sy 0 Pq u64 Maximum size in bytes allowed to be passed as .Sy zc_nvlist_src_size for ioctls on @@ -822,7 +822,7 @@ even with a small average compressed block size of ~8 KiB. The parameter can be set to 0 (zero) to disable the limit, and only applies on Linux. . -.It Sy zfs_arc_sys_free Ns = Ns Sy 0 Ns B Pq ulong +.It Sy zfs_arc_sys_free Ns = Ns Sy 0 Ns B Pq u64 The target number of bytes the ARC should leave as free memory on the system. If zero, equivalent to the bigger of .Sy 512 KiB No and Sy all_system_memory/64 . @@ -866,12 +866,12 @@ bytes of memory and if the obsolete space map object uses more than bytes on-disk. The condensing process is an attempt to save memory by removing obsolete mappings. . -.It Sy zfs_condense_max_obsolete_bytes Ns = Ns Sy 1073741824 Ns B Po 1 GiB Pc Pq ulong +.It Sy zfs_condense_max_obsolete_bytes Ns = Ns Sy 1073741824 Ns B Po 1 GiB Pc Pq u64 Only attempt to condense indirect vdev mappings if the on-disk size of the obsolete space map object is greater than this number of bytes .Pq see Sy zfs_condense_indirect_vdevs_enable . . -.It Sy zfs_condense_min_mapping_bytes Ns = Ns Sy 131072 Ns B Po 128 KiB Pc Pq ulong +.It Sy zfs_condense_min_mapping_bytes Ns = Ns Sy 131072 Ns B Po 128 KiB Pc Pq u64 Minimum size vdev mapping to attempt to condense .Pq see Sy zfs_condense_indirect_vdevs_enable . . @@ -927,21 +927,21 @@ This can be used to facilitate automatic fail-over to a properly configured fail-over partner. .El . -.It Sy zfs_deadman_checktime_ms Ns = Ns Sy 60000 Ns ms Po 1 min Pc Pq int +.It Sy zfs_deadman_checktime_ms Ns = Ns Sy 60000 Ns ms Po 1 min Pc Pq u64 Check time in milliseconds. This defines the frequency at which we check for hung I/O requests and potentially invoke the .Sy zfs_deadman_failmode behavior. . -.It Sy zfs_deadman_synctime_ms Ns = Ns Sy 600000 Ns ms Po 10 min Pc Pq ulong +.It Sy zfs_deadman_synctime_ms Ns = Ns Sy 600000 Ns ms Po 10 min Pc Pq u64 Interval in milliseconds after which the deadman is triggered and also the interval after which a pool sync operation is considered to be "hung". Once this limit is exceeded the deadman will be invoked every .Sy zfs_deadman_checktime_ms milliseconds until the pool sync completes. . -.It Sy zfs_deadman_ziotime_ms Ns = Ns Sy 300000 Ns ms Po 5 min Pc Pq ulong +.It Sy zfs_deadman_ziotime_ms Ns = Ns Sy 300000 Ns ms Po 5 min Pc Pq u64 Interval in milliseconds after which the deadman is triggered and an individual I/O operation is considered to be "hung". As long as the operation remains "hung", @@ -994,15 +994,15 @@ same object. Rate limit delay and deadman zevents (which report slow I/O operations) to this many per second. . -.It Sy zfs_unflushed_max_mem_amt Ns = Ns Sy 1073741824 Ns B Po 1 GiB Pc Pq ulong +.It Sy zfs_unflushed_max_mem_amt Ns = Ns Sy 1073741824 Ns B Po 1 GiB Pc Pq u64 Upper-bound limit for unflushed metadata changes to be held by the log spacemap in memory, in bytes. . -.It Sy zfs_unflushed_max_mem_ppm Ns = Ns Sy 1000 Ns ppm Po 0.1% Pc Pq ulong +.It Sy zfs_unflushed_max_mem_ppm Ns = Ns Sy 1000 Ns ppm Po 0.1% Pc Pq u64 Part of overall system memory that ZFS allows to be used for unflushed metadata changes by the log spacemap, in millionths. . -.It Sy zfs_unflushed_log_block_max Ns = Ns Sy 131072 Po 128k Pc Pq ulong +.It Sy zfs_unflushed_log_block_max Ns = Ns Sy 131072 Po 128k Pc Pq u64 Describes the maximum number of log spacemap blocks allowed for each pool. The default value means that the space in all the log spacemaps can add up to no more than @@ -1030,17 +1030,17 @@ one extra logical I/O issued. This is the reason why this tunable is exposed in terms of blocks rather than space used. . -.It Sy zfs_unflushed_log_block_min Ns = Ns Sy 1000 Pq ulong +.It Sy zfs_unflushed_log_block_min Ns = Ns Sy 1000 Pq u64 If the number of metaslabs is small and our incoming rate is high, we could get into a situation that we are flushing all our metaslabs every TXG. Thus we always allow at least this many log blocks. . -.It Sy zfs_unflushed_log_block_pct Ns = Ns Sy 400 Ns % Pq ulong +.It Sy zfs_unflushed_log_block_pct Ns = Ns Sy 400 Ns % Pq u64 Tunable used to determine the number of blocks that can be used for the spacemap log, expressed as a percentage of the total number of unflushed metaslabs in the pool. . -.It Sy zfs_unflushed_log_txg_max Ns = Ns Sy 1000 Pq ulong +.It Sy zfs_unflushed_log_txg_max Ns = Ns Sy 1000 Pq u64 Tunable limiting maximum time in TXGs any metaslab may remain unflushed. It effectively limits maximum number of unflushed per-TXG spacemap logs that need to be read after unclean pool export. @@ -1060,6 +1060,7 @@ will be deleted asynchronously, while smaller files are deleted synchronously. Decreasing this value will reduce the time spent in an .Xr unlink 2 system call, at the expense of a longer delay before the freed space is available. +This only applies on Linux. . .It Sy zfs_dirty_data_max Ns = Pq int Determines the dirty space limit in bytes. @@ -1185,10 +1186,10 @@ benchmark results by reading this kstat file: .It Sy zfs_free_bpobj_enabled Ns = Ns Sy 1 Ns | Ns 0 Pq int Enable/disable the processing of the free_bpobj object. . -.It Sy zfs_async_block_max_blocks Ns = Ns Sy ULONG_MAX Po unlimited Pc Pq ulong +.It Sy zfs_async_block_max_blocks Ns = Ns Sy UINT64_MAX Po unlimited Pc Pq u64 Maximum number of blocks freed in a single TXG. . -.It Sy zfs_max_async_dedup_frees Ns = Ns Sy 100000 Po 10^5 Pc Pq ulong +.It Sy zfs_max_async_dedup_frees Ns = Ns Sy 100000 Po 10^5 Pc Pq u64 Maximum number of dedup blocks freed in a single TXG. . .It Sy zfs_vdev_async_read_max_active Ns = Ns Sy 3 Pq uint @@ -1444,22 +1445,22 @@ Similar to .Sy zfs_free_min_time_ms , but for cleanup of old indirection records for removed vdevs. . -.It Sy zfs_immediate_write_sz Ns = Ns Sy 32768 Ns B Po 32 KiB Pc Pq long +.It Sy zfs_immediate_write_sz Ns = Ns Sy 32768 Ns B Po 32 KiB Pc Pq s64 Largest data block to write to the ZIL. Larger blocks will be treated as if the dataset being written to had the .Sy logbias Ns = Ns Sy throughput property set. . -.It Sy zfs_initialize_value Ns = Ns Sy 16045690984833335022 Po 0xDEADBEEFDEADBEEE Pc Pq ulong +.It Sy zfs_initialize_value Ns = Ns Sy 16045690984833335022 Po 0xDEADBEEFDEADBEEE Pc Pq u64 Pattern written to vdev free space by .Xr zpool-initialize 8 . . -.It Sy zfs_initialize_chunk_size Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq ulong +.It Sy zfs_initialize_chunk_size Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64 Size of writes used by .Xr zpool-initialize 8 . This option is used by the test suite. . -.It Sy zfs_livelist_max_entries Ns = Ns Sy 500000 Po 5*10^5 Pc Pq ulong +.It Sy zfs_livelist_max_entries Ns = Ns Sy 500000 Po 5*10^5 Pc Pq u64 The threshold size (in block pointers) at which we create a new sub-livelist. Larger sublists are more costly from a memory perspective but the fewer sublists there are, the lower the cost of insertion. @@ -1498,11 +1499,11 @@ executing the open context condensing work in .Fn spa_livelist_condense_cb . This option is used by the test suite to trigger race conditions. . -.It Sy zfs_lua_max_instrlimit Ns = Ns Sy 100000000 Po 10^8 Pc Pq ulong +.It Sy zfs_lua_max_instrlimit Ns = Ns Sy 100000000 Po 10^8 Pc Pq u64 The maximum execution time limit that can be set for a ZFS channel program, specified as a number of Lua instructions. . -.It Sy zfs_lua_max_memlimit Ns = Ns Sy 104857600 Po 100 MiB Pc Pq ulong +.It Sy zfs_lua_max_memlimit Ns = Ns Sy 104857600 Po 100 MiB Pc Pq u64 The maximum memory limit that can be set for a ZFS channel program, specified in bytes. . @@ -1511,11 +1512,11 @@ The maximum depth of nested datasets. This value can be tuned temporarily to fix existing datasets that exceed the predefined limit. . -.It Sy zfs_max_log_walking Ns = Ns Sy 5 Pq ulong +.It Sy zfs_max_log_walking Ns = Ns Sy 5 Pq u64 The number of past TXGs that the flushing algorithm of the log spacemap feature uses to estimate incoming log blocks. . -.It Sy zfs_max_logsm_summary_length Ns = Ns Sy 10 Pq ulong +.It Sy zfs_max_logsm_summary_length Ns = Ns Sy 10 Pq u64 Maximum number of rows allowed in the summary of the spacemap log. . .It Sy zfs_max_recordsize Ns = Ns Sy 16777216 Po 16 MiB Pc Pq uint @@ -1534,7 +1535,7 @@ regardless of this setting. Allow datasets received with redacted send/receive to be mounted. Normally disabled because these datasets may be missing key data. . -.It Sy zfs_min_metaslabs_to_flush Ns = Ns Sy 1 Pq ulong +.It Sy zfs_min_metaslabs_to_flush Ns = Ns Sy 1 Pq u64 Minimum number of metaslabs to flush per dirty TXG. . .It Sy zfs_metaslab_fragmentation_threshold Ns = Ns Sy 70 Ns % Pq uint @@ -1584,7 +1585,7 @@ into the special allocation class. Historical statistics for this many latest multihost updates will be available in .Pa /proc/spl/kstat/zfs/ Ns Ao Ar pool Ac Ns Pa /multihost . . -.It Sy zfs_multihost_interval Ns = Ns Sy 1000 Ns ms Po 1 s Pc Pq ulong +.It Sy zfs_multihost_interval Ns = Ns Sy 1000 Ns ms Po 1 s Pc Pq u64 Used to control the frequency of multihost writes which are performed when the .Sy multihost pool property is on. @@ -1677,7 +1678,7 @@ prefetched during a pool traversal, like .Nm zfs Cm send or other data crawling operations. . -.It Sy zfs_per_txg_dirty_frees_percent Ns = Ns Sy 30 Ns % Pq ulong +.It Sy zfs_per_txg_dirty_frees_percent Ns = Ns Sy 30 Ns % Pq u64 Control percentage of dirtied indirect blocks from frees allowed into one TXG. After this threshold is crossed, additional frees will wait until the next TXG. .Sy 0 No disables this throttle. @@ -1705,7 +1706,7 @@ Disable QAT hardware acceleration for AES-GCM encryption. May be unset after the ZFS modules have been loaded to initialize the QAT hardware as long as support is compiled in and the QAT driver is present. . -.It Sy zfs_vnops_read_chunk_size Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq long +.It Sy zfs_vnops_read_chunk_size Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64 Bytes to read per chunk. . .It Sy zfs_read_history Ns = Ns Sy 0 Pq uint @@ -1715,7 +1716,7 @@ Historical statistics for this many latest reads will be available in .It Sy zfs_read_history_hits Ns = Ns Sy 0 Ns | Ns 1 Pq int Include cache hits in read history . -.It Sy zfs_rebuild_max_segment Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq ulong +.It Sy zfs_rebuild_max_segment Ns = Ns Sy 1048576 Ns B Po 1 MiB Pc Pq u64 Maximum read segment size to issue when sequentially resilvering a top-level vdev. . @@ -1725,7 +1726,7 @@ completes in order to verify the checksums of all blocks which have been resilvered. This is enabled by default and strongly recommended. . -.It Sy zfs_rebuild_vdev_limit Ns = Ns Sy 33554432 Ns B Po 32 MiB Pc Pq ulong +.It Sy zfs_rebuild_vdev_limit Ns = Ns Sy 33554432 Ns B Po 32 MiB Pc Pq u64 Maximum amount of I/O that can be concurrently issued for a sequential resilver per leaf device, given in bytes. . @@ -2166,7 +2167,7 @@ if a volatile out-of-order write cache is enabled. Disable intent logging replay. Can be disabled for recovery from corrupted ZIL. . -.It Sy zil_slog_bulk Ns = Ns Sy 786432 Ns B Po 768 KiB Pc Pq ulong +.It Sy zil_slog_bulk Ns = Ns Sy 786432 Ns B Po 768 KiB Pc Pq u64 Limit SLOG write size per commit executed with synchronous priority. Any writes above that will be executed with lower (asynchronous) priority to limit potential SLOG device abuse by single active ZIL writer. @@ -2276,7 +2277,7 @@ systems with a very large number of zvols. .It Sy zvol_major Ns = Ns Sy 230 Pq uint Major number for zvol block devices. . -.It Sy zvol_max_discard_blocks Ns = Ns Sy 16384 Pq ulong +.It Sy zvol_max_discard_blocks Ns = Ns Sy 16384 Pq long Discard (TRIM) operations done on zvols will be done in batches of this many blocks, where block size is determined by the .Sy volblocksize diff --git a/module/os/freebsd/zfs/sysctl_os.c b/module/os/freebsd/zfs/sysctl_os.c index 980bb1c0f941..48af1eaf8ea7 100644 --- a/module/os/freebsd/zfs/sysctl_os.c +++ b/module/os/freebsd/zfs/sysctl_os.c @@ -137,11 +137,11 @@ SYSCTL_CONST_STRING(_vfs_zfs_version, OID_AUTO, module, CTLFLAG_RD, /* arc.c */ int -param_set_arc_long(SYSCTL_HANDLER_ARGS) +param_set_arc_u64(SYSCTL_HANDLER_ARGS) { int err; - err = sysctl_handle_long(oidp, arg1, 0, req); + err = sysctl_handle_64(oidp, arg1, 0, req); if (err != 0 || req->newptr == NULL) return (err); @@ -171,7 +171,7 @@ param_set_arc_max(SYSCTL_HANDLER_ARGS) int err; val = zfs_arc_max; - err = sysctl_handle_long(oidp, &val, 0, req); + err = sysctl_handle_64(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (SET_ERROR(err)); @@ -203,7 +203,7 @@ param_set_arc_min(SYSCTL_HANDLER_ARGS) int err; val = zfs_arc_min; - err = sysctl_handle_long(oidp, &val, 0, req); + err = sysctl_handle_64(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (SET_ERROR(err)); @@ -599,7 +599,7 @@ param_set_multihost_interval(SYSCTL_HANDLER_ARGS) { int err; - err = sysctl_handle_long(oidp, &zfs_multihost_interval, 0, req); + err = sysctl_handle_64(oidp, &zfs_multihost_interval, 0, req); if (err != 0 || req->newptr == NULL) return (err); @@ -676,7 +676,7 @@ param_set_deadman_synctime(SYSCTL_HANDLER_ARGS) int err; val = zfs_deadman_synctime_ms; - err = sysctl_handle_long(oidp, &val, 0, req); + err = sysctl_handle_64(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (err); zfs_deadman_synctime_ms = val; @@ -693,7 +693,7 @@ param_set_deadman_ziotime(SYSCTL_HANDLER_ARGS) int err; val = zfs_deadman_ziotime_ms; - err = sysctl_handle_long(oidp, &val, 0, req); + err = sysctl_handle_64(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (err); zfs_deadman_ziotime_ms = val; @@ -761,11 +761,11 @@ SYSCTL_INT(_vfs_zfs, OID_AUTO, space_map_ibs, CTLFLAG_RWTUN, int param_set_min_auto_ashift(SYSCTL_HANDLER_ARGS) { - uint64_t val; + int val; int err; val = zfs_vdev_min_auto_ashift; - err = sysctl_handle_64(oidp, &val, 0, req); + err = sysctl_handle_int(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (SET_ERROR(err)); @@ -779,20 +779,20 @@ param_set_min_auto_ashift(SYSCTL_HANDLER_ARGS) /* BEGIN CSTYLED */ SYSCTL_PROC(_vfs_zfs, OID_AUTO, min_auto_ashift, - CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, + CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &zfs_vdev_min_auto_ashift, sizeof (zfs_vdev_min_auto_ashift), - param_set_min_auto_ashift, "QU", + param_set_min_auto_ashift, "IU", "Min ashift used when creating new top-level vdev. (LEGACY)"); /* END CSTYLED */ int param_set_max_auto_ashift(SYSCTL_HANDLER_ARGS) { - uint64_t val; + int val; int err; val = zfs_vdev_max_auto_ashift; - err = sysctl_handle_64(oidp, &val, 0, req); + err = sysctl_handle_int(oidp, &val, 0, req); if (err != 0 || req->newptr == NULL) return (SET_ERROR(err)); @@ -806,9 +806,9 @@ param_set_max_auto_ashift(SYSCTL_HANDLER_ARGS) /* BEGIN CSTYLED */ SYSCTL_PROC(_vfs_zfs, OID_AUTO, max_auto_ashift, - CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, + CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, &zfs_vdev_max_auto_ashift, sizeof (zfs_vdev_max_auto_ashift), - param_set_max_auto_ashift, "QU", + param_set_max_auto_ashift, "IU", "Max ashift used when optimizing for logical -> physical sector size on" " new top-level vdevs. (LEGACY)"); /* END CSTYLED */ diff --git a/module/os/freebsd/zfs/vdev_file.c b/module/os/freebsd/zfs/vdev_file.c index 73cc6aa48c0b..a65dfec86caf 100644 --- a/module/os/freebsd/zfs/vdev_file.c +++ b/module/os/freebsd/zfs/vdev_file.c @@ -40,8 +40,8 @@ static taskq_t *vdev_file_taskq; -static unsigned long vdev_file_logical_ashift = SPA_MINBLOCKSHIFT; -static unsigned long vdev_file_physical_ashift = SPA_MINBLOCKSHIFT; +static uint_t vdev_file_logical_ashift = SPA_MINBLOCKSHIFT; +static uint_t vdev_file_physical_ashift = SPA_MINBLOCKSHIFT; void vdev_file_init(void) @@ -350,7 +350,7 @@ vdev_ops_t vdev_disk_ops = { #endif -ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, UINT, ZMOD_RW, "Logical ashift for file-based devices"); -ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, UINT, ZMOD_RW, "Physical ashift for file-based devices"); diff --git a/module/os/linux/spl/spl-generic.c b/module/os/linux/spl/spl-generic.c index bc39ece9a427..6efaec592b8b 100644 --- a/module/os/linux/spl/spl-generic.c +++ b/module/os/linux/spl/spl-generic.c @@ -48,6 +48,7 @@ #include #include #include +#include unsigned long spl_hostid = 0; EXPORT_SYMBOL(spl_hostid); @@ -518,6 +519,29 @@ ddi_copyin(const void *from, void *to, size_t len, int flags) } EXPORT_SYMBOL(ddi_copyin); +#define define_spl_param(type, fmt) \ +int \ +spl_param_get_##type(char *buf, zfs_kernel_param_t *kp) \ +{ \ + return (scnprintf(buf, PAGE_SIZE, fmt "\n", \ + *(type *)kp->arg)); \ +} \ +int \ +spl_param_set_##type(const char *buf, zfs_kernel_param_t *kp) \ +{ \ + return (kstrto##type(buf, 0, (type *)kp->arg)); \ +} \ +const struct kernel_param_ops spl_param_ops_##type = { \ + .set = spl_param_set_##type, \ + .get = spl_param_get_##type, \ +}; \ +EXPORT_SYMBOL(spl_param_get_##type); \ +EXPORT_SYMBOL(spl_param_set_##type); \ +EXPORT_SYMBOL(spl_param_ops_##type); + +define_spl_param(s64, "%lld") +define_spl_param(u64, "%llu") + /* * Post a uevent to userspace whenever a new vdev adds to the pool. It is * necessary to sync blkid information with udev, which zed daemon uses diff --git a/module/os/linux/zfs/arc_os.c b/module/os/linux/zfs/arc_os.c index eaaf7d0bb746..6f730e9ddd83 100644 --- a/module/os/linux/zfs/arc_os.c +++ b/module/os/linux/zfs/arc_os.c @@ -358,11 +358,11 @@ arc_lowmem_fini(void) } int -param_set_arc_long(const char *buf, zfs_kernel_param_t *kp) +param_set_arc_u64(const char *buf, zfs_kernel_param_t *kp) { int error; - error = param_set_long(buf, kp); + error = spl_param_set_u64(buf, kp); if (error < 0) return (SET_ERROR(error)); @@ -374,13 +374,13 @@ param_set_arc_long(const char *buf, zfs_kernel_param_t *kp) int param_set_arc_min(const char *buf, zfs_kernel_param_t *kp) { - return (param_set_arc_long(buf, kp)); + return (param_set_arc_u64(buf, kp)); } int param_set_arc_max(const char *buf, zfs_kernel_param_t *kp) { - return (param_set_arc_long(buf, kp)); + return (param_set_arc_u64(buf, kp)); } int diff --git a/module/os/linux/zfs/mmp_os.c b/module/os/linux/zfs/mmp_os.c index d502127b5ba3..7e5bd392437e 100644 --- a/module/os/linux/zfs/mmp_os.c +++ b/module/os/linux/zfs/mmp_os.c @@ -30,7 +30,7 @@ param_set_multihost_interval(const char *val, zfs_kernel_param_t *kp) { int ret; - ret = param_set_ulong(val, kp); + ret = spl_param_set_u64(val, kp); if (ret < 0) return (ret); diff --git a/module/os/linux/zfs/spa_misc_os.c b/module/os/linux/zfs/spa_misc_os.c index f999df3b7db9..3efc8b9644fd 100644 --- a/module/os/linux/zfs/spa_misc_os.c +++ b/module/os/linux/zfs/spa_misc_os.c @@ -60,7 +60,7 @@ param_set_deadman_ziotime(const char *val, zfs_kernel_param_t *kp) { int error; - error = param_set_ulong(val, kp); + error = spl_param_set_u64(val, kp); if (error < 0) return (SET_ERROR(error)); @@ -74,7 +74,7 @@ param_set_deadman_synctime(const char *val, zfs_kernel_param_t *kp) { int error; - error = param_set_ulong(val, kp); + error = spl_param_set_u64(val, kp); if (error < 0) return (SET_ERROR(error)); diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c index 0fed09df5203..349ef392dc0a 100644 --- a/module/os/linux/zfs/vdev_disk.c +++ b/module/os/linux/zfs/vdev_disk.c @@ -1006,17 +1006,17 @@ MODULE_PARM_DESC(zfs_vdev_scheduler, "I/O scheduler"); int param_set_min_auto_ashift(const char *buf, zfs_kernel_param_t *kp) { - uint64_t val; + uint_t val; int error; - error = kstrtoull(buf, 0, &val); + error = kstrtouint(buf, 0, &val); if (error < 0) return (SET_ERROR(error)); if (val < ASHIFT_MIN || val > zfs_vdev_max_auto_ashift) return (SET_ERROR(-EINVAL)); - error = param_set_ulong(buf, kp); + error = param_set_uint(buf, kp); if (error < 0) return (SET_ERROR(error)); @@ -1026,17 +1026,17 @@ param_set_min_auto_ashift(const char *buf, zfs_kernel_param_t *kp) int param_set_max_auto_ashift(const char *buf, zfs_kernel_param_t *kp) { - uint64_t val; + uint_t val; int error; - error = kstrtoull(buf, 0, &val); + error = kstrtouint(buf, 0, &val); if (error < 0) return (SET_ERROR(error)); if (val > ASHIFT_MAX || val < zfs_vdev_min_auto_ashift) return (SET_ERROR(-EINVAL)); - error = param_set_ulong(buf, kp); + error = param_set_uint(buf, kp); if (error < 0) return (SET_ERROR(error)); diff --git a/module/os/linux/zfs/vdev_file.c b/module/os/linux/zfs/vdev_file.c index 46e412f6eeb4..5abc0426d1a7 100644 --- a/module/os/linux/zfs/vdev_file.c +++ b/module/os/linux/zfs/vdev_file.c @@ -53,8 +53,8 @@ static taskq_t *vdev_file_taskq; * impact the vdev_ashift setting which can only be set at vdev creation * time. */ -static unsigned long vdev_file_logical_ashift = SPA_MINBLOCKSHIFT; -static unsigned long vdev_file_physical_ashift = SPA_MINBLOCKSHIFT; +static uint_t vdev_file_logical_ashift = SPA_MINBLOCKSHIFT; +static uint_t vdev_file_physical_ashift = SPA_MINBLOCKSHIFT; static void vdev_file_hold(vdev_t *vd) @@ -376,7 +376,7 @@ vdev_ops_t vdev_disk_ops = { #endif -ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, logical_ashift, UINT, ZMOD_RW, "Logical ashift for file-based devices"); -ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_vdev_file, vdev_file_, physical_ashift, UINT, ZMOD_RW, "Physical ashift for file-based devices"); diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 9254d8b84902..58fb36207313 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -419,12 +419,12 @@ boolean_t arc_warm; /* * These tunables are for performance analysis. */ -unsigned long zfs_arc_max = 0; -unsigned long zfs_arc_min = 0; -unsigned long zfs_arc_meta_limit = 0; -unsigned long zfs_arc_meta_min = 0; -static unsigned long zfs_arc_dnode_limit = 0; -static unsigned long zfs_arc_dnode_reduce_percent = 10; +uint64_t zfs_arc_max = 0; +uint64_t zfs_arc_min = 0; +uint64_t zfs_arc_meta_limit = 0; +uint64_t zfs_arc_meta_min = 0; +static uint64_t zfs_arc_dnode_limit = 0; +static uint_t zfs_arc_dnode_reduce_percent = 10; static uint_t zfs_arc_grow_retry = 0; static uint_t zfs_arc_shrink_shift = 0; static uint_t zfs_arc_p_min_shift = 0; @@ -449,17 +449,17 @@ int zfs_compressed_arc_enabled = B_TRUE; * ARC will evict meta buffers that exceed arc_meta_limit. This * tunable make arc_meta_limit adjustable for different workloads. */ -static unsigned long zfs_arc_meta_limit_percent = 75; +static uint64_t zfs_arc_meta_limit_percent = 75; /* * Percentage that can be consumed by dnodes of ARC meta buffers. */ -static unsigned long zfs_arc_dnode_limit_percent = 10; +static uint_t zfs_arc_dnode_limit_percent = 10; /* * These tunables are Linux-specific */ -static unsigned long zfs_arc_sys_free = 0; +static uint64_t zfs_arc_sys_free = 0; static uint_t zfs_arc_min_prefetch_ms = 0; static uint_t zfs_arc_min_prescient_prefetch_ms = 0; static int zfs_arc_p_dampener_disable = 1; @@ -781,12 +781,12 @@ uint64_t zfs_crc64_table[256]; #define L2ARC_FEED_TYPES 4 /* L2ARC Performance Tunables */ -unsigned long l2arc_write_max = L2ARC_WRITE_SIZE; /* def max write size */ -unsigned long l2arc_write_boost = L2ARC_WRITE_SIZE; /* extra warmup write */ -unsigned long l2arc_headroom = L2ARC_HEADROOM; /* # of dev writes */ -unsigned long l2arc_headroom_boost = L2ARC_HEADROOM_BOOST; -unsigned long l2arc_feed_secs = L2ARC_FEED_SECS; /* interval seconds */ -unsigned long l2arc_feed_min_ms = L2ARC_FEED_MIN_MS; /* min interval msecs */ +uint64_t l2arc_write_max = L2ARC_WRITE_SIZE; /* def max write size */ +uint64_t l2arc_write_boost = L2ARC_WRITE_SIZE; /* extra warmup write */ +uint64_t l2arc_headroom = L2ARC_HEADROOM; /* # of dev writes */ +uint64_t l2arc_headroom_boost = L2ARC_HEADROOM_BOOST; +uint64_t l2arc_feed_secs = L2ARC_FEED_SECS; /* interval seconds */ +uint64_t l2arc_feed_min_ms = L2ARC_FEED_MIN_MS; /* min interval msecs */ int l2arc_noprefetch = B_TRUE; /* don't cache prefetch bufs */ int l2arc_feed_again = B_TRUE; /* turbo warmup */ int l2arc_norw = B_FALSE; /* no reads during writes */ @@ -909,7 +909,7 @@ static int l2arc_mfuonly = 0; * will vary depending of how well the specific device handles * these commands. */ -static unsigned long l2arc_trim_ahead = 0; +static uint64_t l2arc_trim_ahead = 0; /* * Performance tuning of L2ARC persistence: @@ -925,7 +925,7 @@ static unsigned long l2arc_trim_ahead = 0; * not to waste space. */ static int l2arc_rebuild_enabled = B_TRUE; -static unsigned long l2arc_rebuild_blocks_min_l2size = 1024 * 1024 * 1024; +static uint64_t l2arc_rebuild_blocks_min_l2size = 1024 * 1024 * 1024; /* L2ARC persistence rebuild control routines. */ void l2arc_rebuild_vdev(vdev_t *vd, boolean_t reopen); @@ -11077,20 +11077,20 @@ EXPORT_SYMBOL(arc_add_prune_callback); EXPORT_SYMBOL(arc_remove_prune_callback); ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min, param_set_arc_min, - param_get_ulong, ZMOD_RW, "Minimum ARC size in bytes"); + spl_param_get_u64, ZMOD_RW, "Minimum ARC size in bytes"); ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, max, param_set_arc_max, - param_get_ulong, ZMOD_RW, "Maximum ARC size in bytes"); + spl_param_get_u64, ZMOD_RW, "Maximum ARC size in bytes"); -ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_limit, param_set_arc_long, - param_get_ulong, ZMOD_RW, "Metadata limit for ARC size in bytes"); +ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_limit, param_set_arc_u64, + spl_param_get_u64, ZMOD_RW, "Metadata limit for ARC size in bytes"); ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_limit_percent, - param_set_arc_long, param_get_ulong, ZMOD_RW, + param_set_arc_int, param_get_uint, ZMOD_RW, "Percent of ARC size for ARC meta limit"); -ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_min, param_set_arc_long, - param_get_ulong, ZMOD_RW, "Minimum ARC metadata size in bytes"); +ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, meta_min, param_set_arc_u64, + spl_param_get_u64, ZMOD_RW, "Minimum ARC metadata size in bytes"); ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, meta_prune, INT, ZMOD_RW, "Meta objects to scan for prune"); @@ -11129,25 +11129,25 @@ ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, min_prescient_prefetch_ms, param_set_arc_int, param_get_uint, ZMOD_RW, "Min life of prescient prefetched block in ms"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, write_max, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, write_max, U64, ZMOD_RW, "Max write bytes per interval"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, write_boost, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, write_boost, U64, ZMOD_RW, "Extra write bytes during device warmup"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, headroom, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, headroom, U64, ZMOD_RW, "Number of max device writes to precache"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, headroom_boost, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, headroom_boost, U64, ZMOD_RW, "Compressed l2arc_headroom multiplier"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, trim_ahead, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, trim_ahead, U64, ZMOD_RW, "TRIM ahead L2ARC write size multiplier"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, feed_secs, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, feed_secs, U64, ZMOD_RW, "Seconds between L2ARC writing"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, feed_min_ms, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, feed_min_ms, U64, ZMOD_RW, "Min feed interval in milliseconds"); ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, noprefetch, INT, ZMOD_RW, @@ -11165,7 +11165,7 @@ ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, meta_percent, UINT, ZMOD_RW, ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, rebuild_enabled, INT, ZMOD_RW, "Rebuild the L2ARC when importing a pool"); -ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, rebuild_blocks_min_l2size, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, rebuild_blocks_min_l2size, U64, ZMOD_RW, "Min size in bytes to write rebuild log blocks in L2ARC"); ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, mfuonly, INT, ZMOD_RW, @@ -11177,17 +11177,17 @@ ZFS_MODULE_PARAM(zfs_l2arc, l2arc_, exclude_special, INT, ZMOD_RW, ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, lotsfree_percent, param_set_arc_int, param_get_uint, ZMOD_RW, "System free memory I/O throttle in bytes"); -ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, sys_free, param_set_arc_long, - param_get_ulong, ZMOD_RW, "System free memory target size in bytes"); +ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, sys_free, param_set_arc_u64, + spl_param_get_u64, ZMOD_RW, "System free memory target size in bytes"); -ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, dnode_limit, param_set_arc_long, - param_get_ulong, ZMOD_RW, "Minimum bytes of dnodes in ARC"); +ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, dnode_limit, param_set_arc_u64, + spl_param_get_u64, ZMOD_RW, "Minimum bytes of dnodes in ARC"); ZFS_MODULE_PARAM_CALL(zfs_arc, zfs_arc_, dnode_limit_percent, - param_set_arc_long, param_get_ulong, ZMOD_RW, + param_set_arc_int, param_get_uint, ZMOD_RW, "Percent of ARC meta buffers for dnodes"); -ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, dnode_reduce_percent, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, dnode_reduce_percent, UINT, ZMOD_RW, "Percentage of excess dnodes to try to unpin"); ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, eviction_pct, UINT, ZMOD_RW, diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 85de95baf61a..77e6ad23ef89 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -227,8 +227,8 @@ typedef struct dbuf_cache { dbuf_cache_t dbuf_caches[DB_CACHE_MAX]; /* Size limits for the caches */ -static unsigned long dbuf_cache_max_bytes = ULONG_MAX; -static unsigned long dbuf_metadata_cache_max_bytes = ULONG_MAX; +static uint64_t dbuf_cache_max_bytes = UINT64_MAX; +static uint64_t dbuf_metadata_cache_max_bytes = UINT64_MAX; /* Set the default sizes of the caches to log2 fraction of arc size */ static uint_t dbuf_cache_shift = 5; @@ -5122,7 +5122,7 @@ EXPORT_SYMBOL(dmu_buf_set_user_ie); EXPORT_SYMBOL(dmu_buf_get_user); EXPORT_SYMBOL(dmu_buf_get_blkptr); -ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, max_bytes, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, max_bytes, U64, ZMOD_RW, "Maximum size in bytes of the dbuf cache."); ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, hiwater_pct, UINT, ZMOD_RW, @@ -5131,7 +5131,7 @@ ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, hiwater_pct, UINT, ZMOD_RW, ZFS_MODULE_PARAM(zfs_dbuf_cache, dbuf_cache_, lowater_pct, UINT, ZMOD_RW, "Percentage below dbuf_cache_max_bytes when dbuf eviction stops."); -ZFS_MODULE_PARAM(zfs_dbuf, dbuf_, metadata_cache_max_bytes, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_dbuf, dbuf_, metadata_cache_max_bytes, U64, ZMOD_RW, "Maximum size in bytes of dbuf metadata cache."); ZFS_MODULE_PARAM(zfs_dbuf, dbuf_, cache_shift, UINT, ZMOD_RW, diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 9e67eb51f415..d95d7bf639bb 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -70,7 +70,7 @@ static int zfs_nopwrite_enabled = 1; * will wait until the next TXG. * A value of zero will disable this throttle. */ -static unsigned long zfs_per_txg_dirty_frees_percent = 30; +static uint_t zfs_per_txg_dirty_frees_percent = 30; /* * Enable/disable forcing txg sync when dirty checking for holes with lseek(). @@ -2355,7 +2355,7 @@ EXPORT_SYMBOL(dmu_ot); ZFS_MODULE_PARAM(zfs, zfs_, nopwrite_enabled, INT, ZMOD_RW, "Enable NOP writes"); -ZFS_MODULE_PARAM(zfs, zfs_, per_txg_dirty_frees_percent, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, per_txg_dirty_frees_percent, UINT, ZMOD_RW, "Percentage of dirtied blocks from frees in one TXG"); ZFS_MODULE_PARAM(zfs, zfs_, dmu_offset_next_sync, INT, ZMOD_RW, diff --git a/module/zfs/dmu_zfetch.c b/module/zfs/dmu_zfetch.c index 101d2ee7b7a2..1d63d7de65a1 100644 --- a/module/zfs/dmu_zfetch.c +++ b/module/zfs/dmu_zfetch.c @@ -58,7 +58,7 @@ unsigned int zfetch_max_distance = 64 * 1024 * 1024; /* max bytes to prefetch indirects for per stream (default 64MB) */ unsigned int zfetch_max_idistance = 64 * 1024 * 1024; /* max number of bytes in an array_read in which we allow prefetching (1MB) */ -unsigned long zfetch_array_rd_sz = 1024 * 1024; +uint64_t zfetch_array_rd_sz = 1024 * 1024; typedef struct zfetch_stats { kstat_named_t zfetchstat_hits; @@ -565,5 +565,5 @@ ZFS_MODULE_PARAM(zfs_prefetch, zfetch_, max_distance, UINT, ZMOD_RW, ZFS_MODULE_PARAM(zfs_prefetch, zfetch_, max_idistance, UINT, ZMOD_RW, "Max bytes to prefetch indirects for per stream"); -ZFS_MODULE_PARAM(zfs_prefetch, zfetch_, array_rd_sz, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_prefetch, zfetch_, array_rd_sz, U64, ZMOD_RW, "Number of bytes in a array_read"); diff --git a/module/zfs/dsl_deadlist.c b/module/zfs/dsl_deadlist.c index 031be59e31cc..2b33446e66af 100644 --- a/module/zfs/dsl_deadlist.c +++ b/module/zfs/dsl_deadlist.c @@ -92,7 +92,7 @@ * will be loaded into memory and shouldn't take up an inordinate amount of * space. We settled on ~500000 entries, corresponding to roughly 128M. */ -unsigned long zfs_livelist_max_entries = 500000; +uint64_t zfs_livelist_max_entries = 500000; /* * We can approximate how much of a performance gain a livelist will give us @@ -1040,7 +1040,7 @@ dsl_process_sub_livelist(bpobj_t *bpobj, bplist_t *to_free, zthr_t *t, return (err); } -ZFS_MODULE_PARAM(zfs_livelist, zfs_livelist_, max_entries, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_livelist, zfs_livelist_, max_entries, U64, ZMOD_RW, "Size to start the next sub-livelist in a livelist"); ZFS_MODULE_PARAM(zfs_livelist, zfs_livelist_, min_percent_shared, INT, ZMOD_RW, diff --git a/module/zfs/dsl_pool.c b/module/zfs/dsl_pool.c index 4fd3722a051e..5d4311ff4557 100644 --- a/module/zfs/dsl_pool.c +++ b/module/zfs/dsl_pool.c @@ -99,8 +99,8 @@ * capped at zfs_dirty_data_max_max. It can also be overridden with a module * parameter. */ -unsigned long zfs_dirty_data_max = 0; -unsigned long zfs_dirty_data_max_max = 0; +uint64_t zfs_dirty_data_max = 0; +uint64_t zfs_dirty_data_max_max = 0; uint_t zfs_dirty_data_max_percent = 10; uint_t zfs_dirty_data_max_max_percent = 25; @@ -109,7 +109,7 @@ uint_t zfs_dirty_data_max_max_percent = 25; * when approaching the limit until log data is cleared out after txg sync. * It only counts TX_WRITE log with WR_COPIED or WR_NEED_COPY. */ -unsigned long zfs_wrlog_data_max = 0; +uint64_t zfs_wrlog_data_max = 0; /* * If there's at least this much dirty data (as a percentage of @@ -138,7 +138,7 @@ uint_t zfs_delay_min_dirty_percent = 60; * Note: zfs_delay_scale * zfs_dirty_data_max must be < 2^64, due to the * multiply in dmu_tx_delay(). */ -unsigned long zfs_delay_scale = 1000 * 1000 * 1000 / 2000; +uint64_t zfs_delay_scale = 1000 * 1000 * 1000 / 2000; /* * This determines the number of threads used by the dp_sync_taskq. @@ -1465,20 +1465,20 @@ ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_max_max_percent, UINT, ZMOD_RD, ZFS_MODULE_PARAM(zfs, zfs_, delay_min_dirty_percent, UINT, ZMOD_RW, "Transaction delay threshold"); -ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_max, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_max, U64, ZMOD_RW, "Determines the dirty space limit"); -ZFS_MODULE_PARAM(zfs, zfs_, wrlog_data_max, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, wrlog_data_max, U64, ZMOD_RW, "The size limit of write-transaction zil log data"); /* zfs_dirty_data_max_max only applied at module load in arc_init(). */ -ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_max_max, ULONG, ZMOD_RD, +ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_max_max, U64, ZMOD_RD, "zfs_dirty_data_max upper bound in bytes"); ZFS_MODULE_PARAM(zfs, zfs_, dirty_data_sync_percent, UINT, ZMOD_RW, "Dirty data txg sync threshold as a percentage of zfs_dirty_data_max"); -ZFS_MODULE_PARAM(zfs, zfs_, delay_scale, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, delay_scale, U64, ZMOD_RW, "How quickly delay approaches infinity"); ZFS_MODULE_PARAM(zfs, zfs_, sync_taskq_batch_pct, INT, ZMOD_RW, diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index 09e271395cc4..03c2aa313af0 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -147,13 +147,13 @@ static int zfs_scan_strict_mem_lim = B_FALSE; * overload the drives with I/O, since that is protected by * zfs_vdev_scrub_max_active. */ -static unsigned long zfs_scan_vdev_limit = 4 << 20; +static uint64_t zfs_scan_vdev_limit = 4 << 20; static uint_t zfs_scan_issue_strategy = 0; /* don't queue & sort zios, go direct */ static int zfs_scan_legacy = B_FALSE; -static unsigned long zfs_scan_max_ext_gap = 2 << 20; /* in bytes */ +static uint64_t zfs_scan_max_ext_gap = 2 << 20; /* in bytes */ /* * fill_weight is non-tunable at runtime, so we copy it at module init from @@ -192,9 +192,9 @@ static int zfs_no_scrub_io = B_FALSE; /* set to disable scrub i/o */ static int zfs_no_scrub_prefetch = B_FALSE; /* set to disable scrub prefetch */ static const enum ddt_class zfs_scrub_ddt_class_max = DDT_CLASS_DUPLICATE; /* max number of blocks to free in a single TXG */ -static unsigned long zfs_async_block_max_blocks = ULONG_MAX; +static uint64_t zfs_async_block_max_blocks = UINT64_MAX; /* max number of dedup blocks to free in a single TXG */ -static unsigned long zfs_max_async_dedup_frees = 100000; +static uint64_t zfs_max_async_dedup_frees = 100000; /* set to disable resilver deferring */ static int zfs_resilver_disable_defer = B_FALSE; @@ -4447,7 +4447,7 @@ dsl_scan_assess_vdev(dsl_pool_t *dp, vdev_t *vd) spa_async_request(dp->dp_spa, SPA_ASYNC_RESILVER); } -ZFS_MODULE_PARAM(zfs, zfs_, scan_vdev_limit, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, scan_vdev_limit, U64, ZMOD_RW, "Max bytes in flight per leaf vdev for scrubs and resilvers"); ZFS_MODULE_PARAM(zfs, zfs_, scrub_min_time_ms, UINT, ZMOD_RW, @@ -4471,10 +4471,10 @@ ZFS_MODULE_PARAM(zfs, zfs_, no_scrub_io, INT, ZMOD_RW, ZFS_MODULE_PARAM(zfs, zfs_, no_scrub_prefetch, INT, ZMOD_RW, "Set to disable scrub prefetching"); -ZFS_MODULE_PARAM(zfs, zfs_, async_block_max_blocks, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, async_block_max_blocks, U64, ZMOD_RW, "Max number of blocks freed in one txg"); -ZFS_MODULE_PARAM(zfs, zfs_, max_async_dedup_frees, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, max_async_dedup_frees, U64, ZMOD_RW, "Max number of dedup blocks freed in one txg"); ZFS_MODULE_PARAM(zfs, zfs_, free_bpobj_enabled, INT, ZMOD_RW, @@ -4495,7 +4495,7 @@ ZFS_MODULE_PARAM(zfs, zfs_, scan_legacy, INT, ZMOD_RW, ZFS_MODULE_PARAM(zfs, zfs_, scan_checkpoint_intval, UINT, ZMOD_RW, "Scan progress on-disk checkpointing interval"); -ZFS_MODULE_PARAM(zfs, zfs_, scan_max_ext_gap, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, scan_max_ext_gap, U64, ZMOD_RW, "Max gap in bytes between sequential scrub / resilver I/Os"); ZFS_MODULE_PARAM(zfs, zfs_, scan_mem_lim_soft_fact, UINT, ZMOD_RW, diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c index cf853a42de07..3c32d6f051e8 100644 --- a/module/zfs/metaslab.c +++ b/module/zfs/metaslab.c @@ -51,12 +51,12 @@ * operation, we will try to write this amount of data to each disk before * moving on to the next top-level vdev. */ -static unsigned long metaslab_aliquot = 1024 * 1024; +static uint64_t metaslab_aliquot = 1024 * 1024; /* * For testing, make some blocks above a certain size be gang blocks. */ -unsigned long metaslab_force_ganging = SPA_MAXBLOCKSIZE + 1; +uint64_t metaslab_force_ganging = SPA_MAXBLOCKSIZE + 1; /* * In pools where the log space map feature is not enabled we touch @@ -286,7 +286,7 @@ static const int max_disabled_ms = 3; * Time (in seconds) to respect ms_max_size when the metaslab is not loaded. * To avoid 64-bit overflow, don't set above UINT32_MAX. */ -static unsigned long zfs_metaslab_max_size_cache_sec = 1 * 60 * 60; /* 1 hour */ +static uint64_t zfs_metaslab_max_size_cache_sec = 1 * 60 * 60; /* 1 hour */ /* * Maximum percentage of memory to use on storing loaded metaslabs. If loading @@ -6202,7 +6202,7 @@ metaslab_unflushed_txg(metaslab_t *ms) return (ms->ms_unflushed_txg); } -ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, aliquot, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, aliquot, U64, ZMOD_RW, "Allocation granularity (a.k.a. stripe size)"); ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, debug_load, INT, ZMOD_RW, @@ -6250,7 +6250,7 @@ ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, segment_weight_enabled, INT, ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, switch_threshold, INT, ZMOD_RW, "Segment-based metaslab selection maximum buckets before switching"); -ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, force_ganging, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, force_ganging, U64, ZMOD_RW, "Blocks larger than this size are forced to be gang blocks"); ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, df_max_search, UINT, ZMOD_RW, @@ -6259,7 +6259,7 @@ ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, df_max_search, UINT, ZMOD_RW, ZFS_MODULE_PARAM(zfs_metaslab, metaslab_, df_use_largest_segment, INT, ZMOD_RW, "When looking in size tree, use largest segment instead of exact fit"); -ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, max_size_cache_sec, ULONG, +ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, max_size_cache_sec, U64, ZMOD_RW, "How long to trust the cached max chunk size of a metaslab"); ZFS_MODULE_PARAM(zfs_metaslab, zfs_metaslab_, mem_limit, UINT, ZMOD_RW, diff --git a/module/zfs/mmp.c b/module/zfs/mmp.c index b6d71aa8a458..4f0273f3ed86 100644 --- a/module/zfs/mmp.c +++ b/module/zfs/mmp.c @@ -156,7 +156,7 @@ * vary with the I/O load and this observed value is the ub_mmp_delay which is * stored in the uberblock. The minimum allowed value is 100 ms. */ -ulong_t zfs_multihost_interval = MMP_DEFAULT_INTERVAL; +uint64_t zfs_multihost_interval = MMP_DEFAULT_INTERVAL; /* * Used to control the duration of the activity test on import. Smaller values @@ -736,7 +736,7 @@ mmp_signal_all_threads(void) /* BEGIN CSTYLED */ ZFS_MODULE_PARAM_CALL(zfs_multihost, zfs_multihost_, interval, - param_set_multihost_interval, param_get_ulong, ZMOD_RW, + param_set_multihost_interval, spl_param_get_u64, ZMOD_RW, "Milliseconds between mmp writes to each leaf"); /* END CSTYLED */ diff --git a/module/zfs/spa.c b/module/zfs/spa.c index cc367745e486..26df0290c9ff 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -218,7 +218,7 @@ static int spa_load_print_vdev_tree = B_FALSE; * there are also risks of performing an inadvertent rewind as we might be * missing all the vdevs with the latest uberblocks. */ -unsigned long zfs_max_missing_tvds = 0; +uint64_t zfs_max_missing_tvds = 0; /* * The parameters below are similar to zfs_max_missing_tvds but are only @@ -10016,7 +10016,7 @@ ZFS_MODULE_PARAM(zfs_zio, zio_, taskq_batch_tpq, UINT, ZMOD_RD, "Number of threads per IO worker taskqueue"); /* BEGIN CSTYLED */ -ZFS_MODULE_PARAM(zfs, zfs_, max_missing_tvds, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, max_missing_tvds, U64, ZMOD_RW, "Allow importing pool with up to this number of missing top-level " "vdevs (in read-only mode)"); /* END CSTYLED */ diff --git a/module/zfs/spa_checkpoint.c b/module/zfs/spa_checkpoint.c index a837b1ce97ec..b588f7041e5c 100644 --- a/module/zfs/spa_checkpoint.c +++ b/module/zfs/spa_checkpoint.c @@ -158,7 +158,7 @@ * amount of checkpointed data that has been freed within them while * the pool had a checkpoint. */ -static unsigned long zfs_spa_discard_memory_limit = 16 * 1024 * 1024; +static uint64_t zfs_spa_discard_memory_limit = 16 * 1024 * 1024; int spa_checkpoint_get_stats(spa_t *spa, pool_checkpoint_stat_t *pcs) @@ -631,7 +631,7 @@ EXPORT_SYMBOL(spa_checkpoint_discard_thread); EXPORT_SYMBOL(spa_checkpoint_discard_thread_check); /* BEGIN CSTYLED */ -ZFS_MODULE_PARAM(zfs_spa, zfs_spa_, discard_memory_limit, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_spa, zfs_spa_, discard_memory_limit, U64, ZMOD_RW, "Limit for memory used in prefetching the checkpoint space map done " "on each vdev while discarding the checkpoint"); /* END CSTYLED */ diff --git a/module/zfs/spa_log_spacemap.c b/module/zfs/spa_log_spacemap.c index 5ce60bf212f1..c7ba5f65af58 100644 --- a/module/zfs/spa_log_spacemap.c +++ b/module/zfs/spa_log_spacemap.c @@ -188,13 +188,13 @@ static const unsigned long zfs_log_sm_blksz = 1ULL << 17; * (thus the _ppm suffix; reads as "parts per million"). As an example, * the default of 1000 allows 0.1% of memory to be used. */ -static unsigned long zfs_unflushed_max_mem_ppm = 1000; +static uint64_t zfs_unflushed_max_mem_ppm = 1000; /* * Specific hard-limit in memory that ZFS allows to be used for * unflushed changes. */ -static unsigned long zfs_unflushed_max_mem_amt = 1ULL << 30; +static uint64_t zfs_unflushed_max_mem_amt = 1ULL << 30; /* * The following tunable determines the number of blocks that can be used for @@ -243,33 +243,33 @@ static unsigned long zfs_unflushed_max_mem_amt = 1ULL << 30; * provide upper and lower bounds for the log block limit. * [see zfs_unflushed_log_block_{min,max}] */ -static unsigned long zfs_unflushed_log_block_pct = 400; +static uint_t zfs_unflushed_log_block_pct = 400; /* * If the number of metaslabs is small and our incoming rate is high, we could * get into a situation that we are flushing all our metaslabs every TXG. Thus * we always allow at least this many log blocks. */ -static unsigned long zfs_unflushed_log_block_min = 1000; +static uint64_t zfs_unflushed_log_block_min = 1000; /* * If the log becomes too big, the import time of the pool can take a hit in * terms of performance. Thus we have a hard limit in the size of the log in * terms of blocks. */ -static unsigned long zfs_unflushed_log_block_max = (1ULL << 17); +static uint64_t zfs_unflushed_log_block_max = (1ULL << 17); /* * Also we have a hard limit in the size of the log in terms of dirty TXGs. */ -static unsigned long zfs_unflushed_log_txg_max = 1000; +static uint64_t zfs_unflushed_log_txg_max = 1000; /* * Max # of rows allowed for the log_summary. The tradeoff here is accuracy and * stability of the flushing algorithm (longer summary) vs its runtime overhead * (smaller summary is faster to traverse). */ -static unsigned long zfs_max_logsm_summary_length = 10; +static uint64_t zfs_max_logsm_summary_length = 10; /* * Tunable that sets the lower bound on the metaslabs to flush every TXG. @@ -282,7 +282,7 @@ static unsigned long zfs_max_logsm_summary_length = 10; * The point of this tunable is to be used in extreme cases where we really * want to flush more metaslabs than our adaptable heuristic plans to flush. */ -static unsigned long zfs_min_metaslabs_to_flush = 1; +static uint64_t zfs_min_metaslabs_to_flush = 1; /* * Tunable that specifies how far in the past do we want to look when trying to @@ -293,7 +293,7 @@ static unsigned long zfs_min_metaslabs_to_flush = 1; * average over all the blocks that we walk * [see spa_estimate_incoming_log_blocks]. */ -static unsigned long zfs_max_log_walking = 5; +static uint64_t zfs_max_log_walking = 5; /* * This tunable exists solely for testing purposes. It ensures that the log @@ -1357,34 +1357,34 @@ spa_ld_log_spacemaps(spa_t *spa) } /* BEGIN CSTYLED */ -ZFS_MODULE_PARAM(zfs, zfs_, unflushed_max_mem_amt, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, unflushed_max_mem_amt, U64, ZMOD_RW, "Specific hard-limit in memory that ZFS allows to be used for " "unflushed changes"); -ZFS_MODULE_PARAM(zfs, zfs_, unflushed_max_mem_ppm, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, unflushed_max_mem_ppm, U64, ZMOD_RW, "Percentage of the overall system memory that ZFS allows to be " "used for unflushed changes (value is calculated over 1000000 for " "finer granularity)"); -ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_max, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_max, U64, ZMOD_RW, "Hard limit (upper-bound) in the size of the space map log " "in terms of blocks."); -ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_min, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_min, U64, ZMOD_RW, "Lower-bound limit for the maximum amount of blocks allowed in " "log spacemap (see zfs_unflushed_log_block_max)"); -ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_txg_max, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_txg_max, U64, ZMOD_RW, "Hard limit (upper-bound) in the size of the space map log " "in terms of dirty TXGs."); -ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_pct, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, unflushed_log_block_pct, UINT, ZMOD_RW, "Tunable used to determine the number of blocks that can be used for " "the spacemap log, expressed as a percentage of the total number of " "metaslabs in the pool (e.g. 400 means the number of log blocks is " "capped at 4 times the number of metaslabs)"); -ZFS_MODULE_PARAM(zfs, zfs_, max_log_walking, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, max_log_walking, U64, ZMOD_RW, "The number of past TXGs that the flushing algorithm of the log " "spacemap feature uses to estimate incoming log blocks"); @@ -1393,8 +1393,8 @@ ZFS_MODULE_PARAM(zfs, zfs_, keep_log_spacemaps_at_export, INT, ZMOD_RW, "during pool export/destroy"); /* END CSTYLED */ -ZFS_MODULE_PARAM(zfs, zfs_, max_logsm_summary_length, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, max_logsm_summary_length, U64, ZMOD_RW, "Maximum number of rows allowed in the summary of the spacemap log"); -ZFS_MODULE_PARAM(zfs, zfs_, min_metaslabs_to_flush, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, min_metaslabs_to_flush, U64, ZMOD_RW, "Minimum number of metaslabs to flush per dirty TXG"); diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index 102070013404..9ec37502986f 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -304,20 +304,20 @@ int zfs_free_leak_on_eio = B_FALSE; * has not completed in zfs_deadman_synctime_ms is considered "hung" resulting * in one of three behaviors controlled by zfs_deadman_failmode. */ -unsigned long zfs_deadman_synctime_ms = 600000UL; /* 10 min. */ +uint64_t zfs_deadman_synctime_ms = 600000UL; /* 10 min. */ /* * This value controls the maximum amount of time zio_wait() will block for an * outstanding IO. By default this is 300 seconds at which point the "hung" * behavior will be applied as described for zfs_deadman_synctime_ms. */ -unsigned long zfs_deadman_ziotime_ms = 300000UL; /* 5 min. */ +uint64_t zfs_deadman_ziotime_ms = 300000UL; /* 5 min. */ /* * Check time in milliseconds. This defines the frequency at which we check * for hung I/O. */ -unsigned long zfs_deadman_checktime_ms = 60000UL; /* 1 min. */ +uint64_t zfs_deadman_checktime_ms = 60000UL; /* 1 min. */ /* * By default the deadman is enabled. @@ -2922,7 +2922,7 @@ ZFS_MODULE_PARAM(zfs, zfs_, recover, INT, ZMOD_RW, ZFS_MODULE_PARAM(zfs, zfs_, free_leak_on_eio, INT, ZMOD_RW, "Set to ignore IO errors during free and permanently leak the space"); -ZFS_MODULE_PARAM(zfs_deadman, zfs_deadman_, checktime_ms, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_deadman, zfs_deadman_, checktime_ms, U64, ZMOD_RW, "Dead I/O check interval in milliseconds"); ZFS_MODULE_PARAM(zfs_deadman, zfs_deadman_, enabled, INT, ZMOD_RW, @@ -2943,11 +2943,11 @@ ZFS_MODULE_PARAM_CALL(zfs_deadman, zfs_deadman_, failmode, "Failmode for deadman timer"); ZFS_MODULE_PARAM_CALL(zfs_deadman, zfs_deadman_, synctime_ms, - param_set_deadman_synctime, param_get_ulong, ZMOD_RW, + param_set_deadman_synctime, spl_param_get_u64, ZMOD_RW, "Pool sync expiration time in milliseconds"); ZFS_MODULE_PARAM_CALL(zfs_deadman, zfs_deadman_, ziotime_ms, - param_set_deadman_ziotime, param_get_ulong, ZMOD_RW, + param_set_deadman_ziotime, spl_param_get_u64, ZMOD_RW, "IO expiration time in milliseconds"); ZFS_MODULE_PARAM(zfs, zfs_, special_class_metadata_reserve_pct, UINT, ZMOD_RW, diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 52265d960c63..7d22a66c7819 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -144,8 +144,8 @@ int zfs_nocacheflush = 0; * be forced by vdev logical ashift or by user via ashift property, but won't * be set automatically as a performance optimization. */ -uint64_t zfs_vdev_max_auto_ashift = 14; -uint64_t zfs_vdev_min_auto_ashift = ASHIFT_MIN; +uint_t zfs_vdev_max_auto_ashift = 14; +uint_t zfs_vdev_min_auto_ashift = ASHIFT_MIN; void vdev_dbgmsg(vdev_t *vd, const char *fmt, ...) @@ -6156,11 +6156,11 @@ ZFS_MODULE_PARAM(zfs, zfs_, embedded_slog_min_ms, UINT, ZMOD_RW, /* BEGIN CSTYLED */ ZFS_MODULE_PARAM_CALL(zfs_vdev, zfs_vdev_, min_auto_ashift, - param_set_min_auto_ashift, param_get_ulong, ZMOD_RW, + param_set_min_auto_ashift, param_get_uint, ZMOD_RW, "Minimum ashift used when creating new top-level vdevs"); ZFS_MODULE_PARAM_CALL(zfs_vdev, zfs_vdev_, max_auto_ashift, - param_set_max_auto_ashift, param_get_ulong, ZMOD_RW, + param_set_max_auto_ashift, param_get_uint, ZMOD_RW, "Maximum ashift used when optimizing for logical -> physical sector " "size on new top-level vdevs"); /* END CSTYLED */ diff --git a/module/zfs/vdev_indirect.c b/module/zfs/vdev_indirect.c index b0bd71c58e69..814a1f0efe4c 100644 --- a/module/zfs/vdev_indirect.c +++ b/module/zfs/vdev_indirect.c @@ -189,14 +189,14 @@ static uint_t zfs_condense_indirect_obsolete_pct = 25; * consumed by the obsolete space map; the default of 1GB is small enough * that we typically don't mind "wasting" it. */ -static unsigned long zfs_condense_max_obsolete_bytes = 1024 * 1024 * 1024; +static uint64_t zfs_condense_max_obsolete_bytes = 1024 * 1024 * 1024; /* * Don't bother condensing if the mapping uses less than this amount of * memory. The default of 128KB is considered a "trivial" amount of * memory and not worth reducing. */ -static unsigned long zfs_condense_min_mapping_bytes = 128 * 1024; +static uint64_t zfs_condense_min_mapping_bytes = 128 * 1024; /* * This is used by the test suite so that it can ensure that certain @@ -1892,11 +1892,11 @@ ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, indirect_obsolete_pct, UINT, "Minimum obsolete percent of bytes in the mapping " "to attempt condensing"); -ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, min_mapping_bytes, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, min_mapping_bytes, U64, ZMOD_RW, "Don't bother condensing if the mapping uses less than this amount of " "memory"); -ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, max_obsolete_bytes, ULONG, +ZFS_MODULE_PARAM(zfs_condense, zfs_condense_, max_obsolete_bytes, U64, ZMOD_RW, "Minimum size obsolete spacemap to attempt condensing"); diff --git a/module/zfs/vdev_initialize.c b/module/zfs/vdev_initialize.c index 965fb7ef0593..75beb0cc3d12 100644 --- a/module/zfs/vdev_initialize.c +++ b/module/zfs/vdev_initialize.c @@ -36,17 +36,13 @@ /* * Value that is written to disk during initialization. */ -#ifdef _ILP32 -static unsigned long zfs_initialize_value = 0xdeadbeefUL; -#else -static unsigned long zfs_initialize_value = 0xdeadbeefdeadbeeeULL; -#endif +static uint64_t zfs_initialize_value = 0xdeadbeefdeadbeeeULL; /* maximum number of I/Os outstanding per leaf vdev */ static const int zfs_initialize_limit = 1; /* size of initializing writes; default 1MiB, see zfs_remove_max_segment */ -static unsigned long zfs_initialize_chunk_size = 1024 * 1024; +static uint64_t zfs_initialize_chunk_size = 1024 * 1024; static boolean_t vdev_initialize_should_stop(vdev_t *vd) @@ -261,15 +257,9 @@ vdev_initialize_block_fill(void *buf, size_t len, void *unused) (void) unused; ASSERT0(len % sizeof (uint64_t)); -#ifdef _ILP32 - for (uint64_t i = 0; i < len; i += sizeof (uint32_t)) { - *(uint32_t *)((char *)(buf) + i) = zfs_initialize_value; - } -#else for (uint64_t i = 0; i < len; i += sizeof (uint64_t)) { *(uint64_t *)((char *)(buf) + i) = zfs_initialize_value; } -#endif return (0); } @@ -765,8 +755,8 @@ EXPORT_SYMBOL(vdev_initialize_stop_all); EXPORT_SYMBOL(vdev_initialize_stop_wait); EXPORT_SYMBOL(vdev_initialize_restart); -ZFS_MODULE_PARAM(zfs, zfs_, initialize_value, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, initialize_value, U64, ZMOD_RW, "Value written during zpool initialize"); -ZFS_MODULE_PARAM(zfs, zfs_, initialize_chunk_size, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, initialize_chunk_size, U64, ZMOD_RW, "Size in bytes of writes by zpool initialize"); diff --git a/module/zfs/vdev_rebuild.c b/module/zfs/vdev_rebuild.c index 1ce578e228d8..fdb8ad97b439 100644 --- a/module/zfs/vdev_rebuild.c +++ b/module/zfs/vdev_rebuild.c @@ -103,7 +103,7 @@ * Size of rebuild reads; defaults to 1MiB per data disk and is capped at * SPA_MAXBLOCKSIZE. */ -static unsigned long zfs_rebuild_max_segment = 1024 * 1024; +static uint64_t zfs_rebuild_max_segment = 1024 * 1024; /* * Maximum number of parallelly executed bytes per leaf vdev caused by a @@ -121,7 +121,7 @@ static unsigned long zfs_rebuild_max_segment = 1024 * 1024; * With a value of 32MB the sequential resilver write rate was measured at * 800MB/s sustained while rebuilding to a distributed spare. */ -static unsigned long zfs_rebuild_vdev_limit = 32 << 20; +static uint64_t zfs_rebuild_vdev_limit = 32 << 20; /* * Automatically start a pool scrub when the last active sequential resilver @@ -1138,10 +1138,10 @@ vdev_rebuild_get_stats(vdev_t *tvd, vdev_rebuild_stat_t *vrs) return (error); } -ZFS_MODULE_PARAM(zfs, zfs_, rebuild_max_segment, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, rebuild_max_segment, U64, ZMOD_RW, "Max segment size in bytes of rebuild reads"); -ZFS_MODULE_PARAM(zfs, zfs_, rebuild_vdev_limit, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, rebuild_vdev_limit, U64, ZMOD_RW, "Max bytes in flight per leaf vdev for sequential resilvers"); ZFS_MODULE_PARAM(zfs, zfs_, rebuild_scrub_enabled, INT, ZMOD_RW, diff --git a/module/zfs/zcp.c b/module/zfs/zcp.c index fe90242ca40d..2b79f0a2a04a 100644 --- a/module/zfs/zcp.c +++ b/module/zfs/zcp.c @@ -109,8 +109,8 @@ #define ZCP_NVLIST_MAX_DEPTH 20 static const uint64_t zfs_lua_check_instrlimit_interval = 100; -unsigned long zfs_lua_max_instrlimit = ZCP_MAX_INSTRLIMIT; -unsigned long zfs_lua_max_memlimit = ZCP_MAX_MEMLIMIT; +uint64_t zfs_lua_max_instrlimit = ZCP_MAX_INSTRLIMIT; +uint64_t zfs_lua_max_memlimit = ZCP_MAX_MEMLIMIT; /* * Forward declarations for mutually recursive functions @@ -1443,8 +1443,8 @@ zcp_parse_args(lua_State *state, const char *fname, const zcp_arg_t *pargs, } } -ZFS_MODULE_PARAM(zfs_lua, zfs_lua_, max_instrlimit, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_lua, zfs_lua_, max_instrlimit, U64, ZMOD_RW, "Max instruction limit that can be specified for a channel program"); -ZFS_MODULE_PARAM(zfs_lua, zfs_lua_, max_memlimit, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_lua, zfs_lua_, max_memlimit, U64, ZMOD_RW, "Max memory limit that can be specified for a channel program"); diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index c3266c09306b..a5168b937588 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -229,14 +229,14 @@ static zfsdev_state_t *zfsdev_state_list; * for zc->zc_nvlist_src_size, since we will need to allocate that much memory. * Defaults to 0=auto which is handled by platform code. */ -unsigned long zfs_max_nvlist_src_size = 0; +uint64_t zfs_max_nvlist_src_size = 0; /* * When logging the output nvlist of an ioctl in the on-disk history, limit * the logged size to this many bytes. This must be less than DMU_MAX_ACCESS. * This applies primarily to zfs_ioc_channel_program(). */ -static unsigned long zfs_history_output_max = 1024 * 1024; +static uint64_t zfs_history_output_max = 1024 * 1024; uint_t zfs_fsyncer_key; uint_t zfs_allow_log_key; @@ -7884,8 +7884,8 @@ zfs_kmod_fini(void) tsd_destroy(&zfs_allow_log_key); } -ZFS_MODULE_PARAM(zfs, zfs_, max_nvlist_src_size, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, max_nvlist_src_size, U64, ZMOD_RW, "Maximum size in bytes allowed for src nvlist passed with ZFS ioctls"); -ZFS_MODULE_PARAM(zfs, zfs_, history_output_max, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, history_output_max, U64, ZMOD_RW, "Maximum size in bytes of ZFS ioctl output that will be logged"); diff --git a/module/zfs/zfs_log.c b/module/zfs/zfs_log.c index c92044337bce..245699882aa9 100644 --- a/module/zfs/zfs_log.c +++ b/module/zfs/zfs_log.c @@ -525,7 +525,7 @@ zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *sdzp, * called as soon as the write is on stable storage (be it via a DMU sync or a * ZIL commit). */ -static long zfs_immediate_write_sz = 32768; +static int64_t zfs_immediate_write_sz = 32768; void zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype, @@ -815,5 +815,5 @@ zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp, zil_itx_assign(zilog, itx, tx); } -ZFS_MODULE_PARAM(zfs, zfs_, immediate_write_sz, LONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs, zfs_, immediate_write_sz, S64, ZMOD_RW, "Largest data block to write to zil"); diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 57f03f116273..a2c15bc807a8 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -176,7 +176,7 @@ zfs_access(znode_t *zp, int mode, int flag, cred_t *cr) return (error); } -static unsigned long zfs_vnops_read_chunk_size = 1024 * 1024; /* Tunable */ +static uint64_t zfs_vnops_read_chunk_size = 1024 * 1024; /* Tunable */ /* * Read bytes from specified file into supplied buffer. @@ -991,5 +991,5 @@ EXPORT_SYMBOL(zfs_write); EXPORT_SYMBOL(zfs_getsecattr); EXPORT_SYMBOL(zfs_setsecattr); -ZFS_MODULE_PARAM(zfs_vnops, zfs_vnops_, read_chunk_size, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_vnops, zfs_vnops_, read_chunk_size, U64, ZMOD_RW, "Bytes to read per chunk"); diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 075bac832f06..f26cc52613ea 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -132,7 +132,7 @@ static int zil_nocacheflush = 0; * Any writes above that will be executed with lower (asynchronous) priority * to limit potential SLOG device abuse by single active ZIL writer. */ -static unsigned long zil_slog_bulk = 768 * 1024; +static uint64_t zil_slog_bulk = 768 * 1024; static kmem_cache_t *zil_lwb_cache; static kmem_cache_t *zil_zcw_cache; @@ -3946,7 +3946,7 @@ ZFS_MODULE_PARAM(zfs_zil, zil_, replay_disable, INT, ZMOD_RW, ZFS_MODULE_PARAM(zfs_zil, zil_, nocacheflush, INT, ZMOD_RW, "Disable ZIL cache flushes"); -ZFS_MODULE_PARAM(zfs_zil, zil_, slog_bulk, ULONG, ZMOD_RW, +ZFS_MODULE_PARAM(zfs_zil, zil_, slog_bulk, U64, ZMOD_RW, "Limit in bytes slog sync writes per commit"); ZFS_MODULE_PARAM(zfs_zil, zil_, maxblocksize, UINT, ZMOD_RW, diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_add/add-o_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_add/add-o_ashift.ksh index 0166e84baa18..7ecaf849e44b 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_add/add-o_ashift.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_add/add-o_ashift.ksh @@ -44,7 +44,7 @@ verify_runnable "global" function cleanup { - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift poolexists $TESTPOOL && destroy_pool $TESTPOOL rm -f $disk1 $disk2 } @@ -77,13 +77,13 @@ do # Make sure we can also set the ashift using the tunable. # log_must zpool create $TESTPOOL $disk1 - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $ashift log_must zpool add $TESTPOOL $disk2 exp=$(( (ashift <= max_auto_ashift) ? ashift : logical_ashift )) log_must verify_ashift $disk2 $exp # clean things for the next run - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift log_must zpool destroy $TESTPOOL log_must zpool labelclear $disk1 log_must zpool labelclear $disk2 diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_add/add_prop_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_add/add_prop_ashift.ksh index 964cfaa525e0..228f62232aae 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_add/add_prop_ashift.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_add/add_prop_ashift.ksh @@ -44,7 +44,7 @@ verify_runnable "global" function cleanup { - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift poolexists $TESTPOOL && destroy_pool $TESTPOOL log_must rm -f $disk1 $disk2 } @@ -63,7 +63,7 @@ orig_ashift=$(get_tunable VDEV_FILE_PHYSICAL_ASHIFT) # the ashift using the -o ashift property should still # be honored. # -log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT 16 +log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT 16 typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16") for ashift in ${ashifts[@]} diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_attach/attach-o_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_attach/attach-o_ashift.ksh index a96bc16761f7..6ccec6abd66f 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_attach/attach-o_ashift.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_attach/attach-o_ashift.ksh @@ -42,7 +42,7 @@ verify_runnable "global" function cleanup { - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1 rm -f $disk1 $disk2 } @@ -61,7 +61,7 @@ orig_ashift=$(get_tunable VDEV_FILE_PHYSICAL_ASHIFT) # the ashift using the -o ashift property should still # be honored. # -log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT 16 +log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT 16 typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16") for ashift in ${ashifts[@]} diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace-o_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace-o_ashift.ksh index 7610f2855c03..37ed0062e61c 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace-o_ashift.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace-o_ashift.ksh @@ -42,7 +42,7 @@ verify_runnable "global" function cleanup { - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1 rm -f $disk1 $disk2 } @@ -61,7 +61,7 @@ orig_ashift=$(get_tunable VDEV_FILE_PHYSICAL_ASHIFT) # the ashift using the -o ashift property should still # be honored. # -log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT 16 +log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT 16 typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16") for ashift in ${ashifts[@]} diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace_prop_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace_prop_ashift.ksh index 313b388b2ba4..ffdaf91a2841 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace_prop_ashift.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_replace/replace_prop_ashift.ksh @@ -44,7 +44,7 @@ verify_runnable "global" function cleanup { - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1 rm -f $disk1 $disk2 } @@ -63,7 +63,7 @@ orig_ashift=$(get_tunable VDEV_FILE_PHYSICAL_ASHIFT) # the ashift using the -o ashift property should still # be honored. # -log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT 16 +log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT 16 typeset ashifts=("9" "10" "11" "12" "13" "14" "15" "16") for ashift in ${ashifts[@]} diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_ashift.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_ashift.ksh index 58119e37cc67..41fef8f7cdb4 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_ashift.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_ashift.ksh @@ -42,7 +42,7 @@ verify_runnable "global" function cleanup { - log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift + log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT $orig_ashift destroy_pool $TESTPOOL1 rm -f $disk } @@ -60,7 +60,7 @@ orig_ashift=$(get_tunable VDEV_FILE_PHYSICAL_ASHIFT) # the ashift using the -o ashift property should still # be honored. # -log_must set_tunable64 VDEV_FILE_PHYSICAL_ASHIFT 16 +log_must set_tunable32 VDEV_FILE_PHYSICAL_ASHIFT 16 disk=$TEST_BASE_DIR/disk log_must mkfile $SIZE $disk From 642c2dee44acbb35045515f3a012e24b24c79776 Mon Sep 17 00:00:00 2001 From: ColMelvin Date: Thu, 13 Oct 2022 13:05:05 -0500 Subject: [PATCH 019/126] cstyle: Allow URLs in C++ comments If a C++ comment contained a URL, the `://` part of the URL would trigger an error because there was no trailing blank, but trailing blanks make for an invalid URL. Modify the check to ignore text within the C++ comment. Reviewed-by: Brian Behlendorf Signed-off-by: Chris Lindee Closes #13987 --- scripts/cstyle.pl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/scripts/cstyle.pl b/scripts/cstyle.pl index ca7f027051cc..d47fd3362408 100755 --- a/scripts/cstyle.pl +++ b/scripts/cstyle.pl @@ -498,9 +498,6 @@ line: while (<$filehandle>) { if (/\S\*\/[^)]|\S\*\/$/ && !/$lint_re/) { err("missing blank before close comment"); } - if (/\/\/\S/) { # C++ comments - err("missing blank after start comment"); - } # check for unterminated single line comments, but allow them when # they are used to comment out the argument list of a function # declaration. @@ -534,7 +531,15 @@ line: while (<$filehandle>) { # multiple comments on the same line. # s/\/\*.*?\*\///g; - s/\/\/.*$//; # C++ comments + s/\/\/(?:\s.*)?$//; # Valid C++ comments + + # After stripping correctly spaced comments, check for (and strip) comments + # without a blank. By checking this after clearing out C++ comments that + # correctly have a blank, we guarantee URIs in a C++ comment will not cause + # an error. + if (s!//.*$!!) { # C++ comments + err("missing blank after start comment"); + } # delete any trailing whitespace; we have already checked for that. s/\s*$//; From 4d5aef3ba919b1a328e9ff9063340fc6f5389c3a Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Fri, 14 Oct 2022 20:46:47 +0200 Subject: [PATCH 020/126] zfs_domount: fix double-disown of dataset / double-free of zfsvfs_t Before this patch, in zfs_domount, if zfs_root or d_make_root fails, we leave zfsvfs != NULL. This will lead to execution of the error handling `if` statement at the `out` label, and hence to a call to dmu_objset_disown and zfsvfs_free. However, zfs_umount, which we call upon failure of zfs_root and d_make_root already does dmu_objset_disown and zfsvfs_free. I suppose this patch rather adds to the brittleness of this part of the code base, but I don't want to invest more time in this right now. To add a regression test, we'd need some kind of fault injection facility for zfs_root or d_make_root, which doesn't exist right now. And even then, I think that regression test would be too closely tied to the implementation. To repro the double-disown / double-free, do the following: 1. patch zfs_root to always return an error 2. mount a ZFS filesystem Here's the stack trace you would see then: VERIFY3(ds->ds_owner == tag) failed (0000000000000000 == ffff9142361e8000) PANIC at dsl_dataset.c:1003:dsl_dataset_disown() Showing stack for process 28332 CPU: 2 PID: 28332 Comm: zpool Tainted: G O 5.10.103-1.nutanix.el7.x86_64 #1 Call Trace: dump_stack+0x74/0x92 spl_dumpstack+0x29/0x2b [spl] spl_panic+0xd4/0xfc [spl] dsl_dataset_disown+0xe9/0x150 [zfs] dmu_objset_disown+0xd6/0x150 [zfs] zfs_domount+0x17b/0x4b0 [zfs] zpl_mount+0x174/0x220 [zfs] legacy_get_tree+0x2b/0x50 vfs_get_tree+0x2a/0xc0 path_mount+0x2fa/0xa70 do_mount+0x7c/0xa0 __x64_sys_mount+0x8b/0xe0 do_syscall_64+0x38/0x50 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Reviewed-by: Ryan Moeller Co-authored-by: Christian Schwarz Signed-off-by: Christian Schwarz Closes #14025 --- module/os/linux/zfs/zfs_vfsops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c index 64d6b4616e1c..7b682e49d84e 100644 --- a/module/os/linux/zfs/zfs_vfsops.c +++ b/module/os/linux/zfs/zfs_vfsops.c @@ -1556,6 +1556,7 @@ zfs_domount(struct super_block *sb, zfs_mnt_t *zm, int silent) error = zfs_root(zfsvfs, &root_inode); if (error) { (void) zfs_umount(sb); + zfsvfs = NULL; /* avoid double-free; first in zfs_umount */ goto out; } @@ -1563,6 +1564,7 @@ zfs_domount(struct super_block *sb, zfs_mnt_t *zm, int silent) sb->s_root = d_make_root(root_inode); if (sb->s_root == NULL) { (void) zfs_umount(sb); + zfsvfs = NULL; /* avoid double-free; first in zfs_umount */ error = SET_ERROR(ENOMEM); goto out; } From 19516b69ee41c9d3e239cb132c31fa9b13af2356 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 14 Oct 2022 16:33:22 -0400 Subject: [PATCH 021/126] Fix potential NULL pointer dereference in lzc_ioctl() Users are allowed to pass NULL to resultp, but we unconditionally assume that they never do. When an external user does pass NULL to resultp, we dereference a NULL pointer. Clang's static analyzer complained about this. Reviewed-by: Brian Behlendorf Reviewed-by: Ryan Moeller Signed-off-by: Richard Yao Closes #14008 --- lib/libzfs_core/libzfs_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libzfs_core/libzfs_core.c b/lib/libzfs_core/libzfs_core.c index 16bd9af1bbc8..3fe65e665b9c 100644 --- a/lib/libzfs_core/libzfs_core.c +++ b/lib/libzfs_core/libzfs_core.c @@ -235,7 +235,7 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name, break; } } - if (zc.zc_nvlist_dst_filled) { + if (zc.zc_nvlist_dst_filled && resultp != NULL) { *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst, zc.zc_nvlist_dst_size); } From 6a42939fcd62533b7675e4c3fce12ded70806583 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 14 Oct 2022 16:37:54 -0400 Subject: [PATCH 022/126] Cleanup: Address Clang's static analyzer's unused code complaints These were categorized as the following: * Dead assignment 23 * Dead increment 4 * Dead initialization 6 * Dead nested assignment 18 Most of these are harmless, but since actual issues can hide among them, we correct them. That said, there were a few return values that were being ignored that appeared to merit some correction: * `destroy_callback()` in `cmd/zfs/zfs_main.c` ignored the error from `destroy_batched()`. We handle it by returning -1 if there is an error. * `zfs_do_upgrade()` in `cmd/zfs/zfs_main.c` ignored the error from `zfs_for_each()`. We handle it by doing a binary OR of the error value from the subsequent `zfs_for_each()` call to the existing value. This is how errors are mostly handled inside `zfs_for_each()`. The error value here is passed to exit from the zfs command, so doing a binary or on it is better than what we did previously. * `get_zap_prop()` in `module/zfs/zcp_get.c` ignored the error from `dsl_prop_get_ds()` when the property is not of type string. We return an error when it does. There is a small concern that the `zfs_get_temporary_prop()` call would handle things, but in the case that it does not, we would be pushing an uninitialized numval onto the lua stack. It is expected that `dsl_prop_get_ds()` will succeed anytime that `zfs_get_temporary_prop()` does, so that not giving it a chance to fix things is not a problem. * `draid_merge_impl()` in `tests/zfs-tests/cmd/draid.c` used `nvlist_add_nvlist()` twice in ways in which errors are expected to be impossible, so we switch to `fnvlist_add_nvlist()`. A few notable ones did not merit use of the return value, so we suppressed it with `(void)`: * `write_free_diffs()` in `lib/libzfs/libzfs_diff.c` ignored the error value from `describe_free()`. A look through the commit history revealed that this was intentional. * `arc_evict_hdr()` in `module/zfs/arc.c` did not need to use the returned handle from `arc_hdr_realloc()` because it is already referenced in lists. * `spa_vdev_detach()` in `module/zfs/spa.c` has a comment explicitly saying not to use the error from `vdev_label_init()` because whatever causes the error could be the reason why a detach is being done. Unfortunately, I am not presently able to analyze the kernel modules with Clang's static analyzer, so I could have missed some cases of this. In cases where reports were present in code that is duplicated between Linux and FreeBSD, I made a conscious effort to fix the FreeBSD version too. After this commit is merged, regressions like dee8934 should become extremely obvious with Clang's static analyzer since a regression would appear in the results as the only instance of unused code. That assumes that Coverity does not catch the issue first. My local branch with fixes from all of my outstanding non-draft pull requests shows 118 reports from Clang's static anlayzer after this patch. That is down by 51 from 169. Reviewed-by: Brian Behlendorf Reviewed-by: Cedric Berger Signed-off-by: Richard Yao Closes #13986 --- cmd/raidz_test/raidz_test.c | 2 -- cmd/zfs/zfs_main.c | 9 ++++-- lib/libefi/rdwr_efi.c | 4 +-- lib/libzfs/libzfs_dataset.c | 2 +- lib/libzfs/libzfs_diff.c | 2 +- lib/libzfs/libzfs_pool.c | 1 - lib/libzfs/libzfs_sendrecv.c | 4 +-- lib/libzfs/libzfs_util.c | 2 +- lib/libzutil/os/linux/zutil_device_path_os.c | 8 ++---- module/icp/algs/blake3/blake3.c | 4 +-- module/icp/algs/modes/ccm.c | 1 - module/icp/algs/modes/ctr.c | 1 - module/icp/algs/modes/gcm.c | 1 - module/lua/ldo.c | 2 +- module/os/freebsd/zfs/zfs_znode.c | 1 - module/os/freebsd/zfs/zio_crypt.c | 1 - module/os/linux/zfs/zfs_znode.c | 1 - module/os/linux/zfs/zio_crypt.c | 1 - module/zfs/arc.c | 2 +- module/zfs/dbuf.c | 1 - module/zfs/dsl_bookmark.c | 1 - module/zfs/dsl_dataset.c | 3 +- module/zfs/dsl_pool.c | 1 - module/zfs/mmp.c | 10 +++---- module/zfs/spa.c | 6 ++-- module/zfs/vdev.c | 1 - module/zfs/zcp_get.c | 4 ++- tests/zfs-tests/cmd/btree_test.c | 29 ++++++-------------- tests/zfs-tests/cmd/ctime.c | 1 - tests/zfs-tests/cmd/draid.c | 5 ++-- tests/zfs-tests/cmd/mkbusy.c | 8 ++---- tests/zfs-tests/cmd/user_ns_exec.c | 1 - 32 files changed, 45 insertions(+), 75 deletions(-) diff --git a/cmd/raidz_test/raidz_test.c b/cmd/raidz_test/raidz_test.c index 1ece55960d33..34f3f6f1ccc6 100644 --- a/cmd/raidz_test/raidz_test.c +++ b/cmd/raidz_test/raidz_test.c @@ -146,8 +146,6 @@ static void process_options(int argc, char **argv) memcpy(o, &rto_opts_defaults, sizeof (*o)); while ((opt = getopt(argc, argv, "TDBSvha:er:o:d:s:t:")) != -1) { - value = 0; - switch (opt) { case 'a': value = strtoull(optarg, NULL, 0); diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 7bda3f5292b3..ac51df0f9c10 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -1453,8 +1453,13 @@ destroy_callback(zfs_handle_t *zhp, void *data) if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) { cb->cb_snap_count++; fnvlist_add_boolean(cb->cb_batchedsnaps, name); - if (cb->cb_snap_count % 10 == 0 && cb->cb_defer_destroy) + if (cb->cb_snap_count % 10 == 0 && cb->cb_defer_destroy) { error = destroy_batched(cb); + if (error != 0) { + zfs_close(zhp); + return (-1); + } + } } else { error = destroy_batched(cb); if (error != 0 || @@ -2576,7 +2581,7 @@ zfs_do_upgrade(int argc, char **argv) cb.cb_foundone = B_FALSE; cb.cb_newer = B_TRUE; - ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM, + ret |= zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM, NULL, NULL, 0, upgrade_list_callback, &cb); if (!cb.cb_foundone && !found) { diff --git a/lib/libefi/rdwr_efi.c b/lib/libefi/rdwr_efi.c index f159a022496c..3501c3ea391c 100644 --- a/lib/libefi/rdwr_efi.c +++ b/lib/libefi/rdwr_efi.c @@ -423,7 +423,6 @@ efi_alloc_and_read(int fd, struct dk_gpt **vtoc) void *tmp; length = (int) sizeof (struct dk_gpt) + (int) sizeof (struct dk_part) * (vptr->efi_nparts - 1); - nparts = vptr->efi_nparts; if ((tmp = realloc(vptr, length)) == NULL) { /* cppcheck-suppress doubleFree */ free(vptr); @@ -565,10 +564,9 @@ int efi_rescan(int fd) { int retry = 10; - int error; /* Notify the kernel a devices partition table has been updated */ - while ((error = ioctl(fd, BLKRRPART)) != 0) { + while (ioctl(fd, BLKRRPART) != 0) { if ((--retry == 0) || (errno != EBUSY)) { (void) fprintf(stderr, "the kernel failed to rescan " "the partition table: %d\n", errno); diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index 133b3b358831..f8a61c64261f 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -2006,7 +2006,7 @@ zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received) if ((ret = changelist_prefix(cl)) != 0) goto error; - if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) { + if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0) { changelist_free(cl); return (zfs_standard_error(hdl, errno, errbuf)); } else { diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c index 80588a860c18..84e140ede665 100644 --- a/lib/libzfs/libzfs_diff.c +++ b/lib/libzfs/libzfs_diff.c @@ -377,7 +377,7 @@ write_free_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr) if (zc.zc_obj > dr->ddr_last) { break; } - err = describe_free(fp, di, zc.zc_obj, fobjname, + (void) describe_free(fp, di, zc.zc_obj, fobjname, MAXPATHLEN); } else if (errno == ESRCH) { break; diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index b9806dc30dac..c6f31d785b89 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -2214,7 +2214,6 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname, ((policy.zlp_rewind & ZPOOL_TRY_REWIND) != 0), nv); } nvlist_free(nv); - return (0); } return (ret); diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index bf93ac9bac18..3e9f63777424 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -2117,9 +2117,9 @@ send_prelim_records(zfs_handle_t *zhp, const char *from, int fd, fnvlist_add_boolean(hdrnv, "raw"); } - if ((err = gather_nvlist(zhp->zfs_hdl, tofs, + if (gather_nvlist(zhp->zfs_hdl, tofs, from, tosnap, recursive, raw, doall, replicate, skipmissing, - verbose, backup, holds, props, &fss, fsavlp)) != 0) { + verbose, backup, holds, props, &fss, fsavlp) != 0) { return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP, errbuf)); } diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 28dd4f426a96..b4679dbb36fd 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -1249,7 +1249,7 @@ zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp) static void zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type) { - zprop_list_t *pl = cbp->cb_proplist; + zprop_list_t *pl; int i; char *title; size_t len; diff --git a/lib/libzutil/os/linux/zutil_device_path_os.c b/lib/libzutil/os/linux/zutil_device_path_os.c index 05dbb39954fa..900d5e5bacd2 100644 --- a/lib/libzutil/os/linux/zutil_device_path_os.c +++ b/lib/libzutil/os/linux/zutil_device_path_os.c @@ -428,7 +428,6 @@ dm_get_underlying_path(const char *dm_name) char *tmp = NULL; char *path = NULL; char *dev_str; - int size; char *first_path = NULL; char *enclosure_path; @@ -450,7 +449,7 @@ dm_get_underlying_path(const char *dm_name) else dev_str = tmp; - if ((size = asprintf(&tmp, "/sys/block/%s/slaves/", dev_str)) == -1) { + if (asprintf(&tmp, "/sys/block/%s/slaves/", dev_str) == -1) { tmp = NULL; goto end; } @@ -479,8 +478,7 @@ dm_get_underlying_path(const char *dm_name) if (!enclosure_path) continue; - if ((size = asprintf( - &path, "/dev/%s", ep->d_name)) == -1) + if (asprintf(&path, "/dev/%s", ep->d_name) == -1) path = NULL; free(enclosure_path); break; @@ -499,7 +497,7 @@ dm_get_underlying_path(const char *dm_name) * enclosure devices. Throw up out hands and return the first * underlying path. */ - if ((size = asprintf(&path, "/dev/%s", first_path)) == -1) + if (asprintf(&path, "/dev/%s", first_path) == -1) path = NULL; } diff --git a/module/icp/algs/blake3/blake3.c b/module/icp/algs/blake3/blake3.c index 5f7018598820..604e05847ee6 100644 --- a/module/icp/algs/blake3/blake3.c +++ b/module/icp/algs/blake3/blake3.c @@ -189,9 +189,7 @@ static void chunk_state_update(const blake3_ops_t *ops, input_len -= BLAKE3_BLOCK_LEN; } - size_t take = chunk_state_fill_buf(ctx, input, input_len); - input += take; - input_len -= take; + chunk_state_fill_buf(ctx, input, input_len); } static output_t chunk_state_output(const blake3_chunk_state_t *ctx) diff --git a/module/icp/algs/modes/ccm.c b/module/icp/algs/modes/ccm.c index ed5498dafaa1..4a8bb9bbc2c8 100644 --- a/module/icp/algs/modes/ccm.c +++ b/module/icp/algs/modes/ccm.c @@ -67,7 +67,6 @@ ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length, return (CRYPTO_SUCCESS); } - lastp = (uint8_t *)ctx->ccm_cb; crypto_init_ptrs(out, &iov_or_mp, &offset); mac_buf = (uint8_t *)ctx->ccm_mac_buf; diff --git a/module/icp/algs/modes/ctr.c b/module/icp/algs/modes/ctr.c index c116ba3662ba..db6b1c71d5cd 100644 --- a/module/icp/algs/modes/ctr.c +++ b/module/icp/algs/modes/ctr.c @@ -60,7 +60,6 @@ ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length, return (CRYPTO_SUCCESS); } - lastp = (uint8_t *)ctx->ctr_cb; crypto_init_ptrs(out, &iov_or_mp, &offset); do { diff --git a/module/icp/algs/modes/gcm.c b/module/icp/algs/modes/gcm.c index ca328d54a7e6..16ef14b8ccaf 100644 --- a/module/icp/algs/modes/gcm.c +++ b/module/icp/algs/modes/gcm.c @@ -118,7 +118,6 @@ gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length, return (CRYPTO_SUCCESS); } - lastp = (uint8_t *)ctx->gcm_cb; crypto_init_ptrs(out, &iov_or_mp, &offset); gops = gcm_impl_get_ops(); diff --git a/module/lua/ldo.c b/module/lua/ldo.c index 24677596de12..6bef80514ce2 100644 --- a/module/lua/ldo.c +++ b/module/lua/ldo.c @@ -452,7 +452,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) { } res = ci->func; /* res == final position of 1st result */ wanted = ci->nresults; - L->ci = ci = ci->previous; /* back to caller */ + L->ci = ci->previous; /* back to caller */ /* move results to correct place */ for (i = wanted; i != 0 && firstResult < L->top; i--) setobjs2s(L, res++, firstResult++); diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c index 6345e9e69d30..192aa748fc13 100644 --- a/module/os/freebsd/zfs/zfs_znode.c +++ b/module/os/freebsd/zfs/zfs_znode.c @@ -1949,7 +1949,6 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl, } else if (error != ENOENT) { return (error); } - error = 0; for (;;) { uint64_t pobj; diff --git a/module/os/freebsd/zfs/zio_crypt.c b/module/os/freebsd/zfs/zio_crypt.c index 0410ddd65a5c..c5e745f7d196 100644 --- a/module/os/freebsd/zfs/zio_crypt.c +++ b/module/os/freebsd/zfs/zio_crypt.c @@ -1735,7 +1735,6 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key, goto error; if (locked) { rw_exit(&key->zk_salt_lock); - locked = B_FALSE; } if (authbuf != NULL) diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index 73c21b6c00a8..a97955f4020a 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -2136,7 +2136,6 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl, } else if (error != ENOENT) { return (error); } - error = 0; for (;;) { uint64_t pobj = 0; diff --git a/module/os/linux/zfs/zio_crypt.c b/module/os/linux/zfs/zio_crypt.c index 2bc1482e91ec..6f2bf7ed7569 100644 --- a/module/os/linux/zfs/zio_crypt.c +++ b/module/os/linux/zfs/zio_crypt.c @@ -1968,7 +1968,6 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key, if (locked) { rw_exit(&key->zk_salt_lock); - locked = B_FALSE; } if (authbuf != NULL) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 58fb36207313..54cfb4bd3d04 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -3939,7 +3939,7 @@ arc_evict_hdr(arc_buf_hdr_t *hdr, kmutex_t *hash_lock, uint64_t *real_evicted) * dropping from L1+L2 cached to L2-only, * realloc to remove the L1 header. */ - hdr = arc_hdr_realloc(hdr, hdr_full_cache, + (void) arc_hdr_realloc(hdr, hdr_full_cache, hdr_l2only_cache); *real_evicted += HDR_FULL_SIZE - HDR_L2ONLY_SIZE; } else { diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 77e6ad23ef89..7982d9702896 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -1549,7 +1549,6 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags, uint32_t aflags = ARC_FLAG_NOWAIT; int err, zio_flags; - err = zio_flags = 0; DB_DNODE_ENTER(db); dn = DB_DNODE(db); ASSERT(!zfs_refcount_is_zero(&db->db_holds)); diff --git a/module/zfs/dsl_bookmark.c b/module/zfs/dsl_bookmark.c index 8ca7ba8957aa..b95c94beff1f 100644 --- a/module/zfs/dsl_bookmark.c +++ b/module/zfs/dsl_bookmark.c @@ -229,7 +229,6 @@ dsl_bookmark_create_check_impl(dsl_pool_t *dp, switch (error) { case ESRCH: /* happy path: new bmark doesn't exist, proceed after switch */ - error = 0; break; case 0: error = SET_ERROR(EEXIST); diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c index 7a066b786cd0..c7577fc584af 100644 --- a/module/zfs/dsl_dataset.c +++ b/module/zfs/dsl_dataset.c @@ -3421,7 +3421,8 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx) conflicting_snaps = B_TRUE; } else if (err == ESRCH) { err = 0; - } else if (err != 0) { + } + if (err != 0) { goto out; } } diff --git a/module/zfs/dsl_pool.c b/module/zfs/dsl_pool.c index 5d4311ff4557..5ca918a87ee1 100644 --- a/module/zfs/dsl_pool.c +++ b/module/zfs/dsl_pool.c @@ -331,7 +331,6 @@ dsl_pool_open(dsl_pool_t *dp) /* * We might not have created the remap bpobj yet. */ - err = 0; } else { goto out; } diff --git a/module/zfs/mmp.c b/module/zfs/mmp.c index 4f0273f3ed86..ef0e01df390f 100644 --- a/module/zfs/mmp.c +++ b/module/zfs/mmp.c @@ -550,11 +550,11 @@ mmp_thread(void *arg) uint32_t mmp_fail_intervals = MMP_FAIL_INTVS_OK( zfs_multihost_fail_intervals); hrtime_t mmp_fail_ns = mmp_fail_intervals * mmp_interval; - boolean_t last_spa_suspended = suspended; - boolean_t last_spa_multihost = multihost; - uint64_t last_mmp_interval = mmp_interval; - uint32_t last_mmp_fail_intervals = mmp_fail_intervals; - hrtime_t last_mmp_fail_ns = mmp_fail_ns; + boolean_t last_spa_suspended; + boolean_t last_spa_multihost; + uint64_t last_mmp_interval; + uint32_t last_mmp_fail_intervals; + hrtime_t last_mmp_fail_ns; callb_cpr_t cpr; int skip_wait = 0; diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 26df0290c9ff..0a9f31a8fc85 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -6803,8 +6803,8 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing, pvd = oldvd->vdev_parent; - if ((error = spa_config_parse(spa, &newrootvd, nvroot, NULL, 0, - VDEV_ALLOC_ATTACH)) != 0) + if (spa_config_parse(spa, &newrootvd, nvroot, NULL, 0, + VDEV_ALLOC_ATTACH) != 0) return (spa_vdev_exit(spa, NULL, txg, EINVAL)); if (newrootvd->vdev_children != 1) @@ -7160,7 +7160,7 @@ spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done) * it may be that the unwritability of the disk is the reason * it's being detached! */ - error = vdev_label_init(vd, 0, VDEV_LABEL_REMOVE); + (void) vdev_label_init(vd, 0, VDEV_LABEL_REMOVE); /* * Remove vd from its parent and compact the parent's children. diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 7d22a66c7819..8c62112de71b 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -6078,7 +6078,6 @@ vdev_prop_get(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) strval = NULL; zprop_source_t src = ZPROP_SRC_DEFAULT; propname = za.za_name; - prop = vdev_name_to_prop(propname); switch (za.za_integer_length) { case 8: diff --git a/module/zfs/zcp_get.c b/module/zfs/zcp_get.c index cd17374eb422..f28266b8095f 100644 --- a/module/zfs/zcp_get.c +++ b/module/zfs/zcp_get.c @@ -467,7 +467,8 @@ get_zap_prop(lua_State *state, dsl_dataset_t *ds, zfs_prop_t zfs_prop) } else { error = dsl_prop_get_ds(ds, prop_name, sizeof (numval), 1, &numval, setpoint); - + if (error != 0) + goto out; #ifdef _KERNEL /* Fill in temporary value for prop, if applicable */ (void) zfs_get_temporary_prop(ds, zfs_prop, &numval, setpoint); @@ -489,6 +490,7 @@ get_zap_prop(lua_State *state, dsl_dataset_t *ds, zfs_prop_t zfs_prop) (void) lua_pushnumber(state, numval); } } +out: kmem_free(strval, ZAP_MAXVALUELEN); if (error == 0) get_prop_src(state, setpoint, zfs_prop); diff --git a/tests/zfs-tests/cmd/btree_test.c b/tests/zfs-tests/cmd/btree_test.c index ab8967b22b22..fb9de9c77787 100644 --- a/tests/zfs-tests/cmd/btree_test.c +++ b/tests/zfs-tests/cmd/btree_test.c @@ -220,7 +220,6 @@ insert_find_remove(zfs_btree_t *bt, char *why) static int drain_tree(zfs_btree_t *bt, char *why) { - uint64_t *p; avl_tree_t avl; int i = 0; int_node_t *node; @@ -232,11 +231,8 @@ drain_tree(zfs_btree_t *bt, char *why) /* Fill both trees with the same data */ for (i = 0; i < 64 * 1024; i++) { - void *ret; - u_longlong_t randval = random(); - if ((p = (uint64_t *)zfs_btree_find(bt, &randval, &bt_idx)) != - NULL) { + if (zfs_btree_find(bt, &randval, &bt_idx) != NULL) { continue; } zfs_btree_add_idx(bt, &randval, &bt_idx); @@ -248,7 +244,7 @@ drain_tree(zfs_btree_t *bt, char *why) } node->data = randval; - if ((ret = avl_find(&avl, node, &avl_idx)) != NULL) { + if (avl_find(&avl, node, &avl_idx) != NULL) { (void) snprintf(why, BUFSIZE, "Found in avl: %llu\n", randval); return (1); @@ -372,9 +368,7 @@ stress_tree(zfs_btree_t *bt, char *why) if (stress_only) { zfs_btree_index_t *idx = NULL; - uint64_t *rv; - - while ((rv = zfs_btree_destroy_nodes(bt, &idx)) != NULL) + while (zfs_btree_destroy_nodes(bt, &idx) != NULL) ; zfs_btree_verify(bt); } @@ -389,15 +383,15 @@ stress_tree(zfs_btree_t *bt, char *why) static int insert_duplicate(zfs_btree_t *bt) { - uint64_t *p, i = 23456; + uint64_t i = 23456; zfs_btree_index_t bt_idx = {0}; - if ((p = (uint64_t *)zfs_btree_find(bt, &i, &bt_idx)) != NULL) { + if (zfs_btree_find(bt, &i, &bt_idx) != NULL) { fprintf(stderr, "Found value in empty tree.\n"); return (0); } zfs_btree_add_idx(bt, &i, &bt_idx); - if ((p = (uint64_t *)zfs_btree_find(bt, &i, &bt_idx)) == NULL) { + if (zfs_btree_find(bt, &i, &bt_idx) == NULL) { fprintf(stderr, "Did not find expected value.\n"); return (0); } @@ -415,10 +409,10 @@ insert_duplicate(zfs_btree_t *bt) static int remove_missing(zfs_btree_t *bt) { - uint64_t *p, i = 23456; + uint64_t i = 23456; zfs_btree_index_t bt_idx = {0}; - if ((p = (uint64_t *)zfs_btree_find(bt, &i, &bt_idx)) != NULL) { + if (zfs_btree_find(bt, &i, &bt_idx) != NULL) { fprintf(stderr, "Found value in empty tree.\n"); return (0); } @@ -499,10 +493,6 @@ main(int argc, char *argv[]) break; } } - argc -= optind; - argv += optind; - optind = 1; - if (seed == 0) { (void) gettimeofday(&tp, NULL); @@ -536,7 +526,6 @@ main(int argc, char *argv[]) btree_test_t *test = &test_table[0]; while (test->name) { int retval; - uint64_t *rv; char why[BUFSIZE] = {0}; zfs_btree_index_t *idx = NULL; @@ -554,7 +543,7 @@ main(int argc, char *argv[]) } /* Remove all the elements and re-verify the tree */ - while ((rv = zfs_btree_destroy_nodes(&bt, &idx)) != NULL) + while (zfs_btree_destroy_nodes(&bt, &idx) != NULL) ; zfs_btree_verify(&bt); diff --git a/tests/zfs-tests/cmd/ctime.c b/tests/zfs-tests/cmd/ctime.c index f0f3d526eb3e..0f5d81aea613 100644 --- a/tests/zfs-tests/cmd/ctime.c +++ b/tests/zfs-tests/cmd/ctime.c @@ -327,7 +327,6 @@ main(void) if (access(tfile, F_OK) == 0) { (void) unlink(tfile); } - ret = 0; if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) { (void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno); return (1); diff --git a/tests/zfs-tests/cmd/draid.c b/tests/zfs-tests/cmd/draid.c index 46d7b4dcc69d..3e5ff59f7399 100644 --- a/tests/zfs-tests/cmd/draid.c +++ b/tests/zfs-tests/cmd/draid.c @@ -1285,12 +1285,11 @@ draid_merge_impl(nvlist_t *allcfgs, const char *srcfilename, int *mergedp) if (nv_worst_ratio < allcfg_worst_ratio) { fnvlist_remove(allcfgs, key); - error = nvlist_add_nvlist(allcfgs, - key, cfg); + fnvlist_add_nvlist(allcfgs, key, cfg); merged++; } } else if (error == ENOENT) { - error = nvlist_add_nvlist(allcfgs, key, cfg); + fnvlist_add_nvlist(allcfgs, key, cfg); merged++; } else { return (error); diff --git a/tests/zfs-tests/cmd/mkbusy.c b/tests/zfs-tests/cmd/mkbusy.c index cc4a6cfcb98c..78860381d880 100644 --- a/tests/zfs-tests/cmd/mkbusy.c +++ b/tests/zfs-tests/cmd/mkbusy.c @@ -148,14 +148,10 @@ main(int argc, char *argv[]) } if (!isdir) { - int fd; - - if ((fd = open(fpath, O_CREAT | O_RDWR, 0600)) < 0) + if (open(fpath, O_CREAT | O_RDWR, 0600) < 0) fail("open"); } else { - DIR *dp; - - if ((dp = opendir(fpath)) == NULL) + if (opendir(fpath) == NULL) fail("opendir"); } free(fpath); diff --git a/tests/zfs-tests/cmd/user_ns_exec.c b/tests/zfs-tests/cmd/user_ns_exec.c index 86593622399e..d781301473a9 100644 --- a/tests/zfs-tests/cmd/user_ns_exec.c +++ b/tests/zfs-tests/cmd/user_ns_exec.c @@ -97,7 +97,6 @@ set_idmap(pid_t pid, const char *file) mapfd = open(path, O_WRONLY); if (mapfd < 0) { - result = errno; perror("open"); return (errno); } From a1034ee90978042c3c744ef11549cd732dd1dcfd Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 14 Oct 2022 14:40:00 -0600 Subject: [PATCH 023/126] zstream: allow decompress to fix metadata for uncompressed records If a record is uncompressed on-disk but the block pointer insists otherwise, reading it will return EIO. This commit adds an "off" type to the "zstream decompress" command. Using it will set the compression field in a zfs stream to "off" without changing the record's data. Reviewed-by: Brian Behlendorf Reviewed-by: George Melikov Signed-off-by: Alan Somers Sponsored by: Axcient Closes #13997 --- cmd/zstream/zstream_decompress.c | 38 ++++++++++++++++++++++++++------ man/man8/zstream.8 | 8 ++++++- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/cmd/zstream/zstream_decompress.c b/cmd/zstream/zstream_decompress.c index 31d4b2d36982..e5527777bca3 100644 --- a/cmd/zstream/zstream_decompress.c +++ b/cmd/zstream/zstream_decompress.c @@ -115,7 +115,9 @@ zstream_do_decompress(int argc, char *argv[]) if (errno || *end != '\0') errx(1, "invalid value for offset"); if (argv[i]) { - if (0 == strcmp("lz4", argv[i])) + if (0 == strcmp("off", argv[i])) + type = ZIO_COMPRESS_OFF; + else if (0 == strcmp("lz4", argv[i])) type = ZIO_COMPRESS_LZ4; else if (0 == strcmp("lzjb", argv[i])) type = ZIO_COMPRESS_LZJB; @@ -127,8 +129,8 @@ zstream_do_decompress(int argc, char *argv[]) type = ZIO_COMPRESS_ZSTD; else { fprintf(stderr, "Invalid compression type %s.\n" - "Supported types are lz4, lzjb, gzip, zle, " - "and zstd\n", + "Supported types are off, lz4, lzjb, gzip, " + "zle, and zstd\n", argv[i]); exit(2); } @@ -240,6 +242,9 @@ zstream_do_decompress(int argc, char *argv[]) if (p != NULL) { zio_decompress_func_t *xfunc = NULL; switch ((enum zio_compress)(intptr_t)p->data) { + case ZIO_COMPRESS_OFF: + xfunc = NULL; + break; case ZIO_COMPRESS_LZJB: xfunc = lzjb_decompress; break; @@ -258,7 +263,6 @@ zstream_do_decompress(int argc, char *argv[]) default: assert(B_FALSE); } - assert(xfunc != NULL); /* @@ -266,12 +270,27 @@ zstream_do_decompress(int argc, char *argv[]) */ char *lzbuf = safe_calloc(payload_size); (void) sfread(lzbuf, payload_size, stdin); - if (0 != xfunc(lzbuf, buf, + if (xfunc == NULL) { + memcpy(buf, lzbuf, payload_size); + drrw->drr_compressiontype = + ZIO_COMPRESS_OFF; + if (verbose) + fprintf(stderr, "Resetting " + "compression type to off " + "for ino %llu offset " + "%llu\n", + (u_longlong_t) + drrw->drr_object, + (u_longlong_t) + drrw->drr_offset); + } else if (0 != xfunc(lzbuf, buf, payload_size, payload_size, 0)) { /* * The block must not be compressed, - * possibly because it gets written - * multiple times in this stream. + * at least not with this compression + * type, possibly because it gets + * written multiple times in this + * stream. */ warnx("decompression failed for " "ino %llu offset %llu", @@ -279,11 +298,16 @@ zstream_do_decompress(int argc, char *argv[]) (u_longlong_t)drrw->drr_offset); memcpy(buf, lzbuf, payload_size); } else if (verbose) { + drrw->drr_compressiontype = + ZIO_COMPRESS_OFF; fprintf(stderr, "successfully " "decompressed ino %llu " "offset %llu\n", (u_longlong_t)drrw->drr_object, (u_longlong_t)drrw->drr_offset); + } else { + drrw->drr_compressiontype = + ZIO_COMPRESS_OFF; } free(lzbuf); } else { diff --git a/man/man8/zstream.8 b/man/man8/zstream.8 index dd5342000216..bfe7ac3f6535 100644 --- a/man/man8/zstream.8 +++ b/man/man8/zstream.8 @@ -20,7 +20,7 @@ .\" .\" Copyright (c) 2020 by Delphix. All rights reserved. .\" -.Dd March 25, 2022 +.Dd October 4, 2022 .Dt ZSTREAM 8 .Os . @@ -96,6 +96,7 @@ Specify the object number and byte offset of each record that you wish to decompress. Optionally specify the compression type. Valid compression types include +.Sy off , .Sy gzip , .Sy lz4 , .Sy lzjb , @@ -108,6 +109,11 @@ Every record for that object beginning at that offset will be decompressed, if possible. It may not be possible, because the record may be corrupted in some but not all of the stream's snapshots. +Specifying a compression type of +.Sy off +will change the stream's metadata accordingly, without attempting decompression. +This can be useful if the record is already uncompressed but the metadata +insists otherwise. The repaired stream will be written to standard output. .Bl -tag -width "-v" .It Fl v From 0aae8a449b935e60740b8b282d4bc14da23fc96d Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 14 Oct 2022 16:41:56 -0400 Subject: [PATCH 024/126] Fix theoretical array overflow in lua_typename() Out of the 12 defects in lua that coverity reports, 5 of them involve `lua_typename()` and out of the dozens of defects in ZFS that lua reports, 3 of them involve `lua_typename()` due to the ZCP code. Given all of the uses of `lua_typename()` in the ZCP code, I was surprised that there were not more. It appears that only 2 were reported because only 3 called `lua_type()`, which does a defective sanity check that allows invalid types to be passed. lua/lua@d4fb848be77f4b0209acaf37a5b5e1cee741ddce addressed this in upstream lua 5.3. Unfortunately, we did not get that fix since we use lua 5.2 and we do not have assertions enabled in lua, so the upstream solution would not do anything. While we could adopt the upstream solution and enable assertions, a simpler solution is to fix the issue by making `lua_typename()` return `internal_type_error` whenever it is called with an invalid type. This avoids the array overflow and if we ever see it appear somewhere, we will know there is a problem with the lua interpreter. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #13947 --- module/lua/lapi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/lua/lapi.c b/module/lua/lapi.c index 726e5c2ad4bb..ed3a0f4cf9ec 100644 --- a/module/lua/lapi.c +++ b/module/lua/lapi.c @@ -250,6 +250,8 @@ LUA_API int lua_type (lua_State *L, int idx) { LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); + if (t > 8 || t < 0) + return "internal_type_error"; return ttypename(t); } From ab49df487b5dfee8d045195c30d3bf1b00c23910 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 17 Oct 2022 20:08:36 +0200 Subject: [PATCH 025/126] Linux compat: fix DECLARE_EVENT_CLASS() test when ZFS is built-in ZFS_LINUX_TRY_COMPILE_HEADER macro doesn't take CONFIG_ZFS=y into account. As a result, on several latest Linux versions, configure script marks DECLARE_EVENT_CLASS() available for non-GPL when ZFS is being built as a module, but marks it unavailable when ZFS is built-in. Follow the logic of the neighbor macros and adjust ZFS_LINUX_TRY_COMPILE_HEADER accordingly, so that it doesn't try to look for a .ko when ZFS is built-in. Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Signed-off-by: Alexander Lobakin Closes #14006 --- config/kernel.m4 | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/config/kernel.m4 b/config/kernel.m4 index 8a5c9296ad7b..f12b0da48d4a 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -940,8 +940,15 @@ dnl # like ZFS_LINUX_TRY_COMPILE, except the contents conftest.h are dnl # provided via the fifth parameter dnl # AC_DEFUN([ZFS_LINUX_TRY_COMPILE_HEADER], [ - ZFS_LINUX_COMPILE_IFELSE( - [ZFS_LINUX_TEST_PROGRAM([[$1]], [[$2]], [[ZFS_META_LICENSE]])], - [test -f build/conftest/conftest.ko], - [$3], [$4], [$5]) + AS_IF([test "x$enable_linux_builtin" = "xyes"], [ + ZFS_LINUX_COMPILE_IFELSE( + [ZFS_LINUX_TEST_PROGRAM([[$1]], [[$2]], + [[ZFS_META_LICENSE]])], + [test -f build/conftest/conftest.o], [$3], [$4], [$5]) + ], [ + ZFS_LINUX_COMPILE_IFELSE( + [ZFS_LINUX_TEST_PROGRAM([[$1]], [[$2]], + [[ZFS_META_LICENSE]])], + [test -f build/conftest/conftest.ko], [$3], [$4], [$5]) + ]) ]) From 27218a32fc5eb6661996204af3d43fd97c9bda4d Mon Sep 17 00:00:00 2001 From: Tino Reichardt Date: Tue, 18 Oct 2022 20:05:32 +0200 Subject: [PATCH 026/126] Fix declarations of non-global variables This patch inserts the `static` keyword to non-global variables, which where found by the analysis tool smatch. Reviewed-by: Matthew Ahrens Reviewed-by: Brian Behlendorf Signed-off-by: Tino Reichardt Closes #13970 --- cmd/zdb/zdb.c | 7 ++++--- cmd/zstream/zstream_dump.c | 8 ++++---- cmd/ztest.c | 16 ++++++++-------- module/os/linux/spl/spl-condvar.c | 2 +- module/os/linux/spl/spl-err.c | 2 +- module/os/linux/spl/spl-generic.c | 2 +- module/os/linux/spl/spl-kmem-cache.c | 2 +- module/os/linux/zfs/abd_os.c | 2 +- module/os/linux/zfs/zfs_debug.c | 2 +- module/os/linux/zfs/zvol_os.c | 2 +- module/zfs/zio.c | 2 +- module/zfs/zio_compress.c | 2 +- tests/zfs-tests/cmd/btree_test.c | 10 +++++----- tests/zfs-tests/cmd/checksum/edonr_test.c | 18 +++++++++--------- tests/zfs-tests/cmd/checksum/sha2_test.c | 20 ++++++++++---------- tests/zfs-tests/cmd/checksum/skein_test.c | 16 ++++++++-------- tests/zfs-tests/cmd/mmap_libaio.c | 2 +- 17 files changed, 58 insertions(+), 57 deletions(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 18a94da1f744..ecf044090d6e 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -128,7 +128,7 @@ uint8_t dump_opt[256]; typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size); -uint64_t *zopt_metaslab = NULL; +static uint64_t *zopt_metaslab = NULL; static unsigned zopt_metaslab_args = 0; typedef struct zopt_object_range { @@ -136,7 +136,8 @@ typedef struct zopt_object_range { uint64_t zor_obj_end; uint64_t zor_flags; } zopt_object_range_t; -zopt_object_range_t *zopt_object_ranges = NULL; + +static zopt_object_range_t *zopt_object_ranges = NULL; static unsigned zopt_object_args = 0; static int flagbits[256]; @@ -160,7 +161,7 @@ static int flagbits[256]; #define ZDB_FLAG_PRINT_BLKPTR 0x0040 #define ZDB_FLAG_VERBOSE 0x0080 -uint64_t max_inflight_bytes = 256 * 1024 * 1024; /* 256MB */ +static uint64_t max_inflight_bytes = 256 * 1024 * 1024; /* 256MB */ static int leaked_objects = 0; static range_tree_t *mos_refd_objs; diff --git a/cmd/zstream/zstream_dump.c b/cmd/zstream/zstream_dump.c index 4b562c237373..9955a1361e8d 100644 --- a/cmd/zstream/zstream_dump.c +++ b/cmd/zstream/zstream_dump.c @@ -54,10 +54,10 @@ */ #define DUMP_GROUPING 4 -uint64_t total_stream_len = 0; -FILE *send_stream = 0; -boolean_t do_byteswap = B_FALSE; -boolean_t do_cksum = B_TRUE; +static uint64_t total_stream_len = 0; +static FILE *send_stream = 0; +static boolean_t do_byteswap = B_FALSE; +static boolean_t do_cksum = B_TRUE; void * safe_malloc(size_t size) diff --git a/cmd/ztest.c b/cmd/ztest.c index b89cdde9eda3..a8f9e6b8760a 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -423,11 +423,11 @@ ztest_func_t ztest_fletcher; ztest_func_t ztest_fletcher_incr; ztest_func_t ztest_verify_dnode_bt; -uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */ -uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */ -uint64_t zopt_often = 1ULL * NANOSEC; /* every second */ -uint64_t zopt_sometimes = 10ULL * NANOSEC; /* every 10 seconds */ -uint64_t zopt_rarely = 60ULL * NANOSEC; /* every 60 seconds */ +static uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */ +static uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */ +static uint64_t zopt_often = 1ULL * NANOSEC; /* every second */ +static uint64_t zopt_sometimes = 10ULL * NANOSEC; /* every 10 seconds */ +static uint64_t zopt_rarely = 60ULL * NANOSEC; /* every 60 seconds */ #define ZTI_INIT(func, iters, interval) \ { .zi_func = (func), \ @@ -435,7 +435,7 @@ uint64_t zopt_rarely = 60ULL * NANOSEC; /* every 60 seconds */ .zi_interval = (interval), \ .zi_funcname = # func } -ztest_info_t ztest_info[] = { +static ztest_info_t ztest_info[] = { ZTI_INIT(ztest_dmu_read_write, 1, &zopt_always), ZTI_INIT(ztest_dmu_write_parallel, 10, &zopt_always), ZTI_INIT(ztest_dmu_object_alloc_free, 1, &zopt_always), @@ -515,7 +515,7 @@ typedef struct ztest_shared { static char ztest_dev_template[] = "%s/%s.%llua"; static char ztest_aux_template[] = "%s/%s.%s.%llu"; -ztest_shared_t *ztest_shared; +static ztest_shared_t *ztest_shared; static spa_t *ztest_spa = NULL; static ztest_ds_t *ztest_ds; @@ -2346,7 +2346,7 @@ ztest_replay_setattr(void *arg1, void *arg2, boolean_t byteswap) return (0); } -zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = { +static zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = { NULL, /* 0 no such transaction type */ ztest_replay_create, /* TX_CREATE */ NULL, /* TX_MKDIR */ diff --git a/module/os/linux/spl/spl-condvar.c b/module/os/linux/spl/spl-condvar.c index d0461a9f1298..e87954714e3a 100644 --- a/module/os/linux/spl/spl-condvar.c +++ b/module/os/linux/spl/spl-condvar.c @@ -37,7 +37,7 @@ #endif #define MAX_HRTIMEOUT_SLACK_US 1000 -unsigned int spl_schedule_hrtimeout_slack_us = 0; +static unsigned int spl_schedule_hrtimeout_slack_us = 0; static int param_set_hrtimeout_slack(const char *buf, zfs_kernel_param_t *kp) diff --git a/module/os/linux/spl/spl-err.c b/module/os/linux/spl/spl-err.c index 7d3f6127c4af..29781b9515b2 100644 --- a/module/os/linux/spl/spl-err.c +++ b/module/os/linux/spl/spl-err.c @@ -32,7 +32,7 @@ * analysis and other such goodies. * But we would still default to the current default of not to do that. */ -unsigned int spl_panic_halt; +static unsigned int spl_panic_halt; /* CSTYLED */ module_param(spl_panic_halt, uint, 0644); MODULE_PARM_DESC(spl_panic_halt, "Cause kernel panic on assertion failures"); diff --git a/module/os/linux/spl/spl-generic.c b/module/os/linux/spl/spl-generic.c index 6efaec592b8b..e3aa900ba6dd 100644 --- a/module/os/linux/spl/spl-generic.c +++ b/module/os/linux/spl/spl-generic.c @@ -90,7 +90,7 @@ EXPORT_SYMBOL(p0); * and use them when in_interrupt() from linux/preempt_mask.h evaluates to * true. */ -void __percpu *spl_pseudo_entropy; +static void __percpu *spl_pseudo_entropy; /* * spl_rand_next()/spl_rand_jump() are copied from the following CC-0 licensed diff --git a/module/os/linux/spl/spl-kmem-cache.c b/module/os/linux/spl/spl-kmem-cache.c index e355e2bfc3a0..edd04783b363 100644 --- a/module/os/linux/spl/spl-kmem-cache.c +++ b/module/os/linux/spl/spl-kmem-cache.c @@ -151,7 +151,7 @@ MODULE_PARM_DESC(spl_kmem_cache_kmem_threads, struct list_head spl_kmem_cache_list; /* List of caches */ struct rw_semaphore spl_kmem_cache_sem; /* Cache list lock */ -taskq_t *spl_kmem_cache_taskq; /* Task queue for aging / reclaim */ +static taskq_t *spl_kmem_cache_taskq; /* Task queue for aging / reclaim */ static void spl_cache_shrink(spl_kmem_cache_t *skc, void *obj); diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c index 2ab85f8cccd0..fcdd768522a8 100644 --- a/module/os/linux/zfs/abd_os.c +++ b/module/os/linux/zfs/abd_os.c @@ -132,7 +132,7 @@ static abd_stats_t abd_stats = { { "scatter_sg_table_retry", KSTAT_DATA_UINT64 }, }; -struct { +static struct { wmsum_t abdstat_struct_size; wmsum_t abdstat_linear_cnt; wmsum_t abdstat_linear_data_size; diff --git a/module/os/linux/zfs/zfs_debug.c b/module/os/linux/zfs/zfs_debug.c index 819416b68d5f..e5a600250659 100644 --- a/module/os/linux/zfs/zfs_debug.c +++ b/module/os/linux/zfs/zfs_debug.c @@ -35,7 +35,7 @@ typedef struct zfs_dbgmsg { static procfs_list_t zfs_dbgmsgs; static uint_t zfs_dbgmsg_size = 0; -uint_t zfs_dbgmsg_maxsize = 4<<20; /* 4MB */ +static uint_t zfs_dbgmsg_maxsize = 4<<20; /* 4MB */ /* * Internal ZFS debug messages are enabled by default. diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index 0d4e0dcd5a3d..d76bab3c0106 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -114,7 +114,7 @@ struct zvol_state_os { boolean_t use_blk_mq; }; -taskq_t *zvol_taskq; +static taskq_t *zvol_taskq; static struct ida zvol_ida; typedef struct zv_request_stack { diff --git a/module/zfs/zio.c b/module/zfs/zio.c index dce94b7b29c2..3f6847a236ef 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -3360,7 +3360,7 @@ zio_ddt_write(zio_t *zio) return (zio); } -ddt_entry_t *freedde; /* for debugging */ +static ddt_entry_t *freedde; /* for debugging */ static zio_t * zio_ddt_free(zio_t *zio) diff --git a/module/zfs/zio_compress.c b/module/zfs/zio_compress.c index 4c9cbc962093..0fb91ac81522 100644 --- a/module/zfs/zio_compress.c +++ b/module/zfs/zio_compress.c @@ -44,7 +44,7 @@ * If nonzero, every 1/X decompression attempts will fail, simulating * an undetected memory error. */ -unsigned long zio_decompress_fail_fraction = 0; +static unsigned long zio_decompress_fail_fraction = 0; /* * Compression vectors. diff --git a/tests/zfs-tests/cmd/btree_test.c b/tests/zfs-tests/cmd/btree_test.c index fb9de9c77787..9a34bf559be0 100644 --- a/tests/zfs-tests/cmd/btree_test.c +++ b/tests/zfs-tests/cmd/btree_test.c @@ -23,11 +23,11 @@ #define BUFSIZE 256 -int seed = 0; -int stress_timeout = 180; -int contents_frequency = 100; -int tree_limit = 64 * 1024; -boolean_t stress_only = B_FALSE; +static int seed = 0; +static int stress_timeout = 180; +static int contents_frequency = 100; +static int tree_limit = 64 * 1024; +static boolean_t stress_only = B_FALSE; static void usage(int exit_value) diff --git a/tests/zfs-tests/cmd/checksum/edonr_test.c b/tests/zfs-tests/cmd/checksum/edonr_test.c index 3a0a48533c53..d010fbfcd4d6 100644 --- a/tests/zfs-tests/cmd/checksum/edonr_test.c +++ b/tests/zfs-tests/cmd/checksum/edonr_test.c @@ -40,16 +40,16 @@ * Test messages from: * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf */ -const char *test_msg0 = "abc"; -const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmn" - "lmnomnopnopq"; -const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfghi" - "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; +static const char *test_msg0 = "abc"; +static const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklm" + "nlmnomnopnopq"; +static const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfgh" + "ijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; /* * Test digests computed by hand. There's no formal standard or spec for edonr. */ -const uint8_t edonr_224_test_digests[][28] = { +static const uint8_t edonr_224_test_digests[][28] = { { /* for test_msg0 */ 0x56, 0x63, 0xc4, 0x93, 0x95, 0x20, 0xfa, 0xf6, @@ -67,7 +67,7 @@ const uint8_t edonr_224_test_digests[][28] = { /* no test vector for test_msg2 */ }; -const uint8_t edonr_256_test_digests[][32] = { +static const uint8_t edonr_256_test_digests[][32] = { { /* for test_msg0 */ 0x54, 0xd7, 0x8b, 0x13, 0xc7, 0x4e, 0xda, 0x5a, @@ -85,7 +85,7 @@ const uint8_t edonr_256_test_digests[][32] = { /* no test vectorfor test_msg2 */ }; -const uint8_t edonr_384_test_digests[][48] = { +static const uint8_t edonr_384_test_digests[][48] = { { /* for test_msg0 */ 0x0e, 0x7c, 0xd7, 0x85, 0x78, 0x77, 0xe0, 0x89, @@ -110,7 +110,7 @@ const uint8_t edonr_384_test_digests[][48] = { } }; -const uint8_t edonr_512_test_digests[][64] = { +static const uint8_t edonr_512_test_digests[][64] = { { /* for test_msg0 */ 0x1b, 0x14, 0xdb, 0x15, 0x5f, 0x1d, 0x40, 0x65, diff --git a/tests/zfs-tests/cmd/checksum/sha2_test.c b/tests/zfs-tests/cmd/checksum/sha2_test.c index bb355311091e..d99e8757a24c 100644 --- a/tests/zfs-tests/cmd/checksum/sha2_test.c +++ b/tests/zfs-tests/cmd/checksum/sha2_test.c @@ -44,17 +44,17 @@ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf */ -const char *test_msg0 = "abc"; -const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmn" - "lmnomnopnopq"; -const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfghi" - "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; +static const char *test_msg0 = "abc"; +static const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklm" + "nlmnomnopnopq"; +static const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfgh" + "ijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; /* * Test digests from: * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf */ -const uint8_t sha256_test_digests[][32] = { +static const uint8_t sha256_test_digests[][32] = { { /* for test_msg0 */ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, @@ -72,7 +72,7 @@ const uint8_t sha256_test_digests[][32] = { /* no test vector for test_msg2 */ }; -const uint8_t sha384_test_digests[][48] = { +static const uint8_t sha384_test_digests[][48] = { { /* for test_msg0 */ 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, @@ -97,7 +97,7 @@ const uint8_t sha384_test_digests[][48] = { } }; -const uint8_t sha512_test_digests[][64] = { +static const uint8_t sha512_test_digests[][64] = { { /* for test_msg0 */ 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, @@ -126,7 +126,7 @@ const uint8_t sha512_test_digests[][64] = { } }; -const uint8_t sha512_224_test_digests[][28] = { +static const uint8_t sha512_224_test_digests[][28] = { { /* for test_msg0 */ 0x46, 0x34, 0x27, 0x0F, 0x70, 0x7B, 0x6A, 0x54, @@ -147,7 +147,7 @@ const uint8_t sha512_224_test_digests[][28] = { } }; -const uint8_t sha512_256_test_digests[][32] = { +static const uint8_t sha512_256_test_digests[][32] = { { /* for test_msg0 */ 0x53, 0x04, 0x8E, 0x26, 0x81, 0x94, 0x1E, 0xF9, diff --git a/tests/zfs-tests/cmd/checksum/skein_test.c b/tests/zfs-tests/cmd/checksum/skein_test.c index 13611c860c42..20eb36d3e883 100644 --- a/tests/zfs-tests/cmd/checksum/skein_test.c +++ b/tests/zfs-tests/cmd/checksum/skein_test.c @@ -44,18 +44,18 @@ /* * Test messages from the Skein spec, Appendix C. */ -const uint8_t test_msg0[] = { +static const uint8_t test_msg0[] = { 0xFF }; -const uint8_t test_msg1[] = { +static const uint8_t test_msg1[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, 0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0 }; -const uint8_t test_msg2[] = { +static const uint8_t test_msg2[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, @@ -66,7 +66,7 @@ const uint8_t test_msg2[] = { 0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0 }; -const uint8_t test_msg3[] = { +static const uint8_t test_msg3[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, @@ -85,7 +85,7 @@ const uint8_t test_msg3[] = { 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80 }; -const uint8_t test_msg4[] = { +static const uint8_t test_msg4[] = { 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, @@ -123,7 +123,7 @@ const uint8_t test_msg4[] = { /* * Test digests from the Skein spec, Appendix C. */ -const uint8_t skein_256_test_digests[][32] = { +static const uint8_t skein_256_test_digests[][32] = { { /* for test_msg0 */ 0x0B, 0x98, 0xDC, 0xD1, 0x98, 0xEA, 0x0E, 0x50, @@ -148,7 +148,7 @@ const uint8_t skein_256_test_digests[][32] = { /* no test digests for test_msg3 and test_msg4 */ }; -const uint8_t skein_512_test_digests[][64] = { +static const uint8_t skein_512_test_digests[][64] = { { /* for test_msg0 */ 0x71, 0xB7, 0xBC, 0xE6, 0xFE, 0x64, 0x52, 0x22, @@ -189,7 +189,7 @@ const uint8_t skein_512_test_digests[][64] = { /* no test digests for test_msg4 */ }; -const uint8_t skein_1024_test_digests[][128] = { +static const uint8_t skein_1024_test_digests[][128] = { { /* for test_msg0 */ 0xE6, 0x2C, 0x05, 0x80, 0x2E, 0xA0, 0x15, 0x24, diff --git a/tests/zfs-tests/cmd/mmap_libaio.c b/tests/zfs-tests/cmd/mmap_libaio.c index 7d76c9b4eb2f..5ee1f600a737 100644 --- a/tests/zfs-tests/cmd/mmap_libaio.c +++ b/tests/zfs-tests/cmd/mmap_libaio.c @@ -33,7 +33,7 @@ #include #include -io_context_t io_ctx; +static io_context_t io_ctx; static void do_sync_io(struct iocb *iocb) From d10bd7d288eb44bbdef686a0255271a174200701 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 18 Oct 2022 14:06:35 -0400 Subject: [PATCH 027/126] Coverity model file update Upon review, it was found that the model for malloc() was incorrect. In addition, several general purpose memory allocation functions were missing models: * kmem_vasprintf() * kmem_asprintf() * kmem_strdup() * kmem_strfree() * spl_vmem_alloc() * spl_vmem_zalloc() * spl_vmem_free() * calloc() As an experiment to try to find more bugs, some less than general purpose memory allocation functions were also given models: * zfsvfs_create() * zfsvfs_free() * nvlist_alloc() * nvlist_dup() * nvlist_free() * nvlist_pack() * nvlist_unpack() Finally, the models were improved using additional coverity primitives: * __coverity_negative_sink__() * __coverity_writeall0__() * __coverity_mark_as_uninitialized_buffer__() * __coverity_mark_as_afm_allocated__() In addition, an attempt to inform coverity that certain modelled functions read entire buffers was used by adding the following to certain models: int first = buf[0]; int last = buf[buflen-1]; It was inspired by the QEMU model file. No additional false positives were found by this, but it is believed that the more accurate model file will help to catch false positives in the future. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14048 --- contrib/coverity/model.c | 393 ++++++++++++++++++++++++++++++++++----- 1 file changed, 343 insertions(+), 50 deletions(-) diff --git a/contrib/coverity/model.c b/contrib/coverity/model.c index 8baa3a7e2d31..8e3e83cada19 100644 --- a/contrib/coverity/model.c +++ b/contrib/coverity/model.c @@ -29,11 +29,20 @@ #define NULL (0) +typedef enum { + B_FALSE = 0, + B_TRUE = 1 +} boolean_t; + +typedef unsigned int uint_t; + int condition0, condition1; int ddi_copyin(const void *from, void *to, size_t len, int flags) { + (void) flags; + __coverity_negative_sink__(len); __coverity_tainted_data_argument__(from); __coverity_tainted_data_argument__(to); __coverity_writeall__(to); @@ -42,13 +51,21 @@ ddi_copyin(const void *from, void *to, size_t len, int flags) void * memset(void *dst, int c, size_t len) { - __coverity_writeall__(dst); + __coverity_negative_sink__(len); + if (c == 0) + __coverity_writeall0__(dst); + else + __coverity_writeall__(dst); return (dst); } void * memmove(void *dst, void *src, size_t len) { + int first = ((char *)src)[0]; + int last = ((char *)src)[len-1]; + + __coverity_negative_sink__(len); __coverity_writeall__(dst); return (dst); } @@ -56,6 +73,10 @@ memmove(void *dst, void *src, size_t len) void * memcpy(void *dst, void *src, size_t len) { + int first = ((char *)src)[0]; + int last = ((char *)src)[len-1]; + + __coverity_negative_sink__(len); __coverity_writeall__(dst); return (dst); } @@ -63,43 +84,53 @@ memcpy(void *dst, void *src, size_t len) void * umem_alloc_aligned(size_t size, size_t align, int kmflags) { - (void) align; + __coverity_negative_sink__(size); + __coverity_negative_sink__(align); - if ((UMEM_NOFAIL & kmflags) == UMEM_NOFAIL) - return (__coverity_alloc__(size)); - else if (condition0) - return (__coverity_alloc__(size)); - else - return (NULL); + if (((UMEM_NOFAIL & kmflags) == UMEM_NOFAIL) || condition0) { + void *buf = __coverity_alloc__(size); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "umem_free"); + return (buf); + } + + return (NULL); } void * umem_alloc(size_t size, int kmflags) { - if ((UMEM_NOFAIL & kmflags) == UMEM_NOFAIL) - return (__coverity_alloc__(size)); - else if (condition0) - return (__coverity_alloc__(size)); - else - return (NULL); + __coverity_negative_sink__(size); + + if (((UMEM_NOFAIL & kmflags) == UMEM_NOFAIL) || condition0) { + void *buf = __coverity_alloc__(size); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "umem_free"); + return (buf); + } + + return (NULL); } void * umem_zalloc(size_t size, int kmflags) { - if ((UMEM_NOFAIL & kmflags) == UMEM_NOFAIL) - return (__coverity_alloc__(size)); - else if (condition0) - return (__coverity_alloc__(size)); - else - return (NULL); + __coverity_negative_sink__(size); + + if (((UMEM_NOFAIL & kmflags) == UMEM_NOFAIL) || condition0) { + void *buf = __coverity_alloc__(size); + __coverity_writeall0__(buf); + __coverity_mark_as_afm_allocated__(buf, "umem_free"); + return (buf); + } + + return (NULL); } void umem_free(void *buf, size_t size) { - (void) size; - + __coverity_negative_sink__(size); __coverity_free__(buf); } @@ -113,12 +144,14 @@ umem_cache_alloc(umem_cache_t *skc, int flags) if (condition1) __coverity_sleep__(); - if ((UMEM_NOFAIL & flags) == UMEM_NOFAIL) - return (__coverity_alloc_nosize__()); - else if (condition0) - return (__coverity_alloc_nosize__()); - else - return (NULL); + if (((UMEM_NOFAIL & flags) == UMEM_NOFAIL) || condition0) { + void *buf = __coverity_alloc_nosize__(); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "umem_cache_free"); + return (buf); + } + + return (NULL); } void @@ -135,15 +168,19 @@ spl_kmem_alloc(size_t sz, int fl, const char *func, int line) (void) func; (void) line; + __coverity_negative_sink__(sz); + if (condition1) __coverity_sleep__(); - if (fl == 0) { - return (__coverity_alloc__(sz)); - } else if (condition0) - return (__coverity_alloc__(sz)); - else - return (NULL); + if ((fl == 0) || condition0) { + void *buf = __coverity_alloc__(sz); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "spl_kmem_free"); + return (buf); + } + + return (NULL); } void * @@ -152,22 +189,126 @@ spl_kmem_zalloc(size_t sz, int fl, const char *func, int line) (void) func; (void) line; + __coverity_negative_sink__(sz); + if (condition1) __coverity_sleep__(); - if (fl == 0) { - return (__coverity_alloc__(sz)); - } else if (condition0) - return (__coverity_alloc__(sz)); - else - return (NULL); + if ((fl == 0) || condition0) { + void *buf = __coverity_alloc__(sz); + __coverity_writeall0__(buf); + __coverity_mark_as_afm_allocated__(buf, "spl_kmem_free"); + return (buf); + } + + return (NULL); } void spl_kmem_free(const void *ptr, size_t sz) { - (void) sz; + __coverity_negative_sink__(sz); + __coverity_free__(ptr); +} +char * +kmem_vasprintf(const char *fmt, va_list ap) +{ + char *buf = __coverity_alloc_nosize__(); + (void) ap; + + __coverity_string_null_sink__(fmt); + __coverity_string_size_sink__(fmt); + + __coverity_writeall__(buf); + + __coverity_mark_as_afm_allocated__(buf, "kmem_strfree"); + + return (buf); +} + +char * +kmem_asprintf(const char *fmt, ...) +{ + char *buf = __coverity_alloc_nosize__(); + + __coverity_string_null_sink__(fmt); + __coverity_string_size_sink__(fmt); + + __coverity_writeall__(buf); + + __coverity_mark_as_afm_allocated__(buf, "kmem_strfree"); + + return (buf); +} + +char * +kmem_strdup(const char *str) +{ + char *buf = __coverity_alloc_nosize__(); + + __coverity_string_null_sink__(str); + __coverity_string_size_sink__(str); + + __coverity_writeall__(buf); + + __coverity_mark_as_afm_allocated__(buf, "kmem_strfree"); + + return (buf); + + +} + +void +kmem_strfree(char *str) +{ + __coverity_free__(str); +} + +void * +spl_vmem_alloc(size_t sz, int fl, const char *func, int line) +{ + (void) func; + (void) line; + + __coverity_negative_sink__(sz); + + if (condition1) + __coverity_sleep__(); + + if ((fl == 0) || condition0) { + void *buf = __coverity_alloc__(sz); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "spl_vmem_free"); + return (buf); + } + + return (NULL); +} + +void * +spl_vmem_zalloc(size_t sz, int fl, const char *func, int line) +{ + (void) func; + (void) line; + + if (condition1) + __coverity_sleep__(); + + if ((fl == 0) || condition0) { + void *buf = __coverity_alloc__(sz); + __coverity_writeall0__(buf); + __coverity_mark_as_afm_allocated__(buf, "spl_vmem_free"); + return (buf); + } + + return (NULL); +} + +void +spl_vmem_free(const void *ptr, size_t sz) +{ + __coverity_negative_sink__(sz); __coverity_free__(ptr); } @@ -181,12 +322,12 @@ spl_kmem_cache_alloc(spl_kmem_cache_t *skc, int flags) if (condition1) __coverity_sleep__(); - if (flags == 0) { - return (__coverity_alloc_nosize__()); - } else if (condition0) - return (__coverity_alloc_nosize__()); - else - return (NULL); + if ((flags == 0) || condition0) { + void *buf = __coverity_alloc_nosize__(); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "spl_kmem_cache_free"); + return (buf); + } } void @@ -197,12 +338,164 @@ spl_kmem_cache_free(spl_kmem_cache_t *skc, void *obj) __coverity_free__(obj); } -void -malloc(size_t size) +typedef struct {} zfsvfs_t; + +int +zfsvfs_create(const char *osname, boolean_t readonly, zfsvfs_t **zfvp) { - __coverity_alloc__(size); + (void) osname; + (void) readonly; + + if (condition1) + __coverity_sleep__(); + + if (condition0) { + *zfvp = __coverity_alloc_nosize__(); + __coverity_writeall__(*zfvp); + return (0); + } + + return (1); } +void +zfsvfs_free(zfsvfs_t *zfsvfs) +{ + __coverity_free__(zfsvfs); +} + +typedef struct {} nvlist_t; + +int +nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag) +{ + (void) nvflag; + + if (condition1) + __coverity_sleep__(); + + if ((kmflag == 0) || condition0) { + *nvlp = __coverity_alloc_nosize__(); + __coverity_mark_as_afm_allocated__(*nvlp, "nvlist_free"); + __coverity_writeall__(*nvlp); + return (0); + } + + return (-1); + +} + +int +nvlist_dup(const nvlist_t *nvl, nvlist_t **nvlp, int kmflag) +{ + nvlist_t read = *nvl; + + if (condition1) + __coverity_sleep__(); + + if ((kmflag == 0) || condition0) { + nvlist_t *nvl = __coverity_alloc_nosize__(); + __coverity_mark_as_afm_allocated__(nvl, "nvlist_free"); + __coverity_writeall__(nvl); + *nvlp = nvl; + return (0); + } + + return (-1); +} + +void +nvlist_free(nvlist_t *nvl) +{ + __coverity_free__(nvl); +} + +int +nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, + int kmflag) +{ + (void) nvl; + (void) encoding; + + if (*bufp == NULL) { + if (condition1) + __coverity_sleep__(); + + if ((kmflag == 0) || condition0) { + char *buf = __coverity_alloc_nosize__(); + __coverity_writeall__(buf); + /* + * We cannot use __coverity_mark_as_afm_allocated__() + * because the free function varies between the kernel + * and userspace. + */ + *bufp = buf; + return (0); + } + + return (-1); + } + + /* + * Unfortunately, errors from the buffer being too small are not + * possible to model, so we assume success. + */ + __coverity_negative_sink__(*buflen); + __coverity_writeall__(*bufp); + return (0); +} + + +int +nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag) +{ + __coverity_negative_sink__(buflen); + + if (condition1) + __coverity_sleep__(); + + if ((kmflag == 0) || condition0) { + nvlist_t *nvl = __coverity_alloc_nosize__(); + __coverity_mark_as_afm_allocated__(nvl, "nvlist_free"); + __coverity_writeall__(nvl); + *nvlp = nvl; + int first = buf[0]; + int last = buf[buflen-1]; + return (0); + } + + return (-1); + +} + +void * +malloc(size_t size) +{ + void *buf = __coverity_alloc__(size); + + if (condition1) + __coverity_sleep__(); + + __coverity_negative_sink__(size); + __coverity_mark_as_uninitialized_buffer__(buf); + __coverity_mark_as_afm_allocated__(buf, "free"); + + return (buf); +} + +void * +calloc(size_t nmemb, size_t size) +{ + void *buf = __coverity_alloc__(size * nmemb); + + if (condition1) + __coverity_sleep__(); + + __coverity_negative_sink__(size); + __coverity_writeall0__(buf); + __coverity_mark_as_afm_allocated__(buf, "free"); + return (buf); +} void free(void *buf) { From ecb6a50819448cd2d6570298a5ba46b45eded216 Mon Sep 17 00:00:00 2001 From: Coleman Kane Date: Tue, 18 Oct 2022 15:29:44 -0400 Subject: [PATCH 028/126] Linux 6.1 compat: change order of sys/mutex.h includes After Linux 6.1-rc1 came out, the build started failing to build a couple of the files in the linux spl code due to the mutex_init redefinition. Moving the sys/mutex.h include to a lower position within these two files appears to fix the problem. Reviewed-by: Brian Behlendorf Signed-off-by: Coleman Kane Closes #14040 --- module/os/linux/spl/spl-procfs-list.c | 2 +- module/os/linux/spl/spl-zone.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/module/os/linux/spl/spl-procfs-list.c b/module/os/linux/spl/spl-procfs-list.c index a4a24dcae2bd..5e073950d61a 100644 --- a/module/os/linux/spl/spl-procfs-list.c +++ b/module/os/linux/spl/spl-procfs-list.c @@ -23,9 +23,9 @@ */ #include -#include #include #include +#include /* * A procfs_list is a wrapper around a linked list which implements the seq_file diff --git a/module/os/linux/spl/spl-zone.c b/module/os/linux/spl/spl-zone.c index 9421f81bf0c8..b489179f1257 100644 --- a/module/os/linux/spl/spl-zone.c +++ b/module/os/linux/spl/spl-zone.c @@ -25,7 +25,6 @@ */ #include -#include #include #include #include @@ -37,6 +36,8 @@ #include #endif +#include + static kmutex_t zone_datasets_lock; static struct list_head zone_datasets; From 09453dea6a986278873cd77a571c9b26a53fdb02 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 18 Oct 2022 15:42:14 -0400 Subject: [PATCH 029/126] ZED: Fix uninitialized value reads Coverity complained about a couple of uninitialized value reads in ZED. * zfs_deliver_dle() can pass an uninitialized string to zed_log_msg() * An uninitialized sev.sigev_signo is passed to timer_create() The former would log garbage while the latter is not a real issue, but we might as well suppress it by initializing the field to 0 for consistency's sake. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14047 --- cmd/zed/agents/fmd_api.c | 1 + cmd/zed/agents/zfs_mod.c | 1 + 2 files changed, 2 insertions(+) diff --git a/cmd/zed/agents/fmd_api.c b/cmd/zed/agents/fmd_api.c index 56c134b731b8..6858da5e7cf1 100644 --- a/cmd/zed/agents/fmd_api.c +++ b/cmd/zed/agents/fmd_api.c @@ -616,6 +616,7 @@ fmd_timer_install(fmd_hdl_t *hdl, void *arg, fmd_event_t *ep, hrtime_t delta) sev.sigev_notify_function = _timer_notify; sev.sigev_notify_attributes = NULL; sev.sigev_value.sival_ptr = ftp; + sev.sigev_signo = 0; timer_create(CLOCK_REALTIME, &sev, &ftp->ft_tid); timer_settime(ftp->ft_tid, 0, &its, NULL); diff --git a/cmd/zed/agents/zfs_mod.c b/cmd/zed/agents/zfs_mod.c index e149c27ee025..44abb4eb9a34 100644 --- a/cmd/zed/agents/zfs_mod.c +++ b/cmd/zed/agents/zfs_mod.c @@ -1135,6 +1135,7 @@ zfs_deliver_dle(nvlist_t *nvl) strlcpy(name, devname, MAXPATHLEN); zfs_append_partition(name, MAXPATHLEN); } else { + sprintf(name, "unknown"); zed_log_msg(LOG_INFO, "zfs_deliver_dle: no guid or physpath"); } From aa822e4d9c0f68ff9c7d236cc7c8a88bdf375aea Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 14 Oct 2022 22:45:13 -0400 Subject: [PATCH 030/126] Fix NULL pointer dereference in zdb Clang's static analyzer complained that we dereference a NULL pointer in dump_path() if we return 0 when there is an error. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14044 --- cmd/zdb/zdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index ecf044090d6e..d626d082440f 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -3067,7 +3067,7 @@ open_objset(const char *path, const void *tag, objset_t **osp) } sa_os = *osp; - return (0); + return (err); } static void From 711b35dc24a8165929a9402ff8406248b65467bc Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 14 Oct 2022 22:46:43 -0400 Subject: [PATCH 031/126] fm_fmri_hc_create() must call va_end() before returning clang-tidy caught this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14044 --- module/zfs/fm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/module/zfs/fm.c b/module/zfs/fm.c index 32b5cf8facd1..3f05d759770b 100644 --- a/module/zfs/fm.c +++ b/module/zfs/fm.c @@ -955,6 +955,7 @@ fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth, } atomic_inc_64( &erpt_kstat_data.fmri_set_failed.value.ui64); + va_end(ap); return; } } From 3146fc7edf7e1290396b92d51952b9188b873e7f Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 14 Oct 2022 22:55:48 -0400 Subject: [PATCH 032/126] Fix NULL pointer passed to strlcpy from zap_lookup_impl() Clang's static analyzer pointed out that whenever zap_lookup_by_dnode() is called, we have the following stack where strlcpy() is passed a NULL pointer for realname from zap_lookup_by_dnode(): strlcpy() zap_lookup_impl() zap_lookup_norm_by_dnode() zap_lookup_by_dnode() Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14044 --- module/zfs/zap_micro.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c index 58a5c9f600b7..4bf8a322e91b 100644 --- a/module/zfs/zap_micro.c +++ b/module/zfs/zap_micro.c @@ -990,8 +990,10 @@ zap_lookup_impl(zap_t *zap, const char *name, } else { *(uint64_t *)buf = MZE_PHYS(zap, mze)->mze_value; - (void) strlcpy(realname, - MZE_PHYS(zap, mze)->mze_name, rn_len); + if (realname != NULL) + (void) strlcpy(realname, + MZE_PHYS(zap, mze)->mze_name, + rn_len); if (ncp) { *ncp = mzap_normalization_conflict(zap, zn, mze); From 1bd02680c0dfb0e1350b0efed931d62861ad27b3 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sun, 16 Oct 2022 00:19:13 -0400 Subject: [PATCH 033/126] Fix NULL pointer dereference in spa_open_common() Calling spa_open() will pass a NULL pointer to spa_open_common()'s config parameter. Under the right circumstances, we will dereference the config parameter without doing a NULL check. Clang's static analyzer found this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14044 --- module/zfs/spa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 0a9f31a8fc85..5d568e8340d6 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -5267,7 +5267,7 @@ spa_open_common(const char *pool, spa_t **spapp, const void *tag, * If we've recovered the pool, pass back any information we * gathered while doing the load. */ - if (state == SPA_LOAD_RECOVER) { + if (state == SPA_LOAD_RECOVER && config != NULL) { fnvlist_add_nvlist(*config, ZPOOL_CONFIG_LOAD_INFO, spa->spa_load_info); } From c6b161e390e9daf41ff6b0709cf6dfe529fa0627 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sun, 16 Oct 2022 00:56:55 -0400 Subject: [PATCH 034/126] set_global_var() should not pass NULL pointers to dlclose() Both Coverity and Clang's static analyzer caught this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14044 --- lib/libzpool/util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libzpool/util.c b/lib/libzpool/util.c index 0ce7822a3563..a310255d7a7d 100644 --- a/lib/libzpool/util.c +++ b/lib/libzpool/util.c @@ -229,13 +229,14 @@ set_global_var(char const *arg) fprintf(stderr, "Failed to open libzpool.so to set global " "variable\n"); ret = EIO; - goto out_dlclose; + goto out_free; } ret = 0; out_dlclose: dlclose(zpoolhdl); +out_free: free(varname); out_ret: return (ret); From 6ae2f9088853737b87998408656fe4c3a7b9235b Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 17 Oct 2022 02:06:40 -0400 Subject: [PATCH 035/126] Fix possible NULL pointer dereference in sha2_mac_init() If mechanism->cm_param is NULL, passing mechanism to PROV_SHA2_GET_DIGEST_LEN() will dereference a NULL pointer. Coverity reported this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14044 --- module/icp/io/sha2_mod.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/module/icp/io/sha2_mod.c b/module/icp/io/sha2_mod.c index fadb58b81881..a58f0982c8c0 100644 --- a/module/icp/io/sha2_mod.c +++ b/module/icp/io/sha2_mod.c @@ -737,12 +737,15 @@ sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, */ if (mechanism->cm_type % 3 == 2) { if (mechanism->cm_param == NULL || - mechanism->cm_param_len != sizeof (ulong_t)) - ret = CRYPTO_MECHANISM_PARAM_INVALID; - PROV_SHA2_GET_DIGEST_LEN(mechanism, - PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len); - if (PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len > sha_digest_len) + mechanism->cm_param_len != sizeof (ulong_t)) { ret = CRYPTO_MECHANISM_PARAM_INVALID; + } else { + PROV_SHA2_GET_DIGEST_LEN(mechanism, + PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len); + if (PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len > + sha_digest_len) + ret = CRYPTO_MECHANISM_PARAM_INVALID; + } } if (ret != CRYPTO_SUCCESS) { From 9a8039439a6cee003c7da0eedf7a54486c7145f7 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 15 Oct 2022 22:54:57 -0400 Subject: [PATCH 036/126] Cleanup: Simplify userspace abd_free_chunks() Clang's static analyzer complained that we could use after free here if the inner loop ever iterated. That is a false positive, but upon inspection, the userland abd_alloc_chunks() function never will put multiple consecutive pages into a `struct scatterlist`, so there is no need to loop. We delete the inner loop. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14042 --- module/os/linux/zfs/abd_os.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c index fcdd768522a8..e9b28becf6a0 100644 --- a/module/os/linux/zfs/abd_os.c +++ b/module/os/linux/zfs/abd_os.c @@ -597,10 +597,8 @@ abd_free_chunks(abd_t *abd) struct scatterlist *sg; abd_for_each_sg(abd, sg, n, i) { - for (int j = 0; j < sg->length; j += PAGESIZE) { - struct page *p = nth_page(sg_page(sg), j >> PAGE_SHIFT); - umem_free(p, PAGESIZE); - } + struct page *p = nth_page(sg_page(sg), 0); + umem_free(p, PAGESIZE); } abd_free_sg_table(abd); } From d953bcbf6b28653959a98602665b6c6fc186cef8 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sun, 16 Oct 2022 00:42:03 -0400 Subject: [PATCH 037/126] Cleanup: Delete unnecessary pointer check from vdev_to_nvlist_iter() This confused Clang's static analyzer, making it think there was a possible NULL pointer dereference. There is no NULL pointer dereference. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14042 --- lib/libzfs/libzfs_pool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index c6f31d785b89..f0bb2370a4c8 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -2678,7 +2678,7 @@ vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare, if (zfs_strcmp_pathname(srchval, val, wholedisk) == 0) return (nv); - } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) { + } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0) { char *type, *idx, *end, *p; uint64_t id, vdev_id; From ef55679a75f07a70fd016b2cb2a62d418c5b429f Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 17 Oct 2022 02:02:12 -0400 Subject: [PATCH 038/126] Cleanup: metaslab_alloc_dva() should not NULL check mg->mg_next This is a circularly linked list. mg->mg_next can never be NULL. This caused 3 defect reports in Coverity. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14042 --- module/zfs/metaslab.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c index 3c32d6f051e8..c624833bc981 100644 --- a/module/zfs/metaslab.c +++ b/module/zfs/metaslab.c @@ -5131,8 +5131,7 @@ metaslab_alloc_dva(spa_t *spa, metaslab_class_t *mc, uint64_t psize, if (vd != NULL && vd->vdev_mg != NULL) { mg = vdev_get_mg(vd, mc); - if (flags & METASLAB_HINTBP_AVOID && - mg->mg_next != NULL) + if (flags & METASLAB_HINTBP_AVOID) mg = mg->mg_next; } else { mg = mca->mca_rotor; From 717641ac09315ef254a234f4b866e92662a691a1 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 17 Oct 2022 02:18:09 -0400 Subject: [PATCH 039/126] Cleanup: zvol_add_clones() should not NULL check dp It is never NULL because we return early if dsl_pool_hold() fails. This caused Coverity to complain. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14042 --- module/zfs/zvol.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 2e2860ff0212..be8ee34f27ae 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -1026,8 +1026,7 @@ zvol_add_clones(const char *dsname, list_t *minors_list) out: if (dd != NULL) dsl_dir_rele(dd, FTAG); - if (dp != NULL) - dsl_pool_rele(dp, FTAG); + dsl_pool_rele(dp, FTAG); } /* From fb823de9fb086a43e6618abe93e540d6f8865c32 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 17 Oct 2022 02:20:21 -0400 Subject: [PATCH 040/126] Cleanup: Delete dead code from send_merge_thread() range is always deferenced before it reaches this check, such that the kmem_zalloc() call is never executed. There is also no need to set `range->eos_marker = B_TRUE` because it is already set. Coverity incorrectly complained about a potential NULL pointer dereference because of this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14042 --- module/zfs/dmu_send.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 4ee3ffc352b8..ceef87a3002e 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -1586,9 +1586,8 @@ send_merge_thread(void *arg) } range_free(front_ranges[i]); } - if (range == NULL) - range = kmem_zalloc(sizeof (*range), KM_SLEEP); - range->eos_marker = B_TRUE; + ASSERT3P(range, !=, NULL); + ASSERT3S(range->eos_marker, ==, B_TRUE); bqueue_enqueue_flush(&smt_arg->q, range, 1); spl_fstrans_unmark(cookie); thread_exit(); From 84243acb91b754de167c6bfc9a7db68e46b91870 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 17 Oct 2022 17:57:59 -0400 Subject: [PATCH 041/126] Cleanup: Remove NULL pointer check from dmu_send_impl() The pointer is to a structure member, so it is never NULL. Coverity complained about this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14042 --- module/zfs/dmu_send.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index ceef87a3002e..767b341a4347 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -2510,8 +2510,7 @@ dmu_send_impl(struct dmu_send_params *dspp) } if (featureflags & DMU_BACKUP_FEATURE_RAW) { - uint64_t ivset_guid = (ancestor_zb != NULL) ? - ancestor_zb->zbm_ivset_guid : 0; + uint64_t ivset_guid = ancestor_zb->zbm_ivset_guid; nvlist_t *keynvl = NULL; ASSERT(os->os_encrypted); From eaaed26ffb3a14c0c98ce1e6e039e62327ab4447 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 18 Oct 2022 19:03:33 -0400 Subject: [PATCH 042/126] Fix memory leaks in dmu_send()/dmu_send_obj() If we encounter an EXDEV error when using the redacted snapshots feature, the memory used by dspp.fromredactsnaps is leaked. Clang's static analyzer caught this during an experiment in which I had annotated various headers in an attempt to improve the results of static analysis. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #13973 --- module/zfs/dmu_send.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 767b341a4347..6e0057bb9ea8 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -2714,6 +2714,10 @@ dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap, dspp.numfromredactsnaps = NUM_SNAPS_NOT_REDACTED; err = dmu_send_impl(&dspp); } + if (dspp.fromredactsnaps) + kmem_free(dspp.fromredactsnaps, + dspp.numfromredactsnaps * sizeof (uint64_t)); + dsl_dataset_rele(dspp.to_ds, FTAG); return (err); } @@ -2922,6 +2926,10 @@ dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok, /* dmu_send_impl will call dsl_pool_rele for us. */ err = dmu_send_impl(&dspp); } else { + if (dspp.fromredactsnaps) + kmem_free(dspp.fromredactsnaps, + dspp.numfromredactsnaps * + sizeof (uint64_t)); dsl_pool_rele(dspp.dp, FTAG); } } else { From 2a068a1394d179dda4becf350e3afb4e8819675e Mon Sep 17 00:00:00 2001 From: youzhongyang Date: Wed, 19 Oct 2022 14:17:09 -0400 Subject: [PATCH 043/126] Support idmapped mount Adds support for idmapped mounts. Supported as of Linux 5.12 this functionality allows user and group IDs to be remapped without changing their state on disk. This can be useful for portable home directories and a variety of container related use cases. Reviewed-by: Brian Behlendorf Reviewed-by: Ryan Moeller Signed-off-by: Youzhong Yang Closes #12923 Closes #13671 --- config/kernel-idmap_mnt_api.m4 | 25 + config/kernel.m4 | 2 + include/os/freebsd/spl/sys/types.h | 2 + include/os/freebsd/zfs/sys/zfs_vnops_os.h | 12 +- include/os/linux/spl/sys/cred.h | 28 + include/os/linux/spl/sys/types.h | 3 + include/os/linux/zfs/sys/policy.h | 4 +- include/os/linux/zfs/sys/zfs_vnops_os.h | 15 +- include/os/linux/zfs/sys/zpl.h | 2 +- include/sys/zfs_acl.h | 11 +- module/os/freebsd/zfs/zfs_acl.c | 30 +- module/os/freebsd/zfs/zfs_dir.c | 4 +- module/os/freebsd/zfs/zfs_vnops_os.c | 60 +- module/os/freebsd/zfs/zfs_znode.c | 4 +- module/os/linux/zfs/policy.c | 13 +- module/os/linux/zfs/zfs_acl.c | 76 +- module/os/linux/zfs/zfs_dir.c | 7 +- module/os/linux/zfs/zfs_vnops_os.c | 77 +- module/os/linux/zfs/zfs_znode.c | 2 +- module/os/linux/zfs/zpl_ctldir.c | 6 +- module/os/linux/zfs/zpl_file.c | 6 +- module/os/linux/zfs/zpl_inode.c | 62 +- module/os/linux/zfs/zpl_super.c | 4 + module/os/linux/zfs/zpl_xattr.c | 2 +- module/zfs/zfs_replay.c | 14 +- module/zfs/zfs_vnops.c | 4 +- tests/runfiles/linux.run | 4 + tests/test-runner/bin/zts-report.py.in | 8 + tests/zfs-tests/cmd/.gitignore | 1 + tests/zfs-tests/cmd/Makefile.am | 2 + tests/zfs-tests/cmd/idmap_util.c | 791 ++++++++++++++++++ tests/zfs-tests/include/commands.cfg | 6 +- tests/zfs-tests/tests/Makefile.am | 12 +- .../tests/functional/idmap_mount/cleanup.ksh | 25 + .../functional/idmap_mount/idmap_mount.cfg | 25 + .../idmap_mount/idmap_mount_001.ksh | 76 ++ .../idmap_mount/idmap_mount_002.ksh | 97 +++ .../idmap_mount/idmap_mount_003.ksh | 121 +++ .../idmap_mount/idmap_mount_004.ksh | 106 +++ .../idmap_mount/idmap_mount_common.kshlib | 23 + .../tests/functional/idmap_mount/setup.ksh | 30 + 41 files changed, 1636 insertions(+), 166 deletions(-) create mode 100644 config/kernel-idmap_mnt_api.m4 create mode 100644 tests/zfs-tests/cmd/idmap_util.c create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/cleanup.ksh create mode 100644 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount.cfg create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_001.ksh create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_002.ksh create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_003.ksh create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_004.ksh create mode 100644 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_common.kshlib create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/setup.ksh diff --git a/config/kernel-idmap_mnt_api.m4 b/config/kernel-idmap_mnt_api.m4 new file mode 100644 index 000000000000..47ddc5702fb7 --- /dev/null +++ b/config/kernel-idmap_mnt_api.m4 @@ -0,0 +1,25 @@ +dnl # +dnl # 5.12 API +dnl # +dnl # Check if APIs for idmapped mount are available +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_IDMAP_MNT_API], [ + ZFS_LINUX_TEST_SRC([idmap_mnt_api], [ + #include + ],[ + int fs_flags = 0; + fs_flags |= FS_ALLOW_IDMAP; + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_IDMAP_MNT_API], [ + AC_MSG_CHECKING([whether APIs for idmapped mount are present]) + ZFS_LINUX_TEST_RESULT([idmap_mnt_api], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_IDMAP_MNT_API, 1, + [APIs for idmapped mount are present]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) + diff --git a/config/kernel.m4 b/config/kernel.m4 index f12b0da48d4a..d4d13ddd1d1a 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -147,6 +147,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_ZERO_PAGE ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC ZFS_AC_KERNEL_SRC_USER_NS_COMMON_INUM + ZFS_AC_KERNEL_SRC_IDMAP_MNT_API AC_MSG_CHECKING([for available kernel interfaces]) ZFS_LINUX_TEST_COMPILE_ALL([kabi]) @@ -267,6 +268,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_ZERO_PAGE ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC ZFS_AC_KERNEL_USER_NS_COMMON_INUM + ZFS_AC_KERNEL_IDMAP_MNT_API ]) dnl # diff --git a/include/os/freebsd/spl/sys/types.h b/include/os/freebsd/spl/sys/types.h index b1308df29503..558843dcaa74 100644 --- a/include/os/freebsd/spl/sys/types.h +++ b/include/os/freebsd/spl/sys/types.h @@ -105,5 +105,7 @@ typedef u_longlong_t len_t; typedef longlong_t diskaddr_t; +typedef void zuserns_t; + #include #endif /* !_OPENSOLARIS_SYS_TYPES_H_ */ diff --git a/include/os/freebsd/zfs/sys/zfs_vnops_os.h b/include/os/freebsd/zfs/sys/zfs_vnops_os.h index bf5e03b24c06..460aecd2e708 100644 --- a/include/os/freebsd/zfs/sys/zfs_vnops_os.h +++ b/include/os/freebsd/zfs/sys/zfs_vnops_os.h @@ -35,20 +35,22 @@ int dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count, int *rbehind, int *rahead, int last_size); extern int zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags); extern int zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, - znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp); + znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns); extern int zfs_rmdir(znode_t *dzp, const char *name, znode_t *cwd, cred_t *cr, int flags); -extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr); +extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr, + zuserns_t *mnt_ns); extern int zfs_rename(znode_t *sdzp, const char *snm, znode_t *tdzp, - const char *tnm, cred_t *cr, int flags); + const char *tnm, cred_t *cr, int flags, zuserns_t *mnt_ns); extern int zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap, - const char *link, znode_t **zpp, cred_t *cr, int flags); + const char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns); extern int zfs_link(znode_t *tdzp, znode_t *sp, const char *name, cred_t *cr, int flags); extern int zfs_space(znode_t *zp, int cmd, struct flock *bfp, int flag, offset_t offset, cred_t *cr); extern int zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, - int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp); + int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp, + zuserns_t *mnt_ns); extern int zfs_setsecattr(znode_t *zp, vsecattr_t *vsecp, int flag, cred_t *cr); extern int zfs_write_simple(znode_t *zp, const void *data, size_t len, diff --git a/include/os/linux/spl/sys/cred.h b/include/os/linux/spl/sys/cred.h index b7d3f38d70bb..dc3c260dbbab 100644 --- a/include/os/linux/spl/sys/cred.h +++ b/include/os/linux/spl/sys/cred.h @@ -45,6 +45,34 @@ typedef struct cred cred_t; #define SGID_TO_KGID(x) (KGIDT_INIT(x)) #define KGIDP_TO_SGIDP(x) (&(x)->val) +static inline uid_t zfs_uid_into_mnt(struct user_namespace *mnt_ns, uid_t uid) +{ + if (mnt_ns) + return (__kuid_val(make_kuid(mnt_ns, uid))); + return (uid); +} + +static inline gid_t zfs_gid_into_mnt(struct user_namespace *mnt_ns, gid_t gid) +{ + if (mnt_ns) + return (__kgid_val(make_kgid(mnt_ns, gid))); + return (gid); +} + +static inline uid_t zfs_uid_from_mnt(struct user_namespace *mnt_ns, uid_t uid) +{ + if (mnt_ns) + return (from_kuid(mnt_ns, KUIDT_INIT(uid))); + return (uid); +} + +static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid) +{ + if (mnt_ns) + return (from_kgid(mnt_ns, KGIDT_INIT(gid))); + return (gid); +} + extern void crhold(cred_t *cr); extern void crfree(cred_t *cr); extern uid_t crgetuid(const cred_t *cr); diff --git a/include/os/linux/spl/sys/types.h b/include/os/linux/spl/sys/types.h index b44c94518750..cae1bbddf105 100644 --- a/include/os/linux/spl/sys/types.h +++ b/include/os/linux/spl/sys/types.h @@ -54,4 +54,7 @@ typedef ulong_t pgcnt_t; typedef int major_t; typedef int minor_t; +struct user_namespace; +typedef struct user_namespace zuserns_t; + #endif /* _SPL_TYPES_H */ diff --git a/include/os/linux/zfs/sys/policy.h b/include/os/linux/zfs/sys/policy.h index 3bd7ce36b85d..ee7fda761a3b 100644 --- a/include/os/linux/zfs/sys/policy.h +++ b/include/os/linux/zfs/sys/policy.h @@ -47,13 +47,13 @@ int secpolicy_vnode_create_gid(const cred_t *); int secpolicy_vnode_remove(const cred_t *); int secpolicy_vnode_setdac(const cred_t *, uid_t); int secpolicy_vnode_setid_retain(struct znode *, const cred_t *, boolean_t); -int secpolicy_vnode_setids_setgids(const cred_t *, gid_t); +int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *); int secpolicy_zinject(const cred_t *); int secpolicy_zfs(const cred_t *); int secpolicy_zfs_proc(const cred_t *, proc_t *); void secpolicy_setid_clear(vattr_t *, cred_t *); int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *, - const vattr_t *, cred_t *); + const vattr_t *, cred_t *, zuserns_t *); int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, mode_t); int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *, const struct vattr *, int, int (void *, int, cred_t *), void *); diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h index 22ca625023b0..787d258e1388 100644 --- a/include/os/linux/zfs/sys/zfs_vnops_os.h +++ b/include/os/linux/zfs/sys/zfs_vnops_os.h @@ -45,22 +45,25 @@ extern int zfs_write_simple(znode_t *zp, const void *data, size_t len, extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags, cred_t *cr, int *direntflags, pathname_t *realpnp); extern int zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, - int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp); + int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp, + zuserns_t *mnt_ns); extern int zfs_tmpfile(struct inode *dip, vattr_t *vapzfs, int excl, - int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp); + int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp, + zuserns_t *mnt_ns); extern int zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags); extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, - znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp); + znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns); extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr, int flags); extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr); extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip, struct kstat *sp); -extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr); +extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr, + zuserns_t *mnt_ns); extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, - char *tnm, cred_t *cr, int flags); + char *tnm, cred_t *cr, int flags, zuserns_t *mnt_ns); extern int zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, - char *link, znode_t **zpp, cred_t *cr, int flags); + char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns); extern int zfs_readlink(struct inode *ip, zfs_uio_t *uio, cred_t *cr); extern int zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr, int flags); diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index 95f08f5416d0..30d73db6b9e8 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -39,7 +39,7 @@ /* zpl_inode.c */ extern void zpl_vap_init(vattr_t *vap, struct inode *dir, - umode_t mode, cred_t *cr); + umode_t mode, cred_t *cr, zuserns_t *mnt_ns); extern const struct inode_operations zpl_inode_operations; extern const struct inode_operations zpl_dir_inode_operations; diff --git a/include/sys/zfs_acl.h b/include/sys/zfs_acl.h index c4d2dddd7b1f..82fb98c9fb89 100644 --- a/include/sys/zfs_acl.h +++ b/include/sys/zfs_acl.h @@ -206,7 +206,7 @@ struct zfsvfs; #ifdef _KERNEL int zfs_acl_ids_create(struct znode *, int, vattr_t *, - cred_t *, vsecattr_t *, zfs_acl_ids_t *); + cred_t *, vsecattr_t *, zfs_acl_ids_t *, zuserns_t *); void zfs_acl_ids_free(zfs_acl_ids_t *); boolean_t zfs_acl_ids_overquota(struct zfsvfs *, zfs_acl_ids_t *, uint64_t); int zfs_getacl(struct znode *, vsecattr_t *, boolean_t, cred_t *); @@ -215,15 +215,16 @@ void zfs_acl_rele(void *); void zfs_oldace_byteswap(ace_t *, int); void zfs_ace_byteswap(void *, size_t, boolean_t); extern boolean_t zfs_has_access(struct znode *zp, cred_t *cr); -extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *); +extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *, + zuserns_t *); int zfs_fastaccesschk_execute(struct znode *, cred_t *); -extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *); +extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *, zuserns_t *); extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *); extern int zfs_acl_access(struct znode *, int, cred_t *); int zfs_acl_chmod_setattr(struct znode *, zfs_acl_t **, uint64_t); -int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *); +int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *, zuserns_t *); int zfs_zaccess_rename(struct znode *, struct znode *, - struct znode *, struct znode *, cred_t *cr); + struct znode *, struct znode *, cred_t *cr, zuserns_t *mnt_ns); void zfs_acl_free(zfs_acl_t *); int zfs_vsec_2_aclp(struct zfsvfs *, umode_t, vsecattr_t *, cred_t *, struct zfs_fuid_info **, zfs_acl_t **); diff --git a/module/os/freebsd/zfs/zfs_acl.c b/module/os/freebsd/zfs/zfs_acl.c index a85d4c24178b..c075e180a860 100644 --- a/module/os/freebsd/zfs/zfs_acl.c +++ b/module/os/freebsd/zfs/zfs_acl.c @@ -1619,7 +1619,7 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp, */ int zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, - vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) + vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids, zuserns_t *mnt_ns) { int error; zfsvfs_t *zfsvfs = dzp->z_zfsvfs; @@ -1789,7 +1789,7 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (mask == 0) return (SET_ERROR(ENOSYS)); - if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))) + if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, NULL))) return (error); mutex_enter(&zp->z_acl_lock); @@ -1952,7 +1952,7 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (zp->z_pflags & ZFS_IMMUTABLE) return (SET_ERROR(EPERM)); - if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))) + if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, NULL))) return (error); error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp, @@ -2341,7 +2341,8 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) * can define any form of access. */ int -zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) +zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr, + zuserns_t *mnt_ns) { uint32_t working_mode; int error; @@ -2471,9 +2472,11 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) * NFSv4-style ZFS ACL format and call zfs_zaccess() */ int -zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) +zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr, + zuserns_t *mnt_ns) { - return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); + return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr, + mnt_ns)); } /* @@ -2484,7 +2487,7 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) { int v4_mode = zfs_unix_to_v4(mode >> 6); - return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); + return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, NULL)); } static int @@ -2540,7 +2543,7 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp, * */ int -zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) +zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr, zuserns_t *mnt_ns) { uint32_t dzp_working_mode = 0; uint32_t zp_working_mode = 0; @@ -2627,7 +2630,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) int zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, - znode_t *tzp, cred_t *cr) + znode_t *tzp, cred_t *cr, zuserns_t *mnt_ns) { int add_perm; int error; @@ -2647,7 +2650,8 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, * to another. */ if (ZTOV(szp)->v_type == VDIR && ZTOV(sdzp) != ZTOV(tdzp)) { - if ((error = zfs_zaccess(szp, ACE_WRITE_DATA, 0, B_FALSE, cr))) + if ((error = zfs_zaccess(szp, ACE_WRITE_DATA, 0, B_FALSE, cr, + mnt_ns))) return (error); } @@ -2657,19 +2661,19 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, * If that succeeds then check for add_file/add_subdir permissions */ - if ((error = zfs_zaccess_delete(sdzp, szp, cr))) + if ((error = zfs_zaccess_delete(sdzp, szp, cr, mnt_ns))) return (error); /* * If we have a tzp, see if we can delete it? */ - if (tzp && (error = zfs_zaccess_delete(tdzp, tzp, cr))) + if (tzp && (error = zfs_zaccess_delete(tdzp, tzp, cr, mnt_ns))) return (error); /* * Now check for add permissions */ - error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); + error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr, mnt_ns); return (error); } diff --git a/module/os/freebsd/zfs/zfs_dir.c b/module/os/freebsd/zfs/zfs_dir.c index 778e4151656d..07232086d52b 100644 --- a/module/os/freebsd/zfs/zfs_dir.c +++ b/module/os/freebsd/zfs/zfs_dir.c @@ -809,7 +809,7 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, znode_t **xvpp, cred_t *cr) *xvpp = NULL; if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL, - &acl_ids)) != 0) + &acl_ids, NULL)) != 0) return (error); if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, 0)) { zfs_acl_ids_free(&acl_ids); @@ -955,7 +955,7 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) if ((uid = crgetuid(cr)) == downer || uid == fowner || (ZTOV(zp)->v_type == VREG && - zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0)) + zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL) == 0)) return (0); else return (secpolicy_vnode_remove(ZTOV(zp), cr)); diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index fae390a148d6..362e02751ee4 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -837,7 +837,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, /* * Do we have permission to get into attribute directory? */ - error = zfs_zaccess(zp, ACE_EXECUTE, 0, B_FALSE, cr); + error = zfs_zaccess(zp, ACE_EXECUTE, 0, B_FALSE, cr, NULL); if (error) { vrele(ZTOV(zp)); } @@ -856,7 +856,8 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cnp->cn_flags &= ~NOEXECCHECK; } else #endif - if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, + NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -1036,6 +1037,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, * flag - large file flag [UNUSED]. * ct - caller context * vsecp - ACL to be set + * mnt_ns - Unused on FreeBSD * * OUT: vpp - vnode of created or trunc'd entry. * @@ -1047,7 +1049,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, */ int zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode, - znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp) + znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp, zuserns_t *mnt_ns) { (void) excl, (void) mode, (void) flag; znode_t *zp; @@ -1110,7 +1112,7 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode, * Create a new file object and update the directory * to reference it. */ - if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns))) { goto out; } @@ -1126,7 +1128,7 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode, } if ((error = zfs_acl_ids_create(dzp, 0, vap, - cr, vsecp, &acl_ids)) != 0) + cr, vsecp, &acl_ids, NULL)) != 0) goto out; if (S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode)) @@ -1231,7 +1233,7 @@ zfs_remove_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr) xattr_obj = 0; xzp = NULL; - if ((error = zfs_zaccess_delete(dzp, zp, cr))) { + if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) { goto out; } @@ -1387,6 +1389,7 @@ zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags) * ct - caller context * flags - case flags * vsecp - ACL to be set + * mnt_ns - Unused on FreeBSD * * OUT: vpp - vnode of created directory. * @@ -1398,7 +1401,7 @@ zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags) */ int zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp, - cred_t *cr, int flags, vsecattr_t *vsecp) + cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns) { (void) flags, (void) vsecp; znode_t *zp; @@ -1447,7 +1450,7 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp, } if ((error = zfs_acl_ids_create(dzp, 0, vap, cr, - NULL, &acl_ids)) != 0) { + NULL, &acl_ids, NULL)) != 0) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -1468,7 +1471,8 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp, } ASSERT3P(zp, ==, NULL); - if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr, + mnt_ns))) { zfs_acl_ids_free(&acl_ids); zfs_exit(zfsvfs, FTAG); return (error); @@ -1585,7 +1589,7 @@ zfs_rmdir_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr) zilog = zfsvfs->z_log; - if ((error = zfs_zaccess_delete(dzp, zp, cr))) { + if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) { goto out; } @@ -1976,7 +1980,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) if (!(zp->z_pflags & ZFS_ACL_TRIVIAL) && (vap->va_uid != crgetuid(cr))) { if ((error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0, - skipaclchk, cr))) { + skipaclchk, cr, NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -2142,7 +2146,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) * flags - ATTR_UTIME set if non-default time values provided. * - ATTR_NOACLCHECK (CIFS context only). * cr - credentials of caller. - * ct - caller context + * mnt_ns - Unused on FreeBSD * * RETURN: 0 on success, error code on failure. * @@ -2150,7 +2154,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr) * vp - ctime updated, mtime updated if size changed. */ int -zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) +zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns) { vnode_t *vp = ZTOV(zp); zfsvfs_t *zfsvfs = zp->z_zfsvfs; @@ -2322,7 +2326,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) XVA_ISSET_REQ(xvap, XAT_CREATETIME) || XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) { need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0, - skipaclchk, cr); + skipaclchk, cr, mnt_ns); } if (mask & (AT_UID|AT_GID)) { @@ -2359,7 +2363,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) ((idmask == AT_UID) && take_owner) || ((idmask == AT_GID) && take_group)) { if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0, - skipaclchk, cr) == 0) { + skipaclchk, cr, mnt_ns) == 0) { /* * Remove setuid/setgid for non-privileged users */ @@ -2468,7 +2472,8 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) } if (mask & AT_MODE) { - if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) { + if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, + mnt_ns) == 0) { err = secpolicy_setid_setsticky_clear(vp, vap, &oldva, cr); if (err) { @@ -3264,7 +3269,7 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, * Note that if target and source are the same, this can be * done in a single check. */ - if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr))) + if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr, NULL))) goto out; if ((*svpp)->v_type == VDIR) { @@ -3415,7 +3420,7 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, int zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname, - cred_t *cr, int flags) + cred_t *cr, int flags, zuserns_t *mnt_ns) { struct componentname scn, tcn; vnode_t *sdvp, *tdvp; @@ -3460,6 +3465,7 @@ zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname, * cr - credentials of caller. * ct - caller context * flags - case flags + * mnt_ns - Unused on FreeBSD * * RETURN: 0 on success, error code on failure. * @@ -3468,7 +3474,7 @@ zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname, */ int zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap, - const char *link, znode_t **zpp, cred_t *cr, int flags) + const char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns) { (void) flags; znode_t *zp; @@ -3499,7 +3505,7 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap, } if ((error = zfs_acl_ids_create(dzp, 0, - vap, cr, NULL, &acl_ids)) != 0) { + vap, cr, NULL, &acl_ids, NULL)) != 0) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -3514,7 +3520,7 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap, return (error); } - if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns))) { zfs_acl_ids_free(&acl_ids); zfs_exit(zfsvfs, FTAG); return (error); @@ -3730,7 +3736,7 @@ zfs_link(znode_t *tdzp, znode_t *szp, const char *name, cred_t *cr, return (SET_ERROR(EPERM)); } - if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr, NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -3831,7 +3837,7 @@ zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag, * On Linux we can get here through truncate_range() which * operates directly on inodes, so we need to check access rights. */ - if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -4607,7 +4613,7 @@ zfs_freebsd_create(struct vop_create_args *ap) *ap->a_vpp = NULL; rc = zfs_create(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap, 0, mode, - &zp, cnp->cn_cred, 0 /* flag */, NULL /* vsecattr */); + &zp, cnp->cn_cred, 0 /* flag */, NULL /* vsecattr */, NULL); if (rc == 0) *ap->a_vpp = ZTOV(zp); if (zfsvfs->z_use_namecache && @@ -4661,7 +4667,7 @@ zfs_freebsd_mkdir(struct vop_mkdir_args *ap) *ap->a_vpp = NULL; rc = zfs_mkdir(VTOZ(ap->a_dvp), ap->a_cnp->cn_nameptr, vap, &zp, - ap->a_cnp->cn_cred, 0, NULL); + ap->a_cnp->cn_cred, 0, NULL, NULL); if (rc == 0) *ap->a_vpp = ZTOV(zp); @@ -4914,7 +4920,7 @@ zfs_freebsd_setattr(struct vop_setattr_args *ap) xvap.xva_vattr.va_mask |= AT_XVATTR; XVA_SET_REQ(&xvap, XAT_CREATETIME); } - return (zfs_setattr(VTOZ(vp), (vattr_t *)&xvap, 0, cred)); + return (zfs_setattr(VTOZ(vp), (vattr_t *)&xvap, 0, cred, NULL)); } #ifndef _SYS_SYSPROTO_H_ @@ -4985,7 +4991,7 @@ zfs_freebsd_symlink(struct vop_symlink_args *ap) *ap->a_vpp = NULL; rc = zfs_symlink(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap, - ap->a_target, &zp, cnp->cn_cred, 0 /* flags */); + ap->a_target, &zp, cnp->cn_cred, 0 /* flags */, NULL); if (rc == 0) { *ap->a_vpp = ZTOV(zp); ASSERT_VOP_ELOCKED(ZTOV(zp), __func__); diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c index 192aa748fc13..6c269480cb4b 100644 --- a/module/os/freebsd/zfs/zfs_znode.c +++ b/module/os/freebsd/zfs/zfs_znode.c @@ -298,7 +298,7 @@ zfs_create_share_dir(zfsvfs_t *zfsvfs, dmu_tx_t *tx) sharezp->z_is_sa = zfsvfs->z_use_sa; VERIFY0(zfs_acl_ids_create(sharezp, IS_ROOT_NODE, &vattr, - kcred, NULL, &acl_ids)); + kcred, NULL, &acl_ids, NULL)); zfs_mknode(sharezp, &vattr, tx, kcred, IS_ROOT_NODE, &zp, &acl_ids); ASSERT3P(zp, ==, sharezp); POINTER_INVALIDATE(&sharezp->z_zfsvfs); @@ -1773,7 +1773,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) rootzp->z_zfsvfs = zfsvfs; VERIFY0(zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr, - cr, NULL, &acl_ids)); + cr, NULL, &acl_ids, NULL)); zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids); ASSERT3P(zp, ==, rootzp); error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx); diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c index a69618978622..50eb7cfaa61c 100644 --- a/module/os/linux/zfs/policy.c +++ b/module/os/linux/zfs/policy.c @@ -214,8 +214,9 @@ secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr, * Determine that subject can set the file setgid flag. */ int -secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid) +secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns) { + gid = zfs_gid_into_mnt(mnt_ns, gid); #if defined(CONFIG_USER_NS) if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid))) return (EPERM); @@ -284,8 +285,10 @@ secpolicy_setid_clear(vattr_t *vap, cred_t *cr) * Determine that subject can set the file setid flags. */ static int -secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) +secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns) { + owner = zfs_uid_into_mnt(mnt_ns, owner); + if (crgetuid(cr) == owner) return (0); @@ -310,13 +313,13 @@ secpolicy_vnode_stky_modify(const cred_t *cr) int secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap, - const vattr_t *ovap, cred_t *cr) + const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns) { int error; if ((vap->va_mode & S_ISUID) != 0 && (error = secpolicy_vnode_setid_modify(cr, - ovap->va_uid)) != 0) { + ovap->va_uid, mnt_ns)) != 0) { return (error); } @@ -334,7 +337,7 @@ secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap, * group-id bit. */ if ((vap->va_mode & S_ISGID) != 0 && - secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) { + secpolicy_vnode_setids_setgids(cr, ovap->va_gid, mnt_ns) != 0) { vap->va_mode &= ~S_ISGID; } diff --git a/module/os/linux/zfs/zfs_acl.c b/module/os/linux/zfs/zfs_acl.c index d5cd5de890ab..d04034490758 100644 --- a/module/os/linux/zfs/zfs_acl.c +++ b/module/os/linux/zfs/zfs_acl.c @@ -1802,7 +1802,7 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, umode_t va_mode, zfs_acl_t *paclp, */ int zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, - vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids) + vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids, zuserns_t *mnt_ns) { int error; zfsvfs_t *zfsvfs = ZTOZSB(dzp); @@ -1889,8 +1889,9 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, acl_ids->z_mode |= S_ISGID; } else { if ((acl_ids->z_mode & S_ISGID) && - secpolicy_vnode_setids_setgids(cr, gid) != 0) + secpolicy_vnode_setids_setgids(cr, gid, mnt_ns) != 0) { acl_ids->z_mode &= ~S_ISGID; + } } if (acl_ids->z_aclp == NULL) { @@ -1978,7 +1979,7 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (mask == 0) return (SET_ERROR(ENOSYS)); - if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr))) + if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, NULL))) return (error); mutex_enter(&zp->z_acl_lock); @@ -2137,7 +2138,7 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (zp->z_pflags & ZFS_IMMUTABLE) return (SET_ERROR(EPERM)); - if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr))) + if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, NULL))) return (error); error = zfs_vsec_2_aclp(zfsvfs, ZTOI(zp)->i_mode, vsecp, cr, &fuidp, @@ -2283,7 +2284,7 @@ zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) */ static int zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, - boolean_t anyaccess, cred_t *cr) + boolean_t anyaccess, cred_t *cr, zuserns_t *mnt_ns) { zfsvfs_t *zfsvfs = ZTOZSB(zp); zfs_acl_t *aclp; @@ -2299,7 +2300,13 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, uid_t gowner; uid_t fowner; - zfs_fuid_map_ids(zp, cr, &fowner, &gowner); + if (mnt_ns) { + fowner = zfs_uid_into_mnt(mnt_ns, + KUID_TO_SUID(ZTOI(zp)->i_uid)); + gowner = zfs_gid_into_mnt(mnt_ns, + KGID_TO_SGID(ZTOI(zp)->i_gid)); + } else + zfs_fuid_map_ids(zp, cr, &fowner, &gowner); mutex_enter(&zp->z_acl_lock); @@ -2410,7 +2417,7 @@ zfs_has_access(znode_t *zp, cred_t *cr) { uint32_t have = ACE_ALL_PERMS; - if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { + if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, NULL) != 0) { uid_t owner; owner = zfs_fuid_map_id(ZTOZSB(zp), @@ -2440,7 +2447,8 @@ zfs_has_access(znode_t *zp, cred_t *cr) * we want to avoid that here. */ static int -zfs_zaccess_trivial(znode_t *zp, uint32_t *working_mode, cred_t *cr) +zfs_zaccess_trivial(znode_t *zp, uint32_t *working_mode, cred_t *cr, + zuserns_t *mnt_ns) { int err, mask; int unmapped = 0; @@ -2454,7 +2462,10 @@ zfs_zaccess_trivial(znode_t *zp, uint32_t *working_mode, cred_t *cr) } #if defined(HAVE_IOPS_PERMISSION_USERNS) - err = generic_permission(cr->user_ns, ZTOI(zp), mask); + if (mnt_ns) + err = generic_permission(mnt_ns, ZTOI(zp), mask); + else + err = generic_permission(cr->user_ns, ZTOI(zp), mask); #else err = generic_permission(ZTOI(zp), mask); #endif @@ -2469,7 +2480,7 @@ zfs_zaccess_trivial(znode_t *zp, uint32_t *working_mode, cred_t *cr) static int zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, - boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr) + boolean_t *check_privs, boolean_t skipaclchk, cred_t *cr, zuserns_t *mnt_ns) { zfsvfs_t *zfsvfs = ZTOZSB(zp); int err; @@ -2519,20 +2530,20 @@ zfs_zaccess_common(znode_t *zp, uint32_t v4_mode, uint32_t *working_mode, } if (zp->z_pflags & ZFS_ACL_TRIVIAL) - return (zfs_zaccess_trivial(zp, working_mode, cr)); + return (zfs_zaccess_trivial(zp, working_mode, cr, mnt_ns)); - return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr)); + return (zfs_zaccess_aces_check(zp, working_mode, B_FALSE, cr, mnt_ns)); } static int zfs_zaccess_append(znode_t *zp, uint32_t *working_mode, boolean_t *check_privs, - cred_t *cr) + cred_t *cr, zuserns_t *mnt_ns) { if (*working_mode != ACE_WRITE_DATA) return (SET_ERROR(EACCES)); return (zfs_zaccess_common(zp, ACE_APPEND_DATA, working_mode, - check_privs, B_FALSE, cr)); + check_privs, B_FALSE, cr, mnt_ns)); } int @@ -2599,7 +2610,7 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) DTRACE_PROBE(zfs__fastpath__execute__access__miss); if ((error = zfs_enter(ZTOZSB(zdp), FTAG)) != 0) return (error); - error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr); + error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL); zfs_exit(ZTOZSB(zdp), FTAG); return (error); } @@ -2611,7 +2622,8 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) * can define any form of access. */ int -zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) +zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr, + zuserns_t *mnt_ns) { uint32_t working_mode; int error; @@ -2650,8 +2662,9 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) } } - owner = zfs_fuid_map_id(ZTOZSB(zp), KUID_TO_SUID(ZTOI(zp)->i_uid), - cr, ZFS_OWNER); + owner = zfs_uid_into_mnt(mnt_ns, KUID_TO_SUID(ZTOI(zp)->i_uid)); + owner = zfs_fuid_map_id(ZTOZSB(zp), owner, cr, ZFS_OWNER); + /* * Map the bits required to the standard inode flags * S_IRUSR|S_IWUSR|S_IXUSR in the needed_bits. Map the bits @@ -2676,7 +2689,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) needed_bits |= S_IXUSR; if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, - &check_privs, skipaclchk, cr)) == 0) { + &check_privs, skipaclchk, cr, mnt_ns)) == 0) { if (is_attr) zrele(xzp); return (secpolicy_vnode_access2(cr, ZTOI(zp), owner, @@ -2690,7 +2703,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) } if (error && (flags & V_APPEND)) { - error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr); + error = zfs_zaccess_append(zp, &working_mode, &check_privs, cr, + mnt_ns); } if (error && check_privs) { @@ -2757,9 +2771,11 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) * NFSv4-style ZFS ACL format and call zfs_zaccess() */ int -zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr) +zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr, + zuserns_t *mnt_ns) { - return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr)); + return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr, + mnt_ns)); } /* @@ -2770,7 +2786,7 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) { int v4_mode = zfs_unix_to_v4(mode >> 6); - return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr)); + return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, NULL)); } /* See zfs_zaccess_delete() */ @@ -2847,7 +2863,7 @@ static const boolean_t zfs_write_implies_delete_child = B_TRUE; * zfs_write_implies_delete_child */ int -zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) +zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr, zuserns_t *mnt_ns) { uint32_t wanted_dirperms; uint32_t dzp_working_mode = 0; @@ -2874,7 +2890,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) * (This is part of why we're checking the target first.) */ zp_error = zfs_zaccess_common(zp, ACE_DELETE, &zp_working_mode, - &zpcheck_privs, B_FALSE, cr); + &zpcheck_privs, B_FALSE, cr, mnt_ns); if (zp_error == EACCES) { /* We hit a DENY ACE. */ if (!zpcheck_privs) @@ -2896,7 +2912,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) if (zfs_write_implies_delete_child) wanted_dirperms |= ACE_WRITE_DATA; dzp_error = zfs_zaccess_common(dzp, wanted_dirperms, - &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); + &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr, mnt_ns); if (dzp_error == EACCES) { /* We hit a DENY ACE. */ if (!dzpcheck_privs) @@ -2978,7 +2994,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) int zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, - znode_t *tzp, cred_t *cr) + znode_t *tzp, cred_t *cr, zuserns_t *mnt_ns) { int add_perm; int error; @@ -3000,21 +3016,21 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp, * If that succeeds then check for add_file/add_subdir permissions */ - if ((error = zfs_zaccess_delete(sdzp, szp, cr))) + if ((error = zfs_zaccess_delete(sdzp, szp, cr, mnt_ns))) return (error); /* * If we have a tzp, see if we can delete it? */ if (tzp) { - if ((error = zfs_zaccess_delete(tdzp, tzp, cr))) + if ((error = zfs_zaccess_delete(tdzp, tzp, cr, mnt_ns))) return (error); } /* * Now check for add permissions */ - error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr); + error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr, mnt_ns); return (error); } diff --git a/module/os/linux/zfs/zfs_dir.c b/module/os/linux/zfs/zfs_dir.c index 6738d237b923..611a2471dd94 100644 --- a/module/os/linux/zfs/zfs_dir.c +++ b/module/os/linux/zfs/zfs_dir.c @@ -1066,11 +1066,12 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, znode_t **xzpp, cred_t *cr) *xzpp = NULL; - if ((error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr))) + if ((error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr, + NULL))) return (error); if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL, - &acl_ids)) != 0) + &acl_ids, NULL)) != 0) return (error); if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, zp->z_projid)) { zfs_acl_ids_free(&acl_ids); @@ -1218,7 +1219,7 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) cr, ZFS_OWNER); if ((uid = crgetuid(cr)) == downer || uid == fowner || - zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0) + zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL) == 0) return (0); else return (secpolicy_vnode_remove(cr)); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 1ff88c121a79..9160f3e77390 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -476,7 +476,7 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, */ if ((error = zfs_zaccess(*zpp, ACE_EXECUTE, 0, - B_TRUE, cr))) { + B_TRUE, cr, NULL))) { zrele(*zpp); *zpp = NULL; } @@ -494,7 +494,7 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, * Check accessibility of directory. */ - if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -526,6 +526,7 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, * cr - credentials of caller. * flag - file flag. * vsecp - ACL to be set + * mnt_ns - user namespace of the mount * * OUT: zpp - znode of created or trunc'd entry. * @@ -537,7 +538,8 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, */ int zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, - int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp) + int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp, + zuserns_t *mnt_ns) { znode_t *zp; zfsvfs_t *zfsvfs = ZTOZSB(dzp); @@ -624,7 +626,8 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, * Create a new file object and update the directory * to reference it. */ - if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, + mnt_ns))) { if (have_acl) zfs_acl_ids_free(&acl_ids); goto out; @@ -643,7 +646,7 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, } if (!have_acl && (error = zfs_acl_ids_create(dzp, 0, vap, - cr, vsecp, &acl_ids)) != 0) + cr, vsecp, &acl_ids, mnt_ns)) != 0) goto out; have_acl = B_TRUE; @@ -738,7 +741,8 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, /* * Verify requested access to file. */ - if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr))) { + if (mode && (error = zfs_zaccess_rwx(zp, mode, aflags, cr, + mnt_ns))) { goto out; } @@ -782,7 +786,8 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl, int zfs_tmpfile(struct inode *dip, vattr_t *vap, int excl, - int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp) + int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp, + zuserns_t *mnt_ns) { (void) excl, (void) mode, (void) flag; znode_t *zp = NULL, *dzp = ITOZ(dip); @@ -829,14 +834,14 @@ zfs_tmpfile(struct inode *dip, vattr_t *vap, int excl, * Create a new file object and update the directory * to reference it. */ - if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns))) { if (have_acl) zfs_acl_ids_free(&acl_ids); goto out; } if (!have_acl && (error = zfs_acl_ids_create(dzp, 0, vap, - cr, vsecp, &acl_ids)) != 0) + cr, vsecp, &acl_ids, mnt_ns)) != 0) goto out; have_acl = B_TRUE; @@ -967,7 +972,7 @@ zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags) return (error); } - if ((error = zfs_zaccess_delete(dzp, zp, cr))) { + if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) { goto out; } @@ -1147,6 +1152,7 @@ zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags) * cr - credentials of caller. * flags - case flags. * vsecp - ACL to be set + * mnt_ns - user namespace of the mount * * OUT: zpp - znode of created directory. * @@ -1159,7 +1165,7 @@ zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags) */ int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, znode_t **zpp, - cred_t *cr, int flags, vsecattr_t *vsecp) + cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns) { znode_t *zp; zfsvfs_t *zfsvfs = ZTOZSB(dzp); @@ -1216,7 +1222,7 @@ zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, znode_t **zpp, } if ((error = zfs_acl_ids_create(dzp, 0, vap, cr, - vsecp, &acl_ids)) != 0) { + vsecp, &acl_ids, mnt_ns)) != 0) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -1237,7 +1243,8 @@ zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, znode_t **zpp, return (error); } - if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr, + mnt_ns))) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); zfs_exit(zfsvfs, FTAG); @@ -1379,7 +1386,7 @@ zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr, return (error); } - if ((error = zfs_zaccess_delete(dzp, zp, cr))) { + if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) { goto out; } @@ -1811,6 +1818,7 @@ zfs_setattr_dir(znode_t *dzp) * flags - ATTR_UTIME set if non-default time values provided. * - ATTR_NOACLCHECK (CIFS context only). * cr - credentials of caller. + * mnt_ns - user namespace of the mount * * RETURN: 0 if success * error code if failure @@ -1819,7 +1827,7 @@ zfs_setattr_dir(znode_t *dzp) * ip - ctime updated, mtime updated if size changed. */ int -zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) +zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns) { struct inode *ip; zfsvfs_t *zfsvfs = ZTOZSB(zp); @@ -1968,7 +1976,8 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) */ if (mask & ATTR_SIZE) { - err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr); + err = zfs_zaccess(zp, ACE_WRITE_DATA, 0, skipaclchk, cr, + mnt_ns); if (err) goto out3; @@ -1993,13 +2002,15 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) XVA_ISSET_REQ(xvap, XAT_CREATETIME) || XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) { need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0, - skipaclchk, cr); + skipaclchk, cr, mnt_ns); } if (mask & (ATTR_UID|ATTR_GID)) { int idmask = (mask & (ATTR_UID|ATTR_GID)); int take_owner; int take_group; + uid_t uid; + gid_t gid; /* * NOTE: even if a new mode is being set, @@ -2013,9 +2024,13 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) * Take ownership or chgrp to group we are a member of */ - take_owner = (mask & ATTR_UID) && (vap->va_uid == crgetuid(cr)); + uid = zfs_uid_into_mnt((struct user_namespace *)mnt_ns, + vap->va_uid); + gid = zfs_gid_into_mnt((struct user_namespace *)mnt_ns, + vap->va_gid); + take_owner = (mask & ATTR_UID) && (uid == crgetuid(cr)); take_group = (mask & ATTR_GID) && - zfs_groupmember(zfsvfs, vap->va_gid, cr); + zfs_groupmember(zfsvfs, gid, cr); /* * If both ATTR_UID and ATTR_GID are set then take_owner and @@ -2031,7 +2046,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) ((idmask == ATTR_UID) && take_owner) || ((idmask == ATTR_GID) && take_group)) { if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0, - skipaclchk, cr) == 0) { + skipaclchk, cr, mnt_ns) == 0) { /* * Remove setuid/setgid for non-privileged users */ @@ -2144,12 +2159,12 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) mutex_exit(&zp->z_lock); if (mask & ATTR_MODE) { - if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) { + if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, + mnt_ns) == 0) { err = secpolicy_setid_setsticky_clear(ip, vap, - &oldva, cr); + &oldva, cr, mnt_ns); if (err) goto out3; - trim_mask |= ATTR_MODE; } else { need_policy = TRUE; @@ -2640,6 +2655,7 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp) * tnm - New entry name. * cr - credentials of caller. * flags - case flags + * mnt_ns - user namespace of the mount * * RETURN: 0 on success, error code on failure. * @@ -2648,7 +2664,7 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp) */ int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, - cred_t *cr, int flags) + cred_t *cr, int flags, zuserns_t *mnt_ns) { znode_t *szp, *tzp; zfsvfs_t *zfsvfs = ZTOZSB(sdzp); @@ -2841,7 +2857,7 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, * done in a single check. */ - if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr))) + if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr, mnt_ns))) goto out; if (S_ISDIR(ZTOI(szp)->i_mode)) { @@ -3008,6 +3024,7 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, * link - Name for new symlink entry. * cr - credentials of caller. * flags - case flags + * mnt_ns - user namespace of the mount * * OUT: zpp - Znode for new symbolic link. * @@ -3018,7 +3035,7 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, */ int zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link, - znode_t **zpp, cred_t *cr, int flags) + znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns) { znode_t *zp; zfs_dirlock_t *dl; @@ -3056,7 +3073,7 @@ zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link, } if ((error = zfs_acl_ids_create(dzp, 0, - vap, cr, NULL, &acl_ids)) != 0) { + vap, cr, NULL, &acl_ids, mnt_ns)) != 0) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -3073,7 +3090,7 @@ zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link, return (error); } - if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns))) { zfs_acl_ids_free(&acl_ids); zfs_dirent_unlock(dl); zfs_exit(zfsvfs, FTAG); @@ -3325,7 +3342,7 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr, return (SET_ERROR(EPERM)); } - if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr, NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -3951,7 +3968,7 @@ zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag, * On Linux we can get here through truncate_range() which * operates directly on inodes, so we need to check access rights. */ - if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr))) { + if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL))) { zfs_exit(zfsvfs, FTAG); return (error); } diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index a97955f4020a..9aeffba86150 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -1960,7 +1960,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) } VERIFY(0 == zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr, - cr, NULL, &acl_ids)); + cr, NULL, &acl_ids, NULL)); zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids); ASSERT3P(zp, ==, rootzp); error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx); diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index 837629e4a5e0..8bc4a9b39f22 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -371,7 +371,11 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); - zpl_vap_init(vap, dip, mode | S_IFDIR, cr); +#ifdef HAVE_IOPS_MKDIR_USERNS + zpl_vap_init(vap, dip, mode | S_IFDIR, cr, user_ns); +#else + zpl_vap_init(vap, dip, mode | S_IFDIR, cr, NULL); +#endif error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0); if (error == 0) { diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index 25fc6b223297..cfa03e571f78 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -1085,7 +1085,7 @@ zpl_ioctl_setflags(struct file *filp, void __user *arg) crhold(cr); cookie = spl_fstrans_mark(); - err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr); + err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL); spl_fstrans_unmark(cookie); crfree(cr); @@ -1133,7 +1133,7 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg) crhold(cr); cookie = spl_fstrans_mark(); - err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr); + err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL); spl_fstrans_unmark(cookie); crfree(cr); @@ -1221,7 +1221,7 @@ zpl_ioctl_setdosflags(struct file *filp, void __user *arg) crhold(cr); cookie = spl_fstrans_mark(); - err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr); + err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL); spl_fstrans_unmark(cookie); crfree(cr); diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 7578753ed8ce..8d073ff8cbd3 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -33,7 +33,6 @@ #include #include - static struct dentry * zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { @@ -112,18 +111,22 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) } void -zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr) +zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr, + zuserns_t *mnt_ns) { vap->va_mask = ATTR_MODE; vap->va_mode = mode; - vap->va_uid = crgetuid(cr); + + vap->va_uid = zfs_uid_from_mnt((struct user_namespace *)mnt_ns, + crgetuid(cr)); if (dir && dir->i_mode & S_ISGID) { vap->va_gid = KGID_TO_SGID(dir->i_gid); if (S_ISDIR(mode)) vap->va_mode |= S_ISGID; } else { - vap->va_gid = crgetgid(cr); + vap->va_gid = zfs_gid_from_mnt((struct user_namespace *)mnt_ns, + crgetgid(cr)); } } @@ -140,14 +143,17 @@ zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag) vattr_t *vap; int error; fstrans_cookie_t cookie; +#ifndef HAVE_IOPS_CREATE_USERNS + zuserns_t *user_ns = NULL; +#endif crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); - zpl_vap_init(vap, dir, mode, cr); + zpl_vap_init(vap, dir, mode, cr, user_ns); cookie = spl_fstrans_mark(); error = -zfs_create(ITOZ(dir), dname(dentry), vap, 0, - mode, &zp, cr, 0, NULL); + mode, &zp, cr, 0, NULL, user_ns); if (error == 0) { error = zpl_xattr_security_init(ZTOI(zp), dir, &dentry->d_name); if (error == 0) @@ -184,6 +190,9 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, vattr_t *vap; int error; fstrans_cookie_t cookie; +#ifndef HAVE_IOPS_MKNOD_USERNS + zuserns_t *user_ns = NULL; +#endif /* * We currently expect Linux to supply rdev=0 for all sockets @@ -194,12 +203,12 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); - zpl_vap_init(vap, dir, mode, cr); + zpl_vap_init(vap, dir, mode, cr, user_ns); vap->va_rdev = rdev; cookie = spl_fstrans_mark(); error = -zfs_create(ITOZ(dir), dname(dentry), vap, 0, - mode, &zp, cr, 0, NULL); + mode, &zp, cr, 0, NULL, user_ns); if (error == 0) { error = zpl_xattr_security_init(ZTOI(zp), dir, &dentry->d_name); if (error == 0) @@ -236,6 +245,9 @@ zpl_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) vattr_t *vap; int error; fstrans_cookie_t cookie; +#ifndef HAVE_TMPFILE_USERNS + zuserns_t *userns = NULL; +#endif crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); @@ -245,10 +257,10 @@ zpl_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) */ if (!IS_POSIXACL(dir)) mode &= ~current_umask(); - zpl_vap_init(vap, dir, mode, cr); + zpl_vap_init(vap, dir, mode, cr, userns); cookie = spl_fstrans_mark(); - error = -zfs_tmpfile(dir, vap, 0, mode, &ip, cr, 0, NULL); + error = -zfs_tmpfile(dir, vap, 0, mode, &ip, cr, 0, NULL, userns); if (error == 0) { /* d_tmpfile will do drop_nlink, so we should set it first */ set_nlink(ip, 1); @@ -311,13 +323,17 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) znode_t *zp; int error; fstrans_cookie_t cookie; +#ifndef HAVE_IOPS_MKDIR_USERNS + zuserns_t *user_ns = NULL; +#endif crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); - zpl_vap_init(vap, dir, mode | S_IFDIR, cr); + zpl_vap_init(vap, dir, mode | S_IFDIR, cr, user_ns); cookie = spl_fstrans_mark(); - error = -zfs_mkdir(ITOZ(dir), dname(dentry), vap, &zp, cr, 0, NULL); + error = -zfs_mkdir(ITOZ(dir), dname(dentry), vap, &zp, cr, 0, NULL, + user_ns); if (error == 0) { error = zpl_xattr_security_init(ZTOI(zp), dir, &dentry->d_name); if (error == 0) @@ -439,7 +455,11 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) int error; fstrans_cookie_t cookie; +#ifdef HAVE_SETATTR_PREPARE_USERNS + error = zpl_setattr_prepare(user_ns, dentry, ia); +#else error = zpl_setattr_prepare(kcred->user_ns, dentry, ia); +#endif if (error) return (error); @@ -458,7 +478,11 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) ip->i_atime = zpl_inode_timestamp_truncate(ia->ia_atime, ip); cookie = spl_fstrans_mark(); - error = -zfs_setattr(ITOZ(ip), vap, 0, cr); +#ifdef HAVE_SETATTR_PREPARE_USERNS + error = -zfs_setattr(ITOZ(ip), vap, 0, cr, user_ns); +#else + error = -zfs_setattr(ITOZ(ip), vap, 0, cr, NULL); +#endif if (!error && (ia->ia_valid & ATTR_MODE)) error = zpl_chmod_acl(ip); @@ -483,6 +507,9 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry, cred_t *cr = CRED(); int error; fstrans_cookie_t cookie; +#ifndef HAVE_IOPS_RENAME_USERNS + zuserns_t *user_ns = NULL; +#endif /* We don't have renameat2(2) support */ if (flags) @@ -491,7 +518,7 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry, crhold(cr); cookie = spl_fstrans_mark(); error = -zfs_rename(ITOZ(sdip), dname(sdentry), ITOZ(tdip), - dname(tdentry), cr, 0); + dname(tdentry), cr, 0, user_ns); spl_fstrans_unmark(cookie); crfree(cr); ASSERT3S(error, <=, 0); @@ -521,14 +548,17 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) znode_t *zp; int error; fstrans_cookie_t cookie; +#ifndef HAVE_IOPS_SYMLINK_USERNS + zuserns_t *user_ns = NULL; +#endif crhold(cr); vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); - zpl_vap_init(vap, dir, S_IFLNK | S_IRWXUGO, cr); + zpl_vap_init(vap, dir, S_IFLNK | S_IRWXUGO, cr, user_ns); cookie = spl_fstrans_mark(); error = -zfs_symlink(ITOZ(dir), dname(dentry), vap, - (char *)name, &zp, cr, 0); + (char *)name, &zp, cr, 0, user_ns); if (error == 0) { error = zpl_xattr_security_init(ZTOI(zp), dir, &dentry->d_name); if (error) { diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index e3945a2a05fe..63ba731dd804 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -374,7 +374,11 @@ const struct super_operations zpl_super_operations = { struct file_system_type zpl_fs_type = { .owner = THIS_MODULE, .name = ZFS_DRIVER, +#if defined(HAVE_IDMAP_MNT_API) + .fs_flags = FS_USERNS_MOUNT | FS_ALLOW_IDMAP, +#else .fs_flags = FS_USERNS_MOUNT, +#endif .mount = zpl_mount, .kill_sb = zpl_kill_sb, }; diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c index a010667adfa8..97b6e048c8a8 100644 --- a/module/os/linux/zfs/zpl_xattr.c +++ b/module/os/linux/zfs/zpl_xattr.c @@ -499,7 +499,7 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value, vap->va_gid = crgetgid(cr); error = -zfs_create(dxzp, (char *)name, vap, 0, 0644, &xzp, - cr, 0, NULL); + cr, 0, NULL, NULL); if (error) goto out; } diff --git a/module/zfs/zfs_replay.c b/module/zfs/zfs_replay.c index 379e1d1a7b57..45c2fa3720cf 100644 --- a/module/zfs/zfs_replay.c +++ b/module/zfs/zfs_replay.c @@ -387,7 +387,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap) } error = zfs_create(dzp, name, &xva.xva_vattr, - 0, 0, &zp, kcred, vflg, &vsec); + 0, 0, &zp, kcred, vflg, &vsec, NULL); break; case TX_MKDIR_ACL: aclstart = (caddr_t)(lracl + 1); @@ -417,7 +417,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap) lr->lr_uid, lr->lr_gid); } error = zfs_mkdir(dzp, name, &xva.xva_vattr, - &zp, kcred, vflg, &vsec); + &zp, kcred, vflg, &vsec, NULL); break; default: error = SET_ERROR(ENOTSUP); @@ -528,7 +528,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) name = (char *)start; error = zfs_create(dzp, name, &xva.xva_vattr, - 0, 0, &zp, kcred, vflg, NULL); + 0, 0, &zp, kcred, vflg, NULL, NULL); break; case TX_MKDIR_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); @@ -546,7 +546,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) name = (char *)(lr + 1); error = zfs_mkdir(dzp, name, &xva.xva_vattr, - &zp, kcred, vflg, NULL); + &zp, kcred, vflg, NULL, NULL); break; case TX_MKXATTR: error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &zp, kcred); @@ -555,7 +555,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) name = (char *)(lr + 1); link = name + strlen(name) + 1; error = zfs_symlink(dzp, name, &xva.xva_vattr, - link, &zp, kcred, vflg); + link, &zp, kcred, vflg, NULL); break; default: error = SET_ERROR(ENOTSUP); @@ -667,7 +667,7 @@ zfs_replay_rename(void *arg1, void *arg2, boolean_t byteswap) if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; - error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg); + error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, NULL); zrele(tdzp); zrele(sdzp); @@ -860,7 +860,7 @@ zfs_replay_setattr(void *arg1, void *arg2, boolean_t byteswap) zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); - error = zfs_setattr(zp, vap, 0, kcred); + error = zfs_setattr(zp, vap, 0, kcred, NULL); zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index a2c15bc807a8..c63076f90c18 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -168,9 +168,9 @@ zfs_access(znode_t *zp, int mode, int flag, cred_t *cr) return (error); if (flag & V_ACE_MASK) - error = zfs_zaccess(zp, mode, flag, B_FALSE, cr); + error = zfs_zaccess(zp, mode, flag, B_FALSE, cr, NULL); else - error = zfs_zaccess_rwx(zp, mode, flag, cr); + error = zfs_zaccess_rwx(zp, mode, flag, cr, NULL); zfs_exit(zfsvfs, FTAG); return (error); diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 09dfb5eb1e1d..21e0f882dc40 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -194,3 +194,7 @@ tags = ['functional', 'userquota'] tests = ['zvol_misc_fua'] tags = ['functional', 'zvol', 'zvol_misc'] +[tests/functional/idmap_mount:Linux] +tests = ['idmap_mount_001', 'idmap_mount_002', 'idmap_mount_003', + 'idmap_mount_004'] +tags = ['functional', 'idmap_mount'] diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in index bf7cf22b61fc..e7d338fcf8a9 100755 --- a/tests/test-runner/bin/zts-report.py.in +++ b/tests/test-runner/bin/zts-report.py.in @@ -132,6 +132,10 @@ na_reason = "Not applicable" # ci_reason = 'CI runner doesn\'t have all requirements' +# +# Idmapped mount is only supported in kernel version >= 5.12 +# +idmap_reason = 'Idmapped mount needs kernel 5.12+' # # These tests are known to fail, thus we use this list to prevent these @@ -270,6 +274,10 @@ elif sys.platform.startswith('linux'): 'mmp/mmp_inactive_import': ['FAIL', known_reason], 'zvol/zvol_misc/zvol_misc_snapdev': ['FAIL', 12621], 'zvol/zvol_misc/zvol_misc_volmode': ['FAIL', known_reason], + 'idmap_mount/idmap_mount_001': ['SKIP', idmap_reason], + 'idmap_mount/idmap_mount_002': ['SKIP', idmap_reason], + 'idmap_mount/idmap_mount_003': ['SKIP', idmap_reason], + 'idmap_mount/idmap_mount_004': ['SKIP', idmap_reason], }) diff --git a/tests/zfs-tests/cmd/.gitignore b/tests/zfs-tests/cmd/.gitignore index 1fd54c1dd510..0ec450e248db 100644 --- a/tests/zfs-tests/cmd/.gitignore +++ b/tests/zfs-tests/cmd/.gitignore @@ -47,3 +47,4 @@ /edonr_test /skein_test /sha2_test +/idmap_util diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index c19c870cf698..673a18b4c083 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -118,7 +118,9 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/getversion scripts_zfs_tests_bin_PROGRAMS += %D%/user_ns_exec scripts_zfs_tests_bin_PROGRAMS += %D%/xattrtest scripts_zfs_tests_bin_PROGRAMS += %D%/zed_fd_spill-zedlet +scripts_zfs_tests_bin_PROGRAMS += %D%/idmap_util +%C%_idmap_util_LDADD = libspl.la dist_noinst_DATA += %D%/linux_dos_attributes/dos_attributes.h scripts_zfs_tests_bin_PROGRAMS += %D%/read_dos_attributes %D%/write_dos_attributes diff --git a/tests/zfs-tests/cmd/idmap_util.c b/tests/zfs-tests/cmd/idmap_util.c new file mode 100644 index 000000000000..a9731f00dbc0 --- /dev/null +++ b/tests/zfs-tests/cmd/idmap_util.c @@ -0,0 +1,791 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef UINT_MAX +#define UINT_MAX 4294967295U +#endif + +#ifndef __NR_Linux +#if defined __alpha__ +#define __NR_Linux 110 +#elif defined _MIPS_SIM +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#define __NR_Linux 4000 +#endif +#if _MIPS_SIM == _MIPS_SIM_NABI32 +#define __NR_Linux 6000 +#endif +#if _MIPS_SIM == _MIPS_SIM_ABI64 +#define __NR_Linux 5000 +#endif +#elif defined __ia64__ +#define __NR_Linux 1024 +#else +#define __NR_Linux 0 +#endif +#endif + +#ifndef __NR_mount_setattr +#define __NR_mount_setattr (442 + __NR_Linux) +#endif + +#ifndef __NR_open_tree +#define __NR_open_tree (428 + __NR_Linux) +#endif + +#ifndef __NR_move_mount +#define __NR_move_mount (429 + __NR_Linux) +#endif + +#ifndef MNT_DETACH +#define MNT_DETACH 2 +#endif + +#ifndef MOVE_MOUNT_F_EMPTY_PATH +#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 +#endif + +#ifndef MOUNT_ATTR_IDMAP +#define MOUNT_ATTR_IDMAP 0x00100000 +#endif + +#ifndef OPEN_TREE_CLONE +#define OPEN_TREE_CLONE 1 +#endif + +#ifndef OPEN_TREE_CLOEXEC +#define OPEN_TREE_CLOEXEC O_CLOEXEC +#endif + +#ifndef AT_RECURSIVE +#define AT_RECURSIVE 0x8000 +#endif + +#ifndef mount_attr +struct mount_attr { + __u64 attr_set; + __u64 attr_clr; + __u64 propagation; + __u64 userns_fd; +}; +#endif + +static inline int +sys_mount_setattr(int dfd, const char *path, unsigned int flags, + struct mount_attr *attr, size_t size) +{ + return (syscall(__NR_mount_setattr, dfd, path, flags, attr, size)); +} + +static inline int +sys_open_tree(int dfd, const char *filename, unsigned int flags) +{ + return (syscall(__NR_open_tree, dfd, filename, flags)); +} + +static inline int sys_move_mount(int from_dfd, const char *from_pathname, + int to_dfd, const char *to_pathname, unsigned int flags) +{ + return (syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, + to_pathname, flags)); +} + +typedef enum idmap_type_t { + TYPE_UID, + TYPE_GID, + TYPE_BOTH +} idmap_type_t; + +struct idmap_entry { + __u32 first; + __u32 lower_first; + __u32 count; + idmap_type_t type; + list_node_t node; +}; + +static void +log_msg(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + fputc('\n', stderr); + va_end(ap); +} + +#define log_errno(msg, args...) \ + do { \ + log_msg("%s:%d:%s: [%m] " msg, __FILE__, __LINE__,\ + __FUNCTION__, ##args); \ + } while (0) + +/* + * Parse the idmapping in the following format + * and add to the list: + * + * u:nsid_first:hostid_first:count + * g:nsid_first:hostid_first:count + * b:nsid_first:hostid_first:count + * + * The delimiter can be : or space character. + * + * Return: + * 0 if success + * ENOMEM if out of memory + * EINVAL if wrong arg or input + */ +static int +parse_idmap_entry(list_t *head, char *input) +{ + char *token, *savedptr = NULL; + struct idmap_entry *entry; + unsigned long ul; + char *delimiter = (char *)": "; + char c; + + if (!input || !head) + return (EINVAL); + entry = malloc(sizeof (*entry)); + if (!entry) + return (ENOMEM); + + token = strtok_r(input, delimiter, &savedptr); + if (token) + c = token[0]; + if (!token || (c != 'b' && c != 'u' && c != 'g')) + goto errout; + entry->type = (c == 'b') ? TYPE_BOTH : + ((c == 'u') ? TYPE_UID : TYPE_GID); + + token = strtok_r(NULL, delimiter, &savedptr); + if (!token) + goto errout; + ul = strtoul(token, NULL, 10); + if (ul > UINT_MAX || errno != 0) + goto errout; + entry->first = (__u32)ul; + + token = strtok_r(NULL, delimiter, &savedptr); + if (!token) + goto errout; + ul = strtoul(token, NULL, 10); + if (ul > UINT_MAX || errno != 0) + goto errout; + entry->lower_first = (__u32)ul; + + token = strtok_r(NULL, delimiter, &savedptr); + if (!token) + goto errout; + ul = strtoul(token, NULL, 10); + if (ul > UINT_MAX || errno != 0) + goto errout; + entry->count = (__u32)ul; + + list_insert_tail(head, entry); + + return (0); + +errout: + free(entry); + return (EINVAL); +} + +/* + * Release all the entries in the list + */ +static void +free_idmap(list_t *head) +{ + struct idmap_entry *entry; + + while ((entry = list_remove_head(head)) != NULL) + free(entry); + /* list_destroy() to be done by the caller */ +} + +/* + * Write all bytes in the buffer to fd + */ +static ssize_t +write_buf(int fd, const char *buf, size_t buf_size) +{ + ssize_t written, total_written = 0; + size_t remaining = buf_size; + char *position = (char *)buf; + + for (;;) { + written = write(fd, position, remaining); + if (written < 0 && errno == EINTR) + continue; + if (written < 0) { + log_errno("write"); + return (written); + } + total_written += written; + if (total_written == buf_size) + break; + remaining -= written; + position += written; + } + + return (total_written); +} + +/* + * Read data from file into buffer + */ +static ssize_t +read_buf(int fd, char *buf, size_t buf_size) +{ + int ret; + for (;;) { + ret = read(fd, buf, buf_size); + if (ret < 0 && errno == EINTR) + continue; + break; + } + if (ret < 0) + log_errno("read"); + return (ret); +} + +/* + * Write idmap of the given type in the buffer to the + * process' uid_map or gid_map proc file. + * + * Return: + * 0 if success + * errno if there's any error + */ +static int +write_idmap(pid_t pid, char *buf, size_t buf_size, idmap_type_t type) +{ + char path[PATH_MAX]; + int fd = -EBADF; + int ret; + + (void) snprintf(path, sizeof (path), "/proc/%d/%cid_map", + pid, type == TYPE_UID ? 'u' : 'g'); + fd = open(path, O_WRONLY | O_CLOEXEC); + if (fd < 0) { + ret = errno; + log_errno("open(%s)", path); + goto out; + } + ret = write_buf(fd, buf, buf_size); + if (ret < 0) + ret = errno; + else + ret = 0; +out: + if (fd > 0) + close(fd); + return (ret); +} + +/* + * Write idmap info in the list to the process + * user namespace, i.e. its /proc//uid_map + * and /proc//gid_map file. + * + * Return: + * 0 if success + * errno if it fails + */ +static int +write_pid_idmaps(pid_t pid, list_t *head) +{ + char *buf_uids, *buf_gids; + char *curr_bufu, *curr_bufg; + /* max 4k to be allowed for each map */ + int size_buf_uids = 4096, size_buf_gids = 4096; + struct idmap_entry *entry; + int uid_filled, gid_filled; + int ret; + int has_uids = 0, has_gids = 0; + size_t buf_size; + + buf_uids = malloc(size_buf_uids); + if (!buf_uids) + return (ENOMEM); + buf_gids = malloc(size_buf_gids); + if (!buf_gids) { + free(buf_uids); + return (ENOMEM); + } + curr_bufu = buf_uids; + curr_bufg = buf_gids; + + for (entry = list_head(head); entry; entry = list_next(head, entry)) { + if (entry->type == TYPE_UID || entry->type == TYPE_BOTH) { + uid_filled = snprintf(curr_bufu, size_buf_uids, + "%u %u %u\n", entry->first, entry->lower_first, + entry->count); + if (uid_filled <= 0 || uid_filled >= size_buf_uids) { + ret = E2BIG; + goto out; + } + curr_bufu += uid_filled; + size_buf_uids -= uid_filled; + has_uids = 1; + } + if (entry->type == TYPE_GID || entry->type == TYPE_BOTH) { + gid_filled = snprintf(curr_bufg, size_buf_gids, + "%u %u %u\n", entry->first, entry->lower_first, + entry->count); + if (gid_filled <= 0 || gid_filled >= size_buf_gids) { + ret = E2BIG; + goto out; + } + curr_bufg += gid_filled; + size_buf_gids -= gid_filled; + has_gids = 1; + } + } + if (has_uids) { + buf_size = curr_bufu - buf_uids; + ret = write_idmap(pid, buf_uids, buf_size, TYPE_UID); + if (ret) + goto out; + } + if (has_gids) { + buf_size = curr_bufg - buf_gids; + ret = write_idmap(pid, buf_gids, buf_size, TYPE_GID); + } + +out: + free(buf_uids); + free(buf_gids); + return (ret); +} + +/* + * Wait for the child process to exit + * and reap it. + * + * Return: + * process exit code if available + */ +static int +wait_for_pid(pid_t pid) +{ + int status; + int ret; + + for (;;) { + ret = waitpid(pid, &status, 0); + if (ret < 0) { + if (errno == EINTR) + continue; + return (EXIT_FAILURE); + } + break; + } + if (!WIFEXITED(status)) + return (EXIT_FAILURE); + return (WEXITSTATUS(status)); +} + +/* + * Get the file descriptor of the process user namespace + * given its pid. + * + * Return: + * fd if success + * -1 if it fails + */ +static int +userns_fd_from_pid(pid_t pid) +{ + int fd; + char path[PATH_MAX]; + + (void) snprintf(path, sizeof (path), "/proc/%d/ns/user", pid); + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + log_errno("open(%s)", path); + return (fd); +} + +/* + * Get the user namespace file descriptor given a list + * of idmap info. + * + * Return: + * fd if success + * -errno if it fails + */ +static int +userns_fd_from_idmap(list_t *head) +{ + pid_t pid; + int ret, fd; + int pipe_fd[2]; + char c; + int saved_errno = 0; + + /* pipe for bidirectional communication */ + ret = pipe(pipe_fd); + if (ret) { + log_errno("pipe"); + return (-errno); + } + + pid = fork(); + if (pid < 0) { + log_errno("fork"); + return (-errno); + } + + if (pid == 0) { + /* child process */ + close(pipe_fd[0]); + ret = unshare(CLONE_NEWUSER); + if (ret == 0) { + /* notify the parent of success */ + ret = write_buf(pipe_fd[1], "1", 1); + } else { + saved_errno = errno; + log_errno("unshare"); + ret = write_buf(pipe_fd[1], "0", 1); + } + if (ret < 0) + saved_errno = errno; + close(pipe_fd[1]); + exit(saved_errno); + } + /* parent process */ + close(pipe_fd[1]); + ret = read_buf(pipe_fd[0], &c, 1); + if (ret == 1 && c == '1') { + ret = write_pid_idmaps(pid, head); + if (!ret) { + fd = userns_fd_from_pid(pid); + if (fd < 0) + fd = -errno; + } else { + fd = -ret; + } + } else { + fd = -EBADF; + } + close(pipe_fd[0]); + (void) wait_for_pid(pid); + return (fd); +} + +/* + * Check if the operating system supports idmapped mount on the + * given path or not. + * + * Return: + * true if supported + * false if not supported + */ +static bool +is_idmap_supported(char *path) +{ + list_t head; + int ret; + int tree_fd = -EBADF, path_fd = -EBADF; + struct mount_attr attr = { + .attr_set = MOUNT_ATTR_IDMAP, + .userns_fd = -EBADF, + }; + + /* strtok_r() won't be happy with a const string */ + char *input = strdup("b:0:1000000:1000000"); + + if (!input) { + errno = ENOMEM; + log_errno("strdup"); + return (false); + } + + list_create(&head, sizeof (struct idmap_entry), + offsetof(struct idmap_entry, node)); + ret = parse_idmap_entry(&head, input); + if (ret) { + errno = ret; + log_errno("parse_idmap_entry(%s)", input); + goto out; + } + ret = userns_fd_from_idmap(&head); + if (ret < 0) + goto out; + attr.userns_fd = ret; + ret = openat(-EBADF, path, O_DIRECTORY | O_CLOEXEC); + if (ret < 0) { + log_errno("openat(%s)", path); + goto out; + } + path_fd = ret; + ret = sys_open_tree(path_fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE); + if (ret < 0) { + log_errno("sys_open_tree"); + goto out; + } + tree_fd = ret; + ret = sys_mount_setattr(tree_fd, "", AT_EMPTY_PATH, &attr, + sizeof (attr)); + if (ret < 0) { + log_errno("sys_mount_setattr"); + } +out: + free_idmap(&head); + list_destroy(&head); + if (tree_fd > 0) + close(tree_fd); + if (path_fd > 0) + close(path_fd); + if (attr.userns_fd > 0) + close(attr.userns_fd); + free(input); + return (ret == 0); +} + +/* + * Check if the given path is a mount point or not. + * + * Return: + * true if it is + * false otherwise + */ +static bool +is_mountpoint(char *path) +{ + char *parent; + struct stat st_me, st_parent; + bool ret; + + parent = malloc(strlen(path)+4); + if (!parent) { + errno = ENOMEM; + log_errno("malloc"); + return (false); + } + strcat(strcpy(parent, path), "/.."); + if (lstat(path, &st_me) != 0 || + lstat(parent, &st_parent) != 0) + ret = false; + else + if (st_me.st_dev != st_parent.st_dev || + st_me.st_ino == st_parent.st_ino) + ret = true; + else + ret = false; + free(parent); + return (ret); +} + +/* + * Remount the source on the new target folder with the given + * list of idmap info. If target is NULL, the source will be + * unmounted and then remounted if it is a mountpoint, otherwise + * no unmount is done, the source is simply idmap remounted. + * + * Return: + * 0 if success + * -errno otherwise + */ +static int +do_idmap_mount(list_t *idmap, char *source, char *target, int flags) +{ + int ret; + int tree_fd = -EBADF, source_fd = -EBADF; + struct mount_attr attr = { + .attr_set = MOUNT_ATTR_IDMAP, + .userns_fd = -EBADF, + }; + + ret = userns_fd_from_idmap(idmap); + if (ret < 0) + goto out; + attr.userns_fd = ret; + ret = openat(-EBADF, source, O_DIRECTORY | O_CLOEXEC); + if (ret < 0) { + ret = -errno; + log_errno("openat(%s)", source); + goto out; + } + source_fd = ret; + ret = sys_open_tree(source_fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE | flags); + if (ret < 0) { + ret = -errno; + log_errno("sys_open_tree"); + goto out; + } + tree_fd = ret; + ret = sys_mount_setattr(tree_fd, "", AT_EMPTY_PATH | flags, &attr, + sizeof (attr)); + if (ret < 0) { + ret = -errno; + log_errno("sys_mount_setattr"); + goto out; + } + if (source != NULL && target == NULL && is_mountpoint(source)) { + ret = umount2(source, MNT_DETACH); + if (ret < 0) { + ret = -errno; + log_errno("umount2(%s)", source); + goto out; + } + } + ret = sys_move_mount(tree_fd, "", -EBADF, target == NULL ? + source : target, MOVE_MOUNT_F_EMPTY_PATH); + if (ret < 0) { + ret = -errno; + log_errno("sys_move_mount(%s)", target == NULL ? + source : target); + } +out: + if (tree_fd > 0) + close(tree_fd); + if (source_fd > 0) + close(source_fd); + if (attr.userns_fd > 0) + close(attr.userns_fd); + return (ret); +} + +static void +print_usage(char *argv[]) +{ + fprintf(stderr, "Usage: %s [-r] [-c] [-m ] [-m ]" \ + " ... [] []\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, " -r Recursively do idmapped mount.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " -c Checks if idmapped mount is supported " \ + "on the by the operating system or not.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " -m to specify the idmap info, " \ + "in the following format:\n"); + fprintf(stderr, " :::\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " can be either of 'b', 'u', and 'g'.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "The folder will be mounted at " \ + "with the provided idmap information.\nIf no is " \ + "specified, and is a mount point, " \ + "then will be unmounted and then remounted.\n"); +} + +int +main(int argc, char *argv[]) +{ + int opt; + list_t idmap_head; + int check_supported = 0; + int ret = EXIT_SUCCESS; + char *source = NULL, *target = NULL; + int flags = 0; + + list_create(&idmap_head, sizeof (struct idmap_entry), + offsetof(struct idmap_entry, node)); + + while ((opt = getopt(argc, argv, "rcm:")) != -1) { + switch (opt) { + case 'r': + flags |= AT_RECURSIVE; + break; + case 'c': + check_supported = 1; + break; + case 'm': + ret = parse_idmap_entry(&idmap_head, optarg); + if (ret) { + errno = ret; + log_errno("parse_idmap_entry(%s)", optarg); + ret = EXIT_FAILURE; + goto out; + } + break; + default: + print_usage(argv); + exit(EXIT_FAILURE); + } + } + + if (check_supported == 0 && list_is_empty(&idmap_head)) { + print_usage(argv); + ret = EXIT_FAILURE; + goto out; + } + + if (optind >= argc) { + fprintf(stderr, "Expected to have , .\n"); + print_usage(argv); + ret = EXIT_FAILURE; + goto out; + } + + source = argv[optind]; + if (optind < (argc - 1)) { + target = argv[optind + 1]; + } + + if (check_supported) { + free_idmap(&idmap_head); + list_destroy(&idmap_head); + if (is_idmap_supported(source)) { + printf("idmapped mount is supported on [%s].\n", + source); + return (EXIT_SUCCESS); + } else { + printf("idmapped mount is NOT supported.\n"); + return (EXIT_FAILURE); + } + } + + ret = do_idmap_mount(&idmap_head, source, target, flags); + if (ret) + ret = EXIT_FAILURE; +out: + free_idmap(&idmap_head); + list_destroy(&idmap_head); + + exit(ret); +} diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg index c05b918325b7..30514361ad57 100644 --- a/tests/zfs-tests/include/commands.cfg +++ b/tests/zfs-tests/include/commands.cfg @@ -156,7 +156,8 @@ export SYSTEM_FILES_LINUX='attr useradd userdel usermod - + setpriv + mountpoint flock logger' @@ -226,4 +227,5 @@ export ZFSTEST_FILES='badsend truncate_test ereports zfs_diff-socket - dosmode_readonly_write' + dosmode_readonly_write + idmap_util' diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 6aeb862fbb85..2d99027754c4 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -378,7 +378,9 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \ functional/zvol/zvol_common.shlib \ functional/zvol/zvol_ENOSPC/zvol_ENOSPC.cfg \ functional/zvol/zvol_misc/zvol_misc_common.kshlib \ - functional/zvol/zvol_swap/zvol_swap.cfg + functional/zvol/zvol_swap/zvol_swap.cfg \ + functional/idmap_mount/idmap_mount.cfg \ + functional/idmap_mount/idmap_mount_common.kshlib nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/acl/off/cleanup.ksh \ @@ -1998,4 +2000,10 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/zvol/zvol_swap/zvol_swap_003_pos.ksh \ functional/zvol/zvol_swap/zvol_swap_004_pos.ksh \ functional/zvol/zvol_swap/zvol_swap_005_pos.ksh \ - functional/zvol/zvol_swap/zvol_swap_006_pos.ksh + functional/zvol/zvol_swap/zvol_swap_006_pos.ksh \ + functional/idmap_mount/cleanup.ksh \ + functional/idmap_mount/setup.ksh \ + functional/idmap_mount/idmap_mount_001.ksh \ + functional/idmap_mount/idmap_mount_002.ksh \ + functional/idmap_mount/idmap_mount_003.ksh \ + functional/idmap_mount/idmap_mount_004.ksh diff --git a/tests/zfs-tests/tests/functional/idmap_mount/cleanup.ksh b/tests/zfs-tests/tests/functional/idmap_mount/cleanup.ksh new file mode 100755 index 000000000000..4895aa23ee4a --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/cleanup.ksh @@ -0,0 +1,25 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/include/libtest.shlib + +default_cleanup diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount.cfg b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount.cfg new file mode 100644 index 000000000000..51998945d0d1 --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount.cfg @@ -0,0 +1,25 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +export UID1=1000000 +export GID1=1000000 +export UID2=2000000 +export GID2=2000000 diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_001.ksh b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_001.ksh new file mode 100755 index 000000000000..e7187935e532 --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_001.ksh @@ -0,0 +1,76 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib + +# +# +# DESCRIPTION: +# Test uid and gid of files in idmapped folder are mapped correctly +# +# +# STRATEGY: +# 1. Create files/folder owned by $UID1 and $GID1 under "idmap_test" +# 2. Idmap the folder to "idmap_dest" +# 3. Verify the owner of files/folder under "idmap_dest" +# + +verify_runnable "global" + +export WORKDIR=$TESTDIR/idmap_test +export IDMAPDIR=$TESTDIR/idmap_dest + +function cleanup +{ + log_must rm -rf $WORKDIR + if mountpoint $IDMAPDIR; then + log_must umount $IDMAPDIR + fi + log_must rm -rf $IDMAPDIR +} + +log_onexit cleanup + +if ! idmap_util -c $TESTDIR; then + log_unsupported "Idmap mount not supported." +fi + +log_must mkdir -p $WORKDIR +log_must mkdir -p $IDMAPDIR +log_must touch $WORKDIR/file1 +log_must mkdir $WORKDIR/subdir +log_must ln -s $WORKDIR/file1 $WORKDIR/file1_sym +log_must ln $WORKDIR/file1 $WORKDIR/subdir/file1_hard +log_must touch $WORKDIR/subdir/file2 +log_must chown -R $UID1:$GID1 $WORKDIR +log_must chown $UID2:$GID2 $WORKDIR/subdir/file2 + +log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR + +log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/file1)" +log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/file1_sym)" +log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/subdir)" +log_must test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/subdir/file1_hard)" +log_mustnot test "$UID2 $GID2" = "$(stat -c '%u %g' $IDMAPDIR/subdir/file2)" + +log_pass "Owner verification of entries under idmapped folder is successful." + diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_002.ksh b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_002.ksh new file mode 100755 index 000000000000..8cba90ea58b7 --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_002.ksh @@ -0,0 +1,97 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib + +# +# +# DESCRIPTION: +# Perform file operations in idmapped folder, check owner in its base. +# +# +# STRATEGY: +# 1. Create folder "idmap_test" +# 2. Idmap the folder to "idmap_dest" +# 3. Do basic file operations in "idmap_dest" folder, verify the owner in +# the base folder "idmap_test" +# + +verify_runnable "global" + +export WORKDIR=$TESTDIR/idmap_test +export IDMAPDIR=$TESTDIR/idmap_dest + +function cleanup +{ + log_must rm -rf $IDMAPDIR/* + if mountpoint $IDMAPDIR; then + log_must umount $IDMAPDIR + fi + log_must rm -rf $IDMAPDIR $WORKDIR +} + +log_onexit cleanup + +if ! idmap_util -c $TESTDIR; then + log_unsupported "Idmap mount not supported." +fi + +log_must mkdir -p $WORKDIR +log_must mkdir -p $IDMAPDIR + +log_must chown $UID1:$GID1 $WORKDIR +log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR + +SETPRIV="setpriv --reuid $UID2 --regid $GID2 --clear-groups" + +log_must $SETPRIV touch $IDMAPDIR/file1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)" + +log_must $SETPRIV mv $IDMAPDIR/file1 $IDMAPDIR/file1_renamed +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_renamed)" + +log_must $SETPRIV mv $IDMAPDIR/file1_renamed $IDMAPDIR/file1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)" + +log_must $SETPRIV mkdir $IDMAPDIR/subdir +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir)" + +log_must $SETPRIV ln -s $IDMAPDIR/file1 $IDMAPDIR/file1_sym +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_sym)" + +log_must $SETPRIV ln $IDMAPDIR/file1 $IDMAPDIR/subdir/file1_hard +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir/file1_hard)" + +log_must $SETPRIV touch $IDMAPDIR/subdir/file2 +log_must $SETPRIV chown $UID2:$GID2 $IDMAPDIR/subdir/file2 +log_mustnot $SETPRIV chown $UID1 $IDMAPDIR/subdir/file2 + +log_must $SETPRIV cp -r $IDMAPDIR/subdir $IDMAPDIR/subdir1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file2)" +log_must $SETPRIV rm -rf $IDMAPDIR/subdir1 + +log_must $SETPRIV cp -rp $IDMAPDIR/subdir $IDMAPDIR/subdir1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file1_hard)" +log_must $SETPRIV rm -rf $IDMAPDIR/subdir1 + +log_pass "Owner verification of entries under base folder is successful." + diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_003.ksh b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_003.ksh new file mode 100755 index 000000000000..1f1a2aec655e --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_003.ksh @@ -0,0 +1,121 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib + +# +# +# DESCRIPTION: +# Perform file operations in idmapped folder in user namespace, +# then check the owner in its base. +# +# +# STRATEGY: +# 1. Create folder "idmap_test" +# 2. Idmap the folder to "idmap_dest" +# 3. Perform file operations in the idmapped folder in the user +# namespace having the same idmap info as the idmapped mount +# 4. Verify the owner of entries under the base folder "idmap_test" +# + +verify_runnable "global" + +export WORKDIR=$TESTDIR/idmap_test +export IDMAPDIR=$TESTDIR/idmap_dest + +function cleanup +{ + kill -TERM ${unshared_pid} + log_must rm -rf $IDMAPDIR/* + if mountpoint $IDMAPDIR; then + log_must umount $IDMAPDIR + fi + log_must rm -rf $IDMAPDIR $WORKDIR +} + +log_onexit cleanup + +if ! idmap_util -c $TESTDIR; then + log_unsupported "Idmap mount not supported." +fi + +log_must mkdir -p $WORKDIR +log_must mkdir -p $IDMAPDIR + +log_must chown $UID1:$GID1 $WORKDIR +log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR + +# Create a user namespace with the same idmapping +unshare -Urm echo test +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to create user namespace" +fi +unshare -Um /usr/bin/sleep 2h & +unshared_pid=$! +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to create user namespace" +fi +# wait for userns to be ready +sleep 1 +echo "${UID1} ${UID2} 1" > /proc/$unshared_pid/uid_map +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to write to uid_map" +fi +echo "${GID1} ${GID2} 1" > /proc/$unshared_pid/gid_map +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to write to gid_map" +fi + +NSENTER="nsenter -t $unshared_pid --all -S ${UID1} -G ${GID1}" + +log_must $NSENTER touch $IDMAPDIR/file1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)" + +log_must $NSENTER mv $IDMAPDIR/file1 $IDMAPDIR/file1_renamed +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_renamed)" + +log_must $NSENTER mv $IDMAPDIR/file1_renamed $IDMAPDIR/file1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1)" + +log_must $NSENTER mkdir $IDMAPDIR/subdir +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir)" + +log_must $NSENTER ln -s $IDMAPDIR/file1 $IDMAPDIR/file1_sym +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/file1_sym)" + +log_must $NSENTER ln $IDMAPDIR/file1 $IDMAPDIR/subdir/file1_hard +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir/file1_hard)" + +log_must $NSENTER touch $IDMAPDIR/subdir/file2 +log_must $NSENTER chown $UID1:$GID1 $IDMAPDIR/subdir/file2 +log_mustnot $NSENTER chown $UID2 $IDMAPDIR/subdir/file2 + +log_must $NSENTER cp -r $IDMAPDIR/subdir $IDMAPDIR/subdir1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file2)" +log_must $NSENTER rm -rf $IDMAPDIR/subdir1 + +log_must $NSENTER cp -rp $IDMAPDIR/subdir $IDMAPDIR/subdir1 +log_must test "$UID1 $GID1" = "$(stat -c '%u %g' $WORKDIR/subdir1/file1_hard)" +log_must $NSENTER rm -rf $IDMAPDIR/subdir1 + +log_pass "Owner verification of entries under the base folder is successful." + diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_004.ksh b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_004.ksh new file mode 100755 index 000000000000..89f2f750d23c --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_004.ksh @@ -0,0 +1,106 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib + +# +# +# DESCRIPTION: +# Test setgid bit is set properly on the idmapped mount +# in a user namespace. +# +# STRATEGY: +# 1. Create folder "idmap_test", set gid bit on it +# 2. Idmap the folder to "idmap_dest" +# 3. Create file and folder in the idmapped folder in the user +# namespace having the same idmap info +# 4. Verify the gid bit of the file and folder is set +# + +verify_runnable "global" + +export WORKDIR=$TESTDIR/idmap_test +export IDMAPDIR=$TESTDIR/idmap_dest + +function cleanup +{ + kill -TERM ${unshared_pid} + log_must rm -rf $IDMAPDIR/* + if mountpoint $IDMAPDIR; then + log_must umount $IDMAPDIR + fi + log_must rm -rf $IDMAPDIR $WORKDIR +} + +log_onexit cleanup + +if ! idmap_util -c $TESTDIR; then + log_unsupported "Idmap mount not supported." +fi + +log_must mkdir -p $WORKDIR +log_must mkdir -p $IDMAPDIR + +log_must chown $UID1:$GID1 $WORKDIR +# set gid bit +log_must chmod 2755 $WORKDIR +log_must idmap_util -m "u:${UID1}:${UID2}:1" -m "g:${GID1}:${GID2}:1" $WORKDIR $IDMAPDIR +log_must test -g $IDMAPDIR + +# Create a user namespace with the same idmapping +unshare -Urm echo test +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to create user namespace" +fi +unshare -Um /usr/bin/sleep 2h & +unshared_pid=$! +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to create user namespace" +fi +# wait for userns to be ready +sleep 1 +echo "${UID1} ${UID2} 1" > /proc/$unshared_pid/uid_map +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to write to uid_map" +fi +echo "${GID1} ${GID2} 1" > /proc/$unshared_pid/gid_map +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to write to gid_map" +fi + +NSENTER="nsenter -t $unshared_pid --all -S ${UID1} -G ${GID1}" + +# gid bit can be set on the file +log_must $NSENTER touch $IDMAPDIR/file1 +log_must $NSENTER chmod 2654 $IDMAPDIR/file1 +log_must test -g $WORKDIR/file1 +log_must test -g $IDMAPDIR/file1 +log_must test "$UID1 $GID1" = "$($NSENTER stat -c '%u %g' $IDMAPDIR/file1)" + +# gid bit is carried over to new folder +log_must $NSENTER mkdir $IDMAPDIR/subdir +log_must test -g $WORKDIR/subdir +log_must test -g $IDMAPDIR/subdir +log_must test "$UID1 $GID1" = "$($NSENTER stat -c '%u %g' $IDMAPDIR/subdir)" + +log_pass "Verification of setting gid bit in userns is successful." + diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_common.kshlib b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_common.kshlib new file mode 100644 index 000000000000..980845ca209c --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_common.kshlib @@ -0,0 +1,23 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/include/libtest.shlib +. $STF_SUITE/tests/functional/idmap_mount/idmap_mount.cfg diff --git a/tests/zfs-tests/tests/functional/idmap_mount/setup.ksh b/tests/zfs-tests/tests/functional/idmap_mount/setup.ksh new file mode 100755 index 000000000000..90a14f12058f --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/setup.ksh @@ -0,0 +1,30 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/include/libtest.shlib + +# unable to do idmapped mount in a local zone +verify_runnable "global" + +DISK=${DISKS%% *} +default_setup $DISK + From 2be0a124afea461f5fb01f56c00d68b70d09b196 Mon Sep 17 00:00:00 2001 From: samwyc <115969550+samwyc@users.noreply.github.com> Date: Thu, 20 Oct 2022 04:18:13 +0530 Subject: [PATCH 044/126] Fix sequential resilver drive failure race condition This patch handles the race condition on simultaneous failure of 2 drives, which misses the vdev_rebuild_reset_wanted signal in vdev_rebuild_thread. We retry to catch this inside the vdev_rebuild_complete_sync function. Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Reviewed-by: Dipak Ghosh Reviewed-by: Akash B Signed-off-by: Samuel Wycliffe J Closes #14041 Closes #14050 --- module/zfs/vdev_rebuild.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/module/zfs/vdev_rebuild.c b/module/zfs/vdev_rebuild.c index fdb8ad97b439..1f56275c853b 100644 --- a/module/zfs/vdev_rebuild.c +++ b/module/zfs/vdev_rebuild.c @@ -22,6 +22,7 @@ * * Copyright (c) 2018, Intel Corporation. * Copyright (c) 2020 by Lawrence Livermore National Security, LLC. + * Copyright (c) 2022 Hewlett Packard Enterprise Development LP. */ #include @@ -134,6 +135,7 @@ static int zfs_rebuild_scrub_enabled = 1; * For vdev_rebuild_initiate_sync() and vdev_rebuild_reset_sync(). */ static __attribute__((noreturn)) void vdev_rebuild_thread(void *arg); +static void vdev_rebuild_reset_sync(void *arg, dmu_tx_t *tx); /* * Clear the per-vdev rebuild bytes value for a vdev tree. @@ -307,6 +309,17 @@ vdev_rebuild_complete_sync(void *arg, dmu_tx_t *tx) vdev_rebuild_phys_t *vrp = &vr->vr_rebuild_phys; mutex_enter(&vd->vdev_rebuild_lock); + + /* + * Handle a second device failure if it occurs after all rebuild I/O + * has completed but before this sync task has been executed. + */ + if (vd->vdev_rebuild_reset_wanted) { + mutex_exit(&vd->vdev_rebuild_lock); + vdev_rebuild_reset_sync(arg, tx); + return; + } + vrp->vrp_rebuild_state = VDEV_REBUILD_COMPLETE; vrp->vrp_end_time = gethrestime_sec(); @@ -760,7 +773,6 @@ vdev_rebuild_thread(void *arg) ASSERT(vd->vdev_rebuilding); ASSERT(spa_feature_is_active(spa, SPA_FEATURE_DEVICE_REBUILD)); ASSERT3B(vd->vdev_rebuild_cancel_wanted, ==, B_FALSE); - ASSERT3B(vd->vdev_rebuild_reset_wanted, ==, B_FALSE); vdev_rebuild_t *vr = &vd->vdev_rebuild_config; vdev_rebuild_phys_t *vrp = &vr->vr_rebuild_phys; From 5405be036516280c00d481bc44394d8ef7ab15c6 Mon Sep 17 00:00:00 2001 From: Akash B Date: Thu, 20 Oct 2022 05:37:51 +0530 Subject: [PATCH 045/126] Add options to zfs redundant_metadata property 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 Reviewed-by: Dipak Ghosh Signed-off-by: Akash B Closes #13680 --- include/sys/dmu.h | 7 ++ include/sys/fs/zfs.h | 5 +- man/man7/zfsprops.7 | 18 +++- module/zcommon/zfs_prop.c | 5 +- module/zfs/dmu.c | 21 ++++- module/zfs/dmu_objset.c | 5 +- module/zfs/dsl_prop.c | 92 +++++++++++++++++++ tests/zfs-tests/include/properties.shlib | 3 +- .../inheritance/inherit_001_pos.ksh | 10 +- 9 files changed, 151 insertions(+), 15 deletions(-) diff --git a/include/sys/dmu.h b/include/sys/dmu.h index d68700d371db..93de991ccd86 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -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) diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index b3fecf489eb0..10a5ec3172a2 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -29,6 +29,7 @@ * Copyright (c) 2019 Datto Inc. * Portions Copyright 2010 Robert Milkowski * Copyright (c) 2021, Colm Buckley + * Copyright (c) 2022 Hewlett Packard Enterprise Development LP. */ #ifndef _SYS_FS_ZFS_H @@ -501,7 +502,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 { diff --git a/man/man7/zfsprops.7 b/man/man7/zfsprops.7 index 93a7bfcc865f..0b7711da88a6 100644 --- a/man/man7/zfsprops.7 +++ b/man/man7/zfsprops.7 @@ -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 . @@ -1454,7 +1455,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. @@ -1486,7 +1487,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 @@ -1495,6 +1496,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 diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 0e91304ecd4b..c03933d126c6 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -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 */ @@ -369,6 +370,8 @@ zfs_prop_init(void) static const 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 } }; @@ -388,7 +391,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, sfeatures); zprop_register_index(ZFS_PROP_SYNC, "sync", ZFS_SYNC_STANDARD, PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index d95d7bf639bb..4f5dbfdde015 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -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 @@ -1992,12 +1993,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); diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index 4c20afcdb9c6..b8fcbdf487d0 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -32,6 +32,7 @@ * Copyright (c) 2018, loli10K . 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; } diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index 610e887b3fba..ad927b622fcf 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -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 @@ -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_USERPROP || 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 diff --git a/tests/zfs-tests/include/properties.shlib b/tests/zfs-tests/include/properties.shlib index 14b3f4415b7d..3dfb295a40df 100644 --- a/tests/zfs-tests/include/properties.shlib +++ b/tests/zfs-tests/include/properties.shlib @@ -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') diff --git a/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh b/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh index e525c51344ad..1f203e1dc551 100755 --- a/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh @@ -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 @@ -376,7 +377,8 @@ set -A prop "checksum" "" \ "sharenfs" "" \ "recordsize" "recsize" \ "snapdir" "" \ - "readonly" "" + "readonly" "" \ + "redundant_metadata" "" # # Note except for the mountpoint default value (which is handled in @@ -387,12 +389,14 @@ set -A prop "checksum" "" \ set -A def_val "on" "on" "on" \ "off" "" \ "hidden" \ - "off" + "off" \ + "all" set -A local_val "off" "off" "off" \ "on" "" \ "visible" \ - "off" + "off" \ + "none" # # Add system specific values From 219cf0f928475d832d5a7bf0e286ee9ae008fb84 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Wed, 19 Oct 2022 20:08:33 -0400 Subject: [PATCH 046/126] Fix userland memory leak in zfs_do_send() Clang 15's static analyzer caught this. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14045 --- cmd/zfs/zfs_main.c | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index ac51df0f9c10..dddf387de587 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -4504,6 +4504,7 @@ zfs_do_send(int argc, char **argv) gettext("missing argument for '%s' " "option\n"), argv[optind - 1]); } + free(excludes.list); usage(B_FALSE); break; case '?': @@ -4522,6 +4523,7 @@ zfs_do_send(int argc, char **argv) argv[optind - 1]); } + free(excludes.list); usage(B_FALSE); } } @@ -4530,6 +4532,7 @@ zfs_do_send(int argc, char **argv) flags.verbosity = 1; if (excludes.count > 0 && !flags.replicate) { + free(excludes.list); (void) fprintf(stderr, gettext("Cannot specify " "dataset exclusion (-X) on a non-recursive " "send.\n")); @@ -4543,21 +4546,25 @@ zfs_do_send(int argc, char **argv) if (fromname != NULL || flags.replicate || flags.props || flags.backup || flags.holds || flags.saved || redactbook != NULL) { + free(excludes.list); (void) fprintf(stderr, gettext("invalid flags combined with -t\n")); usage(B_FALSE); } if (argc > 0) { + free(excludes.list); (void) fprintf(stderr, gettext("too many arguments\n")); usage(B_FALSE); } } else { if (argc < 1) { + free(excludes.list); (void) fprintf(stderr, gettext("missing snapshot argument\n")); usage(B_FALSE); } if (argc > 1) { + free(excludes.list); (void) fprintf(stderr, gettext("too many arguments\n")); usage(B_FALSE); } @@ -4568,11 +4575,15 @@ zfs_do_send(int argc, char **argv) flags.doall || flags.backup || flags.holds || flags.largeblock || flags.embed_data || flags.compress || flags.raw || redactbook != NULL) { + free(excludes.list); + (void) fprintf(stderr, gettext("incompatible flags " "combined with saved send flag\n")); usage(B_FALSE); } if (strchr(argv[0], '@') != NULL) { + free(excludes.list); + (void) fprintf(stderr, gettext("saved send must " "specify the dataset with partially-received " "state\n")); @@ -4581,12 +4592,14 @@ zfs_do_send(int argc, char **argv) } if (flags.raw && redactbook != NULL) { + free(excludes.list); (void) fprintf(stderr, gettext("Error: raw sends may not be redacted.\n")); return (1); } if (!flags.dryrun && isatty(STDOUT_FILENO)) { + free(excludes.list); (void) fprintf(stderr, gettext("Error: Stream can not be written to a terminal.\n" "You must redirect standard output.\n")); @@ -4595,19 +4608,24 @@ zfs_do_send(int argc, char **argv) if (flags.saved) { zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET); - if (zhp == NULL) + if (zhp == NULL) { + free(excludes.list); return (1); + } err = zfs_send_saved(zhp, &flags, STDOUT_FILENO, resume_token); + free(excludes.list); zfs_close(zhp); return (err != 0); } else if (resume_token != NULL) { + free(excludes.list); return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO, resume_token)); } if (flags.skipmissing && !flags.replicate) { + free(excludes.list); (void) fprintf(stderr, gettext("skip-missing flag can only be used in " "conjunction with replicate\n")); @@ -4650,10 +4668,14 @@ zfs_do_send(int argc, char **argv) } zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET); - if (zhp == NULL) + if (zhp == NULL) { + free(excludes.list); return (1); + } err = zfs_send_one(zhp, fromname, STDOUT_FILENO, &flags, redactbook); + + free(excludes.list); zfs_close(zhp); return (err != 0); } @@ -4662,25 +4684,30 @@ zfs_do_send(int argc, char **argv) (void) fprintf(stderr, gettext("Error: multiple snapshots cannot be " "sent from a bookmark.\n")); + free(excludes.list); return (1); } if (redactbook != NULL) { (void) fprintf(stderr, gettext("Error: multiple snapshots " "cannot be sent redacted.\n")); + free(excludes.list); return (1); } if ((cp = strchr(argv[0], '@')) == NULL) { (void) fprintf(stderr, gettext("Error: " "Unsupported flag with filesystem or bookmark.\n")); + free(excludes.list); return (1); } *cp = '\0'; toname = cp + 1; zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); - if (zhp == NULL) + if (zhp == NULL) { + free(excludes.list); return (1); + } /* * If they specified the full path to the snapshot, chop off @@ -4700,6 +4727,8 @@ zfs_do_send(int argc, char **argv) } else { *cp = '\0'; if (cp != fromname && strcmp(argv[0], fromname)) { + zfs_close(zhp); + free(excludes.list); (void) fprintf(stderr, gettext("incremental source must be " "in same filesystem\n")); @@ -4707,6 +4736,8 @@ zfs_do_send(int argc, char **argv) } fromname = cp + 1; if (strchr(fromname, '@') || strchr(fromname, '/')) { + zfs_close(zhp); + free(excludes.list); (void) fprintf(stderr, gettext("invalid incremental source\n")); usage(B_FALSE); From 4ecd96371bcd71b4f0e3be3591098037a58977cb Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 15 Oct 2022 18:27:03 -0400 Subject: [PATCH 047/126] Fix theoretical use of uninitialized values Clang's static analyzer complains about this. In get_configs(), if we have an invalid configuration that has no top level vdevs, we can read a couple of uninitialized variables. Aborting upon seeing this would break the userland tools for healthy pools, so we instead initialize the two variables to 0 to allow the userland tools to continue functioning for the pools with valid configurations. In zfs_do_wait(), if no wait activities are enabled, we read an uninitialized error variable. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14043 --- cmd/zfs/zfs_main.c | 2 +- lib/libzutil/zutil_import.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index dddf387de587..bdbd0bfc63f2 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -8554,7 +8554,7 @@ static int zfs_do_wait(int argc, char **argv) { boolean_t enabled[ZFS_WAIT_NUM_ACTIVITIES]; - int error, i; + int error = 0, i; int c; /* By default, wait for all types of activity. */ diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index e7a755dcbd97..fee176184e5d 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -501,11 +501,9 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok, uint64_t guid; uint_t children = 0; nvlist_t **child = NULL; - uint_t holes; uint64_t *hole_array, max_id; uint_t c; boolean_t isactive; - uint64_t hostid; nvlist_t *nvl; boolean_t valid_top_config = B_FALSE; @@ -513,7 +511,8 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok, goto nomem; for (pe = pl->pools; pe != NULL; pe = pe->pe_next) { - uint64_t id, max_txg = 0; + uint64_t id, max_txg = 0, hostid = 0; + uint_t holes = 0; if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0) goto nomem; From 44f71818f82c984ba8848b734d74d52142f2b098 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 15 Oct 2022 18:34:31 -0400 Subject: [PATCH 048/126] Silence static analyzer warnings about spa_sync_props() Both Coverity and Clang's static analyzer complain about reading an uninitialized intval if the property is not passed as DATA_TYPE_UINT64 in the nvlist. This is impossible becuase spa_prop_validate() already checked this, but they are unlikely to be the last static analyzers to complain about this, so lets just refactor the code to suppress the warnings. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14043 --- module/zfs/spa.c | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 5d568e8340d6..de5bbcc09412 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -8867,37 +8867,37 @@ spa_sync_props(void *arg, dmu_tx_t *tx) spa_history_log_internal(spa, "set", tx, "%s=%lld", nvpair_name(elem), (longlong_t)intval); + + switch (prop) { + case ZPOOL_PROP_DELEGATION: + spa->spa_delegation = intval; + break; + case ZPOOL_PROP_BOOTFS: + spa->spa_bootfs = intval; + break; + case ZPOOL_PROP_FAILUREMODE: + spa->spa_failmode = intval; + break; + case ZPOOL_PROP_AUTOTRIM: + spa->spa_autotrim = intval; + spa_async_request(spa, + SPA_ASYNC_AUTOTRIM_RESTART); + break; + case ZPOOL_PROP_AUTOEXPAND: + spa->spa_autoexpand = intval; + if (tx->tx_txg != TXG_INITIAL) + spa_async_request(spa, + SPA_ASYNC_AUTOEXPAND); + break; + case ZPOOL_PROP_MULTIHOST: + spa->spa_multihost = intval; + break; + default: + break; + } } else { ASSERT(0); /* not allowed */ } - - switch (prop) { - case ZPOOL_PROP_DELEGATION: - spa->spa_delegation = intval; - break; - case ZPOOL_PROP_BOOTFS: - spa->spa_bootfs = intval; - break; - case ZPOOL_PROP_FAILUREMODE: - spa->spa_failmode = intval; - break; - case ZPOOL_PROP_AUTOTRIM: - spa->spa_autotrim = intval; - spa_async_request(spa, - SPA_ASYNC_AUTOTRIM_RESTART); - break; - case ZPOOL_PROP_AUTOEXPAND: - spa->spa_autoexpand = intval; - if (tx->tx_txg != TXG_INITIAL) - spa_async_request(spa, - SPA_ASYNC_AUTOEXPAND); - break; - case ZPOOL_PROP_MULTIHOST: - spa->spa_multihost = intval; - break; - default: - break; - } } } From c77d2d741571038956ea911743608f1c6266bb2e Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sat, 15 Oct 2022 23:35:56 -0400 Subject: [PATCH 049/126] crypto_get_ptrs() should always write to *out_data_2 Callers will check if it has been set to NULL before trying to access it, but never initialize it themselves. Whenever "one block spans two iovecs", `crypto_get_ptrs()` will return, without ever setting `*out_data_2 = NULL`. The caller will then do a NULL check against the uninitailized pointer and if it is not zero, pass it to `memcpy()`. The only reason this has not caused horrible runtime issues is because `memcpy()` should be told to copy zero bytes when this happens. That said, this is technically undefined behavior, so we should correct it so that future changes to the code cannot trigger it. Clang's static analyzer found this with the help of CodeChecker's CTU analysis. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14043 --- module/icp/algs/modes/modes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module/icp/algs/modes/modes.c b/module/icp/algs/modes/modes.c index b98db0ac14ec..2d1b5ff1a919 100644 --- a/module/icp/algs/modes/modes.c +++ b/module/icp/algs/modes/modes.c @@ -106,8 +106,10 @@ crypto_get_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset, } else { /* one block spans two iovecs */ *out_data_1_len = iov_len - offset; - if (vec_idx == zfs_uio_iovcnt(uio)) + if (vec_idx == zfs_uio_iovcnt(uio)) { + *out_data_2 = NULL; return; + } vec_idx++; zfs_uio_iov_at_index(uio, vec_idx, &iov_base, &iov_len); *out_data_2 = (uint8_t *)iov_base; From d692e6c36e1a9b77a7e4d2eaf5a38c7973cd9a5f Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Sun, 16 Oct 2022 00:02:47 -0400 Subject: [PATCH 050/126] abd_return_buf() should call zfs_refcount_remove_many() early Calling zfs_refcount_remove_many() after freeing memory means we pass a reference to freed memory as the holder. This is not believed to be able to cause a problem, but there is a bit of a tradition of fixing these issues when they appear so that they do not obscure more serious issues in static analyzer output, so we fix this one too. Clang's static analyzer found this with the help of CodeChecker's CTU analysis. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14043 --- module/zfs/abd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/zfs/abd.c b/module/zfs/abd.c index 11a1e5112544..d4921d0ba7db 100644 --- a/module/zfs/abd.c +++ b/module/zfs/abd.c @@ -667,15 +667,15 @@ abd_return_buf(abd_t *abd, void *buf, size_t n) { abd_verify(abd); ASSERT3U(abd->abd_size, >=, n); +#ifdef ZFS_DEBUG + (void) zfs_refcount_remove_many(&abd->abd_children, n, buf); +#endif if (abd_is_linear(abd)) { ASSERT3P(buf, ==, abd_to_buf(abd)); } else { ASSERT0(abd_cmp_buf(abd, buf, n)); zio_buf_free(buf, n); } -#ifdef ZFS_DEBUG - (void) zfs_refcount_remove_many(&abd->abd_children, n, buf); -#endif } void From 411d327c676225ca7a208b61899124ad27327657 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 17 Oct 2022 12:37:31 -0400 Subject: [PATCH 051/126] Add defensive assertion to vdev_queue_aggregate() a6ccb36b948efed0eeee4fcf99fe4b5fb81ae1d5 had been intended to include this to silence Coverity reports, but this one was missed by mistake. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14043 --- module/zfs/vdev_queue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/module/zfs/vdev_queue.c b/module/zfs/vdev_queue.c index f4e8d1427d7c..d3777897e5b0 100644 --- a/module/zfs/vdev_queue.c +++ b/module/zfs/vdev_queue.c @@ -725,6 +725,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) * after our span is mandatory. */ dio = AVL_NEXT(t, last); + ASSERT3P(dio, !=, NULL); dio->io_flags &= ~ZIO_FLAG_OPTIONAL; } else { /* do not include the optional i/o */ From 9650b35e95dd99bb3299b850693ea7218fd81d22 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 20 Oct 2022 12:12:21 -0400 Subject: [PATCH 052/126] Fix multiple definitions of struct mount_attr on recent glibc versions The ifdef used would never work because the CPP is not aware of C structure definitions. Rather than use an autotools check, we can just use a nameless structure that we typedef to mount_attr_t. This is a Linux kernel interface, which means that it is stable and this is fine to do. Reviewed-by: Brian Behlendorf Reviewed-by: Youzhong Yang Signed-off-by: Richard Yao Closes #14057 Closes #14058 --- tests/zfs-tests/cmd/idmap_util.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/zfs-tests/cmd/idmap_util.c b/tests/zfs-tests/cmd/idmap_util.c index a9731f00dbc0..143cd4db67be 100644 --- a/tests/zfs-tests/cmd/idmap_util.c +++ b/tests/zfs-tests/cmd/idmap_util.c @@ -99,18 +99,16 @@ #define AT_RECURSIVE 0x8000 #endif -#ifndef mount_attr -struct mount_attr { +typedef struct { __u64 attr_set; __u64 attr_clr; __u64 propagation; __u64 userns_fd; -}; -#endif +} mount_attr_t; static inline int sys_mount_setattr(int dfd, const char *path, unsigned int flags, - struct mount_attr *attr, size_t size) + mount_attr_t *attr, size_t size) { return (syscall(__NR_mount_setattr, dfd, path, flags, attr, size)); } @@ -528,7 +526,7 @@ is_idmap_supported(char *path) list_t head; int ret; int tree_fd = -EBADF, path_fd = -EBADF; - struct mount_attr attr = { + mount_attr_t attr = { .attr_set = MOUNT_ATTR_IDMAP, .userns_fd = -EBADF, }; @@ -634,7 +632,7 @@ do_idmap_mount(list_t *idmap, char *source, char *target, int flags) { int ret; int tree_fd = -EBADF, source_fd = -EBADF; - struct mount_attr attr = { + mount_attr_t attr = { .attr_set = MOUNT_ATTR_IDMAP, .userns_fd = -EBADF, }; From 9dcdee788985b4aa9bbf250af3e018056402ba9f Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Thu, 20 Oct 2022 14:57:15 -0400 Subject: [PATCH 053/126] Optimize microzaps Microzap on-disk format does not include a hash tree, expecting one to be built in RAM during mzap_open(). The built tree is linked to DMU user buffer, freed when original DMU buffer is dropped from cache. I've found that workloads accessing many large directories and having active eviction from DMU cache spend significant amount of time building and then destroying the trees. I've also found that for each 64 byte mzap element additional 64 byte tree element is allocated, that is a waste of memory and CPU caches. Improve memory efficiency of the hash tree by switching from AVL-tree to B-tree. It allows to save 24 bytes per element just on pointers. Save 32 bits on mze_hash by storing only upper 32 bits since lower 32 bits are always zero for microzaps. Save 16 bits on mze_chunkid, since microzap can never have so many elements. Respectively with the 16 bits there can be no more than 16 bits of collision differentiators. As result, struct mzap_ent now drops from 48 (rounded to 64) to 8 bytes. Tune B-trees for small data. Reduce BTREE_CORE_ELEMS from 128 to 126 to allow struct zfs_btree_core in case of 8 byte elements to pack into 2KB instead of 4KB. Aside of the microzaps it should also help 32bit range trees. Allow custom B-tree leaf size to reduce memmove() time. Split zap_name_alloc() into zap_name_alloc() and zap_name_init_str(). It allows to not waste time allocating/freeing memory when processing multiple names in a loop during mzap_open(). Together on a pool with 10K directories of 1800 files each and DMU cache limited to 128MB this reduces time of `find . -name zzz` by 41% from 7.63s to 4.47s, and saves additional ~30% of CPU time on the DMU cache reclamation. Reviewed-by: Brian Behlendorf Reviewed-by: Matthew Ahrens Reviewed-by: Ryan Moeller Signed-off-by: Alexander Motin Sponsored by: iXsystems, Inc. Closes #14039 --- include/sys/btree.h | 15 +-- include/sys/zap_impl.h | 11 +- module/zfs/btree.c | 50 +++++++-- module/zfs/zap_leaf.c | 4 +- module/zfs/zap_micro.c | 241 +++++++++++++++++++++++------------------ 5 files changed, 188 insertions(+), 133 deletions(-) diff --git a/include/sys/btree.h b/include/sys/btree.h index a901d654ef1c..883abb5181c9 100644 --- a/include/sys/btree.h +++ b/include/sys/btree.h @@ -65,7 +65,7 @@ extern "C" { * them, and increased memory overhead. Increasing these values results in * higher variance in operation time, and reduces memory overhead. */ -#define BTREE_CORE_ELEMS 128 +#define BTREE_CORE_ELEMS 126 #define BTREE_LEAF_SIZE 4096 extern kmem_cache_t *zfs_btree_leaf_cache; @@ -95,9 +95,6 @@ typedef struct zfs_btree_leaf { uint8_t btl_elems[]; } zfs_btree_leaf_t; -#define BTREE_LEAF_ESIZE (BTREE_LEAF_SIZE - \ - offsetof(zfs_btree_leaf_t, btl_elems)) - typedef struct zfs_btree_index { zfs_btree_hdr_t *bti_node; uint32_t bti_offset; @@ -109,14 +106,15 @@ typedef struct zfs_btree_index { } zfs_btree_index_t; typedef struct btree { - zfs_btree_hdr_t *bt_root; - int64_t bt_height; + int (*bt_compar) (const void *, const void *); size_t bt_elem_size; + size_t bt_leaf_size; uint32_t bt_leaf_cap; + int32_t bt_height; uint64_t bt_num_elems; uint64_t bt_num_nodes; + zfs_btree_hdr_t *bt_root; zfs_btree_leaf_t *bt_bulk; // non-null if bulk loading - int (*bt_compar) (const void *, const void *); } zfs_btree_t; /* @@ -132,9 +130,12 @@ void zfs_btree_fini(void); * compar - function to compare two nodes, it must return exactly: -1, 0, or +1 * -1 for <, 0 for ==, and +1 for > * size - the value of sizeof(struct my_type) + * lsize - custom leaf size */ void zfs_btree_create(zfs_btree_t *, int (*) (const void *, const void *), size_t); +void zfs_btree_create_custom(zfs_btree_t *, int (*)(const void *, const void *), + size_t, size_t); /* * Find a node with a matching value in the tree. Returns the matching node diff --git a/include/sys/zap_impl.h b/include/sys/zap_impl.h index fab677964e7c..74853f5faceb 100644 --- a/include/sys/zap_impl.h +++ b/include/sys/zap_impl.h @@ -66,10 +66,9 @@ typedef struct mzap_phys { } mzap_phys_t; typedef struct mzap_ent { - avl_node_t mze_node; - int mze_chunkid; - uint64_t mze_hash; - uint32_t mze_cd; /* copy from mze_phys->mze_cd */ + uint32_t mze_hash; + uint16_t mze_cd; /* copy from mze_phys->mze_cd */ + uint16_t mze_chunkid; } mzap_ent_t; #define MZE_PHYS(zap, mze) \ @@ -164,7 +163,7 @@ typedef struct zap { int16_t zap_num_entries; int16_t zap_num_chunks; int16_t zap_alloc_next; - avl_tree_t zap_avl; + zfs_btree_t zap_tree; } zap_micro; } zap_u; } zap_t; @@ -203,7 +202,7 @@ int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx, zap_t **zapp); void zap_unlockdir(zap_t *zap, const void *tag); void zap_evict_sync(void *dbu); -zap_name_t *zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt); +zap_name_t *zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt); void zap_name_free(zap_name_t *zn); int zap_hashbits(zap_t *zap); uint32_t zap_maxcd(zap_t *zap); diff --git a/module/zfs/btree.c b/module/zfs/btree.c index f0a9222a4308..4c25afaa8199 100644 --- a/module/zfs/btree.c +++ b/module/zfs/btree.c @@ -102,7 +102,7 @@ zfs_btree_poison_node(zfs_btree_t *tree, zfs_btree_hdr_t *hdr) (void) memset(leaf->btl_elems, 0x0f, hdr->bth_first * size); (void) memset(leaf->btl_elems + (hdr->bth_first + hdr->bth_count) * size, 0x0f, - BTREE_LEAF_ESIZE - + tree->bt_leaf_size - offsetof(zfs_btree_leaf_t, btl_elems) - (hdr->bth_first + hdr->bth_count) * size); } #endif @@ -173,16 +173,44 @@ zfs_btree_fini(void) kmem_cache_destroy(zfs_btree_leaf_cache); } +static void * +zfs_btree_leaf_alloc(zfs_btree_t *tree) +{ + if (tree->bt_leaf_size == BTREE_LEAF_SIZE) + return (kmem_cache_alloc(zfs_btree_leaf_cache, KM_SLEEP)); + else + return (kmem_alloc(tree->bt_leaf_size, KM_SLEEP)); +} + +static void +zfs_btree_leaf_free(zfs_btree_t *tree, void *ptr) +{ + if (tree->bt_leaf_size == BTREE_LEAF_SIZE) + return (kmem_cache_free(zfs_btree_leaf_cache, ptr)); + else + return (kmem_free(ptr, tree->bt_leaf_size)); +} + void zfs_btree_create(zfs_btree_t *tree, int (*compar) (const void *, const void *), size_t size) { - ASSERT3U(size, <=, BTREE_LEAF_ESIZE / 2); + zfs_btree_create_custom(tree, compar, size, BTREE_LEAF_SIZE); +} +void +zfs_btree_create_custom(zfs_btree_t *tree, + int (*compar) (const void *, const void *), + size_t size, size_t lsize) +{ + size_t esize = lsize - offsetof(zfs_btree_leaf_t, btl_elems); + + ASSERT3U(size, <=, esize / 2); memset(tree, 0, sizeof (*tree)); tree->bt_compar = compar; tree->bt_elem_size = size; - tree->bt_leaf_cap = P2ALIGN(BTREE_LEAF_ESIZE / size, 2); + tree->bt_leaf_size = lsize; + tree->bt_leaf_cap = P2ALIGN(esize / size, 2); tree->bt_height = -1; tree->bt_bulk = NULL; } @@ -290,7 +318,7 @@ zfs_btree_find(zfs_btree_t *tree, const void *value, zfs_btree_index_t *where) zfs_btree_core_t *node = NULL; uint32_t child = 0; - uint64_t depth = 0; + uint32_t depth = 0; /* * Iterate down the tree, finding which child the value should be in @@ -811,8 +839,7 @@ zfs_btree_insert_into_leaf(zfs_btree_t *tree, zfs_btree_leaf_t *leaf, move_count++; } tree->bt_num_nodes++; - zfs_btree_leaf_t *new_leaf = kmem_cache_alloc(zfs_btree_leaf_cache, - KM_SLEEP); + zfs_btree_leaf_t *new_leaf = zfs_btree_leaf_alloc(tree); zfs_btree_hdr_t *new_hdr = &new_leaf->btl_hdr; new_hdr->bth_parent = leaf->btl_hdr.bth_parent; new_hdr->bth_first = (tree->bt_bulk ? 0 : capacity / 4) + @@ -1078,8 +1105,7 @@ zfs_btree_add_idx(zfs_btree_t *tree, const void *value, ASSERT0(where->bti_offset); tree->bt_num_nodes++; - zfs_btree_leaf_t *leaf = kmem_cache_alloc(zfs_btree_leaf_cache, - KM_SLEEP); + zfs_btree_leaf_t *leaf = zfs_btree_leaf_alloc(tree); tree->bt_root = &leaf->btl_hdr; tree->bt_height++; @@ -1378,7 +1404,7 @@ zfs_btree_node_destroy(zfs_btree_t *tree, zfs_btree_hdr_t *node) { tree->bt_num_nodes--; if (!zfs_btree_is_core(node)) { - kmem_cache_free(zfs_btree_leaf_cache, node); + zfs_btree_leaf_free(tree, node); } else { kmem_free(node, sizeof (zfs_btree_core_t) + BTREE_CORE_ELEMS * tree->bt_elem_size); @@ -1991,7 +2017,7 @@ zfs_btree_verify_counts(zfs_btree_t *tree) */ static uint64_t zfs_btree_verify_height_helper(zfs_btree_t *tree, zfs_btree_hdr_t *hdr, - int64_t height) + int32_t height) { if (!zfs_btree_is_core(hdr)) { VERIFY0(height); @@ -2117,8 +2143,10 @@ zfs_btree_verify_poison_helper(zfs_btree_t *tree, zfs_btree_hdr_t *hdr) zfs_btree_leaf_t *leaf = (zfs_btree_leaf_t *)hdr; for (size_t i = 0; i < hdr->bth_first * size; i++) VERIFY3U(leaf->btl_elems[i], ==, 0x0f); + size_t esize = tree->bt_leaf_size - + offsetof(zfs_btree_leaf_t, btl_elems); for (size_t i = (hdr->bth_first + hdr->bth_count) * size; - i < BTREE_LEAF_ESIZE; i++) + i < esize; i++) VERIFY3U(leaf->btl_elems[i], ==, 0x0f); } else { zfs_btree_core_t *node = (zfs_btree_core_t *)hdr; diff --git a/module/zfs/zap_leaf.c b/module/zfs/zap_leaf.c index 25c2d5163a26..2e8489c7dfcf 100644 --- a/module/zfs/zap_leaf.c +++ b/module/zfs/zap_leaf.c @@ -646,7 +646,7 @@ zap_entry_create(zap_leaf_t *l, zap_name_t *zn, uint32_t cd, * form of the name. But all callers have one of these on hand anyway, * so might as well take advantage. A cleaner but slower interface * would accept neither argument, and compute the normalized name as - * needed (using zap_name_alloc(zap_entry_read_name(zeh))). + * needed (using zap_name_alloc_str(zap_entry_read_name(zeh))). */ boolean_t zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn, @@ -667,7 +667,7 @@ zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn, continue; if (zn == NULL) { - zn = zap_name_alloc(zap, name, MT_NORMALIZE); + zn = zap_name_alloc_str(zap, name, MT_NORMALIZE); allocdzn = B_TRUE; } if (zap_leaf_array_match(zeh->zeh_leaf, zn, diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c index 4bf8a322e91b..606f426404cc 100644 --- a/module/zfs/zap_micro.c +++ b/module/zfs/zap_micro.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -92,7 +92,7 @@ zap_hash(zap_name_t *zn) wp++, i++) { uint64_t word = *wp; - for (int j = 0; j < zn->zn_key_intlen; j++) { + for (int j = 0; j < 8; j++) { h = (h >> 8) ^ zfs_crc64_table[(h ^ word) & 0xFF]; word >>= NBBY; @@ -162,18 +162,25 @@ zap_match(zap_name_t *zn, const char *matchname) } } +static zap_name_t * +zap_name_alloc(zap_t *zap) +{ + zap_name_t *zn = kmem_alloc(sizeof (zap_name_t), KM_SLEEP); + zn->zn_zap = zap; + return (zn); +} + void zap_name_free(zap_name_t *zn) { kmem_free(zn, sizeof (zap_name_t)); } -zap_name_t * -zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt) +static int +zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt) { - zap_name_t *zn = kmem_alloc(sizeof (zap_name_t), KM_SLEEP); + zap_t *zap = zn->zn_zap; - zn->zn_zap = zap; zn->zn_key_intlen = sizeof (*key); zn->zn_key_orig = key; zn->zn_key_orig_numints = strlen(zn->zn_key_orig) + 1; @@ -194,17 +201,13 @@ zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt) * what the hash is computed from. */ if (zap_normalize(zap, key, zn->zn_normbuf, - zap->zap_normflags) != 0) { - zap_name_free(zn); - return (NULL); - } + zap->zap_normflags) != 0) + return (SET_ERROR(ENOTSUP)); zn->zn_key_norm = zn->zn_normbuf; zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1; } else { - if (mt != 0) { - zap_name_free(zn); - return (NULL); - } + if (mt != 0) + return (SET_ERROR(ENOTSUP)); zn->zn_key_norm = zn->zn_key_orig; zn->zn_key_norm_numints = zn->zn_key_orig_numints; } @@ -217,13 +220,22 @@ zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt) * what the matching is based on. (Not the hash!) */ if (zap_normalize(zap, key, zn->zn_normbuf, - zn->zn_normflags) != 0) { - zap_name_free(zn); - return (NULL); - } + zn->zn_normflags) != 0) + return (SET_ERROR(ENOTSUP)); zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1; } + return (0); +} + +zap_name_t * +zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt) +{ + zap_name_t *zn = zap_name_alloc(zap); + if (zap_name_init_str(zn, key, mt) != 0) { + zap_name_free(zn); + return (NULL); + } return (zn); } @@ -277,45 +289,46 @@ mze_compare(const void *arg1, const void *arg2) const mzap_ent_t *mze1 = arg1; const mzap_ent_t *mze2 = arg2; - int cmp = TREE_CMP(mze1->mze_hash, mze2->mze_hash); - if (likely(cmp)) - return (cmp); - - return (TREE_CMP(mze1->mze_cd, mze2->mze_cd)); + return (TREE_CMP((uint64_t)(mze1->mze_hash) << 32 | mze1->mze_cd, + (uint64_t)(mze2->mze_hash) << 32 | mze2->mze_cd)); } static void -mze_insert(zap_t *zap, int chunkid, uint64_t hash) +mze_insert(zap_t *zap, uint16_t chunkid, uint64_t hash) { + mzap_ent_t mze; + ASSERT(zap->zap_ismicro); ASSERT(RW_WRITE_HELD(&zap->zap_rwlock)); - mzap_ent_t *mze = kmem_alloc(sizeof (mzap_ent_t), KM_SLEEP); - mze->mze_chunkid = chunkid; - mze->mze_hash = hash; - mze->mze_cd = MZE_PHYS(zap, mze)->mze_cd; - ASSERT(MZE_PHYS(zap, mze)->mze_name[0] != 0); - avl_add(&zap->zap_m.zap_avl, mze); + mze.mze_chunkid = chunkid; + ASSERT0(hash & 0xffffffff); + mze.mze_hash = hash >> 32; + ASSERT3U(MZE_PHYS(zap, &mze)->mze_cd, <=, 0xffff); + mze.mze_cd = (uint16_t)MZE_PHYS(zap, &mze)->mze_cd; + ASSERT(MZE_PHYS(zap, &mze)->mze_name[0] != 0); + zfs_btree_add(&zap->zap_m.zap_tree, &mze); } static mzap_ent_t * -mze_find(zap_name_t *zn) +mze_find(zap_name_t *zn, zfs_btree_index_t *idx) { mzap_ent_t mze_tofind; mzap_ent_t *mze; - avl_index_t idx; - avl_tree_t *avl = &zn->zn_zap->zap_m.zap_avl; + zfs_btree_t *tree = &zn->zn_zap->zap_m.zap_tree; ASSERT(zn->zn_zap->zap_ismicro); ASSERT(RW_LOCK_HELD(&zn->zn_zap->zap_rwlock)); - mze_tofind.mze_hash = zn->zn_hash; + ASSERT0(zn->zn_hash & 0xffffffff); + mze_tofind.mze_hash = zn->zn_hash >> 32; mze_tofind.mze_cd = 0; - mze = avl_find(avl, &mze_tofind, &idx); + mze = zfs_btree_find(tree, &mze_tofind, idx); if (mze == NULL) - mze = avl_nearest(avl, idx, AVL_AFTER); - for (; mze && mze->mze_hash == zn->zn_hash; mze = AVL_NEXT(avl, mze)) { + mze = zfs_btree_next(tree, idx, idx); + for (; mze && mze->mze_hash == mze_tofind.mze_hash; + mze = zfs_btree_next(tree, idx, idx)) { ASSERT3U(mze->mze_cd, ==, MZE_PHYS(zn->zn_zap, mze)->mze_cd); if (zap_match(zn, MZE_PHYS(zn->zn_zap, mze)->mze_name)) return (mze); @@ -328,18 +341,21 @@ static uint32_t mze_find_unused_cd(zap_t *zap, uint64_t hash) { mzap_ent_t mze_tofind; - avl_index_t idx; - avl_tree_t *avl = &zap->zap_m.zap_avl; + zfs_btree_index_t idx; + zfs_btree_t *tree = &zap->zap_m.zap_tree; ASSERT(zap->zap_ismicro); ASSERT(RW_LOCK_HELD(&zap->zap_rwlock)); + ASSERT0(hash & 0xffffffff); + hash >>= 32; mze_tofind.mze_hash = hash; mze_tofind.mze_cd = 0; uint32_t cd = 0; - for (mzap_ent_t *mze = avl_find(avl, &mze_tofind, &idx); - mze && mze->mze_hash == hash; mze = AVL_NEXT(avl, mze)) { + for (mzap_ent_t *mze = zfs_btree_find(tree, &mze_tofind, &idx); + mze && mze->mze_hash == hash; + mze = zfs_btree_next(tree, &idx, &idx)) { if (mze->mze_cd != cd) break; cd++; @@ -364,16 +380,18 @@ mze_canfit_fzap_leaf(zap_name_t *zn, uint64_t hash) { zap_t *zap = zn->zn_zap; mzap_ent_t mze_tofind; - mzap_ent_t *mze; - avl_index_t idx; - avl_tree_t *avl = &zap->zap_m.zap_avl; + zfs_btree_index_t idx; + zfs_btree_t *tree = &zap->zap_m.zap_tree; uint32_t mzap_ents = 0; + ASSERT0(hash & 0xffffffff); + hash >>= 32; mze_tofind.mze_hash = hash; mze_tofind.mze_cd = 0; - for (mze = avl_find(avl, &mze_tofind, &idx); - mze && mze->mze_hash == hash; mze = AVL_NEXT(avl, mze)) { + for (mzap_ent_t *mze = zfs_btree_find(tree, &mze_tofind, &idx); + mze && mze->mze_hash == hash; + mze = zfs_btree_next(tree, &idx, &idx)) { mzap_ents++; } @@ -383,25 +401,11 @@ mze_canfit_fzap_leaf(zap_name_t *zn, uint64_t hash) return (ZAP_LEAF_NUMCHUNKS_DEF > (mzap_ents * MZAP_ENT_CHUNKS)); } -static void -mze_remove(zap_t *zap, mzap_ent_t *mze) -{ - ASSERT(zap->zap_ismicro); - ASSERT(RW_WRITE_HELD(&zap->zap_rwlock)); - - avl_remove(&zap->zap_m.zap_avl, mze); - kmem_free(mze, sizeof (mzap_ent_t)); -} - static void mze_destroy(zap_t *zap) { - mzap_ent_t *mze; - void *avlcookie = NULL; - - while ((mze = avl_destroy_nodes(&zap->zap_m.zap_avl, &avlcookie))) - kmem_free(mze, sizeof (mzap_ent_t)); - avl_destroy(&zap->zap_m.zap_avl); + zfs_btree_clear(&zap->zap_m.zap_tree); + zfs_btree_destroy(&zap->zap_m.zap_tree); } static zap_t * @@ -448,21 +452,26 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db) zap->zap_salt = zap_m_phys(zap)->mz_salt; zap->zap_normflags = zap_m_phys(zap)->mz_normflags; zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1; - avl_create(&zap->zap_m.zap_avl, mze_compare, - sizeof (mzap_ent_t), offsetof(mzap_ent_t, mze_node)); - for (int i = 0; i < zap->zap_m.zap_num_chunks; i++) { + /* + * Reduce B-tree leaf from 4KB to 512 bytes to reduce memmove() + * overhead on massive inserts below. It still allows to store + * 62 entries before we have to add 2KB B-tree core node. + */ + zfs_btree_create_custom(&zap->zap_m.zap_tree, mze_compare, + sizeof (mzap_ent_t), 512); + + zap_name_t *zn = zap_name_alloc(zap); + for (uint16_t i = 0; i < zap->zap_m.zap_num_chunks; i++) { mzap_ent_phys_t *mze = &zap_m_phys(zap)->mz_chunk[i]; if (mze->mze_name[0]) { - zap_name_t *zn; - zap->zap_m.zap_num_entries++; - zn = zap_name_alloc(zap, mze->mze_name, 0); + zap_name_init_str(zn, mze->mze_name, 0); mze_insert(zap, i, zn->zn_hash); - zap_name_free(zn); } } + zap_name_free(zn); } else { zap->zap_salt = zap_f_phys(zap)->zap_salt; zap->zap_normflags = zap_f_phys(zap)->zap_normflags; @@ -657,24 +666,25 @@ mzap_upgrade(zap_t **zapp, const void *tag, dmu_tx_t *tx, zap_flags_t flags) dprintf("upgrading obj=%llu with %u chunks\n", (u_longlong_t)zap->zap_object, nchunks); - /* XXX destroy the avl later, so we can use the stored hash value */ + /* XXX destroy the tree later, so we can use the stored hash value */ mze_destroy(zap); fzap_upgrade(zap, tx, flags); + zap_name_t *zn = zap_name_alloc(zap); for (int i = 0; i < nchunks; i++) { mzap_ent_phys_t *mze = &mzp->mz_chunk[i]; if (mze->mze_name[0] == 0) continue; dprintf("adding %s=%llu\n", mze->mze_name, (u_longlong_t)mze->mze_value); - zap_name_t *zn = zap_name_alloc(zap, mze->mze_name, 0); + zap_name_init_str(zn, mze->mze_name, 0); /* If we fail here, we would end up losing entries */ VERIFY0(fzap_add_cd(zn, 8, 1, &mze->mze_value, mze->mze_cd, tag, tx)); zap = zn->zn_zap; /* fzap_add_cd() may change zap */ - zap_name_free(zn); } + zap_name_free(zn); vmem_free(mzp, sz); *zapp = zap; return (0); @@ -916,22 +926,23 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count) * See also the comment above zap_entry_normalization_conflict(). */ static boolean_t -mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze) +mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze, + zfs_btree_index_t *idx) { - int direction = AVL_BEFORE; boolean_t allocdzn = B_FALSE; + mzap_ent_t *other; + zfs_btree_index_t oidx; if (zap->zap_normflags == 0) return (B_FALSE); -again: - for (mzap_ent_t *other = avl_walk(&zap->zap_m.zap_avl, mze, direction); + for (other = zfs_btree_prev(&zap->zap_m.zap_tree, idx, &oidx); other && other->mze_hash == mze->mze_hash; - other = avl_walk(&zap->zap_m.zap_avl, other, direction)) { + other = zfs_btree_prev(&zap->zap_m.zap_tree, &oidx, &oidx)) { if (zn == NULL) { - zn = zap_name_alloc(zap, MZE_PHYS(zap, mze)->mze_name, - MT_NORMALIZE); + zn = zap_name_alloc_str(zap, + MZE_PHYS(zap, mze)->mze_name, MT_NORMALIZE); allocdzn = B_TRUE; } if (zap_match(zn, MZE_PHYS(zap, other)->mze_name)) { @@ -941,9 +952,20 @@ mzap_normalization_conflict(zap_t *zap, zap_name_t *zn, mzap_ent_t *mze) } } - if (direction == AVL_BEFORE) { - direction = AVL_AFTER; - goto again; + for (other = zfs_btree_next(&zap->zap_m.zap_tree, idx, &oidx); + other && other->mze_hash == mze->mze_hash; + other = zfs_btree_next(&zap->zap_m.zap_tree, &oidx, &oidx)) { + + if (zn == NULL) { + zn = zap_name_alloc_str(zap, + MZE_PHYS(zap, mze)->mze_name, MT_NORMALIZE); + allocdzn = B_TRUE; + } + if (zap_match(zn, MZE_PHYS(zap, other)->mze_name)) { + if (allocdzn) + zap_name_free(zn); + return (B_TRUE); + } } if (allocdzn) @@ -971,7 +993,7 @@ zap_lookup_impl(zap_t *zap, const char *name, { int err = 0; - zap_name_t *zn = zap_name_alloc(zap, name, mt); + zap_name_t *zn = zap_name_alloc_str(zap, name, mt); if (zn == NULL) return (SET_ERROR(ENOTSUP)); @@ -979,7 +1001,8 @@ zap_lookup_impl(zap_t *zap, const char *name, err = fzap_lookup(zn, integer_size, num_integers, buf, realname, rn_len, ncp); } else { - mzap_ent_t *mze = mze_find(zn); + zfs_btree_index_t idx; + mzap_ent_t *mze = mze_find(zn, &idx); if (mze == NULL) { err = SET_ERROR(ENOENT); } else { @@ -996,7 +1019,7 @@ zap_lookup_impl(zap_t *zap, const char *name, rn_len); if (ncp) { *ncp = mzap_normalization_conflict(zap, - zn, mze); + zn, mze, &idx); } } } @@ -1033,7 +1056,7 @@ zap_prefetch(objset_t *os, uint64_t zapobj, const char *name) err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err) return (err); - zn = zap_name_alloc(zap, name, 0); + zn = zap_name_alloc_str(zap, name, 0); if (zn == NULL) { zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); @@ -1136,7 +1159,7 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name, zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap); if (err != 0) return (err); - zap_name_t *zn = zap_name_alloc(zap, name, 0); + zap_name_t *zn = zap_name_alloc_str(zap, name, 0); if (zn == NULL) { zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); @@ -1144,7 +1167,8 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name, if (!zap->zap_ismicro) { err = fzap_length(zn, integer_size, num_integers); } else { - mzap_ent_t *mze = mze_find(zn); + zfs_btree_index_t idx; + mzap_ent_t *mze = mze_find(zn, &idx); if (mze == NULL) { err = SET_ERROR(ENOENT); } else { @@ -1184,7 +1208,7 @@ static void mzap_addent(zap_name_t *zn, uint64_t value) { zap_t *zap = zn->zn_zap; - int start = zap->zap_m.zap_alloc_next; + uint16_t start = zap->zap_m.zap_alloc_next; ASSERT(RW_WRITE_HELD(&zap->zap_rwlock)); @@ -1200,7 +1224,7 @@ mzap_addent(zap_name_t *zn, uint64_t value) ASSERT(cd < zap_maxcd(zap)); again: - for (int i = start; i < zap->zap_m.zap_num_chunks; i++) { + for (uint16_t i = start; i < zap->zap_m.zap_num_chunks; i++) { mzap_ent_phys_t *mze = &zap_m_phys(zap)->mz_chunk[i]; if (mze->mze_name[0] == 0) { mze->mze_value = value; @@ -1231,7 +1255,7 @@ zap_add_impl(zap_t *zap, const char *key, const uint64_t *intval = val; int err = 0; - zap_name_t *zn = zap_name_alloc(zap, key, 0); + zap_name_t *zn = zap_name_alloc_str(zap, key, 0); if (zn == NULL) { zap_unlockdir(zap, tag); return (SET_ERROR(ENOTSUP)); @@ -1249,7 +1273,8 @@ zap_add_impl(zap_t *zap, const char *key, } zap = zn->zn_zap; /* fzap_add() may change zap */ } else { - if (mze_find(zn) != NULL) { + zfs_btree_index_t idx; + if (mze_find(zn, &idx) != NULL) { err = SET_ERROR(EEXIST); } else { mzap_addent(zn, *intval); @@ -1329,7 +1354,7 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name, zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap); if (err != 0) return (err); - zap_name_t *zn = zap_name_alloc(zap, name, 0); + zap_name_t *zn = zap_name_alloc_str(zap, name, 0); if (zn == NULL) { zap_unlockdir(zap, FTAG); return (SET_ERROR(ENOTSUP)); @@ -1350,7 +1375,8 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name, } zap = zn->zn_zap; /* fzap_update() may change zap */ } else { - mzap_ent_t *mze = mze_find(zn); + zfs_btree_index_t idx; + mzap_ent_t *mze = mze_find(zn, &idx); if (mze != NULL) { MZE_PHYS(zap, mze)->mze_value = *intval; } else { @@ -1400,20 +1426,20 @@ zap_remove_impl(zap_t *zap, const char *name, { int err = 0; - zap_name_t *zn = zap_name_alloc(zap, name, mt); + zap_name_t *zn = zap_name_alloc_str(zap, name, mt); if (zn == NULL) return (SET_ERROR(ENOTSUP)); if (!zap->zap_ismicro) { err = fzap_remove(zn, tx); } else { - mzap_ent_t *mze = mze_find(zn); + zfs_btree_index_t idx; + mzap_ent_t *mze = mze_find(zn, &idx); if (mze == NULL) { err = SET_ERROR(ENOENT); } else { zap->zap_m.zap_num_entries--; - memset(&zap_m_phys(zap)->mz_chunk[mze->mze_chunkid], 0, - sizeof (mzap_ent_phys_t)); - mze_remove(zap, mze); + memset(MZE_PHYS(zap, mze), 0, sizeof (mzap_ent_phys_t)); + zfs_btree_remove_idx(&zap->zap_m.zap_tree, &idx); } } zap_name_free(zn); @@ -1584,29 +1610,30 @@ zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za) if (!zc->zc_zap->zap_ismicro) { err = fzap_cursor_retrieve(zc->zc_zap, zc, za); } else { - avl_index_t idx; + zfs_btree_index_t idx; mzap_ent_t mze_tofind; - mze_tofind.mze_hash = zc->zc_hash; + mze_tofind.mze_hash = zc->zc_hash >> 32; mze_tofind.mze_cd = zc->zc_cd; - mzap_ent_t *mze = - avl_find(&zc->zc_zap->zap_m.zap_avl, &mze_tofind, &idx); + mzap_ent_t *mze = zfs_btree_find(&zc->zc_zap->zap_m.zap_tree, + &mze_tofind, &idx); if (mze == NULL) { - mze = avl_nearest(&zc->zc_zap->zap_m.zap_avl, - idx, AVL_AFTER); + mze = zfs_btree_next(&zc->zc_zap->zap_m.zap_tree, + &idx, &idx); } if (mze) { mzap_ent_phys_t *mzep = MZE_PHYS(zc->zc_zap, mze); ASSERT3U(mze->mze_cd, ==, mzep->mze_cd); za->za_normalization_conflict = - mzap_normalization_conflict(zc->zc_zap, NULL, mze); + mzap_normalization_conflict(zc->zc_zap, NULL, + mze, &idx); za->za_integer_length = 8; za->za_num_integers = 1; za->za_first_integer = mzep->mze_value; (void) strlcpy(za->za_name, mzep->mze_name, sizeof (za->za_name)); - zc->zc_hash = mze->mze_hash; + zc->zc_hash = (uint64_t)mze->mze_hash << 32; zc->zc_cd = mze->mze_cd; err = 0; } else { From a06df8d7c1ec878d3717c16f6457f2b8693893c4 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 20 Oct 2022 17:14:42 -0400 Subject: [PATCH 054/126] Linux: Upgrade random_get_pseudo_bytes() to xoshiro256++ 1.0 The motivation for upgrading our PRNG is the recent buildbot failures in the ZTS' tests/functional/fault/decompress_fault test. The probability of a failure in that test is 0.8^256, which is ~1.6e-25 out of 1, yet we have observed multiple test failures in it. This suggests a problem with our random number generation. The xorshift128+ generator that we were using has been replaced by newer generators that have "better statistical properties". After doing some reading, it turns out that these generators have "low linear complexity of the lowest bits", which could explain the ZTS test failures. We do two things to try to fix this: 1. We upgrade from xorshift128+ to xoshiro256++ 1.0. 2. We tweak random_get_pseudo_bytes() to copy the higher order bytes first. It is hoped that this will fix the test failures in tests/functional/fault/decompress_fault, although I have not done simulations. I am skeptical that any simulations I do on a PRNG with a period of 2^256 - 1 would be meaningful. Since we have raised the minimum kernel version to 3.10 since this was first implemented, we have the option of using the Linux kernel's get_random_int(). However, I am not currently prepared to do performance tests to ensure that this would not be a regression (for the time being), so we opt for upgrading our PRNG to a newer one from Sebastiano Vigna. Reviewed-by: Brian Behlendorf Reviewed-by: Tino Reichardt Signed-off-by: Richard Yao Closes #13983 --- module/os/linux/spl/spl-generic.c | 86 ++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/module/os/linux/spl/spl-generic.c b/module/os/linux/spl/spl-generic.c index e3aa900ba6dd..71eedf635f73 100644 --- a/module/os/linux/spl/spl-generic.c +++ b/module/os/linux/spl/spl-generic.c @@ -23,6 +23,7 @@ * Solaris Porting Layer (SPL) Generic Implementation. */ +#include #include #include #include @@ -61,10 +62,10 @@ proc_t p0; EXPORT_SYMBOL(p0); /* - * Xorshift Pseudo Random Number Generator based on work by Sebastiano Vigna + * xoshiro256++ 1.0 PRNG by David Blackman and Sebastiano Vigna * - * "Further scramblings of Marsaglia's xorshift generators" - * http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf + * "Scrambled Linear Pseudorandom Number Generators∗" + * https://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf * * random_get_pseudo_bytes() is an API function on Illumos whose sole purpose * is to provide bytes containing random numbers. It is mapped to /dev/urandom @@ -76,14 +77,14 @@ EXPORT_SYMBOL(p0); * free of atomic instructions. * * A consequence of using a fast PRNG is that using random_get_pseudo_bytes() - * to generate words larger than 128 bits will paradoxically be limited to - * `2^128 - 1` possibilities. This is because we have a sequence of `2^128 - 1` - * 128-bit words and selecting the first will implicitly select the second. If + * to generate words larger than 256 bits will paradoxically be limited to + * `2^256 - 1` possibilities. This is because we have a sequence of `2^256 - 1` + * 256-bit words and selecting the first will implicitly select the second. If * a caller finds this behavior undesirable, random_get_bytes() should be used * instead. * * XXX: Linux interrupt handlers that trigger within the critical section - * formed by `s[1] = xp[1];` and `xp[0] = s[0];` and call this function will + * formed by `s[3] = xp[3];` and `xp[0] = s[0];` and call this function will * see the same numbers. Nothing in the code currently calls this in an * interrupt handler, so this is considered to be okay. If that becomes a * problem, we could create a set of per-cpu variables for interrupt handlers @@ -93,49 +94,68 @@ EXPORT_SYMBOL(p0); static void __percpu *spl_pseudo_entropy; /* - * spl_rand_next()/spl_rand_jump() are copied from the following CC-0 licensed - * file: + * rotl()/spl_rand_next()/spl_rand_jump() are copied from the following CC-0 + * licensed file: * - * http://xorshift.di.unimi.it/xorshift128plus.c + * https://prng.di.unimi.it/xoshiro256plusplus.c */ +static inline uint64_t rotl(const uint64_t x, int k) +{ + return ((x << k) | (x >> (64 - k))); +} + static inline uint64_t spl_rand_next(uint64_t *s) { - uint64_t s1 = s[0]; - const uint64_t s0 = s[1]; - s[0] = s0; - s1 ^= s1 << 23; // a - s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); // b, c - return (s[1] + s0); + const uint64_t result = rotl(s[0] + s[3], 23) + s[0]; + + const uint64_t t = s[1] << 17; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + + s[2] ^= t; + + s[3] = rotl(s[3], 45); + + return (result); } static inline void spl_rand_jump(uint64_t *s) { - static const uint64_t JUMP[] = - { 0x8a5cd789635d2dff, 0x121fd2155c472f96 }; + static const uint64_t JUMP[] = { 0x180ec6d33cfd0aba, + 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c }; uint64_t s0 = 0; uint64_t s1 = 0; + uint64_t s2 = 0; + uint64_t s3 = 0; int i, b; for (i = 0; i < sizeof (JUMP) / sizeof (*JUMP); i++) for (b = 0; b < 64; b++) { if (JUMP[i] & 1ULL << b) { s0 ^= s[0]; s1 ^= s[1]; + s2 ^= s[2]; + s3 ^= s[3]; } (void) spl_rand_next(s); } s[0] = s0; s[1] = s1; + s[2] = s2; + s[3] = s3; } int random_get_pseudo_bytes(uint8_t *ptr, size_t len) { - uint64_t *xp, s[2]; + uint64_t *xp, s[4]; ASSERT(ptr); @@ -143,6 +163,8 @@ random_get_pseudo_bytes(uint8_t *ptr, size_t len) s[0] = xp[0]; s[1] = xp[1]; + s[2] = xp[2]; + s[3] = xp[3]; while (len) { union { @@ -154,12 +176,22 @@ random_get_pseudo_bytes(uint8_t *ptr, size_t len) len -= i; entropy.ui64 = spl_rand_next(s); + /* + * xoshiro256++ has low entropy lower bytes, so we copy the + * higher order bytes first. + */ while (i--) +#ifdef _ZFS_BIG_ENDIAN *ptr++ = entropy.byte[i]; +#else + *ptr++ = entropy.byte[7 - i]; +#endif } xp[0] = s[0]; xp[1] = s[1]; + xp[2] = s[2]; + xp[3] = s[3]; put_cpu_ptr(spl_pseudo_entropy); @@ -765,10 +797,10 @@ spl_kvmem_init(void) static int __init spl_random_init(void) { - uint64_t s[2]; + uint64_t s[4]; int i = 0; - spl_pseudo_entropy = __alloc_percpu(2 * sizeof (uint64_t), + spl_pseudo_entropy = __alloc_percpu(4 * sizeof (uint64_t), sizeof (uint64_t)); if (!spl_pseudo_entropy) @@ -776,17 +808,19 @@ spl_random_init(void) get_random_bytes(s, sizeof (s)); - if (s[0] == 0 && s[1] == 0) { + if (s[0] == 0 && s[1] == 0 && s[2] == 0 && s[3] == 0) { if (jiffies != 0) { s[0] = jiffies; s[1] = ~0 - jiffies; + s[2] = ~jiffies; + s[3] = jiffies - ~0; } else { - (void) memcpy(s, "improbable seed", sizeof (s)); + (void) memcpy(s, "improbable seed", 16); } printk("SPL: get_random_bytes() returned 0 " "when generating random seed. Setting initial seed to " - "0x%016llx%016llx.\n", cpu_to_be64(s[0]), - cpu_to_be64(s[1])); + "0x%016llx%016llx%016llx%016llx.\n", cpu_to_be64(s[0]), + cpu_to_be64(s[1]), cpu_to_be64(s[2]), cpu_to_be64(s[3])); } for_each_possible_cpu(i) { @@ -796,6 +830,8 @@ spl_random_init(void) wordp[0] = s[0]; wordp[1] = s[1]; + wordp[2] = s[2]; + wordp[3] = s[3]; } return (0); From ab32a14b2ed7531a76fd13a5278dd7d47d2ee923 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 20 Oct 2022 17:46:12 -0400 Subject: [PATCH 055/126] Silence new static analyzer defect reports from idmap_util.c 2a068a1394d179dda4becf350e3afb4e8819675e introduced 2 new defect reports from Coverity and 1 from Clang's static analyzer. Coverity complained about a potential resource leak from only calling `close(fd)` when `fd > 0` because `fd` might be `0`. This is a false positive, but rather than dismiss it as such, we can change the comparison to ensure that this never appears again from any static analyzer. Upon inspection, 6 more instances of this were found in the file, so those were changed too. Unfortunately, since the file descriptor has been put into an unsigned variable in `attr.userns_fd`, we cannot do a non-negative check on it to see if it has not been allocated, so we instead restructure the error handling to avoid the need for a check. This also means that errors had not been handled correctly here, so the static analyzer found a bug (although practically by accident). Coverity also complained about a dereference before a NULL check in `do_idmap_mount()` on `source`. Upon inspection, it appears that the pointer is never NULL, so we delete the NULL check as cleanup. Clang's static analyzer complained that the return value of `write_pid_idmaps()` can be uninitialized if we have no idmaps to write. Reviewed-by: Brian Behlendorf Reviewed-by: Youzhong Yang Signed-off-by: Richard Yao Closes #14061 --- tests/zfs-tests/cmd/idmap_util.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/zfs-tests/cmd/idmap_util.c b/tests/zfs-tests/cmd/idmap_util.c index 143cd4db67be..b6ca111ad227 100644 --- a/tests/zfs-tests/cmd/idmap_util.c +++ b/tests/zfs-tests/cmd/idmap_util.c @@ -316,7 +316,7 @@ write_idmap(pid_t pid, char *buf, size_t buf_size, idmap_type_t type) else ret = 0; out: - if (fd > 0) + if (fd >= 0) close(fd); return (ret); } @@ -339,7 +339,7 @@ write_pid_idmaps(pid_t pid, list_t *head) int size_buf_uids = 4096, size_buf_gids = 4096; struct idmap_entry *entry; int uid_filled, gid_filled; - int ret; + int ret = 0; int has_uids = 0, has_gids = 0; size_t buf_size; @@ -546,11 +546,11 @@ is_idmap_supported(char *path) if (ret) { errno = ret; log_errno("parse_idmap_entry(%s)", input); - goto out; + goto out1; } ret = userns_fd_from_idmap(&head); if (ret < 0) - goto out; + goto out1; attr.userns_fd = ret; ret = openat(-EBADF, path, O_DIRECTORY | O_CLOEXEC); if (ret < 0) { @@ -571,14 +571,14 @@ is_idmap_supported(char *path) log_errno("sys_mount_setattr"); } out: + close(attr.userns_fd); +out1: free_idmap(&head); list_destroy(&head); - if (tree_fd > 0) + if (tree_fd >= 0) close(tree_fd); - if (path_fd > 0) + if (path_fd >= 0) close(path_fd); - if (attr.userns_fd > 0) - close(attr.userns_fd); free(input); return (ret == 0); } @@ -639,7 +639,7 @@ do_idmap_mount(list_t *idmap, char *source, char *target, int flags) ret = userns_fd_from_idmap(idmap); if (ret < 0) - goto out; + goto out1; attr.userns_fd = ret; ret = openat(-EBADF, source, O_DIRECTORY | O_CLOEXEC); if (ret < 0) { @@ -663,7 +663,7 @@ do_idmap_mount(list_t *idmap, char *source, char *target, int flags) log_errno("sys_mount_setattr"); goto out; } - if (source != NULL && target == NULL && is_mountpoint(source)) { + if (target == NULL && is_mountpoint(source)) { ret = umount2(source, MNT_DETACH); if (ret < 0) { ret = -errno; @@ -679,12 +679,12 @@ do_idmap_mount(list_t *idmap, char *source, char *target, int flags) source : target); } out: - if (tree_fd > 0) + close(attr.userns_fd); +out1: + if (tree_fd >= 0) close(tree_fd); - if (source_fd > 0) + if (source_fd >= 0) close(source_fd); - if (attr.userns_fd > 0) - close(attr.userns_fd); return (ret); } From 72a366f0181e541d62c776dbefd12e01f7afd216 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 20 Oct 2022 17:52:35 -0400 Subject: [PATCH 056/126] Linux: Fix big endian and partial read bugs in get_system_hostid() Coverity made two complaints about this function. The first is that we ignore the number of bytes read. The second is that we have a sizeof mismatch. On 64-bit systems, long is a 64-bit type. Paradoxically, the standard says that hostid is 32-bit, yet is also a long type. On 64-bit big endian systems, reading into the long would cause us to return 0 as our hostid after the mask. This is wrong. Also, if a partial read were to happen (it should not), we would return a partial hostid, which is also wrong. We introduce a uint32_t system_hostid stack variable and ensure that the read is done into it and check the read's return value. Then we set the value based on whether the read was successful. This should fix both of coverity's complaints. Reviewed-by: Brian Behlendorf Reviewed-by: Neal Gompa Signed-off-by: Richard Yao Closes #13968 --- lib/libspl/os/linux/gethostid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/libspl/os/linux/gethostid.c b/lib/libspl/os/linux/gethostid.c index 4f0f73c89b5d..fcef8798c615 100644 --- a/lib/libspl/os/linux/gethostid.c +++ b/lib/libspl/os/linux/gethostid.c @@ -59,6 +59,7 @@ unsigned long get_system_hostid(void) { unsigned long hostid = get_spl_hostid(); + uint32_t system_hostid; /* * We do not use gethostid(3) because it can return a bogus ID, @@ -69,8 +70,11 @@ get_system_hostid(void) if (hostid == 0) { int fd = open("/etc/hostid", O_RDONLY | O_CLOEXEC); if (fd >= 0) { - if (read(fd, &hostid, 4) < 0) + if (read(fd, &system_hostid, sizeof (system_hostid)) + != sizeof (system_hostid)) hostid = 0; + else + hostid = system_hostid; (void) close(fd); } } From c5a388a1ef071b308ab0985fe831f94639fd4d7c Mon Sep 17 00:00:00 2001 From: youzhongyang Date: Fri, 21 Oct 2022 13:05:13 -0400 Subject: [PATCH 057/126] Add delay between zpool add zvol and zpool destroy As investigated by #14026, the zpool_add_004_pos can reliably hang if the timing is not right. This is caused by a race condition between zed doing zpool reopen (due to the zvol being added to the zpool), and the command zpool destroy. This change adds a delay between zpool add zvol and zpool destroy to avoid these issue, but does not address the underlying problem. Reviewed-by: Brian Behlendorf Signed-off-by: Youzhong Yang Issue #14026 Closes #14052 --- .../tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh index fbaed2af13c5..646edc1a4557 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh @@ -74,4 +74,8 @@ log_must zpool add $TESTPOOL $ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL log_must vdevs_in_pool "$TESTPOOL" "$ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL" +# Give zed a chance to finish processing the event, otherwise +# a race condition can lead to stuck "zpool destroy $TESTPOOL" +sleep 1 + log_pass "'zpool add ...' adds zfs volume to the pool successfully" From 0b2428da20c69bf32bbb9cbf561aa615fee64395 Mon Sep 17 00:00:00 2001 From: Ameer Hamza <106930537+ixhamza@users.noreply.github.com> Date: Fri, 21 Oct 2022 22:46:38 +0500 Subject: [PATCH 058/126] zed: Avoid core dump if wholedisk property does not exist zed aborts and dumps core in vdev_whole_disk_from_config() if wholedisk property does not exist. make_leaf_vdev() adds the property but there may be already pools that don't have the wholedisk in the label. Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Reviewed-by: Richard Yao Signed-off-by: Ameer Hamza Closes #14062 --- cmd/zed/agents/zfs_mod.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cmd/zed/agents/zfs_mod.c b/cmd/zed/agents/zfs_mod.c index 44abb4eb9a34..0271fffe42ef 100644 --- a/cmd/zed/agents/zfs_mod.c +++ b/cmd/zed/agents/zfs_mod.c @@ -948,14 +948,13 @@ vdev_whole_disk_from_config(zpool_handle_t *zhp, const char *vdev_path) { nvlist_t *nvl = NULL; boolean_t avail_spare, l2cache, log; - uint64_t wholedisk; + uint64_t wholedisk = 0; nvl = zpool_find_vdev(zhp, vdev_path, &avail_spare, &l2cache, &log); if (!nvl) return (0); - verify(nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_WHOLE_DISK, - &wholedisk) == 0); + (void) nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk); return (wholedisk); } @@ -994,7 +993,7 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data) if ((tgt = zpool_find_vdev_by_physpath(zhp, devname, &avail_spare, &l2cache, NULL)) != NULL) { char *path, fullpath[MAXPATHLEN]; - uint64_t wholedisk; + uint64_t wholedisk = 0; error = nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH, &path); if (error) { @@ -1002,10 +1001,8 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data) return (0); } - error = nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, + (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk); - if (error) - wholedisk = 0; if (wholedisk) { path = strrchr(path, '/'); From 871d66dbf2bee4e2aff9346330b3b5add7c44562 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Wed, 26 Oct 2022 14:55:12 -0700 Subject: [PATCH 059/126] Linux 6.0 compat: META Update the META file to reflect compatibility with the 6.0 kernel. Reviewed-by: George Melikov Signed-off-by: Brian Behlendorf Closes #14091 --- META | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/META b/META index 692497fcf1fc..0b4d784bb77c 100644 --- a/META +++ b/META @@ -6,5 +6,5 @@ Release: 1 Release-Tags: relext License: CDDL Author: OpenZFS -Linux-Maximum: 5.19 +Linux-Maximum: 6.0 Linux-Minimum: 3.10 From eeddd805728914c9bdbea394588f31ca22dcb657 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Wed, 26 Oct 2022 14:57:37 -0700 Subject: [PATCH 060/126] Silence objtool warnings from 55d7afa4 The use of __noreturn__ in 55d7afa4adbb4ca569e9c4477a7d121f4dc0bfbd on spl_panic() caused objtool warnings on Linux when the kernel is built with CONFIG_STACK_VALIDATION=y. This patch works around that by restricting the application of __noreturn__ to builds for static analyzers. Reviewed-by: Brian Behlendorf Reviewed-by: Ryan Moeller Signed-off-by: Richard Yao Closes #14068 --- include/os/freebsd/spl/sys/debug.h | 3 +++ include/os/linux/spl/sys/debug.h | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/os/freebsd/spl/sys/debug.h b/include/os/freebsd/spl/sys/debug.h index a5bd677b16d4..91e2cfe5539c 100644 --- a/include/os/freebsd/spl/sys/debug.h +++ b/include/os/freebsd/spl/sys/debug.h @@ -54,6 +54,9 @@ /* * Common DEBUG functionality. */ +#if defined(__COVERITY__) || defined(__clang_analyzer__) +__attribute__((__noreturn__)) +#endif extern void spl_panic(const char *file, const char *func, int line, const char *fmt, ...) __attribute__((__noreturn__)); extern void spl_dumpstack(void); diff --git a/include/os/linux/spl/sys/debug.h b/include/os/linux/spl/sys/debug.h index 8ad199808633..3c6f6d1b83bb 100644 --- a/include/os/linux/spl/sys/debug.h +++ b/include/os/linux/spl/sys/debug.h @@ -54,8 +54,21 @@ #define __maybe_unused __attribute__((unused)) #endif +/* + * Without this, we see warnings from objtool during normal Linux builds when + * the kernel is built with CONFIG_STACK_VALIDATION=y: + * + * warning: objtool: tsd_create() falls through to next function __list_add() + * warning: objtool: .text: unexpected end of section + * + * Until the toolchain stops doing this, we must only define this attribute on + * spl_panic() when doing static analysis. + */ +#if defined(__COVERITY__) || defined(__clang_analyzer__) +__attribute__((__noreturn__)) +#endif extern void spl_panic(const char *file, const char *func, int line, - const char *fmt, ...) __attribute__((__noreturn__)); + const char *fmt, ...); extern void spl_dumpstack(void); static inline int From 41133c97949af43daadee0503a9842a8dce8f0fd Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Thu, 27 Oct 2022 01:00:58 +0300 Subject: [PATCH 061/126] FreeBSD: vn_flush_cached_data: observe vnode locking contract vm_object_page_clean() expects that the associated vnode is locked as VOP_PUTPAGES() may get called on the vnode. Reviewed-by: Ryan Moeller Signed-off-by: Andriy Gapon Closes #14079 --- include/os/freebsd/spl/sys/vnode.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/os/freebsd/spl/sys/vnode.h b/include/os/freebsd/spl/sys/vnode.h index e0f79a1116b2..bbadf569c776 100644 --- a/include/os/freebsd/spl/sys/vnode.h +++ b/include/os/freebsd/spl/sys/vnode.h @@ -96,9 +96,11 @@ vn_flush_cached_data(vnode_t *vp, boolean_t sync) if (vp->v_object->flags & OBJ_MIGHTBEDIRTY) { #endif int flags = sync ? OBJPC_SYNC : 0; + vn_lock(vp, LK_SHARED | LK_RETRY); zfs_vmobject_wlock(vp->v_object); vm_object_page_clean(vp->v_object, 0, 0, flags); zfs_vmobject_wunlock(vp->v_object); + VOP_UNLOCK(vp); } } #endif From 07de86923bcb78352a4f4ffef02408f9a7dc794e Mon Sep 17 00:00:00 2001 From: Andrew Innes Date: Thu, 27 Oct 2022 06:08:31 +0800 Subject: [PATCH 062/126] Aligned free for aligned alloc Windows port frees memory that was alloc'd aligned in a different way then alloc'd memory. So changing frees to be specific. Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Andrew Innes Co-Authored-By: Jorgen Lundman Closes #14059 --- lib/libspl/include/umem.h | 20 +++++++++++++++++++- lib/libzutil/zutil_import.c | 18 +++++++++--------- module/os/linux/zfs/abd_os.c | 4 ++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/lib/libspl/include/umem.h b/lib/libspl/include/umem.h index 82976f756b73..77c216721253 100644 --- a/lib/libspl/include/umem.h +++ b/lib/libspl/include/umem.h @@ -137,6 +137,21 @@ umem_free(const void *ptr, size_t size __maybe_unused) free((void *)ptr); } +/* + * umem_free_aligned was added for supporting portability + * with non-POSIX platforms that require a different free + * to be used with aligned allocations. + */ +static inline void +umem_free_aligned(void *ptr, size_t size __maybe_unused) +{ +#ifndef _WIN32 + free((void *)ptr); +#else + _aligned_free(ptr); +#endif +} + static inline void umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused) {} @@ -196,7 +211,10 @@ umem_cache_free(umem_cache_t *cp, void *ptr) if (cp->cache_destructor) cp->cache_destructor(ptr, cp->cache_private); - umem_free(ptr, cp->cache_bufsize); + if (cp->cache_align != 0) + umem_free_aligned(ptr, cp->cache_bufsize); + else + umem_free(ptr, cp->cache_bufsize); } static inline void diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c index fee176184e5d..5d7b4a946c1e 100644 --- a/lib/libzutil/zutil_import.c +++ b/lib/libzutil/zutil_import.c @@ -934,7 +934,6 @@ zpool_read_label_slow(int fd, nvlist_t **config, int *num_labels) vdev_phys_t *label; nvlist_t *expected_config = NULL; uint64_t expected_guid = 0, size; - int error; *config = NULL; @@ -942,8 +941,9 @@ zpool_read_label_slow(int fd, nvlist_t **config, int *num_labels) return (0); size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); - error = posix_memalign((void **)&label, PAGESIZE, sizeof (*label)); - if (error) + label = (vdev_phys_t *)umem_alloc_aligned(sizeof (*label), PAGESIZE, + UMEM_DEFAULT); + if (label == NULL) return (-1); for (l = 0; l < VDEV_LABELS; l++) { @@ -992,7 +992,7 @@ zpool_read_label_slow(int fd, nvlist_t **config, int *num_labels) if (num_labels != NULL) *num_labels = count; - free(label); + umem_free_aligned(label, sizeof (*label)); *config = expected_config; return (0); @@ -1023,9 +1023,9 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels) return (0); size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t); - error = posix_memalign((void **)&labels, PAGESIZE, - VDEV_LABELS * sizeof (*labels)); - if (error) + labels = (vdev_phys_t *)umem_alloc_aligned( + VDEV_LABELS * sizeof (*labels), PAGESIZE, UMEM_DEFAULT); + if (labels == NULL) return (-1); memset(aiocbs, 0, sizeof (aiocbs)); @@ -1078,7 +1078,7 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels) error = zpool_read_label_slow(fd, config, num_labels); saved_errno = errno; } - free(labels); + umem_free_aligned(labels, VDEV_LABELS * sizeof (*labels)); errno = saved_errno; return (error); } @@ -1127,7 +1127,7 @@ zpool_read_label(int fd, nvlist_t **config, int *num_labels) if (num_labels != NULL) *num_labels = count; - free(labels); + umem_free_aligned(labels, VDEV_LABELS * sizeof (*labels)); *config = expected_config; return (0); diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c index e9b28becf6a0..16530d82693e 100644 --- a/module/os/linux/zfs/abd_os.c +++ b/module/os/linux/zfs/abd_os.c @@ -598,7 +598,7 @@ abd_free_chunks(abd_t *abd) abd_for_each_sg(abd, sg, n, i) { struct page *p = nth_page(sg_page(sg), 0); - umem_free(p, PAGESIZE); + umem_free_aligned(p, PAGESIZE); } abd_free_sg_table(abd); } @@ -704,7 +704,7 @@ abd_free_zero_scatter(void) __free_page(abd_zero_page); #endif /* HAVE_ZERO_PAGE_GPL_ONLY */ #else - umem_free(abd_zero_page, PAGESIZE); + umem_free_aligned(abd_zero_page, PAGESIZE); #endif /* _KERNEL */ } From c8ae0ca11a8c61f5e29e05d95feb823dbabb25e2 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 09:36:17 -0700 Subject: [PATCH 063/126] Add CodeQL workflow CodeQL is a static analyzer from github with a very low false positive rate. We have long wanted to have static analysis runs done on every pull request and using CodeQL, we can. Reviewed-by: Brian Behlendorf Reviewed-by: George Melikov Reviewed-by: Andrew Innes Signed-off-by: Richard Yao Closes #14087 --- .github/workflows/codeql.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000000..c8a49a7f00bc --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,36 @@ +name: "CodeQL" + +on: + push: + pull_request: + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp', 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" From 4938d01db7e12751e0cc3161d23dd549a0cee8ab Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 09:54:54 -0700 Subject: [PATCH 064/126] Convert enum zio_flag to uint64_t We ran out of space in enum zio_flag for additional flags. Rather than introduce enum zio_flag2 and then modify a bunch of functions to take a second flags variable, we expand the type to 64 bits via `typedef uint64_t zio_flag_t`. Reviewed-by: Allan Jude Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Signed-off-by: Allan Jude Co-authored-by: Richard Yao Closes #14086 --- include/os/linux/zfs/sys/trace_common.h | 4 +- include/sys/dbuf.h | 4 +- include/sys/zio.h | 102 ++++++++++++------------ module/os/linux/zfs/vdev_disk.c | 2 +- module/zfs/dmu.c | 2 +- module/zfs/dmu_objset.c | 2 +- module/zfs/dmu_recv.c | 4 +- module/zfs/dmu_send.c | 4 +- module/zfs/dmu_traverse.c | 2 +- module/zfs/vdev_queue.c | 2 +- module/zfs/zil.c | 4 +- module/zfs/zio.c | 39 ++++----- 12 files changed, 88 insertions(+), 83 deletions(-) diff --git a/include/os/linux/zfs/sys/trace_common.h b/include/os/linux/zfs/sys/trace_common.h index 74d77c1c4b21..a14727f15eed 100644 --- a/include/os/linux/zfs/sys/trace_common.h +++ b/include/os/linux/zfs/sys/trace_common.h @@ -39,10 +39,10 @@ __field(hrtime_t, zio_timestamp) \ __field(hrtime_t, zio_delta) \ __field(uint64_t, zio_delay) \ - __field(enum zio_flag, zio_flags) \ + __field(zio_flag_t, zio_flags) \ __field(enum zio_stage, zio_stage) \ __field(enum zio_stage, zio_pipeline) \ - __field(enum zio_flag, zio_orig_flags) \ + __field(zio_flag_t, zio_orig_flags) \ __field(enum zio_stage, zio_orig_stage) \ __field(enum zio_stage, zio_orig_pipeline) \ __field(uint8_t, zio_reexecute) \ diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h index 06489ea84bf8..9ba46f0d725f 100644 --- a/include/sys/dbuf.h +++ b/include/sys/dbuf.h @@ -190,7 +190,7 @@ typedef struct dbuf_dirty_record { uint64_t dr_blkid; abd_t *dr_abd; zio_prop_t dr_props; - enum zio_flag dr_flags; + zio_flag_t dr_flags; } dll; } dt; } dbuf_dirty_record_t; @@ -380,7 +380,7 @@ void dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data, int uncompressed_size, int compressed_size, int byteorder, dmu_tx_t *tx); int dmu_lightweight_write_by_dnode(dnode_t *dn, uint64_t offset, abd_t *abd, - const struct zio_prop *zp, enum zio_flag flags, dmu_tx_t *tx); + const struct zio_prop *zp, zio_flag_t flags, dmu_tx_t *tx); void dmu_buf_redact(dmu_buf_t *dbuf, dmu_tx_t *tx); void dbuf_destroy(dmu_buf_impl_t *db); diff --git a/include/sys/zio.h b/include/sys/zio.h index 23fdda457bc3..28ed837d829e 100644 --- a/include/sys/zio.h +++ b/include/sys/zio.h @@ -163,32 +163,37 @@ typedef enum zio_suspend_reason { ZIO_SUSPEND_MMP, } zio_suspend_reason_t; -enum zio_flag { +/* + * This was originally an enum type. However, those are 32-bit and there is no + * way to make a 64-bit enum type. Since we ran out of bits for flags, we were + * forced to upgrade it to a uint64_t. + */ +typedef uint64_t zio_flag_t; /* * Flags inherited by gang, ddt, and vdev children, * and that must be equal for two zios to aggregate */ - ZIO_FLAG_DONT_AGGREGATE = 1U << 0, - ZIO_FLAG_IO_REPAIR = 1U << 1, - ZIO_FLAG_SELF_HEAL = 1U << 2, - ZIO_FLAG_RESILVER = 1U << 3, - ZIO_FLAG_SCRUB = 1U << 4, - ZIO_FLAG_SCAN_THREAD = 1U << 5, - ZIO_FLAG_PHYSICAL = 1U << 6, +#define ZIO_FLAG_DONT_AGGREGATE (1ULL << 0) +#define ZIO_FLAG_IO_REPAIR (1ULL << 1) +#define ZIO_FLAG_SELF_HEAL (1ULL << 2) +#define ZIO_FLAG_RESILVER (1ULL << 3) +#define ZIO_FLAG_SCRUB (1ULL << 4) +#define ZIO_FLAG_SCAN_THREAD (1ULL << 5) +#define ZIO_FLAG_PHYSICAL (1ULL << 6) #define ZIO_FLAG_AGG_INHERIT (ZIO_FLAG_CANFAIL - 1) /* * Flags inherited by ddt, gang, and vdev children. */ - ZIO_FLAG_CANFAIL = 1U << 7, /* must be first for INHERIT */ - ZIO_FLAG_SPECULATIVE = 1U << 8, - ZIO_FLAG_CONFIG_WRITER = 1U << 9, - ZIO_FLAG_DONT_RETRY = 1U << 10, - ZIO_FLAG_DONT_CACHE = 1U << 11, - ZIO_FLAG_NODATA = 1U << 12, - ZIO_FLAG_INDUCE_DAMAGE = 1U << 13, - ZIO_FLAG_IO_ALLOCATING = 1U << 14, +#define ZIO_FLAG_CANFAIL (1ULL << 7) /* must be first for INHERIT */ +#define ZIO_FLAG_SPECULATIVE (1ULL << 8) +#define ZIO_FLAG_CONFIG_WRITER (1ULL << 9) +#define ZIO_FLAG_DONT_RETRY (1ULL << 10) +#define ZIO_FLAG_DONT_CACHE (1ULL << 11) +#define ZIO_FLAG_NODATA (1ULL << 12) +#define ZIO_FLAG_INDUCE_DAMAGE (1ULL << 13) +#define ZIO_FLAG_IO_ALLOCATING (1ULL << 14) #define ZIO_FLAG_DDT_INHERIT (ZIO_FLAG_IO_RETRY - 1) #define ZIO_FLAG_GANG_INHERIT (ZIO_FLAG_IO_RETRY - 1) @@ -196,30 +201,29 @@ enum zio_flag { /* * Flags inherited by vdev children. */ - ZIO_FLAG_IO_RETRY = 1U << 15, /* must be first for INHERIT */ - ZIO_FLAG_PROBE = 1U << 16, - ZIO_FLAG_TRYHARD = 1U << 17, - ZIO_FLAG_OPTIONAL = 1U << 18, +#define ZIO_FLAG_IO_RETRY (1ULL << 15) /* must be first for INHERIT */ +#define ZIO_FLAG_PROBE (1ULL << 16) +#define ZIO_FLAG_TRYHARD (1ULL << 17) +#define ZIO_FLAG_OPTIONAL (1ULL << 18) #define ZIO_FLAG_VDEV_INHERIT (ZIO_FLAG_DONT_QUEUE - 1) /* * Flags not inherited by any children. */ - ZIO_FLAG_DONT_QUEUE = 1U << 19, /* must be first for INHERIT */ - ZIO_FLAG_DONT_PROPAGATE = 1U << 20, - ZIO_FLAG_IO_BYPASS = 1U << 21, - ZIO_FLAG_IO_REWRITE = 1U << 22, - ZIO_FLAG_RAW_COMPRESS = 1U << 23, - ZIO_FLAG_RAW_ENCRYPT = 1U << 24, - ZIO_FLAG_GANG_CHILD = 1U << 25, - ZIO_FLAG_DDT_CHILD = 1U << 26, - ZIO_FLAG_GODFATHER = 1U << 27, - ZIO_FLAG_NOPWRITE = 1U << 28, - ZIO_FLAG_REEXECUTED = 1U << 29, - ZIO_FLAG_DELEGATED = 1U << 30, - ZIO_FLAG_FASTWRITE = 1U << 31, -}; +#define ZIO_FLAG_DONT_QUEUE (1ULL << 19) /* must be first for INHERIT */ +#define ZIO_FLAG_DONT_PROPAGATE (1ULL << 20) +#define ZIO_FLAG_IO_BYPASS (1ULL << 21) +#define ZIO_FLAG_IO_REWRITE (1ULL << 22) +#define ZIO_FLAG_RAW_COMPRESS (1ULL << 23) +#define ZIO_FLAG_RAW_ENCRYPT (1ULL << 24) +#define ZIO_FLAG_GANG_CHILD (1ULL << 25) +#define ZIO_FLAG_DDT_CHILD (1ULL << 26) +#define ZIO_FLAG_GODFATHER (1ULL << 27) +#define ZIO_FLAG_NOPWRITE (1ULL << 28) +#define ZIO_FLAG_REEXECUTED (1ULL << 29) +#define ZIO_FLAG_DELEGATED (1ULL << 30) +#define ZIO_FLAG_FASTWRITE (1ULL << 31) #define ZIO_FLAG_MUSTSUCCEED 0 #define ZIO_FLAG_RAW (ZIO_FLAG_RAW_COMPRESS | ZIO_FLAG_RAW_ENCRYPT) @@ -489,10 +493,10 @@ struct zio { zio_alloc_list_t io_alloc_list; /* Internal pipeline state */ - enum zio_flag io_flags; + zio_flag_t io_flags; enum zio_stage io_stage; enum zio_stage io_pipeline; - enum zio_flag io_orig_flags; + zio_flag_t io_orig_flags; enum zio_stage io_orig_stage; enum zio_stage io_orig_pipeline; enum zio_stage io_pipeline_trace; @@ -529,27 +533,27 @@ enum blk_verify_flag { extern int zio_bookmark_compare(const void *, const void *); extern zio_t *zio_null(zio_t *pio, spa_t *spa, vdev_t *vd, - zio_done_func_t *done, void *priv, enum zio_flag flags); + zio_done_func_t *done, void *priv, zio_flag_t flags); extern zio_t *zio_root(spa_t *spa, - zio_done_func_t *done, void *priv, enum zio_flag flags); + zio_done_func_t *done, void *priv, zio_flag_t flags); extern void zio_destroy(zio_t *zio); extern zio_t *zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, struct abd *data, uint64_t lsize, zio_done_func_t *done, void *priv, - zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb); + zio_priority_t priority, zio_flag_t flags, const zbookmark_phys_t *zb); extern zio_t *zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp, struct abd *data, uint64_t size, uint64_t psize, const zio_prop_t *zp, zio_done_func_t *ready, zio_done_func_t *children_ready, zio_done_func_t *physdone, zio_done_func_t *done, - void *priv, zio_priority_t priority, enum zio_flag flags, + void *priv, zio_priority_t priority, zio_flag_t flags, const zbookmark_phys_t *zb); extern zio_t *zio_rewrite(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp, struct abd *data, uint64_t size, zio_done_func_t *done, void *priv, - zio_priority_t priority, enum zio_flag flags, zbookmark_phys_t *zb); + zio_priority_t priority, zio_flag_t flags, zbookmark_phys_t *zb); extern void zio_write_override(zio_t *zio, blkptr_t *bp, int copies, boolean_t nopwrite); @@ -558,27 +562,27 @@ extern void zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp); extern zio_t *zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, - zio_done_func_t *done, void *priv, enum zio_flag flags); + zio_done_func_t *done, void *priv, zio_flag_t flags); extern zio_t *zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd, - zio_done_func_t *done, void *priv, enum zio_flag flags); + zio_done_func_t *done, void *priv, zio_flag_t flags); extern zio_t *zio_trim(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, zio_done_func_t *done, void *priv, zio_priority_t priority, - enum zio_flag flags, enum trim_flag trim_flags); + zio_flag_t flags, enum trim_flag trim_flags); extern zio_t *zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, struct abd *data, int checksum, zio_done_func_t *done, void *priv, zio_priority_t priority, - enum zio_flag flags, boolean_t labels); + zio_flag_t flags, boolean_t labels); extern zio_t *zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, struct abd *data, int checksum, zio_done_func_t *done, void *priv, zio_priority_t priority, - enum zio_flag flags, boolean_t labels); + zio_flag_t flags, boolean_t labels); extern zio_t *zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, - const blkptr_t *bp, enum zio_flag flags); + const blkptr_t *bp, zio_flag_t flags); extern int zio_alloc_zil(spa_t *spa, objset_t *os, uint64_t txg, blkptr_t *new_bp, uint64_t size, boolean_t *slog); @@ -611,12 +615,12 @@ extern void zio_resubmit_stage_async(void *); extern zio_t *zio_vdev_child_io(zio_t *zio, blkptr_t *bp, vdev_t *vd, uint64_t offset, struct abd *data, uint64_t size, int type, - zio_priority_t priority, enum zio_flag flags, + zio_priority_t priority, zio_flag_t flags, zio_done_func_t *done, void *priv); extern zio_t *zio_vdev_delegated_io(vdev_t *vd, uint64_t offset, struct abd *data, uint64_t size, zio_type_t type, zio_priority_t priority, - enum zio_flag flags, zio_done_func_t *done, void *priv); + zio_flag_t flags, zio_done_func_t *done, void *priv); extern void zio_vdev_io_bypass(zio_t *zio); extern void zio_vdev_io_reissue(zio_t *zio); diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c index 349ef392dc0a..11ed3ea6f4e0 100644 --- a/module/os/linux/zfs/vdev_disk.c +++ b/module/os/linux/zfs/vdev_disk.c @@ -173,7 +173,7 @@ vdev_disk_error(zio_t *zio) * which is safe from any context. */ printk(KERN_WARNING "zio pool=%s vdev=%s error=%d type=%d " - "offset=%llu size=%llu flags=%x\n", spa_name(zio->io_spa), + "offset=%llu size=%llu flags=%llu\n", spa_name(zio->io_spa), zio->io_vd->vdev_path, zio->io_error, zio->io_type, (u_longlong_t)zio->io_offset, (u_longlong_t)zio->io_size, zio->io_flags); diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 4f5dbfdde015..45304e7ddf7a 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -1436,7 +1436,7 @@ dmu_return_arcbuf(arc_buf_t *buf) */ int dmu_lightweight_write_by_dnode(dnode_t *dn, uint64_t offset, abd_t *abd, - const zio_prop_t *zp, enum zio_flag flags, dmu_tx_t *tx) + const zio_prop_t *zp, zio_flag_t flags, dmu_tx_t *tx) { dbuf_dirty_record_t *dr = dbuf_dirty_lightweight(dn, dbuf_whichblock(dn, 0, offset), tx); diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c index b8fcbdf487d0..c17c829a04d8 100644 --- a/module/zfs/dmu_objset.c +++ b/module/zfs/dmu_objset.c @@ -482,7 +482,7 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, arc_flags_t aflags = ARC_FLAG_WAIT; zbookmark_phys_t zb; int size; - enum zio_flag zio_flags = ZIO_FLAG_CANFAIL; + zio_flag_t zio_flags = ZIO_FLAG_CANFAIL; SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET, ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID); diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c index a9e4a6745905..9f43ffe1e856 100644 --- a/module/zfs/dmu_recv.c +++ b/module/zfs/dmu_recv.c @@ -1344,7 +1344,7 @@ do_corrective_recv(struct receive_writer_arg *rwa, struct drr_write *drrw, dnode_t *dn; abd_t *abd = rrd->abd; zio_cksum_t bp_cksum = bp->blk_cksum; - enum zio_flag flags = ZIO_FLAG_SPECULATIVE | + zio_flag_t flags = ZIO_FLAG_SPECULATIVE | ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_RETRY | ZIO_FLAG_CANFAIL; if (rwa->raw) @@ -2186,7 +2186,7 @@ flush_write_batch_impl(struct receive_writer_arg *rwa) zio_prop_t zp; dmu_write_policy(rwa->os, dn, 0, 0, &zp); - enum zio_flag zio_flags = 0; + zio_flag_t zio_flags = 0; if (rwa->raw) { zp.zp_encrypt = B_TRUE; diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 6e0057bb9ea8..8c96a862762f 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -934,7 +934,7 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range) ASSERT3U(range->start_blkid + 1, ==, range->end_blkid); if (BP_GET_TYPE(bp) == DMU_OT_SA) { arc_flags_t aflags = ARC_FLAG_WAIT; - enum zio_flag zioflags = ZIO_FLAG_CANFAIL; + zio_flag_t zioflags = ZIO_FLAG_CANFAIL; if (dscp->dsc_featureflags & DMU_BACKUP_FEATURE_RAW) { ASSERT(BP_IS_PROTECTED(bp)); @@ -1653,7 +1653,7 @@ issue_data_read(struct send_reader_thread_arg *srta, struct send_range *range) !split_large_blocks && !BP_SHOULD_BYTESWAP(bp) && !BP_IS_EMBEDDED(bp) && !DMU_OT_IS_METADATA(BP_GET_TYPE(bp)); - enum zio_flag zioflags = ZIO_FLAG_CANFAIL; + zio_flag_t zioflags = ZIO_FLAG_CANFAIL; if (srta->featureflags & DMU_BACKUP_FEATURE_RAW) { zioflags |= ZIO_FLAG_RAW; diff --git a/module/zfs/dmu_traverse.c b/module/zfs/dmu_traverse.c index d712133cd789..377634c72bba 100644 --- a/module/zfs/dmu_traverse.c +++ b/module/zfs/dmu_traverse.c @@ -671,7 +671,7 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp, /* See comment on ZIL traversal in dsl_scan_visitds. */ if (ds != NULL && !ds->ds_is_snapshot && !BP_IS_HOLE(rootbp)) { - enum zio_flag zio_flags = ZIO_FLAG_CANFAIL; + zio_flag_t zio_flags = ZIO_FLAG_CANFAIL; uint32_t flags = ARC_FLAG_WAIT; objset_phys_t *osp; arc_buf_t *buf; diff --git a/module/zfs/vdev_queue.c b/module/zfs/vdev_queue.c index d3777897e5b0..ec55674393ce 100644 --- a/module/zfs/vdev_queue.c +++ b/module/zfs/vdev_queue.c @@ -605,7 +605,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio) int maxblocksize; boolean_t stretch = B_FALSE; avl_tree_t *t = vdev_queue_type_tree(vq, zio->io_type); - enum zio_flag flags = zio->io_flags & ZIO_FLAG_AGG_INHERIT; + zio_flag_t flags = zio->io_flags & ZIO_FLAG_AGG_INHERIT; uint64_t next_offset; abd_t *abd; diff --git a/module/zfs/zil.c b/module/zfs/zil.c index f26cc52613ea..6bb99c4b1cdf 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -237,7 +237,7 @@ static int zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp, blkptr_t *nbp, void *dst, char **end) { - enum zio_flag zio_flags = ZIO_FLAG_CANFAIL; + zio_flag_t zio_flags = ZIO_FLAG_CANFAIL; arc_flags_t aflags = ARC_FLAG_WAIT; arc_buf_t *abuf = NULL; zbookmark_phys_t zb; @@ -315,7 +315,7 @@ zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp, static int zil_read_log_data(zilog_t *zilog, const lr_write_t *lr, void *wbuf) { - enum zio_flag zio_flags = ZIO_FLAG_CANFAIL; + zio_flag_t zio_flags = ZIO_FLAG_CANFAIL; const blkptr_t *bp = &lr->lr_blkptr; arc_flags_t aflags = ARC_FLAG_WAIT; arc_buf_t *abuf = NULL; diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 3f6847a236ef..928e28813931 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -512,8 +512,9 @@ zio_decrypt(zio_t *zio, abd_t *data, uint64_t size) /* * If this is an authenticated block, just check the MAC. It would be - * nice to separate this out into its own flag, but for the moment - * enum zio_flag is out of bits. + * nice to separate this out into its own flag, but when this was done, + * we had run out of bits in what is now zio_flag_t. Future cleanup + * could make this a flag bit. */ if (BP_IS_AUTHENTICATED(bp)) { if (ot == DMU_OT_OBJSET) { @@ -802,7 +803,7 @@ static zio_t * zio_create(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, abd_t *data, uint64_t lsize, uint64_t psize, zio_done_func_t *done, void *private, zio_type_t type, zio_priority_t priority, - enum zio_flag flags, vdev_t *vd, uint64_t offset, + zio_flag_t flags, vdev_t *vd, uint64_t offset, const zbookmark_phys_t *zb, enum zio_stage stage, enum zio_stage pipeline) { @@ -901,7 +902,7 @@ zio_destroy(zio_t *zio) zio_t * zio_null(zio_t *pio, spa_t *spa, vdev_t *vd, zio_done_func_t *done, - void *private, enum zio_flag flags) + void *private, zio_flag_t flags) { zio_t *zio; @@ -913,7 +914,7 @@ zio_null(zio_t *pio, spa_t *spa, vdev_t *vd, zio_done_func_t *done, } zio_t * -zio_root(spa_t *spa, zio_done_func_t *done, void *private, enum zio_flag flags) +zio_root(spa_t *spa, zio_done_func_t *done, void *private, zio_flag_t flags) { return (zio_null(NULL, spa, NULL, done, private, flags)); } @@ -1099,7 +1100,7 @@ zfs_dva_valid(spa_t *spa, const dva_t *dva, const blkptr_t *bp) zio_t * zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, abd_t *data, uint64_t size, zio_done_func_t *done, void *private, - zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb) + zio_priority_t priority, zio_flag_t flags, const zbookmark_phys_t *zb) { zio_t *zio; @@ -1117,7 +1118,7 @@ zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp, abd_t *data, uint64_t lsize, uint64_t psize, const zio_prop_t *zp, zio_done_func_t *ready, zio_done_func_t *children_ready, zio_done_func_t *physdone, zio_done_func_t *done, - void *private, zio_priority_t priority, enum zio_flag flags, + void *private, zio_priority_t priority, zio_flag_t flags, const zbookmark_phys_t *zb) { zio_t *zio; @@ -1160,7 +1161,7 @@ zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp, zio_t * zio_rewrite(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp, abd_t *data, uint64_t size, zio_done_func_t *done, void *private, - zio_priority_t priority, enum zio_flag flags, zbookmark_phys_t *zb) + zio_priority_t priority, zio_flag_t flags, zbookmark_phys_t *zb) { zio_t *zio; @@ -1233,7 +1234,7 @@ zio_free(spa_t *spa, uint64_t txg, const blkptr_t *bp) */ zio_t * zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, - enum zio_flag flags) + zio_flag_t flags) { ASSERT(!BP_IS_HOLE(bp)); ASSERT(spa_syncing_txg(spa) == txg); @@ -1266,7 +1267,7 @@ zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, zio_t * zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, - zio_done_func_t *done, void *private, enum zio_flag flags) + zio_done_func_t *done, void *private, zio_flag_t flags) { zio_t *zio; @@ -1303,7 +1304,7 @@ zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp, zio_t * zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd, - zio_done_func_t *done, void *private, enum zio_flag flags) + zio_done_func_t *done, void *private, zio_flag_t flags) { zio_t *zio; int c; @@ -1328,7 +1329,7 @@ zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd, zio_t * zio_trim(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, zio_done_func_t *done, void *private, zio_priority_t priority, - enum zio_flag flags, enum trim_flag trim_flags) + zio_flag_t flags, enum trim_flag trim_flags) { zio_t *zio; @@ -1348,7 +1349,7 @@ zio_trim(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, zio_t * zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, abd_t *data, int checksum, zio_done_func_t *done, void *private, - zio_priority_t priority, enum zio_flag flags, boolean_t labels) + zio_priority_t priority, zio_flag_t flags, boolean_t labels) { zio_t *zio; @@ -1369,7 +1370,7 @@ zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, zio_t * zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, abd_t *data, int checksum, zio_done_func_t *done, void *private, - zio_priority_t priority, enum zio_flag flags, boolean_t labels) + zio_priority_t priority, zio_flag_t flags, boolean_t labels) { zio_t *zio; @@ -1406,7 +1407,7 @@ zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size, zio_t * zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset, abd_t *data, uint64_t size, int type, zio_priority_t priority, - enum zio_flag flags, zio_done_func_t *done, void *private) + zio_flag_t flags, zio_done_func_t *done, void *private) { enum zio_stage pipeline = ZIO_VDEV_CHILD_PIPELINE; zio_t *zio; @@ -1480,7 +1481,7 @@ zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset, zio_t * zio_vdev_delegated_io(vdev_t *vd, uint64_t offset, abd_t *data, uint64_t size, - zio_type_t type, zio_priority_t priority, enum zio_flag flags, + zio_type_t type, zio_priority_t priority, zio_flag_t flags, zio_done_func_t *done, void *private) { zio_t *zio; @@ -2030,7 +2031,7 @@ zio_deadman_impl(zio_t *pio, int ziodepth) "delta=%llu queued=%llu io=%llu " "path=%s " "last=%llu type=%d " - "priority=%d flags=0x%x stage=0x%x " + "priority=%d flags=0x%llx stage=0x%x " "pipeline=0x%x pipeline-trace=0x%x " "objset=%llu object=%llu " "level=%llu blkid=%llu " @@ -2040,8 +2041,8 @@ zio_deadman_impl(zio_t *pio, int ziodepth) (u_longlong_t)delta, pio->io_delta, pio->io_delay, vd ? vd->vdev_path : "NULL", vq ? vq->vq_io_complete_ts : 0, pio->io_type, - pio->io_priority, pio->io_flags, pio->io_stage, - pio->io_pipeline, pio->io_pipeline_trace, + pio->io_priority, (u_longlong_t)pio->io_flags, + pio->io_stage, pio->io_pipeline, pio->io_pipeline_trace, (u_longlong_t)zb->zb_objset, (u_longlong_t)zb->zb_object, (u_longlong_t)zb->zb_level, (u_longlong_t)zb->zb_blkid, (u_longlong_t)pio->io_offset, (u_longlong_t)pio->io_size, From 4d631a509d067c2695a396983cb12f58d92d4e04 Mon Sep 17 00:00:00 2001 From: Umer Saleem Date: Fri, 28 Oct 2022 03:38:45 +0500 Subject: [PATCH 065/126] Add native Debian Packaging for Linux Currently, the Debian packages are generated from ALIEN that converts RPMs to Debian packages. This commit adds native Debian packaging for Debian based systems. This packaging is a fork of Debian zfs-linux 2.1.6-2 release. (source: https://salsa.debian.org/zfsonlinux-team/zfs) Some updates have been made to keep the footprint minimal that include removing the tests, translation files, patches directory etc. All credits go to Debian ZFS on Linux Packaging Team. For copyright information, please refer to contrib/debian/copyright. scripts/debian-packaging.sh can be used to invoke the build. Reviewed-by: Mo Zhou Reviewed-by: Ryan Moeller Signed-off-by: Umer Saleem Closes #13451 --- contrib/debian/changelog | 7 + contrib/debian/clean | 11 + contrib/debian/control | 328 ++++++++++++++++++ contrib/debian/control.modules.in | 33 ++ contrib/debian/copyright | 19 + contrib/debian/not-installed | 13 + contrib/debian/openzfs-libnvpair3.docs | 2 + contrib/debian/openzfs-libnvpair3.install.in | 1 + contrib/debian/openzfs-libpam-zfs.install | 2 + contrib/debian/openzfs-libpam-zfs.postinst | 6 + contrib/debian/openzfs-libpam-zfs.prerm | 8 + contrib/debian/openzfs-libuutil3.docs | 2 + contrib/debian/openzfs-libuutil3.install.in | 1 + contrib/debian/openzfs-libzfs-dev.docs | 2 + contrib/debian/openzfs-libzfs-dev.install.in | 3 + contrib/debian/openzfs-libzfs4.docs | 2 + contrib/debian/openzfs-libzfs4.install.in | 2 + contrib/debian/openzfs-libzfsbootenv1.docs | 2 + .../debian/openzfs-libzfsbootenv1.install.in | 1 + contrib/debian/openzfs-libzpool5.docs | 2 + contrib/debian/openzfs-libzpool5.install.in | 1 + contrib/debian/openzfs-python3-pyzfs.install | 1 + contrib/debian/openzfs-zfs-dkms.config | 31 ++ contrib/debian/openzfs-zfs-dkms.dkms | 1 + contrib/debian/openzfs-zfs-dkms.docs | 2 + contrib/debian/openzfs-zfs-dkms.install | 1 + contrib/debian/openzfs-zfs-dkms.postinst | 51 +++ contrib/debian/openzfs-zfs-dkms.prerm | 8 + contrib/debian/openzfs-zfs-dkms.templates | 40 +++ contrib/debian/openzfs-zfs-dkms.triggers | 1 + contrib/debian/openzfs-zfs-dracut.install | 2 + contrib/debian/openzfs-zfs-initramfs.install | 2 + .../openzfs-zfs-modules-_KVERS_-di.install.in | 2 + .../openzfs-zfs-modules-_KVERS_.install.in | 2 + .../openzfs-zfs-modules-_KVERS_.postinst.in | 16 + .../openzfs-zfs-modules-_KVERS_.postrm.in | 7 + contrib/debian/openzfs-zfs-test.install | 15 + contrib/debian/openzfs-zfs-zed.install | 5 + contrib/debian/openzfs-zfs-zed.postinst | 20 ++ contrib/debian/openzfs-zfs-zed.postrm | 17 + contrib/debian/openzfs-zfs-zed.prerm | 16 + contrib/debian/openzfs-zfs-zed.zfs-zed.init | 1 + contrib/debian/openzfs-zfsutils.docs | 2 + contrib/debian/openzfs-zfsutils.examples | 5 + contrib/debian/openzfs-zfsutils.install | 135 +++++++ contrib/debian/openzfs-zfsutils.postinst | 28 ++ .../debian/openzfs-zfsutils.zfs-import.init | 1 + .../debian/openzfs-zfsutils.zfs-load-key.init | 1 + .../debian/openzfs-zfsutils.zfs-mount.init | 1 + .../debian/openzfs-zfsutils.zfs-share.init | 1 + contrib/debian/rules | 223 ++++++++++++ contrib/debian/source/format | 1 + .../usr/share/initramfs-tools/conf.d/zfs | 8 + .../usr/share/initramfs-tools/hooks/zdev | 67 ++++ scripts/debian-packaging.sh | 36 ++ 55 files changed, 1198 insertions(+) create mode 100644 contrib/debian/changelog create mode 100644 contrib/debian/clean create mode 100644 contrib/debian/control create mode 100644 contrib/debian/control.modules.in create mode 100644 contrib/debian/copyright create mode 100644 contrib/debian/not-installed create mode 100644 contrib/debian/openzfs-libnvpair3.docs create mode 100644 contrib/debian/openzfs-libnvpair3.install.in create mode 100644 contrib/debian/openzfs-libpam-zfs.install create mode 100644 contrib/debian/openzfs-libpam-zfs.postinst create mode 100644 contrib/debian/openzfs-libpam-zfs.prerm create mode 100644 contrib/debian/openzfs-libuutil3.docs create mode 100644 contrib/debian/openzfs-libuutil3.install.in create mode 100644 contrib/debian/openzfs-libzfs-dev.docs create mode 100644 contrib/debian/openzfs-libzfs-dev.install.in create mode 100644 contrib/debian/openzfs-libzfs4.docs create mode 100644 contrib/debian/openzfs-libzfs4.install.in create mode 100644 contrib/debian/openzfs-libzfsbootenv1.docs create mode 100644 contrib/debian/openzfs-libzfsbootenv1.install.in create mode 100644 contrib/debian/openzfs-libzpool5.docs create mode 100644 contrib/debian/openzfs-libzpool5.install.in create mode 100644 contrib/debian/openzfs-python3-pyzfs.install create mode 100644 contrib/debian/openzfs-zfs-dkms.config create mode 100644 contrib/debian/openzfs-zfs-dkms.dkms create mode 100644 contrib/debian/openzfs-zfs-dkms.docs create mode 100644 contrib/debian/openzfs-zfs-dkms.install create mode 100644 contrib/debian/openzfs-zfs-dkms.postinst create mode 100644 contrib/debian/openzfs-zfs-dkms.prerm create mode 100644 contrib/debian/openzfs-zfs-dkms.templates create mode 100644 contrib/debian/openzfs-zfs-dkms.triggers create mode 100644 contrib/debian/openzfs-zfs-dracut.install create mode 100644 contrib/debian/openzfs-zfs-initramfs.install create mode 100644 contrib/debian/openzfs-zfs-modules-_KVERS_-di.install.in create mode 100644 contrib/debian/openzfs-zfs-modules-_KVERS_.install.in create mode 100644 contrib/debian/openzfs-zfs-modules-_KVERS_.postinst.in create mode 100644 contrib/debian/openzfs-zfs-modules-_KVERS_.postrm.in create mode 100644 contrib/debian/openzfs-zfs-test.install create mode 100644 contrib/debian/openzfs-zfs-zed.install create mode 100644 contrib/debian/openzfs-zfs-zed.postinst create mode 100644 contrib/debian/openzfs-zfs-zed.postrm create mode 100644 contrib/debian/openzfs-zfs-zed.prerm create mode 120000 contrib/debian/openzfs-zfs-zed.zfs-zed.init create mode 100644 contrib/debian/openzfs-zfsutils.docs create mode 100644 contrib/debian/openzfs-zfsutils.examples create mode 100644 contrib/debian/openzfs-zfsutils.install create mode 100644 contrib/debian/openzfs-zfsutils.postinst create mode 120000 contrib/debian/openzfs-zfsutils.zfs-import.init create mode 120000 contrib/debian/openzfs-zfsutils.zfs-load-key.init create mode 120000 contrib/debian/openzfs-zfsutils.zfs-mount.init create mode 120000 contrib/debian/openzfs-zfsutils.zfs-share.init create mode 100755 contrib/debian/rules create mode 100644 contrib/debian/source/format create mode 100644 contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/conf.d/zfs create mode 100755 contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/hooks/zdev create mode 100755 scripts/debian-packaging.sh diff --git a/contrib/debian/changelog b/contrib/debian/changelog new file mode 100644 index 000000000000..6273d603834a --- /dev/null +++ b/contrib/debian/changelog @@ -0,0 +1,7 @@ +openzfs-linux (2.1.99-1) unstable; urgency=low + + * Integrate minimally modified Debian packaging from ZFS on Linux + (source: https://salsa.debian.org/zfsonlinux-team/zfs) + * This packaging is a fork of Debian zfs-linux 2.1.6-2 release. + + -- Umer Saleem Fri, 11 Oct 2022 15:00:00 -0400 diff --git a/contrib/debian/clean b/contrib/debian/clean new file mode 100644 index 000000000000..3100d693aeba --- /dev/null +++ b/contrib/debian/clean @@ -0,0 +1,11 @@ +bin/ +cmd/zed/zed.d/history_event-zfs-list-cacher.sh +contrib/pyzfs/build/ +contrib/pyzfs/libzfs_core/__pycache__/ +contrib/pyzfs/libzfs_core/bindings/__pycache__/ +contrib/pyzfs/pyzfs.egg-info/ +debian/openzfs-libnvpair3.install +debian/openzfs-libuutil3.install +debian/openzfs-libzfs4.install +debian/openzfs-libzfs-dev.install +debian/openzfs-libzpool5.install diff --git a/contrib/debian/control b/contrib/debian/control new file mode 100644 index 000000000000..a0db4985ed1a --- /dev/null +++ b/contrib/debian/control @@ -0,0 +1,328 @@ +Source: openzfs-linux +Section: contrib/kernel +Priority: optional +Maintainer: ZFS on Linux specific mailing list +Build-Depends: abigail-tools, + debhelper-compat (= 12), + dh-python, + dkms (>> 2.1.1.2-5), + libaio-dev, + libblkid-dev, + libcurl4-openssl-dev, + libelf-dev, + libpam0g-dev, + libssl-dev | libssl1.0-dev, + libtool, + libudev-dev, + lsb-release, + po-debconf, + python3-all-dev, + python3-cffi, + python3-setuptools, + python3-sphinx, + uuid-dev, + zlib1g-dev +Standards-Version: 4.5.1 +Homepage: https://openzfs.org/ +Vcs-Git: https://github.com/openzfs/zfs.git +Vcs-Browser: https://github.com/openzfs/zfs +Rules-Requires-Root: no +XS-Autobuild: yes + +Package: openzfs-libnvpair3 +Section: contrib/libs +Architecture: linux-any +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: libnvpair1, libnvpair3 +Replaces: libnvpair1, libnvpair3, libnvpair3linux +Conflicts: libnvpair3linux +Description: Solaris name-value library for Linux + This library provides routines for packing and unpacking nv pairs for + transporting data across process boundaries, transporting between + kernel and userland, and possibly saving onto disk files. + +Package: openzfs-libpam-zfs +Section: contrib/admin +Architecture: linux-any +Depends: libpam-runtime, ${misc:Depends}, ${shlibs:Depends} +Replaces: libpam-zfs +Conflicts: libpam-zfs +Description: PAM module for managing encryption keys for ZFS + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This provides a Pluggable Authentication Module (PAM) that automatically + unlocks encrypted ZFS datasets upon login. + +Package: openzfs-libuutil3 +Section: contrib/libs +Architecture: linux-any +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: libuutil1, libuutil3 +Replaces: libuutil1, libuutil3, libuutil3linux +Conflicts: libuutil3linux +Description: Solaris userland utility library for Linux + This library provides a variety of glue functions for ZFS on Linux: + * libspl: The Solaris Porting Layer userland library, which provides APIs + that make it possible to run Solaris user code in a Linux environment + with relatively minimal modification. + * libavl: The Adelson-Velskii Landis balanced binary tree manipulation + library. + * libefi: The Extensible Firmware Interface library for GUID disk + partitioning. + * libshare: NFS, SMB, and iSCSI service integration for ZFS. + +Package: openzfs-libzfs-dev +Section: contrib/libdevel +Architecture: linux-any +Depends: libssl-dev | libssl1.0-dev, + openzfs-libnvpair3 (= ${binary:Version}), + openzfs-libuutil3 (= ${binary:Version}), + openzfs-libzfs4 (= ${binary:Version}), + openzfs-libzfsbootenv1 (= ${binary:Version}), + openzfs-libzpool5 (= ${binary:Version}), + ${misc:Depends} +Replaces: libzfslinux-dev +Conflicts: libzfslinux-dev +Provides: libnvpair-dev, libuutil-dev +Description: OpenZFS filesystem development files for Linux + Header files and static libraries for compiling software against + libraries of OpenZFS filesystem. + . + This package includes the development files of libnvpair3, libuutil3, + libzpool5 and libzfs4. + +Package: openzfs-libzfs4 +Section: contrib/libs +Architecture: linux-any +Depends: ${misc:Depends}, ${shlibs:Depends} +# The libcurl4 is loaded through dlopen("libcurl.so.4"). +# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=988521 +Recommends: libcurl4 +Breaks: libzfs2, libzfs4 +Replaces: libzfs2, libzfs4, libzfs4linux +Conflicts: libzfs4linux +Description: OpenZFS filesystem library for Linux - general support + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + The OpenZFS library provides support for managing OpenZFS filesystems. + +Package: openzfs-libzfsbootenv1 +Section: contrib/libs +Architecture: linux-any +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: libzfs2, libzfs4 +Replaces: libzfs2, libzfs4, libzfsbootenv1linux +Conflicts: libzfsbootenv1linux +Description: OpenZFS filesystem library for Linux - label info support + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + The zfsbootenv library provides support for modifying ZFS label information. + +Package: openzfs-libzpool5 +Section: contrib/libs +Architecture: linux-any +Depends: ${misc:Depends}, ${shlibs:Depends} +Breaks: libzpool2, libzpool5 +Replaces: libzpool2, libzpool5, libzpool5linux +Conflicts: libzpool5linux +Description: OpenZFS pool library for Linux + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This zpool library provides support for managing zpools. + +Package: openzfs-python3-pyzfs +Section: contrib/python +Architecture: linux-any +Depends: python3-cffi, + openzfs-zfsutils (= ${binary:Version}), + ${misc:Depends}, + ${python3:Depends} +Replaces: python3-pyzfs +Conflicts: python3-pyzfs +Description: wrapper for libzfs_core C library + libzfs_core is intended to be a stable interface for programmatic + administration of ZFS. This wrapper provides one-to-one wrappers for + libzfs_core API functions, but the signatures and types are more natural to + Python. + . + nvlists are wrapped as dictionaries or lists depending on their usage. + Some parameters have default values depending on typical use for + increased convenience. Enumerations and bit flags become strings and lists + of strings in Python. Errors are reported as exceptions rather than integer + errno-style error codes. The wrapper takes care to provide one-to-many + mapping of the error codes to the exceptions by interpreting a context + in which the error code is produced. + +Package: openzfs-pyzfs-doc +Section: contrib/doc +Architecture: all +Depends: ${misc:Depends}, ${sphinxdoc:Depends} +Recommends: openzfs-python3-pyzfs +Replaces: pyzfs-doc +Conflicts: pyzfs-doc +Description: wrapper for libzfs_core C library (documentation) + libzfs_core is intended to be a stable interface for programmatic + administration of ZFS. This wrapper provides one-to-one wrappers for + libzfs_core API functions, but the signatures and types are more natural to + Python. + . + nvlists are wrapped as dictionaries or lists depending on their usage. + Some parameters have default values depending on typical use for + increased convenience. Enumerations and bit flags become strings and lists + of strings in Python. Errors are reported as exceptions rather than integer + errno-style error codes. The wrapper takes care to provide one-to-many + mapping of the error codes to the exceptions by interpreting a context + in which the error code is produced. + . + This package contains the documentation. + +Package: openzfs-zfs-dkms +Architecture: all +Depends: dkms (>> 2.1.1.2-5), + file, + libc6-dev | libc-dev, + lsb-release, + python3-distutils | libpython3-stdlib (<< 3.6.4), + ${misc:Depends}, + ${perl:Depends} +Recommends: openzfs-zfs-zed, openzfs-zfsutils (>= ${source:Version}), ${linux:Recommends} +# suggests debhelper because e.g. `dkms mkdeb -m zfs -v 0.8.2` needs dh_testdir (#909183) +Suggests: debhelper +Breaks: spl-dkms (<< 0.8.0~rc1) +Replaces: spl-dkms, zfs-dkms +Conflicts: zfs-dkms +Provides: openzfs-zfs-modules +Description: OpenZFS filesystem kernel modules for Linux + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This DKMS package includes the SPA, DMU, ZVOL, and ZPL components of + OpenZFS. + +Package: openzfs-zfs-initramfs +Architecture: all +Depends: busybox-initramfs | busybox-static | busybox, + initramfs-tools, + openzfs-zfs-modules | openzfs-zfs-dkms, + openzfs-zfsutils (>= ${source:Version}), + ${misc:Depends} +Breaks: zfsutils-linux (<= 0.7.11-2) +Replaces: zfsutils-linux (<= 0.7.11-2), zfs-initramfs +Conflicts: zfs-initramfs +Description: OpenZFS root filesystem capabilities for Linux - initramfs + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This package adds OpenZFS to the system initramfs with a hook + for the initramfs-tools infrastructure. + +Package: openzfs-zfs-dracut +Architecture: all +Depends: dracut, + openzfs-zfs-modules | openzfs-zfs-dkms, + openzfs-zfsutils (>= ${source:Version}), + ${misc:Depends} +Conflicts: zfs-dracut +Replaces: zfs-dracut +Description: OpenZFS root filesystem capabilities for Linux - dracut + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This package adds OpenZFS to the system initramfs with a hook + for the dracut infrastructure. + +Package: openzfs-zfsutils +Section: contrib/admin +Architecture: linux-any +Pre-Depends: ${misc:Pre-Depends} +Depends: openzfs-libnvpair3 (= ${binary:Version}), + openzfs-libuutil3 (= ${binary:Version}), + openzfs-libzfs4 (= ${binary:Version}), + openzfs-libzpool5 (= ${binary:Version}), + python3, + ${misc:Depends}, + ${shlibs:Depends} +Recommends: lsb-base, openzfs-zfs-modules | openzfs-zfs-dkms, openzfs-zfs-zed +Breaks: openrc, + spl (<< 0.7.9-2), + spl-dkms (<< 0.8.0~rc1), + openzfs-zfs-dkms (<< ${source:Version}), + openzfs-zfs-dkms (>> ${source:Version}...) +Replaces: spl (<< 0.7.9-2), spl-dkms, zfsutils-linux +Conflicts: zfs, zfs-fuse, zfsutils-linux +Suggests: nfs-kernel-server, + samba-common-bin (>= 3.0.23), + openzfs-zfs-initramfs | openzfs-zfs-dracut +Provides: openzfsutils +Description: command-line tools to manage OpenZFS filesystems + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This package provides the zfs and zpool commands to create and administer + OpenZFS filesystems. + +Package: openzfs-zfs-zed +Section: contrib/admin +Architecture: linux-any +Pre-Depends: ${misc:Pre-Depends} +Depends: openzfs-zfs-modules | openzfs-zfs-dkms, + openzfs-zfsutils (>= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Conflicts: zfs, zfs-zed +Replaces: zfs-zed +Description: OpenZFS Event Daemon + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + ZED (ZFS Event Daemon) monitors events generated by the ZFS kernel + module. When a zevent (ZFS Event) is posted, ZED will run any ZEDLETs + (ZFS Event Daemon Linkage for Executable Tasks) that have been enabled + for the corresponding zevent class. + . + This package provides the OpenZFS Event Daemon (zed). + +Package: openzfs-zfs-test +Section: contrib/admin +Architecture: linux-any +Depends: acl, + attr, + bc, + fio, + ksh, + lsscsi, + mdadm, + parted, + python3, + openzfs-python3-pyzfs, + sudo, + sysstat, + openzfs-zfs-modules | openzfs-zfs-dkms, + openzfs-zfsutils (>=${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Recommends: nfs-kernel-server +Breaks: zfsutils-linux (<= 0.7.9-2) +Replaces: zfsutils-linux (<= 0.7.9-2), zfs-test +Conflicts: zutils, zfs-test +Description: OpenZFS test infrastructure and support scripts + OpenZFS is a storage platform that encompasses the functionality of + traditional filesystems and volume managers. It supports data checksums, + compression, encryption, snapshots, and more. + . + This package provides the OpenZFS test infrastructure for destructively + testing and validating a system using OpenZFS. It is entirely optional + and should only be installed and used in test environments. diff --git a/contrib/debian/control.modules.in b/contrib/debian/control.modules.in new file mode 100644 index 000000000000..70a165266d16 --- /dev/null +++ b/contrib/debian/control.modules.in @@ -0,0 +1,33 @@ +Source: openzfs-linux +Section: contrib/kernel +Priority: optional +Maintainer: ZFS on Linux specific mailing list +Build-Depends: debhelper-compat (= 10), + dkms (>> 2.1.1.2-5), + libtool, + linux-headers-_KVERS_ +Standards-Version: 4.3.0 +Homepage: http://www.openzfs.org/ +Vcs-Git: https://github.com/openzfs/zfs.git +Vcs-Browser: https://github.com/openzfs/zfs + +Package: openzfs-zfs-modules-_KVERS_ +Architecture: _ARCH_ +Provides: openzfs-zfs-modules +Depends: linux-image-_KVERS_ +Recommends: openzfsutils +Replaces: zfs-modules-_KVERS_ +Conflicts: zfs-modules-_KVERS_ +Description: OpenZFS filesystem kernel modules for Linux (kernel _KVERS_) + An advanced integrated volume manager and filesystem that is designed for + performance and data integrity. Snapshots, clones, checksums, deduplication, + compression, and RAID redundancy are built-in features. + . + This package contains the compiled kernel module for _KVERS_ + . + Includes the SPA, DMU, ZVOL, and ZPL components of OpenZFS. + . + If you have compiled your own kernel, you will most likely need to build + your own zfs-modules. The zfs-source package has been + provided for use with the Debian kernel-package utility to produce a + version of zfs-module for your kernel. diff --git a/contrib/debian/copyright b/contrib/debian/copyright new file mode 100644 index 000000000000..65c7d209d8eb --- /dev/null +++ b/contrib/debian/copyright @@ -0,0 +1,19 @@ +This Debian packaging is a derived work of Debian's zfs-linux package [1]. +The original copy of the Debian-styled copyright file can be found at [2]. +The detailed contributor information can be found in [2][3]. + +Files: contrib/debian/* +Copyright: + 2013-2016, Aron Xu + 2016, Petter Reinholdtsen + 2013, Carlos Alberto Lopez Perez + 2013, Turbo Fredriksson + 2012-2013, Richard Laager + 2011-2013, Darik Horn + 2018-2019, Mo Zhou + 2018-2020, Mo Zhou +License: GPL-2+ + +[1] https://tracker.debian.org/pkg/zfs-linux +[2] https://salsa.debian.org/zfsonlinux-team/zfs/-/blob/master/debian/copyright +[3] https://salsa.debian.org/zfsonlinux-team/zfs/-/blob/master/debian/changelog diff --git a/contrib/debian/not-installed b/contrib/debian/not-installed new file mode 100644 index 000000000000..ad14776f3b7e --- /dev/null +++ b/contrib/debian/not-installed @@ -0,0 +1,13 @@ +usr/bin/arc_summary.py +usr/share/zfs/enum-extract.pl +usr/share/zfs/zfs-helpers.sh +etc/default/zfs +etc/init.d +etc/sudoers.d +etc/zfs/vdev_id.conf.alias.example +etc/zfs/vdev_id.conf.multipath.example +etc/zfs/vdev_id.conf.sas_direct.example +etc/zfs/vdev_id.conf.sas_switch.example +etc/zfs/vdev_id.conf.scsi.example +etc/zfs/zfs-functions +lib/systemd/system/zfs-import.service diff --git a/contrib/debian/openzfs-libnvpair3.docs b/contrib/debian/openzfs-libnvpair3.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-libnvpair3.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-libnvpair3.install.in b/contrib/debian/openzfs-libnvpair3.install.in new file mode 100644 index 000000000000..ed7b541e3607 --- /dev/null +++ b/contrib/debian/openzfs-libnvpair3.install.in @@ -0,0 +1 @@ +lib/@DEB_HOST_MULTIARCH@/libnvpair.so.* diff --git a/contrib/debian/openzfs-libpam-zfs.install b/contrib/debian/openzfs-libpam-zfs.install new file mode 100644 index 000000000000..c33123f69a8d --- /dev/null +++ b/contrib/debian/openzfs-libpam-zfs.install @@ -0,0 +1,2 @@ +lib/*/security/pam_zfs_key.so +usr/share/pam-configs/zfs_key diff --git a/contrib/debian/openzfs-libpam-zfs.postinst b/contrib/debian/openzfs-libpam-zfs.postinst new file mode 100644 index 000000000000..2db86744e4e6 --- /dev/null +++ b/contrib/debian/openzfs-libpam-zfs.postinst @@ -0,0 +1,6 @@ +#!/bin/sh +set -e + +pam-auth-update --package + +#DEBHELPER# diff --git a/contrib/debian/openzfs-libpam-zfs.prerm b/contrib/debian/openzfs-libpam-zfs.prerm new file mode 100644 index 000000000000..21e827001c23 --- /dev/null +++ b/contrib/debian/openzfs-libpam-zfs.prerm @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +if [ "$1" = remove ] ; then + pam-auth-update --package --remove zfs_key +fi + +#DEBHELPER# diff --git a/contrib/debian/openzfs-libuutil3.docs b/contrib/debian/openzfs-libuutil3.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-libuutil3.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-libuutil3.install.in b/contrib/debian/openzfs-libuutil3.install.in new file mode 100644 index 000000000000..a197d030d743 --- /dev/null +++ b/contrib/debian/openzfs-libuutil3.install.in @@ -0,0 +1 @@ +lib/@DEB_HOST_MULTIARCH@/libuutil.so.* diff --git a/contrib/debian/openzfs-libzfs-dev.docs b/contrib/debian/openzfs-libzfs-dev.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-libzfs-dev.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-libzfs-dev.install.in b/contrib/debian/openzfs-libzfs-dev.install.in new file mode 100644 index 000000000000..eaa8c3925e24 --- /dev/null +++ b/contrib/debian/openzfs-libzfs-dev.install.in @@ -0,0 +1,3 @@ +lib/@DEB_HOST_MULTIARCH@/*.a usr/lib/@DEB_HOST_MULTIARCH@ +usr/include +usr/lib/@DEB_HOST_MULTIARCH@ diff --git a/contrib/debian/openzfs-libzfs4.docs b/contrib/debian/openzfs-libzfs4.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-libzfs4.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-libzfs4.install.in b/contrib/debian/openzfs-libzfs4.install.in new file mode 100644 index 000000000000..6765aaee59cc --- /dev/null +++ b/contrib/debian/openzfs-libzfs4.install.in @@ -0,0 +1,2 @@ +lib/@DEB_HOST_MULTIARCH@/libzfs.so.* +lib/@DEB_HOST_MULTIARCH@/libzfs_core.so.* diff --git a/contrib/debian/openzfs-libzfsbootenv1.docs b/contrib/debian/openzfs-libzfsbootenv1.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-libzfsbootenv1.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-libzfsbootenv1.install.in b/contrib/debian/openzfs-libzfsbootenv1.install.in new file mode 100644 index 000000000000..49216742433f --- /dev/null +++ b/contrib/debian/openzfs-libzfsbootenv1.install.in @@ -0,0 +1 @@ +lib/@DEB_HOST_MULTIARCH@/libzfsbootenv.so.* diff --git a/contrib/debian/openzfs-libzpool5.docs b/contrib/debian/openzfs-libzpool5.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-libzpool5.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-libzpool5.install.in b/contrib/debian/openzfs-libzpool5.install.in new file mode 100644 index 000000000000..b9e872df9ba8 --- /dev/null +++ b/contrib/debian/openzfs-libzpool5.install.in @@ -0,0 +1 @@ +lib/@DEB_HOST_MULTIARCH@/libzpool.so.* diff --git a/contrib/debian/openzfs-python3-pyzfs.install b/contrib/debian/openzfs-python3-pyzfs.install new file mode 100644 index 000000000000..4606faae20a7 --- /dev/null +++ b/contrib/debian/openzfs-python3-pyzfs.install @@ -0,0 +1 @@ +usr/lib/python3* diff --git a/contrib/debian/openzfs-zfs-dkms.config b/contrib/debian/openzfs-zfs-dkms.config new file mode 100644 index 000000000000..ad7e160a2b11 --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.config @@ -0,0 +1,31 @@ +#!/bin/sh + +set -e + +# Source debconf library +. /usr/share/debconf/confmodule + +db_input critical zfs-dkms/note-incompatible-licenses || true +db_go + +kernelbits=unknown +if [ -r /proc/kallsyms ]; then + addrlen=$(head -1 /proc/kallsyms|awk '{print $1}'|wc -c) + if [ $addrlen = 17 ]; then + kernelbits=64 + elif [ $addrlen = 9 ]; then + kernelbits=32 + fi +fi + +if [ $kernelbits != 64 ]; then + if [ $kernelbits = 32 ]; then + db_input critical zfs-dkms/stop-build-for-32bit-kernel || true + db_go || true + else + db_input critical zfs-dkms/stop-build-for-unknown-kernel || true + db_go || true + fi +fi + +#DEBHELPER# diff --git a/contrib/debian/openzfs-zfs-dkms.dkms b/contrib/debian/openzfs-zfs-dkms.dkms new file mode 100644 index 000000000000..3ac8677b7cde --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.dkms @@ -0,0 +1 @@ +scripts/zfs-dkms.dkms diff --git a/contrib/debian/openzfs-zfs-dkms.docs b/contrib/debian/openzfs-zfs-dkms.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-zfs-dkms.install b/contrib/debian/openzfs-zfs-dkms.install new file mode 100644 index 000000000000..b601f22c481a --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.install @@ -0,0 +1 @@ +usr/src diff --git a/contrib/debian/openzfs-zfs-dkms.postinst b/contrib/debian/openzfs-zfs-dkms.postinst new file mode 100644 index 000000000000..0ecb9674d559 --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.postinst @@ -0,0 +1,51 @@ +#!/bin/sh +set -e + +# Source debconf library (see dh_installdebconf(1) and #106070 #626312) +. /usr/share/debconf/confmodule + +kernelbits=unknown +if [ -r /proc/kallsyms ]; then + addrlen=$(head -1 /proc/kallsyms| grep -o '^ *[^ ]*' |wc -c) + if [ $addrlen = 17 ]; then + kernelbits=64 + elif [ $addrlen = 9 ]; then + kernelbits=32 + fi +fi + +if [ $kernelbits != 64 ]; then + if [ $kernelbits = 32 ]; then + db_get zfs-dkms/stop-build-for-32bit-kernel + if [ "$RET" = "true" ]; then + echo "Ok, aborting, since ZFS is not designed for 32-bit kernels." 1>&2 + # Exit 0: Tell dpkg that we finished OK but stop here. + # (don't build the module) + exit 0 + else + echo "WARNING: Building ZFS module on a 32-bit kernel." 1>&2 + fi + else + db_get zfs-dkms/stop-build-for-unknown-kernel + if [ "$RET" = "true" ]; then + echo "Ok, aborting, since ZFS is not designed for 32-bit kernels." 1>&2 + # Exit 0: (same that above) + exit 0 + else + echo "WARNING: Building ZFS module on an unknown kernel." 1>&2 + fi + fi +fi + +# Here the module gets built (automatically handled by dh_dkms) + +#DEBHELPER# + + +case $1 in + (configure) + if [ -x /usr/share/update-notifier/notify-reboot-required ]; then + /usr/share/update-notifier/notify-reboot-required + fi + ;; +esac diff --git a/contrib/debian/openzfs-zfs-dkms.prerm b/contrib/debian/openzfs-zfs-dkms.prerm new file mode 100644 index 000000000000..fea2aee8b902 --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.prerm @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +#DEBHELPER# + +if [ "$1" = "remove" ]; then + rm -f /etc/zfs/zpool.cache +fi diff --git a/contrib/debian/openzfs-zfs-dkms.templates b/contrib/debian/openzfs-zfs-dkms.templates new file mode 100644 index 000000000000..3db643464e7f --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.templates @@ -0,0 +1,40 @@ +Template: zfs-dkms/stop-build-for-32bit-kernel +Type: boolean +Default: true +_Description: Abort building OpenZFS on a 32-bit kernel? + You are attempting to build OpenZFS against a 32-bit running kernel. + . + Although possible, building in a 32-bit environment is unsupported and + likely to cause instability leading to possible data corruption. You + are strongly advised to use a 64-bit kernel; if you do decide to + proceed with using OpenZFS on this kernel then keep in mind that it is at + your own risk. + +Template: zfs-dkms/stop-build-for-unknown-kernel +Type: boolean +Default: true +_Description: Abort building OpenZFS on an unknown kernel? + You are attempting to build OpenZFS against a running kernel that could not + be identified as 32-bit or 64-bit. If you are not completely sure that + the running kernel is a 64-bit one, you should probably stop the build. + . + Although possible, building in a 32-bit environment is unsupported and + likely to cause instability leading to possible data corruption. You + are strongly advised to use a 64-bit kernel; if you do decide to + proceed with using OpenZFS on this kernel then keep in mind that it is at + your own risk. + +Template: zfs-dkms/note-incompatible-licenses +Type: note +_Description: Licenses of OpenZFS and Linux are incompatible + OpenZFS is licensed under the Common Development and Distribution License (CDDL), + and the Linux kernel is licensed under the GNU General Public License Version 2 + (GPL-2). While both are free open source licenses they are restrictive + licenses. The combination of them causes problems because it prevents using + pieces of code exclusively available under one license with pieces of code + exclusively available under the other in the same binary. + . + You are going to build OpenZFS using DKMS in such a way that they are not going to + be built into one monolithic binary. Please be aware that distributing both of + the binaries in the same media (disk images, virtual appliances, etc) may + lead to infringing. diff --git a/contrib/debian/openzfs-zfs-dkms.triggers b/contrib/debian/openzfs-zfs-dkms.triggers new file mode 100644 index 000000000000..865f50a5d99d --- /dev/null +++ b/contrib/debian/openzfs-zfs-dkms.triggers @@ -0,0 +1 @@ +activate-await update-initramfs diff --git a/contrib/debian/openzfs-zfs-dracut.install b/contrib/debian/openzfs-zfs-dracut.install new file mode 100644 index 000000000000..8c2bf1b5c58b --- /dev/null +++ b/contrib/debian/openzfs-zfs-dracut.install @@ -0,0 +1,2 @@ +usr/lib/dracut +usr/share/man/man7/dracut.zfs.7 diff --git a/contrib/debian/openzfs-zfs-initramfs.install b/contrib/debian/openzfs-zfs-initramfs.install new file mode 100644 index 000000000000..222620947f10 --- /dev/null +++ b/contrib/debian/openzfs-zfs-initramfs.install @@ -0,0 +1,2 @@ +../tree/zfs-initramfs/* / +usr/share/initramfs-tools/* diff --git a/contrib/debian/openzfs-zfs-modules-_KVERS_-di.install.in b/contrib/debian/openzfs-zfs-modules-_KVERS_-di.install.in new file mode 100644 index 000000000000..fc1828ee9639 --- /dev/null +++ b/contrib/debian/openzfs-zfs-modules-_KVERS_-di.install.in @@ -0,0 +1,2 @@ +module/spl.ko lib/modules/_KVERS_/extra/zcommon/ +module/zfs.ko lib/modules/_KVERS_/extra/zcommon/ diff --git a/contrib/debian/openzfs-zfs-modules-_KVERS_.install.in b/contrib/debian/openzfs-zfs-modules-_KVERS_.install.in new file mode 100644 index 000000000000..fc1828ee9639 --- /dev/null +++ b/contrib/debian/openzfs-zfs-modules-_KVERS_.install.in @@ -0,0 +1,2 @@ +module/spl.ko lib/modules/_KVERS_/extra/zcommon/ +module/zfs.ko lib/modules/_KVERS_/extra/zcommon/ diff --git a/contrib/debian/openzfs-zfs-modules-_KVERS_.postinst.in b/contrib/debian/openzfs-zfs-modules-_KVERS_.postinst.in new file mode 100644 index 000000000000..4eb2314508a6 --- /dev/null +++ b/contrib/debian/openzfs-zfs-modules-_KVERS_.postinst.in @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +# Run depmod first +depmod -a _KVERS_ + +#DEBHELPER# + + +case $1 in + (configure) + if [ -x /usr/share/update-notifier/notify-reboot-required ]; then + /usr/share/update-notifier/notify-reboot-required + fi + ;; +esac diff --git a/contrib/debian/openzfs-zfs-modules-_KVERS_.postrm.in b/contrib/debian/openzfs-zfs-modules-_KVERS_.postrm.in new file mode 100644 index 000000000000..2a2fc4b5cb95 --- /dev/null +++ b/contrib/debian/openzfs-zfs-modules-_KVERS_.postrm.in @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +# Run depmod after module uninstallation. +depmod + +#DEBHELPER# diff --git a/contrib/debian/openzfs-zfs-test.install b/contrib/debian/openzfs-zfs-test.install new file mode 100644 index 000000000000..cafcfdc0e15b --- /dev/null +++ b/contrib/debian/openzfs-zfs-test.install @@ -0,0 +1,15 @@ +sbin/zinject +sbin/ztest +usr/bin/raidz_test +usr/share/man/man1/raidz_test.1 +usr/share/man/man1/test-runner.1 +usr/share/man/man1/ztest.1 +usr/share/man/man8/zinject.8 +usr/share/zfs/common.sh +usr/share/zfs/runfiles/ +usr/share/zfs/test-runner +usr/share/zfs/zfs-tests.sh +usr/share/zfs/zfs-tests/ +usr/share/zfs/zfs.sh +usr/share/zfs/zimport.sh +usr/share/zfs/zloop.sh diff --git a/contrib/debian/openzfs-zfs-zed.install b/contrib/debian/openzfs-zfs-zed.install new file mode 100644 index 000000000000..a348ba828ee5 --- /dev/null +++ b/contrib/debian/openzfs-zfs-zed.install @@ -0,0 +1,5 @@ +etc/zfs/zed.d/* +lib/systemd/system/zfs-zed.service +usr/lib/zfs-linux/zed.d/* +usr/sbin/zed +usr/share/man/man8/zed.8 diff --git a/contrib/debian/openzfs-zfs-zed.postinst b/contrib/debian/openzfs-zfs-zed.postinst new file mode 100644 index 000000000000..a615eec95760 --- /dev/null +++ b/contrib/debian/openzfs-zfs-zed.postinst @@ -0,0 +1,20 @@ +#!/bin/sh +set -e + +zedd="/usr/lib/zfs-linux/zed.d" +etcd="/etc/zfs/zed.d" + +# enable all default zedlets that are not overridden +while read -r file ; do + etcfile="${etcd}/${file}" + [ -e "${etcfile}" ] && continue + ln -sfT "${zedd}/${file}" "${etcfile}" +done < "${zedd}/DEFAULT-ENABLED" + +# remove the overrides created in prerm +find "${etcd}" -maxdepth 1 -lname '/dev/null' -delete +# remove any dangling symlinks to old zedlets +find "${etcd}" -maxdepth 1 -lname "${zedd}/*" -xtype l -delete + +#DEBHELPER# + diff --git a/contrib/debian/openzfs-zfs-zed.postrm b/contrib/debian/openzfs-zfs-zed.postrm new file mode 100644 index 000000000000..e9aed3f4ce2b --- /dev/null +++ b/contrib/debian/openzfs-zfs-zed.postrm @@ -0,0 +1,17 @@ +#!/bin/sh +set -e + +zedd="/usr/lib/zfs-linux/zed.d" +etcd="/etc/zfs/zed.d" + +if [ "$1" = "purge" ] && [ -d "$etcd" ] ; then + # remove the overrides created in prerm + find "${etcd}" -maxdepth 1 -lname '/dev/null' -delete + # remove any dangling symlinks to old zedlets + find "${etcd}" -maxdepth 1 -lname "${zedd}/*" -xtype l -delete + # clean up any empty directories + ( rmdir "$etcd" && rmdir "/etc/zfs" ) || true +fi + +#DEBHELPER# + diff --git a/contrib/debian/openzfs-zfs-zed.prerm b/contrib/debian/openzfs-zfs-zed.prerm new file mode 100644 index 000000000000..b8340df53438 --- /dev/null +++ b/contrib/debian/openzfs-zfs-zed.prerm @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +zedd="/usr/lib/zfs-linux/zed.d" +etcd="/etc/zfs/zed.d" + +if [ "$1" != "failed-upgrade" ] && [ -d "${etcd}" ] && [ -d "${zedd}" ] ; then + while read -r file ; do + etcfile="${etcd}/${file}" + ( [ -L "${etcfile}" ] || [ -e "${etcfile}" ] ) && continue + ln -sT /dev/null "${etcfile}" + done < "${zedd}/DEFAULT-ENABLED" +fi + +#DEBHELPER# + diff --git a/contrib/debian/openzfs-zfs-zed.zfs-zed.init b/contrib/debian/openzfs-zfs-zed.zfs-zed.init new file mode 120000 index 000000000000..3f41f6813577 --- /dev/null +++ b/contrib/debian/openzfs-zfs-zed.zfs-zed.init @@ -0,0 +1 @@ +../etc/init.d/zfs-zed \ No newline at end of file diff --git a/contrib/debian/openzfs-zfsutils.docs b/contrib/debian/openzfs-zfsutils.docs new file mode 100644 index 000000000000..4302f1b2ab6a --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.docs @@ -0,0 +1,2 @@ +COPYRIGHT +LICENSE diff --git a/contrib/debian/openzfs-zfsutils.examples b/contrib/debian/openzfs-zfsutils.examples new file mode 100644 index 000000000000..9f10d3fc0a7a --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.examples @@ -0,0 +1,5 @@ +etc/zfs/vdev_id.conf.alias.example +etc/zfs/vdev_id.conf.multipath.example +etc/zfs/vdev_id.conf.sas_direct.example +etc/zfs/vdev_id.conf.sas_switch.example +etc/zfs/vdev_id.conf.scsi.example diff --git a/contrib/debian/openzfs-zfsutils.install b/contrib/debian/openzfs-zfsutils.install new file mode 100644 index 000000000000..e10a50e012c1 --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.install @@ -0,0 +1,135 @@ +etc/default/zfs +etc/zfs/zfs-functions +etc/zfs/zpool.d/ +etc/bash_completion.d/zfs +lib/systemd/system-generators/ +lib/systemd/system-preset/ +lib/systemd/system/zfs-import-cache.service +lib/systemd/system/zfs-import-scan.service +lib/systemd/system/zfs-import.target +lib/systemd/system/zfs-load-key.service +lib/systemd/system/zfs-mount.service +lib/systemd/system/zfs-scrub-monthly@.timer +lib/systemd/system/zfs-scrub-weekly@.timer +lib/systemd/system/zfs-scrub@.service +lib/systemd/system/zfs-trim-monthly@.timer +lib/systemd/system/zfs-trim-weekly@.timer +lib/systemd/system/zfs-trim@.service +lib/systemd/system/zfs-share.service +lib/systemd/system/zfs-volume-wait.service +lib/systemd/system/zfs-volumes.target +lib/systemd/system/zfs.target +lib/udev/ +sbin/fsck.zfs +sbin/mount.zfs +sbin/zdb +sbin/zfs +sbin/zfs_ids_to_path +sbin/zgenhostid +sbin/zhack +sbin/zpool +sbin/zstream +sbin/zstreamdump +usr/bin/zvol_wait +usr/lib/modules-load.d/ lib/ +usr/lib/zfs-linux/zpool.d/ +usr/lib/zfs-linux/zpool_influxdb +usr/sbin/arc_summary +usr/sbin/arcstat +usr/sbin/dbufstat +usr/sbin/zilstat +usr/share/zfs/compatibility.d/ +usr/share/bash-completion/completions +usr/share/man/man1/arcstat.1 +usr/share/man/man1/zhack.1 +usr/share/man/man1/zvol_wait.1 +usr/share/man/man5/ +usr/share/man/man8/fsck.zfs.8 +usr/share/man/man8/mount.zfs.8 +usr/share/man/man8/vdev_id.8 +usr/share/man/man8/zdb.8 +usr/share/man/man8/zfs-allow.8 +usr/share/man/man8/zfs-bookmark.8 +usr/share/man/man8/zfs-change-key.8 +usr/share/man/man8/zfs-clone.8 +usr/share/man/man8/zfs-create.8 +usr/share/man/man8/zfs-destroy.8 +usr/share/man/man8/zfs-diff.8 +usr/share/man/man8/zfs-get.8 +usr/share/man/man8/zfs-groupspace.8 +usr/share/man/man8/zfs-hold.8 +usr/share/man/man8/zfs-inherit.8 +usr/share/man/man8/zfs-jail.8 +usr/share/man/man8/zfs-list.8 +usr/share/man/man8/zfs-load-key.8 +usr/share/man/man8/zfs-mount-generator.8 +usr/share/man/man8/zfs-mount.8 +usr/share/man/man8/zfs-program.8 +usr/share/man/man8/zfs-project.8 +usr/share/man/man8/zfs-projectspace.8 +usr/share/man/man8/zfs-promote.8 +usr/share/man/man8/zfs-receive.8 +usr/share/man/man8/zfs-recv.8 +usr/share/man/man8/zfs-redact.8 +usr/share/man/man8/zfs-release.8 +usr/share/man/man8/zfs-rename.8 +usr/share/man/man8/zfs-rollback.8 +usr/share/man/man8/zfs-send.8 +usr/share/man/man8/zfs-set.8 +usr/share/man/man8/zfs-share.8 +usr/share/man/man8/zfs-snapshot.8 +usr/share/man/man8/zfs-unallow.8 +usr/share/man/man8/zfs-unjail.8 +usr/share/man/man8/zfs-unload-key.8 +usr/share/man/man8/zfs-unmount.8 +usr/share/man/man8/zfs-unzone.8 +usr/share/man/man8/zfs-upgrade.8 +usr/share/man/man8/zfs-userspace.8 +usr/share/man/man8/zfs-wait.8 +usr/share/man/man8/zfs-zone.8 +usr/share/man/man8/zfs.8 +usr/share/man/man8/zfs_ids_to_path.8 +usr/share/man/man7/zfsconcepts.7 +usr/share/man/man7/zfsprops.7 +usr/share/man/man8/zgenhostid.8 +usr/share/man/man8/zpool-add.8 +usr/share/man/man8/zpool-attach.8 +usr/share/man/man8/zpool-checkpoint.8 +usr/share/man/man8/zpool-clear.8 +usr/share/man/man8/zpool-create.8 +usr/share/man/man8/zpool-destroy.8 +usr/share/man/man8/zpool-detach.8 +usr/share/man/man8/zpool-events.8 +usr/share/man/man8/zpool-export.8 +usr/share/man/man8/zpool-get.8 +usr/share/man/man8/zpool-history.8 +usr/share/man/man8/zpool-import.8 +usr/share/man/man8/zpool-initialize.8 +usr/share/man/man8/zpool-iostat.8 +usr/share/man/man8/zpool-labelclear.8 +usr/share/man/man8/zpool-list.8 +usr/share/man/man8/zpool-offline.8 +usr/share/man/man8/zpool-online.8 +usr/share/man/man8/zpool-reguid.8 +usr/share/man/man8/zpool-remove.8 +usr/share/man/man8/zpool-reopen.8 +usr/share/man/man8/zpool-replace.8 +usr/share/man/man8/zpool-resilver.8 +usr/share/man/man8/zpool-scrub.8 +usr/share/man/man8/zpool-set.8 +usr/share/man/man8/zpool-split.8 +usr/share/man/man8/zpool-status.8 +usr/share/man/man8/zpool-sync.8 +usr/share/man/man8/zpool-trim.8 +usr/share/man/man8/zpool-upgrade.8 +usr/share/man/man8/zpool-wait.8 +usr/share/man/man8/zpool.8 +usr/share/man/man7/zpoolconcepts.7 +usr/share/man/man7/zpoolprops.7 +usr/share/man/man8/zstream.8 +usr/share/man/man8/zstreamdump.8 +usr/share/man/man4/spl.4 +usr/share/man/man4/zfs.4 +usr/share/man/man7/zpool-features.7 +usr/share/man/man7/dracut.zfs.7 +usr/share/man/man8/zpool_influxdb.8 diff --git a/contrib/debian/openzfs-zfsutils.postinst b/contrib/debian/openzfs-zfsutils.postinst new file mode 100644 index 000000000000..b13a78654c37 --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.postinst @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +# The hostname and hostid of the last system to access a ZFS pool are stored in +# the ZFS pool itself. A pool is foreign if, during `zpool import`, the +# current hostname and hostid are different than the stored values thereof. +# +# The only way of having a stable hostid is to define it in /etc/hostid. +# This postinst helper will check if we already have the hostid stabilized by +# checking the existence of the file /etc/hostid to be 4 bytes at least. +# If this file don't already exists on our system or has less than 4 bytes, then +# a new (random) value is generated with zgenhostid (8) and stored in +# /etc/hostid + +if [ ! -f /etc/hostid ] || [ "$(stat -c %s /etc/hostid)" -lt 4 ] ; then + zgenhostid +fi + +# When processed to here but zfs kernel module is not loaded, the subsequent +# services would fail to start. In this case the installation process just +# fails at the postinst stage. The user could do +# $ sudo modprobe zfs; sudo dpkg --configure -a +# to complete the installation. +# +modprobe -v zfs || true # modprobe zfs does nothing if zfs.ko was already loaded. + +#DEBHELPER# + diff --git a/contrib/debian/openzfs-zfsutils.zfs-import.init b/contrib/debian/openzfs-zfsutils.zfs-import.init new file mode 120000 index 000000000000..bfc368fd3426 --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.zfs-import.init @@ -0,0 +1 @@ +../etc/init.d/zfs-import \ No newline at end of file diff --git a/contrib/debian/openzfs-zfsutils.zfs-load-key.init b/contrib/debian/openzfs-zfsutils.zfs-load-key.init new file mode 120000 index 000000000000..3f3e97f811bb --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.zfs-load-key.init @@ -0,0 +1 @@ +../etc/init.d/zfs-load-key \ No newline at end of file diff --git a/contrib/debian/openzfs-zfsutils.zfs-mount.init b/contrib/debian/openzfs-zfsutils.zfs-mount.init new file mode 120000 index 000000000000..62a544332422 --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.zfs-mount.init @@ -0,0 +1 @@ +../etc/init.d/zfs-mount \ No newline at end of file diff --git a/contrib/debian/openzfs-zfsutils.zfs-share.init b/contrib/debian/openzfs-zfsutils.zfs-share.init new file mode 120000 index 000000000000..3f069f9baaaf --- /dev/null +++ b/contrib/debian/openzfs-zfsutils.zfs-share.init @@ -0,0 +1 @@ +../etc/init.d/zfs-share \ No newline at end of file diff --git a/contrib/debian/rules b/contrib/debian/rules new file mode 100755 index 000000000000..5f4889445bea --- /dev/null +++ b/contrib/debian/rules @@ -0,0 +1,223 @@ +#!/usr/bin/make -f + +include /usr/share/dpkg/default.mk + +LSB_DISTRIBUTOR := $(shell lsb_release -is) +NAME := $(shell awk '$$1 == "Name:" { print $$2; }' META) +LINUX_MIN := $(shell awk '/Linux-Minimum:/{print $$2}' META) +LINUX_NEXT := $(shell awk -F'[ .]' '/Linux-Maximum:/{print $$2 "." $$3+1}' META) + +DKMSFILES := module include config zfs.release.in autogen.sh META AUTHORS \ + COPYRIGHT LICENSE README.md + +ifndef KVERS +KVERS=$(shell uname -r) +endif + +non_epoch_version=$(shell echo $(KVERS) | perl -pe 's/^\d+://') +PACKAGE=openzfs-zfs +pmodules = $(PACKAGE)-modules-$(non_epoch_version) + +export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +NUM_CPUS = $(shell nproc 2>/dev/null) +PARALLEL = $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) +NJOBS = -j$(or $(PARALLEL),$(NUM_CPUS),1) + +%: + dh $@ --with autoreconf,dkms,python3,sphinxdoc + +override_dh_autoreconf: + @# Embed the downstream version in the module. + @sed -e 's/^Version:.*/Version: $(DEB_VERSION_UPSTREAM)/' -i.orig META + + dh_autoreconf + +override_dh_auto_configure: + @# Build the userland, but don't build the kernel modules. + dh_auto_configure -- \ + --bindir=/usr/bin \ + --sbindir=/sbin \ + --libdir=/lib/"$(DEB_HOST_MULTIARCH)" \ + --with-udevdir=/lib/udev \ + --with-zfsexecdir=/usr/lib/zfs-linux \ + --enable-systemd \ + --enable-pyzfs \ + --with-python=python3 \ + --with-pammoduledir='/lib/$(DEB_HOST_MULTIARCH)/security' \ + --with-pkgconfigdir='/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig' \ + --with-systemdunitdir=/lib/systemd/system \ + --with-systemdpresetdir=/lib/systemd/system-preset \ + --with-systemdgeneratordir=/lib/systemd/system-generators \ + --with-config=user + + for i in $(wildcard $(CURDIR)/debian/*.install.in) ; do \ + basename "$$i" | grep _KVERS_ && continue ; \ + sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' "$$i" > "$${i%%.in}" ; \ + done + +override_dh_gencontrol: + dh_gencontrol -- -Vlinux:Recommends="linux-libc-dev (<< $(LINUX_NEXT)~), linux-libc-dev (>= $(LINUX_MIN)~)," + +override_dh_auto_build: + @# Get a bare copy of the source code for DKMS. + @# This creates the $(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/ tree, which does not + @# contain the userland sources. NB: Remove-userland-dist-rules.patch + $(MAKE) distdir + + dh_auto_build + +override_dh_auto_install: + @# Install the utilities. + $(MAKE) install DESTDIR='$(CURDIR)/debian/tmp' + + # Use upstream's bash completion + install -D -t '$(CURDIR)/debian/tmp/usr/share/bash-completion/completions/' \ + '$(CURDIR)/contrib/bash_completion.d/zfs' + + # Move from bin_dir to /usr/sbin + # Remove suffix (.py) as per policy 10.4 - Scripts + # https://www.debian.org/doc/debian-policy/ch-files.html#s-scripts + mkdir -p '$(CURDIR)/debian/tmp/usr/sbin/' + mv '$(CURDIR)/debian/tmp/usr/bin/arc_summary' '$(CURDIR)/debian/tmp/usr/sbin/arc_summary' + mv '$(CURDIR)/debian/tmp/usr/bin/arcstat' '$(CURDIR)/debian/tmp/usr/sbin/arcstat' + mv '$(CURDIR)/debian/tmp/usr/bin/dbufstat' '$(CURDIR)/debian/tmp/usr/sbin/dbufstat' + mv '$(CURDIR)/debian/tmp/usr/bin/zilstat' '$(CURDIR)/debian/tmp/usr/sbin/zilstat' + + @# Zed has dependencies outside of the system root. + mv '$(CURDIR)/debian/tmp/sbin/zed' '$(CURDIR)/debian/tmp/usr/sbin/zed' + + @# Install the DKMS source. + @# We only want the files needed to build the modules + install -D -t '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/scripts' \ + '$(CURDIR)/scripts/enum-extract.pl' \ + '$(CURDIR)/scripts/dkms.postbuild' + $(foreach file,$(DKMSFILES),mv '$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/$(file)' '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)' || exit 1;) + + @# Only ever build Linux modules + echo 'SUBDIRS = linux' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/include/os/Makefile.am' + + @# Hellish awk line: + @# * Deletes from configure.ac the parts not needed for building the kernel module + @# * It deletes from inside AC_CONFIG_FILES([]) everything except: + @# - Makefile$ + @# - include/(Makefile|sys|os/(Makefile|linux)) + @# - module/ + @# - zfs.release$ + @# * Takes care of spaces and tabs + @# * Remove reference to ZFS_AC_PACKAGE + awk '/^AC_CONFIG_FILES\(\[/,/^\]\)/ {\ + if ($$0 !~ /^(AC_CONFIG_FILES\(\[([ \t]+)?$$|\]\)([ \t]+)?$$|([ \t]+)?(include\/(Makefile|sys|os\/(Makefile|linux))|module\/|Makefile([ \t]+)?$$|zfs\.release([ \t]+)?$$))/) \ + {next} } {print}' \ + '$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/configure.ac' | sed '/ZFS_AC_PACKAGE/d' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/configure.ac' + @# Set "SUBDIRS = module include" for CONFIG_KERNEL and remove SUBDIRS for all other configs. + @# Do not regenerate zfs_gitrev.h during dkms build + sed '1,/CONFIG_KERNEL/s/SUBDIRS.*=.*//g;s/SUBDIRS.*=.*/SUBDIRS = module include/g;/make_gitrev.sh/d' \ + '$(CURDIR)/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' > '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' + @# Sanity test + grep -q 'SUBDIRS = module include' '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am' + sed -i '/rpm.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/cmd.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/contrib.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/etc.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/lib.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/man.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/scripts.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/tests.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + sed -i '/udev.Makefile/d' $(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/Makefile.am + @# Run autogen on the stripped source tree + cd '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)'; ./autogen.sh + rm -fr '$(CURDIR)/debian/tmp/usr/src/$(NAME)-$(DEB_VERSION_UPSTREAM)/autom4te.cache' + + for i in `ls $(CURDIR)/debian/tmp/lib/$(DEB_HOST_MULTIARCH)/*.so`; do \ + ln -s '/lib/$(DEB_HOST_MULTIARCH)/'`readlink $${i}` '$(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/'`basename $${i}`; \ + rm $${i}; \ + done + + chmod a-x '$(CURDIR)/debian/tmp/etc/zfs/zfs-functions' + chmod a-x '$(CURDIR)/debian/tmp/etc/default/zfs' + chmod a-x '$(CURDIR)/debian/tmp/usr/share/bash-completion/completions/zfs' + +override_dh_python3: + dh_python3 -p openzfs-python3-pyzfs + +override_dh_dkms: + '$(CURDIR)/scripts/dkms.mkconf' -n $(NAME) -v $(DEB_VERSION_UPSTREAM) -f '$(CURDIR)/scripts/zfs-dkms.dkms' + dh_dkms + rm -f '$(CURDIR)/scripts/zfs-dkms.dkms' + +override_dh_makeshlibs: + dh_makeshlibs -a -V + +override_dh_strip: + dh_strip + +override_dh_auto_clean: + rm -rf zfs-$(DEB_VERSION_UPSTREAM) + dh_auto_clean + @if test -e META.orig; then mv META.orig META; fi + +override_dh_install: + find debian/tmp/lib -name '*.la' -delete + dh_install + +override_dh_missing: + dh_missing --fail-missing + +override_dh_installinit: + dh_installinit -r --no-restart-after-upgrade --name zfs-import + dh_installinit -r --no-restart-after-upgrade --name zfs-mount + dh_installinit -r --no-restart-after-upgrade --name zfs-load-key + dh_installinit -R --name zfs-share + dh_installinit -R --name zfs-zed + +override_dh_installsystemd: + mkdir -p debian/openzfs-zfsutils/lib/systemd/system + ln -sr /dev/null debian/openzfs-zfsutils/lib/systemd/system/zfs-import.service + dh_installsystemd --no-stop-on-upgrade -X zfs-zed.service + dh_installsystemd --name zfs-zed + +override_dh_installdocs: + dh_installdocs -A +ifeq (,$(findstring nodoc, $(DEB_BUILD_OPTIONS))) + http_proxy='127.0.0.1:9' sphinx-build -N -bhtml "$(CURDIR)/contrib/pyzfs/docs/source/" debian/openzfs-pyzfs-doc/usr/share/doc/openzfs-pyzfs-doc/html/ +endif + +# ------------ + +override_dh_prep-deb-files: + for templ in $(wildcard $(CURDIR)/debian/*_KVERS_*.in); do \ + sed -e 's/##KVERS##/$(KVERS)/g ; s/#KVERS#/$(KVERS)/g ; s/_KVERS_/$(KVERS)/g ; s/##KDREV##/$(KDREV)/g ; s/#KDREV#/$(KDREV)/g ; s/_KDREV_/$(KDREV)/g ; s/_ARCH_/$(DEB_HOST_ARCH)/' \ + < $$templ > `echo $$templ | sed -e 's/_KVERS_/$(KVERS)/g ; s/_ARCH_/$(DEB_HOST_ARCH)/g ; s/\.in$$//'` ; \ + done + sed -e 's/##KVERS##/$(KVERS)/g ; s/#KVERS#/$(KVERS)/g ; s/_KVERS_/$(KVERS)/g ; s/##KDREV##/$(KDREV)/g ; s/#KDREV#/$(KDREV)/g ; s/_KDREV_/$(KDREV)/g ; s/_ARCH_/$(DEB_HOST_ARCH)/g' \ + < debian/control.modules.in > debian/control + +override_dh_configure_modules: override_dh_configure_modules_stamp +override_dh_configure_modules_stamp: + ./configure \ + --with-config=kernel \ + --with-linux=$(KSRC) \ + --with-linux-obj=$(KOBJ) + touch override_dh_configure_modules_stamp + +override_dh_binary-modules: override_dh_prep-deb-files override_dh_configure_modules + dh_testdir + dh_testroot + dh_prep + + $(MAKE) $(NJOBS) -C $(CURDIR)/module modules + + dh_install -p${pmodules} + dh_installdocs -p${pmodules} + dh_installchangelogs -p${pmodules} + dh_compress -p${pmodules} + dh_strip -p${pmodules} + dh_fixperms -p${pmodules} + dh_installdeb -p${pmodules} + dh_gencontrol -p${pmodules} + dh_md5sums -p${pmodules} + dh_builddeb -p${pmodules} + +debian-copyright: + cme update dpkg-copyright -file debian/copyright.cme diff --git a/contrib/debian/source/format b/contrib/debian/source/format new file mode 100644 index 000000000000..163aaf8d82b6 --- /dev/null +++ b/contrib/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/conf.d/zfs b/contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/conf.d/zfs new file mode 100644 index 000000000000..5103cc450858 --- /dev/null +++ b/contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/conf.d/zfs @@ -0,0 +1,8 @@ +for x in $(cat /proc/cmdline) +do + case $x in + root=ZFS=*) + BOOT=zfs + ;; + esac +done diff --git a/contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/hooks/zdev b/contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/hooks/zdev new file mode 100755 index 000000000000..0cf21a4211a8 --- /dev/null +++ b/contrib/debian/tree/zfs-initramfs/usr/share/initramfs-tools/hooks/zdev @@ -0,0 +1,67 @@ +#!/bin/sh +# +# Add udev rules for ZoL to the initrd. +# + +PREREQ="udev" +PREREQ_UDEV_RULES="60-zvol.rules 69-vdev.rules" +COPY_EXEC_LIST="/lib/udev/zvol_id /lib/udev/vdev_id" + +# Generic result code. +RC=0 + +case $1 in +prereqs) + echo "$PREREQ" + exit 0 + ;; +esac + +for ii in $COPY_EXEC_LIST +do + if [ ! -x "$ii" ] + then + echo "Error: $ii is not executable." + RC=2 + fi +done + +if [ "$RC" -ne 0 ] +then + exit "$RC" +fi + +. /usr/share/initramfs-tools/hook-functions + +mkdir -p "$DESTDIR/lib/udev/rules.d/" +for ii in $PREREQ_UDEV_RULES +do + if [ -e "/etc/udev/rules.d/$ii" ] + then + cp -p "/etc/udev/rules.d/$ii" "$DESTDIR/lib/udev/rules.d/" + elif [ -e "/lib/udev/rules.d/$ii" ] + then + cp -p "/lib/udev/rules.d/$ii" "$DESTDIR/lib/udev/rules.d/" + else + echo "Error: Missing udev rule: $ii" + echo " This file must be in the /etc/udev/rules.d or /lib/udev/rules.d directory." + exit 1 + fi +done + +for ii in $COPY_EXEC_LIST +do + copy_exec "$ii" +done + +if [ -f '/etc/default/zfs' -a -r '/etc/default/zfs' ] +then + mkdir -p "$DESTDIR/etc/default" + cp -a '/etc/default/zfs' "$DESTDIR/etc/default/" +fi + +if [ -d '/etc/zfs' -a -r '/etc/zfs' ] +then + mkdir -p "$DESTDIR/etc" + cp -a '/etc/zfs' "$DESTDIR/etc/" +fi diff --git a/scripts/debian-packaging.sh b/scripts/debian-packaging.sh new file mode 100755 index 000000000000..9cd042fa44da --- /dev/null +++ b/scripts/debian-packaging.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +# +# This script can be used to invoke OpenZFS build from native Debian +# packaging. +# + +print_help () +{ + echo "Usage: $(basename $0) [OPTIONS]" + echo + echo "Options:" + echo " -b, --build Build OpenZFS from Debian Packaging" + echo " -c, --clean Clean the workspace" +} + +if [ "$#" -ne 1 ]; then + print_help + exit 1 +fi + +case $1 in + -b|--build) + cp -r contrib/debian debian + debuild -i -us -uc -b && fakeroot debian/rules override_dh_binary-modules + ;; + -c|--clean) + fakeroot debian/rules override_dh_auto_clean + rm -rf debian + ;; + *) + print_help + ;; +esac + +exit 0 From 1428ede0ba8d112c152c73f37604299db412422c Mon Sep 17 00:00:00 2001 From: Damian Szuberski Date: Fri, 28 Oct 2022 09:45:14 +1000 Subject: [PATCH 066/126] Process `script` directory for all configs Even when only building kmods process the scripts directory. This way the common.sh script will be generated and the zfs.sh script can be used to load/unload the in-tree kernel modules. Reviewed-by: Brian Behlendorf Signed-off-by: szubersk Closes #14027 Closes #14051 --- Makefile.am | 2 +- scripts/Makefile.am | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Makefile.am b/Makefile.am index 54d300e7d40b..11e45dae8255 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,7 @@ include $(top_srcdir)/config/Rules.am include $(top_srcdir)/config/CppCheck.am include $(top_srcdir)/config/Shellcheck.am include $(top_srcdir)/config/Substfiles.am +include $(top_srcdir)/scripts/Makefile.am ACLOCAL_AMFLAGS = -I config @@ -23,7 +24,6 @@ include $(srcdir)/%D%/contrib/Makefile.am include $(srcdir)/%D%/etc/Makefile.am include $(srcdir)/%D%/lib/Makefile.am include $(srcdir)/%D%/man/Makefile.am -include $(srcdir)/%D%/scripts/Makefile.am include $(srcdir)/%D%/tests/Makefile.am if BUILD_LINUX include $(srcdir)/%D%/udev/Makefile.am diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 79719e621b69..4175d27ea32a 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -1,11 +1,4 @@ scriptsdir = $(datadir)/$(PACKAGE) -dist_scripts_SCRIPTS = \ - %D%/zfs-helpers.sh \ - %D%/zfs-tests.sh \ - %D%/zfs.sh \ - %D%/zimport.sh \ - %D%/zloop.sh - dist_noinst_SCRIPTS = \ %D%/commitcheck.sh \ %D%/common.sh.in \ @@ -18,6 +11,19 @@ dist_noinst_SCRIPTS = \ %D%/paxcheck.sh \ %D%/zfs-tests-color.sh +scripts_scripts = \ + %D%/zfs-helpers.sh \ + %D%/zfs-tests.sh \ + %D%/zfs.sh \ + %D%/zimport.sh \ + %D%/zloop.sh + +if CONFIG_USER +dist_scripts_SCRIPTS = $(scripts_scripts) +else +dist_noinst_SCRIPTS += $(scripts_scripts) +endif + dist_noinst_DATA += \ %D%/cstyle.pl \ %D%/enum-extract.pl \ From 5d0fd8429b0257b2dcd80cef9ed13c8293c1060d Mon Sep 17 00:00:00 2001 From: youzhongyang Date: Fri, 28 Oct 2022 12:08:12 -0400 Subject: [PATCH 067/126] Fix zio_flag_t print format Follow up for 4938d01d which changed zio_flag from enum to uint64_t. Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Signed-off-by: Youzhong Yang Closes #14100 --- include/os/linux/zfs/sys/trace_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/os/linux/zfs/sys/trace_common.h b/include/os/linux/zfs/sys/trace_common.h index a14727f15eed..3d4b1920d598 100644 --- a/include/os/linux/zfs/sys/trace_common.h +++ b/include/os/linux/zfs/sys/trace_common.h @@ -92,7 +92,7 @@ #define ZIO_TP_PRINTK_FMT \ "zio { type %u cmd %i prio %u size %llu orig_size %llu " \ "offset %llu timestamp %llu delta %llu delay %llu " \ - "flags 0x%x stage 0x%x pipeline 0x%x orig_flags 0x%x " \ + "flags 0x%llx stage 0x%x pipeline 0x%x orig_flags 0x%llx " \ "orig_stage 0x%x orig_pipeline 0x%x reexecute %u " \ "txg %llu error %d ena %llu prop { checksum %u compress %u " \ "type %u level %u copies %u dedup %u dedup_verify %u nopwrite %u } }" From e09fdda9775d47078a9dff9d958faf25cf8ca9e8 Mon Sep 17 00:00:00 2001 From: Andrew Innes Date: Sat, 29 Oct 2022 00:30:37 +0800 Subject: [PATCH 068/126] Fix multiplication converted to larger type This fixes the instances of the "Multiplication result converted to larger type" alert that codeQL scanning found. Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Signed-off-by: Andrew Innes Closes #14094 --- cmd/raidz_test/raidz_test.c | 2 +- lib/libefi/rdwr_efi.c | 2 +- module/zfs/arc.c | 2 +- tests/zfs-tests/cmd/stride_dd.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/raidz_test/raidz_test.c b/cmd/raidz_test/raidz_test.c index 34f3f6f1ccc6..195026d3a7ab 100644 --- a/cmd/raidz_test/raidz_test.c +++ b/cmd/raidz_test/raidz_test.c @@ -937,7 +937,7 @@ run_sweep(void) opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL); opts->rto_ashift = ashift_v[a]; opts->rto_dcols = dcols_v[d]; - opts->rto_offset = (1 << ashift_v[a]) * rand(); + opts->rto_offset = (1ULL << ashift_v[a]) * rand(); opts->rto_dsize = size_v[s]; opts->rto_expand = rto_opts.rto_expand; opts->rto_expand_offset = rto_opts.rto_expand_offset; diff --git a/lib/libefi/rdwr_efi.c b/lib/libefi/rdwr_efi.c index 3501c3ea391c..739219e0410f 100644 --- a/lib/libefi/rdwr_efi.c +++ b/lib/libefi/rdwr_efi.c @@ -1362,7 +1362,7 @@ efi_write(int fd, struct dk_gpt *vtoc) if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) { dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize; } else { - dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts, + dk_ioc.dki_length = (len_t)NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) * vtoc->efi_lbasize; } diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 54cfb4bd3d04..936bcb5e3efb 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -5136,7 +5136,7 @@ arc_adapt(int bytes, arc_state_t *state) if (!zfs_arc_p_dampener_disable) mult = MIN(mult, 10); /* avoid wild arc_p adjustment */ - arc_p = MIN(arc_c - arc_p_min, arc_p + bytes * mult); + arc_p = MIN(arc_c - arc_p_min, arc_p + (uint64_t)bytes * mult); } else if (state == arc_mfu_ghost) { uint64_t delta; diff --git a/tests/zfs-tests/cmd/stride_dd.c b/tests/zfs-tests/cmd/stride_dd.c index 732ac9f47268..a20b26131650 100644 --- a/tests/zfs-tests/cmd/stride_dd.c +++ b/tests/zfs-tests/cmd/stride_dd.c @@ -25,8 +25,8 @@ static int bsize = 0; static int count = 0; static char *ifile = NULL; static char *ofile = NULL; -static int stride = 0; -static int seek = 0; +static off_t stride = 0; +static off_t seek = 0; static const char *execname = "stride_dd"; static void usage(void); From 86db35c447aa3f4cc848497d78d54ec9c985d1ed Mon Sep 17 00:00:00 2001 From: Pavel Snajdr Date: Thu, 5 Dec 2019 01:52:27 +0100 Subject: [PATCH 069/126] Remove zpl_revalidate: fix snapshot rollback Open files, which aren't present in the snapshot, which is being roll-backed to, need to disappear from the visible VFS image of the dataset. Kernel provides d_drop function to drop invalid entry from the dcache, but inode can be referenced by dentry multiple dentries. The introduced zpl_d_drop_aliases function walks and invalidates all aliases of an inode. Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Pavel Snajdr Closes #9600 Closes #14070 --- config/kernel-dentry-alias.m4 | 30 +++++++++++++ config/kernel.m4 | 2 + include/os/linux/kernel/linux/dcache_compat.h | 21 +++++++++ include/os/linux/zfs/sys/trace_acl.h | 9 ++-- include/os/linux/zfs/sys/zpl.h | 3 +- include/sys/zfs_znode.h | 1 - module/os/linux/zfs/zfs_ctldir.c | 1 - module/os/linux/zfs/zfs_vfsops.c | 3 +- module/os/linux/zfs/zfs_znode.c | 1 - module/os/linux/zfs/zpl_inode.c | 44 ------------------- 10 files changed, 59 insertions(+), 56 deletions(-) create mode 100644 config/kernel-dentry-alias.m4 diff --git a/config/kernel-dentry-alias.m4 b/config/kernel-dentry-alias.m4 new file mode 100644 index 000000000000..f0ddb8d010b0 --- /dev/null +++ b/config/kernel-dentry-alias.m4 @@ -0,0 +1,30 @@ +dnl # +dnl # 3.18 API change +dnl # Dentry aliases are in d_u struct dentry member +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_DENTRY_ALIAS_D_U], [ + ZFS_LINUX_TEST_SRC([dentry_alias_d_u], [ + #include + #include + #include + ], [ + struct inode *inode __attribute__ ((unused)) = NULL; + struct dentry *dentry __attribute__ ((unused)) = NULL; + hlist_for_each_entry(dentry, &inode->i_dentry, + d_u.d_alias) { + d_drop(dentry); + } + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_DENTRY_ALIAS_D_U], [ + AC_MSG_CHECKING([whether dentry aliases are in d_u member]) + ZFS_LINUX_TEST_RESULT([dentry_alias_d_u], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_DENTRY_D_U_ALIASES, 1, + [dentry aliases are in d_u member]) + ],[ + AC_MSG_RESULT(no) + ]) +]) + diff --git a/config/kernel.m4 b/config/kernel.m4 index d4d13ddd1d1a..b573881c4400 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -96,6 +96,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_SETATTR_PREPARE ZFS_AC_KERNEL_SRC_INSERT_INODE_LOCKED ZFS_AC_KERNEL_SRC_DENTRY + ZFS_AC_KERNEL_SRC_DENTRY_ALIAS_D_U ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE ZFS_AC_KERNEL_SRC_SECURITY_INODE ZFS_AC_KERNEL_SRC_FST_MOUNT @@ -217,6 +218,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_SETATTR_PREPARE ZFS_AC_KERNEL_INSERT_INODE_LOCKED ZFS_AC_KERNEL_DENTRY + ZFS_AC_KERNEL_DENTRY_ALIAS_D_U ZFS_AC_KERNEL_TRUNCATE_SETSIZE ZFS_AC_KERNEL_SECURITY_INODE ZFS_AC_KERNEL_FST_MOUNT diff --git a/include/os/linux/kernel/linux/dcache_compat.h b/include/os/linux/kernel/linux/dcache_compat.h index 0fbd92458679..4de1118daafa 100644 --- a/include/os/linux/kernel/linux/dcache_compat.h +++ b/include/os/linux/kernel/linux/dcache_compat.h @@ -61,4 +61,25 @@ d_clear_d_op(struct dentry *dentry) DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE); } +/* + * Walk and invalidate all dentry aliases of an inode + * unless it's a mountpoint + */ +static inline void +zpl_d_drop_aliases(struct inode *inode) +{ + struct dentry *dentry; + spin_lock(&inode->i_lock); +#ifdef HAVE_DENTRY_D_U_ALIASES + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { +#else + hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { +#endif + if (!IS_ROOT(dentry) && !d_mountpoint(dentry) && + (dentry->d_inode == inode)) { + d_drop(dentry); + } + } + spin_unlock(&inode->i_lock); +} #endif /* _ZFS_DCACHE_H */ diff --git a/include/os/linux/zfs/sys/trace_acl.h b/include/os/linux/zfs/sys/trace_acl.h index 6a73545fecda..2c734322267a 100644 --- a/include/os/linux/zfs/sys/trace_acl.h +++ b/include/os/linux/zfs/sys/trace_acl.h @@ -64,7 +64,6 @@ DECLARE_EVENT_CLASS(zfs_ace_class, __field(boolean_t, z_is_sa) __field(boolean_t, z_is_mapped) __field(boolean_t, z_is_ctldir) - __field(boolean_t, z_is_stale) __field(uint32_t, i_uid) __field(uint32_t, i_gid) @@ -99,7 +98,6 @@ DECLARE_EVENT_CLASS(zfs_ace_class, __entry->z_is_sa = zn->z_is_sa; __entry->z_is_mapped = zn->z_is_mapped; __entry->z_is_ctldir = zn->z_is_ctldir; - __entry->z_is_stale = zn->z_is_stale; __entry->i_uid = KUID_TO_SUID(ZTOI(zn)->i_uid); __entry->i_gid = KGID_TO_SGID(ZTOI(zn)->i_gid); @@ -121,9 +119,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class, "zn_prefetch %u blksz %u seq %u " "mapcnt %llu size %llu pflags %llu " "sync_cnt %u sync_writes_cnt %u async_writes_cnt %u " - "mode 0x%x is_sa %d is_mapped %d " - "is_ctldir %d is_stale %d inode { " - "uid %u gid %u ino %lu nlink %u size %lli " + "mode 0x%x is_sa %d is_mapped %d is_ctldir %d " + "inode { uid %u gid %u ino %lu nlink %u size %lli " "blkbits %u bytes %u mode 0x%x generation %x } } " "ace { type %u flags %u access_mask %u } mask_matched %u", __entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty, @@ -132,7 +129,7 @@ DECLARE_EVENT_CLASS(zfs_ace_class, __entry->z_pflags, __entry->z_sync_cnt, __entry->z_sync_writes_cnt, __entry->z_async_writes_cnt, __entry->z_mode, __entry->z_is_sa, __entry->z_is_mapped, - __entry->z_is_ctldir, __entry->z_is_stale, __entry->i_uid, + __entry->z_is_ctldir, __entry->i_uid, __entry->i_gid, __entry->i_ino, __entry->i_nlink, __entry->i_size, __entry->i_blkbits, __entry->i_bytes, __entry->i_mode, __entry->i_generation, diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index 30d73db6b9e8..83416d64744c 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -45,7 +45,8 @@ extern const struct inode_operations zpl_inode_operations; extern const struct inode_operations zpl_dir_inode_operations; extern const struct inode_operations zpl_symlink_inode_operations; extern const struct inode_operations zpl_special_inode_operations; -extern dentry_operations_t zpl_dentry_operations; + +/* zpl_file.c */ extern const struct address_space_operations zpl_address_space_operations; extern const struct file_operations zpl_file_operations; extern const struct file_operations zpl_dir_file_operations; diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h index 7c906050bc47..c8656b3f6162 100644 --- a/include/sys/zfs_znode.h +++ b/include/sys/zfs_znode.h @@ -190,7 +190,6 @@ typedef struct znode { boolean_t z_is_sa; /* are we native sa? */ boolean_t z_is_mapped; /* are we mmap'ed */ boolean_t z_is_ctldir; /* are we .zfs entry */ - boolean_t z_is_stale; /* are we stale due to rollback? */ boolean_t z_suspended; /* extra ref from a suspend? */ uint_t z_blksz; /* block size in bytes */ uint_t z_seq; /* modification sequence number */ diff --git a/module/os/linux/zfs/zfs_ctldir.c b/module/os/linux/zfs/zfs_ctldir.c index 4ae0a65370e5..519f13212fac 100644 --- a/module/os/linux/zfs/zfs_ctldir.c +++ b/module/os/linux/zfs/zfs_ctldir.c @@ -487,7 +487,6 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id, zp->z_is_sa = B_FALSE; zp->z_is_mapped = B_FALSE; zp->z_is_ctldir = B_TRUE; - zp->z_is_stale = B_FALSE; zp->z_sa_hdl = NULL; zp->z_blksz = 0; zp->z_seq = 0; diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c index 7b682e49d84e..c921e587c75c 100644 --- a/module/os/linux/zfs/zfs_vfsops.c +++ b/module/os/linux/zfs/zfs_vfsops.c @@ -1522,7 +1522,6 @@ zfs_domount(struct super_block *sb, zfs_mnt_t *zm, int silent) sb->s_op = &zpl_super_operations; sb->s_xattr = zpl_xattr_handlers; sb->s_export_op = &zpl_export_operations; - sb->s_d_op = &zpl_dentry_operations; /* Set features for file system. */ zfs_set_fuid_feature(zfsvfs); @@ -1881,8 +1880,8 @@ zfs_resume_fs(zfsvfs_t *zfsvfs, dsl_dataset_t *ds) zp = list_next(&zfsvfs->z_all_znodes, zp)) { err2 = zfs_rezget(zp); if (err2) { + zpl_d_drop_aliases(ZTOI(zp)); remove_inode_hash(ZTOI(zp)); - zp->z_is_stale = B_TRUE; } /* see comment in zfs_suspend_fs() */ diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index 9aeffba86150..3ded79a30a6f 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -552,7 +552,6 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, zp->z_atime_dirty = B_FALSE; zp->z_is_mapped = B_FALSE; zp->z_is_ctldir = B_FALSE; - zp->z_is_stale = B_FALSE; zp->z_suspended = B_FALSE; zp->z_sa_hdl = NULL; zp->z_mapcnt = 0; diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 8d073ff8cbd3..9b702c535ea7 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -728,46 +728,6 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) return (error); } -static int -#ifdef HAVE_D_REVALIDATE_NAMEIDATA -zpl_revalidate(struct dentry *dentry, struct nameidata *nd) -{ - unsigned int flags = (nd ? nd->flags : 0); -#else -zpl_revalidate(struct dentry *dentry, unsigned int flags) -{ -#endif /* HAVE_D_REVALIDATE_NAMEIDATA */ - /* CSTYLED */ - zfsvfs_t *zfsvfs = dentry->d_sb->s_fs_info; - int error; - - if (flags & LOOKUP_RCU) - return (-ECHILD); - - /* - * After a rollback negative dentries created before the rollback - * time must be invalidated. Otherwise they can obscure files which - * are only present in the rolled back dataset. - */ - if (dentry->d_inode == NULL) { - spin_lock(&dentry->d_lock); - error = time_before(dentry->d_time, zfsvfs->z_rollback_time); - spin_unlock(&dentry->d_lock); - - if (error) - return (0); - } - - /* - * The dentry may reference a stale inode if a mounted file system - * was rolled back to a point in time where the object didn't exist. - */ - if (dentry->d_inode && ITOZ(dentry->d_inode)->z_is_stale) - return (0); - - return (1); -} - const struct inode_operations zpl_inode_operations = { .setattr = zpl_setattr, .getattr = zpl_getattr, @@ -856,7 +816,3 @@ const struct inode_operations zpl_special_inode_operations = { .get_acl = zpl_get_acl, #endif /* CONFIG_FS_POSIX_ACL */ }; - -dentry_operations_t zpl_dentry_operations = { - .d_revalidate = zpl_revalidate, -}; From 7b3ba296543724611c12c52c18e85a1028f8f19e Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Wed, 18 May 2022 20:29:33 +1000 Subject: [PATCH 070/126] debug: add VERIFY_{IMPLY,EQUIV} variants This allows for much cleaner VERIFY-level assertions. Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Aleksa Sarai Closes #14070 --- include/os/linux/spl/sys/debug.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/include/os/linux/spl/sys/debug.h b/include/os/linux/spl/sys/debug.h index 3c6f6d1b83bb..8bdc0b1d72d5 100644 --- a/include/os/linux/spl/sys/debug.h +++ b/include/os/linux/spl/sys/debug.h @@ -140,6 +140,16 @@ spl_assert(const char *buf, const char *file, const char *func, int line) (long long) (_verify3_right)); \ } while (0) +#define VERIFY_IMPLY(A, B) \ + ((void)(likely((!(A)) || (B)) || \ + spl_assert("(" #A ") implies (" #B ")", \ + __FILE__, __FUNCTION__, __LINE__))) + +#define VERIFY_EQUIV(A, B) \ + ((void)(likely(!!(A) == !!(B)) || \ + spl_assert("(" #A ") is equivalent to (" #B ")", \ + __FILE__, __FUNCTION__, __LINE__))) + /* * Debugging disabled (--disable-debug) */ @@ -171,14 +181,8 @@ spl_assert(const char *buf, const char *file, const char *func, int line) #define ASSERT3P VERIFY3P #define ASSERT0 VERIFY0 #define ASSERT VERIFY -#define IMPLY(A, B) \ - ((void)(likely((!(A)) || (B)) || \ - spl_assert("(" #A ") implies (" #B ")", \ - __FILE__, __FUNCTION__, __LINE__))) -#define EQUIV(A, B) \ - ((void)(likely(!!(A) == !!(B)) || \ - spl_assert("(" #A ") is equivalent to (" #B ")", \ - __FILE__, __FUNCTION__, __LINE__))) +#define IMPLY VERIFY_IMPLY +#define EQUIV VERIFY_EQUIV #endif /* NDEBUG */ From e015d6cc0b60d4675c9b6d2433eed2c8ef0863e8 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Fri, 26 Apr 2019 23:23:07 +1000 Subject: [PATCH 071/126] zfs_rename: restructure to have cleaner fallbacks This is in preparation for RENAME_EXCHANGE and RENAME_WHITEOUT support for ZoL, but the changes here allow for far nicer fallbacks than the previous implementation (the source and target are re-linked in case of the final link failing). In addition, a small cleanup was done for the "target exists but is a different type" codepath so that it's more understandable. Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Aleksa Sarai Closes #12209 Closes #14070 --- include/os/linux/zfs/sys/zfs_dir.h | 1 + module/os/linux/zfs/zfs_dir.c | 95 ++++++++++++++++------ module/os/linux/zfs/zfs_vnops_os.c | 121 ++++++++++++++++------------- 3 files changed, 140 insertions(+), 77 deletions(-) diff --git a/include/os/linux/zfs/sys/zfs_dir.h b/include/os/linux/zfs/sys/zfs_dir.h index 91d873ea4b7f..9b2232c68ba4 100644 --- a/include/os/linux/zfs/sys/zfs_dir.h +++ b/include/os/linux/zfs/sys/zfs_dir.h @@ -52,6 +52,7 @@ extern "C" { extern int zfs_dirent_lock(zfs_dirlock_t **, znode_t *, char *, znode_t **, int, int *, pathname_t *); extern void zfs_dirent_unlock(zfs_dirlock_t *); +extern int zfs_drop_nlink(znode_t *, dmu_tx_t *, boolean_t *); extern int zfs_link_create(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int); extern int zfs_link_destroy(zfs_dirlock_t *, znode_t *, dmu_tx_t *, int, boolean_t *); diff --git a/module/os/linux/zfs/zfs_dir.c b/module/os/linux/zfs/zfs_dir.c index 611a2471dd94..fb6c28f95c3b 100644 --- a/module/os/linux/zfs/zfs_dir.c +++ b/module/os/linux/zfs/zfs_dir.c @@ -926,6 +926,74 @@ zfs_dropname(zfs_dirlock_t *dl, znode_t *zp, znode_t *dzp, dmu_tx_t *tx, return (error); } +static int +zfs_drop_nlink_locked(znode_t *zp, dmu_tx_t *tx, boolean_t *unlinkedp) +{ + zfsvfs_t *zfsvfs = ZTOZSB(zp); + int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode); + boolean_t unlinked = B_FALSE; + sa_bulk_attr_t bulk[3]; + uint64_t mtime[2], ctime[2]; + uint64_t links; + int count = 0; + int error; + + if (zp_is_dir && !zfs_dirempty(zp)) + return (SET_ERROR(ENOTEMPTY)); + + if (ZTOI(zp)->i_nlink <= zp_is_dir) { + zfs_panic_recover("zfs: link count on %lu is %u, " + "should be at least %u", zp->z_id, + (int)ZTOI(zp)->i_nlink, zp_is_dir + 1); + set_nlink(ZTOI(zp), zp_is_dir + 1); + } + drop_nlink(ZTOI(zp)); + if (ZTOI(zp)->i_nlink == zp_is_dir) { + zp->z_unlinked = B_TRUE; + clear_nlink(ZTOI(zp)); + unlinked = B_TRUE; + } else { + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), + NULL, &ctime, sizeof (ctime)); + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), + NULL, &zp->z_pflags, sizeof (zp->z_pflags)); + zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, + ctime); + } + links = ZTOI(zp)->i_nlink; + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs), + NULL, &links, sizeof (links)); + error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx); + ASSERT3U(error, ==, 0); + + if (unlinkedp != NULL) + *unlinkedp = unlinked; + else if (unlinked) + zfs_unlinked_add(zp, tx); + + return (0); +} + +/* + * Forcefully drop an nlink reference from (zp) and mark it for deletion if it + * was the last link. This *must* only be done to znodes which have already + * been zfs_link_destroy()'d with ZRENAMING. This is explicitly only used in + * the error path of zfs_rename(), where we have to correct the nlink count if + * we failed to link the target as well as failing to re-link the original + * znodes. + */ +int +zfs_drop_nlink(znode_t *zp, dmu_tx_t *tx, boolean_t *unlinkedp) +{ + int error; + + mutex_enter(&zp->z_lock); + error = zfs_drop_nlink_locked(zp, tx, unlinkedp); + mutex_exit(&zp->z_lock); + + return (error); +} + /* * Unlink zp from dl, and mark zp for deletion if this was the last link. Can * fail if zp is a mount point (EBUSY) or a non-empty directory (ENOTEMPTY). @@ -966,31 +1034,8 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag, return (error); } - if (ZTOI(zp)->i_nlink <= zp_is_dir) { - zfs_panic_recover("zfs: link count on %lu is %u, " - "should be at least %u", zp->z_id, - (int)ZTOI(zp)->i_nlink, zp_is_dir + 1); - set_nlink(ZTOI(zp), zp_is_dir + 1); - } - drop_nlink(ZTOI(zp)); - if (ZTOI(zp)->i_nlink == zp_is_dir) { - zp->z_unlinked = B_TRUE; - clear_nlink(ZTOI(zp)); - unlinked = B_TRUE; - } else { - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), - NULL, &ctime, sizeof (ctime)); - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), - NULL, &zp->z_pflags, sizeof (zp->z_pflags)); - zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, - ctime); - } - links = ZTOI(zp)->i_nlink; - SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs), - NULL, &links, sizeof (links)); - error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx); - count = 0; - ASSERT(error == 0); + /* The only error is !zfs_dirempty() and we checked earlier. */ + ASSERT3U(zfs_drop_nlink_locked(zp, tx, &unlinked), ==, 0); mutex_exit(&zp->z_lock); } else { error = zfs_dropname(dl, zp, dzp, tx, flag); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 9160f3e77390..f02cefea222b 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -2876,16 +2876,12 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, /* * Source and target must be the same type. */ - if (S_ISDIR(ZTOI(szp)->i_mode)) { - if (!S_ISDIR(ZTOI(tzp)->i_mode)) { - error = SET_ERROR(ENOTDIR); - goto out; - } - } else { - if (S_ISDIR(ZTOI(tzp)->i_mode)) { - error = SET_ERROR(EISDIR); - goto out; - } + boolean_t s_is_dir = S_ISDIR(ZTOI(szp)->i_mode) != 0; + boolean_t t_is_dir = S_ISDIR(ZTOI(tzp)->i_mode) != 0; + + if (s_is_dir != t_is_dir) { + error = SET_ERROR(s_is_dir ? ENOTDIR : EISDIR); + goto out; } /* * POSIX dictates that when the source and target @@ -2941,51 +2937,49 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, return (error); } - if (tzp) /* Attempt to remove the existing target */ + /* + * Unlink the source. + */ + szp->z_pflags |= ZFS_AV_MODIFIED; + if (tdzp->z_pflags & ZFS_PROJINHERIT) + szp->z_pflags |= ZFS_PROJINHERIT; + + error = sa_update(szp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs), + (void *)&szp->z_pflags, sizeof (uint64_t), tx); + ASSERT0(error); + + error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL); + if (error) + goto commit; + + /* + * Unlink the target. + */ + if (tzp) { error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL); - - if (error == 0) { - error = zfs_link_create(tdl, szp, tx, ZRENAMING); - if (error == 0) { - szp->z_pflags |= ZFS_AV_MODIFIED; - if (tdzp->z_pflags & ZFS_PROJINHERIT) - szp->z_pflags |= ZFS_PROJINHERIT; - - error = sa_update(szp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs), - (void *)&szp->z_pflags, sizeof (uint64_t), tx); - ASSERT0(error); - - error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL); - if (error == 0) { - zfs_log_rename(zilog, tx, TX_RENAME | - (flags & FIGNORECASE ? TX_CI : 0), sdzp, - sdl->dl_name, tdzp, tdl->dl_name, szp); - } else { - /* - * At this point, we have successfully created - * the target name, but have failed to remove - * the source name. Since the create was done - * with the ZRENAMING flag, there are - * complications; for one, the link count is - * wrong. The easiest way to deal with this - * is to remove the newly created target, and - * return the original error. This must - * succeed; fortunately, it is very unlikely to - * fail, since we just created it. - */ - VERIFY3U(zfs_link_destroy(tdl, szp, tx, - ZRENAMING, NULL), ==, 0); - } - } else { - /* - * If we had removed the existing target, subsequent - * call to zfs_link_create() to add back the same entry - * but, the new dnode (szp) should not fail. - */ - ASSERT(tzp == NULL); - } + if (error) + goto commit_link_szp; } + /* + * Create a new link at the target. + */ + error = zfs_link_create(tdl, szp, tx, ZRENAMING); + if (error) { + /* + * If we have removed the existing target, a subsequent call to + * zfs_link_create() to add back the same entry, but with a new + * dnode (szp), should not fail. + */ + ASSERT3P(tzp, ==, NULL); + goto commit_link_tzp; + } + + zfs_log_rename(zilog, tx, TX_RENAME | + (flags & FIGNORECASE ? TX_CI : 0), sdzp, + sdl->dl_name, tdzp, tdl->dl_name, szp); + +commit: dmu_tx_commit(tx); out: if (zl != NULL) @@ -3013,6 +3007,29 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, zfs_exit(zfsvfs, FTAG); return (error); + + /* + * Clean-up path for broken link state. + * + * At this point we are in a (very) bad state, so we need to do our + * best to correct the state. In particular, the nlink of szp is wrong + * because we were destroying and creating links with ZRENAMING. + * + * link_create()s are allowed to fail (though they shouldn't because we + * only just unlinked them and are putting the entries back during + * clean-up). But if they fail, we can just forcefully drop the nlink + * value to (at the very least) avoid broken nlink values -- though in + * the case of non-empty directories we will have to panic. + */ +commit_link_tzp: + if (tzp) { + if (zfs_link_create(tdl, tzp, tx, ZRENAMING)) + VERIFY3U(zfs_drop_nlink(tzp, tx, NULL), ==, 0); + } +commit_link_szp: + if (zfs_link_create(sdl, szp, tx, ZRENAMING)) + VERIFY3U(zfs_drop_nlink(szp, tx, NULL), ==, 0); + goto commit; } /* From dbf6108b4df92341eea40d0b41792ac16eabc514 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sat, 22 Jun 2019 10:35:11 +1000 Subject: [PATCH 072/126] zfs_rename: support RENAME_* flags Implement support for Linux's RENAME_* flags (for renameat2). Aside from being quite useful for userspace (providing race-free ways to exchange paths and implement mv --no-clobber), they are used by overlayfs and are thus required in order to use overlayfs-on-ZFS. In order for us to represent the new renameat2(2) flags in the ZIL, we create two new transaction types for the two flags which need transactional-level support (RENAME_EXCHANGE and RENAME_WHITEOUT). RENAME_NOREPLACE does not need any ZIL support because we know that if the operation succeeded before creating the ZIL entry, there was no file to be clobbered and thus it can be treated as a regular TX_RENAME. Reviewed-by: Ryan Moeller Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Reviewed-by: Pavel Snajdr Signed-off-by: Aleksa Sarai Closes #12209 Closes #14070 --- AUTHORS | 2 + cmd/zdb/zdb_il.c | 10 + cmd/ztest.c | 2 + config/kernel-rename.m4 | 71 +++++- include/os/freebsd/zfs/sys/zfs_vnops_os.h | 3 +- include/os/linux/kernel/linux/vfs_compat.h | 13 ++ include/os/linux/spl/sys/sysmacros.h | 10 + include/os/linux/zfs/sys/zfs_vnops_os.h | 3 +- include/os/linux/zfs/sys/zpl.h | 4 + include/sys/zfs_znode.h | 6 + include/sys/zil.h | 17 +- module/os/freebsd/zfs/zfs_vnops_os.c | 5 +- module/os/linux/zfs/zfs_dir.c | 3 +- module/os/linux/zfs/zfs_vnops_os.c | 209 +++++++++++++++--- module/os/linux/zfs/zfs_znode.c | 5 + module/os/linux/zfs/zpl_inode.c | 37 +++- module/zfs/zfs_log.c | 86 ++++++- module/zfs/zfs_replay.c | 106 ++++++++- module/zfs/zil.c | 6 +- module/zfs/zvol.c | 2 + tests/runfiles/linux.run | 4 + tests/test-runner/bin/zts-report.py.in | 6 + tests/zfs-tests/cmd/.gitignore | 1 + tests/zfs-tests/cmd/Makefile.am | 3 +- tests/zfs-tests/cmd/renameat2.c | 128 +++++++++++ tests/zfs-tests/include/commands.cfg | 1 + .../tests/functional/renameat2/Makefile.am | 7 + .../tests/functional/renameat2/cleanup.ksh | 34 +++ .../renameat2/renameat2_exchange.ksh | 61 +++++ .../renameat2/renameat2_noreplace.ksh | 51 +++++ .../renameat2/renameat2_whiteout.ksh | 50 +++++ .../tests/functional/renameat2/setup.ksh | 37 ++++ .../functional/slog/slog_replay_fs_001.ksh | 23 ++ 33 files changed, 932 insertions(+), 74 deletions(-) create mode 100644 tests/zfs-tests/cmd/renameat2.c create mode 100644 tests/zfs-tests/tests/functional/renameat2/Makefile.am create mode 100755 tests/zfs-tests/tests/functional/renameat2/cleanup.ksh create mode 100755 tests/zfs-tests/tests/functional/renameat2/renameat2_exchange.ksh create mode 100755 tests/zfs-tests/tests/functional/renameat2/renameat2_noreplace.ksh create mode 100755 tests/zfs-tests/tests/functional/renameat2/renameat2_whiteout.ksh create mode 100755 tests/zfs-tests/tests/functional/renameat2/setup.ksh diff --git a/AUTHORS b/AUTHORS index 86083ba87715..c2af58d75085 100644 --- a/AUTHORS +++ b/AUTHORS @@ -20,6 +20,7 @@ CONTRIBUTORS: Alec Salazar Alejandro R. Sedeño Alek Pinchuk + Aleksa Sarai Alex Braunegg Alex McWhirter Alex Reece @@ -236,6 +237,7 @@ CONTRIBUTORS: Paul Dagnelie Paul Zuchowski Pavel Boldin + Pavel Snajdr Pavel Zakharov Pawel Jakub Dawidek Pedro Giffuni diff --git a/cmd/zdb/zdb_il.c b/cmd/zdb/zdb_il.c index 02cc10fb7817..55df1f559f6e 100644 --- a/cmd/zdb/zdb_il.c +++ b/cmd/zdb/zdb_il.c @@ -128,6 +128,14 @@ zil_prt_rec_rename(zilog_t *zilog, int txtype, const void *arg) (void) printf("%ssdoid %llu, tdoid %llu\n", tab_prefix, (u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid); (void) printf("%ssrc %s tgt %s\n", tab_prefix, snm, tnm); + switch (txtype) { + case TX_RENAME_EXCHANGE: + (void) printf("%sflags RENAME_EXCHANGE\n", tab_prefix); + break; + case TX_RENAME_WHITEOUT: + (void) printf("%sflags RENAME_WHITEOUT\n", tab_prefix); + break; + } } static int @@ -330,6 +338,8 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = { {.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE2 "}, {.zri_print = zil_prt_rec_setsaxattr, .zri_name = "TX_SETSAXATTR "}, + {.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_EXCHANGE "}, + {.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_WHITEOUT "}, }; static int diff --git a/cmd/ztest.c b/cmd/ztest.c index a8f9e6b8760a..19edab4eb7a2 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -2368,6 +2368,8 @@ static zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = { NULL, /* TX_MKDIR_ACL_ATTR */ NULL, /* TX_WRITE2 */ NULL, /* TX_SETSAXATTR */ + NULL, /* TX_RENAME_EXCHANGE */ + NULL, /* TX_RENAME_WHITEOUT */ }; /* diff --git a/config/kernel-rename.m4 b/config/kernel-rename.m4 index 302db43f5748..a2b0800ab4d2 100644 --- a/config/kernel-rename.m4 +++ b/config/kernel-rename.m4 @@ -1,8 +1,28 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME], [ + dnl # + dnl # 3.9 (to 4.9) API change, + dnl # + dnl # A new version of iops->rename() was added (rename2) that takes a flag + dnl # argument (to support renameat2). However this separate function was + dnl # merged back into iops->rename() in Linux 4.9. + dnl # + ZFS_LINUX_TEST_SRC([inode_operations_rename2], [ + #include + int rename2_fn(struct inode *sip, struct dentry *sdp, + struct inode *tip, struct dentry *tdp, + unsigned int flags) { return 0; } + + static const struct inode_operations + iops __attribute__ ((unused)) = { + .rename2 = rename2_fn, + }; + ],[]) + dnl # dnl # 4.9 API change, - dnl # iops->rename2() merged into iops->rename(), and iops->rename() now wants - dnl # flags. + dnl # + dnl # iops->rename2() merged into iops->rename(), and iops->rename() now + dnl # wants flags. dnl # ZFS_LINUX_TEST_SRC([inode_operations_rename_flags], [ #include @@ -16,11 +36,29 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME], [ }; ],[]) + dnl # + dnl # EL7 compatibility + dnl # + dnl # EL7 has backported renameat2 support, but it's done by defining a + dnl # separate iops wrapper structure that takes the .renameat2 function. + dnl # + ZFS_LINUX_TEST_SRC([dir_inode_operations_wrapper_rename2], [ + #include + int rename2_fn(struct inode *sip, struct dentry *sdp, + struct inode *tip, struct dentry *tdp, + unsigned int flags) { return 0; } + + static const struct inode_operations_wrapper + iops __attribute__ ((unused)) = { + .rename2 = rename2_fn, + }; + ],[]) + dnl # dnl # 5.12 API change, dnl # - dnl # Linux 5.12 introduced passing struct user_namespace* as the first argument - dnl # of the rename() and other inode_operations members. + dnl # Linux 5.12 introduced passing struct user_namespace* as the first + dnl # argument of the rename() and other inode_operations members. dnl # ZFS_LINUX_TEST_SRC([inode_operations_rename_userns], [ #include @@ -44,13 +82,30 @@ AC_DEFUN([ZFS_AC_KERNEL_RENAME], [ ],[ AC_MSG_RESULT(no) - AC_MSG_CHECKING([whether iop->rename() wants flags]) - ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [ + AC_MSG_CHECKING([whether iops->rename2() exists]) + ZFS_LINUX_TEST_RESULT([inode_operations_rename2], [ AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, - [iops->rename() wants flags]) + AC_DEFINE(HAVE_RENAME2, 1, [iops->rename2() exists]) ],[ AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether iops->rename() wants flags]) + ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, + [iops->rename() wants flags]) + ],[ + AC_MSG_RESULT(no) + + AC_MSG_CHECKING([whether struct inode_operations_wrapper takes .rename2()]) + ZFS_LINUX_TEST_RESULT([dir_inode_operations_wrapper_rename2], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RENAME2_OPERATIONS_WRAPPER, 1, + [struct inode_operations_wrapper takes .rename2()]) + ],[ + AC_MSG_RESULT(no) + ]) + ]) ]) ]) ]) diff --git a/include/os/freebsd/zfs/sys/zfs_vnops_os.h b/include/os/freebsd/zfs/sys/zfs_vnops_os.h index 460aecd2e708..839ee629a5ab 100644 --- a/include/os/freebsd/zfs/sys/zfs_vnops_os.h +++ b/include/os/freebsd/zfs/sys/zfs_vnops_os.h @@ -41,7 +41,8 @@ extern int zfs_rmdir(znode_t *dzp, const char *name, znode_t *cwd, extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr, zuserns_t *mnt_ns); extern int zfs_rename(znode_t *sdzp, const char *snm, znode_t *tdzp, - const char *tnm, cred_t *cr, int flags, zuserns_t *mnt_ns); + const char *tnm, cred_t *cr, int flags, uint64_t rflags, vattr_t *wo_vap, + zuserns_t *mnt_ns); extern int zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap, const char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns); extern int zfs_link(znode_t *tdzp, znode_t *sp, diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h index eeed0a388ce4..fd0b9e8e1068 100644 --- a/include/os/linux/kernel/linux/vfs_compat.h +++ b/include/os/linux/kernel/linux/vfs_compat.h @@ -324,6 +324,19 @@ static inline void zfs_gid_write(struct inode *ip, gid_t gid) ip->i_gid = make_kgid(kcred->user_ns, gid); } +/* + * 3.15 API change + */ +#ifndef RENAME_NOREPLACE +#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */ +#endif +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ +#endif +#ifndef RENAME_WHITEOUT +#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */ +#endif + /* * 4.9 API change */ diff --git a/include/os/linux/spl/sys/sysmacros.h b/include/os/linux/spl/sys/sysmacros.h index be1f77e43bda..99e3a6fb41c6 100644 --- a/include/os/linux/spl/sys/sysmacros.h +++ b/include/os/linux/spl/sys/sysmacros.h @@ -120,6 +120,16 @@ extern uint32_t zone_get_hostid(void *zone); extern void spl_setup(void); extern void spl_cleanup(void); +/* + * Only handles the first 4096 majors and first 256 minors. We don't have a + * libc for the kernel module so we define this inline. + */ +static inline dev_t +makedev(unsigned int major, unsigned int minor) +{ + return ((major & 0xFFF) << 8) | (minor & 0xFF); +} + #define highbit(x) __fls(x) #define lowbit(x) __ffs(x) diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h index 787d258e1388..197ea9bec500 100644 --- a/include/os/linux/zfs/sys/zfs_vnops_os.h +++ b/include/os/linux/zfs/sys/zfs_vnops_os.h @@ -61,7 +61,8 @@ extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip, extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr, zuserns_t *mnt_ns); extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, - char *tnm, cred_t *cr, int flags, zuserns_t *mnt_ns); + char *tnm, cred_t *cr, int flags, uint64_t rflags, vattr_t *wo_vap, + zuserns_t *mnt_ns); extern int zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns); extern int zfs_readlink(struct inode *ip, zfs_uio_t *uio, cred_t *cr); diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h index 83416d64744c..c3ee0ae4a600 100644 --- a/include/os/linux/zfs/sys/zpl.h +++ b/include/os/linux/zfs/sys/zpl.h @@ -42,7 +42,11 @@ extern void zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr, zuserns_t *mnt_ns); extern const struct inode_operations zpl_inode_operations; +#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER +extern const struct inode_operations_wrapper zpl_dir_inode_operations; +#else extern const struct inode_operations zpl_dir_inode_operations; +#endif extern const struct inode_operations zpl_symlink_inode_operations; extern const struct inode_operations zpl_special_inode_operations; diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h index c8656b3f6162..88d642350691 100644 --- a/include/sys/zfs_znode.h +++ b/include/sys/zfs_znode.h @@ -299,6 +299,12 @@ extern void zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, extern void zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *sdzp, const char *sname, znode_t *tdzp, const char *dname, znode_t *szp); +extern void zfs_log_rename_exchange(zilog_t *zilog, dmu_tx_t *tx, + uint64_t txtype, znode_t *sdzp, const char *sname, znode_t *tdzp, + const char *dname, znode_t *szp); +extern void zfs_log_rename_whiteout(zilog_t *zilog, dmu_tx_t *tx, + uint64_t txtype, znode_t *sdzp, const char *sname, znode_t *tdzp, + const char *dname, znode_t *szp, znode_t *wzp); extern void zfs_log_write(zilog_t *zilog, dmu_tx_t *tx, int txtype, znode_t *zp, offset_t off, ssize_t len, int ioflag, zil_callback_t callback, void *callback_data); diff --git a/include/sys/zil.h b/include/sys/zil.h index cec04f120ce3..9591fb4f6440 100644 --- a/include/sys/zil.h +++ b/include/sys/zil.h @@ -164,7 +164,9 @@ typedef enum zil_create { #define TX_MKDIR_ACL_ATTR 19 /* mkdir with ACL + attrs */ #define TX_WRITE2 20 /* dmu_sync EALREADY write */ #define TX_SETSAXATTR 21 /* Set sa xattrs on file */ -#define TX_MAX_TYPE 22 /* Max transaction type */ +#define TX_RENAME_EXCHANGE 22 /* Atomic swap via renameat2 */ +#define TX_RENAME_WHITEOUT 23 /* Atomic whiteout via renameat2 */ +#define TX_MAX_TYPE 24 /* Max transaction type */ /* * The transactions for mkdir, symlink, remove, rmdir, link, and rename @@ -317,6 +319,19 @@ typedef struct { /* 2 strings: names of source and destination follow this */ } lr_rename_t; +typedef struct { + lr_rename_t lr_rename; /* common rename portion */ + /* members related to the whiteout file (based on lr_create_t) */ + uint64_t lr_wfoid; /* obj id of the new whiteout file */ + uint64_t lr_wmode; /* mode of object */ + uint64_t lr_wuid; /* uid of whiteout */ + uint64_t lr_wgid; /* gid of whiteout */ + uint64_t lr_wgen; /* generation (txg of creation) */ + uint64_t lr_wcrtime[2]; /* creation time */ + uint64_t lr_wrdev; /* always makedev(0, 0) */ + /* 2 strings: names of source and destination follow this */ +} lr_rename_whiteout_t; + typedef struct { lr_t lr_common; /* common portion of log record */ uint64_t lr_foid; /* file object to write */ diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index 362e02751ee4..bcf4e2f18d83 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -3420,7 +3420,7 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, int zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname, - cred_t *cr, int flags, zuserns_t *mnt_ns) + cred_t *cr, int flags, uint64_t rflags, vattr_t *wo_vap, zuserns_t *mnt_ns) { struct componentname scn, tcn; vnode_t *sdvp, *tdvp; @@ -3428,6 +3428,9 @@ zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname, int error; svp = tvp = NULL; + if (rflags != 0 || wo_vap != NULL) + return (SET_ERROR(EINVAL)); + sdvp = ZTOV(sdzp); tdvp = ZTOV(tdzp); error = zfs_lookup_internal(sdzp, sname, &svp, &scn, DELETE); diff --git a/module/os/linux/zfs/zfs_dir.c b/module/os/linux/zfs/zfs_dir.c index fb6c28f95c3b..b4e4146b09e9 100644 --- a/module/os/linux/zfs/zfs_dir.c +++ b/module/os/linux/zfs/zfs_dir.c @@ -1035,7 +1035,8 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag, } /* The only error is !zfs_dirempty() and we checked earlier. */ - ASSERT3U(zfs_drop_nlink_locked(zp, tx, &unlinked), ==, 0); + error = zfs_drop_nlink_locked(zp, tx, &unlinked); + ASSERT3U(error, ==, 0); mutex_exit(&zp->z_lock); } else { error = zfs_dropname(dl, zp, dzp, tx, flag); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index f02cefea222b..545d8ad8d79c 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -2655,6 +2655,8 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp) * tnm - New entry name. * cr - credentials of caller. * flags - case flags + * rflags - RENAME_* flags + * wa_vap - attributes for RENAME_WHITEOUT (must be a char 0:0). * mnt_ns - user namespace of the mount * * RETURN: 0 on success, error code on failure. @@ -2664,7 +2666,7 @@ zfs_rename_lock(znode_t *szp, znode_t *tdzp, znode_t *sdzp, zfs_zlock_t **zlpp) */ int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, - cred_t *cr, int flags, zuserns_t *mnt_ns) + cred_t *cr, int flags, uint64_t rflags, vattr_t *wo_vap, zuserns_t *mnt_ns) { znode_t *szp, *tzp; zfsvfs_t *zfsvfs = ZTOZSB(sdzp); @@ -2676,10 +2678,33 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, int error = 0; int zflg = 0; boolean_t waited = B_FALSE; + /* Needed for whiteout inode creation. */ + boolean_t fuid_dirtied; + zfs_acl_ids_t acl_ids; + boolean_t have_acl = B_FALSE; + znode_t *wzp = NULL; + if (snm == NULL || tnm == NULL) return (SET_ERROR(EINVAL)); + if (rflags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) + return (SET_ERROR(EINVAL)); + + /* Already checked by Linux VFS, but just to make sure. */ + if (rflags & RENAME_EXCHANGE && + (rflags & (RENAME_NOREPLACE | RENAME_WHITEOUT))) + return (SET_ERROR(EINVAL)); + + /* + * Make sure we only get wo_vap iff. RENAME_WHITEOUT and that it's the + * right kind of vattr_t for the whiteout file. These are set + * internally by ZFS so should never be incorrect. + */ + VERIFY_EQUIV(rflags & RENAME_WHITEOUT, wo_vap != NULL); + VERIFY_IMPLY(wo_vap, wo_vap->va_mode == S_IFCHR); + VERIFY_IMPLY(wo_vap, wo_vap->va_rdev == makedevice(0, 0)); + if ((error = zfs_enter_verify_zp(zfsvfs, sdzp, FTAG)) != 0) return (error); zilog = zfsvfs->z_log; @@ -2856,7 +2881,6 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, * Note that if target and source are the same, this can be * done in a single check. */ - if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr, mnt_ns))) goto out; @@ -2873,16 +2897,22 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, * Does target exist? */ if (tzp) { - /* - * Source and target must be the same type. - */ - boolean_t s_is_dir = S_ISDIR(ZTOI(szp)->i_mode) != 0; - boolean_t t_is_dir = S_ISDIR(ZTOI(tzp)->i_mode) != 0; - - if (s_is_dir != t_is_dir) { - error = SET_ERROR(s_is_dir ? ENOTDIR : EISDIR); + if (rflags & RENAME_NOREPLACE) { + error = SET_ERROR(EEXIST); goto out; } + /* + * Source and target must be the same type (unless exchanging). + */ + if (!(rflags & RENAME_EXCHANGE)) { + boolean_t s_is_dir = S_ISDIR(ZTOI(szp)->i_mode) != 0; + boolean_t t_is_dir = S_ISDIR(ZTOI(tzp)->i_mode) != 0; + + if (s_is_dir != t_is_dir) { + error = SET_ERROR(s_is_dir ? ENOTDIR : EISDIR); + goto out; + } + } /* * POSIX dictates that when the source and target * entries refer to the same file object, rename @@ -2892,12 +2922,43 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, error = 0; goto out; } + } else if (rflags & RENAME_EXCHANGE) { + /* Target must exist for RENAME_EXCHANGE. */ + error = SET_ERROR(ENOENT); + goto out; + } + + /* Set up inode creation for RENAME_WHITEOUT. */ + if (rflags & RENAME_WHITEOUT) { + /* + * Whiteout files are not regular files or directories, so to + * match zfs_create() we do not inherit the project id. + */ + uint64_t wo_projid = ZFS_DEFAULT_PROJID; + + error = zfs_zaccess(sdzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns); + if (error) + goto out; + + if (!have_acl) { + error = zfs_acl_ids_create(sdzp, 0, wo_vap, cr, NULL, + &acl_ids, mnt_ns); + if (error) + goto out; + have_acl = B_TRUE; + } + + if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, wo_projid)) { + error = SET_ERROR(EDQUOT); + goto out; + } } tx = dmu_tx_create(zfsvfs->z_os); dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE); dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE); - dmu_tx_hold_zap(tx, sdzp->z_id, FALSE, snm); + dmu_tx_hold_zap(tx, sdzp->z_id, + (rflags & RENAME_EXCHANGE) ? TRUE : FALSE, snm); dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, tnm); if (sdzp != tdzp) { dmu_tx_hold_sa(tx, tdzp->z_sa_hdl, B_FALSE); @@ -2907,7 +2968,21 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, dmu_tx_hold_sa(tx, tzp->z_sa_hdl, B_FALSE); zfs_sa_upgrade_txholds(tx, tzp); } + if (rflags & RENAME_WHITEOUT) { + dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes + + ZFS_SA_BASE_ATTR_SIZE); + dmu_tx_hold_zap(tx, sdzp->z_id, TRUE, snm); + dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE); + if (!zfsvfs->z_use_sa && + acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) { + dmu_tx_hold_write(tx, DMU_NEW_OBJECT, + 0, acl_ids.z_aclp->z_acl_bytes); + } + } + fuid_dirtied = zfsvfs->z_fuid_dirty; + if (fuid_dirtied) + zfs_fuid_txhold(zfsvfs, tx); zfs_sa_upgrade_txholds(tx, szp); dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); error = dmu_tx_assign(tx, (waited ? TXG_NOTHROTTLE : 0) | TXG_NOWAIT); @@ -2946,7 +3021,7 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, error = sa_update(szp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs), (void *)&szp->z_pflags, sizeof (uint64_t), tx); - ASSERT0(error); + VERIFY0(error); error = zfs_link_destroy(sdl, szp, tx, ZRENAMING, NULL); if (error) @@ -2956,13 +3031,30 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, * Unlink the target. */ if (tzp) { - error = zfs_link_destroy(tdl, tzp, tx, zflg, NULL); + int tzflg = zflg; + + if (rflags & RENAME_EXCHANGE) { + /* This inode will be re-linked soon. */ + tzflg |= ZRENAMING; + + tzp->z_pflags |= ZFS_AV_MODIFIED; + if (sdzp->z_pflags & ZFS_PROJINHERIT) + tzp->z_pflags |= ZFS_PROJINHERIT; + + error = sa_update(tzp->z_sa_hdl, SA_ZPL_FLAGS(zfsvfs), + (void *)&tzp->z_pflags, sizeof (uint64_t), tx); + ASSERT0(error); + } + error = zfs_link_destroy(tdl, tzp, tx, tzflg, NULL); if (error) goto commit_link_szp; } /* - * Create a new link at the target. + * Create the new target links: + * * We always link the target. + * * RENAME_EXCHANGE: Link the old target to the source. + * * RENAME_WHITEOUT: Create a whiteout inode in-place of the source. */ error = zfs_link_create(tdl, szp, tx, ZRENAMING); if (error) { @@ -2975,18 +3067,55 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, goto commit_link_tzp; } - zfs_log_rename(zilog, tx, TX_RENAME | - (flags & FIGNORECASE ? TX_CI : 0), sdzp, - sdl->dl_name, tdzp, tdl->dl_name, szp); + switch (rflags & (RENAME_EXCHANGE | RENAME_WHITEOUT)) { + case RENAME_EXCHANGE: + error = zfs_link_create(sdl, tzp, tx, ZRENAMING); + /* + * The same argument as zfs_link_create() failing for + * szp applies here, since the source directory must + * have had an entry we are replacing. + */ + ASSERT0(error); + if (error) + goto commit_unlink_td_szp; + break; + case RENAME_WHITEOUT: + zfs_mknode(sdzp, wo_vap, tx, cr, 0, &wzp, &acl_ids); + error = zfs_link_create(sdl, wzp, tx, ZNEW); + if (error) { + zfs_znode_delete(wzp, tx); + remove_inode_hash(ZTOI(wzp)); + goto commit_unlink_td_szp; + } + break; + } + + if (fuid_dirtied) + zfs_fuid_sync(zfsvfs, tx); + + switch (rflags & (RENAME_EXCHANGE | RENAME_WHITEOUT)) { + case RENAME_EXCHANGE: + zfs_log_rename_exchange(zilog, tx, + (flags & FIGNORECASE ? TX_CI : 0), sdzp, sdl->dl_name, + tdzp, tdl->dl_name, szp); + break; + case RENAME_WHITEOUT: + zfs_log_rename_whiteout(zilog, tx, + (flags & FIGNORECASE ? TX_CI : 0), sdzp, sdl->dl_name, + tdzp, tdl->dl_name, szp, wzp); + break; + default: + ASSERT0(rflags & ~RENAME_NOREPLACE); + zfs_log_rename(zilog, tx, (flags & FIGNORECASE ? TX_CI : 0), + sdzp, sdl->dl_name, tdzp, tdl->dl_name, szp); + break; + } commit: dmu_tx_commit(tx); out: - if (zl != NULL) - zfs_rename_unlock(&zl); - - zfs_dirent_unlock(sdl); - zfs_dirent_unlock(tdl); + if (have_acl) + zfs_acl_ids_free(&acl_ids); zfs_znode_update_vfs(sdzp); if (sdzp == tdzp) @@ -2997,11 +3126,21 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, zfs_znode_update_vfs(szp); zrele(szp); + if (wzp) { + zfs_znode_update_vfs(wzp); + zrele(wzp); + } if (tzp) { zfs_znode_update_vfs(tzp); zrele(tzp); } + if (zl != NULL) + zfs_rename_unlock(&zl); + + zfs_dirent_unlock(sdl); + zfs_dirent_unlock(tdl); + if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) zil_commit(zilog, 0); @@ -3012,23 +3151,31 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm, * Clean-up path for broken link state. * * At this point we are in a (very) bad state, so we need to do our - * best to correct the state. In particular, the nlink of szp is wrong - * because we were destroying and creating links with ZRENAMING. + * best to correct the state. In particular, all of the nlinks are + * wrong because we were destroying and creating links with ZRENAMING. * - * link_create()s are allowed to fail (though they shouldn't because we - * only just unlinked them and are putting the entries back during - * clean-up). But if they fail, we can just forcefully drop the nlink - * value to (at the very least) avoid broken nlink values -- though in - * the case of non-empty directories we will have to panic. + * In some form, all of these operations have to resolve the state: + * + * * link_destroy() *must* succeed. Fortunately, this is very likely + * since we only just created it. + * + * * link_create()s are allowed to fail (though they shouldn't because + * we only just unlinked them and are putting the entries back + * during clean-up). But if they fail, we can just forcefully drop + * the nlink value to (at the very least) avoid broken nlink values + * -- though in the case of non-empty directories we will have to + * panic (otherwise we'd have a leaked directory with a broken ..). */ +commit_unlink_td_szp: + VERIFY0(zfs_link_destroy(tdl, szp, tx, ZRENAMING, NULL)); commit_link_tzp: if (tzp) { if (zfs_link_create(tdl, tzp, tx, ZRENAMING)) - VERIFY3U(zfs_drop_nlink(tzp, tx, NULL), ==, 0); + VERIFY0(zfs_drop_nlink(tzp, tx, NULL)); } commit_link_szp: if (zfs_link_create(sdl, szp, tx, ZRENAMING)) - VERIFY3U(zfs_drop_nlink(szp, tx, NULL), ==, 0); + VERIFY0(zfs_drop_nlink(szp, tx, NULL)); goto commit; } diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index 3ded79a30a6f..c8f6e02bd224 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -422,7 +422,12 @@ zfs_inode_set_ops(zfsvfs_t *zfsvfs, struct inode *ip) break; case S_IFDIR: +#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER + ip->i_flags |= S_IOPS_WRAPPER; + ip->i_op = &zpl_dir_inode_operations.ops; +#else ip->i_op = &zpl_dir_inode_operations; +#endif ip->i_fop = &zpl_dir_file_operations; ITOZ(ip)->z_zn_prefetch = B_TRUE; break; diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 9b702c535ea7..64016f9ac1de 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -24,6 +24,7 @@ */ +#include #include #include #include @@ -498,35 +499,42 @@ static int #ifdef HAVE_IOPS_RENAME_USERNS zpl_rename2(struct user_namespace *user_ns, struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, - unsigned int flags) + unsigned int rflags) #else zpl_rename2(struct inode *sdip, struct dentry *sdentry, - struct inode *tdip, struct dentry *tdentry, unsigned int flags) + struct inode *tdip, struct dentry *tdentry, unsigned int rflags) #endif { cred_t *cr = CRED(); + vattr_t *wo_vap = NULL; int error; fstrans_cookie_t cookie; #ifndef HAVE_IOPS_RENAME_USERNS zuserns_t *user_ns = NULL; #endif - /* We don't have renameat2(2) support */ - if (flags) - return (-EINVAL); - crhold(cr); + if (rflags & RENAME_WHITEOUT) { + wo_vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); + zpl_vap_init(wo_vap, sdip, S_IFCHR, cr, user_ns); + wo_vap->va_rdev = makedevice(0, 0); + } + cookie = spl_fstrans_mark(); error = -zfs_rename(ITOZ(sdip), dname(sdentry), ITOZ(tdip), - dname(tdentry), cr, 0, user_ns); + dname(tdentry), cr, 0, rflags, wo_vap, user_ns); spl_fstrans_unmark(cookie); + if (wo_vap) + kmem_free(wo_vap, sizeof (vattr_t)); crfree(cr); ASSERT3S(error, <=, 0); return (error); } -#if !defined(HAVE_RENAME_WANTS_FLAGS) && !defined(HAVE_IOPS_RENAME_USERNS) +#if !defined(HAVE_IOPS_RENAME_USERNS) && \ + !defined(HAVE_RENAME_WANTS_FLAGS) && \ + !defined(HAVE_RENAME2) static int zpl_rename(struct inode *sdip, struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry) @@ -745,7 +753,12 @@ const struct inode_operations zpl_inode_operations = { #endif /* CONFIG_FS_POSIX_ACL */ }; +#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER +const struct inode_operations_wrapper zpl_dir_inode_operations = { + .ops = { +#else const struct inode_operations zpl_dir_inode_operations = { +#endif .create = zpl_create, .lookup = zpl_lookup, .link = zpl_link, @@ -754,7 +767,9 @@ const struct inode_operations zpl_dir_inode_operations = { .mkdir = zpl_mkdir, .rmdir = zpl_rmdir, .mknod = zpl_mknod, -#if defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) +#ifdef HAVE_RENAME2 + .rename2 = zpl_rename2, +#elif defined(HAVE_RENAME_WANTS_FLAGS) || defined(HAVE_IOPS_RENAME_USERNS) .rename = zpl_rename2, #else .rename = zpl_rename, @@ -776,6 +791,10 @@ const struct inode_operations zpl_dir_inode_operations = { #endif /* HAVE_SET_ACL */ .get_acl = zpl_get_acl, #endif /* CONFIG_FS_POSIX_ACL */ +#ifdef HAVE_RENAME2_OPERATIONS_WRAPPER + }, + .rename2 = zpl_rename2, +#endif }; const struct inode_operations zpl_symlink_inode_operations = { diff --git a/module/zfs/zfs_log.c b/module/zfs/zfs_log.c index 245699882aa9..77bf9140d52d 100644 --- a/module/zfs/zfs_log.c +++ b/module/zfs/zfs_log.c @@ -494,11 +494,8 @@ zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, zil_itx_assign(zilog, itx, tx); } -/* - * Handles TX_RENAME transactions. - */ -void -zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *sdzp, +static void +do_zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *sdzp, const char *sname, znode_t *tdzp, const char *dname, znode_t *szp) { itx_t *itx; @@ -520,6 +517,85 @@ zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *sdzp, zil_itx_assign(zilog, itx, tx); } +/* + * Handles TX_RENAME transactions. + */ +void +zfs_log_rename(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *sdzp, + const char *sname, znode_t *tdzp, const char *dname, znode_t *szp) +{ + txtype |= TX_RENAME; + do_zfs_log_rename(zilog, tx, txtype, sdzp, sname, tdzp, dname, szp); +} + +/* + * Handles TX_RENAME_EXCHANGE transactions. + */ +void +zfs_log_rename_exchange(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, + znode_t *sdzp, const char *sname, znode_t *tdzp, const char *dname, + znode_t *szp) +{ + txtype |= TX_RENAME_EXCHANGE; + do_zfs_log_rename(zilog, tx, txtype, sdzp, sname, tdzp, dname, szp); +} + +/* + * Handles TX_RENAME_WHITEOUT transactions. + * + * Unfortunately we cannot reuse do_zfs_log_rename because we we need to call + * zfs_mknode() on replay which requires stashing bits as with TX_CREATE. + */ +void +zfs_log_rename_whiteout(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, + znode_t *sdzp, const char *sname, znode_t *tdzp, const char *dname, + znode_t *szp, znode_t *wzp) +{ + itx_t *itx; + lr_rename_whiteout_t *lr; + size_t snamesize = strlen(sname) + 1; + size_t dnamesize = strlen(dname) + 1; + + if (zil_replaying(zilog, tx)) + return; + + txtype |= TX_RENAME_WHITEOUT; + itx = zil_itx_create(txtype, sizeof (*lr) + snamesize + dnamesize); + lr = (lr_rename_whiteout_t *)&itx->itx_lr; + lr->lr_rename.lr_sdoid = sdzp->z_id; + lr->lr_rename.lr_tdoid = tdzp->z_id; + + /* + * RENAME_WHITEOUT will create an entry at the source znode, so we need + * to store the same data that the equivalent call to zfs_log_create() + * would. + */ + lr->lr_wfoid = wzp->z_id; + LR_FOID_SET_SLOTS(lr->lr_wfoid, wzp->z_dnodesize >> DNODE_SHIFT); + (void) sa_lookup(wzp->z_sa_hdl, SA_ZPL_GEN(ZTOZSB(wzp)), &lr->lr_wgen, + sizeof (uint64_t)); + (void) sa_lookup(wzp->z_sa_hdl, SA_ZPL_CRTIME(ZTOZSB(wzp)), + lr->lr_wcrtime, sizeof (uint64_t) * 2); + lr->lr_wmode = wzp->z_mode; + lr->lr_wuid = (uint64_t)KUID_TO_SUID(ZTOUID(wzp)); + lr->lr_wgid = (uint64_t)KGID_TO_SGID(ZTOGID(wzp)); + + /* + * This rdev will always be makdevice(0, 0) but because the ZIL log and + * replay code needs to be platform independent (and there is no + * platform independent makdev()) we need to copy the one created + * during the rename operation. + */ + (void) sa_lookup(wzp->z_sa_hdl, SA_ZPL_RDEV(ZTOZSB(wzp)), &lr->lr_wrdev, + sizeof (lr->lr_wrdev)); + + memcpy((char *)(lr + 1), sname, snamesize); + memcpy((char *)(lr + 1) + snamesize, dname, dnamesize); + itx->itx_oid = szp->z_id; + + zil_itx_assign(zilog, itx, tx); +} + /* * zfs_log_write() handles TX_WRITE transactions. The specified callback is * called as soon as the write is on stable storage (be it via a DMU sync or a diff --git a/module/zfs/zfs_replay.c b/module/zfs/zfs_replay.c index 45c2fa3720cf..5e20ce3319b4 100644 --- a/module/zfs/zfs_replay.c +++ b/module/zfs/zfs_replay.c @@ -643,18 +643,21 @@ zfs_replay_link(void *arg1, void *arg2, boolean_t byteswap) } static int -zfs_replay_rename(void *arg1, void *arg2, boolean_t byteswap) +do_zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, char *sname, + char *tname, uint64_t rflags, vattr_t *wo_vap) { - zfsvfs_t *zfsvfs = arg1; - lr_rename_t *lr = arg2; - char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */ - char *tname = sname + strlen(sname) + 1; znode_t *sdzp, *tdzp; - int error; - int vflg = 0; + int error, vflg = 0; - if (byteswap) - byteswap_uint64_array(lr, sizeof (*lr)); + /* Only Linux currently supports RENAME_* flags. */ +#ifdef __linux__ + VERIFY0(rflags & ~(RENAME_EXCHANGE | RENAME_WHITEOUT)); + + /* wo_vap must be non-NULL iff. we're doing RENAME_WHITEOUT */ + VERIFY_EQUIV(rflags & RENAME_WHITEOUT, wo_vap != NULL); +#else + VERIFY0(rflags); +#endif if ((error = zfs_zget(zfsvfs, lr->lr_sdoid, &sdzp)) != 0) return (error); @@ -667,13 +670,94 @@ zfs_replay_rename(void *arg1, void *arg2, boolean_t byteswap) if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; - error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, NULL); + error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags, + wo_vap, NULL); zrele(tdzp); zrele(sdzp); return (error); } +static int +zfs_replay_rename(void *arg1, void *arg2, boolean_t byteswap) +{ + zfsvfs_t *zfsvfs = arg1; + lr_rename_t *lr = arg2; + char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */ + char *tname = sname + strlen(sname) + 1; + + if (byteswap) + byteswap_uint64_array(lr, sizeof (*lr)); + + return (do_zfs_replay_rename(zfsvfs, lr, sname, tname, 0, NULL)); +} + +static int +zfs_replay_rename_exchange(void *arg1, void *arg2, boolean_t byteswap) +{ +#ifdef __linux__ + zfsvfs_t *zfsvfs = arg1; + lr_rename_t *lr = arg2; + char *sname = (char *)(lr + 1); /* sname and tname follow lr_rename_t */ + char *tname = sname + strlen(sname) + 1; + + if (byteswap) + byteswap_uint64_array(lr, sizeof (*lr)); + + return (do_zfs_replay_rename(zfsvfs, lr, sname, tname, RENAME_EXCHANGE, + NULL)); +#else + return (SET_ERROR(ENOTSUP)); +#endif +} + +static int +zfs_replay_rename_whiteout(void *arg1, void *arg2, boolean_t byteswap) +{ +#ifdef __linux__ + zfsvfs_t *zfsvfs = arg1; + lr_rename_whiteout_t *lr = arg2; + int error; + /* sname and tname follow lr_rename_whiteout_t */ + char *sname = (char *)(lr + 1); + char *tname = sname + strlen(sname) + 1; + /* For the whiteout file. */ + xvattr_t xva; + uint64_t objid; + uint64_t dnodesize; + + if (byteswap) + byteswap_uint64_array(lr, sizeof (*lr)); + + objid = LR_FOID_GET_OBJ(lr->lr_wfoid); + dnodesize = LR_FOID_GET_SLOTS(lr->lr_wfoid) << DNODE_SHIFT; + + xva_init(&xva); + zfs_init_vattr(&xva.xva_vattr, ATTR_MODE | ATTR_UID | ATTR_GID, + lr->lr_wmode, lr->lr_wuid, lr->lr_wgid, lr->lr_wrdev, objid); + + /* + * As with TX_CREATE, RENAME_WHITEOUT ends up in zfs_mknode(), which + * assigns the object's creation time, generation number, and dnode + * slot count. The generic zfs_rename() has no concept of these + * attributes, so we smuggle the values inside the vattr's otherwise + * unused va_ctime, va_nblocks, and va_fsid fields. + */ + ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_wcrtime); + xva.xva_vattr.va_nblocks = lr->lr_wgen; + xva.xva_vattr.va_fsid = dnodesize; + + error = dnode_try_claim(zfsvfs->z_os, objid, dnodesize >> DNODE_SHIFT); + if (error) + return (error); + + return (do_zfs_replay_rename(zfsvfs, &lr->lr_rename, sname, tname, + RENAME_WHITEOUT, &xva.xva_vattr)); +#else + return (SET_ERROR(ENOTSUP)); +#endif +} + static int zfs_replay_write(void *arg1, void *arg2, boolean_t byteswap) { @@ -1069,4 +1153,6 @@ zil_replay_func_t *const zfs_replay_vector[TX_MAX_TYPE] = { zfs_replay_create_acl, /* TX_MKDIR_ACL_ATTR */ zfs_replay_write2, /* TX_WRITE2 */ zfs_replay_setsaxattr, /* TX_SETSAXATTR */ + zfs_replay_rename_exchange, /* TX_RENAME_EXCHANGE */ + zfs_replay_rename_whiteout, /* TX_RENAME_WHITEOUT */ }; diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 6bb99c4b1cdf..23afc8a40bb4 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -759,11 +759,9 @@ zil_commit_activate_saxattr_feature(zilog_t *zilog) uint64_t txg = 0; dmu_tx_t *tx = NULL; - if (spa_feature_is_enabled(zilog->zl_spa, - SPA_FEATURE_ZILSAXATTR) && + if (spa_feature_is_enabled(zilog->zl_spa, SPA_FEATURE_ZILSAXATTR) && dmu_objset_type(zilog->zl_os) != DMU_OST_ZVOL && - !dsl_dataset_feature_is_active(ds, - SPA_FEATURE_ZILSAXATTR)) { + !dsl_dataset_feature_is_active(ds, SPA_FEATURE_ZILSAXATTR)) { tx = dmu_tx_create(zilog->zl_os); VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); dsl_dataset_dirty(ds, tx); diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index be8ee34f27ae..20578a8223b2 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -514,6 +514,8 @@ zil_replay_func_t *const zvol_replay_vector[TX_MAX_TYPE] = { zvol_replay_err, /* TX_MKDIR_ACL_ATTR */ zvol_replay_err, /* TX_WRITE2 */ zvol_replay_err, /* TX_SETSAXATTR */ + zvol_replay_err, /* TX_RENAME_EXCHANGE */ + zvol_replay_err, /* TX_RENAME_WHITEOUT */ }; /* diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 21e0f882dc40..13f7efd96bd3 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -157,6 +157,10 @@ tags = ['functional', 'projectquota'] tests = ['read_dos_attrs_001', 'write_dos_attrs_001'] tags = ['functional', 'dos_attributes'] +[tests/functional/renameat2:Linux] +tests = ['renameat2_noreplace', 'renameat2_exchange', 'renameat2_whiteout'] +tags = ['functional', 'renameat2'] + [tests/functional/rsend:Linux] tests = ['send_realloc_dnode_size', 'send_encrypted_files'] tags = ['functional', 'rsend'] diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in index e7d338fcf8a9..1cebf50827b9 100755 --- a/tests/test-runner/bin/zts-report.py.in +++ b/tests/test-runner/bin/zts-report.py.in @@ -69,6 +69,11 @@ exec_reason = 'Test user execute permissions required for utilities' # python_deps_reason = 'Python modules missing: python3-cffi' +# +# Some tests require that the kernel supports renameat2 syscall. +# +renameat2_reason = 'Kernel renameat2 support required' + # # Some tests require the O_TMPFILE flag which was first introduced in the # 3.11 kernel. @@ -231,6 +236,7 @@ maybe = { 'pool_checkpoint/checkpoint_discard_busy': ['FAIL', 11946], 'projectquota/setup': ['SKIP', exec_reason], 'removal/removal_condense_export': ['FAIL', known_reason], + 'renameat2/setup': ['SKIP', renameat2_reason], 'reservation/reservation_008_pos': ['FAIL', 7741], 'reservation/reservation_018_pos': ['FAIL', 5642], 'snapshot/clone_001_pos': ['FAIL', known_reason], diff --git a/tests/zfs-tests/cmd/.gitignore b/tests/zfs-tests/cmd/.gitignore index 0ec450e248db..f68f58072818 100644 --- a/tests/zfs-tests/cmd/.gitignore +++ b/tests/zfs-tests/cmd/.gitignore @@ -27,6 +27,7 @@ /randwritecomp /read_dos_attributes /readmmap +/renameat2 /rename_dir /rm_lnkcnt_zero_file /send_doall diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index 673a18b4c083..066abb6ce3b5 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -112,10 +112,10 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/edonr_test %D%/skein_test \ %C%_edonr_test_LDADD = $(%C%_skein_test_LDADD) %C%_blake3_test_LDADD = $(%C%_skein_test_LDADD) - if BUILD_LINUX scripts_zfs_tests_bin_PROGRAMS += %D%/getversion scripts_zfs_tests_bin_PROGRAMS += %D%/user_ns_exec +scripts_zfs_tests_bin_PROGRAMS += %D%/renameat2 scripts_zfs_tests_bin_PROGRAMS += %D%/xattrtest scripts_zfs_tests_bin_PROGRAMS += %D%/zed_fd_spill-zedlet scripts_zfs_tests_bin_PROGRAMS += %D%/idmap_util @@ -127,7 +127,6 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/read_dos_attributes %D%/write_dos_attribu %C%_read_dos_attributes_SOURCES = %D%/linux_dos_attributes/read_dos_attributes.c %C%_write_dos_attributes_SOURCES = %D%/linux_dos_attributes/write_dos_attributes.c - scripts_zfs_tests_bin_PROGRAMS += %D%/randfree_file %C%_randfree_file_SOURCES = %D%/file/randfree_file.c diff --git a/tests/zfs-tests/cmd/renameat2.c b/tests/zfs-tests/cmd/renameat2.c new file mode 100644 index 000000000000..a9d0a8b20adf --- /dev/null +++ b/tests/zfs-tests/cmd/renameat2.c @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: CDDL-1.0 OR MPL-2.0 */ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (C) 2019 Aleksa Sarai + * Copyright (C) 2019 SUSE LLC + */ + +/* + * mv(1) doesn't currently support RENAME_{EXCHANGE,WHITEOUT} so this is a very + * simple renameat2(2) wrapper for the OpenZFS self-tests. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef SYS_renameat2 +#ifdef __NR_renameat2 +#define SYS_renameat2 __NR_renameat2 +#elif defined(__x86_64__) +#define SYS_renameat2 316 +#elif defined(__i386__) +#define SYS_renameat2 353 +#elif defined(__arm__) || defined(__aarch64__) +#define SYS_renameat2 382 +#else +#error "SYS_renameat2 not known for this architecture." +#endif +#endif + +#ifndef RENAME_NOREPLACE +#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */ +#endif +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ +#endif +#ifndef RENAME_WHITEOUT +#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */ +#endif + +/* glibc doesn't provide renameat2 wrapper, let's use our own */ +static int +sys_renameat2(int olddirfd, const char *oldpath, + int newdirfd, const char *newpath, unsigned int flags) +{ + int ret = syscall(SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, + flags); + return ((ret < 0) ? -errno : ret); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: renameat2 [-Cnwx] src dst\n"); + exit(1); +} + +static void +check(void) +{ + int err = sys_renameat2(AT_FDCWD, ".", AT_FDCWD, ".", RENAME_EXCHANGE); + exit(err == -ENOSYS); +} + +int +main(int argc, char **argv) +{ + char *src, *dst; + int ch, err; + unsigned int flags = 0; + + while ((ch = getopt(argc, argv, "Cnwx")) >= 0) { + switch (ch) { + case 'C': + check(); + break; + case 'n': + flags |= RENAME_NOREPLACE; + break; + case 'w': + flags |= RENAME_WHITEOUT; + break; + case 'x': + flags |= RENAME_EXCHANGE; + break; + default: + usage(); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + src = argv[0]; + dst = argv[1]; + + err = sys_renameat2(AT_FDCWD, src, AT_FDCWD, dst, flags); + if (err < 0) + fprintf(stderr, "renameat2: %s", strerror(-err)); + return (err != 0); +} diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg index 30514361ad57..b3cfe149ffa7 100644 --- a/tests/zfs-tests/include/commands.cfg +++ b/tests/zfs-tests/include/commands.cfg @@ -208,6 +208,7 @@ export ZFSTEST_FILES='badsend randwritecomp readmmap read_dos_attributes + renameat2 rename_dir rm_lnkcnt_zero_file send_doall diff --git a/tests/zfs-tests/tests/functional/renameat2/Makefile.am b/tests/zfs-tests/tests/functional/renameat2/Makefile.am new file mode 100644 index 000000000000..bd8d6c9d68bf --- /dev/null +++ b/tests/zfs-tests/tests/functional/renameat2/Makefile.am @@ -0,0 +1,7 @@ +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/renameat2 +dist_pkgdata_SCRIPTS = \ + setup.ksh \ + cleanup.ksh \ + renameat2_noreplace.ksh \ + renameat2_exchange.ksh \ + renameat2_whiteout.ksh diff --git a/tests/zfs-tests/tests/functional/renameat2/cleanup.ksh b/tests/zfs-tests/tests/functional/renameat2/cleanup.ksh new file mode 100755 index 000000000000..3166bd6ec16e --- /dev/null +++ b/tests/zfs-tests/tests/functional/renameat2/cleanup.ksh @@ -0,0 +1,34 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# +# Copyright (c) 2013 by Delphix. All rights reserved. +# + +. $STF_SUITE/include/libtest.shlib + +default_cleanup diff --git a/tests/zfs-tests/tests/functional/renameat2/renameat2_exchange.ksh b/tests/zfs-tests/tests/functional/renameat2/renameat2_exchange.ksh new file mode 100755 index 000000000000..94e56231feb1 --- /dev/null +++ b/tests/zfs-tests/tests/functional/renameat2/renameat2_exchange.ksh @@ -0,0 +1,61 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (C) 2019 Aleksa Sarai +# Copyright (C) 2019 SUSE LLC +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "both" + +function cleanup +{ + log_must rm -rf $TESTDIR/* +} + +log_assert "ZFS supports RENAME_EXCHANGE." +log_onexit cleanup + +cd $TESTDIR +echo "foo" > foo +echo "bar" > bar + +# Self-exchange is a no-op. +log_must renameat2 -x foo foo +log_must grep '^foo$' foo + +# Basic exchange. +log_must renameat2 -x foo bar +log_must grep '^bar$' foo +log_must grep '^foo$' bar + +# And exchange back. +log_must renameat2 -x foo bar +log_must grep '^foo$' foo +log_must grep '^bar$' bar + +# Exchange with a bad path should fail. +log_mustnot renameat2 -x bar baz + +log_pass "ZFS supports RENAME_EXCHANGE as expected." diff --git a/tests/zfs-tests/tests/functional/renameat2/renameat2_noreplace.ksh b/tests/zfs-tests/tests/functional/renameat2/renameat2_noreplace.ksh new file mode 100755 index 000000000000..d75b94fab465 --- /dev/null +++ b/tests/zfs-tests/tests/functional/renameat2/renameat2_noreplace.ksh @@ -0,0 +1,51 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (C) 2019 Aleksa Sarai +# Copyright (C) 2019 SUSE LLC +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "both" + +function cleanup +{ + log_must rm -rf $TESTDIR/* +} + +log_assert "ZFS supports RENAME_NOREPLACE." +log_onexit cleanup + +cd $TESTDIR +touch foo bar + +# Clobbers should always fail. +log_mustnot renameat2 -n foo foo +log_mustnot renameat2 -n foo bar +log_mustnot renameat2 -n bar foo + +# Regular renames should succeed. +log_must renameat2 -n bar baz + +log_pass "ZFS supports RENAME_NOREPLACE as expected." diff --git a/tests/zfs-tests/tests/functional/renameat2/renameat2_whiteout.ksh b/tests/zfs-tests/tests/functional/renameat2/renameat2_whiteout.ksh new file mode 100755 index 000000000000..8ecb074dbbdb --- /dev/null +++ b/tests/zfs-tests/tests/functional/renameat2/renameat2_whiteout.ksh @@ -0,0 +1,50 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (C) 2019 Aleksa Sarai +# Copyright (C) 2019 SUSE LLC +# + +. $STF_SUITE/include/libtest.shlib + +verify_runnable "both" + +function cleanup +{ + log_must rm -rf $TESTDIR/* +} + +log_assert "ZFS supports RENAME_WHITEOUT." +log_onexit cleanup + +cd $TESTDIR +echo "whiteout" > whiteout + +# Straight-forward rename-with-whiteout. +log_must renameat2 -w whiteout new +# Check new file. +log_must grep '^whiteout$' new +# Check that the whiteout is actually a {0,0} char device. +log_must grep '^character special file:0:0$' <<<"$(stat -c '%F:%t:%T' whiteout)" + +log_pass "ZFS supports RENAME_WHITEOUT as expected." diff --git a/tests/zfs-tests/tests/functional/renameat2/setup.ksh b/tests/zfs-tests/tests/functional/renameat2/setup.ksh new file mode 100755 index 000000000000..b8c26d5ba062 --- /dev/null +++ b/tests/zfs-tests/tests/functional/renameat2/setup.ksh @@ -0,0 +1,37 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (C) 2019 Aleksa Sarai +# Copyright (C) 2019 SUSE LLC +# + +. $STF_SUITE/include/libtest.shlib + +if ! is_linux ; then + log_unsupported "renameat2 is linux-only" +elif ! renameat2 -C ; then + log_unsupported "renameat2 not supported on this (pre-3.15) linux kernel" +fi + +DISK=${DISKS%% *} +default_setup $DISK diff --git a/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh b/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh index eddecbc2db7e..8f3585a5997f 100755 --- a/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh +++ b/tests/zfs-tests/tests/functional/slog/slog_replay_fs_001.ksh @@ -175,6 +175,29 @@ log_must ln /$TESTPOOL/$TESTFS/link_and_unlink \ /$TESTPOOL/$TESTFS/link_and_unlink.link log_must rm /$TESTPOOL/$TESTFS/link_and_unlink.link +# We can't test RENAME_* flags without renameat2(2) support. +if ! is_linux ; then + log_note "renameat2 is linux-only" +elif ! renameat2 -C ; then + log_note "renameat2 not supported on this (pre-3.15) linux kernel" +else + # TX_RENAME_EXCHANGE + log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/xchg-a bs=1k count=1 + log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/xchg-b bs=1k count=1 + log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/xchg-c bs=1k count=1 + log_must dd if=/dev/urandom of=/$TESTPOOL/$TESTFS/xchg-d bs=1k count=1 + # rotate the files around + log_must renameat2 -x /$TESTPOOL/$TESTFS/xchg-{a,b} + log_must renameat2 -x /$TESTPOOL/$TESTFS/xchg-{b,c} + log_must renameat2 -x /$TESTPOOL/$TESTFS/xchg-{c,a} + # exchange same path + log_must renameat2 -x /$TESTPOOL/$TESTFS/xchg-{d,d} + + # TX_RENAME_WHITEOUT + log_must mkfile 1k /$TESTPOOL/$TESTFS/whiteout + log_must renameat2 -w /$TESTPOOL/$TESTFS/whiteout{,-moved} +fi + # # 4. Copy TESTFS to temporary location (TESTDIR/copy) # From 7822b50f548e6ca73faa6f0d2de029e981be1d73 Mon Sep 17 00:00:00 2001 From: vaclavskala <33496485+vaclavskala@users.noreply.github.com> Date: Fri, 28 Oct 2022 19:16:31 +0200 Subject: [PATCH 073/126] Propagate extent_bytes change to autotrim thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The autotrim thread only reads zfs_trim_extent_bytes_min and zfs_trim_extent_bytes_max variable only on thread start. We should check for parameter changes during thread execution to allow parameter changes take effect without needing to disable then restart the autotrim. Reviewed-by: Brian Behlendorf Signed-off-by: VĂĄclav SkĂĄla Closes #14077 --- module/zfs/vdev_trim.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/module/zfs/vdev_trim.c b/module/zfs/vdev_trim.c index 5905d9a07571..5b5076c8722c 100644 --- a/module/zfs/vdev_trim.c +++ b/module/zfs/vdev_trim.c @@ -1188,12 +1188,11 @@ vdev_autotrim_thread(void *arg) mutex_exit(&vd->vdev_autotrim_lock); spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER); - uint64_t extent_bytes_max = zfs_trim_extent_bytes_max; - uint64_t extent_bytes_min = zfs_trim_extent_bytes_min; - while (!vdev_autotrim_should_stop(vd)) { int txgs_per_trim = MAX(zfs_trim_txg_batch, 1); boolean_t issued_trim = B_FALSE; + uint64_t extent_bytes_max = zfs_trim_extent_bytes_max; + uint64_t extent_bytes_min = zfs_trim_extent_bytes_min; /* * All of the metaslabs are divided in to groups of size From dc56c673e3b0d206f1d3fca66fdf5f6a46dbc4b2 Mon Sep 17 00:00:00 2001 From: shodanshok Date: Fri, 28 Oct 2022 19:21:54 +0200 Subject: [PATCH 074/126] Fix ARC target collapse when zfs_arc_meta_limit_percent=100 Reclaim metadata when arc_available_memory < 0 even if meta_used is not bigger than arc_meta_limit. As described in https://github.com/openzfs/zfs/issues/14054 if zfs_arc_meta_limit_percent=100 then ARC target can collapse to arc_min due to arc_purge not freeing any metadata. This patch lets arc_prune to do its work when arc_available_memory is negative even if meta_used is not bigger than arc_meta_limit, avoiding ARC target collapse. Reviewed-by: Brian Behlendorf Signed-off-by: Gionatan Danti Closes #14054 Closes #14093 --- module/zfs/arc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 936bcb5e3efb..1f97631f974f 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -4469,7 +4469,7 @@ arc_evict_meta_balanced(uint64_t meta_used) * meta buffers. Requests to the upper layers will be made with * increasingly large scan sizes until the ARC is below the limit. */ - if (meta_used > arc_meta_limit) { + if (meta_used > arc_meta_limit || arc_available_memory() < 0) { if (type == ARC_BUFC_DATA) { type = ARC_BUFC_METADATA; } else { From 8af08a69cda63e6d7983fc2f32f9fed4155b95be Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Fri, 28 Oct 2022 20:44:18 +0200 Subject: [PATCH 075/126] quota: extend quota for dataset This patch relax the quota limitation for dataset by around 3%. What this means is that user can write more data then the quota is set to. However thanks to that we can get more stable bandwidth, in case when we are overwriting data in-place, and not consuming any additional space. Reviewed-by: Brian Behlendorf Signed-off-by: Allan Jude Signed-off-by: Mariusz Zaborski Sponsored-by: Zededa Inc. Sponsored-by: Klara Inc. Closes #13839 --- module/zfs/dsl_dir.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index d93c7f08c1c2..15af67ba8560 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -1268,6 +1268,7 @@ dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree, uint64_t quota; struct tempreserve *tr; int retval; + uint64_t ext_quota; uint64_t ref_rsrv; top_of_function: @@ -1343,7 +1344,16 @@ dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree, * on-disk is over quota and there are no pending changes * or deferred frees (which may free up space for us). */ - if (used_on_disk + est_inflight >= quota) { + ext_quota = quota >> 5; + if (quota == UINT64_MAX) + ext_quota = 0; + + if (used_on_disk >= quota) { + /* Quota exceeded */ + mutex_exit(&dd->dd_lock); + DMU_TX_STAT_BUMP(dmu_tx_quota); + return (retval); + } else if (used_on_disk + est_inflight >= quota + ext_quota) { if (est_inflight > 0 || used_on_disk < quota) { retval = SET_ERROR(ERESTART); } else { From 5f0a48c7c95d938e4cb0ae3ee864241b324853b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rob=20N=20=E2=98=85?= Date: Sat, 29 Oct 2022 05:46:44 +1100 Subject: [PATCH 076/126] debug: fix output from VERIFY0 assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous version reported all the right info, but the VERIFY3 name made a little more confusing when looking for the matching location in the source code. Reviewed-by: Brian Behlendorf Reviewed-by: Richard Yao Signed-off-by: Rob N ★ Closes #14099 --- include/os/freebsd/spl/sys/debug.h | 2 +- include/os/linux/spl/sys/debug.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/os/freebsd/spl/sys/debug.h b/include/os/freebsd/spl/sys/debug.h index 91e2cfe5539c..3e67cf0e9a7d 100644 --- a/include/os/freebsd/spl/sys/debug.h +++ b/include/os/freebsd/spl/sys/debug.h @@ -131,7 +131,7 @@ spl_assert(const char *buf, const char *file, const char *func, int line) const int64_t _verify3_right = (int64_t)(RIGHT); \ if (unlikely(!(_verify3_left == _verify3_right))) \ spl_panic(__FILE__, __FUNCTION__, __LINE__, \ - "VERIFY3(0 == " #RIGHT ") " \ + "VERIFY0(0 == " #RIGHT ") " \ "failed (0 == %lld)\n", \ (long long) (_verify3_right)); \ } while (0) diff --git a/include/os/linux/spl/sys/debug.h b/include/os/linux/spl/sys/debug.h index 8bdc0b1d72d5..007238574fe1 100644 --- a/include/os/linux/spl/sys/debug.h +++ b/include/os/linux/spl/sys/debug.h @@ -135,7 +135,7 @@ spl_assert(const char *buf, const char *file, const char *func, int line) const int64_t _verify3_right = (int64_t)(RIGHT); \ if (unlikely(!(_verify3_left == _verify3_right))) \ spl_panic(__FILE__, __FUNCTION__, __LINE__, \ - "VERIFY3(0 == " #RIGHT ") " \ + "VERIFY0(0 == " #RIGHT ") " \ "failed (0 == %lld)\n", \ (long long) (_verify3_right)); \ } while (0) From 82ad2a06ac4e379fa67ff69901a1a70c86fd8f01 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Fri, 28 Oct 2022 13:25:37 -0700 Subject: [PATCH 077/126] Revert "Cleanup: Delete dead code from send_merge_thread()" This reverts commit fb823de9f due to a regression. It is in fact possible for the range->eos_marker to be false on error. Reviewed-by: Richard Yao Signed-off-by: Brian Behlendorf Issue #14042 Closes #14104 --- module/zfs/dmu_send.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 8c96a862762f..ccb7eb20756d 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -1586,8 +1586,9 @@ send_merge_thread(void *arg) } range_free(front_ranges[i]); } - ASSERT3P(range, !=, NULL); - ASSERT3S(range->eos_marker, ==, B_TRUE); + if (range == NULL) + range = kmem_zalloc(sizeof (*range), KM_SLEEP); + range->eos_marker = B_TRUE; bqueue_enqueue_flush(&smt_arg->q, range, 1); spl_fstrans_unmark(cookie); thread_exit(); From 4170ae4ea600fea6ac9daa8b145960c9de3915fc Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 11:03:48 -0400 Subject: [PATCH 078/126] Fix TOCTOU race conditions reported by CodeQL and Coverity CodeQL and Coverity both complained about: * lib/libshare/os/linux/smb.c * tests/zfs-tests/cmd/mmapwrite.c * twice * tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c * tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c * coverity had a second complaint that CodeQL did not have * tests/zfs-tests/cmd/suid_write_to_file.c * Coverity had two complaints and CodeQL had one complaint, both differed. The CodeQL complaint is about the main point of the test, so it is not fixable without a hack involving `fork()`. The issues reported by CodeQL are fixed, with the exception of the last one, which is deemed to be a false positive that is too much trouble to wrokaround. The issues reported by Coverity were only fixed if CodeQL complained about them. There were issues reported by Coverity in a number of other files that were not reported by CodeQL, but fixing the CodeQL complaints is considered a priority since we want to integrate it into a github workflow, so the remaining Coverity complaints are left for future work. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14098 --- lib/libshare/os/linux/smb.c | 19 +++++++++++--- tests/zfs-tests/cmd/mmapwrite.c | 14 +++-------- .../functional/tmpfile/tmpfile_002_pos.c | 7 ++---- .../functional/tmpfile/tmpfile_stat_mode.c | 25 +++++++++++-------- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/libshare/os/linux/smb.c b/lib/libshare/os/linux/smb.c index 157b19aa85f4..8eb1894de531 100644 --- a/lib/libshare/os/linux/smb.c +++ b/lib/libshare/os/linux/smb.c @@ -90,21 +90,32 @@ smb_retrieve_shares(void) /* Go through the directory, looking for shares */ while ((directory = readdir(shares_dir))) { + int fd; + if (directory->d_name[0] == '.') continue; snprintf(file_path, sizeof (file_path), "%s/%s", SHARE_DIR, directory->d_name); - if (stat(file_path, &eStat) == -1) { + if ((fd = open(file_path, O_RDONLY | O_CLOEXEC)) == -1) { rc = SA_SYSTEM_ERR; goto out; } - if (!S_ISREG(eStat.st_mode)) - continue; + if (stat(file_path, &eStat) == -1) { + close(fd); + rc = SA_SYSTEM_ERR; + goto out; + } - if ((share_file_fp = fopen(file_path, "re")) == NULL) { + if (!S_ISREG(eStat.st_mode)) { + close(fd); + continue; + } + + if ((share_file_fp = fdopen(fd, "r")) == NULL) { + close(fd); rc = SA_SYSTEM_ERR; goto out; } diff --git a/tests/zfs-tests/cmd/mmapwrite.c b/tests/zfs-tests/cmd/mmapwrite.c index ca55d730fd34..a18609898485 100644 --- a/tests/zfs-tests/cmd/mmapwrite.c +++ b/tests/zfs-tests/cmd/mmapwrite.c @@ -88,29 +88,21 @@ map_writer(void *filename) int ret = 0; char *buf = NULL; int page_size = getpagesize(); - int op_errno = 0; char *file_path = filename; while (1) { - ret = access(file_path, F_OK); - if (ret) { - op_errno = errno; - if (op_errno == ENOENT) { + fd = open(file_path, O_RDWR); + if (fd == -1) { + if (errno == ENOENT) { fd = open(file_path, O_RDWR | O_CREAT, 0777); if (fd == -1) { err(1, "open file failed"); } - ret = ftruncate(fd, page_size); if (ret == -1) { err(1, "truncate file failed"); } } else { - err(1, "access file failed!"); - } - } else { - fd = open(file_path, O_RDWR, 0777); - if (fd == -1) { err(1, "open file failed"); } } diff --git a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c index 424231d112b2..906b81b4d9b3 100644 --- a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c +++ b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_002_pos.c @@ -46,7 +46,6 @@ main(void) int i, fd; char spath[1024], dpath[1024]; const char *penv[] = {"TESTDIR", "TESTFILE0"}; - struct stat sbuf; (void) fprintf(stdout, "Verify O_TMPFILE file can be linked.\n"); @@ -73,12 +72,10 @@ main(void) run("export"); run("import"); - if (stat(dpath, &sbuf) < 0) { - perror("stat"); - unlink(dpath); + if (unlink(dpath) == -1) { + perror("unlink"); exit(5); } - unlink(dpath); return (0); } diff --git a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c index 4c34aec8bdb4..1a934a8b1852 100644 --- a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c +++ b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c @@ -48,7 +48,7 @@ static void test_stat_mode(mode_t mask) { - struct stat st, fst; + struct stat fst; int i, fd; char spath[1024], dpath[1024]; const char *penv[] = {"TESTDIR", "TESTFILE0"}; @@ -68,7 +68,7 @@ test_stat_mode(mode_t mask) err(2, "open(%s)", penv[0]); if (fstat(fd, &fst) == -1) - err(3, "open"); + err(3, "fstat(%s)", penv[0]); snprintf(spath, sizeof (spath), "/proc/self/fd/%d", fd); snprintf(dpath, sizeof (dpath), "%s/%s", penv[0], penv[1]); @@ -78,19 +78,22 @@ test_stat_mode(mode_t mask) err(4, "linkat"); close(fd); - if (stat(dpath, &st) == -1) - err(5, "stat"); - unlink(dpath); - - /* Verify fstat(2) result */ + /* Verify fstat(2) result at old path */ mode = fst.st_mode & 0777; if (mode != masked) - errx(6, "fstat(2) %o != %o\n", mode, masked); + errx(5, "fstat(2) %o != %o\n", mode, masked); - /* Verify stat(2) result */ - mode = st.st_mode & 0777; + fd = open(dpath, O_RDWR); + if (fd == -1) + err(6, "open(%s)", dpath); + + if (fstat(fd, &fst) == -1) + err(7, "fstat(%s)", dpath); + + /* Verify fstat(2) result at new path */ + mode = fst.st_mode & 0777; if (mode != masked) - errx(7, "stat(2) %o != %o\n", mode, masked); + errx(8, "fstat(2) %o != %o\n", mode, masked); } int From d71d69326116756e69b2d7bee4582f00de27ec72 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 12:45:26 -0400 Subject: [PATCH 079/126] Fix too few arguments to formatting function CodeQL reported that when the VERIFY3U condition is false, we do not pass enough arguments to `spl_panic()`. This is because the format string from `snprintf()` was concatenated into the format string for `spl_panic()`, which causes us to have an unexpected format specifier. A CodeQL developer suggested fixing the macro to have a `%s` format string that takes a stringified RIGHT argument, which would fix this. However, upon inspection, the VERIFY3U check was never necessary in the first place, so we remove it in favor of just calling `snprintf()`. Lastly, it is interesting that every other static analyzer run on the codebase did not catch this, including some that made an effort to catch such things. Presumably, all of them relied on header annotations, which we have not yet done on `spl_panic()`. CodeQL apparently is able to track the flow of arguments on their way to annotated functions, which llowed it to catch this when others did not. A future patch that I have in development should annotate `spl_panic()`, so the others will catch this too. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14098 --- module/zfs/zcp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/zfs/zcp.c b/module/zfs/zcp.c index 2b79f0a2a04a..5ebf1bbbc8cc 100644 --- a/module/zfs/zcp.c +++ b/module/zfs/zcp.c @@ -277,9 +277,9 @@ zcp_table_to_nvlist(lua_State *state, int index, int depth) } break; case LUA_TNUMBER: - VERIFY3U(sizeof (buf), >, - snprintf(buf, sizeof (buf), "%lld", - (longlong_t)lua_tonumber(state, -2))); + (void) snprintf(buf, sizeof (buf), "%lld", + (longlong_t)lua_tonumber(state, -2)); + key = buf; if (saw_str_could_collide) { key_could_collide = B_TRUE; From 2e08df84d8649439e5e9ed39ea13d4b755ee97c9 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 15:41:39 -0400 Subject: [PATCH 080/126] Cleanup dump_bookmarks() Assertions are meant to check assumptions, but the way that this assertion is written does not check an assumption, since it is provably always true. Removing the assertion will cause a compiler warning (made into an error by -Werror) about printing up to 512 bytes to a 256-byte buffer, so instead, we change the assertion to verify the assumption that we never do a snprintf() that is truncated to avoid overrunning the 256-byte buffer. This was caught by an audit of the codebase to look for misuse of `snprintf()` after CodeQL reported that we had misused `snprintf()`. An explanation of how snprintf() can be misused is here: https://www.redhat.com/en/blog/trouble-snprintf This particular instance did not misuse `snprintf()`, but it was caught by the audit anyway. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14098 --- cmd/zdb/zdb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index d626d082440f..d19eb71f0f69 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -2858,9 +2858,11 @@ dump_bookmarks(objset_t *os, int verbosity) zap_cursor_advance(&zc)) { char osname[ZFS_MAX_DATASET_NAME_LEN]; char buf[ZFS_MAX_DATASET_NAME_LEN]; + int len; dmu_objset_name(os, osname); - VERIFY3S(0, <=, snprintf(buf, sizeof (buf), "%s#%s", osname, - attr.za_name)); + len = snprintf(buf, sizeof (buf), "%s#%s", osname, + attr.za_name); + VERIFY3S(len, <, ZFS_MAX_DATASET_NAME_LEN); (void) dump_bookmark(dp, buf, verbosity >= 5, verbosity >= 6); } zap_cursor_fini(&zc); From 97143b9d314d54409244f3995576d8cc8c1ebf0a Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 27 Oct 2022 14:16:04 -0400 Subject: [PATCH 081/126] Introduce kmem_scnprintf() `snprintf()` is meant to protect against buffer overflows, but operating on the buffer using its return value, possibly by calling it again, can cause a buffer overflow, because it will return how many characters it would have written if it had enough space even when it did not. In a number of places, we repeatedly call snprintf() by successively incrementing a buffer offset and decrementing a buffer length, by its return value. This is a potentially unsafe usage of `snprintf()` whenever the buffer length is reached. CodeQL complained about this. To fix this, we introduce `kmem_scnprintf()`, which will return 0 when the buffer is zero or the number of written characters, minus 1 to exclude the NULL character, when the buffer was too small. In all other cases, it behaves like snprintf(). The name is inspired by the Linux and XNU kernels' `scnprintf()`. The implementation was written before I thought to look at `scnprintf()` and had a good name for it, but it turned out to have identical semantics to the Linux kernel version. That lead to the name, `kmem_scnprintf()`. CodeQL only catches this issue in loops, so repeated use of snprintf() outside of a loop was not caught. As a result, a thorough audit of the codebase was done to examine all instances of `snprintf()` usage for potential problems and a few were caught. Fixes for them are included in this patch. Unfortunately, ZED is one of the places where `snprintf()` is potentially used incorrectly. Since using `kmem_scnprintf()` in it would require changing how it is linked, we modify its usage to make it safe, no matter what buffer length is used. In addition, there was a bug in the use of the return value where the NULL format character was not being written by pwrite(). That has been fixed. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14098 --- cmd/zed/zed_event.c | 6 ++++- include/os/freebsd/spl/sys/kmem.h | 3 +++ include/os/linux/spl/sys/kmem.h | 2 ++ include/sys/spa.h | 2 +- include/sys/zfs_context.h | 3 +++ lib/libspl/os/linux/zone.c | 2 +- lib/libzfs/os/freebsd/libzfs_compat.c | 2 +- lib/libzpool/kernel.c | 29 ++++++++++++++++++++ module/os/freebsd/spl/spl_string.c | 30 +++++++++++++++++++++ module/os/linux/zfs/zfs_sysfs.c | 6 ++--- module/zfs/dataset_kstats.c | 7 ++++- module/zfs/spa_misc.c | 2 +- module/zfs/vdev_raidz_math.c | 23 ++++++++-------- module/zfs/zfs_chksum.c | 38 +++++++++++++-------------- 14 files changed, 116 insertions(+), 39 deletions(-) diff --git a/cmd/zed/zed_event.c b/cmd/zed/zed_event.c index 079c6a043e5d..ebd6851a2a86 100644 --- a/cmd/zed/zed_event.c +++ b/cmd/zed/zed_event.c @@ -139,8 +139,12 @@ _bump_event_queue_length(void) if (qlen == orig_qlen) goto done; wr = snprintf(qlen_buf, sizeof (qlen_buf), "%ld", qlen); + if (wr >= sizeof (qlen_buf)) { + wr = sizeof (qlen_buf) - 1; + zed_log_msg(LOG_WARNING, "Truncation in %s()", __func__); + } - if (pwrite(zzlm, qlen_buf, wr, 0) < 0) + if (pwrite(zzlm, qlen_buf, wr + 1, 0) < 0) goto done; zed_log_msg(LOG_WARNING, "Bumping queue length to %ld", qlen); diff --git a/include/os/freebsd/spl/sys/kmem.h b/include/os/freebsd/spl/sys/kmem.h index ae2941b80912..27d290863c0b 100644 --- a/include/os/freebsd/spl/sys/kmem.h +++ b/include/os/freebsd/spl/sys/kmem.h @@ -57,6 +57,9 @@ extern char *kmem_asprintf(const char *, ...) extern char *kmem_vasprintf(const char *fmt, va_list ap) __attribute__((format(printf, 1, 0))); +extern int kmem_scnprintf(char *restrict str, size_t size, + const char *restrict fmt, ...); + typedef struct kmem_cache { char kc_name[32]; #if !defined(KMEM_DEBUG) diff --git a/include/os/linux/spl/sys/kmem.h b/include/os/linux/spl/sys/kmem.h index 86e872fa2492..111924303e16 100644 --- a/include/os/linux/spl/sys/kmem.h +++ b/include/os/linux/spl/sys/kmem.h @@ -38,6 +38,8 @@ extern char *kmem_asprintf(const char *fmt, ...) extern char *kmem_strdup(const char *str); extern void kmem_strfree(char *str); +#define kmem_scnprintf scnprintf + /* * Memory allocation interfaces */ diff --git a/include/sys/spa.h b/include/sys/spa.h index 8dcd8895ba22..b260dd32820e 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -600,7 +600,7 @@ typedef struct blkptr { /* * This macro allows code sharing between zfs, libzpool, and mdb. - * 'func' is either snprintf() or mdb_snprintf(). + * 'func' is either kmem_scnprintf() or mdb_snprintf(). * 'ws' (whitespace) can be ' ' for single-line format, '\n' for multi-line. */ diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index d29d7118ff00..0d31195447d1 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -695,6 +695,9 @@ extern char *kmem_asprintf(const char *fmt, ...); #define kmem_strfree(str) kmem_free((str), strlen(str) + 1) #define kmem_strdup(s) strdup(s) +extern int kmem_scnprintf(char *restrict str, size_t size, + const char *restrict fmt, ...); + /* * Hostname information */ diff --git a/lib/libspl/os/linux/zone.c b/lib/libspl/os/linux/zone.c index e37b34975df6..622d04cbc14a 100644 --- a/lib/libspl/os/linux/zone.c +++ b/lib/libspl/os/linux/zone.c @@ -41,7 +41,7 @@ getzoneid(void) int c = snprintf(path, sizeof (path), "/proc/self/ns/user"); /* This API doesn't have any error checking... */ - if (c < 0) + if (c < 0 || c >= sizeof (path)) return (0); ssize_t r = readlink(path, buf, sizeof (buf) - 1); diff --git a/lib/libzfs/os/freebsd/libzfs_compat.c b/lib/libzfs/os/freebsd/libzfs_compat.c index f4900943c4af..5e280cbae935 100644 --- a/lib/libzfs/os/freebsd/libzfs_compat.c +++ b/lib/libzfs/os/freebsd/libzfs_compat.c @@ -202,7 +202,7 @@ libzfs_error_init(int error) size_t msglen = sizeof (errbuf); if (modfind("zfs") < 0) { - size_t len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN, + size_t len = kmem_scnprintf(msg, msglen, dgettext(TEXT_DOMAIN, "Failed to load %s module: "), ZFS_KMOD); msg += len; msglen -= len; diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 1f58acb0404f..1d46470947d3 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -956,6 +956,35 @@ kmem_asprintf(const char *fmt, ...) return (buf); } +/* + * kmem_scnprintf() will return the number of characters that it would have + * printed whenever it is limited by value of the size variable, rather than + * the number of characters that it did print. This can cause misbehavior on + * subsequent uses of the return value, so we define a safe version that will + * return the number of characters actually printed, minus the NULL format + * character. Subsequent use of this by the safe string functions is safe + * whether it is snprintf(), strlcat() or strlcpy(). + */ +int +kmem_scnprintf(char *restrict str, size_t size, const char *restrict fmt, ...) +{ + int n; + va_list ap; + + /* Make the 0 case a no-op so that we do not return -1 */ + if (size == 0) + return (0); + + va_start(ap, fmt); + n = vsnprintf(str, size, fmt, ap); + va_end(ap); + + if (n >= size) + n = size - 1; + + return (n); +} + zfs_file_t * zfs_onexit_fd_hold(int fd, minor_t *minorp) { diff --git a/module/os/freebsd/spl/spl_string.c b/module/os/freebsd/spl/spl_string.c index 523e10ff6936..eb74720c984a 100644 --- a/module/os/freebsd/spl/spl_string.c +++ b/module/os/freebsd/spl/spl_string.c @@ -105,3 +105,33 @@ kmem_strfree(char *str) ASSERT3P(str, !=, NULL); kmem_free(str, strlen(str) + 1); } + +/* + * kmem_scnprintf() will return the number of characters that it would have + * printed whenever it is limited by value of the size variable, rather than + * the number of characters that it did print. This can cause misbehavior on + * subsequent uses of the return value, so we define a safe version that will + * return the number of characters actually printed, minus the NULL format + * character. Subsequent use of this by the safe string functions is safe + * whether it is snprintf(), strlcat() or strlcpy(). + */ + +int +kmem_scnprintf(char *restrict str, size_t size, const char *restrict fmt, ...) +{ + int n; + va_list ap; + + /* Make the 0 case a no-op so that we do not return -1 */ + if (size == 0) + return (0); + + va_start(ap, fmt); + n = vsnprintf(str, size, fmt, ap); + va_end(ap); + + if (n >= size) + n = size - 1; + + return (n); +} diff --git a/module/os/linux/zfs/zfs_sysfs.c b/module/os/linux/zfs/zfs_sysfs.c index 4a2091f3c396..e2431fe8a803 100644 --- a/module/os/linux/zfs/zfs_sysfs.c +++ b/module/os/linux/zfs/zfs_sysfs.c @@ -279,11 +279,11 @@ zprop_sysfs_show(const char *attr_name, const zprop_desc_t *property, for (int i = 0; i < ARRAY_SIZE(type_map); i++) { if (type_map[i].ztm_type & property->pd_types) { - len += snprintf(buf + len, buflen - len, "%s ", - type_map[i].ztm_name); + len += kmem_scnprintf(buf + len, buflen - len, + "%s ", type_map[i].ztm_name); } } - len += snprintf(buf + len, buflen - len, "\n"); + len += kmem_scnprintf(buf + len, buflen - len, "\n"); return (len); } diff --git a/module/zfs/dataset_kstats.c b/module/zfs/dataset_kstats.c index b63f42a21e44..57b8faf213eb 100644 --- a/module/zfs/dataset_kstats.c +++ b/module/zfs/dataset_kstats.c @@ -128,8 +128,13 @@ dataset_kstats_create(dataset_kstats_t *dk, objset_t *objset) " snprintf() for kstat name returned %d", (unsigned long long)dmu_objset_id(objset), n); return (SET_ERROR(EINVAL)); + } else if (n >= KSTAT_STRLEN) { + zfs_dbgmsg("failed to create dataset kstat for objset %lld: " + "kstat name length (%d) exceeds limit (%d)", + (unsigned long long)dmu_objset_id(objset), + n, KSTAT_STRLEN); + return (SET_ERROR(ENAMETOOLONG)); } - ASSERT3U(n, <, KSTAT_STRLEN); kstat_t *kstat = kstat_create(kstat_module_name, 0, kstat_name, "dataset", KSTAT_TYPE_NAMED, diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index 9ec37502986f..ca55d55405d3 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -1536,7 +1536,7 @@ snprintf_blkptr(char *buf, size_t buflen, const blkptr_t *bp) compress = zio_compress_table[BP_GET_COMPRESS(bp)].ci_name; } - SNPRINTF_BLKPTR(snprintf, ' ', buf, buflen, bp, type, checksum, + SNPRINTF_BLKPTR(kmem_scnprintf, ' ', buf, buflen, bp, type, checksum, compress); } diff --git a/module/zfs/vdev_raidz_math.c b/module/zfs/vdev_raidz_math.c index f74a76a8d5ba..2980f8acfbd7 100644 --- a/module/zfs/vdev_raidz_math.c +++ b/module/zfs/vdev_raidz_math.c @@ -285,17 +285,17 @@ raidz_math_kstat_headers(char *buf, size_t size) { ASSERT3U(size, >=, RAIDZ_KSTAT_LINE_LEN); - ssize_t off = snprintf(buf, size, "%-17s", "implementation"); + ssize_t off = kmem_scnprintf(buf, size, "%-17s", "implementation"); for (int i = 0; i < ARRAY_SIZE(raidz_gen_name); i++) - off += snprintf(buf + off, size - off, "%-16s", + off += kmem_scnprintf(buf + off, size - off, "%-16s", raidz_gen_name[i]); for (int i = 0; i < ARRAY_SIZE(raidz_rec_name); i++) - off += snprintf(buf + off, size - off, "%-16s", + off += kmem_scnprintf(buf + off, size - off, "%-16s", raidz_rec_name[i]); - (void) snprintf(buf + off, size - off, "\n"); + (void) kmem_scnprintf(buf + off, size - off, "\n"); return (0); } @@ -311,34 +311,35 @@ raidz_math_kstat_data(char *buf, size_t size, void *data) ASSERT3U(size, >=, RAIDZ_KSTAT_LINE_LEN); if (cstat == fstat) { - off += snprintf(buf + off, size - off, "%-17s", "fastest"); + off += kmem_scnprintf(buf + off, size - off, "%-17s", + "fastest"); for (i = 0; i < ARRAY_SIZE(raidz_gen_name); i++) { int id = fstat->gen[i]; - off += snprintf(buf + off, size - off, "%-16s", + off += kmem_scnprintf(buf + off, size - off, "%-16s", raidz_supp_impl[id]->name); } for (i = 0; i < ARRAY_SIZE(raidz_rec_name); i++) { int id = fstat->rec[i]; - off += snprintf(buf + off, size - off, "%-16s", + off += kmem_scnprintf(buf + off, size - off, "%-16s", raidz_supp_impl[id]->name); } } else { ptrdiff_t id = cstat - raidz_impl_kstats; - off += snprintf(buf + off, size - off, "%-17s", + off += kmem_scnprintf(buf + off, size - off, "%-17s", raidz_supp_impl[id]->name); for (i = 0; i < ARRAY_SIZE(raidz_gen_name); i++) - off += snprintf(buf + off, size - off, "%-16llu", + off += kmem_scnprintf(buf + off, size - off, "%-16llu", (u_longlong_t)cstat->gen[i]); for (i = 0; i < ARRAY_SIZE(raidz_rec_name); i++) - off += snprintf(buf + off, size - off, "%-16llu", + off += kmem_scnprintf(buf + off, size - off, "%-16llu", (u_longlong_t)cstat->rec[i]); } - (void) snprintf(buf + off, size - off, "\n"); + (void) kmem_scnprintf(buf + off, size - off, "\n"); return (0); } diff --git a/module/zfs/zfs_chksum.c b/module/zfs/zfs_chksum.c index 74b4cb8d2e63..4a9a36d87e66 100644 --- a/module/zfs/zfs_chksum.c +++ b/module/zfs/zfs_chksum.c @@ -81,15 +81,15 @@ chksum_kstat_headers(char *buf, size_t size) { ssize_t off = 0; - off += snprintf(buf + off, size, "%-23s", "implementation"); - off += snprintf(buf + off, size - off, "%8s", "1k"); - off += snprintf(buf + off, size - off, "%8s", "4k"); - off += snprintf(buf + off, size - off, "%8s", "16k"); - off += snprintf(buf + off, size - off, "%8s", "64k"); - off += snprintf(buf + off, size - off, "%8s", "256k"); - off += snprintf(buf + off, size - off, "%8s", "1m"); - off += snprintf(buf + off, size - off, "%8s", "4m"); - (void) snprintf(buf + off, size - off, "%8s\n", "16m"); + off += kmem_scnprintf(buf + off, size, "%-23s", "implementation"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "1k"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "4k"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "16k"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "64k"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "256k"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "1m"); + off += kmem_scnprintf(buf + off, size - off, "%8s", "4m"); + (void) kmem_scnprintf(buf + off, size - off, "%8s\n", "16m"); return (0); } @@ -102,23 +102,23 @@ chksum_kstat_data(char *buf, size_t size, void *data) char b[24]; cs = (chksum_stat_t *)data; - snprintf(b, 23, "%s-%s", cs->name, cs->impl); - off += snprintf(buf + off, size - off, "%-23s", b); - off += snprintf(buf + off, size - off, "%8llu", + kmem_scnprintf(b, 23, "%s-%s", cs->name, cs->impl); + off += kmem_scnprintf(buf + off, size - off, "%-23s", b); + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs1k); - off += snprintf(buf + off, size - off, "%8llu", + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs4k); - off += snprintf(buf + off, size - off, "%8llu", + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs16k); - off += snprintf(buf + off, size - off, "%8llu", + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs64k); - off += snprintf(buf + off, size - off, "%8llu", + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs256k); - off += snprintf(buf + off, size - off, "%8llu", + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs1m); - off += snprintf(buf + off, size - off, "%8llu", + off += kmem_scnprintf(buf + off, size - off, "%8llu", (u_longlong_t)cs->bs4m); - (void) snprintf(buf + off, size - off, "%8llu\n", + (void) kmem_scnprintf(buf + off, size - off, "%8llu\n", (u_longlong_t)cs->bs16m); return (0); From b37d495e04ed6fc0012b2eccfff80af9e8887422 Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Sat, 29 Oct 2022 16:08:54 -0400 Subject: [PATCH 082/126] Avoid null pointer dereference in dsl_fs_ss_limit_check() Check for cr == NULL before dereferencing it in dsl_enforce_ds_ss_limits() to lookup the zone/jail ID. Reported-by: Coverity (CID 1210459) Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Allan Jude Closes #14103 --- module/zfs/dsl_dir.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 15af67ba8560..9af760177445 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -815,6 +815,18 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop, ASSERT(prop == ZFS_PROP_FILESYSTEM_LIMIT || prop == ZFS_PROP_SNAPSHOT_LIMIT); + if (prop == ZFS_PROP_SNAPSHOT_LIMIT) { + /* + * We don't enforce the limit for temporary snapshots. This is + * indicated by a NULL cred_t argument. + */ + if (cr == NULL) + return (0); + + count_prop = DD_FIELD_SNAPSHOT_COUNT; + } else { + count_prop = DD_FIELD_FILESYSTEM_COUNT; + } /* * If we're allowed to change the limit, don't enforce the limit * e.g. this can happen if a snapshot is taken by an administrative @@ -834,19 +846,6 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop, if (delta == 0) return (0); - if (prop == ZFS_PROP_SNAPSHOT_LIMIT) { - /* - * We don't enforce the limit for temporary snapshots. This is - * indicated by a NULL cred_t argument. - */ - if (cr == NULL) - return (0); - - count_prop = DD_FIELD_SNAPSHOT_COUNT; - } else { - count_prop = DD_FIELD_FILESYSTEM_COUNT; - } - /* * If an ancestor has been provided, stop checking the limit once we * hit that dir. We need this during rename so that we don't overcount From dcce0dc5f009e8a3ec6dc48f5fc99abc4d74200f Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Mon, 31 Oct 2022 13:01:04 -0400 Subject: [PATCH 083/126] Fix oversights from 4170ae4e 4170ae4ea600fea6ac9daa8b145960c9de3915fc was intended to tackle TOCTOU race conditions reported by CodeQL, but as an oversight, a file descriptor was not closed and some comments were not updated. Interestingly, CodeQL did not complain about the file descriptor leak, so there is room for improvement in how we configure it to try to detect this issue so that we get early warning about this. In addition, an optimization opportunity was missed by mistake in lib/libshare/os/linux/smb.c, which prevented us from truly closing the TOCTOU race. This was also caught by Coverity. Reported-by: Coverity (CID 1524424) Reported-by: Coverity (CID 1526804) Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14109 --- lib/libshare/os/linux/smb.c | 2 +- tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/libshare/os/linux/smb.c b/lib/libshare/os/linux/smb.c index 8eb1894de531..0679e82104e2 100644 --- a/lib/libshare/os/linux/smb.c +++ b/lib/libshare/os/linux/smb.c @@ -103,7 +103,7 @@ smb_retrieve_shares(void) goto out; } - if (stat(file_path, &eStat) == -1) { + if (fstat(fd, &eStat) == -1) { close(fd); rc = SA_SYSTEM_ERR; goto out; diff --git a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c index 1a934a8b1852..8f936d36de1f 100644 --- a/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c +++ b/tests/zfs-tests/tests/functional/tmpfile/tmpfile_stat_mode.c @@ -37,12 +37,12 @@ /* * DESCRIPTION: - * Verify stat(2) for O_TMPFILE file considers umask. + * Verify fstat(2) for O_TMPFILE file considers umask. * * STRATEGY: * 1. open(2) with O_TMPFILE. * 2. linkat(2). - * 3. fstat(2)/stat(2) and verify .st_mode value. + * 3. fstat(2) and verify .st_mode value. */ static void @@ -94,6 +94,7 @@ test_stat_mode(mode_t mask) mode = fst.st_mode & 0777; if (mode != masked) errx(8, "fstat(2) %o != %o\n", mode, masked); + close(fd); } int From 95055c2ce2a51b5285091d928c8481d02796ea72 Mon Sep 17 00:00:00 2001 From: youzhongyang Date: Tue, 1 Nov 2022 15:08:37 -0400 Subject: [PATCH 084/126] ZTS: rsend_009_pos.ksh is destructive on zfs-on-root system Reviewed-by: Brian Behlendorf Reviewed-by: Allan Jude Reviewed-by: George Melikov Signed-off-by: Youzhong Yang Closes #14113 --- .../tests/functional/rsend/rsend_009_pos.ksh | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh b/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh index ba60afe9acd3..fc5a582f881e 100755 --- a/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh +++ b/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh @@ -45,13 +45,16 @@ verify_runnable "global" +BPOOL=bpool_test +SPOOL=spool_test + function cleanup { - if datasetexists bpool ; then - log_must_busy zpool destroy -f bpool + if datasetexists $BPOOL ; then + log_must_busy zpool destroy -f $BPOOL fi - if datasetexists spool ; then - log_must_busy zpool destroy -f spool + if datasetexists $SPOOL ; then + log_must_busy zpool destroy -f $SPOOL fi } @@ -60,33 +63,33 @@ log_onexit cleanup log_must mkfile $MINVDEVSIZE $TESTDIR/bfile log_must mkfile $SPA_MINDEVSIZE $TESTDIR/sfile -log_must zpool create -O compression=off bpool $TESTDIR/bfile -log_must zpool create -O compression=off spool $TESTDIR/sfile +log_must zpool create -O compression=off $BPOOL $TESTDIR/bfile +log_must zpool create -O compression=off $SPOOL $TESTDIR/sfile # # Test out of space on sub-filesystem # -log_must zfs create bpool/fs -log_must mkfile 30M /bpool/fs/file +log_must zfs create $BPOOL/fs +log_must mkfile 30M /$BPOOL/fs/file -log_must zfs snapshot bpool/fs@snap -log_must eval "zfs send -R bpool/fs@snap > $BACKDIR/fs-R" -log_mustnot eval "zfs receive -d -F spool < $BACKDIR/fs-R" +log_must zfs snapshot $BPOOL/fs@snap +log_must eval "zfs send -R $BPOOL/fs@snap > $BACKDIR/fs-R" +log_mustnot eval "zfs receive -d -F $SPOOL < $BACKDIR/fs-R" -log_must datasetnonexists spool/fs -log_must ismounted spool +log_must datasetnonexists $SPOOL/fs +log_must ismounted $SPOOL # # Test out of space on top filesystem # -log_must mv /bpool/fs/file /bpool -log_must_busy zfs destroy -rf bpool/fs +log_must mv /$BPOOL/fs/file /$BPOOL +log_must_busy zfs destroy -rf $BPOOL/fs -log_must zfs snapshot bpool@snap -log_must eval "zfs send -R bpool@snap > $BACKDIR/bpool-R" -log_mustnot eval "zfs receive -d -F spool < $BACKDIR/bpool-R" +log_must zfs snapshot $BPOOL@snap +log_must eval "zfs send -R $BPOOL@snap > $BACKDIR/bpool-R" +log_mustnot eval "zfs receive -d -F $SPOOL < $BACKDIR/bpool-R" -log_must datasetnonexists spool/fs -log_must ismounted spool +log_must datasetnonexists $SPOOL/fs +log_must ismounted $SPOOL log_pass "zfs receive can handle out of space correctly." From 748b9d5bda935d126eeb62acab86c95e8b2ccac3 Mon Sep 17 00:00:00 2001 From: Ryan Moeller Date: Tue, 1 Nov 2022 15:19:32 -0400 Subject: [PATCH 085/126] zil: Relax assertion in zil_parse Rather than panic debug builds when we fail to parse a whole ZIL, let's instead improve the logging of errors and continue like in a release build. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Ryan Moeller Closes #14116 --- module/zfs/zil.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 23afc8a40bb4..59c7595f6df2 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -480,8 +480,18 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, error = zil_read_log_block(zilog, decrypt, &blk, &next_blk, lrbuf, &end); - if (error != 0) + if (error != 0) { + if (claimed) { + char name[ZFS_MAX_DATASET_NAME_LEN]; + + dmu_objset_name(zilog->zl_os, name); + + cmn_err(CE_WARN, "ZFS read log block error %d, " + "dataset %s, seq 0x%llx\n", error, name, + (u_longlong_t)blk_seq); + } break; + } for (lrp = lrbuf; lrp < end; lrp += reclen) { lr_t *lr = (lr_t *)lrp; @@ -505,10 +515,6 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func, zilog->zl_parse_blk_count = blk_count; zilog->zl_parse_lr_count = lr_count; - ASSERT(!claimed || !(zh->zh_flags & ZIL_CLAIM_LR_SEQ_VALID) || - (max_blk_seq == claim_blk_seq && max_lr_seq == claim_lr_seq) || - (decrypt && error == EIO)); - zil_bp_tree_fini(zilog); zio_buf_free(lrbuf, SPA_OLD_MAXBLOCKSIZE); From b10f73f78eb223dd799a87474c537a69113edee1 Mon Sep 17 00:00:00 2001 From: Vince van Oosten Date: Sun, 23 Oct 2022 10:55:46 +0200 Subject: [PATCH 086/126] include systemd overrides to zfs-dracut module If a user that uses systemd and dracut wants to overide certain settings, they typically use `systemctl edit [unit]` or place a file in `/etc/systemd/system/[unit].d/override.conf` directly. The zfs-dracut module did not include those overrides however, so this did not have any effect at boot time. For zfs-import-scan.service and zfs-import-cache.service, overrides are now included in the dracut initramfs image. Reviewed-by: Brian Behlendorf Signed-off-by: Vince van Oosten Closes #14075 Closes #14076 --- contrib/dracut/90zfs/module-setup.sh.in | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in index 81d7d2abe496..b16529de9057 100755 --- a/contrib/dracut/90zfs/module-setup.sh.in +++ b/contrib/dracut/90zfs/module-setup.sh.in @@ -86,6 +86,16 @@ install() { "zfs-import-cache.service"; do inst_simple "${systemdsystemunitdir}/${_service}" systemctl -q --root "${initdir}" add-wants zfs-import.target "${_service}" + + # Add user-provided unit overrides + # - /etc/systemd/system/zfs-import-{scan,cache}.service + # - /etc/systemd/system/zfs-import-{scan,cache}.service.d/overrides.conf + # -H ensures they are marked host-only + # -o ensures there is no error upon absence of these files + inst_multiple -o -H \ + "${systemdsystemconfdir}/${_service}" \ + "${systemdsystemconfdir}/${_service}.d/"*.conf + done for _service in \ From 59ca6e2ad0b40a67d83cddae8e33d95e8957ad06 Mon Sep 17 00:00:00 2001 From: Vince van Oosten Date: Sun, 23 Oct 2022 11:11:18 +0200 Subject: [PATCH 087/126] include overrides for zfs-import.target Reviewed-by: Brian Behlendorf Signed-off-by: Vince van Oosten Closes #14075 Closes #14076 --- contrib/dracut/90zfs/module-setup.sh.in | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in index b16529de9057..6be718587411 100755 --- a/contrib/dracut/90zfs/module-setup.sh.in +++ b/contrib/dracut/90zfs/module-setup.sh.in @@ -81,15 +81,24 @@ install() { inst_simple "${moddir}/zfs-env-bootfs.service" "${systemdsystemunitdir}/zfs-env-bootfs.service" systemctl -q --root "${initdir}" add-wants zfs-import.target zfs-env-bootfs.service + # Add user-provided unit overrides: + # - /etc/systemd/system/${_service} + # - /etc/systemd/system/${_service}.d/overrides.conf + # -H ensures they are marked host-only + # -o ensures there is no error upon absence of these files + inst_multiple -o -H \ + "${systemdsystemconfdir}/zfs-import.target" \ + "${systemdsystemconfdir}/zfs-import.target.d/"*.conf + for _service in \ "zfs-import-scan.service" \ "zfs-import-cache.service"; do inst_simple "${systemdsystemunitdir}/${_service}" systemctl -q --root "${initdir}" add-wants zfs-import.target "${_service}" - # Add user-provided unit overrides - # - /etc/systemd/system/zfs-import-{scan,cache}.service - # - /etc/systemd/system/zfs-import-{scan,cache}.service.d/overrides.conf + # Add user-provided unit overrides: + # - /etc/systemd/system/${_service} + # - /etc/systemd/system/${_service}.d/overrides.conf # -H ensures they are marked host-only # -o ensures there is no error upon absence of these files inst_multiple -o -H \ From fdc59cf56356858c00b9f06fd9fe11ab60ad7790 Mon Sep 17 00:00:00 2001 From: Vince van Oosten Date: Sun, 23 Oct 2022 11:11:58 +0200 Subject: [PATCH 088/126] include overrides for zfs snapshot/rollback bootfs.service Reviewed-by: Brian Behlendorf Signed-off-by: Vince van Oosten Closes #14075 Closes #14076 --- contrib/dracut/90zfs/module-setup.sh.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in index 6be718587411..528abe42957b 100755 --- a/contrib/dracut/90zfs/module-setup.sh.in +++ b/contrib/dracut/90zfs/module-setup.sh.in @@ -112,6 +112,15 @@ install() { "zfs-rollback-bootfs.service"; do inst_simple "${moddir}/${_service}" "${systemdsystemunitdir}/${_service}" systemctl -q --root "${initdir}" add-wants initrd.target "${_service}" + + # Add user-provided unit overrides: + # - /etc/systemd/system/${_service} + # - /etc/systemd/system/${_service}.d/overrides.conf + # -H ensures they are marked host-only + # -o ensures there is no error upon absence of these files + inst_multiple -o -H \ + "${systemdsystemconfdir}/${_service}" \ + "${systemdsystemconfdir}/${_service}.d/"*.conf done inst_simple "${moddir}/import-opts-generator.sh" "${systemdutildir}/system-environment-generators/zfs-import-opts.sh" From da3d2666728ed21707bd66182c4077f4adcd61aa Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Tue, 1 Nov 2022 16:58:17 -0400 Subject: [PATCH 089/126] FreeBSD: Fix regression from kmem_scnprintf() in libzfs kmem_scnprintf() is only available in libzpool. Recent buildbot issues with showing FreeBSD results kept us from seeing this before 97143b9d314d54409244f3995576d8cc8c1ebf0a was merged. The code has been changed to sanitize the output from `kmem_scnprintf()`. Reviewed-by: Allan Jude Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14111 --- lib/libzfs/os/freebsd/libzfs_compat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/libzfs/os/freebsd/libzfs_compat.c b/lib/libzfs/os/freebsd/libzfs_compat.c index 5e280cbae935..d1c1fea7fb68 100644 --- a/lib/libzfs/os/freebsd/libzfs_compat.c +++ b/lib/libzfs/os/freebsd/libzfs_compat.c @@ -202,8 +202,10 @@ libzfs_error_init(int error) size_t msglen = sizeof (errbuf); if (modfind("zfs") < 0) { - size_t len = kmem_scnprintf(msg, msglen, dgettext(TEXT_DOMAIN, + size_t len = snprintf(msg, msglen, dgettext(TEXT_DOMAIN, "Failed to load %s module: "), ZFS_KMOD); + if (len >= msglen) + len = msglen - 1; msg += len; msglen -= len; } From 5229071ba1e6c5dbba277e50306d2ad38f417947 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Fri, 28 Oct 2022 00:58:41 +0100 Subject: [PATCH 090/126] Improve RISC-V support Check __riscv_xlen == 64 rather than _LP64 and define _LP64 if missing. Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14128 --- include/os/linux/spl/sys/isa_defs.h | 6 +++++- lib/libspl/include/sys/isa_defs.h | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/os/linux/spl/sys/isa_defs.h b/include/os/linux/spl/sys/isa_defs.h index a032aae91658..ee3b7460790f 100644 --- a/include/os/linux/spl/sys/isa_defs.h +++ b/include/os/linux/spl/sys/isa_defs.h @@ -206,9 +206,13 @@ * RISC-V arch specific defines * only RV64G (including atomic) LP64 is supported yet */ -#elif defined(__riscv) && defined(_LP64) && _LP64 && \ +#elif defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 && \ defined(__riscv_atomic) && __riscv_atomic +#if !defined(_LP64) +#define _LP64 1 +#endif + #ifndef __riscv__ #define __riscv__ #endif diff --git a/lib/libspl/include/sys/isa_defs.h b/lib/libspl/include/sys/isa_defs.h index 756adff15ac8..114cca4f1545 100644 --- a/lib/libspl/include/sys/isa_defs.h +++ b/lib/libspl/include/sys/isa_defs.h @@ -227,9 +227,13 @@ extern "C" { * RISC-V arch specific defines * only RV64G (including atomic) LP64 is supported yet */ -#elif defined(__riscv) && defined(_LP64) && _LP64 && \ +#elif defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 && \ defined(__riscv_atomic) && __riscv_atomic +#if !defined(_LP64) +#define _LP64 1 +#endif + #ifndef __riscv__ #define __riscv__ #endif From 7309e94239a456de043c590ae85027e932c86f62 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Fri, 28 Oct 2022 17:36:43 +0100 Subject: [PATCH 091/126] linux isa_defs.h: Don't define _ALIGNMENT_REQUIRED Nothing consumes this definition so stop defining it. Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14128 --- include/os/linux/spl/sys/isa_defs.h | 32 ----------------------------- 1 file changed, 32 deletions(-) diff --git a/include/os/linux/spl/sys/isa_defs.h b/include/os/linux/spl/sys/isa_defs.h index ee3b7460790f..5801ec92bc2b 100644 --- a/include/os/linux/spl/sys/isa_defs.h +++ b/include/os/linux/spl/sys/isa_defs.h @@ -47,9 +47,6 @@ #endif #endif -#define _ALIGNMENT_REQUIRED 1 - - /* i386 arch specific defines */ #elif defined(__i386) || defined(__i386__) @@ -65,8 +62,6 @@ #define _ILP32 #endif -#define _ALIGNMENT_REQUIRED 0 - /* powerpc (ppc64) arch specific defines */ #elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) @@ -88,12 +83,6 @@ #endif #endif -/* - * Illumos doesn't define _ALIGNMENT_REQUIRED for PPC, so default to 1 - * out of paranoia. - */ -#define _ALIGNMENT_REQUIRED 1 - /* arm arch specific defines */ #elif defined(__arm) || defined(__arm__) @@ -115,12 +104,6 @@ #define _ZFS_BIG_ENDIAN #endif -/* - * Illumos doesn't define _ALIGNMENT_REQUIRED for ARM, so default to 1 - * out of paranoia. - */ -#define _ALIGNMENT_REQUIRED 1 - /* aarch64 arch specific defines */ #elif defined(__aarch64__) @@ -157,7 +140,6 @@ #define _ZFS_BIG_ENDIAN #define _SUNOS_VTOC_16 -#define _ALIGNMENT_REQUIRED 1 /* s390 arch specific defines */ #elif defined(__s390__) @@ -173,12 +155,6 @@ #define _ZFS_BIG_ENDIAN -/* - * Illumos doesn't define _ALIGNMENT_REQUIRED for s390, so default to 1 - * out of paranoia. - */ -#define _ALIGNMENT_REQUIRED 1 - /* MIPS arch specific defines */ #elif defined(__mips__) @@ -196,12 +172,6 @@ #define _SUNOS_VTOC_16 -/* - * Illumos doesn't define _ALIGNMENT_REQUIRED for MIPS, so default to 1 - * out of paranoia. - */ -#define _ALIGNMENT_REQUIRED 1 - /* * RISC-V arch specific defines * only RV64G (including atomic) LP64 is supported yet @@ -225,8 +195,6 @@ #define _SUNOS_VTOC_16 -#define _ALIGNMENT_REQUIRED 1 - #else /* * Currently supported: From d96303cb0787bf7217aacd51074e00d820a98700 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 23:04:17 +0100 Subject: [PATCH 092/126] acl: use uintptr_t for ace walker cookies Avoid assuming that a pointer can fit in a uint64_t and use uintptr_t instead. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14131 --- include/os/freebsd/spl/acl/acl_common.h | 2 +- module/os/freebsd/spl/acl_common.c | 4 ++-- module/os/freebsd/zfs/zfs_acl.c | 6 +++--- module/os/linux/zfs/zfs_acl.c | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/os/freebsd/spl/acl/acl_common.h b/include/os/freebsd/spl/acl/acl_common.h index 2b77bdb6ea3d..53b69154d671 100644 --- a/include/os/freebsd/spl/acl/acl_common.h +++ b/include/os/freebsd/spl/acl/acl_common.h @@ -47,7 +47,7 @@ extern int acltrivial(const char *); extern void adjust_ace_pair(ace_t *pair, mode_t mode); extern void adjust_ace_pair_common(void *, size_t, size_t, mode_t); extern int ace_trivial_common(void *, int, - uint64_t (*walk)(void *, uint64_t, int aclcnt, uint16_t *, uint16_t *, + uintptr_t (*walk)(void *, uintptr_t, int aclcnt, uint16_t *, uint16_t *, uint32_t *mask)); #if !defined(_KERNEL) extern acl_t *acl_alloc(acl_type_t); diff --git a/module/os/freebsd/spl/acl_common.c b/module/os/freebsd/spl/acl_common.c index b692ccdf232a..04a5d2869d1b 100644 --- a/module/os/freebsd/spl/acl_common.c +++ b/module/os/freebsd/spl/acl_common.c @@ -1654,13 +1654,13 @@ acl_trivial_create(mode_t mode, boolean_t isdir, ace_t **acl, int *count) */ int ace_trivial_common(void *acep, int aclcnt, - uint64_t (*walk)(void *, uint64_t, int aclcnt, + uintptr_t (*walk)(void *, uintptr_t, int aclcnt, uint16_t *, uint16_t *, uint32_t *)) { uint16_t flags; uint32_t mask; uint16_t type; - uint64_t cookie = 0; + uintptr_t cookie = 0; while ((cookie = walk(acep, cookie, aclcnt, &flags, &type, &mask))) { switch (flags & ACE_TYPE_FLAGS) { diff --git a/module/os/freebsd/zfs/zfs_acl.c b/module/os/freebsd/zfs/zfs_acl.c index c075e180a860..16bcd338de21 100644 --- a/module/os/freebsd/zfs/zfs_acl.c +++ b/module/os/freebsd/zfs/zfs_acl.c @@ -631,8 +631,8 @@ zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, return (NULL); } -static uint64_t -zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, +static uintptr_t +zfs_ace_walk(void *datap, uintptr_t cookie, int aclcnt, uint16_t *flags, uint16_t *type, uint32_t *mask) { (void) aclcnt; @@ -642,7 +642,7 @@ zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, acep = zfs_acl_next_ace(aclp, acep, &who, mask, flags, type); - return ((uint64_t)(uintptr_t)acep); + return ((uintptr_t)acep); } /* diff --git a/module/os/linux/zfs/zfs_acl.c b/module/os/linux/zfs/zfs_acl.c index d04034490758..437169990f02 100644 --- a/module/os/linux/zfs/zfs_acl.c +++ b/module/os/linux/zfs/zfs_acl.c @@ -629,18 +629,18 @@ zfs_acl_next_ace(zfs_acl_t *aclp, void *start, uint64_t *who, return (NULL); } -static uint64_t -zfs_ace_walk(void *datap, uint64_t cookie, int aclcnt, +static uintptr_t +zfs_ace_walk(void *datap, uintptr_t cookie, int aclcnt, uint16_t *flags, uint16_t *type, uint32_t *mask) { (void) aclcnt; zfs_acl_t *aclp = datap; - zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)(uintptr_t)cookie; + zfs_ace_hdr_t *acep = (zfs_ace_hdr_t *)cookie; uint64_t who; acep = zfs_acl_next_ace(aclp, acep, &who, mask, flags, type); - return ((uint64_t)(uintptr_t)acep); + return ((uintptr_t)acep); } /* @@ -1285,7 +1285,7 @@ acl_trivial_access_masks(mode_t mode, boolean_t isdir, trivial_acl_t *masks) */ static int ace_trivial_common(void *acep, int aclcnt, - uint64_t (*walk)(void *, uint64_t, int aclcnt, + uintptr_t (*walk)(void *, uintptr_t, int, uint16_t *, uint16_t *, uint32_t *)) { uint16_t flags; From 250b2bac78102f707dc105450f25d91e5fab481e Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 23:20:05 +0100 Subject: [PATCH 093/126] zfs_onexit_add_cb: make action_handle point to a uintptr_t Avoid assuming than a uint64_t can hold a pointer and reduce the number of casts in the process. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14131 --- include/sys/zfs_onexit.h | 2 +- lib/libzpool/kernel.c | 2 +- module/zfs/zfs_onexit.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sys/zfs_onexit.h b/include/sys/zfs_onexit.h index 18930fe01c7a..91f49d4cc5a3 100644 --- a/include/sys/zfs_onexit.h +++ b/include/sys/zfs_onexit.h @@ -54,7 +54,7 @@ extern void zfs_onexit_destroy(zfs_onexit_t *zo); extern zfs_file_t *zfs_onexit_fd_hold(int fd, minor_t *minorp); extern void zfs_onexit_fd_rele(zfs_file_t *); extern int zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, - uint64_t *action_handle); + uintptr_t *action_handle); #ifdef __cplusplus } diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 1d46470947d3..77264470baef 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -1001,7 +1001,7 @@ zfs_onexit_fd_rele(zfs_file_t *fp) int zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, - uint64_t *action_handle) + uintptr_t *action_handle) { (void) minor, (void) func, (void) data, (void) action_handle; return (0); diff --git a/module/zfs/zfs_onexit.c b/module/zfs/zfs_onexit.c index dfcdeeb5b46f..63acf7ab2e4d 100644 --- a/module/zfs/zfs_onexit.c +++ b/module/zfs/zfs_onexit.c @@ -151,7 +151,7 @@ zfs_onexit_minor_to_state(minor_t minor, zfs_onexit_t **zo) */ int zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, - uint64_t *action_handle) + uintptr_t *action_handle) { zfs_onexit_t *zo; zfs_onexit_action_node_t *ap; @@ -170,7 +170,7 @@ zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, list_insert_tail(&zo->zo_actions, ap); mutex_exit(&zo->zo_lock); if (action_handle) - *action_handle = (uint64_t)(uintptr_t)ap; + *action_handle = (uintptr_t)ap; return (0); } From 877790001e74b6c3b2955e4b7a8c685385e77654 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 23:25:42 +0100 Subject: [PATCH 094/126] recvd_props_mode: use a uintptr_t to stash nvlists Avoid assuming than a uint64_t can hold a pointer. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14131 --- lib/libzfs/libzfs_dataset.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index f8a61c64261f..87bc4ea66c5b 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -2087,16 +2087,16 @@ zfs_is_recvd_props_mode(zfs_handle_t *zhp) } static void -zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) +zfs_set_recvd_props_mode(zfs_handle_t *zhp, uintptr_t *cookie) { - *cookie = (uint64_t)(uintptr_t)zhp->zfs_props; + *cookie = (uintptr_t)zhp->zfs_props; zhp->zfs_props = zhp->zfs_recvd_props; } static void -zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie) +zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uintptr_t *cookie) { - zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie; + zhp->zfs_props = (nvlist_t *)*cookie; *cookie = 0; } @@ -2373,7 +2373,7 @@ zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf, prop = zfs_name_to_prop(propname); if (prop != ZPROP_USERPROP) { - uint64_t cookie; + uintptr_t cookie; if (!nvlist_exists(zhp->zfs_recvd_props, propname)) return (-1); zfs_set_recvd_props_mode(zhp, &cookie); From b9041e1f27b7b29b27ac3b873c7ba2922bccca01 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 23:28:03 +0100 Subject: [PATCH 095/126] Use intptr_t when storing an integer in a pointer Cast the integer type to (u)intptr_t before casting to "void *". In CHERI C/C++ we warn on bare casts from integers to pointers to catch attempts to create pointers our of thin air. We allow the warning to be supressed with a suitable cast through (u)intptr_t. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14131 --- cmd/zstream/zstream_decompress.c | 2 +- module/zfs/zfs_vnops.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/zstream/zstream_decompress.c b/cmd/zstream/zstream_decompress.c index e5527777bca3..6e0da0852b72 100644 --- a/cmd/zstream/zstream_decompress.c +++ b/cmd/zstream/zstream_decompress.c @@ -146,7 +146,7 @@ zstream_do_decompress(int argc, char *argv[]) p = hsearch(e, ENTER); if (p == NULL) errx(1, "hsearch"); - p->data = (void*)type; + p->data = (void*)(intptr_t)type; } if (isatty(STDIN_FILENO)) { diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index c63076f90c18..593249e12cb4 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -64,7 +64,7 @@ zfs_fsync(znode_t *zp, int syncflag, cred_t *cr) int error = 0; zfsvfs_t *zfsvfs = ZTOZSB(zp); - (void) tsd_set(zfs_fsyncer_key, (void *)zfs_fsync_sync_cnt); + (void) tsd_set(zfs_fsyncer_key, (void *)(uintptr_t)zfs_fsync_sync_cnt); if (zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) { if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0) From 84477e148dccf4665067c0d39006f31bb073cc9e Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 23:39:06 +0100 Subject: [PATCH 096/126] lua: cast through uintptr_t when return a pointer Don't assume size_t can carry pointer provenance and use uintptr_t (identialy on all current platforms) instead. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14131 --- module/lua/lapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/lua/lapi.c b/module/lua/lapi.c index ed3a0f4cf9ec..703cf4cc2a36 100644 --- a/module/lua/lapi.c +++ b/module/lua/lapi.c @@ -444,7 +444,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) { case LUA_TTABLE: return hvalue(o); case LUA_TLCL: return clLvalue(o); case LUA_TCCL: return clCvalue(o); - case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); + case LUA_TLCF: return cast(void *, cast(uintptr_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: case LUA_TLIGHTUSERDATA: From 211ec1b9fde303968d42e49553c666f74638d2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20F=C3=BCl=C3=B6p?= Date: Thu, 3 Nov 2022 17:55:13 +0100 Subject: [PATCH 097/126] Deny receiving into encrypted datasets if the keys are not loaded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 68ddc06b611854560fefa377437eb3c9480e084b introduced support for receiving unencrypted datasets as children of encrypted ones but unfortunately got the logic upside down. This resulted in failing to deny receives of incremental sends into encrypted datasets without their keys loaded. If receiving a filesystem, the receive was done into a newly created unencrypted child dataset of the target. In case of volumes the receive made the target volume undeletable since a dataset was created below it, which we obviously can't handle. Incremental streams with embedded blocks are affected as well. We fix the broken logic to properly deny receives in such cases. Reviewed-by: Brian Behlendorf Signed-off-by: Attila FĂŒlöp Closes #13598 Closes #14055 Closes #14119 --- module/zfs/dmu_recv.c | 2 +- .../zfs_receive/zfs_receive_to_encrypted.ksh | 31 +++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c index 9f43ffe1e856..339fb149a49f 100644 --- a/module/zfs/dmu_recv.c +++ b/module/zfs/dmu_recv.c @@ -646,7 +646,7 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx) * so add the DS_HOLD_FLAG_DECRYPT flag only if we are dealing * with a dataset we may encrypt. */ - if (drba->drba_dcp != NULL && + if (drba->drba_dcp == NULL || drba->drba_dcp->cp_crypt != ZIO_CRYPT_OFF) { dsflags |= DS_HOLD_FLAG_DECRYPT; } diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh index 5d76c220fc45..8bd9a6854950 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted.ksh @@ -25,13 +25,16 @@ # ZFS should receive to an encrypted child dataset. # # STRATEGY: -# 1. Snapshot the default dataset -# 2. Create an encrypted dataset -# 3. Attempt to receive a stream to an encrypted child -# 4. Attempt to receive a stream with properties to an encrypted child -# 5. Attempt to receive a replication stream to an encrypted child -# 6. Unmount and unload the encrypted dataset keys -# 7. Attempt to receive a snapshot stream to an encrypted child +# 1. Snapshot the default dataset +# 2. Create an encrypted dataset +# 3. Attempt to receive a stream to an encrypted child +# 4. Unload the key +# 5. Attempt to receive an incremental stream to an encrypted child (must fail) +# 6. Attempt to receive a stream with properties to an unencrypted child +# 7. Attempt to receive an incremental stream to an unencrypted child +# 8. Attempt to receive with -o encryption=off to an unencrypted child +# 9. Attempt to receive a replication stream to an unencrypted child +# 10. Attempt to receive a snapshot stream to an encrypted child (must fail) # verify_runnable "both" @@ -39,6 +42,7 @@ verify_runnable "both" function cleanup { snapexists $snap && destroy_dataset $snap -f + snapexists $snap2 && destroy_dataset $snap2 -f datasetexists $TESTPOOL/$TESTFS1 && \ destroy_dataset $TESTPOOL/$TESTFS1 -r @@ -50,15 +54,17 @@ log_assert "ZFS should receive encrypted filesystems into child dataset" typeset passphrase="password" typeset snap="$TESTPOOL/$TESTFS@snap" +typeset snap2="$TESTPOOL/$TESTFS@snap2" typeset testfile="testfile" log_must zfs snapshot $snap +log_must zfs snapshot $snap2 log_must eval "echo $passphrase | zfs create -o encryption=on" \ "-o keyformat=passphrase $TESTPOOL/$TESTFS1" log_note "Verifying ZFS will receive to an encrypted child" -log_must eval "zfs send $snap | zfs receive $TESTPOOL/$TESTFS1/c1" +log_must eval "zfs send $snap | zfs receive -u $TESTPOOL/$TESTFS1/c1" log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c1)" != "off" # Unload the key, the following tests won't require it and we will test @@ -66,10 +72,17 @@ log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c1)" != "off" log_must zfs unmount $TESTPOOL/$TESTFS1 log_must zfs unload-key $TESTPOOL/$TESTFS1 +log_note "Verifying ZFS will not receive an incremental into an encrypted" \ + "dataset when the key is unloaded" +log_mustnot eval "zfs send -i $snap $snap2 | zfs receive $TESTPOOL/$TESTFS1/c1" + log_note "Verifying 'send -p' will receive to an unencrypted child" -log_must eval "zfs send -p $snap | zfs receive $TESTPOOL/$TESTFS1/c2" +log_must eval "zfs send -p $snap | zfs receive -u $TESTPOOL/$TESTFS1/c2" log_must test "$(get_prop 'encryption' $TESTPOOL/$TESTFS1/c2)" == "off" +log_note "Verifying 'send -i' will receive to an unencrypted child" +log_must eval "zfs send -i $snap $snap2 | zfs receive $TESTPOOL/$TESTFS1/c2" + # For completeness add the property override case. log_note "Verifying recv -o encyption=off' will receive to an unencrypted child" log_must eval "zfs send $snap | \ From 27d29946be5e555d8659d6ebdeda6ae771ada5d6 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 3 Nov 2022 09:57:05 -0700 Subject: [PATCH 098/126] libuutil: deobfuscate internal pointers uu_avl and uu_list stored internal next/prev pointers and parent pointers (unused) obfuscated (byte swapped) to hide them from a long forgotten leak checker (No one at the 2022 OpenZFS developers meeting could recall the history.) This would break on CHERI systems and adds no obvious value. Rename the members, use proper types rather than uintptr_t, and eliminate the related macros. Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14126 --- include/libuutil_impl.h | 31 ++++++------------------------- lib/libuutil/uu_avl.c | 30 ++++++++++++++---------------- lib/libuutil/uu_list.c | 30 ++++++++++++++---------------- 3 files changed, 34 insertions(+), 57 deletions(-) diff --git a/include/libuutil_impl.h b/include/libuutil_impl.h index 7aa8f0cedf15..58b6df579d72 100644 --- a/include/libuutil_impl.h +++ b/include/libuutil_impl.h @@ -46,21 +46,6 @@ __attribute__((format(printf, 1, 2), __noreturn__)) void uu_panic(const char *format, ...); -/* - * For debugging purposes, libuutil keeps around linked lists of all uu_lists - * and uu_avls, along with pointers to their parents. These can cause false - * negatives when looking for memory leaks, so we encode the pointers by - * storing them with swapped endianness; this is not perfect, but it's about - * the best we can do without wasting a lot of space. - */ -#ifdef _LP64 -#define UU_PTR_ENCODE(ptr) BSWAP_64((uintptr_t)(void *)(ptr)) -#else -#define UU_PTR_ENCODE(ptr) BSWAP_32((uintptr_t)(void *)(ptr)) -#endif - -#define UU_PTR_DECODE(ptr) ((void *)UU_PTR_ENCODE(ptr)) - /* * uu_list structures */ @@ -80,11 +65,11 @@ struct uu_list_walk { }; struct uu_list { - uintptr_t ul_next_enc; - uintptr_t ul_prev_enc; + uu_list_t *ul_next; + uu_list_t *ul_prev; uu_list_pool_t *ul_pool; - uintptr_t ul_parent_enc; /* encoded parent pointer */ + void *ul_parent; size_t ul_offset; size_t ul_numnodes; uint8_t ul_debug; @@ -95,8 +80,6 @@ struct uu_list { uu_list_walk_t ul_null_walk; /* for robust walkers */ }; -#define UU_LIST_PTR(ptr) ((uu_list_t *)UU_PTR_DECODE(ptr)) - #define UU_LIST_POOL_MAXNAME 64 struct uu_list_pool { @@ -129,11 +112,11 @@ struct uu_avl_walk { }; struct uu_avl { - uintptr_t ua_next_enc; - uintptr_t ua_prev_enc; + uu_avl_t *ua_next; + uu_avl_t *ua_prev; uu_avl_pool_t *ua_pool; - uintptr_t ua_parent_enc; + void *ua_parent; uint8_t ua_debug; uint8_t ua_index; /* mark for uu_avl_index_ts */ @@ -141,8 +124,6 @@ struct uu_avl { uu_avl_walk_t ua_null_walk; }; -#define UU_AVL_PTR(x) ((uu_avl_t *)UU_PTR_DECODE(x)) - #define UU_AVL_POOL_MAXNAME 64 struct uu_avl_pool { diff --git a/lib/libuutil/uu_avl.c b/lib/libuutil/uu_avl.c index 12f7bd4bcc72..ef1497b31439 100644 --- a/lib/libuutil/uu_avl.c +++ b/lib/libuutil/uu_avl.c @@ -97,8 +97,8 @@ uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset, (void) pthread_mutex_init(&pp->uap_lock, NULL); - pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl); - pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl); + pp->uap_null_avl.ua_next = &pp->uap_null_avl; + pp->uap_null_avl.ua_prev = &pp->uap_null_avl; (void) pthread_mutex_lock(&uu_apool_list_lock); pp->uap_next = next = &uu_null_apool; @@ -114,10 +114,8 @@ void uu_avl_pool_destroy(uu_avl_pool_t *pp) { if (pp->uap_debug) { - if (pp->uap_null_avl.ua_next_enc != - UU_PTR_ENCODE(&pp->uap_null_avl) || - pp->uap_null_avl.ua_prev_enc != - UU_PTR_ENCODE(&pp->uap_null_avl)) { + if (pp->uap_null_avl.ua_next != &pp->uap_null_avl || + pp->uap_null_avl.ua_prev != &pp->uap_null_avl) { uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has " "outstanding avls, or is corrupt.\n", (int)sizeof (pp->uap_name), pp->uap_name, @@ -224,7 +222,7 @@ uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags) } ap->ua_pool = pp; - ap->ua_parent_enc = UU_PTR_ENCODE(parent); + ap->ua_parent = parent; ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG); ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index)); @@ -236,11 +234,11 @@ uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags) (void) pthread_mutex_lock(&pp->uap_lock); next = &pp->uap_null_avl; - prev = UU_PTR_DECODE(next->ua_prev_enc); - ap->ua_next_enc = UU_PTR_ENCODE(next); - ap->ua_prev_enc = UU_PTR_ENCODE(prev); - next->ua_prev_enc = UU_PTR_ENCODE(ap); - prev->ua_next_enc = UU_PTR_ENCODE(ap); + prev = next->ua_prev; + ap->ua_next = next; + ap->ua_prev = prev; + next->ua_prev = ap; + prev->ua_next = ap; (void) pthread_mutex_unlock(&pp->uap_lock); return (ap); @@ -263,11 +261,11 @@ uu_avl_destroy(uu_avl_t *ap) } } (void) pthread_mutex_lock(&pp->uap_lock); - UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc; - UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc; + ap->ua_next->ua_prev = ap->ua_prev; + ap->ua_prev->ua_next = ap->ua_next; (void) pthread_mutex_unlock(&pp->uap_lock); - ap->ua_prev_enc = UU_PTR_ENCODE(NULL); - ap->ua_next_enc = UU_PTR_ENCODE(NULL); + ap->ua_prev = NULL; + ap->ua_next = NULL; ap->ua_pool = NULL; avl_destroy(&ap->ua_tree); diff --git a/lib/libuutil/uu_list.c b/lib/libuutil/uu_list.c index 5ece4b14701e..0ca6f05205e9 100644 --- a/lib/libuutil/uu_list.c +++ b/lib/libuutil/uu_list.c @@ -93,8 +93,8 @@ uu_list_pool_create(const char *name, size_t objsize, (void) pthread_mutex_init(&pp->ulp_lock, NULL); - pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list); - pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list); + pp->ulp_null_list.ul_next = &pp->ulp_null_list; + pp->ulp_null_list.ul_prev = &pp->ulp_null_list; (void) pthread_mutex_lock(&uu_lpool_list_lock); pp->ulp_next = next = &uu_null_lpool; @@ -110,10 +110,8 @@ void uu_list_pool_destroy(uu_list_pool_t *pp) { if (pp->ulp_debug) { - if (pp->ulp_null_list.ul_next_enc != - UU_PTR_ENCODE(&pp->ulp_null_list) || - pp->ulp_null_list.ul_prev_enc != - UU_PTR_ENCODE(&pp->ulp_null_list)) { + if (pp->ulp_null_list.ul_next != &pp->ulp_null_list || + pp->ulp_null_list.ul_prev != &pp->ulp_null_list) { uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has " "outstanding lists, or is corrupt.\n", (int)sizeof (pp->ulp_name), pp->ulp_name, @@ -202,7 +200,7 @@ uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags) } lp->ul_pool = pp; - lp->ul_parent_enc = UU_PTR_ENCODE(parent); + lp->ul_parent = parent; lp->ul_offset = pp->ulp_nodeoffset; lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG); lp->ul_sorted = (flags & UU_LIST_SORTED); @@ -217,11 +215,11 @@ uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags) (void) pthread_mutex_lock(&pp->ulp_lock); next = &pp->ulp_null_list; - prev = UU_PTR_DECODE(next->ul_prev_enc); - lp->ul_next_enc = UU_PTR_ENCODE(next); - lp->ul_prev_enc = UU_PTR_ENCODE(prev); - next->ul_prev_enc = UU_PTR_ENCODE(lp); - prev->ul_next_enc = UU_PTR_ENCODE(lp); + prev = next->ul_prev; + lp->ul_next = next; + lp->ul_prev = prev; + next->ul_prev = lp; + prev->ul_next = lp; (void) pthread_mutex_unlock(&pp->ulp_lock); return (lp); @@ -250,11 +248,11 @@ uu_list_destroy(uu_list_t *lp) } (void) pthread_mutex_lock(&pp->ulp_lock); - UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc; - UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc; + lp->ul_next->ul_prev = lp->ul_prev; + lp->ul_prev->ul_next = lp->ul_next; (void) pthread_mutex_unlock(&pp->ulp_lock); - lp->ul_prev_enc = UU_PTR_ENCODE(NULL); - lp->ul_next_enc = UU_PTR_ENCODE(NULL); + lp->ul_prev = NULL; + lp->ul_next = NULL; lp->ul_pool = NULL; uu_free(lp); } From f47f6a055d0c282593fe701bcaa968225ba9d1fc Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 3 Nov 2022 12:58:14 -0400 Subject: [PATCH 099/126] Address warnings about possible division by zero from clangsa * The complaint in ztest_replay_write() is only possible if something went horribly wrong. An assertion will silence this and if it goes off, we will know that something is wrong. * The complaint in spa_estimate_metaslabs_to_flush() is not impossible, but seems very unlikely. We resolve this by passing the value from the `MIN()` that does not go to infinity when the variable is zero. There was a third report from Clang's scan-build, but that was a definite false positive and disappeared when checked again through Clang's static analyzer with Z3 refution via CodeChecker. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14124 --- cmd/ztest.c | 1 + module/zfs/spa_log_spacemap.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/ztest.c b/cmd/ztest.c index 19edab4eb7a2..1c7c74c5d80f 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -2177,6 +2177,7 @@ ztest_replay_write(void *arg1, void *arg2, boolean_t byteswap) * but not always, because we also want to verify correct * behavior when the data was not recently read into cache. */ + ASSERT(doi.doi_data_block_size); ASSERT0(offset % doi.doi_data_block_size); if (ztest_random(4) != 0) { int prefetch = ztest_random(2) ? diff --git a/module/zfs/spa_log_spacemap.c b/module/zfs/spa_log_spacemap.c index c7ba5f65af58..2878e68c6e4b 100644 --- a/module/zfs/spa_log_spacemap.c +++ b/module/zfs/spa_log_spacemap.c @@ -691,7 +691,8 @@ spa_estimate_metaslabs_to_flush(spa_t *spa) * based on the incoming rate until we exceed it. */ if (available_blocks >= 0 && available_txgs >= 0) { - uint64_t skip_txgs = MIN(available_txgs + 1, + uint64_t skip_txgs = (incoming == 0) ? + available_txgs + 1 : MIN(available_txgs + 1, (available_blocks / incoming) + 1); available_blocks -= (skip_txgs * incoming); available_txgs -= skip_txgs; From abb42dc5e1d5073ac72d9294fa78ab2203406b1c Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Tue, 1 Nov 2022 20:43:32 +0000 Subject: [PATCH 100/126] Make 1-bit bitfields unsigned This fixes -Wsingle-bit-bitfield-constant-conversion warning from clang-16 like: lib/libzfs/libzfs_dataset.c:4529:19: error: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Werror,-Wsingle-bit-bitfield-constant-conversion] flags.nounmount = B_TRUE; ^ ~~~~~~ Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14125 --- include/libzfs.h | 10 +++++----- lib/libzfs/libzfs_pool.c | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/libzfs.h b/include/libzfs.h index df17873369ad..2806d1f7cff5 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -260,10 +260,10 @@ _LIBZFS_H int zpool_add(zpool_handle_t *, nvlist_t *); typedef struct splitflags { /* do not split, but return the config that would be split off */ - int dryrun : 1; + unsigned int dryrun : 1; /* after splitting, import the pool */ - int import : 1; + unsigned int import : 1; int name_flags; } splitflags_t; @@ -690,13 +690,13 @@ _LIBZFS_H int zfs_rollback(zfs_handle_t *, zfs_handle_t *, boolean_t); typedef struct renameflags { /* recursive rename */ - int recursive : 1; + unsigned int recursive : 1; /* don't unmount file systems */ - int nounmount : 1; + unsigned int nounmount : 1; /* force unmount file systems */ - int forceunmount : 1; + unsigned int forceunmount : 1; } renameflags_t; _LIBZFS_H int zfs_rename(zfs_handle_t *, const char *, renameflags_t); diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index f0bb2370a4c8..7f7e19a090bc 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -60,9 +60,9 @@ static boolean_t zpool_vdev_is_interior(const char *name); typedef struct prop_flags { - int create:1; /* Validate property on creation */ - int import:1; /* Validate property on import */ - int vdevprop:1; /* Validate property as a VDEV property */ + unsigned int create:1; /* Validate property on creation */ + unsigned int import:1; /* Validate property on import */ + unsigned int vdevprop:1; /* Validate property as a VDEV property */ } prop_flags_t; /* From 1e1ce10e5579a530606060f095f2f139916621fe Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Tue, 1 Nov 2022 20:45:36 +0000 Subject: [PATCH 101/126] Remove an unused variable Clang-16 detects this set-but-unused variable which is assigned and incremented, but never referenced otherwise. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Signed-off-by: Brooks Davis Closes #14125 --- module/zfs/zfs_fm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c index 06aa1214ace8..fd0dc7d69bf8 100644 --- a/module/zfs/zfs_fm.c +++ b/module/zfs/zfs_fm.c @@ -253,7 +253,6 @@ void zfs_ereport_clear(spa_t *spa, vdev_t *vd) { uint64_t vdev_guid, pool_guid; - int cnt = 0; ASSERT(vd != NULL || spa != NULL); if (vd == NULL) { @@ -277,7 +276,6 @@ zfs_ereport_clear(spa_t *spa, vdev_t *vd) avl_remove(&recent_events_tree, entry); list_remove(&recent_events_list, entry); kmem_free(entry, sizeof (*entry)); - cnt++; } } From 11e3416ae78d09380c523b703fad8dee145658d5 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 3 Nov 2022 13:47:48 -0400 Subject: [PATCH 102/126] Cleanup: Remove branches that always evaluate the same way Coverity reported that the ASSERT in taskq_create() is always true and the `*offp > MAXOFFSET_T` check in zfs_file_seek() is always false. We delete them as cleanup. Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14130 --- module/os/linux/spl/spl-taskq.c | 1 - module/os/linux/zfs/zfs_file_os.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/module/os/linux/spl/spl-taskq.c b/module/os/linux/spl/spl-taskq.c index abf4dca585b2..84497359ce2e 100644 --- a/module/os/linux/spl/spl-taskq.c +++ b/module/os/linux/spl/spl-taskq.c @@ -1048,7 +1048,6 @@ taskq_create(const char *name, int threads_arg, pri_t pri, ASSERT(name != NULL); ASSERT(minalloc >= 0); - ASSERT(maxalloc <= INT_MAX); ASSERT(!(flags & (TASKQ_CPR_SAFE))); /* Unsupported */ /* Scale the number of threads using nthreads as a percentage */ diff --git a/module/os/linux/zfs/zfs_file_os.c b/module/os/linux/zfs/zfs_file_os.c index da80428402cd..bc753614be27 100644 --- a/module/os/linux/zfs/zfs_file_os.c +++ b/module/os/linux/zfs/zfs_file_os.c @@ -246,7 +246,7 @@ zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence) { loff_t rc; - if (*offp < 0 || *offp > MAXOFFSET_T) + if (*offp < 0) return (EINVAL); rc = vfs_llseek(fp, *offp, whence); From 595d3ac2ed61331124feda2cf5787c3dd4c7ae09 Mon Sep 17 00:00:00 2001 From: Allan Jude Date: Thu, 3 Nov 2022 14:53:24 -0400 Subject: [PATCH 103/126] Allow mounting snapshots in .zfs/snapshot as a regular user Rather than doing a terrible credential swapping hack, we just check that the thing being mounted is a snapshot, and the mountpoint is the zfsctl directory, then we allow it. If the mount attempt is from inside a jail, on an unjailed dataset (mounted from the host, not by the jail), the ability to mount the snapshot is controlled by a new per-jail parameter: zfs.mount_snapshot Reviewed-by: Brian Behlendorf Co-authored-by: Ryan Moeller Signed-off-by: Ryan Moeller Signed-off-by: Allan Jude Sponsored-by: Modirum MDPay Sponsored-by: Klara Inc. Closes #13758 --- module/os/freebsd/spl/spl_vfs.c | 12 -- module/os/freebsd/zfs/zfs_vfsops.c | 278 ++++++++++++++++++++++++++++- 2 files changed, 274 insertions(+), 16 deletions(-) diff --git a/module/os/freebsd/spl/spl_vfs.c b/module/os/freebsd/spl/spl_vfs.c index ff11f5d7acb8..a07098afc5b4 100644 --- a/module/os/freebsd/spl/spl_vfs.c +++ b/module/os/freebsd/spl/spl_vfs.c @@ -125,7 +125,6 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, struct vfsconf *vfsp; struct mount *mp; vnode_t *vp, *mvp; - struct ucred *pcr, *tcr; int error; ASSERT_VOP_ELOCKED(*vpp, "mount_snapshot"); @@ -195,18 +194,7 @@ mount_snapshot(kthread_t *td, vnode_t **vpp, const char *fstype, char *fspath, */ mp->mnt_flag |= MNT_IGNORE; - /* - * XXX: This is evil, but we can't mount a snapshot as a regular user. - * XXX: Is is safe when snapshot is mounted from within a jail? - */ - tcr = td->td_ucred; - pcr = td->td_proc->p_ucred; - td->td_ucred = kcred; - td->td_proc->p_ucred = kcred; error = VFS_MOUNT(mp); - td->td_ucred = tcr; - td->td_proc->p_ucred = pcr; - if (error != 0) { /* * Clear VI_MOUNT and decrement the use count "atomically", diff --git a/module/os/freebsd/zfs/zfs_vfsops.c b/module/os/freebsd/zfs/zfs_vfsops.c index 4cb7f63b5230..b4c122bdf4c8 100644 --- a/module/os/freebsd/zfs/zfs_vfsops.c +++ b/module/os/freebsd/zfs/zfs_vfsops.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,20 @@ int zfs_debug_level; SYSCTL_INT(_vfs_zfs, OID_AUTO, debug, CTLFLAG_RWTUN, &zfs_debug_level, 0, "Debug level"); +struct zfs_jailparam { + int mount_snapshot; +}; + +static struct zfs_jailparam zfs_jailparam0 = { + .mount_snapshot = 0, +}; + +static int zfs_jailparam_slot; + +SYSCTL_JAIL_PARAM_SYS_NODE(zfs, CTLFLAG_RW, "Jail ZFS parameters"); +SYSCTL_JAIL_PARAM(_zfs, mount_snapshot, CTLTYPE_INT | CTLFLAG_RW, "I", + "Allow mounting snapshots in the .zfs directory for unjailed datasets"); + SYSCTL_NODE(_vfs_zfs, OID_AUTO, version, CTLFLAG_RD, 0, "ZFS versions"); static int zfs_version_acl = ZFS_ACL_VERSION; SYSCTL_INT(_vfs_zfs_version, OID_AUTO, acl, CTLFLAG_RD, &zfs_version_acl, 0, @@ -1298,7 +1313,7 @@ zfs_mount(vfs_t *vfsp) char *osname; int error = 0; int canwrite; - bool checkpointrewind; + bool checkpointrewind, isctlsnap = false; if (vfs_getopt(vfsp->mnt_optnew, "from", (void **)&osname, NULL)) return (SET_ERROR(EINVAL)); @@ -1313,6 +1328,7 @@ zfs_mount(vfs_t *vfsp) } fetch_osname_options(osname, &checkpointrewind); + isctlsnap = (zfsctl_is_node(mvp) && strchr(osname, '@') != NULL); /* * Check for mount privilege? @@ -1321,7 +1337,9 @@ zfs_mount(vfs_t *vfsp) * we have local permission to allow it */ error = secpolicy_fs_mount(cr, mvp, vfsp); - if (error) { + if (error && isctlsnap) { + secpolicy_fs_mount_clearopts(cr, vfsp); + } else if (error) { if (dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr) != 0) goto out; @@ -1358,8 +1376,27 @@ zfs_mount(vfs_t *vfsp) */ if (!INGLOBALZONE(curproc) && (!zone_dataset_visible(osname, &canwrite) || !canwrite)) { - error = SET_ERROR(EPERM); - goto out; + boolean_t mount_snapshot = B_FALSE; + + /* + * Snapshots may be mounted in .zfs for unjailed datasets + * if allowed by the jail param zfs.mount_snapshot. + */ + if (isctlsnap) { + struct prison *pr; + struct zfs_jailparam *zjp; + + pr = curthread->td_ucred->cr_prison; + mtx_lock(&pr->pr_mtx); + zjp = osd_jail_get(pr, zfs_jailparam_slot); + mtx_unlock(&pr->pr_mtx); + if (zjp && zjp->mount_snapshot) + mount_snapshot = B_TRUE; + } + if (!mount_snapshot) { + error = SET_ERROR(EPERM); + goto out; + } } vfsp->vfs_flag |= MNT_NFS4ACLS; @@ -2316,3 +2353,236 @@ zfsvfs_update_fromname(const char *oldname, const char *newname) mtx_unlock(&mountlist_mtx); } #endif + +/* + * Find a prison with ZFS info. + * Return the ZFS info and the (locked) prison. + */ +static struct zfs_jailparam * +zfs_jailparam_find(struct prison *spr, struct prison **prp) +{ + struct prison *pr; + struct zfs_jailparam *zjp; + + for (pr = spr; ; pr = pr->pr_parent) { + mtx_lock(&pr->pr_mtx); + if (pr == &prison0) { + zjp = &zfs_jailparam0; + break; + } + zjp = osd_jail_get(pr, zfs_jailparam_slot); + if (zjp != NULL) + break; + mtx_unlock(&pr->pr_mtx); + } + *prp = pr; + + return (zjp); +} + +/* + * Ensure a prison has its own ZFS info. If zjpp is non-null, point it to the + * ZFS info and lock the prison. + */ +static void +zfs_jailparam_alloc(struct prison *pr, struct zfs_jailparam **zjpp) +{ + struct prison *ppr; + struct zfs_jailparam *zjp, *nzjp; + void **rsv; + + /* If this prison already has ZFS info, return that. */ + zjp = zfs_jailparam_find(pr, &ppr); + if (ppr == pr) + goto done; + + /* + * Allocate a new info record. Then check again, in case something + * changed during the allocation. + */ + mtx_unlock(&ppr->pr_mtx); + nzjp = malloc(sizeof (struct zfs_jailparam), M_PRISON, M_WAITOK); + rsv = osd_reserve(zfs_jailparam_slot); + zjp = zfs_jailparam_find(pr, &ppr); + if (ppr == pr) { + free(nzjp, M_PRISON); + osd_free_reserved(rsv); + goto done; + } + /* Inherit the initial values from the ancestor. */ + mtx_lock(&pr->pr_mtx); + (void) osd_jail_set_reserved(pr, zfs_jailparam_slot, rsv, nzjp); + (void) memcpy(nzjp, zjp, sizeof (*zjp)); + zjp = nzjp; + mtx_unlock(&ppr->pr_mtx); +done: + if (zjpp != NULL) + *zjpp = zjp; + else + mtx_unlock(&pr->pr_mtx); +} + +/* + * Jail OSD methods for ZFS VFS info. + */ +static int +zfs_jailparam_create(void *obj, void *data) +{ + struct prison *pr = obj; + struct vfsoptlist *opts = data; + int jsys; + + if (vfs_copyopt(opts, "zfs", &jsys, sizeof (jsys)) == 0 && + jsys == JAIL_SYS_INHERIT) + return (0); + /* + * Inherit a prison's initial values from its parent + * (different from JAIL_SYS_INHERIT which also inherits changes). + */ + zfs_jailparam_alloc(pr, NULL); + return (0); +} + +static int +zfs_jailparam_get(void *obj, void *data) +{ + struct prison *ppr, *pr = obj; + struct vfsoptlist *opts = data; + struct zfs_jailparam *zjp; + int jsys, error; + + zjp = zfs_jailparam_find(pr, &ppr); + jsys = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT; + error = vfs_setopt(opts, "zfs", &jsys, sizeof (jsys)); + if (error != 0 && error != ENOENT) + goto done; + if (jsys == JAIL_SYS_NEW) { + error = vfs_setopt(opts, "zfs.mount_snapshot", + &zjp->mount_snapshot, sizeof (zjp->mount_snapshot)); + if (error != 0 && error != ENOENT) + goto done; + } else { + /* + * If this prison is inheriting its ZFS info, report + * empty/zero parameters. + */ + static int mount_snapshot = 0; + + error = vfs_setopt(opts, "zfs.mount_snapshot", + &mount_snapshot, sizeof (mount_snapshot)); + if (error != 0 && error != ENOENT) + goto done; + } + error = 0; +done: + mtx_unlock(&ppr->pr_mtx); + return (error); +} + +static int +zfs_jailparam_set(void *obj, void *data) +{ + struct prison *pr = obj; + struct prison *ppr; + struct vfsoptlist *opts = data; + int error, jsys, mount_snapshot; + + /* Set the parameters, which should be correct. */ + error = vfs_copyopt(opts, "zfs", &jsys, sizeof (jsys)); + if (error == ENOENT) + jsys = -1; + error = vfs_copyopt(opts, "zfs.mount_snapshot", &mount_snapshot, + sizeof (mount_snapshot)); + if (error == ENOENT) + mount_snapshot = -1; + else + jsys = JAIL_SYS_NEW; + if (jsys == JAIL_SYS_NEW) { + /* "zfs=new" or "zfs.*": the prison gets its own ZFS info. */ + struct zfs_jailparam *zjp; + + /* + * A child jail cannot have more permissions than its parent + */ + if (pr->pr_parent != &prison0) { + zjp = zfs_jailparam_find(pr->pr_parent, &ppr); + mtx_unlock(&ppr->pr_mtx); + if (zjp->mount_snapshot < mount_snapshot) { + return (EPERM); + } + } + zfs_jailparam_alloc(pr, &zjp); + if (mount_snapshot != -1) + zjp->mount_snapshot = mount_snapshot; + mtx_unlock(&pr->pr_mtx); + } else { + /* "zfs=inherit": inherit the parent's ZFS info. */ + mtx_lock(&pr->pr_mtx); + osd_jail_del(pr, zfs_jailparam_slot); + mtx_unlock(&pr->pr_mtx); + } + return (0); +} + +static int +zfs_jailparam_check(void *obj __unused, void *data) +{ + struct vfsoptlist *opts = data; + int error, jsys, mount_snapshot; + + /* Check that the parameters are correct. */ + error = vfs_copyopt(opts, "zfs", &jsys, sizeof (jsys)); + if (error != ENOENT) { + if (error != 0) + return (error); + if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT) + return (EINVAL); + } + error = vfs_copyopt(opts, "zfs.mount_snapshot", &mount_snapshot, + sizeof (mount_snapshot)); + if (error != ENOENT) { + if (error != 0) + return (error); + if (mount_snapshot != 0 && mount_snapshot != 1) + return (EINVAL); + } + return (0); +} + +static void +zfs_jailparam_destroy(void *data) +{ + + free(data, M_PRISON); +} + +static void +zfs_jailparam_sysinit(void *arg __unused) +{ + struct prison *pr; + osd_method_t methods[PR_MAXMETHOD] = { + [PR_METHOD_CREATE] = zfs_jailparam_create, + [PR_METHOD_GET] = zfs_jailparam_get, + [PR_METHOD_SET] = zfs_jailparam_set, + [PR_METHOD_CHECK] = zfs_jailparam_check, + }; + + zfs_jailparam_slot = osd_jail_register(zfs_jailparam_destroy, methods); + /* Copy the defaults to any existing prisons. */ + sx_slock(&allprison_lock); + TAILQ_FOREACH(pr, &allprison, pr_list) + zfs_jailparam_alloc(pr, NULL); + sx_sunlock(&allprison_lock); +} + +static void +zfs_jailparam_sysuninit(void *arg __unused) +{ + + osd_jail_deregister(zfs_jailparam_slot); +} + +SYSINIT(zfs_jailparam_sysinit, SI_SUB_DRIVERS, SI_ORDER_ANY, + zfs_jailparam_sysinit, NULL); +SYSUNINIT(zfs_jailparam_sysuninit, SI_SUB_DRIVERS, SI_ORDER_ANY, + zfs_jailparam_sysuninit, NULL); From f66ffe68787f9675ad7cce7644a1f81f28a86939 Mon Sep 17 00:00:00 2001 From: Serapheim Dimitropoulos Date: Thu, 3 Nov 2022 15:02:46 -0700 Subject: [PATCH 104/126] Expose zfs_vdev_open_timeout_ms as a tunable Some of our customers have been occasionally hitting zfs import failures in Linux because udevd doesn't create the by-id symbolic links in time for zpool import to use them. The main issue is that the systemd-udev-settle.service that zfs-import-cache.service and other services depend on is racy. There is also an openzfs issue filed (see https://github.com/openzfs/zfs/issues/10891) outlining the problem and potential solutions. With the proper solutions being significant in terms of complexity and the priority of the issue being low for the time being, this patch exposes `zfs_vdev_open_timeout_ms` as a tunable so people that are experiencing this issue often can increase it as a workaround. Reviewed-by: Matthew Ahrens Reviewed-by: Richard Yao Reviewed-by: Alexander Motin Reviewed-by: Don Brady Reviewed-by: Brian Behlendorf Signed-off-by: Serapheim Dimitropoulos Closes #14133 --- man/man4/zfs.4 | 7 +++++++ module/os/linux/zfs/vdev_disk.c | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index 2bfa3601fbcd..5b53b1310e49 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -1249,6 +1249,13 @@ Ideally, this will be at least the sum of each queue's .Sy max_active . .No See Sx ZFS I/O SCHEDULER . . +.It Sy zfs_vdev_open_timeout_ms Ns = Ns Sy 1000 Pq uint +Timeout value to wait before determining a device is missing +during import. +This is helpful for transient missing paths due +to links being briefly removed and recreated in response to +udev events. +. .It Sy zfs_vdev_rebuild_max_active Ns = Ns Sy 3 Pq uint Maximum sequential resilver I/O operations active to each device. .No See Sx ZFS I/O SCHEDULER . diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c index 11ed3ea6f4e0..84d191abb90b 100644 --- a/module/os/linux/zfs/vdev_disk.c +++ b/module/os/linux/zfs/vdev_disk.c @@ -56,7 +56,7 @@ static void *zfs_vdev_holder = VDEV_HOLDER; * device is missing. The missing path may be transient since the links * can be briefly removed and recreated in response to udev events. */ -static unsigned zfs_vdev_open_timeout_ms = 1000; +static uint_t zfs_vdev_open_timeout_ms = 1000; /* * Size of the "reserved" partition, in blocks. @@ -1042,3 +1042,6 @@ param_set_max_auto_ashift(const char *buf, zfs_kernel_param_t *kp) return (0); } + +ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, open_timeout_ms, UINT, ZMOD_RW, + "Timeout before determining that a device is missing"); From 993ee7a00670667f97d990aa5e38eb5cf5effc37 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Fri, 4 Nov 2022 14:06:14 -0400 Subject: [PATCH 105/126] FreeBSD: Fix out of bounds read in zfs_ioctl_ozfs_to_legacy() There is an off by 1 error in the check. Fortunately, this function does not appear to be used in kernel space, despite being compiled as part of the kernel module. However, it is used in userspace. Callers of lzc_ioctl_fd() likely will crash if they attempt to use the unimplemented request number. This was reported by FreeBSD's coverity scan. Reported-by: Coverity (CID 1432059) Reviewed-by: Ryan Moeller Reviewed-by: Damian Szuberski Reviewed-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #14135 --- module/os/freebsd/zfs/zfs_ioctl_compat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/os/freebsd/zfs/zfs_ioctl_compat.c b/module/os/freebsd/zfs/zfs_ioctl_compat.c index d495cc0dc3f1..08913ab05ddc 100644 --- a/module/os/freebsd/zfs/zfs_ioctl_compat.c +++ b/module/os/freebsd/zfs/zfs_ioctl_compat.c @@ -319,7 +319,7 @@ zfs_ioctl_legacy_to_ozfs(int request) int zfs_ioctl_ozfs_to_legacy(int request) { - if (request > ZFS_IOC_LAST) + if (request >= ZFS_IOC_LAST) return (-1); if (request > ZFS_IOC_PLATFORM) { From b844489ec0e35b0a9b3cda5ba72bf29334f81081 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Sun, 16 Oct 2022 16:53:22 +0200 Subject: [PATCH 106/126] icp: properly fix all RETs in x86_64 Asm code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 43569ee37420 ("Fix objtool: missing int3 after ret warning") addressed replacing all `ret`s in x86 asm code to a macro in the Linux kernel in order to enable SLS. That was done by copying the upstream macro definitions and fixed objtool complaints. Since then, several more mitigations were introduced, including Rethunk. It requires to have a jump to one of the thunks in order to work, so the RET macro was changed again. And, as ZFS code didn't use the mainline defition, but copied it, this is currently missing. Objtool reminds about it time to time (Clang 16, CONFIG_RETHUNK=y): fs/zfs/lua/zlua.o: warning: objtool: setjmp+0x25: 'naked' return found in RETHUNK build fs/zfs/lua/zlua.o: warning: objtool: longjmp+0x27: 'naked' return found in RETHUNK build Do it the following way: * if we're building under Linux, unconditionally include in the related files. It is available in x86 sources since even pre-2.6 times, so doesn't need any conftests; * then, if RET macro is available, it will be used directly, so that we will always have the version actual to the kernel we build; * if there's no such macro, we define it as a simple `ret`, as it was on pre-SLS times. This ensures we always have the up-to-date definition with no need to update it manually, and at the same time is safe for the whole variety of kernels ZFS module supports. Then, there's a couple more "naked" rets left in the code, they're just defined as: .byte 0xf3,0xc3 In fact, this is just: rep ret `rep ret` instead of just `ret` seems to mitigate performance issues on some old AMD processors and most likely makes no sense as of today. Anyways, address those rets, so that they will be protected with Rethunk and SLS. Include here which now always has RET definition and replace those constructs with just RET. This wipes the last couple of places with unpatched rets objtool's been complaining about. Reviewed-by: Attila FĂŒlöp Reviewed-by: Tino Reichardt Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Lobakin Closes #14035 --- module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S | 13 ++++++++----- module/icp/asm-x86_64/modes/ghash-x86_64.S | 9 ++++++--- module/icp/include/sys/ia32/asm_linkage.h | 9 ++++++--- module/lua/setjmp/setjmp_x86_64.S | 15 ++++++++------- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S index 70e419c2e4ab..7414b3540f34 100644 --- a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S +++ b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S @@ -47,6 +47,9 @@ #if defined(__x86_64__) && defined(HAVE_AVX) && \ defined(HAVE_AES) && defined(HAVE_PCLMULQDQ) +#define _ASM +#include + .extern gcm_avx_can_use_movbe .text @@ -363,7 +366,7 @@ _aesni_ctr32_ghash_6x: vpxor 16+8(%rsp),%xmm8,%xmm8 vpxor %xmm4,%xmm8,%xmm8 - .byte 0xf3,0xc3 + RET .cfi_endproc .size _aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x #endif /* ifdef HAVE_MOVBE */ @@ -691,7 +694,7 @@ _aesni_ctr32_ghash_no_movbe_6x: vpxor 16+8(%rsp),%xmm8,%xmm8 vpxor %xmm4,%xmm8,%xmm8 - .byte 0xf3,0xc3 + RET .cfi_endproc .size _aesni_ctr32_ghash_no_movbe_6x,.-_aesni_ctr32_ghash_no_movbe_6x @@ -810,7 +813,7 @@ aesni_gcm_decrypt: .cfi_def_cfa_register %rsp .Lgcm_dec_abort: movq %r10,%rax - .byte 0xf3,0xc3 + RET .cfi_endproc .size aesni_gcm_decrypt,.-aesni_gcm_decrypt .type _aesni_ctr32_6x,@function @@ -880,7 +883,7 @@ _aesni_ctr32_6x: vmovups %xmm14,80(%rsi) leaq 96(%rsi),%rsi - .byte 0xf3,0xc3 + RET .align 32 .Lhandle_ctr32_2: vpshufb %xmm0,%xmm1,%xmm6 @@ -1186,7 +1189,7 @@ aesni_gcm_encrypt: .cfi_def_cfa_register %rsp .Lgcm_enc_abort: movq %r10,%rax - .byte 0xf3,0xc3 + RET .cfi_endproc .size aesni_gcm_encrypt,.-aesni_gcm_encrypt diff --git a/module/icp/asm-x86_64/modes/ghash-x86_64.S b/module/icp/asm-x86_64/modes/ghash-x86_64.S index 90cc36b43a78..77a3ce185952 100644 --- a/module/icp/asm-x86_64/modes/ghash-x86_64.S +++ b/module/icp/asm-x86_64/modes/ghash-x86_64.S @@ -97,6 +97,9 @@ #if defined(__x86_64__) && defined(HAVE_AVX) && \ defined(HAVE_AES) && defined(HAVE_PCLMULQDQ) +#define _ASM +#include + .text .globl gcm_gmult_clmul @@ -149,7 +152,7 @@ gcm_gmult_clmul: pxor %xmm1,%xmm0 .byte 102,15,56,0,197 movdqu %xmm0,(%rdi) - .byte 0xf3,0xc3 + RET .cfi_endproc .size gcm_gmult_clmul,.-gcm_gmult_clmul @@ -262,7 +265,7 @@ gcm_init_htab_avx: vmovdqu %xmm5,-16(%rdi) vzeroupper - .byte 0xf3,0xc3 + RET .cfi_endproc .size gcm_init_htab_avx,.-gcm_init_htab_avx @@ -649,7 +652,7 @@ gcm_ghash_avx: vpshufb %xmm13,%xmm10,%xmm10 vmovdqu %xmm10,(%rdi) vzeroupper - .byte 0xf3,0xc3 + RET .cfi_endproc .size gcm_ghash_avx,.-gcm_ghash_avx .align 64 diff --git a/module/icp/include/sys/ia32/asm_linkage.h b/module/icp/include/sys/ia32/asm_linkage.h index 58964c5d4497..f0aa2dc184c7 100644 --- a/module/icp/include/sys/ia32/asm_linkage.h +++ b/module/icp/include/sys/ia32/asm_linkage.h @@ -30,9 +30,11 @@ #include #include -#if defined(__linux__) && defined(CONFIG_SLS) -#define RET ret; int3 -#else +#if defined(_KERNEL) && defined(__linux__) +#include +#endif + +#ifndef RET #define RET ret #endif @@ -122,6 +124,7 @@ extern "C" { * insert the calls to mcount for profiling. ENTRY_NP is identical, but * never calls mcount. */ +#undef ENTRY #define ENTRY(x) \ .text; \ .align ASM_ENTRY_ALIGN; \ diff --git a/module/lua/setjmp/setjmp_x86_64.S b/module/lua/setjmp/setjmp_x86_64.S index fd661d72eedf..7e13fea05dda 100644 --- a/module/lua/setjmp/setjmp_x86_64.S +++ b/module/lua/setjmp/setjmp_x86_64.S @@ -23,7 +23,15 @@ * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ +#if defined(_KERNEL) && defined(__linux__) +#include +#endif +#ifndef RET +#define RET ret +#endif + +#undef ENTRY #define ENTRY(x) \ .text; \ .align 8; \ @@ -34,13 +42,6 @@ x: #define SET_SIZE(x) \ .size x, [.-x] - -#if defined(__linux__) && defined(CONFIG_SLS) -#define RET ret; int3 -#else -#define RET ret -#endif - /* * Setjmp and longjmp implement non-local gotos using state vectors * type label_t. From 61cca6fa0506d41e5c794b293bedd982265fc1b2 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Sun, 16 Oct 2022 23:23:44 +0200 Subject: [PATCH 107/126] icp: fix rodata being marked as text in x86 Asm code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit objtool properly complains that it can't decode some of the instructions from ICP x86 Asm code. As mentioned in the Makefile, where those object files were excluded from objtool check (but they can still be visible under IBT and LTO), those are just constants, not code. In that case, they must be placed in .rodata, so they won't be marked as "allocatable, executable" (ax) in EFL headers and this effectively prevents objtool from trying to decode this data. That reveals a whole bunch of other issues in ICP Asm code, as previously objtool was bailing out after that warning message. Reviewed-by: Attila FĂŒlöp Reviewed-by: Tino Reichardt Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Lobakin Closes #14035 --- module/Kbuild.in | 6 +----- module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S | 2 ++ module/icp/asm-x86_64/modes/ghash-x86_64.S | 3 +++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/module/Kbuild.in b/module/Kbuild.in index 7a20e6ee4615..581d50e64b42 100644 --- a/module/Kbuild.in +++ b/module/Kbuild.in @@ -150,12 +150,8 @@ $(addprefix $(obj)/icp/,$(ICP_OBJS) $(ICP_OBJS_X86) $(ICP_OBJS_X86_64) \ $(addprefix $(obj)/icp/,$(ICP_OBJS) $(ICP_OBJS_X86) $(ICP_OBJS_X86_64) \ $(ICP_OBJS_ARM64) $(ICP_OBJS_PPC_PPC64)) : ccflags-y += -I$(icp_include) -# Suppress objtool "can't find jump dest instruction at" warnings. They -# are caused by the constants which are defined in the text section of the -# assembly file using .byte instructions (e.g. bswap_mask). The objtool -# utility tries to interpret them as opcodes and obviously fails doing so. +# Suppress objtool "return with modified stack frame" warnings. OBJECT_FILES_NON_STANDARD_aesni-gcm-x86_64.o := y -OBJECT_FILES_NON_STANDARD_ghash-x86_64.o := y # Suppress objtool "unsupported stack pointer realignment" warnings. We are # not using a DRAP register while aligning the stack to a 64 byte boundary. diff --git a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S index 7414b3540f34..6da43ee00597 100644 --- a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S +++ b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S @@ -1242,6 +1242,7 @@ atomic_toggle_boolean_nv: RET .size atomic_toggle_boolean_nv,.-atomic_toggle_boolean_nv +.pushsection .rodata .align 64 .Lbswap_mask: .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 @@ -1255,6 +1256,7 @@ atomic_toggle_boolean_nv: .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .byte 65,69,83,45,78,73,32,71,67,77,32,109,111,100,117,108,101,32,102,111,114,32,120,56,54,95,54,52,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0 .align 64 +.popsection /* Mark the stack non-executable. */ #if defined(__linux__) && defined(__ELF__) diff --git a/module/icp/asm-x86_64/modes/ghash-x86_64.S b/module/icp/asm-x86_64/modes/ghash-x86_64.S index 77a3ce185952..d7cdaeb368d7 100644 --- a/module/icp/asm-x86_64/modes/ghash-x86_64.S +++ b/module/icp/asm-x86_64/modes/ghash-x86_64.S @@ -655,6 +655,8 @@ gcm_ghash_avx: RET .cfi_endproc .size gcm_ghash_avx,.-gcm_ghash_avx + +.pushsection .rodata .align 64 .Lbswap_mask: .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 @@ -708,6 +710,7 @@ gcm_ghash_avx: .byte 71,72,65,83,72,32,102,111,114,32,120,56,54,95,54,52,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0 .align 64 +.popsection /* Mark the stack non-executable. */ #if defined(__linux__) && defined(__ELF__) From 73b8f700b68dc1c537781b2bee0f06c2b6d09418 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Sun, 16 Oct 2022 23:41:39 +0200 Subject: [PATCH 108/126] icp: fix all !ENDBR objtool warnings in x86 Asm code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, only Blake3 x86 Asm code has signs of being ENDBR-aware. At least, under certain conditions it includes some header file and uses some custom macro from there. Linux has its own NOENDBR since several releases ago. It's defined in the same , so currently already is provided with it. Let's unify those two into one %ENDBR macro. At first, check if it's present already. If so -- use Linux kernel version. Otherwise, try to go that second way and use %_CET_ENDBR from if available. If no, fall back to just empty definition. This fixes a couple more 'relocations to !ENDBR' across the module. And now that we always have the latest/actual ENDBR definition, use it at the entrance of the few corresponding functions that objtool still complains about. This matches the way how it's used in the upstream x86 core Asm code. Reviewed-by: Attila FĂŒlöp Reviewed-by: Tino Reichardt Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Lobakin Closes #14035 --- module/icp/asm-x86_64/aes/aes_amd64.S | 2 ++ module/icp/asm-x86_64/blake3/blake3_avx2.S | 12 +----------- module/icp/asm-x86_64/blake3/blake3_avx512.S | 16 +++------------- module/icp/asm-x86_64/blake3/blake3_sse2.S | 16 +++------------- module/icp/asm-x86_64/blake3/blake3_sse41.S | 16 +++------------- module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S | 5 +++++ module/icp/asm-x86_64/modes/ghash-x86_64.S | 4 ++++ module/icp/asm-x86_64/sha2/sha256_impl.S | 1 + module/icp/asm-x86_64/sha2/sha512_impl.S | 1 + module/icp/include/sys/ia32/asm_linkage.h | 18 ++++++++++++++++++ 10 files changed, 41 insertions(+), 50 deletions(-) diff --git a/module/icp/asm-x86_64/aes/aes_amd64.S b/module/icp/asm-x86_64/aes/aes_amd64.S index f546e8933be1..a0525dd464f5 100644 --- a/module/icp/asm-x86_64/aes/aes_amd64.S +++ b/module/icp/asm-x86_64/aes/aes_amd64.S @@ -704,6 +704,7 @@ enc_tab: ENTRY_NP(aes_encrypt_amd64) + ENDBR #ifdef GLADMAN_INTERFACE // Original interface sub $[4*8], %rsp // gnu/linux/opensolaris binary interface @@ -809,6 +810,7 @@ dec_tab: ENTRY_NP(aes_decrypt_amd64) + ENDBR #ifdef GLADMAN_INTERFACE // Original interface sub $[4*8], %rsp // gnu/linux/opensolaris binary interface diff --git a/module/icp/asm-x86_64/blake3/blake3_avx2.S b/module/icp/asm-x86_64/blake3/blake3_avx2.S index f4d9cb766d46..cb08430b81ed 100644 --- a/module/icp/asm-x86_64/blake3/blake3_avx2.S +++ b/module/icp/asm-x86_64/blake3/blake3_avx2.S @@ -30,16 +30,6 @@ #define _ASM #include -#if defined(__ELF__) && defined(__CET__) && defined(__has_include) -#if __has_include() -#include -#endif -#endif - -#if !defined(_CET_ENDBR) -#define _CET_ENDBR -#endif - .intel_syntax noprefix .global zfs_blake3_hash_many_avx2 .text @@ -47,7 +37,7 @@ .type zfs_blake3_hash_many_avx2,@function .p2align 6 zfs_blake3_hash_many_avx2: - _CET_ENDBR + ENDBR push r15 push r14 push r13 diff --git a/module/icp/asm-x86_64/blake3/blake3_avx512.S b/module/icp/asm-x86_64/blake3/blake3_avx512.S index 71b5715c88c1..960406ea2c01 100644 --- a/module/icp/asm-x86_64/blake3/blake3_avx512.S +++ b/module/icp/asm-x86_64/blake3/blake3_avx512.S @@ -30,16 +30,6 @@ #define _ASM #include -#if defined(__ELF__) && defined(__CET__) && defined(__has_include) -#if __has_include() -#include -#endif -#endif - -#if !defined(_CET_ENDBR) -#define _CET_ENDBR -#endif - .intel_syntax noprefix .global zfs_blake3_hash_many_avx512 .global zfs_blake3_compress_in_place_avx512 @@ -52,7 +42,7 @@ .p2align 6 zfs_blake3_hash_many_avx512: - _CET_ENDBR + ENDBR push r15 push r14 push r13 @@ -2409,7 +2399,7 @@ zfs_blake3_hash_many_avx512: jmp 4b .p2align 6 zfs_blake3_compress_in_place_avx512: - _CET_ENDBR + ENDBR vmovdqu xmm0, xmmword ptr [rdi] vmovdqu xmm1, xmmword ptr [rdi+0x10] movzx eax, r8b @@ -2491,7 +2481,7 @@ zfs_blake3_compress_in_place_avx512: .p2align 6 zfs_blake3_compress_xof_avx512: - _CET_ENDBR + ENDBR vmovdqu xmm0, xmmword ptr [rdi] vmovdqu xmm1, xmmword ptr [rdi+0x10] movzx eax, r8b diff --git a/module/icp/asm-x86_64/blake3/blake3_sse2.S b/module/icp/asm-x86_64/blake3/blake3_sse2.S index 20689a7dcef5..c4290aaa8faf 100644 --- a/module/icp/asm-x86_64/blake3/blake3_sse2.S +++ b/module/icp/asm-x86_64/blake3/blake3_sse2.S @@ -30,16 +30,6 @@ #define _ASM #include -#if defined(__ELF__) && defined(__CET__) && defined(__has_include) -#if __has_include() -#include -#endif -#endif - -#if !defined(_CET_ENDBR) -#define _CET_ENDBR -#endif - .intel_syntax noprefix .global zfs_blake3_hash_many_sse2 .global zfs_blake3_compress_in_place_sse2 @@ -52,7 +42,7 @@ .p2align 6 zfs_blake3_hash_many_sse2: - _CET_ENDBR + ENDBR push r15 push r14 push r13 @@ -2050,7 +2040,7 @@ zfs_blake3_hash_many_sse2: .p2align 6 zfs_blake3_compress_in_place_sse2: - _CET_ENDBR + ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] @@ -2161,7 +2151,7 @@ zfs_blake3_compress_in_place_sse2: .p2align 6 zfs_blake3_compress_xof_sse2: - _CET_ENDBR + ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] diff --git a/module/icp/asm-x86_64/blake3/blake3_sse41.S b/module/icp/asm-x86_64/blake3/blake3_sse41.S index c5975a4f0877..45b90cc9ed89 100644 --- a/module/icp/asm-x86_64/blake3/blake3_sse41.S +++ b/module/icp/asm-x86_64/blake3/blake3_sse41.S @@ -30,16 +30,6 @@ #define _ASM #include -#if defined(__ELF__) && defined(__CET__) && defined(__has_include) -#if __has_include() -#include -#endif -#endif - -#if !defined(_CET_ENDBR) -#define _CET_ENDBR -#endif - .intel_syntax noprefix .global zfs_blake3_compress_in_place_sse41 .global zfs_blake3_compress_xof_sse41 @@ -52,7 +42,7 @@ .p2align 6 zfs_blake3_hash_many_sse41: - _CET_ENDBR + ENDBR push r15 push r14 push r13 @@ -1812,7 +1802,7 @@ zfs_blake3_hash_many_sse41: jmp 4b .p2align 6 zfs_blake3_compress_in_place_sse41: - _CET_ENDBR + ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] @@ -1911,7 +1901,7 @@ zfs_blake3_compress_in_place_sse41: RET .p2align 6 zfs_blake3_compress_xof_sse41: - _CET_ENDBR + ENDBR movups xmm0, xmmword ptr [rdi] movups xmm1, xmmword ptr [rdi+0x10] movaps xmm2, xmmword ptr [BLAKE3_IV+rip] diff --git a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S index 6da43ee00597..cf17b3768712 100644 --- a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S +++ b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S @@ -59,6 +59,7 @@ .align 32 _aesni_ctr32_ghash_6x: .cfi_startproc + ENDBR vmovdqu 32(%r11),%xmm2 subq $6,%rdx vpxor %xmm4,%xmm4,%xmm4 @@ -375,6 +376,7 @@ _aesni_ctr32_ghash_6x: .align 32 _aesni_ctr32_ghash_no_movbe_6x: .cfi_startproc + ENDBR vmovdqu 32(%r11),%xmm2 subq $6,%rdx vpxor %xmm4,%xmm4,%xmm4 @@ -703,6 +705,7 @@ _aesni_ctr32_ghash_no_movbe_6x: .align 32 aesni_gcm_decrypt: .cfi_startproc + ENDBR xorq %r10,%r10 cmpq $0x60,%rdx jb .Lgcm_dec_abort @@ -820,6 +823,7 @@ aesni_gcm_decrypt: .align 32 _aesni_ctr32_6x: .cfi_startproc + ENDBR vmovdqu 0-128(%rcx),%xmm4 vmovdqu 32(%r11),%xmm2 leaq -2(%rbp),%r13 // ICP uses 10,12,14 not 9,11,13 for rounds. @@ -914,6 +918,7 @@ _aesni_ctr32_6x: .align 32 aesni_gcm_encrypt: .cfi_startproc + ENDBR xorq %r10,%r10 cmpq $288,%rdx jb .Lgcm_enc_abort diff --git a/module/icp/asm-x86_64/modes/ghash-x86_64.S b/module/icp/asm-x86_64/modes/ghash-x86_64.S index d7cdaeb368d7..bf3724a23eae 100644 --- a/module/icp/asm-x86_64/modes/ghash-x86_64.S +++ b/module/icp/asm-x86_64/modes/ghash-x86_64.S @@ -107,6 +107,7 @@ .align 16 gcm_gmult_clmul: .cfi_startproc + ENDBR .L_gmult_clmul: movdqu (%rdi),%xmm0 movdqa .Lbswap_mask(%rip),%xmm5 @@ -161,6 +162,7 @@ gcm_gmult_clmul: .align 32 gcm_init_htab_avx: .cfi_startproc + ENDBR vzeroupper vmovdqu (%rsi),%xmm2 @@ -274,6 +276,7 @@ gcm_init_htab_avx: .align 32 gcm_gmult_avx: .cfi_startproc + ENDBR jmp .L_gmult_clmul .cfi_endproc .size gcm_gmult_avx,.-gcm_gmult_avx @@ -282,6 +285,7 @@ gcm_gmult_avx: .align 32 gcm_ghash_avx: .cfi_startproc + ENDBR vzeroupper vmovdqu (%rdi),%xmm10 diff --git a/module/icp/asm-x86_64/sha2/sha256_impl.S b/module/icp/asm-x86_64/sha2/sha256_impl.S index 1391bd59a017..60d34b4a3be0 100644 --- a/module/icp/asm-x86_64/sha2/sha256_impl.S +++ b/module/icp/asm-x86_64/sha2/sha256_impl.S @@ -84,6 +84,7 @@ SHA256TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num) ENTRY_NP(SHA256TransformBlocks) .cfi_startproc + ENDBR movq %rsp, %rax .cfi_def_cfa_register %rax push %rbx diff --git a/module/icp/asm-x86_64/sha2/sha512_impl.S b/module/icp/asm-x86_64/sha2/sha512_impl.S index e61e96957bc6..ed7fb362a1ac 100644 --- a/module/icp/asm-x86_64/sha2/sha512_impl.S +++ b/module/icp/asm-x86_64/sha2/sha512_impl.S @@ -85,6 +85,7 @@ SHA512TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num) ENTRY_NP(SHA512TransformBlocks) .cfi_startproc + ENDBR movq %rsp, %rax .cfi_def_cfa_register %rax push %rbx diff --git a/module/icp/include/sys/ia32/asm_linkage.h b/module/icp/include/sys/ia32/asm_linkage.h index f0aa2dc184c7..e3e769ffd858 100644 --- a/module/icp/include/sys/ia32/asm_linkage.h +++ b/module/icp/include/sys/ia32/asm_linkage.h @@ -34,6 +34,24 @@ #include #endif +#ifndef ENDBR +#if defined(__ELF__) && defined(__CET__) && defined(__has_include) +/* CSTYLED */ +#if __has_include() + +#include + +#ifdef _CET_ENDBR +#define ENDBR _CET_ENDBR +#endif /* _CET_ENDBR */ + +#endif /* */ +#endif /* __ELF__ && __CET__ && __has_include */ +#endif /* !ENDBR */ + +#ifndef ENDBR +#define ENDBR +#endif #ifndef RET #define RET ret #endif From c23738c70eb86a7f04f93292caef2ed977047608 Mon Sep 17 00:00:00 2001 From: Ameer Hamza <106930537+ixhamza@users.noreply.github.com> Date: Fri, 4 Nov 2022 23:33:47 +0500 Subject: [PATCH 109/126] zed: Prevent special vdev to be replaced by hot spare Special vdevs should not be replaced by a hot spare. Log vdevs already support this, extending the functionality for special vdevs. Reviewed-by: Ryan Moeller Reviewed-by: Tony Hutter Reviewed-by: Richard Yao Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Ameer Hamza Closes #14129 --- module/zfs/spa.c | 6 ++++-- .../tests/functional/fault/auto_offline_001_pos.ksh | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/module/zfs/spa.c b/module/zfs/spa.c index de5bbcc09412..fe7051db2737 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -6819,10 +6819,12 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing, return (spa_vdev_exit(spa, newrootvd, txg, error)); /* - * Spares can't replace logs + * log, dedup and special vdevs should not be replaced by spares. */ - if (oldvd->vdev_top->vdev_islog && newvd->vdev_isspare) + if ((oldvd->vdev_top->vdev_alloc_bias != VDEV_BIAS_NONE || + oldvd->vdev_top->vdev_islog) && newvd->vdev_isspare) { return (spa_vdev_exit(spa, newrootvd, txg, ENOTSUP)); + } /* * A dRAID spare can only replace a child of its parent dRAID vdev. diff --git a/tests/zfs-tests/tests/functional/fault/auto_offline_001_pos.ksh b/tests/zfs-tests/tests/functional/fault/auto_offline_001_pos.ksh index 0ab9317c0a06..c0387e1d3235 100755 --- a/tests/zfs-tests/tests/functional/fault/auto_offline_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/fault/auto_offline_001_pos.ksh @@ -121,6 +121,11 @@ done # the removed data device for conf in "${poolconfs[@]}" do + # special vdev can not be replaced by a hot spare + if [[ $conf = *"special mirror"* ]]; then + continue + fi + # 1. Create a pool with a spare log_must zpool create -f $TESTPOOL $conf block_device_wait ${DEV_DSKDIR}/${removedev} From 270b1b5fa75adc54d5af5794a885d05120f83640 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 22:24:42 +0100 Subject: [PATCH 110/126] freebsd: remove unused vn_rename() Reviewed-by: Ryan Moeller Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14127 --- include/os/freebsd/spl/sys/vnode.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/os/freebsd/spl/sys/vnode.h b/include/os/freebsd/spl/sys/vnode.h index bbadf569c776..084289b6bfcd 100644 --- a/include/os/freebsd/spl/sys/vnode.h +++ b/include/os/freebsd/spl/sys/vnode.h @@ -205,15 +205,6 @@ vattr_init_mask(vattr_t *vap) #define RLIM64_INFINITY 0 -static __inline int -vn_rename(char *from, char *to, enum uio_seg seg) -{ - - ASSERT(seg == UIO_SYSSPACE); - - return (kern_renameat(curthread, AT_FDCWD, from, AT_FDCWD, to, seg)); -} - #include #endif /* _OPENSOLARIS_SYS_VNODE_H_ */ From 6c89cffc2cccbca82314bf276d31512f9dc4f6ec Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 22:28:55 +0100 Subject: [PATCH 111/126] freebsd: remove no-op vn_renamepath() vn_renamepath() is a Solaris-ism that was defined away in the FreeBSD port. Now that the only use is in the FreeBSD zfs_vnops_os.c, drop it entierly. Reviewed-by: Ryan Moeller Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14127 --- include/os/freebsd/spl/sys/vnode.h | 1 - module/os/freebsd/zfs/zfs_vnops_os.c | 5 ----- 2 files changed, 6 deletions(-) diff --git a/include/os/freebsd/spl/sys/vnode.h b/include/os/freebsd/spl/sys/vnode.h index 084289b6bfcd..483d12ae59a2 100644 --- a/include/os/freebsd/spl/sys/vnode.h +++ b/include/os/freebsd/spl/sys/vnode.h @@ -107,7 +107,6 @@ vn_flush_cached_data(vnode_t *vp, boolean_t sync) #define vn_exists(vp) do { } while (0) #define vn_invalid(vp) do { } while (0) -#define vn_renamepath(tdvp, svp, tnm, lentnm) do { } while (0) #define vn_free(vp) do { } while (0) #define vn_matchops(vp, vops) ((vp)->v_op == &(vops)) diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index bcf4e2f18d83..8a350ab4985c 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -3373,11 +3373,6 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, if (error == 0) { zfs_log_rename(zilog, tx, TX_RENAME, sdzp, snm, tdzp, tnm, szp); - - /* - * Update path information for the target vnode - */ - vn_renamepath(tdvp, *svpp, tnm, strlen(tnm)); } else { /* * At this point, we have successfully created From 20b867f5f716fedab675f5eac395e7e1ea54572d Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 27 Oct 2022 22:45:44 +0100 Subject: [PATCH 112/126] freebsd: add ifdefs around legacy ioctl support Require that ZFS_LEGACY_SUPPORT be defined for legacy ioctl support to be built. For now, define it in zfs_ioctl_compat.h so support is always built. This will allow systems that need never support pre-openzfs tools a mechanism to remove support at build time. This code should be removed once the need for tool compatability is gone. No functional change at this time. Reviewed-by: Ryan Moeller Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14127 --- include/os/freebsd/zfs/sys/zfs_ioctl_compat.h | 13 +++++++++++++ lib/libzfs_core/os/freebsd/libzfs_core_ioctl.c | 13 ++++++++++++- lib/libzpool/util.c | 4 ++++ module/os/freebsd/zfs/kmod_core.c | 16 ++++++++++++++-- module/os/freebsd/zfs/zfs_ioctl_compat.c | 2 ++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/include/os/freebsd/zfs/sys/zfs_ioctl_compat.h b/include/os/freebsd/zfs/sys/zfs_ioctl_compat.h index 79b30b5088c4..34757a486028 100644 --- a/include/os/freebsd/zfs/sys/zfs_ioctl_compat.h +++ b/include/os/freebsd/zfs/sys/zfs_ioctl_compat.h @@ -37,6 +37,15 @@ #include #endif /* _KERNEL */ +/* + * Legacy ioctl support allows compatibility with pre-OpenZFS tools on + * FreeBSD. The need for it will eventually pass (perhaps after FreeBSD + * 12 is well out of support), at which point this code can be removed. + * For now, downstream consumers may choose to disable this code by + * removing the following define. + */ +#define ZFS_LEGACY_SUPPORT + #ifdef __cplusplus extern "C" { #endif @@ -82,6 +91,7 @@ typedef struct zfs_iocparm { } zfs_iocparm_t; +#ifdef ZFS_LEGACY_SUPPORT #define LEGACY_MAXPATHLEN 1024 #define LEGACY_MAXNAMELEN 256 @@ -135,6 +145,7 @@ typedef struct zfs_cmd_legacy { uint64_t zc_createtxg; zfs_stat_t zc_stat; } zfs_cmd_legacy_t; +#endif #ifdef _KERNEL @@ -145,10 +156,12 @@ nvlist_t *zfs_ioctl_compat_innvl(zfs_cmd_t *, nvlist_t *, const int, nvlist_t *zfs_ioctl_compat_outnvl(zfs_cmd_t *, nvlist_t *, const int, const int); #endif /* _KERNEL */ +#ifdef ZFS_LEGACY_SUPPORT int zfs_ioctl_legacy_to_ozfs(int request); int zfs_ioctl_ozfs_to_legacy(int request); void zfs_cmd_legacy_to_ozfs(zfs_cmd_legacy_t *src, zfs_cmd_t *dst); void zfs_cmd_ozfs_to_legacy(zfs_cmd_t *src, zfs_cmd_legacy_t *dst); +#endif void zfs_cmd_compat_put(zfs_cmd_t *, caddr_t, const int, const int); diff --git a/lib/libzfs_core/os/freebsd/libzfs_core_ioctl.c b/lib/libzfs_core/os/freebsd/libzfs_core_ioctl.c index 36fbbd88c2ac..72f8f393039a 100644 --- a/lib/libzfs_core/os/freebsd/libzfs_core_ioctl.c +++ b/lib/libzfs_core/os/freebsd/libzfs_core_ioctl.c @@ -46,8 +46,11 @@ get_zfs_ioctl_version(void) static int zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag) { - int newrequest, ret; + int ret; +#ifdef ZFS_LEGACY_SUPPORT + int newrequest; void *zc_c = NULL; +#endif unsigned long ncmd; zfs_iocparm_t zp; @@ -58,6 +61,7 @@ zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag) zp.zfs_cmd_size = sizeof (zfs_cmd_t); zp.zfs_ioctl_version = ZFS_IOCVER_OZFS; break; +#ifdef ZFS_LEGACY_SUPPORT case ZFS_CMD_COMPAT_LEGACY: newrequest = zfs_ioctl_ozfs_to_legacy(request); ncmd = _IOWR('Z', newrequest, zfs_iocparm_t); @@ -67,6 +71,7 @@ zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag) zp.zfs_cmd_size = sizeof (zfs_cmd_legacy_t); zp.zfs_ioctl_version = ZFS_IOCVER_LEGACY; break; +#endif default: abort(); return (EINVAL); @@ -74,14 +79,18 @@ zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag) ret = ioctl(fd, ncmd, &zp); if (ret) { +#ifdef ZFS_LEGACY_SUPPORT if (zc_c) free(zc_c); +#endif return (ret); } +#ifdef ZFS_LEGACY_SUPPORT if (zc_c) { zfs_cmd_legacy_to_ozfs(zc_c, zc); free(zc_c); } +#endif return (ret); } @@ -100,9 +109,11 @@ lzc_ioctl_fd(int fd, unsigned long request, zfs_cmd_t *zc) zfs_ioctl_version = get_zfs_ioctl_version(); switch (zfs_ioctl_version) { +#ifdef ZFS_LEGACY_SUPPORT case ZFS_IOCVER_LEGACY: cflag = ZFS_CMD_COMPAT_LEGACY; break; +#endif case ZFS_IOCVER_OZFS: cflag = ZFS_CMD_COMPAT_NONE; break; diff --git a/lib/libzpool/util.c b/lib/libzpool/util.c index a310255d7a7d..551f1294d31f 100644 --- a/lib/libzpool/util.c +++ b/lib/libzpool/util.c @@ -261,7 +261,9 @@ pool_active(void *unused, const char *name, uint64_t guid, boolean_t *isactive) (void) unused, (void) guid; zfs_iocparm_t zp; zfs_cmd_t *zc = NULL; +#ifdef ZFS_LEGACY_SUPPORT zfs_cmd_legacy_t *zcl = NULL; +#endif unsigned long request; int ret; @@ -296,6 +298,7 @@ pool_active(void *unused, const char *name, uint64_t guid, boolean_t *isactive) umem_free(zc, sizeof (zfs_cmd_t)); break; +#ifdef ZFS_LEGACY_SUPPORT case ZFS_IOCVER_LEGACY: zcl = umem_zalloc(sizeof (zfs_cmd_legacy_t), UMEM_NOFAIL); @@ -311,6 +314,7 @@ pool_active(void *unused, const char *name, uint64_t guid, boolean_t *isactive) umem_free(zcl, sizeof (zfs_cmd_legacy_t)); break; +#endif default: fprintf(stderr, "unrecognized zfs ioctl version %d", ver); exit(1); diff --git a/module/os/freebsd/zfs/kmod_core.c b/module/os/freebsd/zfs/kmod_core.c index 020ef6a39b5e..6885d565e26c 100644 --- a/module/os/freebsd/zfs/kmod_core.c +++ b/module/os/freebsd/zfs/kmod_core.c @@ -124,7 +124,9 @@ zfsdev_ioctl(struct cdev *dev, ulong_t zcmd, caddr_t arg, int flag, int vecnum; zfs_iocparm_t *zp; zfs_cmd_t *zc; +#ifdef ZFS_LEGACY_SUPPORT zfs_cmd_legacy_t *zcl; +#endif int rc, error; void *uaddr; @@ -133,7 +135,9 @@ zfsdev_ioctl(struct cdev *dev, ulong_t zcmd, caddr_t arg, int flag, zp = (void *)arg; uaddr = (void *)zp->zfs_cmd; error = 0; +#ifdef ZFS_LEGACY_SUPPORT zcl = NULL; +#endif if (len != sizeof (zfs_iocparm_t)) { printf("len %d vecnum: %d sizeof (zfs_cmd_t) %ju\n", @@ -142,6 +146,7 @@ zfsdev_ioctl(struct cdev *dev, ulong_t zcmd, caddr_t arg, int flag, } zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP); +#ifdef ZFS_LEGACY_SUPPORT /* * Remap ioctl code for legacy user binaries */ @@ -157,22 +162,29 @@ zfsdev_ioctl(struct cdev *dev, ulong_t zcmd, caddr_t arg, int flag, goto out; } zfs_cmd_legacy_to_ozfs(zcl, zc); - } else if (copyin(uaddr, zc, sizeof (zfs_cmd_t))) { + } else +#endif + if (copyin(uaddr, zc, sizeof (zfs_cmd_t))) { error = SET_ERROR(EFAULT); goto out; } error = zfsdev_ioctl_common(vecnum, zc, 0); +#ifdef ZFS_LEGACY_SUPPORT if (zcl) { zfs_cmd_ozfs_to_legacy(zc, zcl); rc = copyout(zcl, uaddr, sizeof (*zcl)); - } else { + } else +#endif + { rc = copyout(zc, uaddr, sizeof (*zc)); } if (error == 0 && rc != 0) error = SET_ERROR(EFAULT); out: +#ifdef ZFS_LEGACY_SUPPORT if (zcl) kmem_free(zcl, sizeof (zfs_cmd_legacy_t)); +#endif kmem_free(zc, sizeof (zfs_cmd_t)); MPASS(tsd_get(rrw_tsd_key) == NULL); return (error); diff --git a/module/os/freebsd/zfs/zfs_ioctl_compat.c b/module/os/freebsd/zfs/zfs_ioctl_compat.c index 08913ab05ddc..3ddffec91e83 100644 --- a/module/os/freebsd/zfs/zfs_ioctl_compat.c +++ b/module/os/freebsd/zfs/zfs_ioctl_compat.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef ZFS_LEGACY_SUPPORT enum zfs_ioc_legacy { ZFS_IOC_LEGACY_NONE = -1, ZFS_IOC_LEGACY_FIRST = 0, @@ -361,3 +362,4 @@ zfs_cmd_ozfs_to_legacy(zfs_cmd_t *src, zfs_cmd_legacy_t *dst) sizeof (zfs_cmd_t) - 8 - offsetof(zfs_cmd_t, zc_sendobj)); dst->zc_jailid = src->zc_zoneid; } +#endif /* ZFS_LEGACY_SUPPORT */ From e3ba8eb12ef80a102a3f208a5a8d43eee3d21931 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Fri, 28 Oct 2022 00:41:53 +0100 Subject: [PATCH 113/126] freebsd: trim dkio.h to the minimum Only DKIOCFLUSHWRITECACHE is required. Reviewed-by: Ryan Moeller Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14127 --- include/os/freebsd/spl/sys/dkio.h | 460 ------------------------------ 1 file changed, 460 deletions(-) diff --git a/include/os/freebsd/spl/sys/dkio.h b/include/os/freebsd/spl/sys/dkio.h index 009886cb0763..cd747089d422 100644 --- a/include/os/freebsd/spl/sys/dkio.h +++ b/include/os/freebsd/spl/sys/dkio.h @@ -28,467 +28,7 @@ #ifndef _OPENSOLARIS_SYS_DKIO_H_ #define _OPENSOLARIS_SYS_DKIO_H_ -#include /* Needed for NDKMAP define */ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_SUNOS_VTOC_16) -#define NDKMAP 16 /* # of logical partitions */ -#define DK_LABEL_LOC 1 /* location of disk label */ -#elif defined(_SUNOS_VTOC_8) -#define NDKMAP 8 /* # of logical partitions */ -#define DK_LABEL_LOC 0 /* location of disk label */ -#else -#error "No VTOC format defined." -#endif - -/* - * Structures and definitions for disk io control commands - */ - -/* - * Structures used as data by ioctl calls. - */ - -#define DK_DEVLEN 16 /* device name max length, including */ - /* unit # & NULL (ie - "xyc1") */ - -/* - * Used for controller info - */ -struct dk_cinfo { - char dki_cname[DK_DEVLEN]; /* controller name (no unit #) */ - ushort_t dki_ctype; /* controller type */ - ushort_t dki_flags; /* flags */ - ushort_t dki_cnum; /* controller number */ - uint_t dki_addr; /* controller address */ - uint_t dki_space; /* controller bus type */ - uint_t dki_prio; /* interrupt priority */ - uint_t dki_vec; /* interrupt vector */ - char dki_dname[DK_DEVLEN]; /* drive name (no unit #) */ - uint_t dki_unit; /* unit number */ - ushort_t dki_partition; /* partition number */ - ushort_t dki_maxtransfer; /* max. transfer size in DEV_BSIZE */ -}; - -/* - * Controller types - */ -#define DKC_UNKNOWN 0 -#define DKC_CDROM 1 /* CD-ROM, SCSI or otherwise */ -#define DKC_WDC2880 2 -#define DKC_XXX_0 3 /* unassigned */ -#define DKC_XXX_1 4 /* unassigned */ -#define DKC_DSD5215 5 -#define DKC_ACB4000 7 -#define DKC_MD21 8 -#define DKC_XXX_2 9 /* unassigned */ -#define DKC_NCRFLOPPY 10 -#define DKC_SMSFLOPPY 12 -#define DKC_SCSI_CCS 13 /* SCSI CCS compatible */ -#define DKC_INTEL82072 14 /* native floppy chip */ -#define DKC_MD 16 /* meta-disk (virtual-disk) driver */ -#define DKC_INTEL82077 19 /* 82077 floppy disk controller */ -#define DKC_DIRECT 20 /* Intel direct attached device i.e. IDE */ -#define DKC_PCMCIA_MEM 21 /* PCMCIA memory disk-like type */ -#define DKC_PCMCIA_ATA 22 /* PCMCIA AT Attached type */ -#define DKC_VBD 23 /* virtual block device */ - -/* - * Sun reserves up through 1023 - */ - -#define DKC_CUSTOMER_BASE 1024 - -/* - * Flags - */ -#define DKI_BAD144 0x01 /* use DEC std 144 bad sector fwding */ -#define DKI_MAPTRK 0x02 /* controller does track mapping */ -#define DKI_FMTTRK 0x04 /* formats only full track at a time */ -#define DKI_FMTVOL 0x08 /* formats only full volume at a time */ -#define DKI_FMTCYL 0x10 /* formats only full cylinders at a time */ -#define DKI_HEXUNIT 0x20 /* unit number is printed as 3 hex digits */ -#define DKI_PCMCIA_PFD 0x40 /* PCMCIA pseudo-floppy memory card */ - -/* - * partition headers: section 1 - * Returned in struct dk_allmap by ioctl DKIOC[SG]APART (dkio(7I)) - */ -struct dk_map { - uint64_t dkl_cylno; /* starting cylinder */ - uint64_t dkl_nblk; /* number of blocks; if == 0, */ - /* partition is undefined */ -}; - -/* - * Used for all partitions - */ -struct dk_allmap { - struct dk_map dka_map[NDKMAP]; -}; - -#if defined(_SYSCALL32) -struct dk_allmap32 { - struct dk_map32 dka_map[NDKMAP]; -}; -#endif /* _SYSCALL32 */ - -/* - * Definition of a disk's geometry - */ -struct dk_geom { - unsigned short dkg_ncyl; /* # of data cylinders */ - unsigned short dkg_acyl; /* # of alternate cylinders */ - unsigned short dkg_bcyl; /* cyl offset (for fixed head area) */ - unsigned short dkg_nhead; /* # of heads */ - unsigned short dkg_obs1; /* obsolete */ - unsigned short dkg_nsect; /* # of data sectors per track */ - unsigned short dkg_intrlv; /* interleave factor */ - unsigned short dkg_obs2; /* obsolete */ - unsigned short dkg_obs3; /* obsolete */ - unsigned short dkg_apc; /* alternates per cyl (SCSI only) */ - unsigned short dkg_rpm; /* revolutions per minute */ - unsigned short dkg_pcyl; /* # of physical cylinders */ - unsigned short dkg_write_reinstruct; /* # sectors to skip, writes */ - unsigned short dkg_read_reinstruct; /* # sectors to skip, reads */ - unsigned short dkg_extra[7]; /* for compatible expansion */ -}; - -/* - * These defines are for historic compatibility with old drivers. - */ -#define dkg_bhead dkg_obs1 /* used to be head offset */ -#define dkg_gap1 dkg_obs2 /* used to be gap1 */ -#define dkg_gap2 dkg_obs3 /* used to be gap2 */ - -/* - * Disk io control commands - * Warning: some other ioctls with the DIOC prefix exist elsewhere. - * The Generic DKIOC numbers are from 0 - 50. - * The Floppy Driver uses 51 - 100. - * The Hard Disk (except SCSI) 101 - 106. (these are obsolete) - * The CDROM Driver 151 - 200. - * The USCSI ioctl 201 - 250. - */ #define DKIOC (0x04 << 8) - -/* - * The following ioctls are generic in nature and need to be - * supported as appropriate by all disk drivers - */ -#define DKIOCGGEOM (DKIOC|1) /* Get geometry */ -#define DKIOCINFO (DKIOC|3) /* Get info */ -#define DKIOCEJECT (DKIOC|6) /* Generic 'eject' */ -#define DKIOCGVTOC (DKIOC|11) /* Get VTOC */ -#define DKIOCSVTOC (DKIOC|12) /* Set VTOC & Write to Disk */ - -/* - * Disk Cache Controls. These ioctls should be supported by - * all disk drivers. - * - * DKIOCFLUSHWRITECACHE when used from user-mode ignores the ioctl - * argument, but it should be passed as NULL to allow for future - * reinterpretation. From user-mode, this ioctl request is synchronous. - * - * When invoked from within the kernel, the arg can be NULL to indicate - * a synchronous request or can be the address of a struct dk_callback - * to request an asynchronous callback when the flush request is complete. - * In this case, the flag to the ioctl must include FKIOCTL and the - * dkc_callback field of the pointed to struct must be non-null or the - * request is made synchronously. - * - * In the callback case: if the ioctl returns 0, a callback WILL be performed. - * If the ioctl returns non-zero, a callback will NOT be performed. - * NOTE: In some cases, the callback may be done BEFORE the ioctl call - * returns. The caller's locking strategy should be prepared for this case. - */ #define DKIOCFLUSHWRITECACHE (DKIOC|34) /* flush cache to phys medium */ -struct dk_callback { - void (*dkc_callback)(void *dkc_cookie, int error); - void *dkc_cookie; - int dkc_flag; -}; - -/* bit flag definitions for dkc_flag */ -#define FLUSH_VOLATILE 0x1 /* Bit 0: if set, only flush */ - /* volatile cache; otherwise, flush */ - /* volatile and non-volatile cache */ - -#define DKIOCGETWCE (DKIOC|36) /* Get current write cache */ - /* enablement status */ -#define DKIOCSETWCE (DKIOC|37) /* Enable/Disable write cache */ - -/* - * The following ioctls are used by Sun drivers to communicate - * with their associated format routines. Support of these ioctls - * is not required of foreign drivers - */ -#define DKIOCSGEOM (DKIOC|2) /* Set geometry */ -#define DKIOCSAPART (DKIOC|4) /* Set all partitions */ -#define DKIOCGAPART (DKIOC|5) /* Get all partitions */ -#define DKIOCG_PHYGEOM (DKIOC|32) /* get physical geometry */ -#define DKIOCG_VIRTGEOM (DKIOC|33) /* get virtual geometry */ - -/* - * The following ioctl's are removable media support - */ -#define DKIOCLOCK (DKIOC|7) /* Generic 'lock' */ -#define DKIOCUNLOCK (DKIOC|8) /* Generic 'unlock' */ -#define DKIOCSTATE (DKIOC|13) /* Inquire insert/eject state */ -#define DKIOCREMOVABLE (DKIOC|16) /* is media removable */ - - -/* - * ioctl for hotpluggable devices - */ -#define DKIOCHOTPLUGGABLE (DKIOC|35) /* is hotpluggable */ - -/* - * Ioctl to force driver to re-read the alternate partition and rebuild - * the internal defect map. - */ -#define DKIOCADDBAD (DKIOC|20) /* Re-read the alternate map (IDE) */ -#define DKIOCGETDEF (DKIOC|21) /* read defect list (IDE) */ - -/* - * Used by applications to get disk defect information from IDE - * drives. - */ -#ifdef _SYSCALL32 -struct defect_header32 { - int head; - caddr32_t buffer; -}; -#endif /* _SYSCALL32 */ - -struct defect_header { - int head; - caddr_t buffer; -}; - -#define DKIOCPARTINFO (DKIOC|22) /* Get partition or slice parameters */ - -/* - * Used by applications to get partition or slice information - */ -#ifdef _SYSCALL32 -struct part_info32 { - uint32_t p_start; - int p_length; -}; -#endif /* _SYSCALL32 */ - -struct part_info { - uint64_t p_start; - int p_length; -}; - -/* The following ioctls are for Optical Memory Device */ -#define DKIOC_EBP_ENABLE (DKIOC|40) /* enable by pass erase on write */ -#define DKIOC_EBP_DISABLE (DKIOC|41) /* disable by pass erase on write */ - -/* - * This state enum is the argument passed to the DKIOCSTATE ioctl. - */ -enum dkio_state { DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED, DKIO_DEV_GONE }; - -#define DKIOCGMEDIAINFO (DKIOC|42) /* get information about the media */ - -/* - * ioctls to read/write mboot info. - */ -#define DKIOCGMBOOT (DKIOC|43) /* get mboot info */ -#define DKIOCSMBOOT (DKIOC|44) /* set mboot info */ - -/* - * ioctl to get the device temperature. - */ -#define DKIOCGTEMPERATURE (DKIOC|45) /* get temperature */ - -/* - * Used for providing the temperature. - */ - -struct dk_temperature { - uint_t dkt_flags; /* Flags */ - short dkt_cur_temp; /* Current disk temperature */ - short dkt_ref_temp; /* reference disk temperature */ -}; - -#define DKT_BYPASS_PM 0x1 -#define DKT_INVALID_TEMP 0xFFFF - - -/* - * Media types or profiles known - */ -#define DK_UNKNOWN 0x00 /* Media inserted - type unknown */ - - -/* - * SFF 8090 Specification Version 3, media types 0x01 - 0xfffe are retained to - * maintain compatibility with SFF8090. The following define the - * optical media type. - */ -#define DK_REMOVABLE_DISK 0x02 /* Removable Disk */ -#define DK_MO_ERASABLE 0x03 /* MO Erasable */ -#define DK_MO_WRITEONCE 0x04 /* MO Write once */ -#define DK_AS_MO 0x05 /* AS MO */ -#define DK_CDROM 0x08 /* CDROM */ -#define DK_CDR 0x09 /* CD-R */ -#define DK_CDRW 0x0A /* CD-RW */ -#define DK_DVDROM 0x10 /* DVD-ROM */ -#define DK_DVDR 0x11 /* DVD-R */ -#define DK_DVDRAM 0x12 /* DVD_RAM or DVD-RW */ - -/* - * Media types for other rewritable magnetic media - */ -#define DK_FIXED_DISK 0x10001 /* Fixed disk SCSI or otherwise */ -#define DK_FLOPPY 0x10002 /* Floppy media */ -#define DK_ZIP 0x10003 /* IOMEGA ZIP media */ -#define DK_JAZ 0x10004 /* IOMEGA JAZ media */ - -#define DKIOCSETEFI (DKIOC|17) /* Set EFI info */ -#define DKIOCGETEFI (DKIOC|18) /* Get EFI info */ - -#define DKIOCPARTITION (DKIOC|9) /* Get partition info */ - -/* - * Ioctls to get/set volume capabilities related to Logical Volume Managers. - * They include the ability to get/set capabilities and to issue a read to a - * specific underlying device of a replicated device. - */ - -#define DKIOCGETVOLCAP (DKIOC | 25) /* Get volume capabilities */ -#define DKIOCSETVOLCAP (DKIOC | 26) /* Set volume capabilities */ -#define DKIOCDMR (DKIOC | 27) /* Issue a directed read */ - -typedef uint_t volcapinfo_t; - -typedef uint_t volcapset_t; - -#define DKV_ABR_CAP 0x00000001 /* Support Appl.Based Recovery */ -#define DKV_DMR_CAP 0x00000002 /* Support Directed Mirror Read */ - -typedef struct volcap { - volcapinfo_t vc_info; /* Capabilities available */ - volcapset_t vc_set; /* Capabilities set */ -} volcap_t; - -#define VOL_SIDENAME 256 - -typedef struct vol_directed_rd { - int vdr_flags; - offset_t vdr_offset; - size_t vdr_nbytes; - size_t vdr_bytesread; - void *vdr_data; - int vdr_side; - char vdr_side_name[VOL_SIDENAME]; -} vol_directed_rd_t; - -#define DKV_SIDE_INIT (-1) -#define DKV_DMR_NEXT_SIDE 0x00000001 -#define DKV_DMR_DONE 0x00000002 -#define DKV_DMR_ERROR 0x00000004 -#define DKV_DMR_SUCCESS 0x00000008 -#define DKV_DMR_SHORT 0x00000010 - -#ifdef _MULTI_DATAMODEL -#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 -#pragma pack(4) -#endif -typedef struct vol_directed_rd32 { - int32_t vdr_flags; - offset_t vdr_offset; /* 64-bit element on 32-bit alignment */ - size32_t vdr_nbytes; - size32_t vdr_bytesread; - caddr32_t vdr_data; - int32_t vdr_side; - char vdr_side_name[VOL_SIDENAME]; -} vol_directed_rd32_t; -#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4 -#pragma pack() -#endif -#endif /* _MULTI_DATAMODEL */ - -/* - * The ioctl is used to fetch disk's device type, vendor ID, - * model number/product ID, firmware revision and serial number together. - * - * Currently there are two device types - DKD_ATA_TYPE which means the - * disk is driven by cmdk/ata or dad/uata driver, and DKD_SCSI_TYPE - * which means the disk is driven by sd/scsi hba driver. - */ -#define DKIOC_GETDISKID (DKIOC|46) - -/* These two labels are for dkd_dtype of dk_disk_id_t */ -#define DKD_ATA_TYPE 0x01 /* ATA disk or legacy mode SATA disk */ -#define DKD_SCSI_TYPE 0x02 /* SCSI disk or native mode SATA disk */ - -#define DKD_ATA_MODEL 40 /* model number length */ -#define DKD_ATA_FWVER 8 /* firmware revision length */ -#define DKD_ATA_SERIAL 20 /* serial number length */ - -#define DKD_SCSI_VENDOR 8 /* vendor ID length */ -#define DKD_SCSI_PRODUCT 16 /* product ID length */ -#define DKD_SCSI_REVLEVEL 4 /* revision level length */ -#define DKD_SCSI_SERIAL 12 /* serial number length */ - -/* - * The argument type for DKIOC_GETDISKID ioctl. - */ -typedef struct dk_disk_id { - uint_t dkd_dtype; - union { - struct { - char dkd_amodel[DKD_ATA_MODEL]; /* 40 bytes */ - char dkd_afwver[DKD_ATA_FWVER]; /* 8 bytes */ - char dkd_aserial[DKD_ATA_SERIAL]; /* 20 bytes */ - } ata_disk_id; - struct { - char dkd_svendor[DKD_SCSI_VENDOR]; /* 8 bytes */ - char dkd_sproduct[DKD_SCSI_PRODUCT]; /* 16 bytes */ - char dkd_sfwver[DKD_SCSI_REVLEVEL]; /* 4 bytes */ - char dkd_sserial[DKD_SCSI_SERIAL]; /* 12 bytes */ - } scsi_disk_id; - } disk_id; -} dk_disk_id_t; - -/* - * The ioctl is used to update the firmware of device. - */ -#define DKIOC_UPDATEFW (DKIOC|47) - -/* The argument type for DKIOC_UPDATEFW ioctl */ -typedef struct dk_updatefw { - caddr_t dku_ptrbuf; /* pointer to firmware buf */ - uint_t dku_size; /* firmware buf length */ - uint8_t dku_type; /* firmware update type */ -} dk_updatefw_t; - -#ifdef _SYSCALL32 -typedef struct dk_updatefw_32 { - caddr32_t dku_ptrbuf; /* pointer to firmware buf */ - uint_t dku_size; /* firmware buf length */ - uint8_t dku_type; /* firmware update type */ -} dk_updatefw_32_t; -#endif /* _SYSCALL32 */ - -/* - * firmware update type - temporary or permanent use - */ -#define FW_TYPE_TEMP 0x0 /* temporary use */ -#define FW_TYPE_PERM 0x1 /* permanent use */ - - -#ifdef __cplusplus -} -#endif - #endif /* _OPENSOLARIS_SYS_DKIO_H_ */ From ecbf02791f921b39594719ea103ae66ed2fce095 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Fri, 28 Oct 2022 00:55:45 +0100 Subject: [PATCH 114/126] freebsd: simplify MD isa_defs.h Most of this file was a pile of defines, apparently from Solaris that controlled nothing in the source tree. A few things controlled the definition of unused types or macros which I have removed. Considerable further cleanup is possible including removal of architectures FreeBSD never supported. This file should likely converge with the Linux version to the extent possible. Reviewed-by: Ryan Moeller Reviewed-by: Richard Yao Reviewed-by: Brian Behlendorf Signed-off-by: Brooks Davis Closes #14127 --- include/os/freebsd/spl/sys/isa_defs.h | 415 ------------------------- include/os/freebsd/spl/sys/sysmacros.h | 40 --- lib/libspl/include/sys/types.h | 25 -- 3 files changed, 480 deletions(-) diff --git a/include/os/freebsd/spl/sys/isa_defs.h b/include/os/freebsd/spl/sys/isa_defs.h index 817521cc2cb9..9eba593fa797 100644 --- a/include/os/freebsd/spl/sys/isa_defs.h +++ b/include/os/freebsd/spl/sys/isa_defs.h @@ -41,59 +41,6 @@ * The natural byte order of the processor. A pointer to an int points * to the least/most significant byte of that int. * - * _STACK_GROWS_UPWARD / _STACK_GROWS_DOWNWARD: - * The processor specific direction of stack growth. A push onto the - * stack increases/decreases the stack pointer, so it stores data at - * successively higher/lower addresses. (Stackless machines ignored - * without regrets). - * - * _LONG_LONG_HTOL / _LONG_LONG_LTOH: - * A pointer to a long long points to the most/least significant long - * within that long long. - * - * _BIT_FIELDS_HTOL / _BIT_FIELDS_LTOH: - * The C compiler assigns bit fields from the high/low to the low/high end - * of an int (most to least significant vs. least to most significant). - * - * _IEEE_754: - * The processor (or supported implementations of the processor) - * supports the ieee-754 floating point standard. No other floating - * point standards are supported (or significant). Any other supported - * floating point formats are expected to be cased on the ISA processor - * symbol. - * - * _CHAR_IS_UNSIGNED / _CHAR_IS_SIGNED: - * The C Compiler implements objects of type `char' as `unsigned' or - * `signed' respectively. This is really an implementation choice of - * the compiler writer, but it is specified in the ABI and tends to - * be uniform across compilers for an instruction set architecture. - * Hence, it has the properties of a processor characteristic. - * - * _CHAR_ALIGNMENT / _SHORT_ALIGNMENT / _INT_ALIGNMENT / _LONG_ALIGNMENT / - * _LONG_LONG_ALIGNMENT / _DOUBLE_ALIGNMENT / _LONG_DOUBLE_ALIGNMENT / - * _POINTER_ALIGNMENT / _FLOAT_ALIGNMENT: - * The ABI defines alignment requirements of each of the primitive - * object types. Some, if not all, may be hardware requirements as - * well. The values are expressed in "byte-alignment" units. - * - * _MAX_ALIGNMENT: - * The most stringent alignment requirement as specified by the ABI. - * Equal to the maximum of all the above _XXX_ALIGNMENT values. - * - * _ALIGNMENT_REQUIRED: - * True or false (1 or 0) whether or not the hardware requires the ABI - * alignment. - * - * _LONG_LONG_ALIGNMENT_32 - * The 32-bit ABI supported by a 64-bit kernel may have different - * alignment requirements for primitive object types. The value of this - * identifier is expressed in "byte-alignment" units. - * - * _HAVE_CPUID_INSN - * This indicates that the architecture supports the 'cpuid' - * instruction as defined by Intel. (Intel allows other vendors - * to extend the instruction for their own purposes.) - * * * Implementation Choices: * @@ -112,10 +59,6 @@ * Long/Pointer are 64 bits, Int is 32 bits. This is the chosen * implementation for 64-bit ABIs such as SPARC V9. * - * _I32LPx: - * A compilation environment where 'int' is 32-bit, and - * longs and pointers are simply the same size. - * * In all cases, Char is 8 bits and Short is 16 bits. * * _SUNOS_VTOC_8 / _SUNOS_VTOC_16 / _SVR4_VTOC_16: @@ -141,78 +84,10 @@ * 16 partitions per disk. * * - * _DMA_USES_PHYSADDR / _DMA_USES_VIRTADDR - * This describes the type of addresses used by system DMA: - * - * _DMA_USES_PHYSADDR: - * This type of DMA, used in the x86 implementation, - * requires physical addresses for DMA buffers. The 24-bit - * addresses used by some legacy boards is the source of the - * "low-memory" (<16MB) requirement for some devices using DMA. - * - * _DMA_USES_VIRTADDR: - * This method of DMA allows the use of virtual addresses for - * DMA transfers. - * - * _FIRMWARE_NEEDS_FDISK / _NO_FDISK_PRESENT - * This indicates the presence/absence of an fdisk table. - * - * _FIRMWARE_NEEDS_FDISK - * The fdisk table is required by system firmware. If present, - * it allows a disk to be subdivided into multiple fdisk - * partitions, each of which is equivalent to a separate, - * virtual disk. This enables the co-existence of multiple - * operating systems on a shared hard disk. - * - * _NO_FDISK_PRESENT - * If the fdisk table is absent, it is assumed that the entire - * media is allocated for a single operating system. - * - * _HAVE_TEM_FIRMWARE - * Defined if this architecture has the (fallback) option of - * using prom_* calls for doing I/O if a suitable kernel driver - * is not available to do it. - * - * _DONT_USE_1275_GENERIC_NAMES - * Controls whether or not device tree node names should - * comply with the IEEE 1275 "Generic Names" Recommended - * Practice. With _DONT_USE_GENERIC_NAMES, device-specific - * names identifying the particular device will be used. - * - * __i386_COMPAT - * This indicates whether the i386 ABI is supported as a *non-native* - * mode for the platform. When this symbol is defined: - * - 32-bit xstat-style system calls are enabled - * - 32-bit xmknod-style system calls are enabled - * - 32-bit system calls use i386 sizes -and- alignments - * - * Note that this is NOT defined for the i386 native environment! - * * __x86 * This is ONLY a synonym for defined(__i386) || defined(__amd64) * which is useful only insofar as these two architectures share * common attributes. Analogous to __sparc. - * - * _PSM_MODULES - * This indicates whether or not the implementation uses PSM - * modules for processor support, reading /etc/mach from inside - * the kernel to extract a list. - * - * _RTC_CONFIG - * This indicates whether or not the implementation uses /etc/rtc_config - * to configure the real-time clock in the kernel. - * - * _UNIX_KRTLD - * This indicates that the implementation uses a dynamically - * linked unix + krtld to form the core kernel image at boot - * time, or (in the absence of this symbol) a prelinked kernel image. - * - * _OBP - * This indicates the firmware interface is OBP. - * - * _SOFT_HOSTID - * This indicates that the implementation obtains the hostid - * from the file /etc/hostid, rather than from hardware. */ #ifdef __cplusplus @@ -233,54 +108,13 @@ extern "C" { #define __x86 #endif -/* - * Define the appropriate "processor characteristics" - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_LTOH -#define _BIT_FIELDS_LTOH -#define _IEEE_754 -#define _CHAR_IS_SIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 -#define _LONG_ALIGNMENT 8 -#define _LONG_LONG_ALIGNMENT 8 -#define _DOUBLE_ALIGNMENT 8 -#define _DOUBLE_COMPLEX_ALIGNMENT 8 -#define _LONG_DOUBLE_ALIGNMENT 16 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 16 -#define _POINTER_ALIGNMENT 8 -#define _MAX_ALIGNMENT 16 -#define _ALIGNMENT_REQUIRED 1 - -/* - * Different alignment constraints for the i386 ABI in compatibility mode - */ -#define _LONG_LONG_ALIGNMENT_32 4 - /* * Define the appropriate "implementation choices". */ #if !defined(_LP64) #error "_LP64 not defined" #endif -#if !defined(_I32LPx) -#define _I32LPx -#endif -#define _MULTI_DATAMODEL #define _SUNOS_VTOC_16 -#define _DMA_USES_PHYSADDR -#define _FIRMWARE_NEEDS_FDISK -#define __i386_COMPAT -#define _PSM_MODULES -#define _RTC_CONFIG -#define _SOFT_HOSTID -#define _DONT_USE_1275_GENERIC_NAMES -#define _HAVE_CPUID_INSN /* * The feature test macro __i386 is generic for all processors implementing @@ -297,78 +131,16 @@ extern "C" { #define __x86 #endif -/* - * Define the appropriate "processor characteristics" - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_LTOH -#define _BIT_FIELDS_LTOH -#define _IEEE_754 -#define _CHAR_IS_SIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 -#define _LONG_ALIGNMENT 4 -#define _LONG_LONG_ALIGNMENT 4 -#define _DOUBLE_ALIGNMENT 4 -#define _DOUBLE_COMPLEX_ALIGNMENT 4 -#define _LONG_DOUBLE_ALIGNMENT 4 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 4 -#define _POINTER_ALIGNMENT 4 -#define _MAX_ALIGNMENT 4 -#define _ALIGNMENT_REQUIRED 0 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices". */ #if !defined(_ILP32) #define _ILP32 #endif -#if !defined(_I32LPx) -#define _I32LPx -#endif #define _SUNOS_VTOC_16 -#define _DMA_USES_PHYSADDR -#define _FIRMWARE_NEEDS_FDISK -#define _PSM_MODULES -#define _RTC_CONFIG -#define _SOFT_HOSTID -#define _DONT_USE_1275_GENERIC_NAMES -#define _HAVE_CPUID_INSN #elif defined(__aarch64__) -/* - * Define the appropriate "processor characteristics" - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_LTOH -#define _BIT_FIELDS_LTOH -#define _IEEE_754 -#define _CHAR_IS_UNSIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 -#define _LONG_ALIGNMENT 8 -#define _LONG_LONG_ALIGNMENT 8 -#define _DOUBLE_ALIGNMENT 8 -#define _DOUBLE_COMPLEX_ALIGNMENT 8 -#define _LONG_DOUBLE_ALIGNMENT 16 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 16 -#define _POINTER_ALIGNMENT 8 -#define _MAX_ALIGNMENT 16 -#define _ALIGNMENT_REQUIRED 1 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices" */ @@ -376,41 +148,9 @@ extern "C" { #error "_LP64 not defined" #endif #define _SUNOS_VTOC_16 -#define _DMA_USES_PHYSADDR -#define _FIRMWARE_NEEDS_FDISK -#define _PSM_MODULES -#define _RTC_CONFIG -#define _DONT_USE_1275_GENERIC_NAMES -#define _HAVE_CPUID_INSN #elif defined(__riscv) -/* - * Define the appropriate "processor characteristics" - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_LTOH -#define _BIT_FIELDS_LTOH -#define _IEEE_754 -#define _CHAR_IS_UNSIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 -#define _LONG_ALIGNMENT 8 -#define _LONG_LONG_ALIGNMENT 8 -#define _DOUBLE_ALIGNMENT 8 -#define _DOUBLE_COMPLEX_ALIGNMENT 8 -#define _LONG_DOUBLE_ALIGNMENT 16 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 16 -#define _POINTER_ALIGNMENT 8 -#define _MAX_ALIGNMENT 16 -#define _ALIGNMENT_REQUIRED 1 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices" */ @@ -418,86 +158,20 @@ extern "C" { #define _LP64 #endif #define _SUNOS_VTOC_16 -#define _DMA_USES_PHYSADDR -#define _FIRMWARE_NEEDS_FDISK -#define _PSM_MODULES -#define _RTC_CONFIG -#define _DONT_USE_1275_GENERIC_NAMES -#define _HAVE_CPUID_INSN #elif defined(__arm__) -/* - * Define the appropriate "processor characteristics" - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_LTOH -#define _BIT_FIELDS_LTOH -#define _IEEE_754 -#define _CHAR_IS_SIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 -#define _LONG_ALIGNMENT 4 -#define _LONG_LONG_ALIGNMENT 4 -#define _DOUBLE_ALIGNMENT 4 -#define _DOUBLE_COMPLEX_ALIGNMENT 4 -#define _LONG_DOUBLE_ALIGNMENT 4 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 4 -#define _POINTER_ALIGNMENT 4 -#define _MAX_ALIGNMENT 4 -#define _ALIGNMENT_REQUIRED 0 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices". */ #if !defined(_ILP32) #define _ILP32 #endif -#if !defined(_I32LPx) -#define _I32LPx -#endif #define _SUNOS_VTOC_16 -#define _DMA_USES_PHYSADDR -#define _FIRMWARE_NEEDS_FDISK -#define _PSM_MODULES -#define _RTC_CONFIG -#define _DONT_USE_1275_GENERIC_NAMES -#define _HAVE_CPUID_INSN #elif defined(__mips__) -/* - * Define the appropriate "processor characteristics" - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_LTOH -#define _BIT_FIELDS_LTOH -#define _IEEE_754 -#define _CHAR_IS_SIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 #if defined(__mips_n64) -#define _LONG_ALIGNMENT 8 -#define _LONG_LONG_ALIGNMENT 8 -#define _DOUBLE_ALIGNMENT 8 -#define _DOUBLE_COMPLEX_ALIGNMENT 8 -#define _LONG_DOUBLE_ALIGNMENT 8 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 8 -#define _POINTER_ALIGNMENT 8 -#define _MAX_ALIGNMENT 8 -#define _ALIGNMENT_REQUIRED 0 - -#define _LONG_LONG_ALIGNMENT_32 _INT_ALIGNMENT /* * Define the appropriate "implementation choices". */ @@ -505,57 +179,21 @@ extern "C" { #error "_LP64 not defined" #endif #else -#define _LONG_ALIGNMENT 4 -#define _LONG_LONG_ALIGNMENT 4 -#define _DOUBLE_ALIGNMENT 4 -#define _DOUBLE_COMPLEX_ALIGNMENT 4 -#define _LONG_DOUBLE_ALIGNMENT 4 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 4 -#define _POINTER_ALIGNMENT 4 -#define _MAX_ALIGNMENT 4 -#define _ALIGNMENT_REQUIRED 0 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices". */ #if !defined(_ILP32) #define _ILP32 #endif -#if !defined(_I32LPx) -#define _I32LPx -#endif #endif #define _SUNOS_VTOC_16 -#define _DMA_USES_PHYSADDR -#define _FIRMWARE_NEEDS_FDISK -#define _PSM_MODULES -#define _RTC_CONFIG -#define _DONT_USE_1275_GENERIC_NAMES -#define _HAVE_CPUID_INSN #elif defined(__powerpc__) -#if defined(__BIG_ENDIAN__) -#define _BIT_FIELDS_HTOL -#else -#define _BIT_FIELDS_LTOH -#endif - #if !defined(__powerpc) #define __powerpc #endif -#if defined(__powerpc64__) -#define _LONG_LONG_ALIGNMENT 8 -#define _MULTI_DATAMODEL -#else -#define _LONG_LONG_ALIGNMENT 4 -#endif -#define _LONG_LONG_ALIGNMENT_32 4 -#define _ALIGNMENT_REQUIRED 1 - #define _SUNOS_VTOC_16 1 /* @@ -600,34 +238,10 @@ extern "C" { #define __sparcv8 #endif -/* - * Define the appropriate "processor characteristics" shared between - * all Solaris on SPARC systems. - */ -#define _STACK_GROWS_DOWNWARD -#define _LONG_LONG_HTOL -#define _BIT_FIELDS_HTOL -#define _IEEE_754 -#define _CHAR_IS_SIGNED -#define _BOOL_ALIGNMENT 1 -#define _CHAR_ALIGNMENT 1 -#define _SHORT_ALIGNMENT 2 -#define _INT_ALIGNMENT 4 -#define _FLOAT_ALIGNMENT 4 -#define _FLOAT_COMPLEX_ALIGNMENT 4 -#define _LONG_LONG_ALIGNMENT 8 -#define _DOUBLE_ALIGNMENT 8 -#define _DOUBLE_COMPLEX_ALIGNMENT 8 -#define _ALIGNMENT_REQUIRED 1 - /* * Define the appropriate "implementation choices" shared between versions. */ #define _SUNOS_VTOC_8 -#define _DMA_USES_VIRTADDR -#define _NO_FDISK_PRESENT -#define _HAVE_TEM_FIRMWARE -#define _OBP /* * The following set of definitions characterize the implementation of @@ -635,24 +249,10 @@ extern "C" { */ #if defined(__sparcv8) -/* - * Define the appropriate "processor characteristics" - */ -#define _LONG_ALIGNMENT 4 -#define _LONG_DOUBLE_ALIGNMENT 8 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 8 -#define _POINTER_ALIGNMENT 4 -#define _MAX_ALIGNMENT 8 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices" */ #define _ILP32 -#if !defined(_I32LPx) -#define _I32LPx -#endif /* * The following set of definitions characterize the implementation of @@ -660,27 +260,12 @@ extern "C" { */ #elif defined(__sparcv9) -/* - * Define the appropriate "processor characteristics" - */ -#define _LONG_ALIGNMENT 8 -#define _LONG_DOUBLE_ALIGNMENT 16 -#define _LONG_DOUBLE_COMPLEX_ALIGNMENT 16 -#define _POINTER_ALIGNMENT 8 -#define _MAX_ALIGNMENT 16 - -#define _LONG_LONG_ALIGNMENT_32 _LONG_LONG_ALIGNMENT - /* * Define the appropriate "implementation choices" */ #if !defined(_LP64) #error "_LP64 not defined" #endif -#if !defined(_I32LPx) -#define _I32LPx -#endif -#define _MULTI_DATAMODEL #else #error "unknown SPARC version" diff --git a/include/os/freebsd/spl/sys/sysmacros.h b/include/os/freebsd/spl/sys/sysmacros.h index 1c8475a7092c..3e8841ae66bd 100644 --- a/include/os/freebsd/spl/sys/sysmacros.h +++ b/include/os/freebsd/spl/sys/sysmacros.h @@ -281,46 +281,6 @@ extern unsigned char bcd_to_byte[256]; #define INCR_COUNT(var, mutex) mutex_enter(mutex), (*(var))++, mutex_exit(mutex) #define DECR_COUNT(var, mutex) mutex_enter(mutex), (*(var))--, mutex_exit(mutex) -/* - * Macros to declare bitfields - the order in the parameter list is - * Low to High - that is, declare bit 0 first. We only support 8-bit bitfields - * because if a field crosses a byte boundary it's not likely to be meaningful - * without reassembly in its nonnative endianness. - */ -#if defined(_BIT_FIELDS_LTOH) -#define DECL_BITFIELD2(_a, _b) \ - uint8_t _a, _b -#define DECL_BITFIELD3(_a, _b, _c) \ - uint8_t _a, _b, _c -#define DECL_BITFIELD4(_a, _b, _c, _d) \ - uint8_t _a, _b, _c, _d -#define DECL_BITFIELD5(_a, _b, _c, _d, _e) \ - uint8_t _a, _b, _c, _d, _e -#define DECL_BITFIELD6(_a, _b, _c, _d, _e, _f) \ - uint8_t _a, _b, _c, _d, _e, _f -#define DECL_BITFIELD7(_a, _b, _c, _d, _e, _f, _g) \ - uint8_t _a, _b, _c, _d, _e, _f, _g -#define DECL_BITFIELD8(_a, _b, _c, _d, _e, _f, _g, _h) \ - uint8_t _a, _b, _c, _d, _e, _f, _g, _h -#elif defined(_BIT_FIELDS_HTOL) -#define DECL_BITFIELD2(_a, _b) \ - uint8_t _b, _a -#define DECL_BITFIELD3(_a, _b, _c) \ - uint8_t _c, _b, _a -#define DECL_BITFIELD4(_a, _b, _c, _d) \ - uint8_t _d, _c, _b, _a -#define DECL_BITFIELD5(_a, _b, _c, _d, _e) \ - uint8_t _e, _d, _c, _b, _a -#define DECL_BITFIELD6(_a, _b, _c, _d, _e, _f) \ - uint8_t _f, _e, _d, _c, _b, _a -#define DECL_BITFIELD7(_a, _b, _c, _d, _e, _f, _g) \ - uint8_t _g, _f, _e, _d, _c, _b, _a -#define DECL_BITFIELD8(_a, _b, _c, _d, _e, _f, _g, _h) \ - uint8_t _h, _g, _f, _e, _d, _c, _b, _a -#else -#error One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined -#endif /* _BIT_FIELDS_LTOH */ - #if !defined(_KMEMUSER) && !defined(offsetof) /* avoid any possibility of clashing with version */ diff --git a/lib/libspl/include/sys/types.h b/lib/libspl/include/sys/types.h index 5a84123d201f..90e3cf9bdaf8 100644 --- a/lib/libspl/include/sys/types.h +++ b/lib/libspl/include/sys/types.h @@ -47,31 +47,6 @@ typedef uint_t zoneid_t; typedef int projid_t; -/* - * Definitions remaining from previous partial support for 64-bit file - * offsets. This partial support for devices greater than 2gb requires - * compiler support for long long. - */ -#ifdef _LONG_LONG_LTOH -typedef union { - offset_t _f; /* Full 64 bit offset value */ - struct { - int32_t _l; /* lower 32 bits of offset value */ - int32_t _u; /* upper 32 bits of offset value */ - } _p; -} lloff_t; -#endif - -#ifdef _LONG_LONG_HTOL -typedef union { - offset_t _f; /* Full 64 bit offset value */ - struct { - int32_t _u; /* upper 32 bits of offset value */ - int32_t _l; /* lower 32 bits of offset value */ - } _p; -} lloff_t; -#endif - #include /* for NBBY */ #endif From 41715771b5de07cbfcb1f7b75f324e824dfa1728 Mon Sep 17 00:00:00 2001 From: Mohamed Tawfik Date: Tue, 8 Nov 2022 20:08:21 +0200 Subject: [PATCH 115/126] Adds the `-p` option to `zfs holds` This allows for printing a machine-readable, accurate to the second, hold creation time in the form of a unix epoch timestamp. Additionally, updates relevant documentation and man pages accordingly. Reviewed-by: Allan Jude Reviewed-by: Brian Behlendorf Signed-off-by: Mohamed Tawfik Closes #13690 Closes #14152 --- cmd/zfs/zfs_main.c | 37 ++++++++++++++++++++++++++++--------- man/man8/zfs-hold.8 | 6 ++++-- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index bdbd0bfc63f2..6e79a73b95fb 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -392,7 +392,7 @@ get_usage(zfs_help_t idx) case HELP_HOLD: return (gettext("\thold [-r] ...\n")); case HELP_HOLDS: - return (gettext("\tholds [-rH] ...\n")); + return (gettext("\tholds [-rHp] ...\n")); case HELP_RELEASE: return (gettext("\trelease [-r] ...\n")); case HELP_DIFF: @@ -6456,7 +6456,8 @@ typedef struct holds_cbdata { * */ static void -print_holds(boolean_t scripted, int nwidth, int tagwidth, nvlist_t *nvl) +print_holds(boolean_t scripted, int nwidth, int tagwidth, nvlist_t *nvl, + boolean_t parsable) { int i; nvpair_t *nvp = NULL; @@ -6493,11 +6494,23 @@ print_holds(boolean_t scripted, int nwidth, int tagwidth, nvlist_t *nvl) gettext(STRFTIME_FMT_STR), &t); if (scripted) { - (void) printf("%s\t%s\t%s\n", zname, - tagname, tsbuf); + if (parsable) { + (void) printf("%s\t%s\t%ld\n", zname, + tagname, time); + } else { + (void) printf("%s\t%s\t%s\n", zname, + tagname, tsbuf); + } } else { - (void) printf("%-*s %-*s %s\n", nwidth, - zname, tagwidth, tagname, tsbuf); + if (parsable) { + (void) printf("%-*s %-*s %ld\n", + nwidth, zname, tagwidth, + tagname, time); + } else { + (void) printf("%-*s %-*s %s\n", + nwidth, zname, tagwidth, + tagname, tsbuf); + } } } } @@ -6544,10 +6557,11 @@ holds_callback(zfs_handle_t *zhp, void *data) } /* - * zfs holds [-rH] ... + * zfs holds [-rHp] ... * * -r Lists holds that are set on the named snapshots recursively. * -H Scripted mode; elide headers and separate columns by tabs. + * -p Display values in parsable (literal) format. */ static int zfs_do_holds(int argc, char **argv) @@ -6556,6 +6570,7 @@ zfs_do_holds(int argc, char **argv) boolean_t errors = B_FALSE; boolean_t scripted = B_FALSE; boolean_t recursive = B_FALSE; + boolean_t parsable = B_FALSE; int types = ZFS_TYPE_SNAPSHOT; holds_cbdata_t cb = { 0 }; @@ -6565,7 +6580,7 @@ zfs_do_holds(int argc, char **argv) int flags = 0; /* check options */ - while ((c = getopt(argc, argv, "rH")) != -1) { + while ((c = getopt(argc, argv, "rHp")) != -1) { switch (c) { case 'r': recursive = B_TRUE; @@ -6573,6 +6588,9 @@ zfs_do_holds(int argc, char **argv) case 'H': scripted = B_TRUE; break; + case 'p': + parsable = B_TRUE; + break; case '?': (void) fprintf(stderr, gettext("invalid option '%c'\n"), optopt); @@ -6626,7 +6644,8 @@ zfs_do_holds(int argc, char **argv) /* * 2. print holds data */ - print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl); + print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl, + parsable); if (nvlist_empty(nvl)) (void) fprintf(stderr, gettext("no datasets available\n")); diff --git a/man/man8/zfs-hold.8 b/man/man8/zfs-hold.8 index c2c7b7dc26a3..4bc36cb47fc2 100644 --- a/man/man8/zfs-hold.8 +++ b/man/man8/zfs-hold.8 @@ -43,7 +43,7 @@ .Ar tag Ar snapshot Ns 
 .Nm zfs .Cm holds -.Op Fl rH +.Op Fl rHp .Ar snapshot Ns 
 .Nm zfs .Cm release @@ -76,7 +76,7 @@ of all descendent file systems. .It Xo .Nm zfs .Cm holds -.Op Fl rH +.Op Fl rHp .Ar snapshot Ns 
 .Xc Lists all existing user references for the given snapshot or snapshots. @@ -86,6 +86,8 @@ Lists the holds that are set on the named descendent snapshots, in addition to listing the holds on the named snapshot. .It Fl H Do not print headers, use tab-delimited output. +.It Fl p +Prints holds timestamps as unix epoch timestamps. .El .It Xo .Nm zfs From 109731cd73c56c378b4c71732b9b9d3504a7a7e1 Mon Sep 17 00:00:00 2001 From: Damian Szuberski Date: Wed, 9 Nov 2022 04:16:01 +1000 Subject: [PATCH 116/126] dsl_prop_known_index(): check for invalid prop Resolve UBSAN array-index-out-of-bounds error in zprop_desc_t. Reviewed-by: Brian Behlendorf Signed-off-by: szubersk Closes #14142 Closes #14147 --- module/zcommon/zfs_prop.c | 26 ++++++++++++++++++++++++++ module/zfs/dsl_prop.c | 3 ++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index c03933d126c6..9c65702b8d43 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -748,6 +748,8 @@ zfs_prop_init(void) boolean_t zfs_prop_delegatable(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); zprop_desc_t *pd = &zfs_prop_table[prop]; /* The mlslabel property is never delegatable. */ @@ -858,6 +860,8 @@ zfs_prop_valid_for_type(int prop, zfs_type_t types, boolean_t headcheck) zprop_type_t zfs_prop_get_type(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_proptype); } @@ -867,6 +871,8 @@ zfs_prop_get_type(zfs_prop_t prop) boolean_t zfs_prop_readonly(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_attr == PROP_READONLY || zfs_prop_table[prop].pd_attr == PROP_ONETIME || zfs_prop_table[prop].pd_attr == PROP_ONETIME_DEFAULT); @@ -878,6 +884,8 @@ zfs_prop_readonly(zfs_prop_t prop) boolean_t zfs_prop_visible(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_visible && zfs_prop_table[prop].pd_zfs_mod_supported); } @@ -888,6 +896,8 @@ zfs_prop_visible(zfs_prop_t prop) boolean_t zfs_prop_setonce(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_attr == PROP_ONETIME || zfs_prop_table[prop].pd_attr == PROP_ONETIME_DEFAULT); } @@ -895,12 +905,16 @@ zfs_prop_setonce(zfs_prop_t prop) const char * zfs_prop_default_string(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_strdefault); } uint64_t zfs_prop_default_numeric(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_numdefault); } @@ -911,6 +925,8 @@ zfs_prop_default_numeric(zfs_prop_t prop) const char * zfs_prop_to_name(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_name); } @@ -920,6 +936,8 @@ zfs_prop_to_name(zfs_prop_t prop) boolean_t zfs_prop_inheritable(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_attr == PROP_INHERIT || zfs_prop_table[prop].pd_attr == PROP_ONETIME); } @@ -972,6 +990,8 @@ zfs_prop_valid_keylocation(const char *str, boolean_t encrypted) const char * zfs_prop_values(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_values); } @@ -983,6 +1003,8 @@ zfs_prop_values(zfs_prop_t prop) int zfs_prop_is_string(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_proptype == PROP_TYPE_STRING || zfs_prop_table[prop].pd_proptype == PROP_TYPE_INDEX); } @@ -994,6 +1016,8 @@ zfs_prop_is_string(zfs_prop_t prop) const char * zfs_prop_column_name(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_colname); } @@ -1004,6 +1028,8 @@ zfs_prop_column_name(zfs_prop_t prop) boolean_t zfs_prop_align_right(zfs_prop_t prop) { + ASSERT3S(prop, >=, 0); + ASSERT3S(prop, <, ZFS_NUM_PROPS); return (zfs_prop_table[prop].pd_rightalign); } diff --git a/module/zfs/dsl_prop.c b/module/zfs/dsl_prop.c index ad927b622fcf..d1c0059092b1 100644 --- a/module/zfs/dsl_prop.c +++ b/module/zfs/dsl_prop.c @@ -75,7 +75,8 @@ 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) + if (prop != ZPROP_CONT && prop != ZPROP_INVAL && + zfs_prop_get_type(prop) == PROP_TYPE_INDEX) return (!zfs_prop_index_to_string(prop, value, &str)); return (-1); From f224eddf922a33ca4b86d83148e9e6fa155fc290 Mon Sep 17 00:00:00 2001 From: youzhongyang Date: Tue, 8 Nov 2022 13:28:56 -0500 Subject: [PATCH 117/126] Support idmapped mount in user namespace Linux 5.17 commit torvalds/linux@5dfbfe71e enables "the idmapping infrastructure to support idmapped mounts of filesystems mounted with an idmapping". Update the OpenZFS accordingly to improve the idmapped mount support. This pull request contains the following changes: - xattr setter functions are fixed to take mnt_ns argument. Without this, cp -p would fail for an idmapped mount in a user namespace. - idmap_util is enhanced/fixed for its use in a user ns context. - One test case added to test idmapped mount in a user ns. Reviewed-by: Christian Brauner Reviewed-by: Brian Behlendorf Signed-off-by: Youzhong Yang Closes #14097 --- config/kernel-iattr-vfsid.m4 | 24 +++ config/kernel.m4 | 2 + include/os/linux/kernel/linux/xattr_compat.h | 10 +- include/os/linux/spl/sys/cred.h | 84 ++++++++--- include/os/linux/zfs/sys/policy.h | 5 +- module/os/linux/zfs/policy.c | 17 ++- module/os/linux/zfs/zfs_acl.c | 24 +-- module/os/linux/zfs/zfs_dir.c | 7 +- module/os/linux/zfs/zfs_vnops_os.c | 25 ++-- module/os/linux/zfs/zfs_znode.c | 2 +- module/os/linux/zfs/zpl_ctldir.c | 2 +- module/os/linux/zfs/zpl_file.c | 6 +- module/os/linux/zfs/zpl_inode.c | 38 +++-- module/os/linux/zfs/zpl_xattr.c | 34 ++++- module/zfs/zfs_replay.c | 35 +++++ module/zfs/zfs_vnops.c | 12 +- tests/runfiles/linux.run | 2 +- tests/test-runner/bin/zts-report.py.in | 1 + tests/zfs-tests/cmd/idmap_util.c | 49 +++++-- tests/zfs-tests/tests/Makefile.am | 3 +- .../idmap_mount/idmap_mount_005.ksh | 138 ++++++++++++++++++ 21 files changed, 424 insertions(+), 96 deletions(-) create mode 100644 config/kernel-iattr-vfsid.m4 create mode 100755 tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_005.ksh diff --git a/config/kernel-iattr-vfsid.m4 b/config/kernel-iattr-vfsid.m4 new file mode 100644 index 000000000000..75bc4613b838 --- /dev/null +++ b/config/kernel-iattr-vfsid.m4 @@ -0,0 +1,24 @@ +dnl # +dnl # 6.0 API change +dnl # struct iattr has two unions for the uid and gid +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_IATTR_VFSID], [ + ZFS_LINUX_TEST_SRC([iattr_vfsid], [ + #include + ], [ + struct iattr ia; + ia.ia_vfsuid = (vfsuid_t){0}; + ia.ia_vfsgid = (vfsgid_t){0}; + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_IATTR_VFSID], [ + AC_MSG_CHECKING([whether iattr->ia_vfsuid and iattr->ia_vfsgid exist]) + ZFS_LINUX_TEST_RESULT([iattr_vfsid], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IATTR_VFSID, 1, + [iattr->ia_vfsuid and iattr->ia_vfsgid exist]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index b573881c4400..c71d576f492e 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -149,6 +149,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC ZFS_AC_KERNEL_SRC_USER_NS_COMMON_INUM ZFS_AC_KERNEL_SRC_IDMAP_MNT_API + ZFS_AC_KERNEL_SRC_IATTR_VFSID AC_MSG_CHECKING([for available kernel interfaces]) ZFS_LINUX_TEST_COMPILE_ALL([kabi]) @@ -271,6 +272,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC ZFS_AC_KERNEL_USER_NS_COMMON_INUM ZFS_AC_KERNEL_IDMAP_MNT_API + ZFS_AC_KERNEL_IATTR_VFSID ]) dnl # diff --git a/include/os/linux/kernel/linux/xattr_compat.h b/include/os/linux/kernel/linux/xattr_compat.h index 9b83813db708..ff80fbb06413 100644 --- a/include/os/linux/kernel/linux/xattr_compat.h +++ b/include/os/linux/kernel/linux/xattr_compat.h @@ -146,7 +146,7 @@ fn(const struct xattr_handler *handler, struct user_namespace *user_ns, \ struct dentry *dentry, struct inode *inode, const char *name, \ const void *buffer, size_t size, int flags) \ { \ - return (__ ## fn(inode, name, buffer, size, flags)); \ + return (__ ## fn(user_ns, inode, name, buffer, size, flags)); \ } /* * 4.7 API change, @@ -160,7 +160,7 @@ fn(const struct xattr_handler *handler, struct dentry *dentry, \ struct inode *inode, const char *name, const void *buffer, \ size_t size, int flags) \ { \ - return (__ ## fn(inode, name, buffer, size, flags)); \ + return (__ ## fn(kcred->user_ns, inode, name, buffer, size, flags));\ } /* * 4.4 API change, @@ -174,7 +174,8 @@ static int \ fn(const struct xattr_handler *handler, struct dentry *dentry, \ const char *name, const void *buffer, size_t size, int flags) \ { \ - return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \ + return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \ + buffer, size, flags)); \ } /* * 2.6.33 API change, @@ -187,7 +188,8 @@ static int \ fn(struct dentry *dentry, const char *name, const void *buffer, \ size_t size, int flags, int unused_handler_flags) \ { \ - return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \ + return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \ + buffer, size, flags)); \ } #else #error "Unsupported kernel" diff --git a/include/os/linux/spl/sys/cred.h b/include/os/linux/spl/sys/cred.h index dc3c260dbbab..75ad400d312d 100644 --- a/include/os/linux/spl/sys/cred.h +++ b/include/os/linux/spl/sys/cred.h @@ -26,11 +26,14 @@ #include #include +#include #include #include typedef struct cred cred_t; +extern struct task_struct init_task; + #define kcred ((cred_t *)(init_task.cred)) #define CRED() ((cred_t *)current_cred()) @@ -45,32 +48,80 @@ typedef struct cred cred_t; #define SGID_TO_KGID(x) (KGIDT_INIT(x)) #define KGIDP_TO_SGIDP(x) (&(x)->val) -static inline uid_t zfs_uid_into_mnt(struct user_namespace *mnt_ns, uid_t uid) +/* Check if the user ns is the initial one */ +static inline boolean_t +zfs_is_init_userns(struct user_namespace *user_ns) { - if (mnt_ns) - return (__kuid_val(make_kuid(mnt_ns, uid))); - return (uid); +#if defined(CONFIG_USER_NS) + return (user_ns == kcred->user_ns); +#else + return (B_FALSE); +#endif } -static inline gid_t zfs_gid_into_mnt(struct user_namespace *mnt_ns, gid_t gid) +static inline struct user_namespace *zfs_i_user_ns(struct inode *inode) { - if (mnt_ns) - return (__kgid_val(make_kgid(mnt_ns, gid))); - return (gid); +#ifdef HAVE_SUPER_USER_NS + return (inode->i_sb->s_user_ns); +#else + return (kcred->user_ns); +#endif } -static inline uid_t zfs_uid_from_mnt(struct user_namespace *mnt_ns, uid_t uid) +static inline boolean_t zfs_no_idmapping(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns) { - if (mnt_ns) - return (from_kuid(mnt_ns, KUIDT_INIT(uid))); - return (uid); + return (zfs_is_init_userns(mnt_userns) || mnt_userns == fs_userns); } -static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid) +static inline uid_t zfs_uid_to_vfsuid(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, uid_t uid) { - if (mnt_ns) - return (from_kgid(mnt_ns, KGIDT_INIT(gid))); - return (gid); + if (zfs_no_idmapping(mnt_userns, fs_userns)) + return (uid); + if (!zfs_is_init_userns(fs_userns)) + uid = from_kuid(fs_userns, KUIDT_INIT(uid)); + if (uid == (uid_t)-1) + return (uid); + return (__kuid_val(make_kuid(mnt_userns, uid))); +} + +static inline gid_t zfs_gid_to_vfsgid(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, gid_t gid) +{ + if (zfs_no_idmapping(mnt_userns, fs_userns)) + return (gid); + if (!zfs_is_init_userns(fs_userns)) + gid = from_kgid(fs_userns, KGIDT_INIT(gid)); + if (gid == (gid_t)-1) + return (gid); + return (__kgid_val(make_kgid(mnt_userns, gid))); +} + +static inline uid_t zfs_vfsuid_to_uid(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, uid_t uid) +{ + if (zfs_no_idmapping(mnt_userns, fs_userns)) + return (uid); + uid = from_kuid(mnt_userns, KUIDT_INIT(uid)); + if (uid == (uid_t)-1) + return (uid); + if (zfs_is_init_userns(fs_userns)) + return (uid); + return (__kuid_val(make_kuid(fs_userns, uid))); +} + +static inline gid_t zfs_vfsgid_to_gid(struct user_namespace *mnt_userns, + struct user_namespace *fs_userns, gid_t gid) +{ + if (zfs_no_idmapping(mnt_userns, fs_userns)) + return (gid); + gid = from_kgid(mnt_userns, KGIDT_INIT(gid)); + if (gid == (gid_t)-1) + return (gid); + if (zfs_is_init_userns(fs_userns)) + return (gid); + return (__kgid_val(make_kgid(fs_userns, gid))); } extern void crhold(cred_t *cr); @@ -81,5 +132,4 @@ extern gid_t crgetgid(const cred_t *cr); extern int crgetngroups(const cred_t *cr); extern gid_t *crgetgroups(const cred_t *cr); extern int groupmember(gid_t gid, const cred_t *cr); - #endif /* _SPL_CRED_H */ diff --git a/include/os/linux/zfs/sys/policy.h b/include/os/linux/zfs/sys/policy.h index ee7fda761a3b..b182da95b8e0 100644 --- a/include/os/linux/zfs/sys/policy.h +++ b/include/os/linux/zfs/sys/policy.h @@ -47,13 +47,14 @@ int secpolicy_vnode_create_gid(const cred_t *); int secpolicy_vnode_remove(const cred_t *); int secpolicy_vnode_setdac(const cred_t *, uid_t); int secpolicy_vnode_setid_retain(struct znode *, const cred_t *, boolean_t); -int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *); +int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *, + zuserns_t *); int secpolicy_zinject(const cred_t *); int secpolicy_zfs(const cred_t *); int secpolicy_zfs_proc(const cred_t *, proc_t *); void secpolicy_setid_clear(vattr_t *, cred_t *); int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *, - const vattr_t *, cred_t *, zuserns_t *); + const vattr_t *, cred_t *, zuserns_t *, zuserns_t *); int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, mode_t); int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *, const struct vattr *, int, int (void *, int, cred_t *), void *); diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c index 50eb7cfaa61c..eaf38df864d3 100644 --- a/module/os/linux/zfs/policy.c +++ b/module/os/linux/zfs/policy.c @@ -214,9 +214,10 @@ secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr, * Determine that subject can set the file setgid flag. */ int -secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns) +secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns, + zuserns_t *fs_ns) { - gid = zfs_gid_into_mnt(mnt_ns, gid); + gid = zfs_gid_to_vfsgid(mnt_ns, fs_ns, gid); #if defined(CONFIG_USER_NS) if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid))) return (EPERM); @@ -285,9 +286,10 @@ secpolicy_setid_clear(vattr_t *vap, cred_t *cr) * Determine that subject can set the file setid flags. */ static int -secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns) +secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns, + zuserns_t *fs_ns) { - owner = zfs_uid_into_mnt(mnt_ns, owner); + owner = zfs_uid_to_vfsuid(mnt_ns, fs_ns, owner); if (crgetuid(cr) == owner) return (0); @@ -313,13 +315,13 @@ secpolicy_vnode_stky_modify(const cred_t *cr) int secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap, - const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns) + const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns, zuserns_t *fs_ns) { int error; if ((vap->va_mode & S_ISUID) != 0 && (error = secpolicy_vnode_setid_modify(cr, - ovap->va_uid, mnt_ns)) != 0) { + ovap->va_uid, mnt_ns, fs_ns)) != 0) { return (error); } @@ -337,7 +339,8 @@ secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap, * group-id bit. */ if ((vap->va_mode & S_ISGID) != 0 && - secpolicy_vnode_setids_setgids(cr, ovap->va_gid, mnt_ns) != 0) { + secpolicy_vnode_setids_setgids(cr, ovap->va_gid, + mnt_ns, fs_ns) != 0) { vap->va_mode &= ~S_ISGID; } diff --git a/module/os/linux/zfs/zfs_acl.c b/module/os/linux/zfs/zfs_acl.c index 437169990f02..7d14863c56c4 100644 --- a/module/os/linux/zfs/zfs_acl.c +++ b/module/os/linux/zfs/zfs_acl.c @@ -1889,7 +1889,8 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, acl_ids->z_mode |= S_ISGID; } else { if ((acl_ids->z_mode & S_ISGID) && - secpolicy_vnode_setids_setgids(cr, gid, mnt_ns) != 0) { + secpolicy_vnode_setids_setgids(cr, gid, mnt_ns, + zfs_i_user_ns(ZTOI(dzp))) != 0) { acl_ids->z_mode &= ~S_ISGID; } } @@ -1979,7 +1980,8 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (mask == 0) return (SET_ERROR(ENOSYS)); - if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, NULL))) + if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, + kcred->user_ns))) return (error); mutex_enter(&zp->z_acl_lock); @@ -2138,7 +2140,8 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr) if (zp->z_pflags & ZFS_IMMUTABLE) return (SET_ERROR(EPERM)); - if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, NULL))) + if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, + kcred->user_ns))) return (error); error = zfs_vsec_2_aclp(zfsvfs, ZTOI(zp)->i_mode, vsecp, cr, &fuidp, @@ -2301,9 +2304,9 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, uid_t fowner; if (mnt_ns) { - fowner = zfs_uid_into_mnt(mnt_ns, + fowner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)), KUID_TO_SUID(ZTOI(zp)->i_uid)); - gowner = zfs_gid_into_mnt(mnt_ns, + gowner = zfs_gid_to_vfsgid(mnt_ns, zfs_i_user_ns(ZTOI(zp)), KGID_TO_SGID(ZTOI(zp)->i_gid)); } else zfs_fuid_map_ids(zp, cr, &fowner, &gowner); @@ -2417,7 +2420,8 @@ zfs_has_access(znode_t *zp, cred_t *cr) { uint32_t have = ACE_ALL_PERMS; - if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, NULL) != 0) { + if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, + kcred->user_ns) != 0) { uid_t owner; owner = zfs_fuid_map_id(ZTOZSB(zp), @@ -2610,7 +2614,8 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr) DTRACE_PROBE(zfs__fastpath__execute__access__miss); if ((error = zfs_enter(ZTOZSB(zdp), FTAG)) != 0) return (error); - error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL); + error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, + kcred->user_ns); zfs_exit(ZTOZSB(zdp), FTAG); return (error); } @@ -2662,7 +2667,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr, } } - owner = zfs_uid_into_mnt(mnt_ns, KUID_TO_SUID(ZTOI(zp)->i_uid)); + owner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)), + KUID_TO_SUID(ZTOI(zp)->i_uid)); owner = zfs_fuid_map_id(ZTOZSB(zp), owner, cr, ZFS_OWNER); /* @@ -2786,7 +2792,7 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) { int v4_mode = zfs_unix_to_v4(mode >> 6); - return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, NULL)); + return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, kcred->user_ns)); } /* See zfs_zaccess_delete() */ diff --git a/module/os/linux/zfs/zfs_dir.c b/module/os/linux/zfs/zfs_dir.c index b4e4146b09e9..85aa94d8df6a 100644 --- a/module/os/linux/zfs/zfs_dir.c +++ b/module/os/linux/zfs/zfs_dir.c @@ -1113,11 +1113,11 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, znode_t **xzpp, cred_t *cr) *xzpp = NULL; if ((error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr, - NULL))) + kcred->user_ns))) return (error); if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL, - &acl_ids, NULL)) != 0) + &acl_ids, kcred->user_ns)) != 0) return (error); if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, zp->z_projid)) { zfs_acl_ids_free(&acl_ids); @@ -1265,7 +1265,8 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr) cr, ZFS_OWNER); if ((uid = crgetuid(cr)) == downer || uid == fowner || - zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL) == 0) + zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, + kcred->user_ns) == 0) return (0); else return (secpolicy_vnode_remove(cr)); diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 545d8ad8d79c..29d62837a82a 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -476,7 +476,7 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, */ if ((error = zfs_zaccess(*zpp, ACE_EXECUTE, 0, - B_TRUE, cr, NULL))) { + B_TRUE, cr, kcred->user_ns))) { zrele(*zpp); *zpp = NULL; } @@ -494,7 +494,8 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr, * Check accessibility of directory. */ - if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL))) { + if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, + kcred->user_ns))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -972,7 +973,7 @@ zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags) return (error); } - if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) { + if ((error = zfs_zaccess_delete(dzp, zp, cr, kcred->user_ns))) { goto out; } @@ -1386,7 +1387,7 @@ zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr, return (error); } - if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) { + if ((error = zfs_zaccess_delete(dzp, zp, cr, kcred->user_ns))) { goto out; } @@ -2024,10 +2025,10 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns) * Take ownership or chgrp to group we are a member of */ - uid = zfs_uid_into_mnt((struct user_namespace *)mnt_ns, - vap->va_uid); - gid = zfs_gid_into_mnt((struct user_namespace *)mnt_ns, - vap->va_gid); + uid = zfs_uid_to_vfsuid((struct user_namespace *)mnt_ns, + zfs_i_user_ns(ip), vap->va_uid); + gid = zfs_gid_to_vfsgid((struct user_namespace *)mnt_ns, + zfs_i_user_ns(ip), vap->va_gid); take_owner = (mask & ATTR_UID) && (uid == crgetuid(cr)); take_group = (mask & ATTR_GID) && zfs_groupmember(zfsvfs, gid, cr); @@ -2162,7 +2163,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns) if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, mnt_ns) == 0) { err = secpolicy_setid_setsticky_clear(ip, vap, - &oldva, cr, mnt_ns); + &oldva, cr, mnt_ns, zfs_i_user_ns(ip)); if (err) goto out3; trim_mask |= ATTR_MODE; @@ -3506,7 +3507,8 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr, return (SET_ERROR(EPERM)); } - if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr, NULL))) { + if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr, + kcred->user_ns))) { zfs_exit(zfsvfs, FTAG); return (error); } @@ -4132,7 +4134,8 @@ zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag, * On Linux we can get here through truncate_range() which * operates directly on inodes, so we need to check access rights. */ - if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL))) { + if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, + kcred->user_ns))) { zfs_exit(zfsvfs, FTAG); return (error); } diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index c8f6e02bd224..662147ab4722 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -1964,7 +1964,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx) } VERIFY(0 == zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr, - cr, NULL, &acl_ids, NULL)); + cr, NULL, &acl_ids, kcred->user_ns)); zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids); ASSERT3P(zp, ==, rootzp); error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx); diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c index 8bc4a9b39f22..f0779c81dc75 100644 --- a/module/os/linux/zfs/zpl_ctldir.c +++ b/module/os/linux/zfs/zpl_ctldir.c @@ -374,7 +374,7 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) #ifdef HAVE_IOPS_MKDIR_USERNS zpl_vap_init(vap, dip, mode | S_IFDIR, cr, user_ns); #else - zpl_vap_init(vap, dip, mode | S_IFDIR, cr, NULL); + zpl_vap_init(vap, dip, mode | S_IFDIR, cr, kcred->user_ns); #endif error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0); diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index cfa03e571f78..c56e3691e70a 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -1085,7 +1085,7 @@ zpl_ioctl_setflags(struct file *filp, void __user *arg) crhold(cr); cookie = spl_fstrans_mark(); - err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL); + err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, kcred->user_ns); spl_fstrans_unmark(cookie); crfree(cr); @@ -1133,7 +1133,7 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg) crhold(cr); cookie = spl_fstrans_mark(); - err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL); + err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, kcred->user_ns); spl_fstrans_unmark(cookie); crfree(cr); @@ -1221,7 +1221,7 @@ zpl_ioctl_setdosflags(struct file *filp, void __user *arg) crhold(cr); cookie = spl_fstrans_mark(); - err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL); + err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, kcred->user_ns); spl_fstrans_unmark(cookie); crfree(cr); diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 64016f9ac1de..6f4718f7d528 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -118,16 +118,16 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr, vap->va_mask = ATTR_MODE; vap->va_mode = mode; - vap->va_uid = zfs_uid_from_mnt((struct user_namespace *)mnt_ns, - crgetuid(cr)); + vap->va_uid = zfs_vfsuid_to_uid((struct user_namespace *)mnt_ns, + zfs_i_user_ns(dir), crgetuid(cr)); if (dir && dir->i_mode & S_ISGID) { vap->va_gid = KGID_TO_SGID(dir->i_gid); if (S_ISDIR(mode)) vap->va_mode |= S_ISGID; } else { - vap->va_gid = zfs_gid_from_mnt((struct user_namespace *)mnt_ns, - crgetgid(cr)); + vap->va_gid = zfs_vfsgid_to_gid((struct user_namespace *)mnt_ns, + zfs_i_user_ns(dir), crgetgid(cr)); } } @@ -145,7 +145,7 @@ zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag) int error; fstrans_cookie_t cookie; #ifndef HAVE_IOPS_CREATE_USERNS - zuserns_t *user_ns = NULL; + zuserns_t *user_ns = kcred->user_ns; #endif crhold(cr); @@ -192,7 +192,7 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, int error; fstrans_cookie_t cookie; #ifndef HAVE_IOPS_MKNOD_USERNS - zuserns_t *user_ns = NULL; + zuserns_t *user_ns = kcred->user_ns; #endif /* @@ -247,7 +247,7 @@ zpl_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) int error; fstrans_cookie_t cookie; #ifndef HAVE_TMPFILE_USERNS - zuserns_t *userns = NULL; + zuserns_t *userns = kcred->user_ns; #endif crhold(cr); @@ -325,7 +325,7 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) int error; fstrans_cookie_t cookie; #ifndef HAVE_IOPS_MKDIR_USERNS - zuserns_t *user_ns = NULL; + zuserns_t *user_ns = kcred->user_ns; #endif crhold(cr); @@ -468,8 +468,20 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); vap->va_mask = ia->ia_valid & ATTR_IATTR_MASK; vap->va_mode = ia->ia_mode; - vap->va_uid = KUID_TO_SUID(ia->ia_uid); - vap->va_gid = KGID_TO_SGID(ia->ia_gid); + if (ia->ia_valid & ATTR_UID) +#ifdef HAVE_IATTR_VFSID + vap->va_uid = zfs_vfsuid_to_uid(user_ns, zfs_i_user_ns(ip), + __vfsuid_val(ia->ia_vfsuid)); +#else + vap->va_uid = KUID_TO_SUID(ia->ia_uid); +#endif + if (ia->ia_valid & ATTR_GID) +#ifdef HAVE_IATTR_VFSID + vap->va_gid = zfs_vfsgid_to_gid(user_ns, zfs_i_user_ns(ip), + __vfsgid_val(ia->ia_vfsgid)); +#else + vap->va_gid = KGID_TO_SGID(ia->ia_gid); +#endif vap->va_size = ia->ia_size; vap->va_atime = ia->ia_atime; vap->va_mtime = ia->ia_mtime; @@ -482,7 +494,7 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) #ifdef HAVE_SETATTR_PREPARE_USERNS error = -zfs_setattr(ITOZ(ip), vap, 0, cr, user_ns); #else - error = -zfs_setattr(ITOZ(ip), vap, 0, cr, NULL); + error = -zfs_setattr(ITOZ(ip), vap, 0, cr, kcred->user_ns); #endif if (!error && (ia->ia_valid & ATTR_MODE)) error = zpl_chmod_acl(ip); @@ -510,7 +522,7 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry, int error; fstrans_cookie_t cookie; #ifndef HAVE_IOPS_RENAME_USERNS - zuserns_t *user_ns = NULL; + zuserns_t *user_ns = kcred->user_ns; #endif crhold(cr); @@ -557,7 +569,7 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name) int error; fstrans_cookie_t cookie; #ifndef HAVE_IOPS_SYMLINK_USERNS - zuserns_t *user_ns = NULL; + zuserns_t *user_ns = kcred->user_ns; #endif crhold(cr); diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c index 97b6e048c8a8..99d9b3793f29 100644 --- a/module/os/linux/zfs/zpl_xattr.c +++ b/module/os/linux/zfs/zpl_xattr.c @@ -499,7 +499,7 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value, vap->va_gid = crgetgid(cr); error = -zfs_create(dxzp, (char *)name, vap, 0, 0644, &xzp, - cr, 0, NULL, NULL); + cr, 0, NULL, kcred->user_ns); if (error) goto out; } @@ -738,9 +738,11 @@ __zpl_xattr_user_get(struct inode *ip, const char *name, ZPL_XATTR_GET_WRAPPER(zpl_xattr_user_get); static int -__zpl_xattr_user_set(struct inode *ip, const char *name, +__zpl_xattr_user_set(struct user_namespace *user_ns, + struct inode *ip, const char *name, const void *value, size_t size, int flags) { + (void) user_ns; int error = 0; /* xattr_resolve_name will do this for us if this is defined */ #ifndef HAVE_XATTR_HANDLER_NAME @@ -846,9 +848,11 @@ __zpl_xattr_trusted_get(struct inode *ip, const char *name, ZPL_XATTR_GET_WRAPPER(zpl_xattr_trusted_get); static int -__zpl_xattr_trusted_set(struct inode *ip, const char *name, +__zpl_xattr_trusted_set(struct user_namespace *user_ns, + struct inode *ip, const char *name, const void *value, size_t size, int flags) { + (void) user_ns; char *xattr_name; int error; @@ -914,9 +918,11 @@ __zpl_xattr_security_get(struct inode *ip, const char *name, ZPL_XATTR_GET_WRAPPER(zpl_xattr_security_get); static int -__zpl_xattr_security_set(struct inode *ip, const char *name, +__zpl_xattr_security_set(struct user_namespace *user_ns, + struct inode *ip, const char *name, const void *value, size_t size, int flags) { + (void) user_ns; char *xattr_name; int error; /* xattr_resolve_name will do this for us if this is defined */ @@ -940,7 +946,7 @@ zpl_xattr_security_init_impl(struct inode *ip, const struct xattr *xattrs, int error = 0; for (xattr = xattrs; xattr->name != NULL; xattr++) { - error = __zpl_xattr_security_set(ip, + error = __zpl_xattr_security_set(NULL, ip, xattr->name, xattr->value, xattr->value_len, 0); if (error < 0) @@ -1300,7 +1306,8 @@ __zpl_xattr_acl_get_default(struct inode *ip, const char *name, ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_default); static int -__zpl_xattr_acl_set_access(struct inode *ip, const char *name, +__zpl_xattr_acl_set_access(struct user_namespace *mnt_ns, + struct inode *ip, const char *name, const void *value, size_t size, int flags) { struct posix_acl *acl; @@ -1314,8 +1321,14 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name, if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) return (-EOPNOTSUPP); +#if defined(HAVE_XATTR_SET_USERNS) + if (!zpl_inode_owner_or_capable(mnt_ns, ip)) + return (-EPERM); +#else + (void) mnt_ns; if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) return (-EPERM); +#endif if (value) { acl = zpl_acl_from_xattr(value, size); @@ -1339,7 +1352,8 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name, ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_access); static int -__zpl_xattr_acl_set_default(struct inode *ip, const char *name, +__zpl_xattr_acl_set_default(struct user_namespace *mnt_ns, + struct inode *ip, const char *name, const void *value, size_t size, int flags) { struct posix_acl *acl; @@ -1353,8 +1367,14 @@ __zpl_xattr_acl_set_default(struct inode *ip, const char *name, if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX) return (-EOPNOTSUPP); +#if defined(HAVE_XATTR_SET_USERNS) + if (!zpl_inode_owner_or_capable(mnt_ns, ip)) + return (-EPERM); +#else + (void) mnt_ns; if (!zpl_inode_owner_or_capable(kcred->user_ns, ip)) return (-EPERM); +#endif if (value) { acl = zpl_acl_from_xattr(value, size); diff --git a/module/zfs/zfs_replay.c b/module/zfs/zfs_replay.c index 5e20ce3319b4..0293e46d5858 100644 --- a/module/zfs/zfs_replay.c +++ b/module/zfs/zfs_replay.c @@ -386,8 +386,13 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap) lr->lr_uid, lr->lr_gid); } +#if defined(__linux__) + error = zfs_create(dzp, name, &xva.xva_vattr, + 0, 0, &zp, kcred, vflg, &vsec, kcred->user_ns); +#else error = zfs_create(dzp, name, &xva.xva_vattr, 0, 0, &zp, kcred, vflg, &vsec, NULL); +#endif break; case TX_MKDIR_ACL: aclstart = (caddr_t)(lracl + 1); @@ -416,8 +421,13 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap) (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); } +#if defined(__linux__) + error = zfs_mkdir(dzp, name, &xva.xva_vattr, + &zp, kcred, vflg, &vsec, kcred->user_ns); +#else error = zfs_mkdir(dzp, name, &xva.xva_vattr, &zp, kcred, vflg, &vsec, NULL); +#endif break; default: error = SET_ERROR(ENOTSUP); @@ -527,8 +537,13 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) if (name == NULL) name = (char *)start; +#if defined(__linux__) + error = zfs_create(dzp, name, &xva.xva_vattr, + 0, 0, &zp, kcred, vflg, NULL, kcred->user_ns); +#else error = zfs_create(dzp, name, &xva.xva_vattr, 0, 0, &zp, kcred, vflg, NULL, NULL); +#endif break; case TX_MKDIR_ATTR: lrattr = (lr_attr_t *)(caddr_t)(lr + 1); @@ -545,8 +560,14 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) if (name == NULL) name = (char *)(lr + 1); +#if defined(__linux__) + error = zfs_mkdir(dzp, name, &xva.xva_vattr, + &zp, kcred, vflg, NULL, kcred->user_ns); +#else error = zfs_mkdir(dzp, name, &xva.xva_vattr, &zp, kcred, vflg, NULL, NULL); +#endif + break; case TX_MKXATTR: error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &zp, kcred); @@ -554,8 +575,13 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) case TX_SYMLINK: name = (char *)(lr + 1); link = name + strlen(name) + 1; +#if defined(__linux__) + error = zfs_symlink(dzp, name, &xva.xva_vattr, + link, &zp, kcred, vflg, kcred->user_ns); +#else error = zfs_symlink(dzp, name, &xva.xva_vattr, link, &zp, kcred, vflg, NULL); +#endif break; default: error = SET_ERROR(ENOTSUP); @@ -670,8 +696,13 @@ do_zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, char *sname, if (lr->lr_common.lrc_txtype & TX_CI) vflg |= FIGNORECASE; +#if defined(__linux__) + error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags, + wo_vap, kcred->user_ns); +#else error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags, wo_vap, NULL); +#endif zrele(tdzp); zrele(sdzp); @@ -944,7 +975,11 @@ zfs_replay_setattr(void *arg1, void *arg2, boolean_t byteswap) zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); +#if defined(__linux__) + error = zfs_setattr(zp, vap, 0, kcred, kcred->user_ns); +#else error = zfs_setattr(zp, vap, 0, kcred, NULL); +#endif zfs_fuid_info_free(zfsvfs->z_fuid_replay); zfsvfs->z_fuid_replay = NULL; diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 593249e12cb4..45ecb0773260 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -168,9 +168,19 @@ zfs_access(znode_t *zp, int mode, int flag, cred_t *cr) return (error); if (flag & V_ACE_MASK) - error = zfs_zaccess(zp, mode, flag, B_FALSE, cr, NULL); +#if defined(__linux__) + error = zfs_zaccess(zp, mode, flag, B_FALSE, cr, + kcred->user_ns); +#else + error = zfs_zaccess(zp, mode, flag, B_FALSE, cr, + NULL); +#endif else +#if defined(__linux__) + error = zfs_zaccess_rwx(zp, mode, flag, cr, kcred->user_ns); +#else error = zfs_zaccess_rwx(zp, mode, flag, cr, NULL); +#endif zfs_exit(zfsvfs, FTAG); return (error); diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run index 13f7efd96bd3..52e824a888f2 100644 --- a/tests/runfiles/linux.run +++ b/tests/runfiles/linux.run @@ -200,5 +200,5 @@ tags = ['functional', 'zvol', 'zvol_misc'] [tests/functional/idmap_mount:Linux] tests = ['idmap_mount_001', 'idmap_mount_002', 'idmap_mount_003', - 'idmap_mount_004'] + 'idmap_mount_004', 'idmap_mount_005'] tags = ['functional', 'idmap_mount'] diff --git a/tests/test-runner/bin/zts-report.py.in b/tests/test-runner/bin/zts-report.py.in index 1cebf50827b9..66b041b6e2a9 100755 --- a/tests/test-runner/bin/zts-report.py.in +++ b/tests/test-runner/bin/zts-report.py.in @@ -284,6 +284,7 @@ elif sys.platform.startswith('linux'): 'idmap_mount/idmap_mount_002': ['SKIP', idmap_reason], 'idmap_mount/idmap_mount_003': ['SKIP', idmap_reason], 'idmap_mount/idmap_mount_004': ['SKIP', idmap_reason], + 'idmap_mount/idmap_mount_005': ['SKIP', idmap_reason], }) diff --git a/tests/zfs-tests/cmd/idmap_util.c b/tests/zfs-tests/cmd/idmap_util.c index b6ca111ad227..49483cbaa421 100644 --- a/tests/zfs-tests/cmd/idmap_util.c +++ b/tests/zfs-tests/cmd/idmap_util.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -458,43 +459,56 @@ userns_fd_from_idmap(list_t *head) { pid_t pid; int ret, fd; - int pipe_fd[2]; + int fds[2]; char c; int saved_errno = 0; - /* pipe for bidirectional communication */ - ret = pipe(pipe_fd); + /* socketpair for bidirectional communication */ + ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, fds); if (ret) { - log_errno("pipe"); + log_errno("socketpair"); return (-errno); } pid = fork(); if (pid < 0) { log_errno("fork"); - return (-errno); + fd = -errno; + goto out; } if (pid == 0) { /* child process */ - close(pipe_fd[0]); ret = unshare(CLONE_NEWUSER); if (ret == 0) { /* notify the parent of success */ - ret = write_buf(pipe_fd[1], "1", 1); + ret = write_buf(fds[1], "1", 1); + if (ret < 0) + saved_errno = errno; + else { + /* + * Until the parent has written to idmap, + * we cannot exit, otherwise the defunct + * process is owned by the real root, writing + * to its idmap ends up with EPERM in the + * context of a user ns + */ + ret = read_buf(fds[1], &c, 1); + if (ret < 0) + saved_errno = errno; + } } else { saved_errno = errno; log_errno("unshare"); - ret = write_buf(pipe_fd[1], "0", 1); + ret = write_buf(fds[1], "0", 1); + if (ret < 0) + saved_errno = errno; } - if (ret < 0) - saved_errno = errno; - close(pipe_fd[1]); exit(saved_errno); } + /* parent process */ - close(pipe_fd[1]); - ret = read_buf(pipe_fd[0], &c, 1); + ret = read_buf(fds[0], &c, 1); if (ret == 1 && c == '1') { ret = write_pid_idmaps(pid, head); if (!ret) { @@ -504,11 +518,15 @@ userns_fd_from_idmap(list_t *head) } else { fd = -ret; } + /* Let child know it can exit */ + (void) write_buf(fds[0], "1", 1); } else { fd = -EBADF; } - close(pipe_fd[0]); (void) wait_for_pid(pid); +out: + close(fds[0]); + close(fds[1]); return (fd); } @@ -532,7 +550,8 @@ is_idmap_supported(char *path) }; /* strtok_r() won't be happy with a const string */ - char *input = strdup("b:0:1000000:1000000"); + /* To check if idmapped mount can be done in a user ns, map 0 to 0 */ + char *input = strdup("b:0:0:1"); if (!input) { errno = ENOMEM; diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 2d99027754c4..5b8458b73180 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -2006,4 +2006,5 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/idmap_mount/idmap_mount_001.ksh \ functional/idmap_mount/idmap_mount_002.ksh \ functional/idmap_mount/idmap_mount_003.ksh \ - functional/idmap_mount/idmap_mount_004.ksh + functional/idmap_mount/idmap_mount_004.ksh \ + functional/idmap_mount/idmap_mount_005.ksh diff --git a/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_005.ksh b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_005.ksh new file mode 100755 index 000000000000..a4ecea92c127 --- /dev/null +++ b/tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_005.ksh @@ -0,0 +1,138 @@ +#!/bin/ksh -p +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or https://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib + +# +# +# DESCRIPTION: +# Test idmapped mount in a user namespace +# +# STRATEGY: +# 1. Create a zoned dataset +# 2. Create a user namespace and designate the dataset to the zone +# 3. In the zone, mount the dataset to "idmap_test" +# 4. In the zone, idmap mount the dataset mountpoint to "idmap_dest" +# 5. Do some file operations in the idmapped mountpoint "idmap_dest" +# 6. Check the owner of files/folder in the mount point "idmap_test" +# 7. unmount the mountpoints in the zone +# 8. Remount the dataset in global zone to "idmap_test" +# 9. Check the owenr of filers/folder in the mountpoint "idmap_test" +# + +verify_runnable "global" + +export WORKDIR=$TESTDIR/idmap_test +export IDMAPDIR=$TESTDIR/idmap_dest + +function cleanup +{ + if [[ -v unshared_pid ]]; then + zfs unzone /proc/$unshared_pid/ns/user "$TESTPOOL/userns" + kill -TERM ${unshared_pid} + fi + if mountpoint $WORKDIR; then + log_must umount $WORKDIR + fi + log_must rm -rf $WORKDIR +} + +log_onexit cleanup + +if ! idmap_util -c $TESTDIR; then + log_unsupported "Idmap mount not supported." +fi + +unshare -Urm echo test +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to create user namespace" +fi + +log_must zfs create -o zoned=off -o mountpoint=$WORKDIR "$TESTPOOL/userns" + +# "root" user and group in the user ns +log_must chown 1000000:1000000 $WORKDIR +log_must zfs set zoned=on "$TESTPOOL/userns" + +log_must mkdir -p $IDMAPDIR + +unshare -Um /usr/bin/sleep 2h & +unshared_pid=$! +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to create user namespace" +fi +# wait for userns to be ready +sleep 1 +echo "0 1000000 1000000" > /proc/$unshared_pid/uid_map +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to write to uid_map" +fi +echo "0 1000000 1000000" > /proc/$unshared_pid/gid_map +if [ "$?" -ne "0" ]; then + log_unsupported "Failed to write to gid_map" +fi + +NSENTER="nsenter -t $unshared_pid --all -S 0 -G 0" + +log_must zfs zone /proc/$unshared_pid/ns/user "$TESTPOOL/userns" +log_must $NSENTER zfs mount "$TESTPOOL/userns" +log_must $NSENTER chmod 777 $WORKDIR + +$NSENTER idmap_util -c $WORKDIR +if [ "$?" -ne "0" ]; then + log_unsupported "Idmapped mount not supported in a user namespace" +fi + +log_must $NSENTER idmap_util -m b:0:10000:100000 $WORKDIR $IDMAPDIR +log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups touch $IDMAPDIR/file +log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups mkdir $IDMAPDIR/folder +log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups ln -s file $IDMAPDIR/file-soft +log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups ln $IDMAPDIR/file $IDMAPDIR/file-hard + +log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups cp -p $IDMAPDIR/file $IDMAPDIR/folder/file-p +log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups cp $IDMAPDIR/file $IDMAPDIR/folder/file + +log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/file)" +log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/folder)" +log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/file-soft)" +log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/file-hard)" +log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/folder/file-p)" +log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/folder/file)" + +log_must $NSENTER umount $IDMAPDIR +log_must $NSENTER umount $WORKDIR + +log_must zfs unzone /proc/$unshared_pid/ns/user "$TESTPOOL/userns" +log_must kill -TERM $unshared_pid +unset unshared_pid +log_must zfs set zoned=off "$TESTPOOL/userns" +log_must zfs mount "$TESTPOOL/userns" + +log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/file)" +log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/folder)" +log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/file-soft)" +log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/file-hard)" +log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/folder/file-p)" +log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/folder/file)" + +log_pass "Testing idmapped mount in a user ns is successful." + From e197bb24f1857c823b44c2175b2318c472d79731 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 8 Nov 2022 13:38:08 -0700 Subject: [PATCH 118/126] Optionally skip zil_close during zvol_create_minor_impl If there were no zil entries to replay, skip zil_close. zil_close waits for a transaction to sync. That can take several seconds, for example during pool import of a resilvering pool. Skipping zil_close can cut the time for "zpool import" from 2 hours to 45 seconds on a resilvering pool with a thousand zvols. Reviewed-by: Richard Yao Reviewed-by: Alexander Motin Reviewed-by: Ryan Moeller Sponsored-by: Axcient Closes #13999 Closes #14015 --- include/sys/zil.h | 4 ++-- module/os/freebsd/zfs/zvol_os.c | 8 +++++--- module/os/linux/zfs/zvol_os.c | 8 +++++--- module/zfs/zil.c | 15 ++++++++++----- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/sys/zil.h b/include/sys/zil.h index 9591fb4f6440..9ac421043377 100644 --- a/include/sys/zil.h +++ b/include/sys/zil.h @@ -539,10 +539,10 @@ extern zilog_t *zil_open(objset_t *os, zil_get_data_t *get_data, zil_sums_t *zil_sums); extern void zil_close(zilog_t *zilog); -extern void zil_replay(objset_t *os, void *arg, +extern boolean_t zil_replay(objset_t *os, void *arg, zil_replay_func_t *const replay_func[TX_MAX_TYPE]); extern boolean_t zil_replaying(zilog_t *zilog, dmu_tx_t *tx); -extern void zil_destroy(zilog_t *zilog, boolean_t keep_first); +extern boolean_t zil_destroy(zilog_t *zilog, boolean_t keep_first); extern void zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx); extern itx_t *zil_itx_create(uint64_t txtype, size_t lrsize); diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c index 8d2a6d77624b..631e020db9c9 100644 --- a/module/os/freebsd/zfs/zvol_os.c +++ b/module/os/freebsd/zfs/zvol_os.c @@ -1386,6 +1386,7 @@ zvol_os_create_minor(const char *name) uint64_t volsize; uint64_t volmode, hash; int error; + bool replayed_zil = B_FALSE; ZFS_LOG(1, "Creating ZVOL %s...", name); hash = zvol_name_hash(name); @@ -1490,11 +1491,12 @@ zvol_os_create_minor(const char *name) zv->zv_zilog = zil_open(os, zvol_get_data, &zv->zv_kstat.dk_zil_sums); if (spa_writeable(dmu_objset_spa(os))) { if (zil_replay_disable) - zil_destroy(zv->zv_zilog, B_FALSE); + replayed_zil = zil_destroy(zv->zv_zilog, B_FALSE); else - zil_replay(os, zv, zvol_replay_vector); + replayed_zil = zil_replay(os, zv, zvol_replay_vector); } - zil_close(zv->zv_zilog); + if (replayed_zil) + zil_close(zv->zv_zilog); zv->zv_zilog = NULL; /* TODO: prefetch for geom tasting */ diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index d76bab3c0106..01e6456207b0 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -1279,6 +1279,7 @@ zvol_os_create_minor(const char *name) int error = 0; int idx; uint64_t hash = zvol_name_hash(name); + bool replayed_zil = B_FALSE; if (zvol_inhibit_dev) return (0); @@ -1420,11 +1421,12 @@ zvol_os_create_minor(const char *name) zv->zv_zilog = zil_open(os, zvol_get_data, &zv->zv_kstat.dk_zil_sums); if (spa_writeable(dmu_objset_spa(os))) { if (zil_replay_disable) - zil_destroy(zv->zv_zilog, B_FALSE); + replayed_zil = zil_destroy(zv->zv_zilog, B_FALSE); else - zil_replay(os, zv, zvol_replay_vector); + replayed_zil = zil_replay(os, zv, zvol_replay_vector); } - zil_close(zv->zv_zilog); + if (replayed_zil) + zil_close(zv->zv_zilog); zv->zv_zilog = NULL; /* diff --git a/module/zfs/zil.c b/module/zfs/zil.c index 59c7595f6df2..02e6f4b83b9c 100644 --- a/module/zfs/zil.c +++ b/module/zfs/zil.c @@ -887,8 +887,9 @@ zil_create(zilog_t *zilog) * txg_wait_synced() here either when keep_first is set, because both * zil_create() and zil_destroy() will wait for any in-progress destroys * to complete. + * Return B_TRUE if there were any entries to replay. */ -void +boolean_t zil_destroy(zilog_t *zilog, boolean_t keep_first) { const zil_header_t *zh = zilog->zl_header; @@ -904,7 +905,7 @@ zil_destroy(zilog_t *zilog, boolean_t keep_first) zilog->zl_old_header = *zh; /* debugging aid */ if (BP_IS_HOLE(&zh->zh_log)) - return; + return (B_FALSE); tx = dmu_tx_create(zilog->zl_os); VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); @@ -937,6 +938,8 @@ zil_destroy(zilog_t *zilog, boolean_t keep_first) mutex_exit(&zilog->zl_lock); dmu_tx_commit(tx); + + return (B_TRUE); } void @@ -3849,8 +3852,9 @@ zil_incr_blks(zilog_t *zilog, const blkptr_t *bp, void *arg, uint64_t claim_txg) /* * If this dataset has a non-empty intent log, replay it and destroy it. + * Return B_TRUE if there were any entries to replay. */ -void +boolean_t zil_replay(objset_t *os, void *arg, zil_replay_func_t *const replay_func[TX_MAX_TYPE]) { @@ -3859,8 +3863,7 @@ zil_replay(objset_t *os, void *arg, zil_replay_arg_t zr; if ((zh->zh_flags & ZIL_REPLAY_NEEDED) == 0) { - zil_destroy(zilog, B_TRUE); - return; + return (zil_destroy(zilog, B_TRUE)); } zr.zr_replay = replay_func; @@ -3883,6 +3886,8 @@ zil_replay(objset_t *os, void *arg, zil_destroy(zilog, B_FALSE); txg_wait_synced(zilog->zl_dmu_pool, zilog->zl_destroy_txg); zilog->zl_replay = B_FALSE; + + return (B_TRUE); } boolean_t From 945b407486a0072ec7dd117a0bde2f72d52eb445 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Tue, 8 Nov 2022 21:40:22 +0100 Subject: [PATCH 119/126] quota: disable quota check for ZVOL The quota for ZVOLs is set to the size of the volume. When the quota reaches the maximum, there isn't an excellent way to check if the new writers are overwriting the data or if they are inserting a new one. Because of that, when we reach the maximum quota, we wait till txg is flushed. This is causing a significant fluctuation in bandwidth. In the case of ZVOL, the quota is enforced by the volsize, so we can omit it. This commit adds a sysctl thats allow to control if the quota mechanism should be enforced or not. Reviewed-by: Brian Behlendorf Signed-off-by: Mariusz Zaborski Sponsored-by: Zededa Inc. Sponsored-by: Klara Inc. Closes #13838 --- man/man4/zfs.4 | 6 +++++- module/zfs/dsl_dir.c | 22 ++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index 5b53b1310e49..ad3d8810e925 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -15,7 +15,7 @@ .\" own identifying information: .\" Portions Copyright [yyyy] [name of copyright owner] .\" -.Dd June 1, 2021 +.Dd November 7, 2022 .Dt ZFS 4 .Os . @@ -2386,6 +2386,10 @@ Defines zvol block devices behaviour when .It Sy 3 .No equivalent to Sy none .El +. +.It Sy zvol_enforce_quotas Ns = Ns Sy 0 Ns | Ns 1 Pq uint +Enable strict ZVOL quota enforcement. +The strict quota enforcement may have a performance impact. .El . .Sh ZFS I/O SCHEDULER diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 9af760177445..486f50108bfa 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -53,6 +53,15 @@ #include "zfs_namecheck.h" #include "zfs_prop.h" +/* + * This controls if we verify the ZVOL quota or not. + * Currently, quotas are not implemented for ZVOLs. + * The quota size is the size of the ZVOL. + * The size of the volume already implies the ZVOL size quota. + * The quota mechanism can introduce a significant performance drop. + */ +static int zvol_enforce_quotas = B_TRUE; + /* * Filesystem and Snapshot Limits * ------------------------------ @@ -1311,7 +1320,9 @@ dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree, * If this transaction will result in a net free of space, * we want to let it through. */ - if (ignorequota || netfree || dsl_dir_phys(dd)->dd_quota == 0) + if (ignorequota || netfree || dsl_dir_phys(dd)->dd_quota == 0 || + (dmu_objset_type(tx->tx_objset) == DMU_OST_ZVOL && + zvol_enforce_quotas == B_FALSE)) quota = UINT64_MAX; else quota = dsl_dir_phys(dd)->dd_quota; @@ -1399,10 +1410,9 @@ dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree, ignorequota = (dsl_dir_phys(dd)->dd_head_dataset_obj == 0); first = B_FALSE; goto top_of_function; - - } else { - return (0); } + + return (0); } /* @@ -2483,3 +2493,7 @@ dsl_dir_cancel_waiters(dsl_dir_t *dd) EXPORT_SYMBOL(dsl_dir_set_quota); EXPORT_SYMBOL(dsl_dir_set_reservation); #endif + +/* CSTYLED */ +ZFS_MODULE_PARAM(zfs, , zvol_enforce_quotas, INT, ZMOD_RW, + "Enable strict ZVOL quota enforcment"); From 16f0fdadddcc7562ddf475f496a434b9ac94b0f7 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Thu, 10 Nov 2022 22:37:12 +0100 Subject: [PATCH 120/126] Allow to control failfast Linux defaults to setting "failfast" on BIOs, so that the OS will not retry IOs that fail, and instead report the error to ZFS. In some cases, such as errors reported by the HBA driver, not the device itself, we would wish to retry rather than generating vdev errors in ZFS. This new property allows that. This introduces a per vdev option to disable the failfast option. This also introduces a global module parameter to define the failfast mask value. Reviewed-by: Brian Behlendorf Co-authored-by: Allan Jude Signed-off-by: Allan Jude Signed-off-by: Mariusz Zaborski Sponsored-by: Seagate Technology LLC Submitted-by: Klara, Inc. Closes #14056 --- include/os/linux/kernel/linux/blkdev_compat.h | 10 +++- include/sys/fs/zfs.h | 1 + include/sys/vdev_impl.h | 1 + lib/libzfs/libzfs.abi | 3 +- man/man4/zfs.4 | 17 ++++++- man/man7/vdevprops.7 | 5 +- module/os/linux/zfs/vdev_disk.c | 16 ++++++- module/zcommon/zpool_prop.c | 3 ++ module/zfs/vdev.c | 46 +++++++++++++++++++ 9 files changed, 94 insertions(+), 8 deletions(-) diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h index 3276796537a4..45de1f4993f1 100644 --- a/include/os/linux/kernel/linux/blkdev_compat.h +++ b/include/os/linux/kernel/linux/blkdev_compat.h @@ -126,7 +126,8 @@ typedef int bvec_iterator_t; #endif static inline void -bio_set_flags_failfast(struct block_device *bdev, int *flags) +bio_set_flags_failfast(struct block_device *bdev, int *flags, bool dev, + bool transport, bool driver) { #ifdef CONFIG_BUG /* @@ -148,7 +149,12 @@ bio_set_flags_failfast(struct block_device *bdev, int *flags) #endif /* BLOCK_EXT_MAJOR */ #endif /* CONFIG_BUG */ - *flags |= REQ_FAILFAST_MASK; + if (dev) + *flags |= REQ_FAILFAST_DEV; + if (transport) + *flags |= REQ_FAILFAST_TRANSPORT; + if (driver) + *flags |= REQ_FAILFAST_DRIVER; } /* diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 10a5ec3172a2..1124604e8c68 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -355,6 +355,7 @@ typedef enum { VDEV_PROP_BYTES_TRIM, VDEV_PROP_REMOVING, VDEV_PROP_ALLOCATING, + VDEV_PROP_FAILFAST, VDEV_NUM_PROPS } vdev_prop_t; diff --git a/include/sys/vdev_impl.h b/include/sys/vdev_impl.h index bfa8fe093de2..3f4b78b947a3 100644 --- a/include/sys/vdev_impl.h +++ b/include/sys/vdev_impl.h @@ -299,6 +299,7 @@ struct vdev { uint64_t vdev_islog; /* is an intent log device */ uint64_t vdev_noalloc; /* device is passivated? */ uint64_t vdev_removing; /* device is being removed? */ + uint64_t vdev_failfast; /* device failfast setting */ boolean_t vdev_ishole; /* is a hole in the namespace */ uint64_t vdev_top_zap; vdev_alloc_bias_t vdev_alloc_bias; /* metaslab allocation bias */ diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 061a060b6697..98873784e7dc 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -3214,7 +3214,8 @@ - + + diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index ad3d8810e925..98539a6369e7 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -15,7 +15,7 @@ .\" own identifying information: .\" Portions Copyright [yyyy] [name of copyright owner] .\" -.Dd November 7, 2022 +.Dd November 9, 2022 .Dt ZFS 4 .Os . @@ -1345,6 +1345,19 @@ as fuller devices will tend to be slower than empty devices. Also see .Sy zio_dva_throttle_enabled . . +.It Sy zfs_vdev_failfast_mask Ns = Ns Sy 1 Pq uint +Defines if the driver should retire on a given error type. +The following options may be bitwise-ored together: +.TS +box; +lbz r l l . + Value Name Description +_ + 1 Device No driver retries on device errors + 2 Transport No driver retries on transport errors. + 4 Driver No driver retries on driver errors. +.TE +. .It Sy zfs_expire_snapshot Ns = Ns Sy 300 Ns s Pq int Time before expiring .Pa .zfs/snapshot . @@ -1364,7 +1377,7 @@ The following flags may be bitwise-ored together: .TS box; lbz r l l . - Value Symbolic Name Description + Value Name Description _ 1 ZFS_DEBUG_DPRINTF Enable dprintf entries in the debug log. * 2 ZFS_DEBUG_DBUF_VERIFY Enable extra dbuf verifications. diff --git a/man/man7/vdevprops.7 b/man/man7/vdevprops.7 index b98bda064c70..af5d26f6b486 100644 --- a/man/man7/vdevprops.7 +++ b/man/man7/vdevprops.7 @@ -20,7 +20,7 @@ .\" .\" Copyright (c) 2021 Klara, Inc. .\" -.Dd November 27, 2021 +.Dd October 30, 2022 .Dt VDEVPROPS 7 .Os . @@ -121,6 +121,9 @@ dataset. A text comment up to 8192 characters long .It Sy bootsize The amount of space to reserve for the EFI system partition +.It Sy failfast +If this device should propage BIO errors back to ZFS, used to disable +failfast. .It Sy path The path to the device for this vdev .It Sy allocating diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c index 84d191abb90b..4f33009f14d4 100644 --- a/module/os/linux/zfs/vdev_disk.c +++ b/module/os/linux/zfs/vdev_disk.c @@ -74,6 +74,12 @@ typedef struct dio_request { struct bio *dr_bio[0]; /* Attached bio's */ } dio_request_t; +/* + * BIO request failfast mask. + */ + +static unsigned int zfs_vdev_failfast_mask = 1; + static fmode_t vdev_bdev_mode(spa_mode_t spa_mode) { @@ -659,8 +665,11 @@ __vdev_disk_physio(struct block_device *bdev, zio_t *zio, retry: dr = vdev_disk_dio_alloc(bio_count); - if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) - bio_set_flags_failfast(bdev, &flags); + if (zio && !(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD)) && + zio->io_vd->vdev_failfast == B_TRUE) { + bio_set_flags_failfast(bdev, &flags, zfs_vdev_failfast_mask & 1, + zfs_vdev_failfast_mask & 2, zfs_vdev_failfast_mask & 4); + } dr->dr_zio = zio; @@ -1045,3 +1054,6 @@ param_set_max_auto_ashift(const char *buf, zfs_kernel_param_t *kp) ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, open_timeout_ms, UINT, ZMOD_RW, "Timeout before determining that a device is missing"); + +ZFS_MODULE_PARAM(zfs_vdev, zfs_vdev_, failfast_mask, UINT, ZMOD_RW, + "Defines failfast mask: 1 - device, 2 - transport, 4 - driver"); diff --git a/module/zcommon/zpool_prop.c b/module/zcommon/zpool_prop.c index 4737bd628ddf..285b97909631 100644 --- a/module/zcommon/zpool_prop.c +++ b/module/zcommon/zpool_prop.c @@ -420,6 +420,9 @@ vdev_prop_init(void) boolean_na_table, sfeatures); /* default index properties */ + zprop_register_index(VDEV_PROP_FAILFAST, "failfast", B_TRUE, + PROP_DEFAULT, ZFS_TYPE_VDEV, "on | off", "FAILFAST", boolean_table, + sfeatures); /* hidden properties */ zprop_register_hidden(VDEV_PROP_NAME, "name", PROP_TYPE_STRING, diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 8c62112de71b..4520ca31b7d7 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -3563,6 +3563,26 @@ vdev_load(vdev_t *vd) } } + if (vd == vd->vdev_top && vd->vdev_top_zap != 0) { + spa_t *spa = vd->vdev_spa; + uint64_t failfast; + + error = zap_lookup(spa->spa_meta_objset, vd->vdev_top_zap, + vdev_prop_to_name(VDEV_PROP_FAILFAST), sizeof (failfast), + 1, &failfast); + if (error == 0) { + vd->vdev_failfast = failfast & 1; + } else if (error == ENOENT) { + vd->vdev_failfast = vdev_prop_default_numeric( + VDEV_PROP_FAILFAST); + } else { + vdev_dbgmsg(vd, + "vdev_load: zap_lookup(top_zap=%llu) " + "failed [error=%d]", + (u_longlong_t)vd->vdev_top_zap, error); + } + } + /* * Load any rebuild state from the top-level vdev zap. */ @@ -5709,6 +5729,13 @@ vdev_prop_set(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) else error = spa_vdev_alloc(spa, vdev_guid); break; + case VDEV_PROP_FAILFAST: + if (nvpair_value_uint64(elem, &intval) != 0) { + error = EINVAL; + break; + } + vd->vdev_failfast = intval & 1; + break; default: /* Most processing is done in vdev_props_set_sync */ break; @@ -6019,6 +6046,25 @@ vdev_prop_get(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) intval = ZPROP_BOOLEAN_NA; } + vdev_prop_add_list(outnvl, propname, strval, + intval, src); + break; + case VDEV_PROP_FAILFAST: + src = ZPROP_SRC_LOCAL; + strval = NULL; + + err = zap_lookup(mos, objid, nvpair_name(elem), + sizeof (uint64_t), 1, &intval); + if (err == ENOENT) { + intval = vdev_prop_default_numeric( + prop); + err = 0; + } else if (err) { + break; + } + if (intval == vdev_prop_default_numeric(prop)) + src = ZPROP_SRC_DEFAULT; + vdev_prop_add_list(outnvl, propname, strval, intval, src); break; From 9e2be2dfbde6c41ff53d71f3669cb6b9909c5a40 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 10 Nov 2022 09:01:58 -0500 Subject: [PATCH 121/126] Fix potential NULL pointer dereference regression 945b407486a0072ec7dd117a0bde2f72d52eb445 neglected to `NULL` check `tx->tx_objset`, which is already done in the function. This upset Coverity, which complained about a "dereference after null check". Upon inspection, it was found that whenever `dmu_tx_create_dd()` is called followed by `dmu_tx_assign()`, such as in `dsl_sync_task_common()`, `tx->tx_objset` will be `NULL`. Reported-by: Coverity (CID 1527261) Reviewed-by: Mariusz Zaborski Reviewed-by: Youzhong Yang Signed-off-by: Richard Yao Closes #14170 --- module/zfs/dsl_dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c index 486f50108bfa..c1afaa6aaf82 100644 --- a/module/zfs/dsl_dir.c +++ b/module/zfs/dsl_dir.c @@ -1321,7 +1321,7 @@ dsl_dir_tempreserve_impl(dsl_dir_t *dd, uint64_t asize, boolean_t netfree, * we want to let it through. */ if (ignorequota || netfree || dsl_dir_phys(dd)->dd_quota == 0 || - (dmu_objset_type(tx->tx_objset) == DMU_OST_ZVOL && + (tx->tx_objset && dmu_objset_type(tx->tx_objset) == DMU_OST_ZVOL && zvol_enforce_quotas == B_FALSE)) quota = UINT64_MAX; else From b1eec00904a22bd6600a2853709ca50faa56ea24 Mon Sep 17 00:00:00 2001 From: Richard Yao Date: Thu, 10 Nov 2022 09:09:35 -0500 Subject: [PATCH 122/126] Cleanup: Suppress Coverity dereference before/after NULL check reports f224eddf922a33ca4b86d83148e9e6fa155fc290 began dereferencing a NULL checked pointer in zpl_vap_init(), which made Coverity complain because either the dereference is unsafe or the NULL check is unnecessary. Upon inspection, this pointer is guaranteed to never be NULL because it is from the Linux kernel VFS. The calls into ZFS simply would not make sense if this pointer were NULL, so the NULL check is unnecessary. Reported-by: Coverity (CID 1527260) Reported-by: Coverity (CID 1527262) Reviewed-by: Mariusz Zaborski Reviewed-by: Youzhong Yang Signed-off-by: Richard Yao Closes #14170 --- module/os/linux/zfs/zpl_inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 6f4718f7d528..93eae7201506 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -121,7 +121,7 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr, vap->va_uid = zfs_vfsuid_to_uid((struct user_namespace *)mnt_ns, zfs_i_user_ns(dir), crgetuid(cr)); - if (dir && dir->i_mode & S_ISGID) { + if (dir->i_mode & S_ISGID) { vap->va_gid = KGID_TO_SGID(dir->i_gid); if (S_ISDIR(mode)) vap->va_mode |= S_ISGID; From e9ab9e512c277ce3c22208599ebe5814db41a036 Mon Sep 17 00:00:00 2001 From: John Wren Kennedy Date: Thu, 10 Nov 2022 15:00:04 -0700 Subject: [PATCH 123/126] ZTS: random_readwrite test doesn't run correctly This test uses fio's bssplit mechanism to choose io sizes for the test, leaving the PERF_IOSIZES variable empty. Because that variable is empty, the innermost loop in do_fio_run_impl is never executed, and as a result, this test does the setup but collects no data. Setting the variable to "bssplit" allows performance data to be gathered. Reviewed-by: Tony Nguyen Signed-off-by: John Wren Kennedy Closes #14163 --- tests/zfs-tests/tests/perf/regression/random_readwrite.ksh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh b/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh index 3a358774f565..e0626c0b42f3 100755 --- a/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh +++ b/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh @@ -60,7 +60,7 @@ export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2)) # Variables specific to this test for use by fio. export PERF_NTHREADS=${PERF_NTHREADS:-'32 64'} export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'} -export PERF_IOSIZES='' # bssplit used instead +export PERF_IOSIZES='bssplit' # bssplit used instead of fixed sizes export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'} # Layout the files to be used by the readwrite tests. Create as many files From 9f4ede63d23be4f43ba8dd0ca42c6a773a8eaa8d Mon Sep 17 00:00:00 2001 From: Paul Dagnelie Date: Thu, 10 Nov 2022 15:23:46 -0800 Subject: [PATCH 124/126] Add ability to recompress send streams with new compression algorithm As new compression algorithms are added to ZFS, it could be useful for people to recompress data with new algorithms. There is currently no mechanism to do this aside from copying the data manually into a new filesystem with the new algorithm enabled. This tool allows the transformation to happen through zfs send, allowing it to be done efficiently to remote systems and in an incremental fashion. A new zstream command is added that decompresses WRITE records and then recompresses them with a provided algorithm, and then re-emits the modified send stream. It may also be possible to re-compress embedded block pointers, but that was not attempted for the initial version. Reviewed-by: Brian Behlendorf Reviewed-by: Matthew Ahrens Signed-off-by: Paul Dagnelie Closes #14106 --- cmd/zstream/Makefile.am | 1 + cmd/zstream/zstream.c | 4 + cmd/zstream/zstream.h | 1 + cmd/zstream/zstream_recompress.c | 356 ++++++++++++++++++ man/man8/zstream.8 | 25 ++ tests/runfiles/common.run | 12 +- .../rsend/send-c_zstream_recompress.ksh | 58 +++ 7 files changed, 451 insertions(+), 6 deletions(-) create mode 100644 cmd/zstream/zstream_recompress.c create mode 100755 tests/zfs-tests/tests/functional/rsend/send-c_zstream_recompress.ksh diff --git a/cmd/zstream/Makefile.am b/cmd/zstream/Makefile.am index 9ae33179e5d6..8506b351165e 100644 --- a/cmd/zstream/Makefile.am +++ b/cmd/zstream/Makefile.am @@ -6,6 +6,7 @@ zstream_SOURCES = \ %D%/zstream.h \ %D%/zstream_decompress.c \ %D%/zstream_dump.c \ + %D%/zstream_recompress.c \ %D%/zstream_redup.c \ %D%/zstream_token.c diff --git a/cmd/zstream/zstream.c b/cmd/zstream/zstream.c index eeceba2475ca..b1509c1f29ea 100644 --- a/cmd/zstream/zstream.c +++ b/cmd/zstream/zstream.c @@ -42,6 +42,8 @@ zstream_usage(void) "\n" "\tzstream decompress [-v] [OBJECT,OFFSET[,TYPE]] ...\n" "\n" + "\tzstream recompress [ -l level] TYPE\n" + "\n" "\tzstream token resume_token\n" "\n" "\tzstream redup [-v] FILE | ...\n"); @@ -65,6 +67,8 @@ main(int argc, char *argv[]) return (zstream_do_dump(argc - 1, argv + 1)); } else if (strcmp(subcommand, "decompress") == 0) { return (zstream_do_decompress(argc - 1, argv + 1)); + } else if (strcmp(subcommand, "recompress") == 0) { + return (zstream_do_recompress(argc - 1, argv + 1)); } else if (strcmp(subcommand, "token") == 0) { return (zstream_do_token(argc - 1, argv + 1)); } else if (strcmp(subcommand, "redup") == 0) { diff --git a/cmd/zstream/zstream.h b/cmd/zstream/zstream.h index 931d4e13fec0..f629a6cdfbab 100644 --- a/cmd/zstream/zstream.h +++ b/cmd/zstream/zstream.h @@ -30,6 +30,7 @@ extern void *safe_malloc(size_t size); extern int zstream_do_redup(int, char *[]); extern int zstream_do_dump(int, char *[]); extern int zstream_do_decompress(int argc, char *argv[]); +extern int zstream_do_recompress(int argc, char *argv[]); extern int zstream_do_token(int, char *[]); extern void zstream_usage(void); diff --git a/cmd/zstream/zstream_recompress.c b/cmd/zstream/zstream_recompress.c new file mode 100644 index 000000000000..b7370587fc6a --- /dev/null +++ b/cmd/zstream/zstream_recompress.c @@ -0,0 +1,356 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2022 Axcient. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright (c) 2022 by Delphix. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "zfs_fletcher.h" +#include "zstream.h" + +static int +dump_record(dmu_replay_record_t *drr, void *payload, int payload_len, + zio_cksum_t *zc, int outfd) +{ + assert(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum) + == sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t)); + fletcher_4_incremental_native(drr, + offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc); + if (drr->drr_type != DRR_BEGIN) { + assert(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u. + drr_checksum.drr_checksum)); + drr->drr_u.drr_checksum.drr_checksum = *zc; + } + fletcher_4_incremental_native(&drr->drr_u.drr_checksum.drr_checksum, + sizeof (zio_cksum_t), zc); + if (write(outfd, drr, sizeof (*drr)) == -1) + return (errno); + if (payload_len != 0) { + fletcher_4_incremental_native(payload, payload_len, zc); + if (write(outfd, payload, payload_len) == -1) + return (errno); + } + return (0); +} + +int +zstream_do_recompress(int argc, char *argv[]) +{ + int bufsz = SPA_MAXBLOCKSIZE; + char *buf = safe_malloc(bufsz); + dmu_replay_record_t thedrr; + dmu_replay_record_t *drr = &thedrr; + zio_cksum_t stream_cksum; + int c; + int level = -1; + + while ((c = getopt(argc, argv, "l:")) != -1) { + switch (c) { + case 'l': + if (sscanf(optarg, "%d", &level) != 0) { + fprintf(stderr, + "failed to parse level '%s'\n", + optarg); + zstream_usage(); + } + break; + case '?': + (void) fprintf(stderr, "invalid option '%c'\n", + optopt); + zstream_usage(); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc != 1) + zstream_usage(); + int type = 0; + zio_compress_info_t *cinfo = NULL; + if (0 == strcmp(argv[0], "off")) { + type = ZIO_COMPRESS_OFF; + cinfo = &zio_compress_table[type]; + } else if (0 == strcmp(argv[0], "inherit") || + 0 == strcmp(argv[0], "empty") || + 0 == strcmp(argv[0], "on")) { + // Fall through to invalid compression type case + } else { + for (int i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) { + if (0 == strcmp(zio_compress_table[i].ci_name, + argv[0])) { + cinfo = &zio_compress_table[i]; + type = i; + break; + } + } + } + if (cinfo == NULL) { + fprintf(stderr, "Invalid compression type %s.\n", + argv[0]); + exit(2); + } + + if (cinfo->ci_compress == NULL) { + type = 0; + cinfo = &zio_compress_table[0]; + } + + if (isatty(STDIN_FILENO)) { + (void) fprintf(stderr, + "Error: The send stream is a binary format " + "and can not be read from a\n" + "terminal. Standard input must be redirected.\n"); + exit(1); + } + + fletcher_4_init(); + zio_init(); + zstd_init(); + while (sfread(drr, sizeof (*drr), stdin) != 0) { + struct drr_write *drrw; + uint64_t payload_size = 0; + + /* + * We need to regenerate the checksum. + */ + if (drr->drr_type != DRR_BEGIN) { + memset(&drr->drr_u.drr_checksum.drr_checksum, 0, + sizeof (drr->drr_u.drr_checksum.drr_checksum)); + } + + + switch (drr->drr_type) { + case DRR_BEGIN: + { + ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0); + + int sz = drr->drr_payloadlen; + if (sz != 0) { + if (sz > bufsz) { + buf = realloc(buf, sz); + if (buf == NULL) + err(1, "realloc"); + bufsz = sz; + } + (void) sfread(buf, sz, stdin); + } + payload_size = sz; + break; + } + case DRR_END: + { + struct drr_end *drre = &drr->drr_u.drr_end; + /* + * Use the recalculated checksum, unless this is + * the END record of a stream package, which has + * no checksum. + */ + if (!ZIO_CHECKSUM_IS_ZERO(&drre->drr_checksum)) + drre->drr_checksum = stream_cksum; + break; + } + + case DRR_OBJECT: + { + struct drr_object *drro = &drr->drr_u.drr_object; + + if (drro->drr_bonuslen > 0) { + payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro); + (void) sfread(buf, payload_size, stdin); + } + break; + } + + case DRR_SPILL: + { + struct drr_spill *drrs = &drr->drr_u.drr_spill; + payload_size = DRR_SPILL_PAYLOAD_SIZE(drrs); + (void) sfread(buf, payload_size, stdin); + break; + } + + case DRR_WRITE_BYREF: + fprintf(stderr, + "Deduplicated streams are not supported\n"); + exit(1); + break; + + case DRR_WRITE: + { + drrw = &thedrr.drr_u.drr_write; + payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw); + /* + * In order to recompress an encrypted block, you have + * to decrypt, decompress, recompress, and + * re-encrypt. That can be a future enhancement (along + * with decryption or re-encryption), but for now we + * skip encrypted blocks. + */ + boolean_t encrypted = B_FALSE; + for (int i = 0; i < ZIO_DATA_SALT_LEN; i++) { + if (drrw->drr_salt[i] != 0) { + encrypted = B_TRUE; + break; + } + } + if (encrypted) { + (void) sfread(buf, payload_size, stdin); + break; + } + if (drrw->drr_compressiontype >= + ZIO_COMPRESS_FUNCTIONS) { + fprintf(stderr, "Invalid compression type in " + "stream: %d\n", drrw->drr_compressiontype); + exit(3); + } + zio_compress_info_t *dinfo = + &zio_compress_table[drrw->drr_compressiontype]; + + /* Set up buffers to minimize memcpys */ + char *cbuf, *dbuf; + if (cinfo->ci_compress == NULL) + dbuf = buf; + else + dbuf = safe_calloc(bufsz); + + if (dinfo->ci_decompress == NULL) + cbuf = dbuf; + else + cbuf = safe_calloc(payload_size); + + /* Read and decompress the payload */ + (void) sfread(cbuf, payload_size, stdin); + if (dinfo->ci_decompress != NULL) { + if (0 != dinfo->ci_decompress(cbuf, dbuf, + payload_size, MIN(bufsz, + drrw->drr_logical_size), dinfo->ci_level)) { + warnx("decompression type %d failed " + "for ino %llu offset %llu", + type, + (u_longlong_t)drrw->drr_object, + (u_longlong_t)drrw->drr_offset); + exit(4); + } + payload_size = drrw->drr_logical_size; + free(cbuf); + } + + /* Recompress the payload */ + if (cinfo->ci_compress != NULL) { + payload_size = P2ROUNDUP(cinfo->ci_compress( + dbuf, buf, drrw->drr_logical_size, + MIN(payload_size, bufsz), (level == -1 ? + cinfo->ci_level : level)), + SPA_MINBLOCKSIZE); + if (payload_size != drrw->drr_logical_size) { + drrw->drr_compressiontype = type; + drrw->drr_compressed_size = + payload_size; + } else { + memcpy(buf, dbuf, payload_size); + drrw->drr_compressiontype = 0; + drrw->drr_compressed_size = 0; + } + free(dbuf); + } else { + drrw->drr_compressiontype = type; + drrw->drr_compressed_size = 0; + } + break; + } + + case DRR_WRITE_EMBEDDED: + { + struct drr_write_embedded *drrwe = + &drr->drr_u.drr_write_embedded; + payload_size = + P2ROUNDUP((uint64_t)drrwe->drr_psize, 8); + (void) sfread(buf, payload_size, stdin); + break; + } + + case DRR_FREEOBJECTS: + case DRR_FREE: + case DRR_OBJECT_RANGE: + break; + + default: + (void) fprintf(stderr, "INVALID record type 0x%x\n", + drr->drr_type); + /* should never happen, so assert */ + assert(B_FALSE); + } + + if (feof(stdout)) { + fprintf(stderr, "Error: unexpected end-of-file\n"); + exit(1); + } + if (ferror(stdout)) { + fprintf(stderr, "Error while reading file: %s\n", + strerror(errno)); + exit(1); + } + + /* + * We need to recalculate the checksum, and it needs to be + * initially zero to do that. BEGIN records don't have + * a checksum. + */ + if (drr->drr_type != DRR_BEGIN) { + memset(&drr->drr_u.drr_checksum.drr_checksum, 0, + sizeof (drr->drr_u.drr_checksum.drr_checksum)); + } + if (dump_record(drr, buf, payload_size, + &stream_cksum, STDOUT_FILENO) != 0) + break; + if (drr->drr_type == DRR_END) { + /* + * Typically the END record is either the last + * thing in the stream, or it is followed + * by a BEGIN record (which also zeros the checksum). + * However, a stream package ends with two END + * records. The last END record's checksum starts + * from zero. + */ + ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0); + } + } + free(buf); + fletcher_4_fini(); + zio_fini(); + zstd_fini(); + + return (0); +} diff --git a/man/man8/zstream.8 b/man/man8/zstream.8 index bfe7ac3f6535..c09a20ad20b6 100644 --- a/man/man8/zstream.8 +++ b/man/man8/zstream.8 @@ -43,6 +43,10 @@ .Nm .Cm token .Ar resume_token +.Nm +.Cm recompress +.Op Fl l Ar level +.Ar algorithm . .Sh DESCRIPTION The @@ -149,6 +153,27 @@ Therefore, a deduplicated send stream can be received by running: Verbose. Print summary of converted records. .El +.It Xo +.Nm +.Cm recompress +.Op Fl l Ar level +.Ar algorithm +.Xc +Recompresses a send stream, provided on standard input, using the provided +algorithm and optional level, and writes the modified stream to standard output. +All WRITE records in the send stream will be recompressed, unless they fail +to result in size reduction compared to being left uncompressed. +The provided algorithm can be any valid value to the +.Nm compress +property. +Note that encrypted send streams cannot be recompressed. +.Bl -tag -width "-l" +.It Fl l Ar level +Specifies compression level. +Only needed for algorithms where the level is not implied as part of the name +of the algorithm (e.g. gzip-3 does not require it, while zstd does, if a +non-default level is desired). +.El .El . .Sh EXAMPLES diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 65b64f4fa8cd..323c37a3d17a 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -838,12 +838,12 @@ tests = ['recv_dedup', 'recv_dedup_encrypted_zvol', 'rsend_001_pos', 'rsend_026_neg', 'rsend_027_pos', 'rsend_028_neg', 'rsend_029_neg', 'rsend_030_pos', 'send-c_verify_ratio', 'send-c_verify_contents', 'send-c_props', 'send-c_incremental', 'send-c_volume', - 'send-c_zstreamdump', 'send-c_lz4_disabled', 'send-c_recv_lz4_disabled', - 'send-c_mixed_compression', 'send-c_stream_size_estimate', - 'send-c_embedded_blocks', 'send-c_resume', 'send-cpL_varied_recsize', - 'send-c_recv_dedup', 'send-L_toggle', 'send_encrypted_hierarchy', - 'send_encrypted_props', 'send_encrypted_truncated_files', - 'send_freeobjects', 'send_realloc_files', + 'send-c_zstream_recompress', 'send-c_zstreamdump', 'send-c_lz4_disabled', + 'send-c_recv_lz4_disabled', 'send-c_mixed_compression', + 'send-c_stream_size_estimate', 'send-c_embedded_blocks', 'send-c_resume', + 'send-cpL_varied_recsize', 'send-c_recv_dedup', 'send-L_toggle', + 'send_encrypted_hierarchy', 'send_encrypted_props', + 'send_encrypted_truncated_files', 'send_freeobjects', 'send_realloc_files', 'send_realloc_encrypted_files', 'send_spill_block', 'send_holds', 'send_hole_birth', 'send_mixed_raw', 'send-wR_encrypted_zvol', 'send_partial_dataset', 'send_invalid', 'send_doall', diff --git a/tests/zfs-tests/tests/functional/rsend/send-c_zstream_recompress.ksh b/tests/zfs-tests/tests/functional/rsend/send-c_zstream_recompress.ksh new file mode 100755 index 000000000000..dd2a7d02a261 --- /dev/null +++ b/tests/zfs-tests/tests/functional/rsend/send-c_zstream_recompress.ksh @@ -0,0 +1,58 @@ +#!/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 (c) 2022 by Delphix. All rights reserved. +# + +. $STF_SUITE/tests/functional/rsend/rsend.kshlib +. $STF_SUITE/include/math.shlib + +# +# Description: +# Verify compression features show up in zstream dump +# +# Strategy: +# 1. Create a compressed send stream +# 2. Recompress the stream with a different algorithm +# 3. Verify it can be received correctly +# 4. Verify the contents match the original filesystem +# 5. Create an uncompressed send stream +# 6. Compress the send stream +# 7. Verify that the stream is smaller when compressed +# + +verify_runnable "both" + +log_assert "Verify zstream recompress correctly modifies send streams." +log_onexit cleanup_pool $POOL2 + +typeset sendfs=$POOL2/fs +typeset recvfs=$POOL2/fs2 + +log_must zfs create -o compress=lz4 $sendfs +typeset dir=$(get_prop mountpoint $sendfs) +write_compressible $dir 16m +log_must zfs snapshot $sendfs@snap + +log_must eval "zfs send -c $sendfs@snap | zstream recompress gzip-1 | zfs recv $recvfs" +typeset recvdir=$(get_prop mountpoint $recvfs) +log_must diff -r $dir $recvdir + +log_must eval "zfs send $sendfs@snap >$BACKDIR/uncompressed" +log_must zstream recompress gzip-1 <$BACKDIR/uncompressed >$BACKDIR/compressed +typeset uncomp_size=$(wc -c $BACKDIR/uncompressed | awk '{print $1}') +typeset comp_size=$(wc -c $BACKDIR/compressed | awk '{print $1}') +[[ "$uncomp_size" -gt "$comp_size" ]] || log_fail "recompressed stream was not smaller" + +log_pass "zstream recompress correctly modifies send streams." From b445b25b273d263f032fadd717e5731185b74bf5 Mon Sep 17 00:00:00 2001 From: shodanshok Date: Fri, 11 Nov 2022 19:41:36 +0100 Subject: [PATCH 125/126] Fix arc_p aggressive increase The original ARC paper called for an initial 50/50 MRU/MFU split and this is accounted in various places where arc_p = arc_c >> 1, with further adjustment based on ghost lists size/hit. However, in current code both arc_adapt() and arc_get_data_impl() aggressively grow arc_p until arc_c is reached, causing unneeded pressure on MFU and greatly reducing its scan-resistance until ghost list adjustments kick in. This patch restores the original behavior of initially having arc_p as 1/2 of total ARC, without preventing MRU to use up to 100% total ARC when MFU is empty. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Gionatan Danti Closes #14137 Closes #14120 --- module/zfs/arc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 1f97631f974f..f51f427c1bfd 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -5173,7 +5173,7 @@ arc_adapt(int bytes, arc_state_t *state) atomic_add_64(&arc_c, (int64_t)bytes); if (arc_c > arc_c_max) arc_c = arc_c_max; - else if (state == arc_anon) + else if (state == arc_anon && arc_p < arc_c >> 1) atomic_add_64(&arc_p, (int64_t)bytes); if (arc_p > arc_c) arc_p = arc_c; @@ -5386,7 +5386,8 @@ arc_get_data_impl(arc_buf_hdr_t *hdr, uint64_t size, const void *tag, if (aggsum_upper_bound(&arc_sums.arcstat_size) < arc_c && hdr->b_l1hdr.b_state == arc_anon && (zfs_refcount_count(&arc_anon->arcs_size) + - zfs_refcount_count(&arc_mru->arcs_size) > arc_p)) + zfs_refcount_count(&arc_mru->arcs_size) > arc_p && + arc_p < arc_c >> 1)) arc_p = MIN(arc_c, arc_p + size); } } From 2163cde450d0898b5f7bac16afb4e238485411ff Mon Sep 17 00:00:00 2001 From: Rich Ercolani <214141+rincebrain@users.noreply.github.com> Date: Tue, 15 Nov 2022 17:44:12 -0500 Subject: [PATCH 126/126] Handle and detect #13709's unlock regression (#14161) In #13709, as in #11294 before it, it turns out that 63a26454 still had the same failure mode as when it was first landed as d1d47691, and fails to unlock certain datasets that formerly worked. Rather than reverting it again, let's add handling to just throw out the accounting metadata that failed to unlock when that happens, as well as a test with a pre-broken pool image to ensure that we never get bitten by this again. Fixes: #13709 Signed-off-by: Rich Ercolani Reviewed-by: Brian Behlendorf Reviewed-by: Tony Hutter --- module/zfs/dsl_crypt.c | 18 ++++++- tests/runfiles/common.run | 2 +- tests/zfs-tests/tests/Makefile.am | 2 + .../functional/userquota/13709_reproducer.bz2 | Bin 0 -> 135829 bytes .../userquota/userspace_encrypted_13709.ksh | 45 ++++++++++++++++++ 5 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tests/zfs-tests/tests/functional/userquota/13709_reproducer.bz2 create mode 100755 tests/zfs-tests/tests/functional/userquota/userspace_encrypted_13709.ksh diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c index ce2e6ce742a2..382de208b01d 100644 --- a/module/zfs/dsl_crypt.c +++ b/module/zfs/dsl_crypt.c @@ -2671,6 +2671,7 @@ spa_do_crypt_objset_mac_abd(boolean_t generate, spa_t *spa, uint64_t dsobj, objset_phys_t *osp = buf; uint8_t portable_mac[ZIO_OBJSET_MAC_LEN]; uint8_t local_mac[ZIO_OBJSET_MAC_LEN]; + const uint8_t zeroed_mac[ZIO_OBJSET_MAC_LEN] = {0}; /* look up the key from the spa's keystore */ ret = spa_keystore_lookup_key(spa, dsobj, FTAG, &dck); @@ -2696,8 +2697,21 @@ spa_do_crypt_objset_mac_abd(boolean_t generate, spa_t *spa, uint64_t dsobj, if (memcmp(portable_mac, osp->os_portable_mac, ZIO_OBJSET_MAC_LEN) != 0 || memcmp(local_mac, osp->os_local_mac, ZIO_OBJSET_MAC_LEN) != 0) { - abd_return_buf(abd, buf, datalen); - return (SET_ERROR(ECKSUM)); + /* + * If the MAC is zeroed out, we failed to decrypt it. + * This should only arise, at least on Linux, + * if we hit edge case handling for useraccounting, since we + * shouldn't get here without bailing out on error earlier + * otherwise. + * + * So if we're in that case, we can just fall through and + * special-casing noticing that it's zero will handle it + * elsewhere, since we can just regenerate it. + */ + if (memcmp(local_mac, zeroed_mac, ZIO_OBJSET_MAC_LEN) != 0) { + abd_return_buf(abd, buf, datalen); + return (SET_ERROR(ECKSUM)); + } } abd_return_buf(abd, buf, datalen); diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 323c37a3d17a..73ca69993149 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -911,7 +911,7 @@ tests = [ 'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos', 'userquota_010_pos', 'userquota_011_pos', 'userquota_012_neg', 'userspace_001_pos', 'userspace_002_pos', 'userspace_encrypted', - 'userspace_send_encrypted'] + 'userspace_send_encrypted', 'userspace_encrypted_13709'] tags = ['functional', 'userquota'] [tests/functional/vdev_zaps] diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 5b8458b73180..39eb44f73171 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -368,6 +368,7 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \ functional/upgrade/upgrade_common.kshlib \ functional/user_namespace/user_namespace.cfg \ functional/user_namespace/user_namespace_common.kshlib \ + functional/userquota/13709_reproducer.bz2 \ functional/userquota/userquota.cfg \ functional/userquota/userquota_common.kshlib \ functional/vdev_zaps/vdev_zaps.kshlib \ @@ -1935,6 +1936,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/userquota/userspace_003_pos.ksh \ functional/userquota/userspace_encrypted.ksh \ functional/userquota/userspace_send_encrypted.ksh \ + functional/userquota/userspace_encrypted_13709.ksh \ functional/vdev_zaps/cleanup.ksh \ functional/vdev_zaps/setup.ksh \ functional/vdev_zaps/vdev_zaps_001_pos.ksh \ diff --git a/tests/zfs-tests/tests/functional/userquota/13709_reproducer.bz2 b/tests/zfs-tests/tests/functional/userquota/13709_reproducer.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..9c31682794616688b758dcfd3b01530b6270f4fa GIT binary patch literal 135829 zcmagFcUV(P*Ek9YNJ0@pLKP*OBoLZ0(nRz~2oOSOp*JNOkS<6Q)FUOqgeD0ggeoQU zB2q*F6#^;&R0u@@u^^%-7Q}L_=jQ!=@BQu{_dd^E`+4?Wd(E0PGka#w%qoKm2;aZg z)*t2R|0A*@Q9@pH{@?#Ucz)-v-Nb5+6im`f8f+jXQ4ir85CA68+d!8nV{h1ul!6hI ziA}^>PQ5n-j078cOCOf@Dh3E_1e?HV@&;tc_$EHP#Q;J}*KKN6CJ?NQE618B27n*1w zl@6AW)RmAVNJvRYLDCHh!4gvG)zuP`_L8;|5)yJ!g-srZCF-SE5>N?usdO<(Hyte1 zBvCCPA$b_w3{}o?2MnZI(iu|eP%%Nm)*W_OM$9D!De3=titp}{x598F(oP zhIG1wgp9aC{{eAf%I*>dXv6gX)=vWbf9Mht2GZpJViNBEMN}ljBL4&beMm@D|Cjs! zG)XQ45+cEq0Hy!$`~MpOVI)Wr(nJ66g#U+9PoT+3z#Gz~XGjh% zSc&OsMcFJMgf|7MBT4d)g_TL5#C0Ie3LB)y1k@Q4&l5|XvzZ#D&e%DWX@O_tl? zWHE7O=cl3vdzF2msO95fkJX~{78R=6%gc=y%QW{`vF zq*^?KlLPUK_iB`RA$aIoPk<^*s%Jkrp~PveIH@HOn(8^8av2Y-DYq z6o*N@g5?o-2ojrxbw&dCF1)}4Q)V_^_QzQj|JN^U!npX`})=Jev;WIxGo7UCzeBPe6x5<~ks6v<>Zst~#_`k1q{{tz*V8~SFT=YX zp7&ZlKUOcYC`&Ou6Z?gX9pg9r8XC5e)xbE|fse~*gitcFW#tu68iuQW+YRrr8}ED2 zUH)zPb98Iny6WQm+c~4y4+X0F4zCsl?VP<$J-?kYyxjlf(Az<4S+?(a3V46jmq!-M zbz8mCjj`t^cKox?=yGQpuUQbX=imMFJKviB^;4?pMn_u{=P`yQcijdII`|c>D{mC? zHq7C~&a)?WCb-xgD?7ZF+hu>akn=z72E=VF;7}g|BTAortHYe@Ftc3|wq@K|_9Pm^ zKoF#pO?wTb7tTY95uHVpOzSQ1o+A&bhM1wUNp+~8IU+=+2#gu~wKDQ0U{_q5c^UXK zX~A&$@}YZSyfjM4TchoLQElb(+~vOW17o|qX;bs6&huCl>ChRbM-eDnHU0DC+#dI# z*(W>;4fUn~4Wl~^l5~<$V%zps_)A;<)4vk^E#E!5QEquv4e}vOJzs--qzvy6htI$V zdxb4vI2$4uqK8aYZs5a7eoW^d_Wp|Q`Fp`F=llo_s^N@xv!m5n4+u2l3GGT(eKySZ zP|EvaYx_2q;y4VZ2{-VlGz?YD#HG8{1CMj9yI#PpdmB~53pcd*{4N7xzo04m%R;Mh zq{yz*t-*8EU*yUUoH_Z<_>0K=^-oAKKLieze^&E2(0 zp{{OjK@pYAgAJ2kl*9k2^TPYXT!D#?4`>|K0>!ll7sf&P2>TFYj=H6yvzdHHb# z;Pljph2%H}c^{)x-N_CL1a14{o2UH>lv45_@L@&3vm0GQ)+coHDmQ*pH}!!pdc^#7 zqQGrXkZ>Z6`tlLA74+jn@>sZEL|nn6$+I#qw&h1xSQMLNWOl@8C@RR(0kjkBSqDBQh|^3ejJu=v3t+?096fWF$WXU>7zDuWU= z^NMmkkLij!-IICdkBF7b%(ok;-z)yAot+i3uy~}k%K0k?RfDmU2�}vCyf5>ajfW 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 $FILEDEV + +log_must zpool import -d $FILEDEV $POOLNAME + +echo -e 'password\npassword\n' | log_must zfs mount -al + +# Cleanup +cleanup + +log_pass "#13709 not happening here"