xdr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:7k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/net/sunrpc/xdr.c
  3.  *
  4.  * Generic XDR support.
  5.  *
  6.  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  7.  */
  8. #include <linux/types.h>
  9. #include <linux/socket.h>
  10. #include <linux/string.h>
  11. #include <linux/kernel.h>
  12. #include <linux/pagemap.h>
  13. #include <linux/errno.h>
  14. #include <linux/in.h>
  15. #include <linux/sunrpc/xdr.h>
  16. #include <linux/sunrpc/msg_prot.h>
  17. /*
  18.  * XDR functions for basic NFS types
  19.  */
  20. u32 *
  21. xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
  22. {
  23. unsigned int quadlen = XDR_QUADLEN(obj->len);
  24. p[quadlen] = 0; /* zero trailing bytes */
  25. *p++ = htonl(obj->len);
  26. memcpy(p, obj->data, obj->len);
  27. return p + XDR_QUADLEN(obj->len);
  28. }
  29. u32 *
  30. xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len)
  31. {
  32. if (ntohl(*p++) != len)
  33. return NULL;
  34. memcpy(obj, p, len);
  35. return p + XDR_QUADLEN(len);
  36. }
  37. u32 *
  38. xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
  39. {
  40. unsigned int len;
  41. if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ)
  42. return NULL;
  43. obj->len  = len;
  44. obj->data = (u8 *) p;
  45. return p + XDR_QUADLEN(len);
  46. }
  47. u32 *
  48. xdr_encode_array(u32 *p, const char *array, unsigned int len)
  49. {
  50. int quadlen = XDR_QUADLEN(len);
  51. p[quadlen] = 0;
  52. *p++ = htonl(len);
  53. memcpy(p, array, len);
  54. return p + quadlen;
  55. }
  56. u32 *
  57. xdr_encode_string(u32 *p, const char *string)
  58. {
  59. return xdr_encode_array(p, string, strlen(string));
  60. }
  61. u32 *
  62. xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
  63. {
  64. unsigned int len;
  65. char *string;
  66. if ((len = ntohl(*p++)) > maxlen)
  67. return NULL;
  68. if (lenp)
  69. *lenp = len;
  70. if ((len % 4) != 0) {
  71. string = (char *) p;
  72. } else {
  73. string = (char *) (p - 1);
  74. memmove(string, p, len);
  75. }
  76. string[len] = '';
  77. *sp = string;
  78. return p + XDR_QUADLEN(len);
  79. }
  80. u32 *
  81. xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
  82. {
  83. unsigned int len;
  84. if ((len = ntohl(*p++)) > maxlen)
  85. return NULL;
  86. *lenp = len;
  87. *sp = (char *) p;
  88. return p + XDR_QUADLEN(len);
  89. }
  90. void
  91. xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
  92.  unsigned int len)
  93. {
  94. xdr->pages = pages;
  95. xdr->page_base = base;
  96. xdr->page_len = len;
  97. if (len & 3) {
  98. struct iovec *iov = xdr->tail;
  99. unsigned int pad = 4 - (len & 3);
  100. iov->iov_base = (void *) "";
  101. iov->iov_len  = pad;
  102. len += pad;
  103. }
  104. xdr->len += len;
  105. }
  106. void
  107. xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
  108.  struct page **pages, unsigned int base, unsigned int len)
  109. {
  110. struct iovec *head = xdr->head;
  111. struct iovec *tail = xdr->tail;
  112. char *buf = (char *)head->iov_base;
  113. unsigned int buflen = head->iov_len;
  114. head->iov_len  = offset;
  115. xdr->pages = pages;
  116. xdr->page_base = base;
  117. xdr->page_len = len;
  118. tail->iov_base = buf + offset;
  119. tail->iov_len = buflen - offset;
  120. xdr->len += len;
  121. }
  122. /*
  123.  * Realign the iovec if the server missed out some reply elements
  124.  * (such as post-op attributes,...)
  125.  * Note: This is a simple implementation that assumes that
  126.  *            len <= iov->iov_len !!!
  127.  *       The RPC header (assumed to be the 1st element in the iov array)
  128.  *            is not shifted.
  129.  */
  130. void xdr_shift_iovec(struct iovec *iov, int nr, size_t len)
  131. {
  132. struct iovec *pvec;
  133. for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
  134. struct iovec *svec = pvec - 1;
  135. if (len > pvec->iov_len) {
  136. printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.n");
  137. return;
  138. }
  139. memmove((char *)pvec->iov_base + len, pvec->iov_base,
  140. pvec->iov_len - len);
  141. if (len > svec->iov_len) {
  142. printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.n");
  143. return;
  144. }
  145. memcpy(pvec->iov_base,
  146.        (char *)svec->iov_base + svec->iov_len - len, len);
  147. }
  148. }
  149. /*
  150.  * Map a struct xdr_buf into an iovec array.
  151.  */
  152. int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, unsigned int base)
  153. {
  154. struct iovec *iov = iov_base;
  155. struct page **ppage = xdr->pages;
  156. unsigned int len, pglen = xdr->page_len;
  157. len = xdr->head[0].iov_len;
  158. if (base < len) {
  159. iov->iov_len = len - base;
  160. iov->iov_base = (char *)xdr->head[0].iov_base + base;
  161. iov++;
  162. base = 0;
  163. } else
  164. base -= len;
  165. if (pglen == 0)
  166. goto map_tail;
  167. if (base >= pglen) {
  168. base -= pglen;
  169. goto map_tail;
  170. }
  171. if (base || xdr->page_base) {
  172. pglen -= base;
  173. base  += xdr->page_base;
  174. ppage += base >> PAGE_CACHE_SHIFT;
  175. base &= ~PAGE_CACHE_MASK;
  176. }
  177. do {
  178. len = PAGE_CACHE_SIZE;
  179. iov->iov_base = kmap(*ppage);
  180. if (base) {
  181. iov->iov_base += base;
  182. len -= base;
  183. base = 0;
  184. }
  185. if (pglen < len)
  186. len = pglen;
  187. iov->iov_len = len;
  188. iov++;
  189. ppage++;
  190. } while ((pglen -= len) != 0);
  191. map_tail:
  192. if (xdr->tail[0].iov_len) {
  193. iov->iov_len = xdr->tail[0].iov_len - base;
  194. iov->iov_base = (char *)xdr->tail[0].iov_base + base;
  195. iov++;
  196. }
  197. return (iov - iov_base);
  198. }
  199. void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
  200. {
  201. struct page **ppage = xdr->pages;
  202. unsigned int pglen = xdr->page_len;
  203. if (!pglen)
  204. return;
  205. if (base > xdr->head[0].iov_len)
  206. base -= xdr->head[0].iov_len;
  207. else
  208. base = 0;
  209. if (base >= pglen)
  210. return;
  211. if (base || xdr->page_base) {
  212. pglen -= base;
  213. base  += xdr->page_base;
  214. ppage += base >> PAGE_CACHE_SHIFT;
  215. /* Note: The offset means that the length of the first
  216.  * page is really (PAGE_CACHE_SIZE - (base & ~PAGE_CACHE_MASK)).
  217.  * In order to avoid an extra test inside the loop,
  218.  * we bump pglen here, and just subtract PAGE_CACHE_SIZE... */
  219. pglen += base & ~PAGE_CACHE_MASK;
  220. }
  221. for (;;) {
  222. flush_dcache_page(*ppage);
  223. kunmap(*ppage);
  224. if (pglen <= PAGE_CACHE_SIZE)
  225. break;
  226. pglen -= PAGE_CACHE_SIZE;
  227. ppage++;
  228. }
  229. }
  230. void
  231. xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
  232.   skb_reader_t *desc,
  233.   skb_read_actor_t copy_actor)
  234. {
  235. struct page **ppage = xdr->pages;
  236. unsigned int len, pglen = xdr->page_len;
  237. int ret;
  238. len = xdr->head[0].iov_len;
  239. if (base < len) {
  240. len -= base;
  241. ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
  242. if (ret != len || !desc->count)
  243. return;
  244. base = 0;
  245. } else
  246. base -= len;
  247. if (pglen == 0)
  248. goto copy_tail;
  249. if (base >= pglen) {
  250. base -= pglen;
  251. goto copy_tail;
  252. }
  253. if (base || xdr->page_base) {
  254. pglen -= base;
  255. base  += xdr->page_base;
  256. ppage += base >> PAGE_CACHE_SHIFT;
  257. base &= ~PAGE_CACHE_MASK;
  258. }
  259. do {
  260. char *kaddr;
  261. len = PAGE_CACHE_SIZE;
  262. kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
  263. if (base) {
  264. len -= base;
  265. if (pglen < len)
  266. len = pglen;
  267. ret = copy_actor(desc, kaddr + base, len);
  268. base = 0;
  269. } else {
  270. if (pglen < len)
  271. len = pglen;
  272. ret = copy_actor(desc, kaddr, len);
  273. }
  274. kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
  275. if (ret != len || !desc->count)
  276. return;
  277. ppage++;
  278. } while ((pglen -= len) != 0);
  279. copy_tail:
  280. len = xdr->tail[0].iov_len;
  281. if (len)
  282. copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len);
  283. }
  284. void
  285. xdr_shift_buf(struct xdr_buf *xdr, size_t len)
  286. {
  287. struct iovec iov[MAX_IOVEC];
  288. unsigned int nr;
  289. nr = xdr_kmap(iov, xdr, 0);
  290. xdr_shift_iovec(iov, nr, len);
  291. xdr_kunmap(xdr, 0);
  292. }