Print this page
4045 zfs write throttle & i/o scheduler performance work
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Christopher Siden <christopher.siden@delphix.com>
*** 582,592 ****
return (myspace);
}
struct tempreserve {
list_node_t tr_node;
- dsl_pool_t *tr_dp;
dsl_dir_t *tr_ds;
uint64_t tr_size;
};
static int
--- 582,591 ----
*** 733,761 ****
struct tempreserve *tr;
tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
tr->tr_size = lsize;
list_insert_tail(tr_list, tr);
-
- err = dsl_pool_tempreserve_space(dd->dd_pool, asize, tx);
} else {
if (err == EAGAIN) {
txg_delay(dd->dd_pool, tx->tx_txg,
MSEC2NSEC(10), MSEC2NSEC(10));
err = SET_ERROR(ERESTART);
}
- dsl_pool_memory_pressure(dd->dd_pool);
}
if (err == 0) {
- struct tempreserve *tr;
-
- tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
- tr->tr_dp = dd->dd_pool;
- tr->tr_size = asize;
- list_insert_tail(tr_list, tr);
-
err = dsl_dir_tempreserve_impl(dd, asize, fsize >= asize,
FALSE, asize > usize, tr_list, tx, TRUE);
}
if (err != 0)
--- 732,759 ----
struct tempreserve *tr;
tr = kmem_zalloc(sizeof (struct tempreserve), KM_SLEEP);
tr->tr_size = lsize;
list_insert_tail(tr_list, tr);
} else {
if (err == EAGAIN) {
+ /*
+ * If arc_memory_throttle() detected that pageout
+ * is running and we are low on memory, we delay new
+ * non-pageout transactions to give pageout an
+ * advantage.
+ *
+ * It is unfortunate to be delaying while the caller's
+ * locks are held.
+ */
txg_delay(dd->dd_pool, tx->tx_txg,
MSEC2NSEC(10), MSEC2NSEC(10));
err = SET_ERROR(ERESTART);
}
}
if (err == 0) {
err = dsl_dir_tempreserve_impl(dd, asize, fsize >= asize,
FALSE, asize > usize, tr_list, tx, TRUE);
}
if (err != 0)
*** 780,793 ****
ASSERT3U(tx->tx_txg, !=, 0);
if (tr_cookie == NULL)
return;
! while (tr = list_head(tr_list)) {
! if (tr->tr_dp) {
! dsl_pool_tempreserve_clear(tr->tr_dp, tr->tr_size, tx);
! } else if (tr->tr_ds) {
mutex_enter(&tr->tr_ds->dd_lock);
ASSERT3U(tr->tr_ds->dd_tempreserved[txgidx], >=,
tr->tr_size);
tr->tr_ds->dd_tempreserved[txgidx] -= tr->tr_size;
mutex_exit(&tr->tr_ds->dd_lock);
--- 778,789 ----
ASSERT3U(tx->tx_txg, !=, 0);
if (tr_cookie == NULL)
return;
! while ((tr = list_head(tr_list)) != NULL) {
! if (tr->tr_ds) {
mutex_enter(&tr->tr_ds->dd_lock);
ASSERT3U(tr->tr_ds->dd_tempreserved[txgidx], >=,
tr->tr_size);
tr->tr_ds->dd_tempreserved[txgidx] -= tr->tr_size;
mutex_exit(&tr->tr_ds->dd_lock);
*** 799,810 ****
}
kmem_free(tr_list, sizeof (list_t));
}
! static void
! dsl_dir_willuse_space_impl(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
{
int64_t parent_space;
uint64_t est_used;
mutex_enter(&dd->dd_lock);
--- 795,812 ----
}
kmem_free(tr_list, sizeof (list_t));
}
! /*
! * This should be called from open context when we think we're going to write
! * or free space, for example when dirtying data. Be conservative; it's okay
! * to write less space or free more, but we don't want to write more or free
! * less than the amount specified.
! */
! void
! dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
{
int64_t parent_space;
uint64_t est_used;
mutex_enter(&dd->dd_lock);
*** 818,842 ****
/* Make sure that we clean up dd_space_to* */
dsl_dir_dirty(dd, tx);
/* XXX this is potentially expensive and unnecessary... */
if (parent_space && dd->dd_parent)
! dsl_dir_willuse_space_impl(dd->dd_parent, parent_space, tx);
}
- /*
- * Call in open context when we think we're going to write/free space,
- * eg. when dirtying data. Be conservative (ie. OK to write less than
- * this or free more than this, but don't write more or free less).
- */
- void
- dsl_dir_willuse_space(dsl_dir_t *dd, int64_t space, dmu_tx_t *tx)
- {
- dsl_pool_willuse_space(dd->dd_pool, space, tx);
- dsl_dir_willuse_space_impl(dd, space, tx);
- }
-
/* call from syncing context when we actually write/free space for this dd */
void
dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
int64_t used, int64_t compressed, int64_t uncompressed, dmu_tx_t *tx)
{
--- 820,832 ----
/* Make sure that we clean up dd_space_to* */
dsl_dir_dirty(dd, tx);
/* XXX this is potentially expensive and unnecessary... */
if (parent_space && dd->dd_parent)
! dsl_dir_willuse_space(dd->dd_parent, parent_space, tx);
}
/* call from syncing context when we actually write/free space for this dd */
void
dsl_dir_diduse_space(dsl_dir_t *dd, dd_used_t type,
int64_t used, int64_t compressed, int64_t uncompressed, dmu_tx_t *tx)
{