+
+int journal_uses_fua(journal *jnl)
+{
+ if (jnl->flags & JOURNAL_DO_FUA_WRITES)
+ return 1;
+ return 0;
+}
+
+/*
+ * Relocate the journal.
+ *
+ * You provide the new starting offset and size for the journal. You may
+ * optionally provide a new tbuffer_size; passing zero defaults to not
+ * changing the tbuffer size except as needed to fit within the new journal
+ * size.
+ *
+ * You must have already started a transaction. The transaction may contain
+ * modified blocks (such as those needed to deallocate the old journal,
+ * allocate the new journal, and update the location and size of the journal
+ * in filesystem-private structures). Any transactions prior to the active
+ * transaction will be flushed to the old journal. The new journal will be
+ * initialized, and the blocks from the active transaction will be written to
+ * the new journal.
+ *
+ * The caller will need to update the structures that identify the location
+ * and size of the journal. These updates should be made in the supplied
+ * callback routine. These updates must NOT go into a transaction. You should
+ * force these updates to the media before returning from the callback. In the
+ * even of a crash, either the old journal will be found, with an empty journal,
+ * or the new journal will be found with the contents of the active transaction.
+ *
+ * Upon return from the callback, the blocks from the active transaction are
+ * written to their normal locations on disk.
+ *
+ * (Remember that we have to ensure that blocks get committed to the journal
+ * before being committed to their normal locations. But the blocks don't count
+ * as committed until the new journal is pointed at.)
+ *
+ * Upon return, there is still an active transaction: newly allocated, and
+ * with no modified blocks. Call journal_end_transaction as normal. You may
+ * modifiy additional blocks before calling journal_end_transaction, and those
+ * blocks will (eventually) go to the relocated journal.
+ *
+ * Inputs:
+ * jnl The (opened) journal to relocate.
+ * offset The new journal byte offset (from start of the journal device).
+ * journal_size The size, in bytes, of the new journal.
+ * tbuffer_size The new desired transaction buffer size. Pass zero to keep
+ * the same size as the current journal. The size will be
+ * modified as needed to fit the new journal.
+ * callback Routine called after the new journal has been initialized,
+ * and the active transaction written to the new journal, but
+ * before the blocks are written to their normal locations.
+ * Pass NULL for no callback.
+ * callback_arg An argument passed to the callback routine.
+ *
+ * Result:
+ * 0 No errors
+ * EINVAL The offset is not block aligned
+ * EINVAL The journal_size is not a multiple of the block size
+ * EINVAL The journal is invalid
+ * (any) An error returned by journal_flush.
+ *
+ */
+int journal_relocate(journal *jnl, off_t offset, off_t journal_size, int32_t tbuffer_size,
+ errno_t (*callback)(void *), void *callback_arg)
+{
+ int ret;
+ transaction *tr;
+ size_t i = 0;
+
+ /*
+ * Sanity check inputs, and adjust the size of the transaction buffer.
+ */
+ if ((offset % jnl->jhdr->jhdr_size) != 0) {
+ printf("jnl: %s: relocate: offset 0x%llx is not an even multiple of block size 0x%x\n",
+ jnl->jdev_name, offset, jnl->jhdr->jhdr_size);
+ return EINVAL;
+ }
+ if ((journal_size % jnl->jhdr->jhdr_size) != 0) {
+ printf("jnl: %s: relocate: journal size 0x%llx is not an even multiple of block size 0x%x\n",
+ jnl->jdev_name, journal_size, jnl->jhdr->jhdr_size);
+ return EINVAL;
+ }
+
+ CHECK_JOURNAL(jnl);
+
+ /* Guarantee we own the active transaction. */
+ if (jnl->flags & JOURNAL_INVALID) {
+ return EINVAL;
+ }
+ if (jnl->owner != current_thread()) {
+ panic("jnl: relocate: Not the owner! jnl %p, owner %p, curact %p\n",
+ jnl, jnl->owner, current_thread());
+ }
+
+ if (tbuffer_size == 0)
+ tbuffer_size = jnl->tbuffer_size;
+ size_up_tbuffer(jnl, tbuffer_size, jnl->jhdr->jhdr_size);
+
+ /*
+ * Flush any non-active transactions. We have to temporarily hide the
+ * active transaction to make journal_flush flush out non-active but
+ * current (unwritten) transactions.
+ */
+ tr = jnl->active_tr;
+ CHECK_TRANSACTION(tr);
+ jnl->active_tr = NULL;
+ ret = journal_flush(jnl, TRUE);
+ jnl->active_tr = tr;
+
+ if (ret) {
+ return ret;
+ }
+ wait_condition(jnl, &jnl->flushing, "end_transaction");
+
+ /*
+ * At this point, we have completely flushed the contents of the current
+ * journal to disk (and have asynchronously written all of the txns to
+ * their actual desired locations). As a result, we can (and must) clear
+ * out the old_start array. If we do not, then if the last written transaction
+ * started at the beginning of the journal (starting 1 block into the
+ * journal file) it could confuse the buffer_flushed callback. This is
+ * because we're about to reset the start/end pointers of the journal header
+ * below.
+ */
+ lock_oldstart(jnl);
+ for (i = 0; i < sizeof (jnl->old_start) / sizeof(jnl->old_start[0]); i++) {
+ jnl->old_start[i] = 0;
+ }
+ unlock_oldstart(jnl);
+
+ /* Update the journal's offset and size in memory. */
+ jnl->jdev_offset = offset;
+ jnl->jhdr->start = jnl->jhdr->end = jnl->jhdr->jhdr_size;
+ jnl->jhdr->size = journal_size;
+ jnl->active_start = jnl->jhdr->start;
+
+ /*
+ * Force the active transaction to be written to the new journal. Call the
+ * supplied callback after the blocks have been written to the journal, but
+ * before they get written to their normal on-disk locations.
+ */
+ jnl->active_tr = NULL;
+ ret = end_transaction(tr, 1, callback, callback_arg, FALSE, TRUE);
+ if (ret) {
+ printf("jnl: %s: relocate: end_transaction failed (%d)\n", jnl->jdev_name, ret);
+ goto bad_journal;
+ }
+
+ /*
+ * Create a new, empty transaction to be the active transaction. This way
+ * our caller can use journal_end_transaction as usual.
+ */
+ ret = journal_allocate_transaction(jnl);
+ if (ret) {
+ printf("jnl: %s: relocate: could not allocate new transaction (%d)\n", jnl->jdev_name, ret);
+ goto bad_journal;
+ }
+
+ return 0;
+
+bad_journal:
+ jnl->flags |= JOURNAL_INVALID;
+ abort_transaction(jnl, tr);
+ return ret;
+}
+
+
+#else // !JOURNALING - so provide stub functions
+
+int journal_uses_fua(__unused journal *jnl)
+{
+ return 0;
+}
+
+journal *
+journal_create(__unused struct vnode *jvp,
+ __unused off_t offset,
+ __unused off_t journal_size,
+ __unused struct vnode *fsvp,
+ __unused size_t min_fs_blksz,
+ __unused int32_t flags,
+ __unused int32_t tbuffer_size,
+ __unused void (*flush)(void *arg),
+ __unused void *arg,
+ __unused struct mount *fsmount)
+{
+ return NULL;
+}
+
+journal *
+journal_open(__unused struct vnode *jvp,
+ __unused off_t offset,
+ __unused off_t journal_size,
+ __unused struct vnode *fsvp,
+ __unused size_t min_fs_blksz,
+ __unused int32_t flags,
+ __unused int32_t tbuffer_size,
+ __unused void (*flush)(void *arg),
+ __unused void *arg,
+ __unused struct mount *fsmount)
+{
+ return NULL;
+}
+
+
+int
+journal_modify_block_start(__unused journal *jnl, __unused struct buf *bp)
+{
+ return EINVAL;
+}
+
+int
+journal_modify_block_end(__unused journal *jnl,
+ __unused struct buf *bp,
+ __unused void (*func)(struct buf *bp, void *arg),
+ __unused void *arg)
+{
+ return EINVAL;
+}
+
+int
+journal_kill_block(__unused journal *jnl, __unused struct buf *bp)
+{
+ return EINVAL;
+}
+
+int journal_relocate(__unused journal *jnl,
+ __unused off_t offset,
+ __unused off_t journal_size,
+ __unused int32_t tbuffer_size,
+ __unused errno_t (*callback)(void *),
+ __unused void *callback_arg)
+{
+ return EINVAL;
+}
+
+void
+journal_close(__unused journal *jnl)
+{
+}
+
+int
+journal_start_transaction(__unused journal *jnl)
+{
+ return EINVAL;
+}
+
+int
+journal_end_transaction(__unused journal *jnl)
+{
+ return EINVAL;
+}
+
+int
+journal_flush(__unused journal *jnl, __unused boolean_t wait_for_IO)
+{
+ return EINVAL;
+}
+
+int
+journal_is_clean(__unused struct vnode *jvp,
+ __unused off_t offset,
+ __unused off_t journal_size,
+ __unused struct vnode *fsvp,
+ __unused size_t min_fs_block_size)
+{
+ return 0;
+}
+
+
+void *
+journal_owner(__unused journal *jnl)
+{
+ return NULL;
+}
+
+void
+journal_lock(__unused journal *jnl)
+{
+ return;
+}
+
+void
+journal_unlock(__unused journal *jnl)
+{
+ return;
+}
+
+__private_extern__ int
+journal_trim_add_extent(__unused journal *jnl,
+ __unused uint64_t offset,
+ __unused uint64_t length)
+{
+ return 0;
+}
+
+int
+journal_request_immediate_flush(__unused journal *jnl)
+{
+ return 0;
+}
+
+__private_extern__ int
+journal_trim_remove_extent(__unused journal *jnl,
+ __unused uint64_t offset,
+ __unused uint64_t length)
+{
+ return 0;
+}
+
+int journal_trim_extent_overlap(__unused journal *jnl,
+ __unused uint64_t offset,
+ __unused uint64_t length,
+ __unused uint64_t *end)
+{
+ return 0;
+}
+
+#endif // !JOURNALING