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

📄 xdr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/net/sunrpc/xdr.c * * Generic XDR support. * * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/pagemap.h>#include <linux/errno.h>#include <linux/sunrpc/xdr.h>#include <linux/sunrpc/msg_prot.h>/* * XDR functions for basic NFS types */__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj){	unsigned int	quadlen = XDR_QUADLEN(obj->len);	p[quadlen] = 0;		/* zero trailing bytes */	*p++ = htonl(obj->len);	memcpy(p, obj->data, obj->len);	return p + XDR_QUADLEN(obj->len);}__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj){	unsigned int	len;	if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ)		return NULL;	obj->len  = len;	obj->data = (u8 *) p;	return p + XDR_QUADLEN(len);}/** * xdr_encode_opaque_fixed - Encode fixed length opaque data * @p: pointer to current position in XDR buffer. * @ptr: pointer to data to encode (or NULL) * @nbytes: size of data. * * Copy the array of data of length nbytes at ptr to the XDR buffer * at position p, then align to the next 32-bit boundary by padding * with zero bytes (see RFC1832). * Note: if ptr is NULL, only the padding is performed. * * Returns the updated current XDR buffer position * */__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes){	if (likely(nbytes != 0)) {		unsigned int quadlen = XDR_QUADLEN(nbytes);		unsigned int padding = (quadlen << 2) - nbytes;		if (ptr != NULL)			memcpy(p, ptr, nbytes);		if (padding != 0)			memset((char *)p + nbytes, 0, padding);		p += quadlen;	}	return p;}EXPORT_SYMBOL(xdr_encode_opaque_fixed);/** * xdr_encode_opaque - Encode variable length opaque data * @p: pointer to current position in XDR buffer. * @ptr: pointer to data to encode (or NULL) * @nbytes: size of data. * * Returns the updated current XDR buffer position */__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes){	*p++ = htonl(nbytes);	return xdr_encode_opaque_fixed(p, ptr, nbytes);}EXPORT_SYMBOL(xdr_encode_opaque);__be32 *xdr_encode_string(__be32 *p, const char *string){	return xdr_encode_array(p, string, strlen(string));}__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen){	unsigned int	len;	if ((len = ntohl(*p++)) > maxlen)		return NULL;	*lenp = len;	*sp = (char *) p;	return p + XDR_QUADLEN(len);}voidxdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,		 unsigned int len){	struct kvec *tail = xdr->tail;	u32 *p;	xdr->pages = pages;	xdr->page_base = base;	xdr->page_len = len;	p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);	tail->iov_base = p;	tail->iov_len = 0;	if (len & 3) {		unsigned int pad = 4 - (len & 3);		*p = 0;		tail->iov_base = (char *)p + (len & 3);		tail->iov_len  = pad;		len += pad;	}	xdr->buflen += len;	xdr->len += len;}voidxdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,		 struct page **pages, unsigned int base, unsigned int len){	struct kvec *head = xdr->head;	struct kvec *tail = xdr->tail;	char *buf = (char *)head->iov_base;	unsigned int buflen = head->iov_len;	head->iov_len  = offset;	xdr->pages = pages;	xdr->page_base = base;	xdr->page_len = len;	tail->iov_base = buf + offset;	tail->iov_len = buflen - offset;	xdr->buflen += len;}/* * Helper routines for doing 'memmove' like operations on a struct xdr_buf * * _shift_data_right_pages * @pages: vector of pages containing both the source and dest memory area. * @pgto_base: page vector address of destination * @pgfrom_base: page vector address of source * @len: number of bytes to copy * * Note: the addresses pgto_base and pgfrom_base are both calculated in *       the same way: *            if a memory area starts at byte 'base' in page 'pages[i]', *            then its address is given as (i << PAGE_CACHE_SHIFT) + base * Also note: pgfrom_base must be < pgto_base, but the memory areas * 	they point to may overlap. */static void_shift_data_right_pages(struct page **pages, size_t pgto_base,		size_t pgfrom_base, size_t len){	struct page **pgfrom, **pgto;	char *vfrom, *vto;	size_t copy;	BUG_ON(pgto_base <= pgfrom_base);	pgto_base += len;	pgfrom_base += len;	pgto = pages + (pgto_base >> PAGE_CACHE_SHIFT);	pgfrom = pages + (pgfrom_base >> PAGE_CACHE_SHIFT);	pgto_base &= ~PAGE_CACHE_MASK;	pgfrom_base &= ~PAGE_CACHE_MASK;	do {		/* Are any pointers crossing a page boundary? */		if (pgto_base == 0) {			pgto_base = PAGE_CACHE_SIZE;			pgto--;		}		if (pgfrom_base == 0) {			pgfrom_base = PAGE_CACHE_SIZE;			pgfrom--;		}		copy = len;		if (copy > pgto_base)			copy = pgto_base;		if (copy > pgfrom_base)			copy = pgfrom_base;		pgto_base -= copy;		pgfrom_base -= copy;		vto = kmap_atomic(*pgto, KM_USER0);		vfrom = kmap_atomic(*pgfrom, KM_USER1);		memmove(vto + pgto_base, vfrom + pgfrom_base, copy);		flush_dcache_page(*pgto);		kunmap_atomic(vfrom, KM_USER1);		kunmap_atomic(vto, KM_USER0);	} 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) {			flush_dcache_page(*pgto);			pgbase = 0;			pgto++;		}		p += copy;	} while ((len -= copy) != 0);	flush_dcache_page(*pgto);}/* * _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. */static 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. */static 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. */static 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, __be32 *p){	struct kvec *iov = buf->head;	int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;	BUG_ON(scratch_len < 0);	xdr->buf = buf;	xdr->iov = iov;	xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);	xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);	BUG_ON(iov->iov_len > scratch_len);	if (p != xdr->p && p != NULL) {		size_t len;		BUG_ON(p < xdr->p || p > xdr->end);		len = (char *)p - (char *)xdr->p;		xdr->p = p;		buf->len += len;		iov->iov_len += len;	}}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. */__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes){	__be32 *p = xdr->p;	__be32 *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, __be32 *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 = (__be32 *)((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

⌨️ 快捷键说明

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