⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xdr.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	} while ((len -= copy) != 0);}/* * _copy_to_pages * @pages: array of pages * @pgbase: page vector address of destination * @p: pointer to source data * @len: length * * Copies data from an arbitrary memory location into an array of pages * The copy is assumed to be non-overlapping. */static void_copy_to_pages(struct page **pages, size_t pgbase, const char *p, size_t len){	struct page **pgto;	char *vto;	size_t copy;	pgto = pages + (pgbase >> PAGE_CACHE_SHIFT);	pgbase &= ~PAGE_CACHE_MASK;	do {		copy = PAGE_CACHE_SIZE - pgbase;		if (copy > len)			copy = len;		vto = kmap_atomic(*pgto, KM_USER0);		memcpy(vto + pgbase, p, copy);		kunmap_atomic(vto, KM_USER0);		pgbase += copy;		if (pgbase == PAGE_CACHE_SIZE) {			pgbase = 0;			pgto++;		}		p += copy;	} while ((len -= copy) != 0);}/* * _copy_from_pages * @p: pointer to destination * @pages: array of pages * @pgbase: offset of source data * @len: length * * Copies data into an arbitrary memory location from an array of pages * The copy is assumed to be non-overlapping. */void_copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len){	struct page **pgfrom;	char *vfrom;	size_t copy;	pgfrom = pages + (pgbase >> PAGE_CACHE_SHIFT);	pgbase &= ~PAGE_CACHE_MASK;	do {		copy = PAGE_CACHE_SIZE - pgbase;		if (copy > len)			copy = len;		vfrom = kmap_atomic(*pgfrom, KM_USER0);		memcpy(p, vfrom + pgbase, copy);		kunmap_atomic(vfrom, KM_USER0);		pgbase += copy;		if (pgbase == PAGE_CACHE_SIZE) {			pgbase = 0;			pgfrom++;		}		p += copy;	} while ((len -= copy) != 0);}/* * xdr_shrink_bufhead * @buf: xdr_buf * @len: bytes to remove from buf->head[0] * * Shrinks XDR buffer's header kvec buf->head[0] by  * 'len' bytes. The extra data is not lost, but is instead * moved into the inlined pages and/or the tail. */voidxdr_shrink_bufhead(struct xdr_buf *buf, size_t len){	struct kvec *head, *tail;	size_t copy, offs;	unsigned int pglen = buf->page_len;	tail = buf->tail;	head = buf->head;	BUG_ON (len > head->iov_len);	/* Shift the tail first */	if (tail->iov_len != 0) {		if (tail->iov_len > len) {			copy = tail->iov_len - len;			memmove((char *)tail->iov_base + len,					tail->iov_base, copy);		}		/* Copy from the inlined pages into the tail */		copy = len;		if (copy > pglen)			copy = pglen;		offs = len - copy;		if (offs >= tail->iov_len)			copy = 0;		else if (copy > tail->iov_len - offs)			copy = tail->iov_len - offs;		if (copy != 0)			_copy_from_pages((char *)tail->iov_base + offs,					buf->pages,					buf->page_base + pglen + offs - len,					copy);		/* Do we also need to copy data from the head into the tail ? */		if (len > pglen) {			offs = copy = len - pglen;			if (copy > tail->iov_len)				copy = tail->iov_len;			memcpy(tail->iov_base,					(char *)head->iov_base +					head->iov_len - offs,					copy);		}	}	/* Now handle pages */	if (pglen != 0) {		if (pglen > len)			_shift_data_right_pages(buf->pages,					buf->page_base + len,					buf->page_base,					pglen - len);		copy = len;		if (len > pglen)			copy = pglen;		_copy_to_pages(buf->pages, buf->page_base,				(char *)head->iov_base + head->iov_len - len,				copy);	}	head->iov_len -= len;	buf->buflen -= len;	/* Have we truncated the message? */	if (buf->len > buf->buflen)		buf->len = buf->buflen;}/* * xdr_shrink_pagelen * @buf: xdr_buf * @len: bytes to remove from buf->pages * * Shrinks XDR buffer's page array buf->pages by  * 'len' bytes. The extra data is not lost, but is instead * moved into the tail. */voidxdr_shrink_pagelen(struct xdr_buf *buf, size_t len){	struct kvec *tail;	size_t copy;	char *p;	unsigned int pglen = buf->page_len;	tail = buf->tail;	BUG_ON (len > pglen);	/* Shift the tail first */	if (tail->iov_len != 0) {		p = (char *)tail->iov_base + len;		if (tail->iov_len > len) {			copy = tail->iov_len - len;			memmove(p, tail->iov_base, copy);		} else			buf->buflen -= len;		/* Copy from the inlined pages into the tail */		copy = len;		if (copy > tail->iov_len)			copy = tail->iov_len;		_copy_from_pages((char *)tail->iov_base,				buf->pages, buf->page_base + pglen - len,				copy);	}	buf->page_len -= len;	buf->buflen -= len;	/* Have we truncated the message? */	if (buf->len > buf->buflen)		buf->len = buf->buflen;}voidxdr_shift_buf(struct xdr_buf *buf, size_t len){	xdr_shrink_bufhead(buf, len);}/** * xdr_init_encode - Initialize a struct xdr_stream for sending data. * @xdr: pointer to xdr_stream struct * @buf: pointer to XDR buffer in which to encode data * @p: current pointer inside XDR buffer * * Note: at the moment the RPC client only passes the length of our *	 scratch buffer in the xdr_buf's header kvec. Previously this *	 meant we needed to call xdr_adjust_iovec() after encoding the *	 data. With the new scheme, the xdr_stream manages the details *	 of the buffer length, and takes care of adjusting the kvec *	 length for us. */void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p){	struct kvec *iov = buf->head;	xdr->buf = buf;	xdr->iov = iov;	xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);	buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;	xdr->p = p;}EXPORT_SYMBOL(xdr_init_encode);/** * xdr_reserve_space - Reserve buffer space for sending * @xdr: pointer to xdr_stream * @nbytes: number of bytes to reserve * * Checks that we have enough buffer space to encode 'nbytes' more * bytes of data. If so, update the total xdr_buf length, and * adjust the length of the current kvec. */uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes){	uint32_t *p = xdr->p;	uint32_t *q;	/* align nbytes on the next 32-bit boundary */	nbytes += 3;	nbytes &= ~3;	q = p + (nbytes >> 2);	if (unlikely(q > xdr->end || q < p))		return NULL;	xdr->p = q;	xdr->iov->iov_len += nbytes;	xdr->buf->len += nbytes;	return p;}EXPORT_SYMBOL(xdr_reserve_space);/** * xdr_write_pages - Insert a list of pages into an XDR buffer for sending * @xdr: pointer to xdr_stream * @pages: list of pages * @base: offset of first byte * @len: length of data in bytes * */void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,		 unsigned int len){	struct xdr_buf *buf = xdr->buf;	struct kvec *iov = buf->tail;	buf->pages = pages;	buf->page_base = base;	buf->page_len = len;	iov->iov_base = (char *)xdr->p;	iov->iov_len  = 0;	xdr->iov = iov;	if (len & 3) {		unsigned int pad = 4 - (len & 3);		BUG_ON(xdr->p >= xdr->end);		iov->iov_base = (char *)xdr->p + (len & 3);		iov->iov_len  += pad;		len += pad;		*xdr->p++ = 0;	}	buf->buflen += len;	buf->len += len;}EXPORT_SYMBOL(xdr_write_pages);/** * xdr_init_decode - Initialize an xdr_stream for decoding data. * @xdr: pointer to xdr_stream struct * @buf: pointer to XDR buffer from which to decode data * @p: current pointer inside XDR buffer */void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p){	struct kvec *iov = buf->head;	unsigned int len = iov->iov_len;	if (len > buf->len)		len = buf->len;	xdr->buf = buf;	xdr->iov = iov;	xdr->p = p;	xdr->end = (uint32_t *)((char *)iov->iov_base + len);}EXPORT_SYMBOL(xdr_init_decode);/** * xdr_inline_decode - Retrieve non-page XDR data to decode * @xdr: pointer to xdr_stream struct * @nbytes: number of bytes of data to decode * * Check if the input buffer is long enough to enable us to decode * 'nbytes' more bytes of data starting at the current position. * If so return the current pointer, then update the current * pointer position. */uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes){	uint32_t *p = xdr->p;	uint32_t *q = p + XDR_QUADLEN(nbytes);	if (unlikely(q > xdr->end || q < p))		return NULL;	xdr->p = q;	return p;}EXPORT_SYMBOL(xdr_inline_decode);/** * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position * @xdr: pointer to xdr_stream struct * @len: number of bytes of page data * * Moves data beyond the current pointer position from the XDR head[] buffer * into the page list. Any data that lies beyond current position + "len" * bytes is moved into the XDR tail[]. The current pointer is then * repositioned at the beginning of the XDR tail. */void xdr_read_pages(struct xdr_stream *xdr, unsigned int len){	struct xdr_buf *buf = xdr->buf;	struct kvec *iov;	ssize_t shift;	unsigned int end;	int padding;	/* Realign pages to current pointer position */	iov  = buf->head;	shift = iov->iov_len + (char *)iov->iov_base - (char *)xdr->p;	if (shift > 0)		xdr_shrink_bufhead(buf, shift);	/* Truncate page data and move it into the tail */	if (buf->page_len > len)		xdr_shrink_pagelen(buf, buf->page_len - len);	padding = (XDR_QUADLEN(len) << 2) - len;	xdr->iov = iov = buf->tail;	/* Compute remaining message length.  */	end = iov->iov_len;	shift = buf->buflen - buf->len;	if (shift < end)		end -= shift;	else if (shift > 0)		end = 0;	/*	 * Position current pointer at beginning of tail, and	 * set remaining message length.	 */	xdr->p = (uint32_t *)((char *)iov->iov_base + padding);	xdr->end = (uint32_t *)((char *)iov->iov_base + end);}EXPORT_SYMBOL(xdr_read_pages);static struct kvec empty_iov = {.iov_base = NULL, .iov_len = 0};voidxdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf){	buf->head[0] = *iov;	buf->tail[0] = empty_iov;	buf->page_len = 0;	buf->buflen = buf->len = iov->iov_len;}/* Sets subiov to the intersection of iov with the buffer of length len * starting base bytes after iov.  Indicates empty intersection by setting * length of subiov to zero.  Decrements len by length of subiov, sets base * to zero (or decrements it by length of iov if subiov is empty). */static voidiov_subsegment(struct kvec *iov, struct kvec *subiov, int *base, int *len){	if (*base > iov->iov_len) {		subiov->iov_base = NULL;		subiov->iov_len = 0;		*base -= iov->iov_len;	} else {		subiov->iov_base = iov->iov_base + *base;		subiov->iov_len = min(*len, (int)iov->iov_len - *base);		*base = 0;	}	*len -= subiov->iov_len; }/* Sets subbuf to the portion of buf of length len beginning base bytes * from the start of buf. Returns -1 if base of length are out of bounds. */intxdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,			int base, int len){	int i;	subbuf->buflen = subbuf->len = len;	iov_subsegment(buf->head, subbuf->head, &base, &len);	if (base < buf->page_len) {		i = (base + buf->page_base) >> PAGE_CACHE_SHIFT;		subbuf->pages = &buf->pages[i];		subbuf->page_base = (base + buf->page_base) & ~PAGE_CACHE_MASK;		subbuf->page_len = min((int)buf->page_len - base, len);		len -= subbuf->page_len;		base = 0;	} else {		base -= buf->page_len;		subbuf->page_len = 0;	}	iov_subsegment(buf->tail, subbuf->tail, &base, &len);	if (base || len)		return -1;	return 0;}/* obj is assumed to point to allocated memory of size at least len: */intread_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len){	struct xdr_buf subbuf;	int this_len;	int status;	status = xdr_buf_subsegment(buf, &subbuf, base, len);	if (status)		goto out;	this_len = min(len, (int)subbuf.head[0].iov_len);	memcpy(obj, subbuf.head[0].iov_base, this_len);	len -= this_len;	obj += this_len;	this_len = min(len, (int)subbuf.page_len);	if (this_len)		_copy_from_pages(obj, subbuf.pages, subbuf.page_base, this_len);	len -= this_len;	obj += this_len;	this_len = min(len, (int)subbuf.tail[0].iov_len);	memcpy(obj, subbuf.tail[0].iov_base, this_len);out:	return status;}static intread_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj){	u32	raw;	int	status;	status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));	if (status)		return status;	*obj = ntohl(raw);	return 0;}/* If the netobj starting offset bytes from the start of xdr_buf is contained * entirely in the head or the tail, set object to point to it; otherwise * try to find space for it at the end of the tail, copy it there, and * set obj to point to it. */intxdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, int offset){	u32	tail_offset = buf->head[0].iov_len + buf->page_len;	u32	obj_end_offset;	if (read_u32_from_xdr_buf(buf, offset, &obj->len))		goto out;	obj_end_offset = offset + 4 + obj->len;	if (obj_end_offset <= buf->head[0].iov_len) {		/* The obj is contained entirely in the head: */		obj->data = buf->head[0].iov_base + offset + 4;	} else if (offset + 4 >= tail_offset) {		if (obj_end_offset - tail_offset				> buf->tail[0].iov_len)			goto out;		/* The obj is contained entirely in the tail: */		obj->data = buf->tail[0].iov_base			+ offset - tail_offset + 4;	} else {		/* use end of tail as storage for obj:		 * (We don't copy to the beginning because then we'd have		 * to worry about doing a potentially overlapping copy.		 * This assumes the object is at most half the length of the		 * tail.) */		if (obj->len > buf->tail[0].iov_len)			goto out;		obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len - 				obj->len;		if (read_bytes_from_xdr_buf(buf, offset + 4,					obj->data, obj->len))			goto out;	}	return 0;out:	return -1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -