Skip to content

Commit

Permalink
Cleanup: 64-bit kernel module parameters should use fixed width types
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Jorgen Lundman <[email protected]>
Reviewed-by: Ryan Moeller <[email protected]>
Reviewed-by: Alexander Motin <[email protected]>
Original-patch-by: Andrew Innes <[email protected]>
Original-patch-by: Jorgen Lundman <[email protected]>
Signed-off-by: Richard Yao <[email protected]>
Closes openzfs#13984
Closes openzfs#14004
  • Loading branch information
ryao authored and andrewc12 committed Oct 13, 2022
1 parent 389ef1b commit 38a47d3
Show file tree
Hide file tree
Showing 49 changed files with 338 additions and 285 deletions.
6 changes: 3 additions & 3 deletions cmd/ztest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
18 changes: 9 additions & 9 deletions include/os/freebsd/spl/sys/mod_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,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"
Expand All @@ -82,22 +82,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"
Expand Down
59 changes: 46 additions & 13 deletions include/os/linux/kernel/linux/mod_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +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

/* Other platforms have long as 32-bit */
#define ZFS_MODULE_LONG long
#define ZFS_MODULE_ULONG unsigned long

enum scope_prefix_types {
zfs,
zfs_arc,
Expand Down Expand Up @@ -88,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
*
Expand Down Expand Up @@ -120,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)

/*
Expand Down
2 changes: 1 addition & 1 deletion include/sys/arc_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,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);
Expand Down
2 changes: 1 addition & 1 deletion include/sys/dmu_zfetch.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
extern "C" {
#endif

extern ZFS_MODULE_ULONG zfetch_array_rd_sz;
extern uint64_t zfetch_array_rd_sz;

struct dnode; /* so we can reference dnode */

Expand Down
2 changes: 1 addition & 1 deletion include/sys/dsl_deadlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ typedef struct livelist_condense_entry {
boolean_t cancelled;
} livelist_condense_entry_t;

extern ZFS_MODULE_ULONG 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);
Expand Down
8 changes: 4 additions & 4 deletions include/sys/dsl_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ struct dsl_scan;
struct dsl_crypto_params;
struct dsl_deadlist;

extern ZFS_MODULE_ULONG zfs_dirty_data_max;
extern ZFS_MODULE_ULONG zfs_dirty_data_max_max;
extern ZFS_MODULE_ULONG 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 ZFS_MODULE_ULONG 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
Expand Down
2 changes: 1 addition & 1 deletion include/sys/mmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ extern void mmp_signal_all_threads(void);

/* Global tuning */
extern int param_set_multihost_interval(ZFS_MODULE_PARAM_ARGS);
extern ZFS_MODULE_ULONG zfs_multihost_interval;
extern uint64_t zfs_multihost_interval;
extern uint_t zfs_multihost_fail_intervals;
extern uint_t zfs_multihost_import_intervals;

Expand Down
6 changes: 3 additions & 3 deletions include/sys/spa.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ZFS_MODULE_ULONG zfs_deadman_synctime_ms;
extern ZFS_MODULE_ULONG zfs_deadman_ziotime_ms;
extern ZFS_MODULE_ULONG 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[];
Expand Down
4 changes: 2 additions & 2 deletions include/sys/vdev_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions include/sys/zcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ extern "C" {

#define ZCP_RUN_INFO_KEY "runinfo"

extern ZFS_MODULE_ULONG zfs_lua_max_instrlimit;
extern ZFS_MODULE_ULONG 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 *, ...);

Expand Down
2 changes: 1 addition & 1 deletion include/sys/zfs_ioctl_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#define _ZFS_IOCTL_IMPL_H_

extern kmutex_t zfsdev_state_lock;
extern ZFS_MODULE_ULONG 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 *);
Expand Down
Loading

0 comments on commit 38a47d3

Please sign in to comment.