Notable upstream pull request merges:

#15539 687e4d7f9 Extend import_progress kstat with a notes field
 #15544 c7b611926 Allow block cloning across encrypted datasets
 #15553 adcea23cb ZIO: Add overflow checks for linear buffers
 #15593 5f2700eee zpool: flush output before sleeping
 #15609 3e4bef52b Only provide execvpe(3) when needed
 #15610 735ba3a7b Use uint64_t instead of u_int64_t
 #15612 bcd83ccd2 ZIL: Remove TX_CLONE_RANGE replay for ZVOLs
 #15617 55b764e06 ZIL: Do not clone blocks from the future
 #15623 727497ccd module/icp/asm-arm/sha2: enable non-SIMD asm kernels
                  on armv5/6
 #15625 9743d0963 BRT: Limit brt_vdev_dump() to only one vdev
 #15629 f9765b182 zdb: Dump encrypted write and clone ZIL records
 #15634 2aa3a482a ZIL: Remove 128K into 2x68K LWB split optimization
 #15639 11656234b FreeBSD: Ensure that zfs_getattr() initializes the
                  va_rdev field
 #15647 4836d293c zfs_refcount_remove: explictly ignore returns
 #15649 f0cb6482e setproctitle: fix ununitialised variable
 #15650 450f2d0b0 import: ignore return on hostid lookups

Obtained from:	OpenZFS
OpenZFS commit:	450f2d0b08
This commit is contained in:
Martin Matuska 2023-12-08 09:32:30 +01:00
commit 3494f7c019
42 changed files with 885 additions and 209 deletions

View file

@ -168,7 +168,7 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
(u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
(u_longlong_t)lr->lr_length);
if (txtype == TX_WRITE2 || verbose < 5)
if (txtype == TX_WRITE2 || verbose < 4)
return;
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
@ -178,6 +178,8 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
"will claim" : "won't claim");
print_log_bp(bp, tab_prefix);
if (verbose < 5)
return;
if (BP_IS_HOLE(bp)) {
(void) printf("\t\t\tLSIZE 0x%llx\n",
(u_longlong_t)BP_GET_LSIZE(bp));
@ -202,6 +204,9 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
if (error)
goto out;
} else {
if (verbose < 5)
return;
/* data is stored after the end of the lr_write record */
data = abd_alloc(lr->lr_length, B_FALSE);
abd_copy_from_buf(data, lr + 1, lr->lr_length);
@ -217,6 +222,28 @@ zil_prt_rec_write(zilog_t *zilog, int txtype, const void *arg)
abd_free(data);
}
static void
zil_prt_rec_write_enc(zilog_t *zilog, int txtype, const void *arg)
{
(void) txtype;
const lr_write_t *lr = arg;
const blkptr_t *bp = &lr->lr_blkptr;
int verbose = MAX(dump_opt['d'], dump_opt['i']);
(void) printf("%s(encrypted)\n", tab_prefix);
if (verbose < 4)
return;
if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
(void) printf("%shas blkptr, %s\n", tab_prefix,
!BP_IS_HOLE(bp) &&
bp->blk_birth >= spa_min_claim_txg(zilog->zl_spa) ?
"will claim" : "won't claim");
print_log_bp(bp, tab_prefix);
}
}
static void
zil_prt_rec_truncate(zilog_t *zilog, int txtype, const void *arg)
{
@ -312,11 +339,34 @@ zil_prt_rec_clone_range(zilog_t *zilog, int txtype, const void *arg)
{
(void) zilog, (void) txtype;
const lr_clone_range_t *lr = arg;
int verbose = MAX(dump_opt['d'], dump_opt['i']);
(void) printf("%sfoid %llu, offset %llx, length %llx, blksize %llx\n",
tab_prefix, (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
(u_longlong_t)lr->lr_length, (u_longlong_t)lr->lr_blksz);
if (verbose < 4)
return;
for (unsigned int i = 0; i < lr->lr_nbps; i++) {
(void) printf("%s[%u/%llu] ", tab_prefix, i + 1,
(u_longlong_t)lr->lr_nbps);
print_log_bp(&lr->lr_bps[i], "");
}
}
static void
zil_prt_rec_clone_range_enc(zilog_t *zilog, int txtype, const void *arg)
{
(void) zilog, (void) txtype;
const lr_clone_range_t *lr = arg;
int verbose = MAX(dump_opt['d'], dump_opt['i']);
(void) printf("%s(encrypted)\n", tab_prefix);
if (verbose < 4)
return;
for (unsigned int i = 0; i < lr->lr_nbps; i++) {
(void) printf("%s[%u/%llu] ", tab_prefix, i + 1,
(u_longlong_t)lr->lr_nbps);
@ -327,6 +377,7 @@ zil_prt_rec_clone_range(zilog_t *zilog, int txtype, const void *arg)
typedef void (*zil_prt_rec_func_t)(zilog_t *, int, const void *);
typedef struct zil_rec_info {
zil_prt_rec_func_t zri_print;
zil_prt_rec_func_t zri_print_enc;
const char *zri_name;
uint64_t zri_count;
} zil_rec_info_t;
@ -341,7 +392,9 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
{.zri_print = zil_prt_rec_remove, .zri_name = "TX_RMDIR "},
{.zri_print = zil_prt_rec_link, .zri_name = "TX_LINK "},
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME "},
{.zri_print = zil_prt_rec_write, .zri_name = "TX_WRITE "},
{.zri_print = zil_prt_rec_write,
.zri_print_enc = zil_prt_rec_write_enc,
.zri_name = "TX_WRITE "},
{.zri_print = zil_prt_rec_truncate, .zri_name = "TX_TRUNCATE "},
{.zri_print = zil_prt_rec_setattr, .zri_name = "TX_SETATTR "},
{.zri_print = zil_prt_rec_acl, .zri_name = "TX_ACL_V0 "},
@ -358,6 +411,7 @@ static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_EXCHANGE "},
{.zri_print = zil_prt_rec_rename, .zri_name = "TX_RENAME_WHITEOUT "},
{.zri_print = zil_prt_rec_clone_range,
.zri_print_enc = zil_prt_rec_clone_range_enc,
.zri_name = "TX_CLONE_RANGE "},
};
@ -384,6 +438,8 @@ print_log_record(zilog_t *zilog, const lr_t *lr, void *arg, uint64_t claim_txg)
if (txtype && verbose >= 3) {
if (!zilog->zl_os->os_encrypted) {
zil_rec_info[txtype].zri_print(zilog, txtype, lr);
} else if (zil_rec_info[txtype].zri_print_enc) {
zil_rec_info[txtype].zri_print_enc(zilog, txtype, lr);
} else {
(void) printf("%s(encrypted)\n", tab_prefix);
}

View file

@ -205,6 +205,10 @@ zed_notify()
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
zed_notify_ntfy "${subject}" "${pathname}"; rv=$?
[ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
[ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
[ "${num_success}" -gt 0 ] && return 0
[ "${num_failure}" -gt 0 ] && return 1
return 2
@ -527,6 +531,100 @@ zed_notify_pushover()
}
# zed_notify_ntfy (subject, pathname)
#
# Send a notification via Ntfy.sh <https://ntfy.sh/>.
# The ntfy topic (ZED_NTFY_TOPIC) identifies the topic that the notification
# will be sent to Ntfy.sh server. The ntfy url (ZED_NTFY_URL) defines the
# self-hosted or provided hosted ntfy service location. The ntfy access token
# <https://docs.ntfy.sh/publish/#access-tokens> (ZED_NTFY_ACCESS_TOKEN) reprsents an
# access token that could be used if a topic is read/write protected. If a
# topic can be written to publicaly, a ZED_NTFY_ACCESS_TOKEN is not required.
#
# Requires curl and sed executables to be installed in the standard PATH.
#
# References
# https://docs.ntfy.sh
#
# Arguments
# subject: notification subject
# pathname: pathname containing the notification message (OPTIONAL)
#
# Globals
# ZED_NTFY_TOPIC
# ZED_NTFY_ACCESS_TOKEN (OPTIONAL)
# ZED_NTFY_URL
#
# Return
# 0: notification sent
# 1: notification failed
# 2: not configured
#
zed_notify_ntfy()
{
local subject="$1"
local pathname="${2:-"/dev/null"}"
local msg_body
local msg_out
local msg_err
[ -n "${ZED_NTFY_TOPIC}" ] || return 2
local url="${ZED_NTFY_URL:-"https://ntfy.sh"}/${ZED_NTFY_TOPIC}"
if [ ! -r "${pathname}" ]; then
zed_log_err "ntfy cannot read \"${pathname}\""
return 1
fi
zed_check_cmd "curl" "sed" || return 1
# Read the message body in.
#
msg_body="$(cat "${pathname}")"
if [ -z "${msg_body}" ]
then
msg_body=$subject
subject=""
fi
# Send the POST request and check for errors.
#
if [ -n "${ZED_NTFY_ACCESS_TOKEN}" ]; then
msg_out="$( \
curl \
-u ":${ZED_NTFY_ACCESS_TOKEN}" \
-H "Title: ${subject}" \
-d "${msg_body}" \
-H "Priority: high" \
"${url}" \
2>/dev/null \
)"; rv=$?
else
msg_out="$( \
curl \
-H "Title: ${subject}" \
-d "${msg_body}" \
-H "Priority: high" \
"${url}" \
2>/dev/null \
)"; rv=$?
fi
if [ "${rv}" -ne 0 ]; then
zed_log_err "curl exit=${rv}"
return 1
fi
msg_err="$(echo "${msg_out}" \
| sed -n -e 's/.*"errors" *:.*\[\(.*\)\].*/\1/p')"
if [ -n "${msg_err}" ]; then
zed_log_err "ntfy \"${msg_err}"\"
return 1
fi
return 0
}
# zed_rate_limit (tag, [interval])
#
# Check whether an event of a given type [tag] has already occurred within the

View file

@ -147,3 +147,25 @@ ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event"
# help silence misbehaving drives. This assumes your drive enclosure fully
# supports slot power control via sysfs.
#ZED_POWER_OFF_ENCLOUSRE_SLOT_ON_FAULT=1
##
# Ntfy topic
# This defines which topic will receive the ntfy notification.
# <https://docs.ntfy.sh/publish/>
# Disabled by default; uncomment to enable.
#ZED_NTFY_TOPIC=""
##
# Ntfy access token (optional for public topics)
# This defines an access token which can be used
# to allow you to authenticate when sending to topics
# <https://docs.ntfy.sh/publish/#access-tokens>
# Disabled by default; uncomment to enable.
#ZED_NTFY_ACCESS_TOKEN=""
##
# Ntfy Service URL
# This defines which service the ntfy call will be directed toward
# <https://docs.ntfy.sh/install/>
# https://ntfy.sh by default; uncomment to enable an alternative service url.
#ZED_NTFY_URL="https://ntfy.sh"

View file

@ -3132,7 +3132,8 @@ zfs_force_import_required(nvlist_t *config)
* local hostid.
*/
if (nvlist_lookup_uint64(nvinfo, ZPOOL_CONFIG_HOSTID, &hostid) != 0)
nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
&hostid);
if (state != POOL_STATE_EXPORTED && hostid != get_system_hostid())
return (B_TRUE);
@ -5950,6 +5951,7 @@ zpool_do_iostat(int argc, char **argv)
print_iostat_header(&cb);
if (skip) {
(void) fflush(stdout);
(void) fsleep(interval);
continue;
}
@ -5980,18 +5982,13 @@ zpool_do_iostat(int argc, char **argv)
}
/*
* Flush the output so that redirection to a file isn't buffered
* indefinitely.
*/
(void) fflush(stdout);
if (interval == 0)
break;
if (count != 0 && --count == 0)
break;
(void) fflush(stdout);
(void) fsleep(interval);
}
@ -6514,6 +6511,8 @@ zpool_do_list(int argc, char **argv)
break;
pool_list_free(list);
(void) fflush(stdout);
(void) fsleep(interval);
}
@ -9094,6 +9093,7 @@ zpool_do_status(int argc, char **argv)
if (count != 0 && --count == 0)
break;
(void) fflush(stdout);
(void) fsleep(interval);
}

View file

@ -1,7 +1,8 @@
dnl #
dnl # Starting from Linux 5.13, flush_dcache_page() becomes an inline
dnl # function and may indirectly referencing GPL-only cpu_feature_keys on
dnl # powerpc
dnl # function and may indirectly referencing GPL-only symbols:
dnl # on powerpc: cpu_feature_keys
dnl # on riscv: PageHuge (added from 6.2)
dnl #
dnl #

View file

@ -168,6 +168,9 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
ZFS_AC_KERNEL_SRC_FLUSH_DCACHE_PAGE
;;
riscv*)
ZFS_AC_KERNEL_SRC_FLUSH_DCACHE_PAGE
;;
esac
AC_MSG_CHECKING([for available kernel interfaces])
@ -310,6 +313,9 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_CPU_HAS_FEATURE
ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE
;;
riscv*)
ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE
;;
esac
])

View file

@ -31,7 +31,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
ZFS_AC_CONFIG_USER_MAKEDEV_IN_MKDEV
ZFS_AC_CONFIG_USER_ZFSEXEC
AC_CHECK_FUNCS([issetugid mlockall strlcat strlcpy])
AC_CHECK_FUNCS([execvpe issetugid mlockall strlcat strlcpy])
AC_SUBST(RM)
])

View file

@ -22,8 +22,6 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _OPENSOLARIS_SYS_TIME_H_
@ -91,6 +89,6 @@ gethrtime(void)
{
struct timespec ts;
clock_gettime(CLOCK_UPTIME, &ts);
return (((u_int64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec);
return (((uint64_t)ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
#endif /* !_OPENSOLARIS_SYS_TIME_H_ */

View file

@ -42,8 +42,8 @@
/*
* Starting from Linux 5.13, flush_dcache_page() becomes an inline function
* and under some configurations, may indirectly referencing GPL-only
* cpu_feature_keys on powerpc. Override this function when it is detected
* being GPL-only.
* symbols, e.g., cpu_feature_keys on powerpc and PageHuge on riscv.
* Override this function when it is detected being GPL-only.
*/
#if defined __powerpc__ && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY
#include <linux/simd_powerpc.h>
@ -53,6 +53,17 @@
clear_bit(PG_dcache_clean, &(page)->flags); \
} while (0)
#endif
/*
* For riscv implementation, the use of PageHuge can be safely removed.
* Because it handles pages allocated by HugeTLB, while flush_dcache_page
* in zfs module is only called on kernel pages.
*/
#if defined __riscv && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY
#define flush_dcache_page(page) do { \
if (test_bit(PG_dcache_clean, &(page)->flags)) \
clear_bit(PG_dcache_clean, &(page)->flags); \
} while (0)
#endif
/*
* 2.6.30 API change,

View file

@ -206,6 +206,7 @@ void dsl_dataset_promote_crypt_sync(dsl_dir_t *target, dsl_dir_t *origin,
dmu_tx_t *tx);
int dmu_objset_create_crypt_check(dsl_dir_t *parentdd,
dsl_crypto_params_t *dcp, boolean_t *will_encrypt);
boolean_t dmu_objset_crypto_key_equal(objset_t *osa, objset_t *osb);
void dsl_dataset_create_crypt_sync(uint64_t dsobj, dsl_dir_t *dd,
struct dsl_dataset *origin, dsl_crypto_params_t *dcp, dmu_tx_t *tx);
uint64_t dsl_crypto_key_create_sync(uint64_t crypt, dsl_wrapping_key_t *wkey,

View file

@ -971,6 +971,10 @@ extern int spa_import_progress_set_max_txg(uint64_t pool_guid,
uint64_t max_txg);
extern int spa_import_progress_set_state(uint64_t pool_guid,
spa_load_state_t spa_load_state);
extern void spa_import_progress_set_notes(spa_t *spa,
const char *fmt, ...) __printflike(2, 3);
extern void spa_import_progress_set_notes_nolog(spa_t *spa,
const char *fmt, ...) __printflike(2, 3);
/* Pool configuration locks */
extern int spa_config_tryenter(spa_t *spa, int locks, const void *tag,

View file

@ -64,6 +64,9 @@ libspl_assert(const char *buf, const char *file, const char *func, int line)
#undef verify
#endif
#define PANIC(fmt, a...) \
libspl_assertf(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
#define VERIFY(cond) \
(void) ((!(cond)) && \
libspl_assert(#cond, __FILE__, __FUNCTION__, __LINE__))

View file

@ -57,6 +57,8 @@
extern size_t spl_pagesize(void);
#define PAGESIZE (spl_pagesize())
#ifndef HAVE_EXECVPE
extern int execvpe(const char *name, char * const argv[], char * const envp[]);
#endif
#endif

View file

@ -101,7 +101,7 @@ gethrtime(void)
{
struct timespec ts;
(void) clock_gettime(CLOCK_MONOTONIC, &ts);
return ((((u_int64_t)ts.tv_sec) * NANOSEC) + ts.tv_nsec);
return ((((uint64_t)ts.tv_sec) * NANOSEC) + ts.tv_nsec);
}
#endif /* _LIBSPL_SYS_TIME_H */

View file

@ -38,7 +38,8 @@
#define ZFS_KMOD "openzfs"
#endif
#ifndef HAVE_EXECVPE
/* FreeBSD prior to 15 lacks execvpe */
static int
execvPe(const char *name, const char *path, char * const *argv,
char * const *envp)
@ -192,6 +193,7 @@ execvpe(const char *name, char * const argv[], char * const envp[])
return (execvPe(name, path, argv, envp));
}
#endif /* !HAVE_EXECVPE */
static __thread char errbuf[ERRBUFLEN];

View file

@ -88,7 +88,7 @@ spt_copyenv(int envc, char *envp[])
char **envcopy;
char *eq;
int envsize;
int i, error;
int i, error = 0;
if (environ != envp)
return (0);

View file

@ -364,9 +364,12 @@ When this feature is enabled ZFS will use block cloning for operations like
Block cloning allows to create multiple references to a single block.
It is much faster than copying the data (as the actual data is neither read nor
written) and takes no additional space.
Blocks can be cloned across datasets under some conditions (like disabled
encryption and equal
.Nm recordsize ) .
Blocks can be cloned across datasets under some conditions (like equal
.Nm recordsize ,
the same master encryption key, etc.).
ZFS tries its best to clone across datasets including encrypted ones.
This is limited for various (nontrivial) reasons depending on the OS
and/or ZFS internals.
.Pp
This feature becomes
.Sy active

View file

@ -118,7 +118,15 @@ const sha256_ops_t sha256_shani_impl = {
};
#endif
#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH > 6)
#elif defined(__aarch64__) || defined(__arm__)
extern void zfs_sha256_block_armv7(uint32_t s[8], const void *, size_t);
const sha256_ops_t sha256_armv7_impl = {
.is_supported = sha2_is_supported,
.transform = zfs_sha256_block_armv7,
.name = "armv7"
};
#if __ARM_ARCH > 6
static boolean_t sha256_have_neon(void)
{
return (kfpu_allowed() && zfs_neon_available());
@ -129,13 +137,6 @@ static boolean_t sha256_have_armv8ce(void)
return (kfpu_allowed() && zfs_sha256_available());
}
extern void zfs_sha256_block_armv7(uint32_t s[8], const void *, size_t);
const sha256_ops_t sha256_armv7_impl = {
.is_supported = sha2_is_supported,
.transform = zfs_sha256_block_armv7,
.name = "armv7"
};
TF(zfs_sha256_block_neon, tf_sha256_neon);
const sha256_ops_t sha256_neon_impl = {
.is_supported = sha256_have_neon,
@ -149,6 +150,7 @@ const sha256_ops_t sha256_armv8_impl = {
.transform = tf_sha256_armv8ce,
.name = "armv8-ce"
};
#endif
#elif defined(__PPC64__)
static boolean_t sha256_have_isa207(void)
@ -192,11 +194,13 @@ static const sha256_ops_t *const sha256_impls[] = {
#if defined(__x86_64) && defined(HAVE_SSE4_1)
&sha256_shani_impl,
#endif
#if defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH > 6)
#if defined(__aarch64__) || defined(__arm__)
&sha256_armv7_impl,
#if __ARM_ARCH > 6
&sha256_neon_impl,
&sha256_armv8_impl,
#endif
#endif
#if defined(__PPC64__)
&sha256_ppc_impl,
&sha256_power8_impl,

View file

@ -88,7 +88,7 @@ const sha512_ops_t sha512_avx2_impl = {
};
#endif
#elif defined(__aarch64__)
#elif defined(__aarch64__) || defined(__arm__)
extern void zfs_sha512_block_armv7(uint64_t s[8], const void *, size_t);
const sha512_ops_t sha512_armv7_impl = {
.is_supported = sha2_is_supported,
@ -96,6 +96,7 @@ const sha512_ops_t sha512_armv7_impl = {
.name = "armv7"
};
#if defined(__aarch64__)
static boolean_t sha512_have_armv8ce(void)
{
return (kfpu_allowed() && zfs_sha512_available());
@ -107,15 +108,9 @@ const sha512_ops_t sha512_armv8_impl = {
.transform = tf_sha512_armv8ce,
.name = "armv8-ce"
};
#endif
#elif defined(__arm__) && __ARM_ARCH > 6
extern void zfs_sha512_block_armv7(uint64_t s[8], const void *, size_t);
const sha512_ops_t sha512_armv7_impl = {
.is_supported = sha2_is_supported,
.transform = zfs_sha512_block_armv7,
.name = "armv7"
};
#if defined(__arm__) && __ARM_ARCH > 6
static boolean_t sha512_have_neon(void)
{
return (kfpu_allowed() && zfs_neon_available());
@ -127,6 +122,7 @@ const sha512_ops_t sha512_neon_impl = {
.transform = tf_sha512_neon,
.name = "neon"
};
#endif
#elif defined(__PPC64__)
TF(zfs_sha512_ppc, tf_sha512_ppc);
@ -164,14 +160,15 @@ static const sha512_ops_t *const sha512_impls[] = {
#if defined(__x86_64) && defined(HAVE_AVX2)
&sha512_avx2_impl,
#endif
#if defined(__aarch64__)
#if defined(__aarch64__) || defined(__arm__)
&sha512_armv7_impl,
#if defined(__aarch64__)
&sha512_armv8_impl,
#endif
#if defined(__arm__) && __ARM_ARCH > 6
&sha512_armv7_impl,
&sha512_neon_impl,
#endif
#endif
#if defined(__PPC64__)
&sha512_ppc_impl,
&sha512_power8_impl,

View file

@ -1837,6 +1837,7 @@ zfs_sha256_block_armv7:
#endif
.size zfs_sha256_block_armv7,.-zfs_sha256_block_armv7
#if __ARM_ARCH__ >= 7
.arch armv7-a
.fpu neon
@ -1849,11 +1850,7 @@ zfs_sha256_block_neon:
stmdb sp!,{r4-r12,lr}
sub r11,sp,#16*4+16
#if __ARM_ARCH__ >=7
adr r14,K256
#else
ldr r14,=K256
#endif
bic r11,r11,#15 @ align for 128-bit stores
mov r12,sp
mov sp,r11 @ alloca
@ -2773,4 +2770,5 @@ zfs_sha256_block_armv8:
bx lr @ bx lr
.size zfs_sha256_block_armv8,.-zfs_sha256_block_armv8
#endif
#endif // #if __ARM_ARCH__ >= 7
#endif // #if defined(__arm__)

View file

@ -493,6 +493,7 @@ zfs_sha512_block_armv7:
#endif
.size zfs_sha512_block_armv7,.-zfs_sha512_block_armv7
#if __ARM_ARCH__ >= 7
.arch armv7-a
.fpu neon
@ -1822,4 +1823,5 @@ zfs_sha512_block_neon:
VFP_ABI_POP
bx lr @ .word 0xe12fff1e
.size zfs_sha512_block_neon,.-zfs_sha512_block_neon
#endif
#endif // #if __ARM_ARCH__ >= 7
#endif // #if defined(__arm__)

View file

@ -2011,6 +2011,8 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
vap->va_size = zp->z_size;
if (vp->v_type == VBLK || vp->v_type == VCHR)
vap->va_rdev = zfs_cmpldev(rdev);
else
vap->va_rdev = 0;
vap->va_gen = zp->z_gen;
vap->va_flags = 0; /* FreeBSD: Reset chflags(2) flags. */
vap->va_filerev = zp->z_seq;

View file

@ -6069,7 +6069,7 @@ arc_prune_task(void *ptr)
if (func != NULL)
func(ap->p_adjust, ap->p_private);
zfs_refcount_remove(&ap->p_refcnt, func);
(void) zfs_refcount_remove(&ap->p_refcnt, func);
}
/*
@ -6098,7 +6098,7 @@ arc_prune_async(uint64_t adjust)
ap->p_adjust = adjust;
if (taskq_dispatch(arc_prune_taskq, arc_prune_task,
ap, TQ_SLEEP) == TASKQID_INVALID) {
zfs_refcount_remove(&ap->p_refcnt, ap->p_pfunc);
(void) zfs_refcount_remove(&ap->p_refcnt, ap->p_pfunc);
continue;
}
ARCSTAT_BUMP(arcstat_prune);
@ -7720,7 +7720,7 @@ arc_fini(void)
mutex_enter(&arc_prune_mtx);
while ((p = list_remove_head(&arc_prune_list)) != NULL) {
zfs_refcount_remove(&p->p_refcnt, &arc_prune_list);
(void) zfs_refcount_remove(&p->p_refcnt, &arc_prune_list);
zfs_refcount_destroy(&p->p_refcnt);
kmem_free(p, sizeof (*p));
}
@ -8301,7 +8301,8 @@ l2arc_write_done(zio_t *zio)
ARCSTAT_BUMPDOWN(arcstat_l2_log_blk_count);
zfs_refcount_remove_many(&dev->l2ad_lb_asize, asize,
lb_ptr_buf);
zfs_refcount_remove(&dev->l2ad_lb_count, lb_ptr_buf);
(void) zfs_refcount_remove(&dev->l2ad_lb_count,
lb_ptr_buf);
kmem_free(lb_ptr_buf->lb_ptr,
sizeof (l2arc_log_blkptr_t));
kmem_free(lb_ptr_buf, sizeof (l2arc_lb_ptr_buf_t));
@ -8772,7 +8773,8 @@ l2arc_evict(l2arc_dev_t *dev, uint64_t distance, boolean_t all)
ARCSTAT_BUMPDOWN(arcstat_l2_log_blk_count);
zfs_refcount_remove_many(&dev->l2ad_lb_asize, asize,
lb_ptr_buf);
zfs_refcount_remove(&dev->l2ad_lb_count, lb_ptr_buf);
(void) zfs_refcount_remove(&dev->l2ad_lb_count,
lb_ptr_buf);
list_remove(&dev->l2ad_lbptr_list, lb_ptr_buf);
kmem_free(lb_ptr_buf->lb_ptr,
sizeof (l2arc_log_blkptr_t));

View file

@ -157,10 +157,8 @@
* (copying the file content to the new dataset and removing the source file).
* In that case Block Cloning will only be used briefly, because the BRT entries
* will be removed when the source is removed.
* Note: currently it is not possible to clone blocks between encrypted
* datasets, even if those datasets use the same encryption key (this includes
* snapshots of encrypted datasets). Cloning blocks between datasets that use
* the same keys should be possible and should be implemented in the future.
* Block Cloning across encrypted datasets is supported as long as both
* datasets share the same master key (e.g. snapshots and clones)
*
* Block Cloning flow through ZFS layers.
*
@ -344,7 +342,7 @@ brt_vdev_entcount_get(const brt_vdev_t *brtvd, uint64_t idx)
ASSERT3U(idx, <, brtvd->bv_size);
if (brtvd->bv_need_byteswap) {
if (unlikely(brtvd->bv_need_byteswap)) {
return (BSWAP_16(brtvd->bv_entcount[idx]));
} else {
return (brtvd->bv_entcount[idx]);
@ -357,7 +355,7 @@ brt_vdev_entcount_set(brt_vdev_t *brtvd, uint64_t idx, uint16_t entcnt)
ASSERT3U(idx, <, brtvd->bv_size);
if (brtvd->bv_need_byteswap) {
if (unlikely(brtvd->bv_need_byteswap)) {
brtvd->bv_entcount[idx] = BSWAP_16(entcnt);
} else {
brtvd->bv_entcount[idx] = entcnt;
@ -392,55 +390,39 @@ brt_vdev_entcount_dec(brt_vdev_t *brtvd, uint64_t idx)
#ifdef ZFS_DEBUG
static void
brt_vdev_dump(brt_t *brt)
brt_vdev_dump(brt_vdev_t *brtvd)
{
brt_vdev_t *brtvd;
uint64_t vdevid;
uint64_t idx;
if ((zfs_flags & ZFS_DEBUG_BRT) == 0) {
return;
}
if (brt->brt_nvdevs == 0) {
zfs_dbgmsg("BRT empty");
return;
}
zfs_dbgmsg("BRT vdev dump:");
for (vdevid = 0; vdevid < brt->brt_nvdevs; vdevid++) {
uint64_t idx;
brtvd = &brt->brt_vdevs[vdevid];
zfs_dbgmsg(" vdevid=%llu/%llu meta_dirty=%d entcount_dirty=%d "
"size=%llu totalcount=%llu nblocks=%llu bitmapsize=%zu\n",
(u_longlong_t)vdevid, (u_longlong_t)brtvd->bv_vdevid,
brtvd->bv_meta_dirty, brtvd->bv_entcount_dirty,
(u_longlong_t)brtvd->bv_size,
(u_longlong_t)brtvd->bv_totalcount,
(u_longlong_t)brtvd->bv_nblocks,
(size_t)BT_SIZEOFMAP(brtvd->bv_nblocks));
if (brtvd->bv_totalcount > 0) {
zfs_dbgmsg(" entcounts:");
for (idx = 0; idx < brtvd->bv_size; idx++) {
if (brt_vdev_entcount_get(brtvd, idx) > 0) {
zfs_dbgmsg(" [%04llu] %hu",
(u_longlong_t)idx,
brt_vdev_entcount_get(brtvd, idx));
}
zfs_dbgmsg(" BRT vdevid=%llu meta_dirty=%d entcount_dirty=%d "
"size=%llu totalcount=%llu nblocks=%llu bitmapsize=%zu\n",
(u_longlong_t)brtvd->bv_vdevid,
brtvd->bv_meta_dirty, brtvd->bv_entcount_dirty,
(u_longlong_t)brtvd->bv_size,
(u_longlong_t)brtvd->bv_totalcount,
(u_longlong_t)brtvd->bv_nblocks,
(size_t)BT_SIZEOFMAP(brtvd->bv_nblocks));
if (brtvd->bv_totalcount > 0) {
zfs_dbgmsg(" entcounts:");
for (idx = 0; idx < brtvd->bv_size; idx++) {
uint16_t entcnt = brt_vdev_entcount_get(brtvd, idx);
if (entcnt > 0) {
zfs_dbgmsg(" [%04llu] %hu",
(u_longlong_t)idx, entcnt);
}
}
if (brtvd->bv_entcount_dirty) {
char *bitmap;
}
if (brtvd->bv_entcount_dirty) {
char *bitmap;
bitmap = kmem_alloc(brtvd->bv_nblocks + 1, KM_SLEEP);
for (idx = 0; idx < brtvd->bv_nblocks; idx++) {
bitmap[idx] =
BT_TEST(brtvd->bv_bitmap, idx) ? 'x' : '.';
}
bitmap[idx] = '\0';
zfs_dbgmsg(" bitmap: %s", bitmap);
kmem_free(bitmap, brtvd->bv_nblocks + 1);
bitmap = kmem_alloc(brtvd->bv_nblocks + 1, KM_SLEEP);
for (idx = 0; idx < brtvd->bv_nblocks; idx++) {
bitmap[idx] =
BT_TEST(brtvd->bv_bitmap, idx) ? 'x' : '.';
}
bitmap[idx] = '\0';
zfs_dbgmsg(" dirty: %s", bitmap);
kmem_free(bitmap, brtvd->bv_nblocks + 1);
}
}
#endif
@ -769,7 +751,8 @@ brt_vdev_addref(brt_t *brt, brt_vdev_t *brtvd, const brt_entry_t *bre,
BT_SET(brtvd->bv_bitmap, idx);
#ifdef ZFS_DEBUG
brt_vdev_dump(brt);
if (zfs_flags & ZFS_DEBUG_BRT)
brt_vdev_dump(brtvd);
#endif
}
@ -805,7 +788,8 @@ brt_vdev_decref(brt_t *brt, brt_vdev_t *brtvd, const brt_entry_t *bre,
BT_SET(brtvd->bv_bitmap, idx);
#ifdef ZFS_DEBUG
brt_vdev_dump(brt);
if (zfs_flags & ZFS_DEBUG_BRT)
brt_vdev_dump(brtvd);
#endif
}

View file

@ -2274,6 +2274,21 @@ dmu_read_l0_bps(objset_t *os, uint64_t object, uint64_t offset, uint64_t length,
goto out;
}
/*
* If the block was allocated in transaction group that is not
* yet synced, we could clone it, but we couldn't write this
* operation into ZIL, or it may be impossible to replay, since
* the block may appear not yet allocated at that point.
*/
if (BP_PHYSICAL_BIRTH(bp) > spa_freeze_txg(os->os_spa)) {
error = SET_ERROR(EINVAL);
goto out;
}
if (BP_PHYSICAL_BIRTH(bp) > spa_last_synced_txg(os->os_spa)) {
error = SET_ERROR(EAGAIN);
goto out;
}
bps[i] = *bp;
}

View file

@ -266,6 +266,40 @@ spa_crypto_key_compare(const void *a, const void *b)
return (0);
}
/*
* this compares a crypto key based on zk_guid. See comment on
* spa_crypto_key_compare for more information.
*/
boolean_t
dmu_objset_crypto_key_equal(objset_t *osa, objset_t *osb)
{
dsl_crypto_key_t *dcka = NULL;
dsl_crypto_key_t *dckb = NULL;
uint64_t obja, objb;
boolean_t equal;
spa_t *spa;
spa = dmu_objset_spa(osa);
if (spa != dmu_objset_spa(osb))
return (B_FALSE);
obja = dmu_objset_ds(osa)->ds_object;
objb = dmu_objset_ds(osb)->ds_object;
if (spa_keystore_lookup_key(spa, obja, FTAG, &dcka) != 0)
return (B_FALSE);
if (spa_keystore_lookup_key(spa, objb, FTAG, &dckb) != 0) {
spa_keystore_dsl_key_rele(spa, dcka, FTAG);
return (B_FALSE);
}
equal = (dcka->dck_key.zk_guid == dckb->dck_key.zk_guid);
spa_keystore_dsl_key_rele(spa, dcka, FTAG);
spa_keystore_dsl_key_rele(spa, dckb, FTAG);
return (equal);
}
static int
spa_key_mapping_compare(const void *a, const void *b)
{

View file

@ -3109,6 +3109,7 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type)
spa->spa_load_state = state;
(void) spa_import_progress_set_state(spa_guid(spa),
spa_load_state(spa));
spa_import_progress_set_notes(spa, "spa_load()");
gethrestime(&spa->spa_loaded_ts);
error = spa_load_impl(spa, type, &ereport);
@ -3337,7 +3338,7 @@ spa_activity_check(spa_t *spa, uberblock_t *ub, nvlist_t *config)
uint64_t mmp_config = ub->ub_mmp_config;
uint16_t mmp_seq = MMP_SEQ_VALID(ub) ? MMP_SEQ(ub) : 0;
uint64_t import_delay;
hrtime_t import_expire;
hrtime_t import_expire, now;
nvlist_t *mmp_label = NULL;
vdev_t *rvd = spa->spa_root_vdev;
kcondvar_t cv;
@ -3375,7 +3376,17 @@ spa_activity_check(spa_t *spa, uberblock_t *ub, nvlist_t *config)
import_expire = gethrtime() + import_delay;
while (gethrtime() < import_expire) {
spa_import_progress_set_notes(spa, "Checking MMP activity, waiting "
"%llu ms", (u_longlong_t)NSEC2MSEC(import_delay));
int interations = 0;
while ((now = gethrtime()) < import_expire) {
if (interations++ % 30 == 0) {
spa_import_progress_set_notes(spa, "Checking MMP "
"activity, %llu ms remaining",
(u_longlong_t)NSEC2MSEC(import_expire - now));
}
(void) spa_import_progress_set_mmp_check(spa_guid(spa),
NSEC2SEC(import_expire - gethrtime()));
@ -4995,6 +5006,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
/*
* Retrieve the checkpoint txg if the pool has a checkpoint.
*/
spa_import_progress_set_notes(spa, "Loading checkpoint txg");
error = spa_ld_read_checkpoint_txg(spa);
if (error != 0)
return (error);
@ -5007,6 +5019,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* initiated. Otherwise we could be reading from indirect vdevs before
* we have loaded their mappings.
*/
spa_import_progress_set_notes(spa, "Loading indirect vdev metadata");
error = spa_ld_open_indirect_vdev_metadata(spa);
if (error != 0)
return (error);
@ -5015,6 +5028,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* Retrieve the full list of active features from the MOS and check if
* they are all supported.
*/
spa_import_progress_set_notes(spa, "Checking feature flags");
error = spa_ld_check_features(spa, &missing_feat_write);
if (error != 0)
return (error);
@ -5023,6 +5037,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* Load several special directories from the MOS needed by the dsl_pool
* layer.
*/
spa_import_progress_set_notes(spa, "Loading special MOS directories");
error = spa_ld_load_special_directories(spa);
if (error != 0)
return (error);
@ -5030,6 +5045,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
/*
* Retrieve pool properties from the MOS.
*/
spa_import_progress_set_notes(spa, "Loading properties");
error = spa_ld_get_props(spa);
if (error != 0)
return (error);
@ -5038,6 +5054,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* Retrieve the list of auxiliary devices - cache devices and spares -
* and open them.
*/
spa_import_progress_set_notes(spa, "Loading AUX vdevs");
error = spa_ld_open_aux_vdevs(spa, type);
if (error != 0)
return (error);
@ -5046,14 +5063,17 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* Load the metadata for all vdevs. Also check if unopenable devices
* should be autoreplaced.
*/
spa_import_progress_set_notes(spa, "Loading vdev metadata");
error = spa_ld_load_vdev_metadata(spa);
if (error != 0)
return (error);
spa_import_progress_set_notes(spa, "Loading dedup tables");
error = spa_ld_load_dedup_tables(spa);
if (error != 0)
return (error);
spa_import_progress_set_notes(spa, "Loading BRT");
error = spa_ld_load_brt(spa);
if (error != 0)
return (error);
@ -5062,6 +5082,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* Verify the logs now to make sure we don't have any unexpected errors
* when we claim log blocks later.
*/
spa_import_progress_set_notes(spa, "Verifying Log Devices");
error = spa_ld_verify_logs(spa, type, ereport);
if (error != 0)
return (error);
@ -5083,6 +5104,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* state. When performing an extreme rewind, we verify the whole pool,
* which can take a very long time.
*/
spa_import_progress_set_notes(spa, "Verifying pool data");
error = spa_ld_verify_pool_data(spa);
if (error != 0)
return (error);
@ -5092,6 +5114,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* we write anything to the pool because we'd need to update the space
* accounting using the deflated sizes.
*/
spa_import_progress_set_notes(spa, "Calculating deflated space");
spa_update_dspace(spa);
/*
@ -5099,6 +5122,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* pool. If we are importing the pool in read-write mode, a few
* additional steps must be performed to finish the import.
*/
spa_import_progress_set_notes(spa, "Starting import");
if (spa_writeable(spa) && (spa->spa_load_state == SPA_LOAD_RECOVER ||
spa->spa_load_max_txg == UINT64_MAX)) {
uint64_t config_cache_txg = spa->spa_config_txg;
@ -5122,6 +5146,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
(u_longlong_t)spa->spa_uberblock.ub_checkpoint_txg);
}
spa_import_progress_set_notes(spa, "Claiming ZIL blocks");
/*
* Traverse the ZIL and claim all blocks.
*/
@ -5141,6 +5166,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* will have been set for us by ZIL traversal operations
* performed above.
*/
spa_import_progress_set_notes(spa, "Syncing ZIL claims");
txg_wait_synced(spa->spa_dsl_pool, spa->spa_claim_max_txg);
/*
@ -5148,6 +5174,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* next sync, we would update the config stored in vdev labels
* and the cachefile (by default /etc/zfs/zpool.cache).
*/
spa_import_progress_set_notes(spa, "Updating configs");
spa_ld_check_for_config_update(spa, config_cache_txg,
update_config_cache);
@ -5156,6 +5183,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* Then check all DTLs to see if anything needs resilvering.
* The resilver will be deferred if a rebuild was started.
*/
spa_import_progress_set_notes(spa, "Starting resilvers");
if (vdev_rebuild_active(spa->spa_root_vdev)) {
vdev_rebuild_restart(spa);
} else if (!dsl_scan_resilvering(spa->spa_dsl_pool) &&
@ -5169,6 +5197,8 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
*/
spa_history_log_version(spa, "open", NULL);
spa_import_progress_set_notes(spa,
"Restarting device removals");
spa_restart_removal(spa);
spa_spawn_aux_threads(spa);
@ -5181,19 +5211,26 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport)
* auxiliary threads above (from which the livelist
* deletion zthr is part of).
*/
spa_import_progress_set_notes(spa,
"Cleaning up inconsistent objsets");
(void) dmu_objset_find(spa_name(spa),
dsl_destroy_inconsistent, NULL, DS_FIND_CHILDREN);
/*
* Clean up any stale temporary dataset userrefs.
*/
spa_import_progress_set_notes(spa,
"Cleaning up temporary userrefs");
dsl_pool_clean_tmp_userrefs(spa->spa_dsl_pool);
spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
spa_import_progress_set_notes(spa, "Restarting initialize");
vdev_initialize_restart(spa->spa_root_vdev);
spa_import_progress_set_notes(spa, "Restarting TRIM");
vdev_trim_restart(spa->spa_root_vdev);
vdev_autotrim_restart(spa);
spa_config_exit(spa, SCL_CONFIG, FTAG);
spa_import_progress_set_notes(spa, "Finished importing");
}
spa_import_progress_remove(spa_guid(spa));

View file

@ -1153,6 +1153,7 @@ spa_ld_log_sm_data(spa_t *spa)
uint_t pn = 0;
uint64_t ps = 0;
uint64_t nsm = 0;
psls = sls = avl_first(&spa->spa_sm_logs_by_txg);
while (sls != NULL) {
/* Prefetch log spacemaps up to 16 TXGs or MBs ahead. */
@ -1185,6 +1186,10 @@ spa_ld_log_sm_data(spa_t *spa)
summary_add_data(spa, sls->sls_txg,
sls->sls_mscount, 0, sls->sls_nblocks);
spa_import_progress_set_notes_nolog(spa,
"Read %llu of %lu log space maps", (u_longlong_t)nsm,
avl_numnodes(&spa->spa_sm_logs_by_txg));
struct spa_ld_log_sm_arg vla = {
.slls_spa = spa,
.slls_txg = sls->sls_txg
@ -1200,6 +1205,7 @@ spa_ld_log_sm_data(spa_t *spa)
pn--;
ps -= space_map_length(sls->sls_sm);
nsm++;
space_map_close(sls->sls_sm);
sls->sls_sm = NULL;
sls = AVL_NEXT(&spa->spa_sm_logs_by_txg, sls);
@ -1210,11 +1216,11 @@ spa_ld_log_sm_data(spa_t *spa)
hrtime_t read_logs_endtime = gethrtime();
spa_load_note(spa,
"read %llu log space maps (%llu total blocks - blksz = %llu bytes) "
"in %lld ms", (u_longlong_t)avl_numnodes(&spa->spa_sm_logs_by_txg),
"Read %lu log space maps (%llu total blocks - blksz = %llu bytes) "
"in %lld ms", avl_numnodes(&spa->spa_sm_logs_by_txg),
(u_longlong_t)spa_log_sm_nblocks(spa),
(u_longlong_t)zfs_log_sm_blksz,
(longlong_t)((read_logs_endtime - read_logs_starttime) / 1000000));
(longlong_t)NSEC2MSEC(read_logs_endtime - read_logs_starttime));
out:
if (error != 0) {

View file

@ -426,6 +426,8 @@ spa_load_note(spa_t *spa, const char *fmt, ...)
zfs_dbgmsg("spa_load(%s, config %s): %s", spa->spa_name,
spa->spa_trust_config ? "trusted" : "untrusted", buf);
spa_import_progress_set_notes_nolog(spa, "%s", buf);
}
/*
@ -2184,6 +2186,7 @@ typedef struct spa_import_progress {
uint64_t pool_guid; /* unique id for updates */
char *pool_name;
spa_load_state_t spa_load_state;
char *spa_load_notes;
uint64_t mmp_sec_remaining; /* MMP activity check */
uint64_t spa_load_max_txg; /* rewind txg */
procfs_list_node_t smh_node;
@ -2194,9 +2197,9 @@ spa_history_list_t *spa_import_progress_list = NULL;
static int
spa_import_progress_show_header(struct seq_file *f)
{
seq_printf(f, "%-20s %-14s %-14s %-12s %s\n", "pool_guid",
seq_printf(f, "%-20s %-14s %-14s %-12s %-16s %s\n", "pool_guid",
"load_state", "multihost_secs", "max_txg",
"pool_name");
"pool_name", "notes");
return (0);
}
@ -2205,11 +2208,12 @@ spa_import_progress_show(struct seq_file *f, void *data)
{
spa_import_progress_t *sip = (spa_import_progress_t *)data;
seq_printf(f, "%-20llu %-14llu %-14llu %-12llu %s\n",
seq_printf(f, "%-20llu %-14llu %-14llu %-12llu %-16s %s\n",
(u_longlong_t)sip->pool_guid, (u_longlong_t)sip->spa_load_state,
(u_longlong_t)sip->mmp_sec_remaining,
(u_longlong_t)sip->spa_load_max_txg,
(sip->pool_name ? sip->pool_name : "-"));
(sip->pool_name ? sip->pool_name : "-"),
(sip->spa_load_notes ? sip->spa_load_notes : "-"));
return (0);
}
@ -2223,6 +2227,8 @@ spa_import_progress_truncate(spa_history_list_t *shl, unsigned int size)
sip = list_remove_head(&shl->procfs_list.pl_list);
if (sip->pool_name)
spa_strfree(sip->pool_name);
if (sip->spa_load_notes)
kmem_strfree(sip->spa_load_notes);
kmem_free(sip, sizeof (spa_import_progress_t));
shl->size--;
}
@ -2278,6 +2284,10 @@ spa_import_progress_set_state(uint64_t pool_guid,
sip = list_prev(&shl->procfs_list.pl_list, sip)) {
if (sip->pool_guid == pool_guid) {
sip->spa_load_state = load_state;
if (sip->spa_load_notes != NULL) {
kmem_strfree(sip->spa_load_notes);
sip->spa_load_notes = NULL;
}
error = 0;
break;
}
@ -2287,6 +2297,59 @@ spa_import_progress_set_state(uint64_t pool_guid,
return (error);
}
static void
spa_import_progress_set_notes_impl(spa_t *spa, boolean_t log_dbgmsg,
const char *fmt, va_list adx)
{
spa_history_list_t *shl = spa_import_progress_list;
spa_import_progress_t *sip;
uint64_t pool_guid = spa_guid(spa);
if (shl->size == 0)
return;
char *notes = kmem_vasprintf(fmt, adx);
mutex_enter(&shl->procfs_list.pl_lock);
for (sip = list_tail(&shl->procfs_list.pl_list); sip != NULL;
sip = list_prev(&shl->procfs_list.pl_list, sip)) {
if (sip->pool_guid == pool_guid) {
if (sip->spa_load_notes != NULL) {
kmem_strfree(sip->spa_load_notes);
sip->spa_load_notes = NULL;
}
sip->spa_load_notes = notes;
if (log_dbgmsg)
zfs_dbgmsg("'%s' %s", sip->pool_name, notes);
notes = NULL;
break;
}
}
mutex_exit(&shl->procfs_list.pl_lock);
if (notes != NULL)
kmem_strfree(notes);
}
void
spa_import_progress_set_notes(spa_t *spa, const char *fmt, ...)
{
va_list adx;
va_start(adx, fmt);
spa_import_progress_set_notes_impl(spa, B_TRUE, fmt, adx);
va_end(adx);
}
void
spa_import_progress_set_notes_nolog(spa_t *spa, const char *fmt, ...)
{
va_list adx;
va_start(adx, fmt);
spa_import_progress_set_notes_impl(spa, B_FALSE, fmt, adx);
va_end(adx);
}
int
spa_import_progress_set_max_txg(uint64_t pool_guid, uint64_t load_max_txg)
{
@ -2355,6 +2418,7 @@ spa_import_progress_add(spa_t *spa)
poolname = spa_name(spa);
sip->pool_name = spa_strdup(poolname);
sip->spa_load_state = spa_load_state(spa);
sip->spa_load_notes = NULL;
mutex_enter(&shl->procfs_list.pl_lock);
procfs_list_add(&shl->procfs_list, sip);
@ -2374,6 +2438,8 @@ spa_import_progress_remove(uint64_t pool_guid)
if (sip->pool_guid == pool_guid) {
if (sip->pool_name)
spa_strfree(sip->pool_name);
if (sip->spa_load_notes)
spa_strfree(sip->spa_load_notes);
list_remove(&shl->procfs_list.pl_list, sip);
shl->size--;
kmem_free(sip, sizeof (spa_import_progress_t));

View file

@ -47,6 +47,7 @@
#include <sys/fs/zfs.h>
#include <sys/dmu.h>
#include <sys/dmu_objset.h>
#include <sys/dsl_crypt.h>
#include <sys/spa.h>
#include <sys/txg.h>
#include <sys/dbuf.h>
@ -1097,6 +1098,16 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
return (SET_ERROR(EXDEV));
}
/*
* Cloning across encrypted datasets is possible only if they
* share the same master key.
*/
if (inos != outos && inos->os_encrypted &&
!dmu_objset_crypto_key_equal(inos, outos)) {
zfs_exit_two(inzfsvfs, outzfsvfs, FTAG);
return (SET_ERROR(EXDEV));
}
error = zfs_verify_zp(inzp);
if (error == 0)
error = zfs_verify_zp(outzp);
@ -1280,20 +1291,6 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
*/
break;
}
/*
* Encrypted data is fine as long as it comes from the same
* dataset.
* TODO: We want to extend it in the future to allow cloning to
* datasets with the same keys, like clones or to be able to
* clone a file from a snapshot of an encrypted dataset into the
* dataset itself.
*/
if (BP_IS_PROTECTED(&bps[0])) {
if (inzfsvfs != outzfsvfs) {
error = SET_ERROR(EXDEV);
break;
}
}
/*
* Start a transaction.

View file

@ -617,11 +617,12 @@ zil_claim_write(zilog_t *zilog, const lr_t *lrc, void *tx, uint64_t first_txg)
}
static int
zil_claim_clone_range(zilog_t *zilog, const lr_t *lrc, void *tx)
zil_claim_clone_range(zilog_t *zilog, const lr_t *lrc, void *tx,
uint64_t first_txg)
{
const lr_clone_range_t *lr = (const lr_clone_range_t *)lrc;
const blkptr_t *bp;
spa_t *spa;
spa_t *spa = zilog->zl_spa;
uint_t ii;
ASSERT3U(lrc->lrc_reclen, >=, sizeof (*lr));
@ -636,19 +637,36 @@ zil_claim_clone_range(zilog_t *zilog, const lr_t *lrc, void *tx)
* XXX: Do we need to byteswap lr?
*/
spa = zilog->zl_spa;
for (ii = 0; ii < lr->lr_nbps; ii++) {
bp = &lr->lr_bps[ii];
/*
* When data in embedded into BP there is no need to create
* BRT entry as there is no data block. Just copy the BP as
* it contains the data.
* When data is embedded into the BP there is no need to create
* BRT entry as there is no data block. Just copy the BP as it
* contains the data.
*/
if (!BP_IS_HOLE(bp) && !BP_IS_EMBEDDED(bp)) {
if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
continue;
/*
* We can not handle block pointers from the future, since they
* are not yet allocated. It should not normally happen, but
* just in case lets be safe and just stop here now instead of
* corrupting the pool.
*/
if (BP_PHYSICAL_BIRTH(bp) >= first_txg)
return (SET_ERROR(ENOENT));
/*
* Assert the block is really allocated before we reference it.
*/
metaslab_check_free(spa, bp);
}
for (ii = 0; ii < lr->lr_nbps; ii++) {
bp = &lr->lr_bps[ii];
if (!BP_IS_HOLE(bp) && !BP_IS_EMBEDDED(bp))
brt_pending_add(spa, bp, tx);
}
}
return (0);
@ -663,7 +681,7 @@ zil_claim_log_record(zilog_t *zilog, const lr_t *lrc, void *tx,
case TX_WRITE:
return (zil_claim_write(zilog, lrc, tx, first_txg));
case TX_CLONE_RANGE:
return (zil_claim_clone_range(zilog, lrc, tx));
return (zil_claim_clone_range(zilog, lrc, tx, first_txg));
default:
return (0);
}
@ -1707,8 +1725,6 @@ static const struct {
{ 8192 + 4096, 8192 + 4096 }, /* database */
{ 32768 + 4096, 32768 + 4096 }, /* NFS writes */
{ 65536 + 4096, 65536 + 4096 }, /* 64KB writes */
{ 131072, 131072 }, /* < 128KB writes */
{ 131072 +4096, 65536 + 4096 }, /* 128KB writes */
{ UINT64_MAX, SPA_OLD_MAXBLOCKSIZE}, /* > 128KB writes */
};

View file

@ -295,6 +295,53 @@ zio_fini(void)
* ==========================================================================
*/
#ifdef ZFS_DEBUG
static const ulong_t zio_buf_canary = (ulong_t)0xdeadc0dedead210b;
#endif
/*
* Use empty space after the buffer to detect overflows.
*
* Since zio_init() creates kmem caches only for certain set of buffer sizes,
* allocations of different sizes may have some unused space after the data.
* Filling part of that space with a known pattern on allocation and checking
* it on free should allow us to detect some buffer overflows.
*/
static void
zio_buf_put_canary(ulong_t *p, size_t size, kmem_cache_t **cache, size_t c)
{
#ifdef ZFS_DEBUG
size_t off = P2ROUNDUP(size, sizeof (ulong_t));
ulong_t *canary = p + off / sizeof (ulong_t);
size_t asize = (c + 1) << SPA_MINBLOCKSHIFT;
if (c + 1 < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT &&
cache[c] == cache[c + 1])
asize = (c + 2) << SPA_MINBLOCKSHIFT;
for (; off < asize; canary++, off += sizeof (ulong_t))
*canary = zio_buf_canary;
#endif
}
static void
zio_buf_check_canary(ulong_t *p, size_t size, kmem_cache_t **cache, size_t c)
{
#ifdef ZFS_DEBUG
size_t off = P2ROUNDUP(size, sizeof (ulong_t));
ulong_t *canary = p + off / sizeof (ulong_t);
size_t asize = (c + 1) << SPA_MINBLOCKSHIFT;
if (c + 1 < SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT &&
cache[c] == cache[c + 1])
asize = (c + 2) << SPA_MINBLOCKSHIFT;
for (; off < asize; canary++, off += sizeof (ulong_t)) {
if (unlikely(*canary != zio_buf_canary)) {
PANIC("ZIO buffer overflow %p (%zu) + %zu %#lx != %#lx",
p, size, (canary - p) * sizeof (ulong_t),
*canary, zio_buf_canary);
}
}
#endif
}
/*
* Use zio_buf_alloc to allocate ZFS metadata. This data will appear in a
* crashdump if the kernel panics, so use it judiciously. Obviously, it's
@ -311,7 +358,9 @@ zio_buf_alloc(size_t size)
atomic_add_64(&zio_buf_cache_allocs[c], 1);
#endif
return (kmem_cache_alloc(zio_buf_cache[c], KM_PUSHPAGE));
void *p = kmem_cache_alloc(zio_buf_cache[c], KM_PUSHPAGE);
zio_buf_put_canary(p, size, zio_buf_cache, c);
return (p);
}
/*
@ -327,7 +376,9 @@ zio_data_buf_alloc(size_t size)
VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
return (kmem_cache_alloc(zio_data_buf_cache[c], KM_PUSHPAGE));
void *p = kmem_cache_alloc(zio_data_buf_cache[c], KM_PUSHPAGE);
zio_buf_put_canary(p, size, zio_data_buf_cache, c);
return (p);
}
void
@ -340,6 +391,7 @@ zio_buf_free(void *buf, size_t size)
atomic_add_64(&zio_buf_cache_frees[c], 1);
#endif
zio_buf_check_canary(buf, size, zio_buf_cache, c);
kmem_cache_free(zio_buf_cache[c], buf);
}
@ -350,6 +402,7 @@ zio_data_buf_free(void *buf, size_t size)
VERIFY3U(c, <, SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT);
zio_buf_check_canary(buf, size, zio_data_buf_cache, c);
kmem_cache_free(zio_data_buf_cache[c], buf);
}

View file

@ -515,64 +515,6 @@ zvol_replay_write(void *arg1, void *arg2, boolean_t byteswap)
return (error);
}
/*
* Replay a TX_CLONE_RANGE ZIL transaction that didn't get committed
* after a system failure.
*
* TODO: For now we drop block cloning transations for ZVOLs as they are
* unsupported, but we still need to inform BRT about that as we
* claimed them during pool import.
* This situation can occur when we try to import a pool from a ZFS
* version supporting block cloning for ZVOLs into a system that
* has this ZFS version, that doesn't support block cloning for ZVOLs.
*/
static int
zvol_replay_clone_range(void *arg1, void *arg2, boolean_t byteswap)
{
char name[ZFS_MAX_DATASET_NAME_LEN];
zvol_state_t *zv = arg1;
objset_t *os = zv->zv_objset;
lr_clone_range_t *lr = arg2;
blkptr_t *bp;
dmu_tx_t *tx;
spa_t *spa;
uint_t ii;
int error;
ASSERT3U(lr->lr_common.lrc_reclen, >=, sizeof (*lr));
ASSERT3U(lr->lr_common.lrc_reclen, >=, offsetof(lr_clone_range_t,
lr_bps[lr->lr_nbps]));
dmu_objset_name(os, name);
cmn_err(CE_WARN, "ZFS dropping block cloning transaction for %s.",
name);
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
tx = dmu_tx_create(os);
error = dmu_tx_assign(tx, TXG_WAIT);
if (error) {
dmu_tx_abort(tx);
return (error);
}
spa = os->os_spa;
for (ii = 0; ii < lr->lr_nbps; ii++) {
bp = &lr->lr_bps[ii];
if (!BP_IS_HOLE(bp)) {
zio_free(spa, dmu_tx_get_txg(tx), bp);
}
}
(void) zil_replaying(zv->zv_zilog, tx);
dmu_tx_commit(tx);
return (0);
}
static int
zvol_replay_err(void *arg1, void *arg2, boolean_t byteswap)
{
@ -607,7 +549,7 @@ zil_replay_func_t *const zvol_replay_vector[TX_MAX_TYPE] = {
zvol_replay_err, /* TX_SETSAXATTR */
zvol_replay_err, /* TX_RENAME_EXCHANGE */
zvol_replay_err, /* TX_RENAME_WHITEOUT */
zvol_replay_clone_range /* TX_CLONE_RANGE */
zvol_replay_err, /* TX_CLONE_RANGE */
};
/*

View file

@ -425,7 +425,8 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos',
'import_devices_missing', 'import_log_missing',
'import_paths_changed',
'import_rewind_config_changed',
'import_rewind_device_replaced']
'import_rewind_device_replaced',
'zpool_import_status']
tags = ['functional', 'cli_root', 'zpool_import']
timeout = 1200

View file

@ -42,6 +42,7 @@ tests = ['block_cloning_copyfilerange', 'block_cloning_copyfilerange_partial',
'block_cloning_disabled_copyfilerange', 'block_cloning_disabled_ficlone',
'block_cloning_disabled_ficlonerange',
'block_cloning_copyfilerange_cross_dataset',
'block_cloning_cross_enc_dataset',
'block_cloning_copyfilerange_fallback_same_txg']
tags = ['functional', 'block_cloning']

View file

@ -305,6 +305,8 @@ elif sys.platform.startswith('linux'):
['SKIP', cfr_cross_reason],
'block_cloning/block_cloning_copyfilerange_fallback_same_txg':
['SKIP', cfr_cross_reason],
'block_cloning/block_cloning_cross_enc_dataset':
['SKIP', cfr_cross_reason],
})

View file

@ -451,6 +451,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/block_cloning/block_cloning_ficlone.ksh \
functional/block_cloning/block_cloning_ficlonerange.ksh \
functional/block_cloning/block_cloning_ficlonerange_partial.ksh \
functional/block_cloning/block_cloning_cross_enc_dataset.ksh \
functional/bootfs/bootfs_001_pos.ksh \
functional/bootfs/bootfs_002_neg.ksh \
functional/bootfs/bootfs_003_pos.ksh \

View file

@ -28,8 +28,8 @@
function have_same_content
{
typeset hash1=$(cat $1 | md5sum)
typeset hash2=$(cat $2 | md5sum)
typeset hash1=$(md5digest $1)
typeset hash2=$(md5digest $2)
log_must [ "$hash1" = "$hash2" ]
}
@ -44,10 +44,14 @@ function have_same_content
#
function get_same_blocks
{
KEY=$5
if [ ${#KEY} -gt 0 ]; then
KEY="--key=$KEY"
fi
typeset zdbout=${TMPDIR:-$TEST_BASE_DIR}/zdbout.$$
zdb -vvvvv $1 -O $2 | \
zdb $KEY -vvvvv $1 -O $2 | \
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout.a
zdb -vvvvv $3 -O $4 | \
zdb $KEY -vvvvv $3 -O $4 | \
awk '/ L0 / { print l++ " " $3 " " $7 }' > $zdbout.b
echo $(sort $zdbout.a $zdbout.b | uniq -d | cut -f1 -d' ')
}

View file

@ -0,0 +1,170 @@
#!/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
#
#
# Copyright (c) 2023, Kay Pedersen <mail@mkwg.de>
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/block_cloning/block_cloning.kshlib
verify_runnable "global"
if [[ $(linux_version) -lt $(linux_version "5.3") ]]; then
log_unsupported "copy_file_range can't copy cross-filesystem before Linux 5.3"
fi
claim="Block cloning across encrypted datasets."
log_assert $claim
DS1="$TESTPOOL/encrypted1"
DS2="$TESTPOOL/encrypted2"
DS1_NC="$TESTPOOL/notcrypted1"
PASSPHRASE="top_secret"
function prepare_enc
{
log_must zpool create -o feature@block_cloning=enabled $TESTPOOL $DISKS
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
"-o keyformat=passphrase -o keylocation=prompt $DS1"
log_must eval "echo $PASSPHRASE | zfs create -o encryption=on" \
"-o keyformat=passphrase -o keylocation=prompt $DS2"
log_must zfs create $DS1/child1
log_must zfs create $DS1/child2
log_must zfs create $DS1_NC
log_note "Create test file"
# we must wait until the src file txg is written to the disk otherwise we
# will fallback to normal copy. See "dmu_read_l0_bps" in
# "zfs/module/zfs/dmu.c" and "zfs_clone_range" in
# "zfs/module/zfs/zfs_vnops.c"
log_must dd if=/dev/urandom of=/$DS1/file bs=128K count=4
log_must dd if=/dev/urandom of=/$DS1/child1/file bs=128K count=4
log_must dd if=/dev/urandom of=/$DS1_NC/file bs=128K count=4
log_must sync_pool $TESTPOOL
}
function cleanup_enc
{
datasetexists $TESTPOOL && destroy_pool $TESTPOOL
}
function clone_and_check
{
I_FILE="$1"
O_FILE=$2
I_DS=$3
O_DS=$4
SAME_BLOCKS=$5
# the CLONE option provides a choice between copy_file_range
# which should clone and a dd which is a copy no matter what
CLONE=$6
SNAPSHOT=$7
if [ ${#SNAPSHOT} -gt 0 ]; then
I_FILE=".zfs/snapshot/$SNAPSHOT/$1"
fi
if [ $CLONE ]; then
log_must clonefile -f "/$I_DS/$I_FILE" "/$O_DS/$O_FILE" 0 0 524288
else
log_must dd if="/$I_DS/$I_FILE" of="/$O_DS/$O_FILE" bs=128K
fi
log_must sync_pool $TESTPOOL
log_must have_same_content "/$I_DS/$I_FILE" "/$O_DS/$O_FILE"
if [ ${#SNAPSHOT} -gt 0 ]; then
I_DS="$I_DS@$SNAPSHOT"
I_FILE="$1"
fi
typeset blocks=$(get_same_blocks \
$I_DS $I_FILE $O_DS $O_FILE $PASSPHRASE)
log_must [ "$blocks" = "$SAME_BLOCKS" ]
}
log_onexit cleanup_enc
prepare_enc
log_note "Cloning entire file with copy_file_range across different enc" \
"roots, should fallback"
# we are expecting no same block map.
clone_and_check "file" "clone" $DS1 $DS2 "" true
log_note "check if the file is still readable and the same after" \
"unmount and key unload, shouldn't fail"
typeset hash1=$(md5digest "/$DS1/file")
log_must zfs umount $DS1 && zfs unload-key $DS1
typeset hash2=$(md5digest "/$DS2/clone")
log_must [ "$hash1" = "$hash2" ]
cleanup_enc
prepare_enc
log_note "Cloning entire file with copy_file_range across different child datasets"
# clone shouldn't work because of deriving a new master key for the child
# we are expecting no same block map.
clone_and_check "file" "clone" $DS1 "$DS1/child1" "" true
clone_and_check "file" "clone" "$DS1/child1" "$DS1/child2" "" true
cleanup_enc
prepare_enc
log_note "Copying entire file with copy_file_range across same snapshot"
log_must zfs snapshot -r $DS1@s1
log_must sync_pool $TESTPOOL
log_must rm -f "/$DS1/file"
log_must sync_pool $TESTPOOL
clone_and_check "file" "clone" "$DS1" "$DS1" "0 1 2 3" true "s1"
cleanup_enc
prepare_enc
log_note "Copying entire file with copy_file_range across different snapshot"
clone_and_check "file" "file" $DS1 $DS2 "" true
log_must zfs snapshot -r $DS2@s1
log_must sync_pool $TESTPOOL
log_must rm -f "/$DS1/file" "/$DS2/file"
log_must sync_pool $TESTPOOL
clone_and_check "file" "clone" "$DS2" "$DS1" "" true "s1"
typeset hash1=$(md5digest "/$DS1/.zfs/snapshot/s1/file")
log_note "destroy the snapshot and check if the file is still readable and" \
"has the same content"
log_must zfs destroy -r $DS2@s1
log_must sync_pool $TESTPOOL
typeset hash2=$(md5digest "/$DS1/file")
log_must [ "$hash1" = "$hash2" ]
cleanup_enc
prepare_enc
log_note "Copying with copy_file_range from non encrypted to encrypted"
clone_and_check "file" "copy" $DS1_NC $DS1 "" true
cleanup_enc
prepare_enc
log_note "Copying with copy_file_range from encrypted to non encrypted"
clone_and_check "file" "copy" $DS1 $DS1_NC "" true
log_must sync_pool $TESTPOOL
log_pass $claim

View file

@ -0,0 +1,132 @@
#!/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
#
#
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
# Copyright (c) 2023 Klara, Inc.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
#
# DESCRIPTION:
# During a pool import, the 'import_progress' kstat contains details
# on the import progress.
#
# STRATEGY:
# 1. Create test pool with several devices
# 2. Generate some ZIL records and spacemap logs
# 3. Export the pool
# 4. Import the pool in the background and monitor the kstat content
# 5. Check the zfs debug messages for import progress
#
verify_runnable "global"
function cleanup
{
log_must set_tunable64 KEEP_LOG_SPACEMAPS_AT_EXPORT 0
log_must set_tunable64 METASLAB_DEBUG_LOAD 0
destroy_pool $TESTPOOL1
}
log_assert "During a pool import, the 'import_progress' kstat contains " \
"notes on the progress"
log_onexit cleanup
log_must zpool create $TESTPOOL1 $VDEV0 $VDEV1 $VDEV2
typeset guid=$(zpool get -H -o value guid $TESTPOOL1)
log_must zfs create -o recordsize=8k $TESTPOOL1/fs
#
# This dd command works around an issue where ZIL records aren't created
# after freezing the pool unless a ZIL header already exists. Create a file
# synchronously to force ZFS to write one out.
#
log_must dd if=/dev/zero of=/$TESTPOOL1/fs/sync conv=fsync bs=1 count=1
#
# Overwrite some blocks to populate spacemap logs
#
log_must dd if=/dev/urandom of=/$TESTPOOL1/fs/00 bs=1M count=200
sync_all_pools
log_must dd if=/dev/urandom of=/$TESTPOOL1/fs/00 bs=1M count=200
sync_all_pools
#
# Freeze the pool to retain intent log records
#
log_must zpool freeze $TESTPOOL1
# fill_fs [destdir] [dirnum] [filenum] [bytes] [num_writes] [data]
log_must fill_fs /$TESTPOOL1/fs 1 2000 100 1024 R
log_must zpool list -v $TESTPOOL1
#
# Unmount filesystem and export the pool
#
# At this stage the zfs intent log contains
# a set of records to replay.
#
log_must zfs unmount /$TESTPOOL1/fs
log_must set_tunable64 KEEP_LOG_SPACEMAPS_AT_EXPORT 1
log_must zpool export $TESTPOOL1
log_must set_tunable64 METASLAB_DEBUG_LOAD 1
log_note "Starting zpool import in background at" $(date +'%H:%M:%S')
zpool import -d $DEVICE_DIR -f $guid &
pid=$!
#
# capture progress until import is finished
#
log_note waiting for pid $pid to exit
kstat import_progress
while [[ -d /proc/"$pid" ]]; do
line=$(kstat import_progress | grep -v pool_guid)
if [[ -n $line ]]; then
echo $line
fi
if [[ -f /$TESTPOOL1/fs/00 ]]; then
break;
fi
sleep 0.0001
done
log_note "zpool import completed at" $(date +'%H:%M:%S')
entries=$(kstat dbgmsg | grep "spa_import_progress_set_notes_impl(): 'testpool1'" | wc -l)
log_note "found $entries progress notes in dbgmsg"
log_must test $entries -gt 20
log_must zpool status $TESTPOOL1
log_pass "During a pool import, the 'import_progress' kstat contains " \
"notes on the progress"

View file

@ -316,6 +316,9 @@
/* sops->evict_inode() exists */
/* #undef HAVE_EVICT_INODE */
/* Define to 1 if you have the `execvpe' function. */
/* #undef HAVE_EXECVPE */
/* FALLOC_FL_ZERO_RANGE is defined */
/* #undef HAVE_FALLOC_FL_ZERO_RANGE */
@ -1110,7 +1113,7 @@
/* #undef ZFS_IS_GPL_COMPATIBLE */
/* Define the project alias string. */
#define ZFS_META_ALIAS "zfs-2.2.99-239-FreeBSD_ga03ebd9be"
#define ZFS_META_ALIAS "zfs-2.2.99-257-FreeBSD_g450f2d0b0"
/* Define the project author. */
#define ZFS_META_AUTHOR "OpenZFS"
@ -1140,7 +1143,7 @@
#define ZFS_META_NAME "zfs"
/* Define the project release. */
#define ZFS_META_RELEASE "239-FreeBSD_ga03ebd9be"
#define ZFS_META_RELEASE "257-FreeBSD_g450f2d0b0"
/* Define the project version. */
#define ZFS_META_VERSION "2.2.99"

View file

@ -1 +1 @@
#define ZFS_META_GITREV "zfs-2.2.99-239-ga03ebd9be"
#define ZFS_META_GITREV "zfs-2.2.99-257-g450f2d0b0"