diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 524cff335..d6a890fcc 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -9036,6 +9036,12 @@ print_history_records(nvlist_t *nvhis, hist_cbdata_t *cb) dump_nvlist(fnvlist_lookup_nvlist(rec, ZPOOL_HIST_OUTPUT_NVL), 8); } + if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_SIZE)) { + (void) printf(" output nvlist omitted; " + "original size: %lldKB\n", + (longlong_t)fnvlist_lookup_int64(rec, + ZPOOL_HIST_OUTPUT_SIZE) / 1024); + } if (nvlist_exists(rec, ZPOOL_HIST_ERRNO)) { (void) printf(" errno: %lld\n", (longlong_t)fnvlist_lookup_int64(rec, diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 5bb7971d4..60c1b8460 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -1452,6 +1452,7 @@ typedef enum { #define ZPOOL_HIST_IOCTL "ioctl" #define ZPOOL_HIST_INPUT_NVL "in_nvl" #define ZPOOL_HIST_OUTPUT_NVL "out_nvl" +#define ZPOOL_HIST_OUTPUT_SIZE "out_size" #define ZPOOL_HIST_DSNAME "dsname" #define ZPOOL_HIST_DSID "dsid" #define ZPOOL_HIST_ERRNO "errno" diff --git a/man/man5/zfs-module-parameters.5 b/man/man5/zfs-module-parameters.5 index 5b4dac42f..c6c40cf80 100644 --- a/man/man5/zfs-module-parameters.5 +++ b/man/man5/zfs-module-parameters.5 @@ -379,6 +379,20 @@ by the test suite to facilitate testing. Default value: \fB16,777,217\fR. .RE +.sp +.ne 2 +.na +\fBzfs_history_output_max\fR (int) +.ad +.RS 12n +When attempting to log the output nvlist of an ioctl in the on-disk history, the +output will not be stored if it is larger than size (in bytes). This must be +less then DMU_MAX_ACCESS (64MB). This applies primarily to +zfs_ioc_channel_program(). +.sp +Default value: \fB1MB\fR. +.RE + .sp .ne 2 .na diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 94cd1a3dc..7f2cf2a75 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -231,6 +231,13 @@ zfsdev_state_t *zfsdev_state_list; */ unsigned long 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 then DMU_MAX_ACCESS. + * This applies primarily to zfs_ioc_channel_program(). + */ +unsigned long zfs_history_output_max = 1024 * 1024; + uint_t zfs_fsyncer_key; uint_t zfs_allow_log_key; @@ -7517,8 +7524,14 @@ zfsdev_ioctl_common(uint_t vecnum, zfs_cmd_t *zc, int flag) vec->zvec_allow_log && spa_open(zc->zc_name, &spa, FTAG) == 0) { if (!nvlist_empty(outnvl)) { - fnvlist_add_nvlist(lognv, ZPOOL_HIST_OUTPUT_NVL, - outnvl); + size_t out_size = fnvlist_size(outnvl); + if (out_size > zfs_history_output_max) { + fnvlist_add_int64(lognv, + ZPOOL_HIST_OUTPUT_SIZE, out_size); + } else { + fnvlist_add_nvlist(lognv, + ZPOOL_HIST_OUTPUT_NVL, outnvl); + } } if (error != 0) { fnvlist_add_int64(lognv, ZPOOL_HIST_ERRNO, @@ -7627,4 +7640,7 @@ zfs_kmod_fini(void) /* BEGIN CSTYLED */ ZFS_MODULE_PARAM(zfs, zfs_, max_nvlist_src_size, ULONG, 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, + "Maximum size in bytes of ZFS ioctl output that will be logged"); /* END CSTYLED */