fs/xfs/xfs_log_cil.c

Source file repositories/reference/linux-study-clean/fs/xfs/xfs_log_cil.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_log_cil.c
Extension
.c
Size
66599 bytes
Lines
2070
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xlog_format_buf {
	struct xfs_log_vec	*lv;
	unsigned int		idx;
};

/*
 * We need to make sure the buffer pointer returned is naturally aligned for the
 * biggest basic data type we put into it. We have already accounted for this
 * padding when sizing the buffer.
 *
 * However, this padding does not get written into the log, and hence we have to
 * track the space used by the log vectors separately to prevent log space hangs
 * due to inaccurate accounting (i.e. a leak) of the used log space through the
 * CIL context ticket.
 *
 * We also add space for the xlog_op_header that describes this region in the
 * log. This prepends the data region we return to the caller to copy their data
 * into, so do all the static initialisation of the ophdr now. Because the ophdr
 * is not 8 byte aligned, we have to be careful to ensure that we align the
 * start of the buffer such that the region we return to the call is 8 byte
 * aligned and packed against the tail of the ophdr.
 */
void *
xlog_format_start(
	struct xlog_format_buf	*lfb,
	uint16_t		type)
{
	struct xfs_log_vec	*lv = lfb->lv;
	struct xfs_log_iovec	*vec = &lv->lv_iovecp[lfb->idx];
	struct xlog_op_header	*oph;
	uint32_t		len;
	void			*buf;

	ASSERT(lfb->idx < lv->lv_niovecs);

	len = lv->lv_buf_used + sizeof(struct xlog_op_header);
	if (!IS_ALIGNED(len, sizeof(uint64_t))) {
		lv->lv_buf_used = round_up(len, sizeof(uint64_t)) -
					sizeof(struct xlog_op_header);
	}

	vec->i_type = type;
	vec->i_addr = lv->lv_buf + lv->lv_buf_used;

	oph = vec->i_addr;
	oph->oh_clientid = XFS_TRANSACTION;
	oph->oh_res2 = 0;
	oph->oh_flags = 0;

	buf = vec->i_addr + sizeof(struct xlog_op_header);
	ASSERT(IS_ALIGNED((unsigned long)buf, sizeof(uint64_t)));
	return buf;
}

void
xlog_format_commit(
	struct xlog_format_buf	*lfb,
	unsigned int		data_len)
{
	struct xfs_log_vec	*lv = lfb->lv;
	struct xfs_log_iovec	*vec = &lv->lv_iovecp[lfb->idx];
	struct xlog_op_header	*oph = vec->i_addr;
	int			len;

	/*
	 * Always round up the length to the correct alignment so callers don't
	 * need to know anything about this log vec layout requirement. This
	 * means we have to zero the area the data to be written does not cover.
	 * This is complicated by fact the payload region is offset into the
	 * logvec region by the opheader that tracks the payload.
	 */
	len = xlog_calc_iovec_len(data_len);
	if (len - data_len != 0) {
		char	*buf = vec->i_addr + sizeof(struct xlog_op_header);

		memset(buf + data_len, 0, len - data_len);
	}

	/*
	 * The opheader tracks aligned payload length, whilst the logvec tracks
	 * the overall region length.
	 */
	oph->oh_len = cpu_to_be32(len);

	len += sizeof(struct xlog_op_header);
	lv->lv_buf_used += len;
	lv->lv_bytes += len;
	vec->i_len = len;

	/* Catch buffer overruns */

Annotation

Implementation Notes