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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/nfs/nfs3xdr.c
  3.  *
  4.  * XDR functions to encode/decode NFSv3 RPC arguments and results.
  5.  *
  6.  * Copyright (C) 1996, 1997 Olaf Kirch
  7.  */
  8. #include <linux/param.h>
  9. #include <linux/sched.h>
  10. #include <linux/mm.h>
  11. #include <linux/slab.h>
  12. #include <linux/utsname.h>
  13. #include <linux/errno.h>
  14. #include <linux/string.h>
  15. #include <linux/in.h>
  16. #include <linux/pagemap.h>
  17. #include <linux/proc_fs.h>
  18. #include <linux/kdev_t.h>
  19. #include <linux/sunrpc/clnt.h>
  20. #include <linux/nfs.h>
  21. #include <linux/nfs3.h>
  22. #include <linux/nfs_fs.h>
  23. #define NFSDBG_FACILITY NFSDBG_XDR
  24. /* Mapping from NFS error code to "errno" error code. */
  25. #define errno_NFSERR_IO EIO
  26. extern int nfs_stat_to_errno(int);
  27. /*
  28.  * Declare the space requirements for NFS arguments and replies as
  29.  * number of 32bit-words
  30.  */
  31. #define NFS3_fhandle_sz 1+16
  32. #define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */
  33. #define NFS3_sattr_sz 15
  34. #define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2)
  35. #define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2)
  36. #define NFS3_fattr_sz 21
  37. #define NFS3_wcc_attr_sz 6
  38. #define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz
  39. #define NFS3_post_op_attr_sz 1+NFS3_fattr_sz
  40. #define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
  41. #define NFS3_fsstat_sz
  42. #define NFS3_fsinfo_sz
  43. #define NFS3_pathconf_sz
  44. #define NFS3_entry_sz NFS3_filename_sz+3
  45. #define NFS3_enc_void_sz 0
  46. #define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3
  47. #define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz
  48. #define NFS3_accessargs_sz NFS3_fh_sz+1
  49. #define NFS3_readlinkargs_sz NFS3_fh_sz
  50. #define NFS3_readargs_sz NFS3_fh_sz+3
  51. #define NFS3_writeargs_sz NFS3_fh_sz+5
  52. #define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
  53. #define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
  54. #define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
  55. #define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz
  56. #define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz
  57. #define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz
  58. #define NFS3_readdirargs_sz NFS3_fh_sz+2
  59. #define NFS3_commitargs_sz NFS3_fh_sz+3
  60. #define NFS3_dec_void_sz 0
  61. #define NFS3_attrstat_sz 1+NFS3_fattr_sz
  62. #define NFS3_wccstat_sz 1+NFS3_wcc_data_sz
  63. #define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
  64. #define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1
  65. #define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz
  66. #define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3
  67. #define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4
  68. #define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
  69. #define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz)
  70. #define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
  71. #define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2
  72. #define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13
  73. #define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12
  74. #define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6
  75. #define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2
  76. /*
  77.  * Map file type to S_IFMT bits
  78.  */
  79. static struct {
  80. unsigned int mode;
  81. unsigned int nfs2type;
  82. } nfs_type2fmt[] = {
  83.       { 0, NFNON },
  84.       { S_IFREG, NFREG },
  85.       { S_IFDIR, NFDIR },
  86.       { S_IFBLK, NFBLK },
  87.       { S_IFCHR, NFCHR },
  88.       { S_IFLNK, NFLNK },
  89.       { S_IFSOCK, NFSOCK },
  90.       { S_IFIFO, NFFIFO },
  91.       { 0, NFBAD }
  92. };
  93. /*
  94.  * Common NFS XDR functions as inlines
  95.  */
  96. static inline u32 *
  97. xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
  98. {
  99. *p++ = htonl(fh->size);
  100. memcpy(p, fh->data, fh->size);
  101. return p + XDR_QUADLEN(fh->size);
  102. }
  103. static inline u32 *
  104. xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
  105. {
  106. /*
  107.  * Zero all nonused bytes
  108.  */
  109. memset((u8 *)fh, 0, sizeof(*fh));
  110. if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
  111. memcpy(fh->data, p, fh->size);
  112. return p + XDR_QUADLEN(fh->size);
  113. }
  114. return NULL;
  115. }
  116. /*
  117.  * Encode/decode time.
  118.  * Since the VFS doesn't care for fractional times, we ignore the
  119.  * nanosecond field.
  120.  */
  121. static inline u32 *
  122. xdr_encode_time(u32 *p, time_t time)
  123. {
  124. *p++ = htonl(time);
  125. *p++ = 0;
  126. return p;
  127. }
  128. static inline u32 *
  129. xdr_decode_time3(u32 *p, u64 *timep)
  130. {
  131. u64 tmp = (u64)ntohl(*p++) << 32;
  132. *timep = tmp + (u64)ntohl(*p++);
  133. return p;
  134. }
  135. static inline u32 *
  136. xdr_encode_time3(u32 *p, u64 time)
  137. {
  138. *p++ = htonl(time >> 32);
  139. *p++ = htonl(time & 0xFFFFFFFF);
  140. return p;
  141. }
  142. static u32 *
  143. xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
  144. {
  145. unsigned int type;
  146. int fmode;
  147. type = ntohl(*p++);
  148. if (type >= NF3BAD)
  149. type = NF3BAD;
  150. fmode = nfs_type2fmt[type].mode;
  151. fattr->type = nfs_type2fmt[type].nfs2type;
  152. fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
  153. fattr->nlink = ntohl(*p++);
  154. fattr->uid = ntohl(*p++);
  155. fattr->gid = ntohl(*p++);
  156. p = xdr_decode_hyper(p, &fattr->size);
  157. p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
  158. /* Turn remote device info into Linux-specific dev_t */
  159. fattr->rdev = ntohl(*p++) << MINORBITS;
  160. fattr->rdev |= ntohl(*p++) & MINORMASK;
  161. p = xdr_decode_hyper(p, &fattr->fsid);
  162. p = xdr_decode_hyper(p, &fattr->fileid);
  163. p = xdr_decode_time3(p, &fattr->atime);
  164. p = xdr_decode_time3(p, &fattr->mtime);
  165. p = xdr_decode_time3(p, &fattr->ctime);
  166. /* Update the mode bits */
  167. fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
  168. return p;
  169. }
  170. static inline u32 *
  171. xdr_encode_sattr(u32 *p, struct iattr *attr)
  172. {
  173. if (attr->ia_valid & ATTR_MODE) {
  174. *p++ = xdr_one;
  175. *p++ = htonl(attr->ia_mode);
  176. } else {
  177. *p++ = xdr_zero;
  178. }
  179. if (attr->ia_valid & ATTR_UID) {
  180. *p++ = xdr_one;
  181. *p++ = htonl(attr->ia_uid);
  182. } else {
  183. *p++ = xdr_zero;
  184. }
  185. if (attr->ia_valid & ATTR_GID) {
  186. *p++ = xdr_one;
  187. *p++ = htonl(attr->ia_gid);
  188. } else {
  189. *p++ = xdr_zero;
  190. }
  191. if (attr->ia_valid & ATTR_SIZE) {
  192. *p++ = xdr_one;
  193. p = xdr_encode_hyper(p, (__u64) attr->ia_size);
  194. } else {
  195. *p++ = xdr_zero;
  196. }
  197. if (attr->ia_valid & ATTR_ATIME_SET) {
  198. *p++ = xdr_two;
  199. p = xdr_encode_time(p, attr->ia_atime);
  200. } else if (attr->ia_valid & ATTR_ATIME) {
  201. *p++ = xdr_one;
  202. } else {
  203. *p++ = xdr_zero;
  204. }
  205. if (attr->ia_valid & ATTR_MTIME_SET) {
  206. *p++ = xdr_two;
  207. p = xdr_encode_time(p, attr->ia_mtime);
  208. } else if (attr->ia_valid & ATTR_MTIME) {
  209. *p++ = xdr_one;
  210. } else {
  211. *p++ = xdr_zero;
  212. }
  213. return p;
  214. }
  215. static inline u32 *
  216. xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
  217. {
  218. p = xdr_decode_hyper(p, &fattr->pre_size);
  219. p = xdr_decode_time3(p, &fattr->pre_mtime);
  220. p = xdr_decode_time3(p, &fattr->pre_ctime);
  221. fattr->valid |= NFS_ATTR_WCC;
  222. return p;
  223. }
  224. static inline u32 *
  225. xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
  226. {
  227. if (*p++)
  228. p = xdr_decode_fattr(p, fattr);
  229. return p;
  230. }
  231. static inline u32 *
  232. xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
  233. {
  234. if (*p++)
  235. return xdr_decode_wcc_attr(p, fattr);
  236. return p;
  237. }
  238. static inline u32 *
  239. xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
  240. {
  241. p = xdr_decode_pre_op_attr(p, fattr);
  242. return xdr_decode_post_op_attr(p, fattr);
  243. }
  244. /*
  245.  * NFS encode functions
  246.  */
  247. /*
  248.  * Encode void argument
  249.  */
  250. static int
  251. nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
  252. {
  253. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  254. return 0;
  255. }
  256. /*
  257.  * Encode file handle argument
  258.  */
  259. static int
  260. nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
  261. {
  262. p = xdr_encode_fhandle(p, fh);
  263. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  264. return 0;
  265. }
  266. /*
  267.  * Encode SETATTR arguments
  268.  */
  269. static int
  270. nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
  271. {
  272. p = xdr_encode_fhandle(p, args->fh);
  273. p = xdr_encode_sattr(p, args->sattr);
  274. *p++ = htonl(args->guard);
  275. if (args->guard)
  276. p = xdr_encode_time3(p, args->guardtime);
  277. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  278. return 0;
  279. }
  280. /*
  281.  * Encode directory ops argument
  282.  */
  283. static int
  284. nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
  285. {
  286. p = xdr_encode_fhandle(p, args->fh);
  287. p = xdr_encode_array(p, args->name, args->len);
  288. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  289. return 0;
  290. }
  291. /*
  292.  * Encode access() argument
  293.  */
  294. static int
  295. nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
  296. {
  297. p = xdr_encode_fhandle(p, args->fh);
  298. *p++ = htonl(args->access);
  299. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  300. return 0;
  301. }
  302. /*
  303.  * Arguments to a READ call. Since we read data directly into the page
  304.  * cache, we also set up the reply iovec here so that iov[1] points
  305.  * exactly to the page we want to fetch.
  306.  */
  307. static int
  308. nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
  309. {
  310. struct rpc_auth *auth = req->rq_task->tk_auth;
  311. unsigned int replen;
  312. u32 count = args->count;
  313. p = xdr_encode_fhandle(p, args->fh);
  314. p = xdr_encode_hyper(p, args->offset);
  315. *p++ = htonl(count);
  316. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  317. /* Inline the page array */
  318. replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
  319. xdr_inline_pages(&req->rq_rcv_buf, replen,
  320.  args->pages, args->pgbase, count);
  321. return 0;
  322. }
  323. /*
  324.  * Write arguments. Splice the buffer to be written into the iovec.
  325.  */
  326. static int
  327. nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
  328. {
  329. struct xdr_buf *sndbuf = &req->rq_snd_buf;
  330. u32 count = args->count;
  331. p = xdr_encode_fhandle(p, args->fh);
  332. p = xdr_encode_hyper(p, args->offset);
  333. *p++ = htonl(count);
  334. *p++ = htonl(args->stable);
  335. *p++ = htonl(count);
  336. sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
  337. /* Copy the page array */
  338. xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
  339. return 0;
  340. }
  341. /*
  342.  * Encode CREATE arguments
  343.  */
  344. static int
  345. nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
  346. {
  347. p = xdr_encode_fhandle(p, args->fh);
  348. p = xdr_encode_array(p, args->name, args->len);
  349. *p++ = htonl(args->createmode);
  350. if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
  351. *p++ = args->verifier[0];
  352. *p++ = args->verifier[1];
  353. } else
  354. p = xdr_encode_sattr(p, args->sattr);
  355. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  356. return 0;
  357. }
  358. /*
  359.  * Encode MKDIR arguments
  360.  */
  361. static int
  362. nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
  363. {
  364. p = xdr_encode_fhandle(p, args->fh);
  365. p = xdr_encode_array(p, args->name, args->len);
  366. p = xdr_encode_sattr(p, args->sattr);
  367. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  368. return 0;
  369. }
  370. /*
  371.  * Encode SYMLINK arguments
  372.  */
  373. static int
  374. nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
  375. {
  376. p = xdr_encode_fhandle(p, args->fromfh);
  377. p = xdr_encode_array(p, args->fromname, args->fromlen);
  378. p = xdr_encode_sattr(p, args->sattr);
  379. p = xdr_encode_array(p, args->topath, args->tolen);
  380. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  381. return 0;
  382. }
  383. /*
  384.  * Encode MKNOD arguments
  385.  */
  386. static int
  387. nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
  388. {
  389. p = xdr_encode_fhandle(p, args->fh);
  390. p = xdr_encode_array(p, args->name, args->len);
  391. *p++ = htonl(args->type);
  392. p = xdr_encode_sattr(p, args->sattr);
  393. if (args->type == NF3CHR || args->type == NF3BLK) {
  394. *p++ = htonl(args->rdev >> MINORBITS);
  395. *p++ = htonl(args->rdev & MINORMASK);
  396. }
  397. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  398. return 0;
  399. }
  400. /*
  401.  * Encode RENAME arguments
  402.  */
  403. static int
  404. nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
  405. {
  406. p = xdr_encode_fhandle(p, args->fromfh);
  407. p = xdr_encode_array(p, args->fromname, args->fromlen);
  408. p = xdr_encode_fhandle(p, args->tofh);
  409. p = xdr_encode_array(p, args->toname, args->tolen);
  410. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  411. return 0;
  412. }
  413. /*
  414.  * Encode LINK arguments
  415.  */
  416. static int
  417. nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
  418. {
  419. p = xdr_encode_fhandle(p, args->fromfh);
  420. p = xdr_encode_fhandle(p, args->tofh);
  421. p = xdr_encode_array(p, args->toname, args->tolen);
  422. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  423. return 0;
  424. }
  425. /*
  426.  * Encode arguments to readdir call
  427.  */
  428. static int
  429. nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
  430. {
  431. struct rpc_auth *auth = req->rq_task->tk_auth;
  432. unsigned int replen;
  433. u32 count = args->count;
  434. p = xdr_encode_fhandle(p, args->fh);
  435. p = xdr_encode_hyper(p, args->cookie);
  436. *p++ = args->verf[0];
  437. *p++ = args->verf[1];
  438. if (args->plus) {
  439. /* readdirplus: need dircount + buffer size.
  440.  * We just make sure we make dircount big enough */
  441. *p++ = htonl(count >> 3);
  442. }
  443. *p++ = htonl(count);
  444. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  445. /* Inline the page array */
  446. replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
  447. xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
  448. return 0;
  449. }
  450. /*
  451.  * Decode the result of a readdir call.
  452.  * We just check for syntactical correctness.
  453.  */
  454. static int
  455. nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
  456. {
  457. struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
  458. struct iovec *iov = rcvbuf->head;
  459. struct page **page;
  460. int hdrlen, recvd;
  461. int status, nr;
  462. unsigned int len, pglen;
  463. u32 *entry, *end;
  464. status = ntohl(*p++);
  465. /* Decode post_op_attrs */
  466. p = xdr_decode_post_op_attr(p, res->dir_attr);
  467. if (status)
  468. return -nfs_stat_to_errno(status);
  469. /* Decode verifier cookie */
  470. if (res->verf) {
  471. res->verf[0] = *p++;
  472. res->verf[1] = *p++;
  473. } else {
  474. p += 2;
  475. }
  476. hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  477. if (iov->iov_len < hdrlen) {
  478. printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
  479. "length %d > %Zun", hdrlen, iov->iov_len);
  480. return -errno_NFSERR_IO;
  481. } else if (iov->iov_len != hdrlen) {
  482. dprintk("NFS: READDIR header is short. iovec will be shifted.n");
  483. xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
  484. }
  485. pglen = rcvbuf->page_len;
  486. recvd = req->rq_received - hdrlen;
  487. if (pglen > recvd)
  488. pglen = recvd;
  489. page = rcvbuf->pages;
  490. p = kmap(*page);
  491. end = (u32 *)((char *)p + pglen);
  492. entry = p;
  493. for (nr = 0; *p++; nr++) {
  494. if (p + 3 > end)
  495. goto short_pkt;
  496. p += 2; /* inode # */
  497. len = ntohl(*p++); /* string length */
  498. p += XDR_QUADLEN(len) + 2; /* name + cookie */
  499. if (len > NFS3_MAXNAMLEN) {
  500. printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!n",
  501. len);
  502. goto err_unmap;
  503. }
  504. if (res->plus) {
  505. /* post_op_attr */
  506. if (p > end)
  507. goto short_pkt;
  508. if (*p++) {
  509. p += 21;
  510. if (p > end)
  511. goto short_pkt;
  512. }
  513. /* post_op_fh3 */
  514. if (*p++) {
  515. if (p > end)
  516. goto short_pkt;
  517. len = ntohl(*p++);
  518. if (len > NFS3_FHSIZE) {
  519. printk(KERN_WARNING "NFS: giant filehandle in "
  520. "readdir (len %x)!n", len);
  521. goto err_unmap;
  522. }
  523. p += XDR_QUADLEN(len);
  524. }
  525. }
  526. if (p + 2 > end)
  527. goto short_pkt;
  528. entry = p;
  529. }
  530. if (!nr && (entry[0] != 0 || entry[1] == 0))
  531. goto short_pkt;
  532.  out:
  533. kunmap(*page);
  534. return nr;
  535.  short_pkt:
  536. entry[0] = entry[1] = 0;
  537. /* truncate listing ? */
  538. if (!nr) {
  539. printk(KERN_NOTICE "NFS: readdir reply truncated!n");
  540. entry[1] = 1;
  541. }
  542. goto out;
  543. err_unmap:
  544. kunmap(*page);
  545. return -errno_NFSERR_IO;
  546. }
  547. u32 *
  548. nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
  549. {
  550. struct nfs_entry old = *entry;
  551. if (!*p++) {
  552. if (!*p)
  553. return ERR_PTR(-EAGAIN);
  554. entry->eof = 1;
  555. return ERR_PTR(-EBADCOOKIE);
  556. }
  557. p = xdr_decode_hyper(p, &entry->ino);
  558. entry->len  = ntohl(*p++);
  559. entry->name = (const char *) p;
  560. p += XDR_QUADLEN(entry->len);
  561. entry->prev_cookie = entry->cookie;
  562. p = xdr_decode_hyper(p, &entry->cookie);
  563. if (plus) {
  564. p = xdr_decode_post_op_attr(p, &entry->fattr);
  565. /* In fact, a post_op_fh3: */
  566. if (*p++) {
  567. p = xdr_decode_fhandle(p, &entry->fh);
  568. /* Ugh -- server reply was truncated */
  569. if (p == NULL) {
  570. dprintk("NFS: FH truncatedn");
  571. *entry = old;
  572. return ERR_PTR(-EAGAIN);
  573. }
  574. } else {
  575. /* If we don't get a file handle, the attrs
  576.  * aren't worth a lot. */
  577. entry->fattr.valid = 0;
  578. }
  579. }
  580. entry->eof = !p[0] && p[1];
  581. return p;
  582. }
  583. /*
  584.  * Encode COMMIT arguments
  585.  */
  586. static int
  587. nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
  588. {
  589. p = xdr_encode_fhandle(p, args->fh);
  590. p = xdr_encode_hyper(p, args->offset);
  591. *p++ = htonl(args->count);
  592. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  593. return 0;
  594. }
  595. /*
  596.  * NFS XDR decode functions
  597.  */
  598. /*
  599.  * Decode void reply
  600.  */
  601. static int
  602. nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
  603. {
  604. return 0;
  605. }
  606. /*
  607.  * Decode attrstat reply.
  608.  */
  609. static int
  610. nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  611. {
  612. int status;
  613. if ((status = ntohl(*p++)))
  614. return -nfs_stat_to_errno(status);
  615. xdr_decode_fattr(p, fattr);
  616. return 0;
  617. }
  618. /*
  619.  * Decode status+wcc_data reply
  620.  * SATTR, REMOVE, RMDIR
  621.  */
  622. static int
  623. nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  624. {
  625. int status;
  626. if ((status = ntohl(*p++)))
  627. status = -nfs_stat_to_errno(status);
  628. xdr_decode_wcc_data(p, fattr);
  629. return status;
  630. }
  631. /*
  632.  * Decode LOOKUP reply
  633.  */
  634. static int
  635. nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
  636. {
  637. int status;
  638. if ((status = ntohl(*p++))) {
  639. status = -nfs_stat_to_errno(status);
  640. } else {
  641. if (!(p = xdr_decode_fhandle(p, res->fh)))
  642. return -errno_NFSERR_IO;
  643. p = xdr_decode_post_op_attr(p, res->fattr);
  644. }
  645. xdr_decode_post_op_attr(p, res->dir_attr);
  646. return status;
  647. }
  648. /*
  649.  * Decode ACCESS reply
  650.  */
  651. static int
  652. nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
  653. {
  654. int status = ntohl(*p++);
  655. p = xdr_decode_post_op_attr(p, res->fattr);
  656. if (status)
  657. return -nfs_stat_to_errno(status);
  658. res->access = ntohl(*p++);
  659. return 0;
  660. }
  661. static int
  662. nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
  663. {
  664. struct rpc_auth *auth = req->rq_task->tk_auth;
  665. unsigned int replen;
  666. u32 count = args->count - 4;
  667. p = xdr_encode_fhandle(p, args->fh);
  668. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  669. /* Inline the page array */
  670. replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
  671. xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
  672. return 0;
  673. }
  674. /*
  675.  * Decode READLINK reply
  676.  */
  677. static int
  678. nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  679. {
  680. struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
  681. struct iovec *iov = rcvbuf->head;
  682. unsigned int hdrlen;
  683. u32 *strlen, len;
  684. char *string;
  685. int status;
  686. status = ntohl(*p++);
  687. p = xdr_decode_post_op_attr(p, fattr);
  688. if (status != 0)
  689. return -nfs_stat_to_errno(status);
  690. hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  691. if (iov->iov_len > hdrlen) {
  692. dprintk("NFS: READLINK header is short. iovec will be shifted.n");
  693. xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
  694. }
  695. strlen = (u32*)kmap(rcvbuf->pages[0]);
  696. /* Convert length of symlink */
  697. len = ntohl(*strlen);
  698. if (len > rcvbuf->page_len)
  699. len = rcvbuf->page_len;
  700. *strlen = len;
  701. /* NULL terminate the string we got */
  702. string = (char *)(strlen + 1);
  703. string[len] = 0;
  704. kunmap(rcvbuf->pages[0]);
  705. return 0;
  706. }
  707. /*
  708.  * Decode READ reply
  709.  */
  710. static int
  711. nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
  712. {
  713. struct iovec *iov = req->rq_rvec;
  714. int status, count, ocount, recvd, hdrlen;
  715. status = ntohl(*p++);
  716. p = xdr_decode_post_op_attr(p, res->fattr);
  717. if (status != 0)
  718. return -nfs_stat_to_errno(status);
  719. /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
  720.  * in that it puts the count both in the res struct and in the
  721.  * opaque data count. */
  722. count    = ntohl(*p++);
  723. res->eof = ntohl(*p++);
  724. ocount   = ntohl(*p++);
  725. if (ocount != count) {
  726. printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.n");
  727. return -errno_NFSERR_IO;
  728. }
  729. hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  730. if (iov->iov_len < hdrlen) {
  731. printk(KERN_WARNING "NFS: READ reply header overflowed:"
  732. "length %d > %Zun", hdrlen, iov->iov_len);
  733. return -errno_NFSERR_IO;
  734. } else if (iov->iov_len != hdrlen) {
  735. dprintk("NFS: READ header is short. iovec will be shifted.n");
  736. xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
  737. }
  738. recvd = req->rq_received - hdrlen;
  739. if (count > recvd) {
  740. printk(KERN_WARNING "NFS: server cheating in read reply: "
  741. "count %d > recvd %dn", count, recvd);
  742. count = recvd;
  743. res->eof = 0;
  744. }
  745. if (count < res->count)
  746. res->count = count;
  747. return count;
  748. }
  749. /*
  750.  * Decode WRITE response
  751.  */
  752. static int
  753. nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
  754. {
  755. int status;
  756. status = ntohl(*p++);
  757. p = xdr_decode_wcc_data(p, res->fattr);
  758. if (status != 0)
  759. return -nfs_stat_to_errno(status);
  760. res->count = ntohl(*p++);
  761. res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
  762. res->verf->verifier[0] = *p++;
  763. res->verf->verifier[1] = *p++;
  764. return res->count;
  765. }
  766. /*
  767.  * Decode a CREATE response
  768.  */
  769. static int
  770. nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
  771. {
  772. int status;
  773. status = ntohl(*p++);
  774. if (status == 0) {
  775. if (*p++) {
  776. if (!(p = xdr_decode_fhandle(p, res->fh)))
  777. return -errno_NFSERR_IO;
  778. p = xdr_decode_post_op_attr(p, res->fattr);
  779. } else {
  780. memset(res->fh, 0, sizeof(*res->fh));
  781. /* Do decode post_op_attr but set it to NULL */
  782. p = xdr_decode_post_op_attr(p, res->fattr);
  783. res->fattr->valid = 0;
  784. }
  785. } else {
  786. status = -nfs_stat_to_errno(status);
  787. }
  788. p = xdr_decode_wcc_data(p, res->dir_attr);
  789. return status;
  790. }
  791. /*
  792.  * Decode RENAME reply
  793.  */
  794. static int
  795. nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
  796. {
  797. int status;
  798. if ((status = ntohl(*p++)) != 0)
  799. status = -nfs_stat_to_errno(status);
  800. p = xdr_decode_wcc_data(p, res->fromattr);
  801. p = xdr_decode_wcc_data(p, res->toattr);
  802. return status;
  803. }
  804. /*
  805.  * Decode LINK reply
  806.  */
  807. static int
  808. nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
  809. {
  810. int status;
  811. if ((status = ntohl(*p++)) != 0)
  812. status = -nfs_stat_to_errno(status);
  813. p = xdr_decode_post_op_attr(p, res->fattr);
  814. p = xdr_decode_wcc_data(p, res->dir_attr);
  815. return status;
  816. }
  817. /*
  818.  * Decode FSSTAT reply
  819.  */
  820. static int
  821. nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  822. {
  823. struct nfs_fattr dummy;
  824. int status;
  825. status = ntohl(*p++);
  826. p = xdr_decode_post_op_attr(p, &dummy);
  827. if (status != 0)
  828. return -nfs_stat_to_errno(status);
  829. p = xdr_decode_hyper(p, &res->tbytes);
  830. p = xdr_decode_hyper(p, &res->fbytes);
  831. p = xdr_decode_hyper(p, &res->abytes);
  832. p = xdr_decode_hyper(p, &res->tfiles);
  833. p = xdr_decode_hyper(p, &res->ffiles);
  834. p = xdr_decode_hyper(p, &res->afiles);
  835. /* ignore invarsec */
  836. return 0;
  837. }
  838. /*
  839.  * Decode FSINFO reply
  840.  */
  841. static int
  842. nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  843. {
  844. struct nfs_fattr dummy;
  845. int status;
  846. status = ntohl(*p++);
  847. p = xdr_decode_post_op_attr(p, &dummy);
  848. if (status != 0)
  849. return -nfs_stat_to_errno(status);
  850. res->rtmax  = ntohl(*p++);
  851. res->rtpref = ntohl(*p++);
  852. res->rtmult = ntohl(*p++);
  853. res->wtmax  = ntohl(*p++);
  854. res->wtpref = ntohl(*p++);
  855. res->wtmult = ntohl(*p++);
  856. res->dtpref = ntohl(*p++);
  857. p = xdr_decode_hyper(p, &res->maxfilesize);
  858. /* ignore time_delta and properties */
  859. return 0;
  860. }
  861. /*
  862.  * Decode PATHCONF reply
  863.  */
  864. static int
  865. nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  866. {
  867. struct nfs_fattr dummy;
  868. int status;
  869. status = ntohl(*p++);
  870. p = xdr_decode_post_op_attr(p, &dummy);
  871. if (status != 0)
  872. return -nfs_stat_to_errno(status);
  873. res->linkmax = ntohl(*p++);
  874. res->namelen = ntohl(*p++);
  875. /* ignore remaining fields */
  876. return 0;
  877. }
  878. /*
  879.  * Decode COMMIT reply
  880.  */
  881. static int
  882. nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
  883. {
  884. int status;
  885. status = ntohl(*p++);
  886. p = xdr_decode_wcc_data(p, res->fattr);
  887. if (status != 0)
  888. return -nfs_stat_to_errno(status);
  889. res->verf->verifier[0] = *p++;
  890. res->verf->verifier[1] = *p++;
  891. return 0;
  892. }
  893. #ifndef MAX
  894. # define MAX(a, b) (((a) > (b))? (a) : (b))
  895. #endif
  896. #define PROC(proc, argtype, restype, timer)
  897.     { .p_procname  = "nfs3_" #proc,
  898.       .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,
  899.       .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,
  900.       .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,
  901.       .p_timer     = timer
  902.     }
  903. static struct rpc_procinfo nfs3_procedures[22] = {
  904.   PROC(null, enc_void, dec_void, 0),
  905.   PROC(getattr, fhandle, attrstat, 1),
  906.   PROC(setattr,  sattrargs, wccstat, 0),
  907.   PROC(lookup, diropargs, lookupres, 2),
  908.   PROC(access, accessargs, accessres, 1),
  909.   PROC(readlink, readlinkargs, readlinkres, 3),
  910.   PROC(read, readargs, readres, 3),
  911.   PROC(write, writeargs, writeres, 4),
  912.   PROC(create, createargs, createres, 0),
  913.   PROC(mkdir, mkdirargs, createres, 0),
  914.   PROC(symlink, symlinkargs, createres, 0),
  915.   PROC(mknod, mknodargs, createres, 0),
  916.   PROC(remove, diropargs, wccstat, 0),
  917.   PROC(rmdir, diropargs, wccstat, 0),
  918.   PROC(rename, renameargs, renameres, 0),
  919.   PROC(link, linkargs, linkres, 0),
  920.   PROC(readdir, readdirargs, readdirres, 3),
  921.   PROC(readdirplus, readdirargs, readdirres, 3),
  922.   PROC(fsstat, fhandle, fsstatres, 0),
  923.   PROC(fsinfo,   fhandle, fsinfores, 0),
  924.   PROC(pathconf, fhandle, pathconfres, 0),
  925.   PROC(commit, commitargs, commitres, 5),
  926. };
  927. struct rpc_version nfs_version3 = {
  928. 3,
  929. sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
  930. nfs3_procedures
  931. };