fs/nfs/nfs42xdr.c

Source file repositories/reference/linux-study-clean/fs/nfs/nfs42xdr.c

File Facts

System
Linux kernel
Corpus path
fs/nfs/nfs42xdr.c
Extension
.c
Size
47301 bytes
Lines
1831
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 read_plus_segment {
	enum data_content4 type;
	uint64_t offset;
	union {
		struct {
			uint64_t length;
		} hole;

		struct {
			uint32_t length;
			unsigned int from;
		} data;
	};
};

static inline uint64_t read_plus_segment_length(struct read_plus_segment *seg)
{
	return seg->type == NFS4_CONTENT_DATA ? seg->data.length : seg->hole.length;
}

static int decode_read_plus_segment(struct xdr_stream *xdr,
				    struct read_plus_segment *seg)
{
	__be32 *p;

	p = xdr_inline_decode(xdr, 4);
	if (!p)
		return -EIO;
	seg->type = be32_to_cpup(p++);

	p = xdr_inline_decode(xdr, seg->type == NFS4_CONTENT_DATA ? 12 : 16);
	if (!p)
		return -EIO;
	p = xdr_decode_hyper(p, &seg->offset);

	if (seg->type == NFS4_CONTENT_DATA) {
		struct xdr_buf buf;
		uint32_t len = be32_to_cpup(p);

		seg->data.length = len;
		seg->data.from = xdr_stream_pos(xdr);

		if (!xdr_stream_subsegment(xdr, &buf, xdr_align_size(len)))
			return -EIO;
	} else if (seg->type == NFS4_CONTENT_HOLE) {
		xdr_decode_hyper(p, &seg->hole.length);
	} else
		return -EINVAL;
	return 0;
}

static int process_read_plus_segment(struct xdr_stream *xdr,
				     struct nfs_pgio_args *args,
				     struct nfs_pgio_res *res,
				     struct read_plus_segment *seg)
{
	unsigned long offset = seg->offset;
	unsigned long length = read_plus_segment_length(seg);
	unsigned int bufpos;

	if (offset + length < args->offset)
		return 0;
	else if (offset > args->offset + args->count) {
		res->eof = 0;
		return 0;
	} else if (offset < args->offset) {
		length -= (args->offset - offset);
		offset = args->offset;
	} else if (offset + length > args->offset + args->count) {
		length = (args->offset + args->count) - offset;
		res->eof = 0;
	}

	bufpos = xdr->buf->head[0].iov_len + (offset - args->offset);
	if (seg->type == NFS4_CONTENT_HOLE)
		return xdr_stream_zero(xdr, bufpos, length);
	else
		return xdr_stream_move_subsegment(xdr, seg->data.from, bufpos, length);
}

static int decode_read_plus(struct xdr_stream *xdr, struct nfs_pgio_res *res)
{
	struct nfs_pgio_header *hdr =
		container_of(res, struct nfs_pgio_header, res);
	struct nfs_pgio_args *args = &hdr->args;
	uint32_t segments;
	struct read_plus_segment *segs;
	int status, i;
	__be32 *p;

Annotation

Implementation Notes