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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/nfsd/nfs3xdr.c
  3.  *
  4.  * XDR support for nfsd/protocol version 3.
  5.  *
  6.  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  7.  */
  8. #include <linux/types.h>
  9. #include <linux/sched.h>
  10. #include <linux/nfs3.h>
  11. #include <linux/sunrpc/xdr.h>
  12. #include <linux/sunrpc/svc.h>
  13. #include <linux/nfsd/nfsd.h>
  14. #include <linux/nfsd/xdr3.h>
  15. #define NFSDDBG_FACILITY NFSDDBG_XDR
  16. #ifdef NFSD_OPTIMIZE_SPACE
  17. # define inline
  18. #endif
  19. /*
  20.  * Mapping of S_IF* types to NFS file types
  21.  */
  22. static u32 nfs3_ftypes[] = {
  23. NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
  24. NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
  25. NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
  26. NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
  27. };
  28. /*
  29.  * XDR functions for basic NFS types
  30.  */
  31. static inline u32 *
  32. encode_time3(u32 *p, time_t secs)
  33. {
  34. *p++ = htonl((u32) secs); *p++ = 0;
  35. return p;
  36. }
  37. static inline u32 *
  38. decode_time3(u32 *p, time_t *secp)
  39. {
  40. *secp = ntohl(*p++);
  41. return p + 1;
  42. }
  43. static inline u32 *
  44. decode_fh(u32 *p, struct svc_fh *fhp)
  45. {
  46. int size;
  47. fh_init(fhp, NFS3_FHSIZE);
  48. size = ntohl(*p++);
  49. if (size > NFS3_FHSIZE)
  50. return NULL;
  51. memcpy(&fhp->fh_handle.fh_base, p, size);
  52. fhp->fh_handle.fh_size = size;
  53. return p + XDR_QUADLEN(size);
  54. }
  55. static inline u32 *
  56. encode_fh(u32 *p, struct svc_fh *fhp)
  57. {
  58. int size = fhp->fh_handle.fh_size;
  59. *p++ = htonl(size);
  60. if (size) p[XDR_QUADLEN(size)-1]=0;
  61. memcpy(p, &fhp->fh_handle.fh_base, size);
  62. return p + XDR_QUADLEN(size);
  63. }
  64. /*
  65.  * Decode a file name and make sure that the path contains
  66.  * no slashes or null bytes.
  67.  */
  68. static inline u32 *
  69. decode_filename(u32 *p, char **namp, int *lenp)
  70. {
  71. char *name;
  72. int i;
  73. if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
  74. for (i = 0, name = *namp; i < *lenp; i++, name++) {
  75. if (*name == '' || *name == '/')
  76. return NULL;
  77. }
  78. }
  79. return p;
  80. }
  81. static inline u32 *
  82. decode_pathname(u32 *p, char **namp, int *lenp)
  83. {
  84. char *name;
  85. int i;
  86. if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
  87. for (i = 0, name = *namp; i < *lenp; i++, name++) {
  88. if (*name == '')
  89. return NULL;
  90. }
  91. }
  92. return p;
  93. }
  94. static inline u32 *
  95. decode_sattr3(u32 *p, struct iattr *iap)
  96. {
  97. u32 tmp;
  98. iap->ia_valid = 0;
  99. if (*p++) {
  100. iap->ia_valid |= ATTR_MODE;
  101. iap->ia_mode = ntohl(*p++);
  102. }
  103. if (*p++) {
  104. iap->ia_valid |= ATTR_UID;
  105. iap->ia_uid = ntohl(*p++);
  106. }
  107. if (*p++) {
  108. iap->ia_valid |= ATTR_GID;
  109. iap->ia_gid = ntohl(*p++);
  110. }
  111. if (*p++) {
  112. u64 newsize;
  113. iap->ia_valid |= ATTR_SIZE;
  114. p = xdr_decode_hyper(p, &newsize);
  115. if (newsize <= NFS_OFFSET_MAX)
  116. iap->ia_size = newsize;
  117. else
  118. iap->ia_size = NFS_OFFSET_MAX;
  119. }
  120. if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
  121. iap->ia_valid |= ATTR_ATIME;
  122. } else if (tmp == 2) { /* set to client time */
  123. iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
  124. iap->ia_atime = ntohl(*p++), p++;
  125. }
  126. if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
  127. iap->ia_valid |= ATTR_MTIME;
  128. } else if (tmp == 2) { /* set to client time */
  129. iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
  130. iap->ia_mtime = ntohl(*p++), p++;
  131. }
  132. return p;
  133. }
  134. static inline u32 *
  135. encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  136. {
  137. struct inode *inode = fhp->fh_dentry->d_inode;
  138. *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
  139. *p++ = htonl((u32) inode->i_mode);
  140. *p++ = htonl((u32) inode->i_nlink);
  141. *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
  142. *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
  143. if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
  144. p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
  145. } else {
  146. p = xdr_encode_hyper(p, (u64) inode->i_size);
  147. }
  148. if (inode->i_blksize == 0 && inode->i_blocks == 0)
  149. /* Minix file system(?) i_size is (hopefully) close enough */
  150. p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
  151. else
  152. p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
  153. *p++ = htonl((u32) MAJOR(inode->i_rdev));
  154. *p++ = htonl((u32) MINOR(inode->i_rdev));
  155. if (rqstp->rq_reffh->fh_version == 1
  156.     && rqstp->rq_reffh->fh_fsid_type == 1
  157.     && (fhp->fh_export->ex_flags & NFSEXP_FSID))
  158. p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
  159. else
  160. p = xdr_encode_hyper(p, (u64) inode->i_dev);
  161. p = xdr_encode_hyper(p, (u64) inode->i_ino);
  162. p = encode_time3(p, inode->i_atime);
  163. p = encode_time3(p, lease_get_mtime(inode));
  164. p = encode_time3(p, inode->i_ctime);
  165. return p;
  166. }
  167. static inline u32 *
  168. encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  169. {
  170. struct inode *inode = fhp->fh_dentry->d_inode;
  171. /* Attributes to follow */
  172. *p++ = xdr_one;
  173. *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
  174. *p++ = htonl((u32) fhp->fh_post_mode);
  175. *p++ = htonl((u32) fhp->fh_post_nlink);
  176. *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
  177. *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
  178. if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
  179. p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
  180. } else {
  181. p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
  182. }
  183. p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
  184. *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
  185. *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
  186. if (rqstp->rq_reffh->fh_version == 1
  187.     && rqstp->rq_reffh->fh_fsid_type == 1
  188.     && (fhp->fh_export->ex_flags & NFSEXP_FSID))
  189. p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
  190. else
  191. p = xdr_encode_hyper(p, (u64) inode->i_dev);
  192. p = xdr_encode_hyper(p, (u64) inode->i_ino);
  193. p = encode_time3(p, fhp->fh_post_atime);
  194. p = encode_time3(p, fhp->fh_post_mtime);
  195. p = encode_time3(p, fhp->fh_post_ctime);
  196. return p;
  197. }
  198. /*
  199.  * Encode post-operation attributes.
  200.  * The inode may be NULL if the call failed because of a stale file
  201.  * handle. In this case, no attributes are returned.
  202.  */
  203. static u32 *
  204. encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  205. {
  206. struct dentry *dentry = fhp->fh_dentry;
  207. if (dentry && dentry->d_inode != NULL) {
  208. *p++ = xdr_one; /* attributes follow */
  209. return encode_fattr3(rqstp, p, fhp);
  210. }
  211. *p++ = xdr_zero;
  212. return p;
  213. }
  214. /*
  215.  * Enocde weak cache consistency data
  216.  */
  217. static u32 *
  218. encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  219. {
  220. struct dentry *dentry = fhp->fh_dentry;
  221. if (dentry && dentry->d_inode && fhp->fh_post_saved) {
  222. if (fhp->fh_pre_saved) {
  223. *p++ = xdr_one;
  224. p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
  225. p = encode_time3(p, fhp->fh_pre_mtime);
  226. p = encode_time3(p, fhp->fh_pre_ctime);
  227. } else {
  228. *p++ = xdr_zero;
  229. }
  230. return encode_saved_post_attr(rqstp, p, fhp);
  231. }
  232. /* no pre- or post-attrs */
  233. *p++ = xdr_zero;
  234. return encode_post_op_attr(rqstp, p, fhp);
  235. }
  236. /*
  237.  * Check buffer bounds after decoding arguments
  238.  */
  239. static inline int
  240. xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
  241. {
  242. struct svc_buf *buf = &rqstp->rq_argbuf;
  243. return p - buf->base <= buf->buflen;
  244. }
  245. static inline int
  246. xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
  247. {
  248. struct svc_buf *buf = &rqstp->rq_resbuf;
  249. buf->len = p - buf->base;
  250. dprintk("nfsd: ressize_check p %p base %p len %dn",
  251. p, buf->base, buf->buflen);
  252. return (buf->len <= buf->buflen);
  253. }
  254. /*
  255.  * XDR decode functions
  256.  */
  257. int
  258. nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  259. {
  260. if (!(p = decode_fh(p, fhp)))
  261. return 0;
  262. return xdr_argsize_check(rqstp, p);
  263. }
  264. int
  265. nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
  266. struct nfsd3_sattrargs *args)
  267. {
  268. if (!(p = decode_fh(p, &args->fh))
  269.  || !(p = decode_sattr3(p, &args->attrs)))
  270. return 0;
  271. if ((args->check_guard = ntohl(*p++)) != 0)
  272. p = decode_time3(p, &args->guardtime);
  273. return xdr_argsize_check(rqstp, p);
  274. }
  275. int
  276. nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
  277. struct nfsd3_diropargs *args)
  278. {
  279. if (!(p = decode_fh(p, &args->fh))
  280.  || !(p = decode_filename(p, &args->name, &args->len)))
  281. return 0;
  282. return xdr_argsize_check(rqstp, p);
  283. }
  284. int
  285. nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
  286. struct nfsd3_accessargs *args)
  287. {
  288. if (!(p = decode_fh(p, &args->fh)))
  289. return 0;
  290. args->access = ntohl(*p++);
  291. return xdr_argsize_check(rqstp, p);
  292. }
  293. int
  294. nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
  295. struct nfsd3_readargs *args)
  296. {
  297. if (!(p = decode_fh(p, &args->fh))
  298.  || !(p = xdr_decode_hyper(p, &args->offset)))
  299. return 0;
  300. args->count = ntohl(*p++);
  301. return xdr_argsize_check(rqstp, p);
  302. }
  303. int
  304. nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
  305. struct nfsd3_writeargs *args)
  306. {
  307. if (!(p = decode_fh(p, &args->fh))
  308.  || !(p = xdr_decode_hyper(p, &args->offset)))
  309. return 0;
  310. args->count = ntohl(*p++);
  311. args->stable = ntohl(*p++);
  312. args->len = ntohl(*p++);
  313. args->data = (char *) p;
  314. p += XDR_QUADLEN(args->len);
  315. return xdr_argsize_check(rqstp, p);
  316. }
  317. int
  318. nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
  319. struct nfsd3_createargs *args)
  320. {
  321. if (!(p = decode_fh(p, &args->fh))
  322.  || !(p = decode_filename(p, &args->name, &args->len)))
  323. return 0;
  324. switch (args->createmode = ntohl(*p++)) {
  325. case NFS3_CREATE_UNCHECKED:
  326. case NFS3_CREATE_GUARDED:
  327. if (!(p = decode_sattr3(p, &args->attrs)))
  328. return 0;
  329. break;
  330. case NFS3_CREATE_EXCLUSIVE:
  331. args->verf = p;
  332. p += 2;
  333. break;
  334. default:
  335. return 0;
  336. }
  337. return xdr_argsize_check(rqstp, p);
  338. }
  339. int
  340. nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
  341. struct nfsd3_createargs *args)
  342. {
  343. if (!(p = decode_fh(p, &args->fh))
  344.  || !(p = decode_filename(p, &args->name, &args->len))
  345.  || !(p = decode_sattr3(p, &args->attrs)))
  346. return 0;
  347. return xdr_argsize_check(rqstp, p);
  348. }
  349. int
  350. nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
  351. struct nfsd3_symlinkargs *args)
  352. {
  353. if (!(p = decode_fh(p, &args->ffh))
  354.  || !(p = decode_filename(p, &args->fname, &args->flen))
  355.  || !(p = decode_sattr3(p, &args->attrs))
  356.  || !(p = decode_pathname(p, &args->tname, &args->tlen)))
  357. return 0;
  358. return xdr_argsize_check(rqstp, p);
  359. }
  360. int
  361. nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
  362. struct nfsd3_mknodargs *args)
  363. {
  364. if (!(p = decode_fh(p, &args->fh))
  365.  || !(p = decode_filename(p, &args->name, &args->len)))
  366. return 0;
  367. args->ftype = ntohl(*p++);
  368. if (args->ftype == NF3BLK  || args->ftype == NF3CHR
  369.  || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
  370. if (!(p = decode_sattr3(p, &args->attrs)))
  371. return 0;
  372. }
  373. if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
  374. args->major = ntohl(*p++);
  375. args->minor = ntohl(*p++);
  376. }
  377. return xdr_argsize_check(rqstp, p);
  378. }
  379. int
  380. nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
  381. struct nfsd3_renameargs *args)
  382. {
  383. if (!(p = decode_fh(p, &args->ffh))
  384.  || !(p = decode_filename(p, &args->fname, &args->flen))
  385.  || !(p = decode_fh(p, &args->tfh))
  386.  || !(p = decode_filename(p, &args->tname, &args->tlen)))
  387. return 0;
  388. return xdr_argsize_check(rqstp, p);
  389. }
  390. int
  391. nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
  392. struct nfsd3_linkargs *args)
  393. {
  394. if (!(p = decode_fh(p, &args->ffh))
  395.  || !(p = decode_fh(p, &args->tfh))
  396.  || !(p = decode_filename(p, &args->tname, &args->tlen)))
  397. return 0;
  398. return xdr_argsize_check(rqstp, p);
  399. }
  400. int
  401. nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
  402. struct nfsd3_readdirargs *args)
  403. {
  404. if (!(p = decode_fh(p, &args->fh)))
  405. return 0;
  406. p = xdr_decode_hyper(p, &args->cookie);
  407. args->verf   = p; p += 2;
  408. args->dircount = ~0;
  409. args->count  = ntohl(*p++);
  410. return xdr_argsize_check(rqstp, p);
  411. }
  412. int
  413. nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
  414. struct nfsd3_readdirargs *args)
  415. {
  416. if (!(p = decode_fh(p, &args->fh)))
  417. return 0;
  418. p = xdr_decode_hyper(p, &args->cookie);
  419. args->verf     = p; p += 2;
  420. args->dircount = ntohl(*p++);
  421. args->count    = ntohl(*p++);
  422. return xdr_argsize_check(rqstp, p);
  423. }
  424. int
  425. nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
  426. struct nfsd3_commitargs *args)
  427. {
  428. if (!(p = decode_fh(p, &args->fh)))
  429. return 0;
  430. p = xdr_decode_hyper(p, &args->offset);
  431. args->count = ntohl(*p++);
  432. return xdr_argsize_check(rqstp, p);
  433. }
  434. /*
  435.  * XDR encode functions
  436.  */
  437. /*
  438.  * There must be an encoding function for void results so svc_process
  439.  * will work properly.
  440.  */
  441. int
  442. nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
  443. {
  444. return xdr_ressize_check(rqstp, p);
  445. }
  446. /* GETATTR */
  447. int
  448. nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
  449. struct nfsd3_attrstat *resp)
  450. {
  451. if (resp->status == 0)
  452. p = encode_fattr3(rqstp, p, &resp->fh);
  453. return xdr_ressize_check(rqstp, p);
  454. }
  455. /* SETATTR, REMOVE, RMDIR */
  456. int
  457. nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
  458. struct nfsd3_attrstat *resp)
  459. {
  460. p = encode_wcc_data(rqstp, p, &resp->fh);
  461. return xdr_ressize_check(rqstp, p);
  462. }
  463. /* LOOKUP */
  464. int
  465. nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
  466. struct nfsd3_diropres *resp)
  467. {
  468. if (resp->status == 0) {
  469. p = encode_fh(p, &resp->fh);
  470. p = encode_post_op_attr(rqstp, p, &resp->fh);
  471. }
  472. p = encode_post_op_attr(rqstp, p, &resp->dirfh);
  473. return xdr_ressize_check(rqstp, p);
  474. }
  475. /* ACCESS */
  476. int
  477. nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
  478. struct nfsd3_accessres *resp)
  479. {
  480. p = encode_post_op_attr(rqstp, p, &resp->fh);
  481. if (resp->status == 0)
  482. *p++ = htonl(resp->access);
  483. return xdr_ressize_check(rqstp, p);
  484. }
  485. /* READLINK */
  486. int
  487. nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
  488. struct nfsd3_readlinkres *resp)
  489. {
  490. p = encode_post_op_attr(rqstp, p, &resp->fh);
  491. if (resp->status == 0) {
  492. *p++ = htonl(resp->len);
  493. p += XDR_QUADLEN(resp->len);
  494. }
  495. return xdr_ressize_check(rqstp, p);
  496. }
  497. /* READ */
  498. int
  499. nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
  500. struct nfsd3_readres *resp)
  501. {
  502. p = encode_post_op_attr(rqstp, p, &resp->fh);
  503. if (resp->status == 0) {
  504. *p++ = htonl(resp->count);
  505. *p++ = htonl(resp->eof);
  506. *p++ = htonl(resp->count); /* xdr opaque count */
  507. p += XDR_QUADLEN(resp->count);
  508. }
  509. return xdr_ressize_check(rqstp, p);
  510. }
  511. /* WRITE */
  512. int
  513. nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
  514. struct nfsd3_writeres *resp)
  515. {
  516. p = encode_wcc_data(rqstp, p, &resp->fh);
  517. if (resp->status == 0) {
  518. *p++ = htonl(resp->count);
  519. *p++ = htonl(resp->committed);
  520. *p++ = htonl(nfssvc_boot.tv_sec);
  521. *p++ = htonl(nfssvc_boot.tv_usec);
  522. }
  523. return xdr_ressize_check(rqstp, p);
  524. }
  525. /* CREATE, MKDIR, SYMLINK, MKNOD */
  526. int
  527. nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
  528. struct nfsd3_diropres *resp)
  529. {
  530. if (resp->status == 0) {
  531. *p++ = xdr_one;
  532. p = encode_fh(p, &resp->fh);
  533. p = encode_post_op_attr(rqstp, p, &resp->fh);
  534. }
  535. p = encode_wcc_data(rqstp, p, &resp->dirfh);
  536. return xdr_ressize_check(rqstp, p);
  537. }
  538. /* RENAME */
  539. int
  540. nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
  541. struct nfsd3_renameres *resp)
  542. {
  543. p = encode_wcc_data(rqstp, p, &resp->ffh);
  544. p = encode_wcc_data(rqstp, p, &resp->tfh);
  545. return xdr_ressize_check(rqstp, p);
  546. }
  547. /* LINK */
  548. int
  549. nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
  550. struct nfsd3_linkres *resp)
  551. {
  552. p = encode_post_op_attr(rqstp, p, &resp->fh);
  553. p = encode_wcc_data(rqstp, p, &resp->tfh);
  554. return xdr_ressize_check(rqstp, p);
  555. }
  556. /* READDIR */
  557. int
  558. nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
  559. struct nfsd3_readdirres *resp)
  560. {
  561. p = encode_post_op_attr(rqstp, p, &resp->fh);
  562. if (resp->status == 0) {
  563. /* stupid readdir cookie */
  564. memcpy(p, resp->verf, 8); p += 2;
  565. p += XDR_QUADLEN(resp->count);
  566. }
  567. return xdr_ressize_check(rqstp, p);
  568. }
  569. /*
  570.  * Encode a directory entry. This one works for both normal readdir
  571.  * and readdirplus.
  572.  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
  573.  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
  574.  * 
  575.  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
  576.  * file handle.
  577.  */
  578. #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
  579. #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
  580. static int
  581. encode_entry(struct readdir_cd *cd, const char *name,
  582.      int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
  583. {
  584. u32 *p = cd->buffer;
  585. int buflen, slen, elen;
  586. if (cd->offset)
  587. xdr_encode_hyper(cd->offset, (u64) offset);
  588. /* nfsd_readdir calls us with name == 0 when it wants us to
  589.  * set the last offset entry. */
  590. if (name == 0)
  591. return 0;
  592. /*
  593. dprintk("encode_entry(%.*s @%ld%s)n",
  594. namlen, name, (long) offset, plus? " plus" : "");
  595.  */
  596. /* truncate filename if too long */
  597. if (namlen > NFS3_MAXNAMLEN)
  598. namlen = NFS3_MAXNAMLEN;
  599. slen = XDR_QUADLEN(namlen);
  600. elen = slen + NFS3_ENTRY_BAGGAGE
  601. + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
  602. if ((buflen = cd->buflen - elen) < 0) {
  603. cd->eob = 1;
  604. return -EINVAL;
  605. }
  606. *p++ = xdr_one;  /* mark entry present */
  607. p    = xdr_encode_hyper(p, ino);  /* file id */
  608. p    = xdr_encode_array(p, name, namlen);/* name length & name */
  609. cd->offset = p; /* remember pointer */
  610. p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
  611. /* throw in readdirplus baggage */
  612. if (plus) {
  613. struct svc_fh fh;
  614. struct svc_export *exp;
  615. struct dentry *dparent, *dchild;
  616. dparent = cd->dirfh->fh_dentry;
  617. exp  = cd->dirfh->fh_export;
  618. fh_init(&fh, NFS3_FHSIZE);
  619. if (isdotent(name, namlen)) {
  620. dchild = dparent;
  621. if (namlen == 2)
  622. dchild = dchild->d_parent;
  623. dchild = dget(dchild);
  624. } else
  625. dchild = lookup_one_len(name, dparent,namlen);
  626. if (IS_ERR(dchild))
  627. goto noexec;
  628. if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
  629. goto noexec;
  630. p = encode_post_op_attr(cd->rqstp, p, &fh);
  631. *p++ = xdr_one; /* yes, a file handle follows */
  632. p = encode_fh(p, &fh);
  633. fh_put(&fh);
  634. }
  635. out:
  636. cd->buflen = buflen;
  637. cd->buffer = p;
  638. return 0;
  639. noexec:
  640. *p++ = 0;
  641. *p++ = 0;
  642. goto out;
  643. }
  644. int
  645. nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
  646.      int namlen, loff_t offset, ino_t ino, unsigned int d_type)
  647. {
  648. return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
  649. }
  650. int
  651. nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
  652.   int namlen, loff_t offset, ino_t ino, unsigned int d_type)
  653. {
  654. return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
  655. }
  656. /* FSSTAT */
  657. int
  658. nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
  659. struct nfsd3_fsstatres *resp)
  660. {
  661. struct statfs *s = &resp->stats;
  662. u64 bs = s->f_bsize;
  663. *p++ = xdr_zero; /* no post_op_attr */
  664. if (resp->status == 0) {
  665. p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
  666. p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
  667. p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
  668. p = xdr_encode_hyper(p, s->f_files); /* total inodes */
  669. p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
  670. p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
  671. *p++ = htonl(resp->invarsec); /* mean unchanged time */
  672. }
  673. return xdr_ressize_check(rqstp, p);
  674. }
  675. /* FSINFO */
  676. int
  677. nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
  678. struct nfsd3_fsinfores *resp)
  679. {
  680. *p++ = xdr_zero; /* no post_op_attr */
  681. if (resp->status == 0) {
  682. *p++ = htonl(resp->f_rtmax);
  683. *p++ = htonl(resp->f_rtpref);
  684. *p++ = htonl(resp->f_rtmult);
  685. *p++ = htonl(resp->f_wtmax);
  686. *p++ = htonl(resp->f_wtpref);
  687. *p++ = htonl(resp->f_wtmult);
  688. *p++ = htonl(resp->f_dtpref);
  689. p = xdr_encode_hyper(p, resp->f_maxfilesize);
  690. *p++ = xdr_one;
  691. *p++ = xdr_zero;
  692. *p++ = htonl(resp->f_properties);
  693. }
  694. return xdr_ressize_check(rqstp, p);
  695. }
  696. /* PATHCONF */
  697. int
  698. nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
  699. struct nfsd3_pathconfres *resp)
  700. {
  701. *p++ = xdr_zero; /* no post_op_attr */
  702. if (resp->status == 0) {
  703. *p++ = htonl(resp->p_link_max);
  704. *p++ = htonl(resp->p_name_max);
  705. *p++ = htonl(resp->p_no_trunc);
  706. *p++ = htonl(resp->p_chown_restricted);
  707. *p++ = htonl(resp->p_case_insensitive);
  708. *p++ = htonl(resp->p_case_preserving);
  709. }
  710. return xdr_ressize_check(rqstp, p);
  711. }
  712. /* COMMIT */
  713. int
  714. nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
  715. struct nfsd3_commitres *resp)
  716. {
  717. p = encode_wcc_data(rqstp, p, &resp->fh);
  718. /* Write verifier */
  719. if (resp->status == 0) {
  720. *p++ = htonl(nfssvc_boot.tv_sec);
  721. *p++ = htonl(nfssvc_boot.tv_usec);
  722. }
  723. return xdr_ressize_check(rqstp, p);
  724. }
  725. /*
  726.  * XDR release functions
  727.  */
  728. int
  729. nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
  730. struct nfsd3_attrstat *resp)
  731. {
  732. fh_put(&resp->fh);
  733. return 1;
  734. }
  735. int
  736. nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
  737. struct nfsd3_fhandle_pair *resp)
  738. {
  739. fh_put(&resp->fh1);
  740. fh_put(&resp->fh2);
  741. return 1;
  742. }