net/sunrpc/xdr.c

Source file repositories/reference/linux-study-clean/net/sunrpc/xdr.c

File Facts

System
Linux kernel
Corpus path
net/sunrpc/xdr.c
Extension
.c
Size
63834 bytes
Lines
2445
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

while (remaining > 0) {
			len = min_t(unsigned int, remaining,
				    PAGE_SIZE - offset);
			if (unlikely(count >= bvec_size))
				goto bvec_overflow;
			bvec_set_page(bvec++, *pages++, len, offset);
			remaining -= len;
			offset = 0;
			++count;
		}
	}

	if (tail->iov_len) {
		if (unlikely(count >= bvec_size))
			goto bvec_overflow;
		bvec_set_virt(bvec, tail->iov_base, tail->iov_len);
		++count;
	}

	return count;

bvec_overflow:
	pr_warn_once("%s: bio_vec array overflow\n", __func__);
	return -ESERVERFAULT;
}
EXPORT_SYMBOL_GPL(xdr_buf_to_bvec);

/**
 * xdr_buf_to_sg - Populate a scatterlist from an xdr_buf range
 * @buf: xdr_buf to map
 * @offset: starting byte offset within @buf
 * @len: number of bytes to cover
 * @sg: scatterlist array initialized with sg_init_table()
 * @nsg: number of entries available in @sg
 *
 * @sg is traversed with sg_next(), so callers may pass a list
 * assembled with sg_chain().
 *
 * Return: on success, the number of scatterlist entries used; the
 * last used entry is marked with sg_mark_end().  On failure, a
 * negative errno.
 */
int xdr_buf_to_sg(const struct xdr_buf *buf, unsigned int offset,
		  unsigned int len, struct scatterlist *sg, unsigned int nsg)
{
	unsigned int page_len, thislen, page_offset;
	struct scatterlist *cur = sg, *prev = NULL;
	int nents = 0;
	int i;

	if (len == 0)
		return 0;

	if (offset >= buf->head[0].iov_len) {
		offset -= buf->head[0].iov_len;
	} else {
		thislen = min_t(unsigned int,
				buf->head[0].iov_len - offset, len);
		if (nents >= nsg)
			return -ENOSPC;
		sg_set_buf(cur, buf->head[0].iov_base + offset,
			   thislen);
		prev = cur;
		cur = sg_next(cur);
		nents++;
		len -= thislen;
		offset = 0;
	}
	if (len == 0)
		goto done;

	if (offset >= buf->page_len) {
		offset -= buf->page_len;
	} else {
		page_len = min(buf->page_len - offset, len);
		len -= page_len;
		page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
		i = (offset + buf->page_base) >> PAGE_SHIFT;
		thislen = PAGE_SIZE - page_offset;
		do {
			if (thislen > page_len)
				thislen = page_len;
			if (nents >= nsg)
				return -ENOSPC;
			sg_set_page(cur, buf->pages[i],
				    thislen, page_offset);
			prev = cur;
			cur = sg_next(cur);
			nents++;
			page_len -= thislen;

Annotation

Implementation Notes