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

📄 xdr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * 'nbytes' more bytes of data starting at the current position. * If so return the current pointer, then update the current * pointer position. */__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes){	__be32 *p = xdr->p;	__be32 *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[]. */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 = (__be32 *)((char *)iov->iov_base + padding);	xdr->end = (__be32 *)((char *)iov->iov_base + end);}EXPORT_SYMBOL(xdr_read_pages);/** * xdr_enter_page - decode data from the XDR page * @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 first XDR page. */void xdr_enter_page(struct xdr_stream *xdr, unsigned int len){	char * kaddr = page_address(xdr->buf->pages[0]);	xdr_read_pages(xdr, len);	/*	 * Position current pointer at beginning of tail, and	 * set remaining message length.	 */	if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)		len = PAGE_CACHE_SIZE - xdr->buf->page_base;	xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);	xdr->end = (__be32 *)((char *)xdr->p + len);}EXPORT_SYMBOL(xdr_enter_page);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 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,			unsigned int base, unsigned int len){	subbuf->buflen = subbuf->len = len;	if (base < buf->head[0].iov_len) {		subbuf->head[0].iov_base = buf->head[0].iov_base + base;		subbuf->head[0].iov_len = min_t(unsigned int, len,						buf->head[0].iov_len - base);		len -= subbuf->head[0].iov_len;		base = 0;	} else {		subbuf->head[0].iov_base = NULL;		subbuf->head[0].iov_len = 0;		base -= buf->head[0].iov_len;	}	if (base < buf->page_len) {		subbuf->page_len = min(buf->page_len - base, len);		base += buf->page_base;		subbuf->page_base = base & ~PAGE_CACHE_MASK;		subbuf->pages = &buf->pages[base >> PAGE_CACHE_SHIFT];		len -= subbuf->page_len;		base = 0;	} else {		base -= buf->page_len;		subbuf->page_len = 0;	}	if (base < buf->tail[0].iov_len) {		subbuf->tail[0].iov_base = buf->tail[0].iov_base + base;		subbuf->tail[0].iov_len = min_t(unsigned int, len,						buf->tail[0].iov_len - base);		len -= subbuf->tail[0].iov_len;		base = 0;	} else {		subbuf->tail[0].iov_base = NULL;		subbuf->tail[0].iov_len = 0;		base -= buf->tail[0].iov_len;	}	if (base || len)		return -1;	return 0;}static void __read_bytes_from_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len){	unsigned int this_len;	this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);	memcpy(obj, subbuf->head[0].iov_base, this_len);	len -= this_len;	obj += this_len;	this_len = min_t(unsigned int, len, 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_t(unsigned int, len, subbuf->tail[0].iov_len);	memcpy(obj, subbuf->tail[0].iov_base, this_len);}/* obj is assumed to point to allocated memory of size at least len: */int read_bytes_from_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len){	struct xdr_buf subbuf;	int status;	status = xdr_buf_subsegment(buf, &subbuf, base, len);	if (status != 0)		return status;	__read_bytes_from_xdr_buf(&subbuf, obj, len);	return 0;}static void __write_bytes_to_xdr_buf(struct xdr_buf *subbuf, void *obj, unsigned int len){	unsigned int this_len;	this_len = min_t(unsigned int, len, subbuf->head[0].iov_len);	memcpy(subbuf->head[0].iov_base, obj, this_len);	len -= this_len;	obj += this_len;	this_len = min_t(unsigned int, len, subbuf->page_len);	if (this_len)		_copy_to_pages(subbuf->pages, subbuf->page_base, obj, this_len);	len -= this_len;	obj += this_len;	this_len = min_t(unsigned int, len, subbuf->tail[0].iov_len);	memcpy(subbuf->tail[0].iov_base, obj, this_len);}/* obj is assumed to point to allocated memory of size at least len: */int write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, unsigned int len){	struct xdr_buf subbuf;	int status;	status = xdr_buf_subsegment(buf, &subbuf, base, len);	if (status != 0)		return status;	__write_bytes_to_xdr_buf(&subbuf, obj, len);	return 0;}intxdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj){	__be32	raw;	int	status;	status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));	if (status)		return status;	*obj = ntohl(raw);	return 0;}intxdr_encode_word(struct xdr_buf *buf, unsigned int base, u32 obj){	__be32	raw = htonl(obj);	return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));}/* 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. */int xdr_buf_read_netobj(struct xdr_buf *buf, struct xdr_netobj *obj, unsigned int offset){	struct xdr_buf subbuf;	if (xdr_decode_word(buf, offset, &obj->len))		return -EFAULT;	if (xdr_buf_subsegment(buf, &subbuf, offset + 4, obj->len))		return -EFAULT;	/* Is the obj contained entirely in the head? */	obj->data = subbuf.head[0].iov_base;	if (subbuf.head[0].iov_len == obj->len)		return 0;	/* ..or is the obj contained entirely in the tail? */	obj->data = subbuf.tail[0].iov_base;	if (subbuf.tail[0].iov_len == obj->len)		return 0;	/* 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->buflen - buf->len)		return -ENOMEM;	if (buf->tail[0].iov_len != 0)		obj->data = buf->tail[0].iov_base + buf->tail[0].iov_len;	else		obj->data = buf->head[0].iov_base + buf->head[0].iov_len;	__read_bytes_from_xdr_buf(&subbuf, obj->data, obj->len);	return 0;}/* Returns 0 on success, or else a negative error code. */static intxdr_xcode_array2(struct xdr_buf *buf, unsigned int base,		 struct xdr_array2_desc *desc, int encode){	char *elem = NULL, *c;	unsigned int copied = 0, todo, avail_here;	struct page **ppages = NULL;	int err;	if (encode) {		if (xdr_encode_word(buf, base, desc->array_len) != 0)			return -EINVAL;	} else {		if (xdr_decode_word(buf, base, &desc->array_len) != 0 ||		    desc->array_len > desc->array_maxlen ||		    (unsigned long) base + 4 + desc->array_len *				    desc->elem_size > buf->len)			return -EINVAL;	}	base += 4;	if (!desc->xcode)		return 0;	todo = desc->array_len * desc->elem_size;	/* process head */	if (todo && base < buf->head->iov_len) {		c = buf->head->iov_base + base;		avail_here = min_t(unsigned int, todo,				   buf->head->iov_len - base);		todo -= avail_here;		while (avail_here >= desc->elem_size) {			err = desc->xcode(desc, c);			if (err)				goto out;			c += desc->elem_size;			avail_here -= desc->elem_size;		}		if (avail_here) {			if (!elem) {				elem = kmalloc(desc->elem_size, GFP_KERNEL);				err = -ENOMEM;				if (!elem)					goto out;			}			if (encode) {				err = desc->xcode(desc, elem);				if (err)					goto out;				memcpy(c, elem, avail_here);			} else				memcpy(elem, c, avail_here);			copied = avail_here;		}		base = buf->head->iov_len;  /* align to start of pages */	}	/* process pages array */	base -= buf->head->iov_len;	if (todo && base < buf->page_len) {		unsigned int avail_page;		avail_here = min(todo, buf->page_len - base);		todo -= avail_here;		base += buf->page_base;		ppages = buf->pages + (base >> PAGE_CACHE_SHIFT);		base &= ~PAGE_CACHE_MASK;		avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base,					avail_here);		c = kmap(*ppages) + base;		while (avail_here) {			avail_here -= avail_page;			if (copied || avail_page < desc->elem_size) {				unsigned int l = min(avail_page,					desc->elem_size - copied);				if (!elem) {					elem = kmalloc(desc->elem_size,						       GFP_KERNEL);					err = -ENOMEM;					if (!elem)						goto out;				}				if (encode) {					if (!copied) {						err = desc->xcode(desc, elem);						if (err)							goto out;					}					memcpy(c, elem + copied, l);					copied += l;					if (copied == desc->elem_size)						copied = 0;				} else {					memcpy(elem + copied, c, l);					copied += l;					if (copied == desc->elem_size) {						err = desc->xcode(desc, elem);						if (err)							goto out;						copied = 0;					}				}				avail_page -= l;				c += l;			}			while (avail_page >= desc->elem_size) {				err = desc->xcode(desc, c);				if (err)					goto out;				c += desc->elem_size;				avail_page -= desc->elem_size;			}			if (avail_page) {				unsigned int l = min(avail_page,					    desc->elem_size - copied);				if (!elem) {					elem = kmalloc(desc->elem_size,						       GFP_KERNEL);					err = -ENOMEM;					if (!elem)						goto out;				}				if (encode) {					if (!copied) {						err = desc->xcode(desc, elem);						if (err)							goto out;					}					memcpy(c, elem + copied, l);					copied += l;					if (copied == desc->elem_size)						copied = 0;				} else {					memcpy(elem + copied, c, l);					copied += l;					if (copied == desc->elem_size) {						err = desc->xcode(desc, elem);						if (err)							goto out;						copied = 0;					}				}			}			if (avail_here) {				kunmap(*ppages);				ppages++;				c = kmap(*ppages);			}			avail_page = min(avail_here,				 (unsigned int) PAGE_CACHE_SIZE);		}		base = buf->page_len;  /* align to start of tail */	}	/* process tail */	base -= buf->page_len;	if (todo) {		c = buf->tail->iov_base + base;		if (copied) {			unsigned int l = desc->elem_size - copied;			if (encode)				memcpy(c, elem + copied, l);			else {				memcpy(elem + copied, c, l);				err = desc->xcode(desc, elem);				if (err)					goto out;			}			todo -= l;			c += l;		}		while (todo) {			err = desc->xcode(desc, c);			if (err)				goto out;			c += desc->elem_size;			todo -= desc->elem_size;		}	}	err = 0;out:	kfree(elem);	if (ppages)		kunmap(*ppages);	return err;}intxdr_decode_array2(struct xdr_buf *buf, unsigned int base,		  struct xdr_array2_desc *desc){	if (base >= buf->len)		return -EINVAL;	return xdr_xcode_array2(buf, base, desc, 0);}intxdr_encode_array2(struct xdr_buf *buf, unsigned int base,		  struct xdr_array2_desc *desc){	if ((unsigned long) base + 4 + desc->array_len * desc->elem_size >	    buf->head->iov_len + buf->page_len + buf->tail->iov_len)		return -EINVAL;	return xdr_xcode_array2(buf, base, desc, 1);}intxdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len,		int (*actor)(struct scatterlist *, void *), void *data){	int i, ret = 0;	unsigned page_len, thislen, page_offset;	struct scatterlist      sg[1];	sg_init_table(sg, 1);	if (offset >= buf->head[0].iov_len) {		offset -= buf->head[0].iov_len;	} else {		thislen = buf->head[0].iov_len - offset;		if (thislen > len)			thislen = len;		sg_set_buf(sg, buf->head[0].iov_base + offset, thislen);		ret = actor(sg, data);		if (ret)			goto out;		offset = 0;		len -= thislen;	}	if (len == 0)		goto out;	if (offset >= buf->page_len) {		offset -= buf->page_len;	} else {		page_len = buf->page_len - offset;		if (page_len > len)			page_len = len;		len -= page_len;		page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1);		i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT;		thislen = PAGE_CACHE_SIZE - page_offset;		do {			if (thislen > page_len)				thislen = page_len;			sg_set_page(sg, buf->pages[i], thislen, page_offset);			ret = actor(sg, data);			if (ret)				goto out;			page_len -= thislen;			i++;			page_offset = 0;			thislen = PAGE_CACHE_SIZE;		} while (page_len != 0);		offset = 0;	}	if (len == 0)		goto out;	if (offset < buf->tail[0].iov_len) {		thislen = buf->tail[0].iov_len - offset;		if (thislen > len)			thislen = len;		sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen);		ret = actor(sg, data);		len -= thislen;	}	if (len != 0)		ret = -EINVAL;out:	return ret;}EXPORT_SYMBOL(xdr_process_buf);

⌨️ 快捷键说明

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