Skip to content

txg: generalise txg_wait_synced_sig() to txg_wait_synced_flags() #17284

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

Merged
merged 1 commit into from
May 2, 2025
Merged
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
23 changes: 20 additions & 3 deletions include/sys/txg.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ typedef struct txg_list {
txg_node_t *tl_head[TXG_SIZE];
} txg_list_t;

/*
* Wait flags for txg_wait_synced_flags(). By default (TXG_WAIT_NONE), it will
* wait until the wanted txg is reached, or block forever. Additional flags
* indicate other conditions that the caller is interested in, that will cause
* the wait to break and return an error code describing the condition.
*/
typedef enum {
/* No special flags. Guaranteed to block forever or return 0 */
TXG_WAIT_NONE = 0,

/* If a signal arrives while waiting, abort and return EINTR */
TXG_WAIT_SIGNAL = (1 << 0),
} txg_wait_flag_t;

struct dsl_pool;

extern void txg_init(struct dsl_pool *dp, uint64_t txg);
Expand All @@ -86,13 +100,16 @@ extern void txg_kick(struct dsl_pool *dp, uint64_t txg);
* Try to make this happen as soon as possible (eg. kick off any
* necessary syncs immediately). If txg==0, wait for the currently open
* txg to finish syncing.
* See txg_wait_flag_t above for a description of how the flags affect the wait.
*/
extern void txg_wait_synced(struct dsl_pool *dp, uint64_t txg);
extern int txg_wait_synced_flags(struct dsl_pool *dp, uint64_t txg,
txg_wait_flag_t flags);

/*
* Wait as above. Returns true if the thread was signaled while waiting.
* Traditional form of txg_wait_synced_flags, waits forever.
* Shorthand for VERIFY0(txg_wait_synced_flags(dp, TXG_WAIT_NONE))
*/
extern boolean_t txg_wait_synced_sig(struct dsl_pool *dp, uint64_t txg);
extern void txg_wait_synced(struct dsl_pool *dp, uint64_t txg);

/*
* Wait until the given transaction group, or one after it, is
Expand Down
19 changes: 13 additions & 6 deletions module/zfs/dsl_synctask.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,19 @@ dsl_sync_task_common(const char *pool, dsl_checkfunc_t *checkfunc,

dmu_tx_commit(tx);

if (sigfunc != NULL && txg_wait_synced_sig(dp, dst.dst_txg)) {
/* current contract is to call func once */
sigfunc(arg, tx);
sigfunc = NULL; /* in case we're performing an EAGAIN retry */
}
txg_wait_synced(dp, dst.dst_txg);
if (sigfunc != NULL) {
err = txg_wait_synced_flags(dp, dst.dst_txg, TXG_WAIT_SIGNAL);
if (err != 0) {
VERIFY3U(err, ==, EINTR);
/* current contract is to call func once */
sigfunc(arg, tx);
/* in case we're performing an EAGAIN retry */
sigfunc = NULL;

txg_wait_synced(dp, dst.dst_txg);
}
} else
txg_wait_synced(dp, dst.dst_txg);

if (dst.dst_error == EAGAIN) {
txg_wait_synced(dp, dst.dst_txg + TXG_DEFER_SIZE);
Expand Down
34 changes: 17 additions & 17 deletions module/zfs/txg.c
Original file line number Diff line number Diff line change
Expand Up @@ -699,11 +699,13 @@ txg_delay(dsl_pool_t *dp, uint64_t txg, hrtime_t delay, hrtime_t resolution)
mutex_exit(&tx->tx_sync_lock);
}

static boolean_t
txg_wait_synced_impl(dsl_pool_t *dp, uint64_t txg, boolean_t wait_sig)
int
txg_wait_synced_flags(dsl_pool_t *dp, uint64_t txg, txg_wait_flag_t flags)
{
int error = 0;
tx_state_t *tx = &dp->dp_tx;

ASSERT0(flags & ~TXG_WAIT_SIGNAL);
ASSERT(!dsl_pool_config_held(dp));

mutex_enter(&tx->tx_sync_lock);
Expand All @@ -715,45 +717,43 @@ txg_wait_synced_impl(dsl_pool_t *dp, uint64_t txg, boolean_t wait_sig)
dprintf("txg=%llu quiesce_txg=%llu sync_txg=%llu\n",
(u_longlong_t)txg, (u_longlong_t)tx->tx_quiesce_txg_waiting,
(u_longlong_t)tx->tx_sync_txg_waiting);

/*
* Keep pushing util the pool gets to the wanted txg. If something
* else interesting happens, we'll set an error and break out.
*/
while (tx->tx_synced_txg < txg) {
dprintf("broadcasting sync more "
"tx_synced=%llu waiting=%llu dp=%px\n",
(u_longlong_t)tx->tx_synced_txg,
(u_longlong_t)tx->tx_sync_txg_waiting, dp);
cv_broadcast(&tx->tx_sync_more_cv);
if (wait_sig) {

if (flags & TXG_WAIT_SIGNAL) {
/*
* Condition wait here but stop if the thread receives a
* signal. The caller may call txg_wait_synced*() again
* to resume waiting for this txg.
*/
if (cv_wait_io_sig(&tx->tx_sync_done_cv,
&tx->tx_sync_lock) == 0) {
mutex_exit(&tx->tx_sync_lock);
return (B_TRUE);
error = SET_ERROR(EINTR);
break;
}
} else {
/* Uninterruptable wait, until the condvar fires */
cv_wait_io(&tx->tx_sync_done_cv, &tx->tx_sync_lock);
}
}

mutex_exit(&tx->tx_sync_lock);
return (B_FALSE);
return (error);
}

void
txg_wait_synced(dsl_pool_t *dp, uint64_t txg)
{
VERIFY0(txg_wait_synced_impl(dp, txg, B_FALSE));
}

/*
* Similar to a txg_wait_synced but it can be interrupted from a signal.
* Returns B_TRUE if the thread was signaled while waiting.
*/
boolean_t
txg_wait_synced_sig(dsl_pool_t *dp, uint64_t txg)
{
return (txg_wait_synced_impl(dp, txg, B_TRUE));
VERIFY0(txg_wait_synced_flags(dp, txg, TXG_WAIT_NONE));
}

/*
Expand Down
4 changes: 2 additions & 2 deletions module/zfs/zcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -970,8 +970,8 @@ zcp_pool_error(zcp_run_info_t *ri, const char *poolname, int error)
}

/*
* This callback is called when txg_wait_synced_sig encountered a signal.
* The txg_wait_synced_sig will continue to wait for the txg to complete
* This callback is called when txg_wait_synced_flags encountered a signal.
* The txg_wait_synced_flags will continue to wait for the txg to complete
* after calling this callback.
*/
static void
Expand Down
Loading