* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
* Copyright (c) 2019 Datto Inc.
* Copyright (c) 2019, 2020 by Christian Schwarz. All rights reserved.
- * Copyright (c) 2019, 2021, Klara Inc.
+ * Copyright (c) 2019, 2021, 2024, Klara Inc.
* Copyright (c) 2019, Allan Jude
* Copyright 2024 Oxide Computer Company
*/
return (error);
}
+/*
+ * When stack space is limited, we write replication stream data to the target
+ * on a separate taskq thread, to make sure there's enough stack space.
+ */
+#ifndef HAVE_LARGE_STACKS
+#define USE_SEND_TASKQ 1
+#endif
+
typedef struct dump_bytes_io {
zfs_file_t *dbi_fp;
caddr_t dbi_buf;
dbi->dbi_err = zfs_file_write(fp, buf, dbi->dbi_len, NULL);
}
+typedef struct dump_bytes_arg {
+ zfs_file_t *dba_fp;
+#ifdef USE_SEND_TASKQ
+ taskq_t *dba_tq;
+ taskq_ent_t dba_tqent;
+#endif
+} dump_bytes_arg_t;
+
static int
dump_bytes(objset_t *os, void *buf, int len, void *arg)
{
+ dump_bytes_arg_t *dba = (dump_bytes_arg_t *)arg;
dump_bytes_io_t dbi;
- dbi.dbi_fp = arg;
+ dbi.dbi_fp = dba->dba_fp;
dbi.dbi_buf = buf;
dbi.dbi_len = len;
-#if defined(HAVE_LARGE_STACKS)
- dump_bytes_cb(&dbi);
+#ifdef USE_SEND_TASKQ
+ taskq_dispatch_ent(dba->dba_tq, dump_bytes_cb, &dbi, TQ_SLEEP,
+ &dba->dba_tqent);
+ taskq_wait(dba->dba_tq);
#else
- /*
- * The vn_rdwr() call is performed in a taskq to ensure that there is
- * always enough stack space to write safely to the target filesystem.
- * The ZIO_TYPE_FREE threads are used because there can be a lot of
- * them and they are used in vdev_file.c for a similar purpose.
- */
- spa_taskq_dispatch_sync(dmu_objset_spa(os), ZIO_TYPE_FREE,
- ZIO_TASKQ_ISSUE, dump_bytes_cb, &dbi, TQ_SLEEP);
-#endif /* HAVE_LARGE_STACKS */
+ dump_bytes_cb(&dbi);
+#endif
return (dbi.dbi_err);
}
+static int
+dump_bytes_init(dump_bytes_arg_t *dba, int fd, dmu_send_outparams_t *out)
+{
+ zfs_file_t *fp = zfs_file_get(fd);
+ if (fp == NULL)
+ return (SET_ERROR(EBADF));
+
+ dba->dba_fp = fp;
+#ifdef USE_SEND_TASKQ
+ dba->dba_tq = taskq_create("z_send", 1, defclsyspri, 0, 0, 0);
+ taskq_init_ent(&dba->dba_tqent);
+#endif
+
+ memset(out, 0, sizeof (dmu_send_outparams_t));
+ out->dso_outfunc = dump_bytes;
+ out->dso_arg = dba;
+ out->dso_dryrun = B_FALSE;
+
+ return (0);
+}
+
+static void
+dump_bytes_fini(dump_bytes_arg_t *dba)
+{
+ zfs_file_put(dba->dba_fp);
+#ifdef USE_SEND_TASKQ
+ taskq_destroy(dba->dba_tq);
+#endif
+}
+
/*
* inputs:
* zc_name name of snapshot to send
dsl_dataset_rele(tosnap, FTAG);
dsl_pool_rele(dp, FTAG);
} else {
- zfs_file_t *fp;
- dmu_send_outparams_t out = {0};
-
- if ((fp = zfs_file_get(zc->zc_cookie)) == NULL)
- return (SET_ERROR(EBADF));
+ dump_bytes_arg_t dba;
+ dmu_send_outparams_t out;
+ error = dump_bytes_init(&dba, zc->zc_cookie, &out);
+ if (error)
+ return (error);
- off = zfs_file_off(fp);
- out.dso_outfunc = dump_bytes;
- out.dso_arg = fp;
- out.dso_dryrun = B_FALSE;
+ off = zfs_file_off(dba.dba_fp);
error = dmu_send_obj(zc->zc_name, zc->zc_sendobj,
zc->zc_fromobj, embedok, large_block_ok, compressok,
rawok, savedok, zc->zc_cookie, &off, &out);
- zfs_file_put(fp);
+ dump_bytes_fini(&dba);
}
return (error);
}
offset_t off;
const char *fromname = NULL;
int fd;
- zfs_file_t *fp;
boolean_t largeblockok;
boolean_t embedok;
boolean_t compressok;
(void) nvlist_lookup_string(innvl, "redactbook", &redactbook);
- if ((fp = zfs_file_get(fd)) == NULL)
- return (SET_ERROR(EBADF));
-
- off = zfs_file_off(fp);
+ dump_bytes_arg_t dba;
+ dmu_send_outparams_t out;
+ error = dump_bytes_init(&dba, fd, &out);
+ if (error)
+ return (error);
- dmu_send_outparams_t out = {0};
- out.dso_outfunc = dump_bytes;
- out.dso_arg = fp;
- out.dso_dryrun = B_FALSE;
+ off = zfs_file_off(dba.dba_fp);
error = dmu_send(snapname, fromname, embedok, largeblockok,
compressok, rawok, savedok, resumeobj, resumeoff,
redactbook, fd, &off, &out);
- zfs_file_put(fp);
+ dump_bytes_fini(&dba);
+
return (error);
}