Skip to content

Allow lockless zpool status #17305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -7723,7 +7723,8 @@ import_checkpointed_state(char *target, nvlist_t *cfg, char **new_path)

if (cfg == NULL) {
zdb_set_skip_mmp(poolname);
error = spa_get_stats(poolname, &cfg, NULL, 0);
error = spa_get_stats(poolname, &cfg, NULL, 0,
ZPOOL_LOCK_BEHAVIOR_DEFAULT);
if (error != 0) {
fatal("Tried to read config of pool \"%s\" but "
"spa_get_stats() failed with error %d\n",
Expand Down
7 changes: 6 additions & 1 deletion cmd/zpool/zpool_iter.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ pool_list_get(int argc, char **argv, zprop_list_t **proplist, zfs_type_t type,
boolean_t literal, int *err)
{
zpool_list_t *zlp;
int rc;

zlp = safe_malloc(sizeof (zpool_list_t));

Expand All @@ -137,7 +138,11 @@ pool_list_get(int argc, char **argv, zprop_list_t **proplist, zfs_type_t type,
zlp->zl_literal = literal;

if (argc == 0) {
(void) zpool_iter(g_zfs, add_pool, zlp);
rc = zpool_iter(g_zfs, add_pool, zlp);
if (rc != 0) {
free(zlp);
return (NULL);
}
zlp->zl_findall = B_TRUE;
} else {
int i;
Expand Down
28 changes: 28 additions & 0 deletions cmd/zpool/zpool_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10979,6 +10979,32 @@ status_callback(zpool_handle_t *zhp, void *data)
return (0);
}

/*
* Set the zpool status lock behavior based off of the ZPOOL_LOCK_BEHAVIOR
* envvar. If the var is not set, or an unknown value, then set the lock
* behavior to ZPOOL_LOCK_BEHAVIOR_DEFAULT.
*/
static void
zpool_set_lock_behavior(void)
{
char *str;
zpool_lock_behavior_t zpool_lock_behavior;

str = getenv("ZPOOL_LOCK_BEHAVIOR");
if (str == NULL)
zpool_lock_behavior = ZPOOL_LOCK_BEHAVIOR_DEFAULT;
else if (strcmp(str, "wait") == 0)
zpool_lock_behavior = ZPOOL_LOCK_BEHAVIOR_WAIT;
else if (strcmp(str, "trylock") == 0)
zpool_lock_behavior = ZPOOL_LOCK_BEHAVIOR_TRYLOCK;
else if (strcmp(str, "lockless") == 0)
zpool_lock_behavior = ZPOOL_LOCK_BEHAVIOR_LOCKLESS;
else
zpool_lock_behavior = ZPOOL_LOCK_BEHAVIOR_DEFAULT;

libzfs_set_lock_behavior(g_zfs, zpool_lock_behavior);
}

/*
* zpool status [-c [script1,script2,...]] [-dDegiLpPstvx] [--power] ...
* [-T d|u] [pool] [interval [count]]
Expand Down Expand Up @@ -11152,6 +11178,8 @@ zpool_do_status(int argc, char **argv)
usage(B_FALSE);
}

zpool_set_lock_behavior();

for (;;) {
if (cb.cb_json) {
cb.cb_jsobj = zpool_json_schema(0, 1);
Expand Down
2 changes: 2 additions & 0 deletions include/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ _LIBZFS_H int zpool_create(libzfs_handle_t *, const char *, nvlist_t *,
nvlist_t *, nvlist_t *);
_LIBZFS_H int zpool_destroy(zpool_handle_t *, const char *);
_LIBZFS_H int zpool_add(zpool_handle_t *, nvlist_t *, boolean_t check_ashift);
_LIBZFS_H void libzfs_set_lock_behavior(libzfs_handle_t *,
zpool_lock_behavior_t);

typedef struct splitflags {
/* do not split, but return the config that would be split off */
Expand Down
15 changes: 15 additions & 0 deletions include/os/freebsd/spl/sys/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,19 @@ typedef enum {
#define mutex_owned(lock) sx_xlocked(lock)
#define mutex_owner(lock) sx_xholder(lock)

/*
* Poor-man's version of Linux kernel's down_timeout(). Try to acquire a mutex
* for 'ns' number of nanoseconds. Returns 0 if mutex was acquired or ETIME
* if timeout occurred.
*/
static inline int mutex_enter_timeout(kmutex_t *mutex, uint64_t ns)
{
hrtime_t end = gethrtime() + ns;
while (gethrtime() < end) {
if (mutex_tryenter(mutex))
return (0); /* success */
}
return (ETIME);
}

#endif /* _OPENSOLARIS_SYS_MUTEX_H_ */
16 changes: 16 additions & 0 deletions include/os/linux/spl/sys/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define _SPL_MUTEX_H

#include <sys/types.h>
#include <sys/time.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/lockdep.h>
Expand Down Expand Up @@ -187,4 +188,19 @@ spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
/* NOTE: do not dereference mp after this point */ \
}

/*
* Poor-man's version of Linux kernel's down_timeout(). Try to acquire a mutex
* for 'ns' number of nanoseconds. Returns 0 if mutex was acquired or ETIME
* if timeout occurred.
*/
static inline int mutex_enter_timeout(kmutex_t *mutex, uint64_t ns)
{
hrtime_t end = gethrtime() + ns;
while (gethrtime() < end) {
if (mutex_tryenter(mutex))
return (0); /* success */
}
return (ETIME);
}

#endif /* _SPL_MUTEX_H */
27 changes: 27 additions & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,9 @@ typedef struct zpool_load_policy {
#define ZPOOL_CONFIG_REBUILD_STATS "org.openzfs:rebuild_stats"
#define ZPOOL_CONFIG_COMPATIBILITY "compatibility"

/* ZFS_IOC_POOL_STATS argument to for spa_namespace locking behavior */
#define ZPOOL_CONFIG_LOCK_BEHAVIOR "lock_behavior" /* not stored on disk */

/*
* The persistent vdev state is stored as separate values rather than a single
* 'vdev_state' entry. This is because a device can be in multiple states, such
Expand Down Expand Up @@ -1984,6 +1987,30 @@ enum zio_encrypt {
ZFS_XA_NS_PREFIX_MATCH(LINUX_TRUSTED, name) || \
ZFS_XA_NS_PREFIX_MATCH(LINUX_USER, name))

/*
* Set locking behavior for zpool commands.
*/
typedef enum {
/* Wait to acquire the lock on the zpool config */
ZPOOL_LOCK_BEHAVIOR_WAIT = 0,
ZPOOL_LOCK_BEHAVIOR_DEFAULT = ZPOOL_LOCK_BEHAVIOR_WAIT,
/*
* Return an error if it's taking an unnecessarily long time to
* acquire the lock on the pool config (default 100ms)
*/
ZPOOL_LOCK_BEHAVIOR_TRYLOCK = 1,

/*
* DANGER: THIS CAN CRASH YOUR SYSTEM
*
* If you can't acquire the pool config lock after 100ms then do a
* a lockless lookup. This should only be done in emergencies, as it
* can crash the kernel module!
*/
ZPOOL_LOCK_BEHAVIOR_LOCKLESS = 2,
ZPOOL_LOCK_BEHAVIOR_END = 3 /* last entry marker */
} zpool_lock_behavior_t;

#ifdef __cplusplus
}
#endif
Expand Down
12 changes: 10 additions & 2 deletions include/sys/spa.h
Original file line number Diff line number Diff line change
Expand Up @@ -742,10 +742,13 @@ typedef enum trim_type {

/* state manipulation functions */
extern int spa_open(const char *pool, spa_t **, const void *tag);
extern int spa_open_common_lock_behavior(const char *pool, spa_t **spapp,
const void *tag, nvlist_t *nvpolicy, nvlist_t **config,
zpool_lock_behavior_t zpool_lock_behavior);
extern int spa_open_rewind(const char *pool, spa_t **, const void *tag,
nvlist_t *policy, nvlist_t **config);
extern int spa_get_stats(const char *pool, nvlist_t **config, char *altroot,
size_t buflen);
size_t buflen, zpool_lock_behavior_t zpool_lock_behavior);
extern int spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
nvlist_t *zplprops, struct dsl_crypto_params *dcp);
extern int spa_import(char *pool, nvlist_t *config, nvlist_t *props,
Expand Down Expand Up @@ -851,10 +854,13 @@ extern kcondvar_t spa_namespace_cv;

extern void spa_write_cachefile(spa_t *, boolean_t, boolean_t, boolean_t);
extern void spa_config_load(void);
extern int spa_all_configs(uint64_t *generation, nvlist_t **pools);
extern int spa_all_configs(uint64_t *generation, nvlist_t **pools,
zpool_lock_behavior_t zpool_lock_behavior);
extern void spa_config_set(spa_t *spa, nvlist_t *config);
extern nvlist_t *spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg,
int getstats);
extern nvlist_t *spa_config_generate_lock_behavior(spa_t *spa, vdev_t *vd,
uint64_t txg, int getstats, zpool_lock_behavior_t zpool_lock_behavior);
extern void spa_config_update(spa_t *spa, int what);
extern int spa_config_parse(spa_t *spa, vdev_t **vdp, nvlist_t *nv,
vdev_t *parent, uint_t id, int atype);
Expand All @@ -866,9 +872,11 @@ extern int spa_config_parse(spa_t *spa, vdev_t **vdp, nvlist_t *nv,

/* Namespace manipulation */
extern spa_t *spa_lookup(const char *name);
extern spa_t *spa_lookup_lockless(const char *name);
extern spa_t *spa_add(const char *name, nvlist_t *config, const char *altroot);
extern void spa_remove(spa_t *spa);
extern spa_t *spa_next(spa_t *prev);
extern spa_t *spa_next_lockless(spa_t *prev);

/* Refcount functions */
extern void spa_open_ref(spa_t *spa, const void *tag);
Expand Down
1 change: 1 addition & 0 deletions include/sys/spa_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ extern void spa_set_deadman_synctime(hrtime_t ns);
extern void spa_set_deadman_ziotime(hrtime_t ns);
extern const char *spa_history_zone(void);
extern const char *zfs_active_allocator;
extern unsigned int spa_namespace_trylock_ms;
extern int param_set_active_allocator_common(const char *val);

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions include/sys/zfs_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ extern void mutex_enter(kmutex_t *mp);
extern int mutex_enter_check_return(kmutex_t *mp);
extern void mutex_exit(kmutex_t *mp);
extern int mutex_tryenter(kmutex_t *mp);
extern int mutex_enter_timeout(kmutex_t *mp, uint64_t ns);

#define NESTED_SINGLE 1
#define mutex_enter_nested(mp, class) mutex_enter(mp)
Expand Down
56 changes: 37 additions & 19 deletions lib/libzfs/libzfs.abi
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
<elf-symbol name='libzfs_run_process' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_run_process_get_stdout' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_run_process_get_stdout_nopath' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='libzfs_set_lock_behavior' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_create' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_destroy' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='list_head' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
Expand Down Expand Up @@ -2073,6 +2074,15 @@
<enumerator name='ZPROP_SRC_RECEIVED' value='32'/>
</enum-decl>
<typedef-decl name='zprop_source_t' type-id='5903f80e' id='a2256d42'/>
<enum-decl name='zpool_lock_behavior_t' naming-typedef-id='8b691302' id='cdf5aa2e'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='ZPOOL_LOCK_BEHAVIOR_WAIT' value='0'/>
<enumerator name='ZPOOL_LOCK_BEHAVIOR_DEFAULT' value='0'/>
<enumerator name='ZPOOL_LOCK_BEHAVIOR_TRYLOCK' value='1'/>
<enumerator name='ZPOOL_LOCK_BEHAVIOR_LOCKLESS' value='2'/>
<enumerator name='ZPOOL_LOCK_BEHAVIOR_END' value='3'/>
</enum-decl>
<typedef-decl name='zpool_lock_behavior_t' type-id='cdf5aa2e' id='8b691302'/>
<class-decl name='nvlist' size-in-bits='192' is-struct='yes' visibility='default' id='ac266fd9'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='nvl_version' type-id='3ff5601b' visibility='default'/>
Expand Down Expand Up @@ -2212,7 +2222,7 @@
<typedef-decl name='__uint32_t' type-id='f0981eeb' id='62f1140c'/>
<typedef-decl name='__uint64_t' type-id='7359adad' id='8910171f'/>
<typedef-decl name='size_t' type-id='7359adad' id='b59d7dce'/>
<class-decl name='libzfs_handle' size-in-bits='18240' is-struct='yes' visibility='default' id='c8a9d9d8'>
<class-decl name='libzfs_handle' size-in-bits='18304' is-struct='yes' visibility='default' id='c8a9d9d8'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='libzfs_error' type-id='95e97e5e' visibility='default'/>
</data-member>
Expand Down Expand Up @@ -2270,6 +2280,9 @@
<data-member access='public' layout-offset-in-bits='18176'>
<var-decl name='libfetch_load_error' type-id='26a90f95' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='18240'>
<var-decl name='zpool_lock_behavior' type-id='8b691302' visibility='default'/>
</data-member>
</class-decl>
<class-decl name='zfs_handle' size-in-bits='4928' is-struct='yes' visibility='default' id='f6ee4445'>
<data-member access='public' layout-offset-in-bits='0'>
Expand Down Expand Up @@ -2949,6 +2962,12 @@
<parameter type-id='b65f7fd1'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_alloc' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='857bb57e'/>
<parameter type-id='3502e3ff'/>
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_free' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
Expand All @@ -2959,6 +2978,12 @@
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9c313c2d'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_lookup_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
Expand Down Expand Up @@ -3054,6 +3079,12 @@
<parameter type-id='b59d7dce'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zcmd_write_src_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='b0382bb3'/>
<parameter type-id='e4ec4540'/>
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zcmd_expand_dst_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='b0382bb3'/>
<parameter type-id='e4ec4540'/>
Expand Down Expand Up @@ -3563,12 +3594,6 @@
<parameter type-id='80f4b756'/>
<return type-id='58603c44'/>
</function-decl>
<function-decl name='nvlist_add_uint64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9c313c2d'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_string' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
Expand Down Expand Up @@ -4324,12 +4349,6 @@
<parameter type-id='c19b74c3'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='nvlist_alloc' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='857bb57e'/>
<parameter type-id='3502e3ff'/>
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_size' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='78c01427'/>
Expand Down Expand Up @@ -4948,12 +4967,6 @@
<parameter type-id='2e45de5d'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zcmd_write_src_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='b0382bb3'/>
<parameter type-id='e4ec4540'/>
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='changelist_prefix' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='0d41d328'/>
<return type-id='95e97e5e'/>
Expand Down Expand Up @@ -8550,6 +8563,11 @@
<parameter type-id='7292109c' name='lines_cnt'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='libzfs_set_lock_behavior' mangled-name='libzfs_set_lock_behavior' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='libzfs_set_lock_behavior'>
<parameter type-id='b0382bb3' name='hdl'/>
<parameter type-id='8b691302' name='zpool_lock_behavior'/>
<return type-id='48b5725f'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfs/os/linux/libzfs_mount_os.c' language='LANG_C99'>
<pointer-type-def type-id='7359adad' size-in-bits='64' id='1d2c2b85'/>
Expand Down
Loading
Loading