aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_ioctl.c
diff options
context:
space:
mode:
authorMatthew Ahrens <[email protected]>2020-11-14 10:17:16 -0800
committerGitHub <[email protected]>2020-11-14 10:17:16 -0800
commitd66aab7c081274c97b785cdc9033456c493ca6b1 (patch)
treeffff201b4bf48631f0428e0d27b71229c829bb7e /module/zfs/zfs_ioctl.c
parent7e3617de35defa931ec124d1442008f73b275ecc (diff)
Assertion failure when logging large output of channel program
The output of ZFS channel programs is logged on-disk in the zpool history, and printed by `zpool history -i`. Channel programs can use 10MB of memory by default, and up to 100MB by using the `zfs program -m` flag. Therefore their output can be up to some fraction of 100MB. In addition to being somewhat wasteful of the limited space reserved for the pool history (which for large pools is 1GB), in extreme cases this can result in a failure of `ASSERT(length <= DMU_MAX_ACCESS);` in `dmu_buf_hold_array_by_dnode()`. This commit limits the output size that will be logged to 1MB. Larger outputs will not be logged, instead a entry will be logged indicating the size of the omitted output. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Matthew Ahrens <[email protected]> Closes #11194
Diffstat (limited to 'module/zfs/zfs_ioctl.c')
-rw-r--r--module/zfs/zfs_ioctl.c20
1 files changed, 18 insertions, 2 deletions
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 */