nfs2xdr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:19k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/nfs/nfs2xdr.c
  3.  *
  4.  * XDR functions to encode/decode NFS RPC arguments and results.
  5.  *
  6.  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
  7.  * Copyright (C) 1996 Olaf Kirch
  8.  * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
  9.  *  FIFO's need special handling in NFSv2
  10.  */
  11. #include <linux/param.h>
  12. #include <linux/sched.h>
  13. #include <linux/mm.h>
  14. #include <linux/slab.h>
  15. #include <linux/utsname.h>
  16. #include <linux/errno.h>
  17. #include <linux/string.h>
  18. #include <linux/in.h>
  19. #include <linux/pagemap.h>
  20. #include <linux/proc_fs.h>
  21. #include <linux/sunrpc/clnt.h>
  22. #include <linux/nfs.h>
  23. #include <linux/nfs2.h>
  24. #include <linux/nfs_fs.h>
  25. /* Uncomment this to support servers requiring longword lengths */
  26. #define NFS_PAD_WRITES 1
  27. #define NFSDBG_FACILITY NFSDBG_XDR
  28. /* #define NFS_PARANOIA 1 */
  29. extern int nfs_stat_to_errno(int stat);
  30. /* Mapping from NFS error code to "errno" error code. */
  31. #define errno_NFSERR_IO EIO
  32. /*
  33.  * Declare the space requirements for NFS arguments and replies as
  34.  * number of 32bit-words
  35.  */
  36. #define NFS_fhandle_sz 8
  37. #define NFS_sattr_sz 8
  38. #define NFS_filename_sz 1+(NFS2_MAXNAMLEN>>2)
  39. #define NFS_path_sz 1+(NFS2_MAXPATHLEN>>2)
  40. #define NFS_fattr_sz 17
  41. #define NFS_info_sz 5
  42. #define NFS_entry_sz NFS_filename_sz+3
  43. #define NFS_enc_void_sz 0
  44. #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
  45. #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
  46. #define NFS_readlinkargs_sz NFS_fhandle_sz
  47. #define NFS_readargs_sz NFS_fhandle_sz+3
  48. #define NFS_writeargs_sz NFS_fhandle_sz+4
  49. #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
  50. #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
  51. #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
  52. #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
  53. #define NFS_readdirargs_sz NFS_fhandle_sz+2
  54. #define NFS_dec_void_sz 0
  55. #define NFS_attrstat_sz 1+NFS_fattr_sz
  56. #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
  57. #define NFS_readlinkres_sz 1
  58. #define NFS_readres_sz 1+NFS_fattr_sz+1
  59. #define NFS_writeres_sz         NFS_attrstat_sz
  60. #define NFS_stat_sz 1
  61. #define NFS_readdirres_sz 1
  62. #define NFS_statfsres_sz 1+NFS_info_sz
  63. /*
  64.  * Common NFS XDR functions as inlines
  65.  */
  66. static inline u32 *
  67. xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
  68. {
  69. memcpy(p, fhandle->data, NFS2_FHSIZE);
  70. return p + XDR_QUADLEN(NFS2_FHSIZE);
  71. }
  72. static inline u32 *
  73. xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
  74. {
  75. /* Zero handle first to allow comparisons */
  76. memset(fhandle, 0, sizeof(*fhandle));
  77. /* NFSv2 handles have a fixed length */
  78. fhandle->size = NFS2_FHSIZE;
  79. memcpy(fhandle->data, p, NFS2_FHSIZE);
  80. return p + XDR_QUADLEN(NFS2_FHSIZE);
  81. }
  82. static inline u32 *
  83. xdr_decode_string2(u32 *p, char **string, unsigned int *len,
  84. unsigned int maxlen)
  85. {
  86. *len = ntohl(*p++);
  87. if (*len > maxlen)
  88. return NULL;
  89. *string = (char *) p;
  90. return p + XDR_QUADLEN(*len);
  91. }
  92. static inline u32*
  93. xdr_decode_time(u32 *p, u64 *timep)
  94. {
  95. u64 tmp = (u64)ntohl(*p++) << 32;
  96. *timep = tmp + (u64)ntohl(*p++);
  97. return p;
  98. }
  99. static inline u32 *
  100. xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
  101. {
  102. fattr->type = (enum nfs_ftype) ntohl(*p++);
  103. fattr->mode = ntohl(*p++);
  104. fattr->nlink = ntohl(*p++);
  105. fattr->uid = ntohl(*p++);
  106. fattr->gid = ntohl(*p++);
  107. fattr->size = ntohl(*p++);
  108. fattr->du.nfs2.blocksize = ntohl(*p++);
  109. fattr->rdev = ntohl(*p++);
  110. fattr->du.nfs2.blocks = ntohl(*p++);
  111. fattr->fsid = ntohl(*p++);
  112. fattr->fileid = ntohl(*p++);
  113. p = xdr_decode_time(p, &fattr->atime);
  114. p = xdr_decode_time(p, &fattr->mtime);
  115. p = xdr_decode_time(p, &fattr->ctime);
  116. fattr->valid |= NFS_ATTR_FATTR;
  117. if (fattr->type == NFCHR && fattr->rdev == NFS2_FIFO_DEV) {
  118. fattr->type = NFFIFO;
  119. fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
  120. fattr->rdev = 0;
  121. }
  122. return p;
  123. }
  124. #define SATTR(p, attr, flag, field) 
  125.         *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
  126. static inline u32 *
  127. xdr_encode_sattr(u32 *p, struct iattr *attr)
  128. {
  129. SATTR(p, attr, ATTR_MODE, ia_mode);
  130. SATTR(p, attr, ATTR_UID, ia_uid);
  131. SATTR(p, attr, ATTR_GID, ia_gid);
  132. SATTR(p, attr, ATTR_SIZE, ia_size);
  133. if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
  134. *p++ = htonl(attr->ia_atime);
  135. *p++ = 0;
  136. } else {
  137. *p++ = ~(u32) 0;
  138. *p++ = ~(u32) 0;
  139. }
  140. if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
  141. *p++ = htonl(attr->ia_mtime);
  142. *p++ = 0;
  143. } else {
  144. *p++ = ~(u32) 0;
  145. *p++ = ~(u32) 0;
  146. }
  147.    return p;
  148. }
  149. #undef SATTR
  150. /*
  151.  * NFS encode functions
  152.  */
  153. /*
  154.  * Encode void argument
  155.  */
  156. static int
  157. nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
  158. {
  159. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  160. return 0;
  161. }
  162. /*
  163.  * Encode file handle argument
  164.  * GETATTR, READLINK, STATFS
  165.  */
  166. static int
  167. nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
  168. {
  169. p = xdr_encode_fhandle(p, fh);
  170. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  171. return 0;
  172. }
  173. /*
  174.  * Encode SETATTR arguments
  175.  */
  176. static int
  177. nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
  178. {
  179. p = xdr_encode_fhandle(p, args->fh);
  180. p = xdr_encode_sattr(p, args->sattr);
  181. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  182. return 0;
  183. }
  184. /*
  185.  * Encode directory ops argument
  186.  * LOOKUP, REMOVE, RMDIR
  187.  */
  188. static int
  189. nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
  190. {
  191. p = xdr_encode_fhandle(p, args->fh);
  192. p = xdr_encode_array(p, args->name, args->len);
  193. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  194. return 0;
  195. }
  196. /*
  197.  * Arguments to a READ call. Since we read data directly into the page
  198.  * cache, we also set up the reply iovec here so that iov[1] points
  199.  * exactly to the page we want to fetch.
  200.  */
  201. static int
  202. nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
  203. {
  204. struct rpc_auth *auth = req->rq_task->tk_auth;
  205. int buflen, replen;
  206. unsigned int nr;
  207. p = xdr_encode_fhandle(p, args->fh);
  208. *p++ = htonl(args->offset);
  209. *p++ = htonl(args->count);
  210. *p++ = htonl(args->count);
  211. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  212. /* Get the number of buffers in the receive iovec */
  213.         nr = args->nriov;
  214.         if (nr+2 > MAX_IOVEC) {
  215.                 printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargsn");
  216.                 return -EINVAL;
  217.         }
  218. /* set up reply iovec */
  219. replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
  220. buflen = req->rq_rvec[0].iov_len;
  221. req->rq_rvec[0].iov_len  = replen;
  222.         /* Copy the iovec */
  223.         memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
  224. req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
  225. req->rq_rvec[nr+1].iov_len  = buflen - replen;
  226. req->rq_rlen = args->count + buflen;
  227. req->rq_rnr += nr+1;
  228. return 0;
  229. }
  230. /*
  231.  * Decode READ reply
  232.  */
  233. static int
  234. nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
  235. {
  236. struct iovec *iov = req->rq_rvec;
  237. int status, count, recvd, hdrlen;
  238. if ((status = ntohl(*p++)))
  239. return -nfs_stat_to_errno(status);
  240. p = xdr_decode_fattr(p, res->fattr);
  241. count = ntohl(*p++);
  242. hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  243. if (iov->iov_len > hdrlen) {
  244. dprintk("NFS: READ header is short. iovec will be shifted.n");
  245. xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
  246. }
  247. recvd = req->rq_rlen - hdrlen;
  248. if (count > recvd) {
  249. printk(KERN_WARNING "NFS: server cheating in read reply: "
  250. "count %d > recvd %dn", count, recvd);
  251. count = recvd;
  252. }
  253. dprintk("RPC:      readres OK count %dn", count);
  254. if (count < res->count) {
  255. xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
  256. res->count = count;
  257. res->eof = 1;  /* Silly NFSv3ism which can't be helped */
  258. } else
  259. res->eof = 0;
  260. return count;
  261. }
  262. /*
  263.  * Write arguments. Splice the buffer to be written into the iovec.
  264.  */
  265. static int
  266. nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
  267. {
  268. unsigned int nr;
  269. u32 count = args->count;
  270. p = xdr_encode_fhandle(p, args->fh);
  271. *p++ = htonl(args->offset);
  272. *p++ = htonl(args->offset);
  273. *p++ = htonl(count);
  274. *p++ = htonl(count);
  275. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  276. /* Get the number of buffers in the send iovec */
  277. nr = args->nriov;
  278. if (nr+2 > MAX_IOVEC) {
  279.                 printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
  280.                         "(nr %d max %d)n", nr, MAX_IOVEC);
  281.                 return -EINVAL;
  282.         }
  283. /* Copy the iovec */
  284.         memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
  285. #ifdef NFS_PAD_WRITES
  286. /*
  287.  * Some old servers require that the message length
  288.  * be a multiple of 4, so we pad it here if needed.
  289.  */
  290. if (count & 3) {
  291. struct iovec *iov = req->rq_svec + nr + 1;
  292. int pad = 4 - (count & 3);
  293. iov->iov_base = (void *) "";
  294. iov->iov_len  = pad;
  295. count += pad;
  296. nr++;
  297. }
  298. #endif
  299. req->rq_slen += count;
  300. req->rq_snr += nr;
  301. return 0;
  302. }
  303. /*
  304.  * Encode create arguments
  305.  * CREATE, MKDIR
  306.  */
  307. static int
  308. nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
  309. {
  310. p = xdr_encode_fhandle(p, args->fh);
  311. p = xdr_encode_array(p, args->name, args->len);
  312. p = xdr_encode_sattr(p, args->sattr);
  313. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  314. return 0;
  315. }
  316. /*
  317.  * Encode RENAME arguments
  318.  */
  319. static int
  320. nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
  321. {
  322. p = xdr_encode_fhandle(p, args->fromfh);
  323. p = xdr_encode_array(p, args->fromname, args->fromlen);
  324. p = xdr_encode_fhandle(p, args->tofh);
  325. p = xdr_encode_array(p, args->toname, args->tolen);
  326. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  327. return 0;
  328. }
  329. /*
  330.  * Encode LINK arguments
  331.  */
  332. static int
  333. nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
  334. {
  335. p = xdr_encode_fhandle(p, args->fromfh);
  336. p = xdr_encode_fhandle(p, args->tofh);
  337. p = xdr_encode_array(p, args->toname, args->tolen);
  338. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  339. return 0;
  340. }
  341. /*
  342.  * Encode SYMLINK arguments
  343.  */
  344. static int
  345. nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
  346. {
  347. p = xdr_encode_fhandle(p, args->fromfh);
  348. p = xdr_encode_array(p, args->fromname, args->fromlen);
  349. p = xdr_encode_array(p, args->topath, args->tolen);
  350. p = xdr_encode_sattr(p, args->sattr);
  351. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  352. return 0;
  353. }
  354. /*
  355.  * Encode arguments to readdir call
  356.  */
  357. static int
  358. nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
  359. {
  360. struct rpc_task *task = req->rq_task;
  361. struct rpc_auth *auth = task->tk_auth;
  362. u32 bufsiz = args->bufsiz;
  363. int buflen, replen;
  364. /*
  365.  * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
  366.  * to be in longwords ... check whether to convert the size.
  367.  */
  368. if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
  369. bufsiz = bufsiz >> 2;
  370. p = xdr_encode_fhandle(p, args->fh);
  371. *p++ = htonl(args->cookie);
  372. *p++ = htonl(bufsiz); /* see above */
  373. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  374. /* set up reply iovec */
  375. replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
  376. buflen = req->rq_rvec[0].iov_len;
  377. req->rq_rvec[0].iov_len  = replen;
  378. req->rq_rvec[1].iov_base = args->buffer;
  379. req->rq_rvec[1].iov_len  = args->bufsiz;
  380. req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
  381. req->rq_rvec[2].iov_len  = buflen - replen;
  382. req->rq_rlen = buflen + args->bufsiz;
  383. req->rq_rnr += 2;
  384. return 0;
  385. }
  386. /*
  387.  * Decode the result of a readdir call.
  388.  * We're not really decoding anymore, we just leave the buffer untouched
  389.  * and only check that it is syntactically correct.
  390.  * The real decoding happens in nfs_decode_entry below, called directly
  391.  * from nfs_readdir for each entry.
  392.  */
  393. static int
  394. nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
  395. {
  396. struct iovec *iov = req->rq_rvec;
  397. int  hdrlen;
  398. int  status, nr;
  399. u32 *end, *entry, len;
  400. if ((status = ntohl(*p++)))
  401. return -nfs_stat_to_errno(status);
  402. hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  403. if (iov->iov_len > hdrlen) {
  404. dprintk("NFS: READDIR header is short. iovec will be shifted.n");
  405. xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
  406. }
  407. /* Get start and end address of XDR data */
  408. p   = (u32 *) iov[1].iov_base;
  409. end = (u32 *) ((u8 *) p + iov[1].iov_len);
  410. for (nr = 0; *p++; nr++) {
  411. entry = p - 1;
  412. if (p + 2 > end)
  413. goto short_pkt;
  414. p++; /* fileid */
  415. len = ntohl(*p++);
  416. p += XDR_QUADLEN(len) + 1; /* name plus cookie */
  417. if (len > NFS2_MAXNAMLEN) {
  418. printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!n",
  419. len);
  420. return -errno_NFSERR_IO;
  421. }
  422. if (p + 2 > end)
  423. goto short_pkt;
  424. }
  425. return nr;
  426.  short_pkt:
  427. printk(KERN_NOTICE "NFS: short packet in readdir reply!n");
  428. entry[0] = entry[1] = 0;
  429. return nr;
  430. }
  431. u32 *
  432. nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
  433. {
  434. if (!*p++) {
  435. if (!*p)
  436. return ERR_PTR(-EAGAIN);
  437. entry->eof = 1;
  438. return ERR_PTR(-EBADCOOKIE);
  439. }
  440. entry->ino   = ntohl(*p++);
  441. entry->len   = ntohl(*p++);
  442. entry->name   = (const char *) p;
  443. p  += XDR_QUADLEN(entry->len);
  444. entry->prev_cookie   = entry->cookie;
  445. entry->cookie   = ntohl(*p++);
  446. entry->eof   = !p[0] && p[1];
  447. return p;
  448. }
  449. /*
  450.  * NFS XDR decode functions
  451.  */
  452. /*
  453.  * Decode void reply
  454.  */
  455. static int
  456. nfs_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
  457. {
  458. return 0;
  459. }
  460. /*
  461.  * Decode simple status reply
  462.  */
  463. static int
  464. nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
  465. {
  466. int status;
  467. if ((status = ntohl(*p++)) != 0)
  468. status = -nfs_stat_to_errno(status);
  469. return status;
  470. }
  471. /*
  472.  * Decode attrstat reply
  473.  * GETATTR, SETATTR, WRITE
  474.  */
  475. static int
  476. nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
  477. {
  478. int status;
  479. if ((status = ntohl(*p++)))
  480. return -nfs_stat_to_errno(status);
  481. xdr_decode_fattr(p, fattr);
  482. return 0;
  483. }
  484. /*
  485.  * Decode diropres reply
  486.  * LOOKUP, CREATE, MKDIR
  487.  */
  488. static int
  489. nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
  490. {
  491. int status;
  492. if ((status = ntohl(*p++)))
  493. return -nfs_stat_to_errno(status);
  494. p = xdr_decode_fhandle(p, res->fh);
  495. xdr_decode_fattr(p, res->fattr);
  496. return 0;
  497. }
  498. /*
  499.  * Encode READLINK args
  500.  */
  501. static int
  502. nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
  503. {
  504. struct rpc_task *task = req->rq_task;
  505. struct rpc_auth *auth = task->tk_auth;
  506. int buflen, replen;
  507. p = xdr_encode_fhandle(p, args->fh);
  508. req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
  509. replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
  510. buflen = req->rq_rvec[0].iov_len;
  511. req->rq_rvec[0].iov_len  = replen;
  512. req->rq_rvec[1].iov_base = args->buffer;
  513. req->rq_rvec[1].iov_len  = args->bufsiz;
  514. req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
  515. req->rq_rvec[2].iov_len  = buflen - replen;
  516. req->rq_rlen = buflen + args->bufsiz;
  517. req->rq_rnr += 2;
  518. return 0;
  519. }
  520. /*
  521.  * Decode READLINK reply
  522.  */
  523. static int
  524. nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
  525. {
  526. struct iovec *iov = req->rq_rvec;
  527. u32 *strlen;
  528. char *string;
  529. int hdrlen;
  530. int status;
  531. unsigned int len;
  532. if ((status = ntohl(*p++)))
  533. return -nfs_stat_to_errno(status);
  534. hdrlen = (u8 *) p - (u8 *) iov->iov_base;
  535. if (iov->iov_len > hdrlen) {
  536. dprintk("NFS: READLINK header is short. iovec will be shifted.n");
  537. xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
  538. }
  539. strlen = (u32*)res->buffer;
  540. /* Convert length of symlink */
  541. len = ntohl(*strlen);
  542. if (len > res->bufsiz - 5)
  543. len = res->bufsiz - 5;
  544. *strlen = len;
  545. /* NULL terminate the string we got */
  546. string = (char *)(strlen + 1);
  547. string[len] = 0;
  548. return 0;
  549. }
  550. /*
  551.  * Decode WRITE reply
  552.  */
  553. static int
  554. nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
  555. {
  556. res->verf->committed = NFS_FILE_SYNC;
  557. return nfs_xdr_attrstat(req, p, res->fattr);
  558. }
  559. /*
  560.  * Decode STATFS reply
  561.  */
  562. static int
  563. nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
  564. {
  565. int status;
  566. u32 xfer_size;
  567. if ((status = ntohl(*p++)))
  568. return -nfs_stat_to_errno(status);
  569. /* For NFSv2, we more or less have to guess the preferred
  570.  * read/write/readdir sizes from the single 'transfer size'
  571.  * value.
  572.  */
  573. xfer_size = ntohl(*p++); /* tsize */
  574. res->rtmax  = 8 * 1024;
  575. res->rtpref = xfer_size;
  576. res->rtmult = xfer_size;
  577. res->wtmax  = 8 * 1024;
  578. res->wtpref = xfer_size;
  579. res->wtmult = xfer_size;
  580. res->dtpref = PAGE_CACHE_SIZE;
  581. res->maxfilesize = 0x7FFFFFFF; /* just a guess */
  582. res->bsize  = ntohl(*p++);
  583. res->tbytes = ntohl(*p++) * res->bsize;
  584. res->fbytes = ntohl(*p++) * res->bsize;
  585. res->abytes = ntohl(*p++) * res->bsize;
  586. res->tfiles = 0;
  587. res->ffiles = 0;
  588. res->afiles = 0;
  589. res->namelen = 0;
  590. return 0;
  591. }
  592. /*
  593.  * We need to translate between nfs status return values and
  594.  * the local errno values which may not be the same.
  595.  */
  596. static struct {
  597. int stat;
  598. int errno;
  599. } nfs_errtbl[] = {
  600. { NFS_OK, 0 },
  601. { NFSERR_PERM, EPERM },
  602. { NFSERR_NOENT, ENOENT },
  603. { NFSERR_IO, errno_NFSERR_IO },
  604. { NFSERR_NXIO, ENXIO },
  605. /* { NFSERR_EAGAIN, EAGAIN }, */
  606. { NFSERR_ACCES, EACCES },
  607. { NFSERR_EXIST, EEXIST },
  608. { NFSERR_XDEV, EXDEV },
  609. { NFSERR_NODEV, ENODEV },
  610. { NFSERR_NOTDIR, ENOTDIR },
  611. { NFSERR_ISDIR, EISDIR },
  612. { NFSERR_INVAL, EINVAL },
  613. { NFSERR_FBIG, EFBIG },
  614. { NFSERR_NOSPC, ENOSPC },
  615. { NFSERR_ROFS, EROFS },
  616. { NFSERR_MLINK, EMLINK },
  617. { NFSERR_NAMETOOLONG, ENAMETOOLONG },
  618. { NFSERR_NOTEMPTY, ENOTEMPTY },
  619. { NFSERR_DQUOT, EDQUOT },
  620. { NFSERR_STALE, ESTALE },
  621. { NFSERR_REMOTE, EREMOTE },
  622. #ifdef EWFLUSH
  623. { NFSERR_WFLUSH, EWFLUSH },
  624. #endif
  625. { NFSERR_BADHANDLE, EBADHANDLE },
  626. { NFSERR_NOT_SYNC, ENOTSYNC },
  627. { NFSERR_BAD_COOKIE, EBADCOOKIE },
  628. { NFSERR_NOTSUPP, ENOTSUPP },
  629. { NFSERR_TOOSMALL, ETOOSMALL },
  630. { NFSERR_SERVERFAULT, ESERVERFAULT },
  631. { NFSERR_BADTYPE, EBADTYPE },
  632. { NFSERR_JUKEBOX, EJUKEBOX },
  633. { -1, EIO }
  634. };
  635. /*
  636.  * Convert an NFS error code to a local one.
  637.  * This one is used jointly by NFSv2 and NFSv3.
  638.  */
  639. int
  640. nfs_stat_to_errno(int stat)
  641. {
  642. int i;
  643. for (i = 0; nfs_errtbl[i].stat != -1; i++) {
  644. if (nfs_errtbl[i].stat == stat)
  645. return nfs_errtbl[i].errno;
  646. }
  647. printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %dn", stat);
  648. return nfs_errtbl[i].errno;
  649. }
  650. #ifndef MAX
  651. # define MAX(a, b) (((a) > (b))? (a) : (b))
  652. #endif
  653. #define PROC(proc, argtype, restype)
  654.     { "nfs_" #proc,
  655.       (kxdrproc_t) nfs_xdr_##argtype,
  656.       (kxdrproc_t) nfs_xdr_##restype,
  657.       MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,
  658.       0
  659.     }
  660. static struct rpc_procinfo nfs_procedures[18] = {
  661.     PROC(null, enc_void, dec_void),
  662.     PROC(getattr, fhandle, attrstat),
  663.     PROC(setattr, sattrargs, attrstat),
  664.     PROC(root, enc_void, dec_void),
  665.     PROC(lookup, diropargs, diropres),
  666.     PROC(readlink, readlinkargs, readlinkres),
  667.     PROC(read, readargs, readres),
  668.     PROC(writecache, enc_void, dec_void),
  669.     PROC(write, writeargs, writeres),
  670.     PROC(create, createargs, diropres),
  671.     PROC(remove, diropargs, stat),
  672.     PROC(rename, renameargs, stat),
  673.     PROC(link, linkargs, stat),
  674.     PROC(symlink, symlinkargs, stat),
  675.     PROC(mkdir, createargs, diropres),
  676.     PROC(rmdir, diropargs, stat),
  677.     PROC(readdir, readdirargs, readdirres),
  678.     PROC(statfs, fhandle, statfsres),
  679. };
  680. struct rpc_version nfs_version2 = {
  681. 2,
  682. sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
  683. nfs_procedures
  684. };