// File: /workspace/github_c_makefile_star2_O2/albertito[P]libjio/libjio/trans.c
// Function: jtrans_commit
ssize_t jtrans_commit(struct jtrans *ts)
{
	ssize_t r, retval = -1;
	struct operation *op;
	struct jlinger *linger;
	jop_t *jop = NULL;
	size_t written = 0;

	pthread_mutex_lock(&(ts->lock));

	/* clear the flags */
	ts->flags = ts->flags & ~J_COMMITTED;
	ts->flags = ts->flags & ~J_ROLLBACKED;

	if (ts->numops_r + ts->numops_w == 0)
		goto exit;

	/* fail for read-only accesses if we have write operations */
	if (ts->numops_w && (ts->flags & J_RDONLY))
		goto exit;

	/* Lock all the regions we're going to work with; otherwise there
	 * could be another transaction trying to write the same spots and we
	 * could end up with interleaved writes, that could break atomicity
	 * warantees if we need to rollback.
	 * Note we do this before creating a new transaction, so we know it's
	 * not possible to have two overlapping transactions on disk at the
	 * same time. */
	if (lock_file_ranges(ts, F_LOCKW) != 0)
		goto unlock_exit;

	/* create and fill the transaction file only if we have at least one
	 * write operation */
	if (ts->numops_w) {
		jop = journal_new(ts->fs, ts->flags);
		if (jop == NULL)
			goto unlock_exit;
	}

	for (op = ts->op; op != NULL; op = op->next) {
		if (op->direction == D_READ)
			continue;

		r = journal_add_op(jop, op->buf, op->len, op->offset);
		if (r != 0)
			goto unlink_exit;

		fiu_exit_on("jio/commit/tf_opdata");
	}

	if (jop)
		journal_pre_commit(jop);

	fiu_exit_on("jio/commit/tf_data");

	if (!(ts->flags & J_NOROLLBACK)) {
		for (op = ts->op; op != NULL; op = op->next) {
			if (op->direction == D_READ)
				continue;

			 r = operation_read_prev(ts, op);
			 if (r < 0)
				 goto unlink_exit;
		}
	}

	if (jop) {
		r = journal_commit(jop);
		if (r < 0)
			goto unlink_exit;
	}

	/* now that we have a safe transaction file, let's apply it */
	written = 0;
	for (op = ts->op; op != NULL; op = op->next) {
		if (op->direction == D_READ) {
			r = spread(ts->fs->fd, op->buf, op->len, op->offset);
			if (r != op->len)
				goto rollback_exit;

			continue;
		}

		/* from now on, write ops (which are more interesting) */

		r = spwrite(ts->fs->fd, op->buf, op->len, op->offset);
		if (r != op->len)
			goto rollback_exit;

		written += r;

		if (have_sync_range && !(ts->flags & J_LINGER)) {
			r = sync_range_submit(ts->fs->fd, op->len,
					op->offset);
			if (r != 0)
				goto rollback_exit;
		}

		fiu_exit_on("jio/commit/wrote_op");
	}

	fiu_exit_on("jio/commit/wrote_all_ops");

	if (jop && (ts->flags & J_LINGER)) {
		struct jlinger *lp;

		linger = malloc(sizeof(struct jlinger));
		if (linger == NULL)
			goto rollback_exit;

		linger->jop = jop;
		linger->next = NULL;

		pthread_mutex_lock(&(ts->fs->ltlock));

		/* add it to the end of the list so they're in order */
		if (ts->fs->ltrans == NULL) {
			ts->fs->ltrans = linger;
		} else {
			lp = ts->fs->ltrans;
			while (lp->next != NULL)
				lp = lp->next;
			lp->next = linger;
		}

		ts->fs->ltrans_len += written;
		autosync_check(ts->fs);

		pthread_mutex_unlock(&(ts->fs->ltlock));

		/* Leave the journal_free() up to jsync() */
		jop = NULL;
	} else if (jop) {
		if (have_sync_range) {
			for (op = ts->op; op != NULL; op = op->next) {
				if (op->direction == D_READ)
					continue;

				r = sync_range_wait(ts->fs->fd, op->len,
						op->offset);
				if (r != 0)
					goto rollback_exit;
			}
		} else {
			if (fdatasync(ts->fs->fd) != 0)
				goto rollback_exit;
		}
	}

	/* mark the transaction as committed */
	ts->flags = ts->flags | J_COMMITTED;

	retval = 1;

rollback_exit:
	/* If the transaction failed we try to recover by rolling it back.
	 * Only used if it has at least one write operation.
	 *
	 * NOTE: on extreme conditions (ENOSPC/disk failure) this can fail
	 * too! There's nothing much we can do in that case, the caller should
	 * take care of it by itself.
	 *
	 * Transactions that were successfuly recovered by rolling them back
	 * will have J_ROLLBACKED in their flags. */
	if (jop && !(ts->flags & J_COMMITTED) &&
			!(ts->flags & J_ROLLBACKING)) {
		r = ts->flags;
		ts->flags = ts->flags | J_NOLOCK | J_ROLLBACKING;
		if (jtrans_rollback(ts) >= 0) {
			ts->flags = r | J_ROLLBACKED;
			retval = -1;
		} else {
			ts->flags = r;
			retval = -2;
		}
	}

unlink_exit:
	/* If the journal operation is no longer needed, we remove it from the
	 * disk.
	 *
	 * Extreme conditions (filesystem just got read-only, for example) can
	 * cause journal_free() to fail, but there's not much left to do at
	 * that point, and the caller will have to be careful and stop its
	 * operations. In that case, we will return -2, and the transaction
	 * will be marked as J_COMMITTED to indicate that the data was
	 * effectively written to disk. */
	if (jop) {
		/* Note we only unlink if we've written down the real data, or
		 * at least rolled it back properly */
		int data_is_safe = (ts->flags & J_COMMITTED) ||
			(ts->flags & J_ROLLBACKED);
		r = journal_free(jop, data_is_safe ? 1 : 0);
		if (r != 0)
			retval = -2;

		jop = NULL;
	}

unlock_exit:
	/* always unlock everything at the end; otherwise we could have
	 * half-overlapping transactions applying simultaneously, and if
	 * anything goes wrong it would be possible to break consistency */
	lock_file_ranges(ts, F_UNLOCK);

exit:
	pthread_mutex_unlock(&(ts->lock));

	return retval;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdi, %r14
leaq 0x20(%rdi), %rbx
movq %rbx, %rdi
callq 0x25a0
movl 0xc(%r14), %eax
movl 0x14(%r14), %ecx
movl %eax, %edx
andl $0xfffff3ff, %edx       # imm = 0xFFFFF3FF
movl %edx, 0xc(%r14)
pushq $-0x1
popq %r12
movl 0x10(%r14), %edx
addl %ecx, %edx
je 0x30d9
testl %ecx, %ecx
sete %cl
btl $0x9, %eax
setae %al
orb %cl, %al
cmpb $0x1, %al
jne 0x30d9
movq %r14, %rdi
movl $0x110, %esi            # imm = 0x110
callq 0x30f3
pushq $-0x1
popq %r12
testl %eax, %eax
jne 0x30cc
cmpl $0x0, 0x14(%r14)
je 0x2e08
movq (%r14), %rdi
movl 0xc(%r14), %esi
callq 0x2060
movq %rax, %r15
testq %rax, %rax
jne 0x2e0b
jmp 0x30cc
xorl %r15d, %r15d
leaq 0x48(%r14), %rbp
movq %rbp, %r12
movq (%r12), %r12
testq %r12, %r12
je 0x2e48
cmpl $0x1, 0x20(%r12)
je 0x2e42
movq 0x18(%r12), %rsi
movq 0x8(%r12), %rcx
movq 0x10(%r12), %rdx
movq %r15, %rdi
callq 0x2150
testl %eax, %eax
jne 0x2fc7
addq $0x40, %r12
jmp 0x2e12
testq %r15, %r15
je 0x2e55
movq %r15, %rdi
callq 0x23a0
testb $0x2, 0xc(%r14)
jne 0x2eba
movq %rbp, %r13
movq (%r13), %r13
testq %r13, %r13
je 0x2eba
cmpl $0x1, 0x20(%r13)
je 0x2eb4
movq 0x10(%r13), %r12
movq %r12, %rdi
callq 0x2390
movq %rax, 0x30(%r13)
testq %rax, %rax
je 0x2fc7
movq (%r14), %rcx
movl (%rcx), %edi
movq 0x8(%r13), %rcx
movq %rax, %rsi
movq %r12, %rdx
callq 0x22d0
testq %rax, %rax
js 0x2fb9
movq 0x10(%r13), %rcx
cmpq %rcx, %rax
cmovbq %rax, %rcx
movq %rcx, 0x28(%r13)
addq $0x40, %r13
jmp 0x2e5f
testq %r15, %r15
je 0x2ecf
movq %r15, %rdi
callq 0x22a0
testl %eax, %eax
js 0x2fb0
movq %r15, 0x8(%rsp)
movq 0x50fd(%rip), %rax      # 0x7fd8
movl (%rax), %eax
movl %eax, 0x14(%rsp)
xorl %r15d, %r15d
pushq $-0x1
popq %r12
movq %rbp, %r13
movq (%r13), %r13
testq %r13, %r13
je 0x2f5a
cmpl $0x1, 0x20(%r13)
movq (%r14), %rax
movl (%rax), %edi
movq 0x18(%r13), %rsi
movq 0x8(%r13), %rcx
movq 0x10(%r13), %rdx
jne 0x2f19
callq 0x22d0
cmpq 0x10(%r13), %rax
je 0x2f4a
jmp 0x2f50
callq 0x2440
cmpq 0x10(%r13), %rax
jne 0x2f50
addq %rax, %r15
cmpl $0x0, 0x14(%rsp)
je 0x2f4a
testb $0x4, 0xc(%r14)
jne 0x2f4a
movq (%r14), %rcx
movl (%rcx), %edi
movq 0x8(%r13), %rdx
movq %rax, %rsi
callq 0x2050
testl %eax, %eax
jne 0x2f50
addq $0x40, %r13
jmp 0x2eeb
movq 0x8(%rsp), %r15
jmp 0x306e
cmpq $0x0, 0x8(%rsp)
je 0x3062
testb $0x4, 0xc(%r14)
jne 0x2fd9
cmpl $0x0, 0x14(%rsp)
je 0x3022
movq 0x8(%rsp), %r15
movq (%rbp), %rbp
testq %rbp, %rbp
je 0x3065
cmpl $0x1, 0x20(%rbp)
je 0x2faa
movq (%r14), %rax
movl (%rax), %edi
movq 0x8(%rbp), %rdx
movq 0x10(%rbp), %rsi
callq 0x2030
testl %eax, %eax
jne 0x306e
addq $0x40, %rbp
jmp 0x2f7d
pushq $-0x1
popq %r12
jmp 0x30ae
movq 0x30(%r13), %rdi
callq 0x2040
andq $0x0, 0x30(%r13)
pushq $-0x1
popq %r12
testq %r15, %r15
jne 0x30ae
jmp 0x30cc
pushq $0x10
popq %rdi
callq 0x2390
testq %rax, %rax
je 0x303b
movq %rax, %r12
movq 0x8(%rsp), %rax
movq %rax, (%r12)
andq $0x0, 0x8(%r12)
movq (%r14), %rdi
addq $0x40, %rdi
callq 0x25a0
movq (%r14), %rdi
movq 0x30(%rdi), %rcx
testq %rcx, %rcx
je 0x3046
movq %rcx, %rax
movq 0x8(%rcx), %rcx
testq %rcx, %rcx
jne 0x3010
addq $0x8, %rax
jmp 0x304a
movq (%r14), %rax
movl (%rax), %edi
callq 0x2080
testl %eax, %eax
movq 0x8(%rsp), %r15
je 0x3065
pushq $-0x1
popq %r12
jmp 0x3073
pushq $-0x1
popq %r12
movq 0x8(%rsp), %r15
jmp 0x3073
leaq 0x30(%rdi), %rax
movq %r12, (%rax)
addq %r15, 0x38(%rdi)
callq 0x2470
movq (%r14), %rdi
addq $0x40, %rdi
callq 0x2370
xorl %r15d, %r15d
orb $0x4, 0xd(%r14)
pushq $0x1
popq %r12
testq %r15, %r15
je 0x30cc
movl 0xc(%r14), %ebp
testw $0x1400, %bp            # imm = 0x1400
jne 0x30ae
movl %ebp, %eax
orl $0x1001, %eax           # imm = 0x1001
movl %eax, 0xc(%r14)
movq %r14, %rdi
callq 0x20e0
movl %ebp, %ecx
orl $0x800, %ecx            # imm = 0x800
xorl %r12d, %r12d
testq %rax, %rax
setns %r12b
cmovsl %ebp, %ecx
orq $-0x2, %r12
movl %ecx, 0xc(%r14)
xorl %esi, %esi
testw $0xc00, 0xc(%r14)       # imm = 0xC00
setne %sil
movq %r15, %rdi
callq 0x23c0
testl %eax, %eax
pushq $-0x2
popq %rax
cmovneq %rax, %r12
movq %r14, %rdi
movl $0x10000, %esi          # imm = 0x10000
callq 0x30f3
movq %rbx, %rdi
callq 0x2370
movq %r12, %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq