Skip to content

Commit 97a0b5b

Browse files
authored
Add mutex_enter_interruptible() for interruptible sleeping IOCTLs
Many long-running ZFS ioctls lock the spa_namespace_lock, forcing concurrent ioctls to sleep for the mutex. Previously, the only option is to call mutex_enter() which sleeps uninterruptibly. This is a usability issue for sysadmins, for example, if the admin runs `zpool status` while a slow `zpool import` is ongoing, the admin's shell will be locked in uninterruptible sleep for a long time. This patch resolves this admin usability issue by introducing mutex_enter_interruptible() which sleeps interruptibly while waiting to acquire a lock. It is implemented for both Linux and FreeBSD. The ZFS_IOC_POOL_CONFIGS ioctl, used by `zpool status`, is changed to use this new macro so that the command can be interrupted if it is issued during a concurrent `zpool import` (or other long-running operation). Reviewed-by: Tony Hutter <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Thomas Bertschinger <[email protected]> Closes #15360
1 parent 6a629f3 commit 97a0b5b

File tree

7 files changed

+38
-19
lines changed

7 files changed

+38
-19
lines changed

include/os/freebsd/spl/sys/mutex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ typedef enum {
6464
} while (0)
6565
#define mutex_destroy(lock) sx_destroy(lock)
6666
#define mutex_enter(lock) sx_xlock(lock)
67+
#define mutex_enter_interruptible(lock) sx_xlock_sig(lock)
6768
#define mutex_enter_nested(lock, type) sx_xlock(lock)
6869
#define mutex_tryenter(lock) sx_try_xlock(lock)
6970
#define mutex_exit(lock) sx_xunlock(lock)

include/os/linux/spl/sys/mutex.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
128128

129129
#define NESTED_SINGLE 1
130130

131-
#ifdef CONFIG_DEBUG_LOCK_ALLOC
132131
#define mutex_enter_nested(mp, subclass) \
133132
{ \
134133
ASSERT3P(mutex_owner(mp), !=, current); \
@@ -137,16 +136,22 @@ spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
137136
spl_mutex_lockdep_on_maybe(mp); \
138137
spl_mutex_set_owner(mp); \
139138
}
140-
#else /* CONFIG_DEBUG_LOCK_ALLOC */
141-
#define mutex_enter_nested(mp, subclass) \
142-
{ \
139+
140+
#define mutex_enter_interruptible(mp) \
141+
/* CSTYLED */ \
142+
({ \
143+
int _rc_; \
144+
\
143145
ASSERT3P(mutex_owner(mp), !=, current); \
144146
spl_mutex_lockdep_off_maybe(mp); \
145-
mutex_lock(MUTEX(mp)); \
147+
_rc_ = mutex_lock_interruptible(MUTEX(mp)); \
146148
spl_mutex_lockdep_on_maybe(mp); \
147-
spl_mutex_set_owner(mp); \
148-
}
149-
#endif /* CONFIG_DEBUG_LOCK_ALLOC */
149+
if (!_rc_) { \
150+
spl_mutex_set_owner(mp); \
151+
} \
152+
\
153+
_rc_; \
154+
})
150155

151156
#define mutex_enter(mp) mutex_enter_nested((mp), 0)
152157

include/sys/spa.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ extern kmutex_t spa_namespace_lock;
837837

838838
extern void spa_write_cachefile(spa_t *, boolean_t, boolean_t, boolean_t);
839839
extern void spa_config_load(void);
840-
extern nvlist_t *spa_all_configs(uint64_t *);
840+
extern int spa_all_configs(uint64_t *generation, nvlist_t **pools);
841841
extern void spa_config_set(spa_t *spa, nvlist_t *config);
842842
extern nvlist_t *spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg,
843843
int getstats);

include/sys/zfs_context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,13 @@ typedef struct kmutex {
274274
extern void mutex_init(kmutex_t *mp, char *name, int type, void *cookie);
275275
extern void mutex_destroy(kmutex_t *mp);
276276
extern void mutex_enter(kmutex_t *mp);
277+
extern int mutex_enter_check_return(kmutex_t *mp);
277278
extern void mutex_exit(kmutex_t *mp);
278279
extern int mutex_tryenter(kmutex_t *mp);
279280

280281
#define NESTED_SINGLE 1
281282
#define mutex_enter_nested(mp, class) mutex_enter(mp)
283+
#define mutex_enter_interruptible(mp) mutex_enter_check_return(mp)
282284
/*
283285
* RW locks
284286
*/

lib/libzpool/kernel.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ mutex_enter(kmutex_t *mp)
205205
mp->m_owner = pthread_self();
206206
}
207207

208+
int
209+
mutex_enter_check_return(kmutex_t *mp)
210+
{
211+
int error = pthread_mutex_lock(&mp->m_lock);
212+
if (error == 0)
213+
mp->m_owner = pthread_self();
214+
return (error);
215+
}
216+
208217
int
209218
mutex_tryenter(kmutex_t *mp)
210219
{

module/zfs/spa_config.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -367,31 +367,32 @@ spa_write_cachefile(spa_t *target, boolean_t removing, boolean_t postsysevent,
367367
* So we have to invent the ZFS_IOC_CONFIG ioctl to grab the configuration
368368
* information for all pool visible within the zone.
369369
*/
370-
nvlist_t *
371-
spa_all_configs(uint64_t *generation)
370+
int
371+
spa_all_configs(uint64_t *generation, nvlist_t **pools)
372372
{
373-
nvlist_t *pools;
374373
spa_t *spa = NULL;
375374

376375
if (*generation == spa_config_generation)
377-
return (NULL);
376+
return (SET_ERROR(EEXIST));
378377

379-
pools = fnvlist_alloc();
378+
int error = mutex_enter_interruptible(&spa_namespace_lock);
379+
if (error)
380+
return (SET_ERROR(EINTR));
380381

381-
mutex_enter(&spa_namespace_lock);
382+
*pools = fnvlist_alloc();
382383
while ((spa = spa_next(spa)) != NULL) {
383384
if (INGLOBALZONE(curproc) ||
384385
zone_dataset_visible(spa_name(spa), NULL)) {
385386
mutex_enter(&spa->spa_props_lock);
386-
fnvlist_add_nvlist(pools, spa_name(spa),
387+
fnvlist_add_nvlist(*pools, spa_name(spa),
387388
spa->spa_config);
388389
mutex_exit(&spa->spa_props_lock);
389390
}
390391
}
391392
*generation = spa_config_generation;
392393
mutex_exit(&spa_namespace_lock);
393394

394-
return (pools);
395+
return (0);
395396
}
396397

397398
void

module/zfs/zfs_ioctl.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,8 +1582,9 @@ zfs_ioc_pool_configs(zfs_cmd_t *zc)
15821582
nvlist_t *configs;
15831583
int error;
15841584

1585-
if ((configs = spa_all_configs(&zc->zc_cookie)) == NULL)
1586-
return (SET_ERROR(EEXIST));
1585+
error = spa_all_configs(&zc->zc_cookie, &configs);
1586+
if (error)
1587+
return (error);
15871588

15881589
error = put_nvlist(zc, configs);
15891590

0 commit comments

Comments
 (0)