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

嵌入式Linux

开发平台:

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 dentry *dentry)
  136. {
  137. struct inode *inode = 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. p = xdr_encode_hyper(p, (u64) inode->i_dev);
  156. p = xdr_encode_hyper(p, (u64) inode->i_ino);
  157. p = encode_time3(p, inode->i_atime);
  158. p = encode_time3(p, lease_get_mtime(inode));
  159. p = encode_time3(p, inode->i_ctime);
  160. return p;
  161. }
  162. static inline u32 *
  163. encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  164. {
  165. struct inode *inode = fhp->fh_dentry->d_inode;
  166. /* Attributes to follow */
  167. *p++ = xdr_one;
  168. *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
  169. *p++ = htonl((u32) fhp->fh_post_mode);
  170. *p++ = htonl((u32) fhp->fh_post_nlink);
  171. *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
  172. *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
  173. if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
  174. p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
  175. } else {
  176. p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
  177. }
  178. p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
  179. *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
  180. *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
  181. p = xdr_encode_hyper(p, (u64) inode->i_dev);
  182. p = xdr_encode_hyper(p, (u64) inode->i_ino);
  183. p = encode_time3(p, fhp->fh_post_atime);
  184. p = encode_time3(p, fhp->fh_post_mtime);
  185. p = encode_time3(p, fhp->fh_post_ctime);
  186. return p;
  187. }
  188. /*
  189.  * Encode post-operation attributes.
  190.  * The inode may be NULL if the call failed because of a stale file
  191.  * handle. In this case, no attributes are returned.
  192.  */
  193. static u32 *
  194. encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
  195. {
  196. if (dentry && dentry->d_inode != NULL) {
  197. *p++ = xdr_one; /* attributes follow */
  198. return encode_fattr3(rqstp, p, dentry);
  199. }
  200. *p++ = xdr_zero;
  201. return p;
  202. }
  203. /*
  204.  * Enocde weak cache consistency data
  205.  */
  206. static u32 *
  207. encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  208. {
  209. struct dentry *dentry = fhp->fh_dentry;
  210. if (dentry && dentry->d_inode && fhp->fh_post_saved) {
  211. if (fhp->fh_pre_saved) {
  212. *p++ = xdr_one;
  213. p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
  214. p = encode_time3(p, fhp->fh_pre_mtime);
  215. p = encode_time3(p, fhp->fh_pre_ctime);
  216. } else {
  217. *p++ = xdr_zero;
  218. }
  219. return encode_saved_post_attr(rqstp, p, fhp);
  220. }
  221. /* no pre- or post-attrs */
  222. *p++ = xdr_zero;
  223. return encode_post_op_attr(rqstp, p, dentry);
  224. }
  225. /*
  226.  * Check buffer bounds after decoding arguments
  227.  */
  228. static inline int
  229. xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
  230. {
  231. struct svc_buf *buf = &rqstp->rq_argbuf;
  232. return p - buf->base <= buf->buflen;
  233. }
  234. static inline int
  235. xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
  236. {
  237. struct svc_buf *buf = &rqstp->rq_resbuf;
  238. buf->len = p - buf->base;
  239. dprintk("nfsd: ressize_check p %p base %p len %dn",
  240. p, buf->base, buf->buflen);
  241. return (buf->len <= buf->buflen);
  242. }
  243. /*
  244.  * XDR decode functions
  245.  */
  246. int
  247. nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  248. {
  249. if (!(p = decode_fh(p, fhp)))
  250. return 0;
  251. return xdr_argsize_check(rqstp, p);
  252. }
  253. int
  254. nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
  255. struct nfsd3_sattrargs *args)
  256. {
  257. if (!(p = decode_fh(p, &args->fh))
  258.  || !(p = decode_sattr3(p, &args->attrs)))
  259. return 0;
  260. if ((args->check_guard = ntohl(*p++)) != 0)
  261. p = decode_time3(p, &args->guardtime);
  262. return xdr_argsize_check(rqstp, p);
  263. }
  264. int
  265. nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
  266. struct nfsd3_diropargs *args)
  267. {
  268. if (!(p = decode_fh(p, &args->fh))
  269.  || !(p = decode_filename(p, &args->name, &args->len)))
  270. return 0;
  271. return xdr_argsize_check(rqstp, p);
  272. }
  273. int
  274. nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
  275. struct nfsd3_accessargs *args)
  276. {
  277. if (!(p = decode_fh(p, &args->fh)))
  278. return 0;
  279. args->access = ntohl(*p++);
  280. return xdr_argsize_check(rqstp, p);
  281. }
  282. int
  283. nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
  284. struct nfsd3_readargs *args)
  285. {
  286. if (!(p = decode_fh(p, &args->fh))
  287.  || !(p = xdr_decode_hyper(p, &args->offset)))
  288. return 0;
  289. args->count = ntohl(*p++);
  290. return xdr_argsize_check(rqstp, p);
  291. }
  292. int
  293. nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
  294. struct nfsd3_writeargs *args)
  295. {
  296. if (!(p = decode_fh(p, &args->fh))
  297.  || !(p = xdr_decode_hyper(p, &args->offset)))
  298. return 0;
  299. args->count = ntohl(*p++);
  300. args->stable = ntohl(*p++);
  301. args->len = ntohl(*p++);
  302. args->data = (char *) p;
  303. p += XDR_QUADLEN(args->len);
  304. return xdr_argsize_check(rqstp, p);
  305. }
  306. int
  307. nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
  308. struct nfsd3_createargs *args)
  309. {
  310. if (!(p = decode_fh(p, &args->fh))
  311.  || !(p = decode_filename(p, &args->name, &args->len)))
  312. return 0;
  313. switch (args->createmode = ntohl(*p++)) {
  314. case NFS3_CREATE_UNCHECKED:
  315. case NFS3_CREATE_GUARDED:
  316. if (!(p = decode_sattr3(p, &args->attrs)))
  317. return 0;
  318. break;
  319. case NFS3_CREATE_EXCLUSIVE:
  320. args->verf = p;
  321. p += 2;
  322. break;
  323. default:
  324. return 0;
  325. }
  326. return xdr_argsize_check(rqstp, p);
  327. }
  328. int
  329. nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
  330. struct nfsd3_createargs *args)
  331. {
  332. if (!(p = decode_fh(p, &args->fh))
  333.  || !(p = decode_filename(p, &args->name, &args->len))
  334.  || !(p = decode_sattr3(p, &args->attrs)))
  335. return 0;
  336. return xdr_argsize_check(rqstp, p);
  337. }
  338. int
  339. nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
  340. struct nfsd3_symlinkargs *args)
  341. {
  342. if (!(p = decode_fh(p, &args->ffh))
  343.  || !(p = decode_filename(p, &args->fname, &args->flen))
  344.  || !(p = decode_sattr3(p, &args->attrs))
  345.  || !(p = decode_pathname(p, &args->tname, &args->tlen)))
  346. return 0;
  347. return xdr_argsize_check(rqstp, p);
  348. }
  349. int
  350. nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
  351. struct nfsd3_mknodargs *args)
  352. {
  353. if (!(p = decode_fh(p, &args->fh))
  354.  || !(p = decode_filename(p, &args->name, &args->len)))
  355. return 0;
  356. args->ftype = ntohl(*p++);
  357. if (args->ftype == NF3BLK  || args->ftype == NF3CHR
  358.  || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
  359. if (!(p = decode_sattr3(p, &args->attrs)))
  360. return 0;
  361. }
  362. if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
  363. args->major = ntohl(*p++);
  364. args->minor = ntohl(*p++);
  365. }
  366. return xdr_argsize_check(rqstp, p);
  367. }
  368. int
  369. nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
  370. struct nfsd3_renameargs *args)
  371. {
  372. if (!(p = decode_fh(p, &args->ffh))
  373.  || !(p = decode_filename(p, &args->fname, &args->flen))
  374.  || !(p = decode_fh(p, &args->tfh))
  375.  || !(p = decode_filename(p, &args->tname, &args->tlen)))
  376. return 0;
  377. return xdr_argsize_check(rqstp, p);
  378. }
  379. int
  380. nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
  381. struct nfsd3_linkargs *args)
  382. {
  383. if (!(p = decode_fh(p, &args->ffh))
  384.  || !(p = decode_fh(p, &args->tfh))
  385.  || !(p = decode_filename(p, &args->tname, &args->tlen)))
  386. return 0;
  387. return xdr_argsize_check(rqstp, p);
  388. }
  389. int
  390. nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
  391. struct nfsd3_readdirargs *args)
  392. {
  393. if (!(p = decode_fh(p, &args->fh)))
  394. return 0;
  395. p = xdr_decode_hyper(p, &args->cookie);
  396. args->verf   = p; p += 2;
  397. args->dircount = ~0;
  398. args->count  = ntohl(*p++);
  399. return xdr_argsize_check(rqstp, p);
  400. }
  401. int
  402. nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
  403. struct nfsd3_readdirargs *args)
  404. {
  405. if (!(p = decode_fh(p, &args->fh)))
  406. return 0;
  407. p = xdr_decode_hyper(p, &args->cookie);
  408. args->verf     = p; p += 2;
  409. args->dircount = ntohl(*p++);
  410. args->count    = ntohl(*p++);
  411. return xdr_argsize_check(rqstp, p);
  412. }
  413. int
  414. nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
  415. struct nfsd3_commitargs *args)
  416. {
  417. if (!(p = decode_fh(p, &args->fh)))
  418. return 0;
  419. p = xdr_decode_hyper(p, &args->offset);
  420. args->count = ntohl(*p++);
  421. return xdr_argsize_check(rqstp, p);
  422. }
  423. /*
  424.  * XDR encode functions
  425.  */
  426. /*
  427.  * There must be an encoding function for void results so svc_process
  428.  * will work properly.
  429.  */
  430. int
  431. nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
  432. {
  433. return xdr_ressize_check(rqstp, p);
  434. }
  435. /* GETATTR */
  436. int
  437. nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
  438. struct nfsd3_attrstat *resp)
  439. {
  440. if (resp->status == 0)
  441. p = encode_fattr3(rqstp, p, resp->fh.fh_dentry);
  442. return xdr_ressize_check(rqstp, p);
  443. }
  444. /* SETATTR, REMOVE, RMDIR */
  445. int
  446. nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
  447. struct nfsd3_attrstat *resp)
  448. {
  449. p = encode_wcc_data(rqstp, p, &resp->fh);
  450. return xdr_ressize_check(rqstp, p);
  451. }
  452. /* LOOKUP */
  453. int
  454. nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
  455. struct nfsd3_diropres *resp)
  456. {
  457. if (resp->status == 0) {
  458. p = encode_fh(p, &resp->fh);
  459. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  460. }
  461. p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
  462. return xdr_ressize_check(rqstp, p);
  463. }
  464. /* ACCESS */
  465. int
  466. nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
  467. struct nfsd3_accessres *resp)
  468. {
  469. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  470. if (resp->status == 0)
  471. *p++ = htonl(resp->access);
  472. return xdr_ressize_check(rqstp, p);
  473. }
  474. /* READLINK */
  475. int
  476. nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
  477. struct nfsd3_readlinkres *resp)
  478. {
  479. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  480. if (resp->status == 0) {
  481. *p++ = htonl(resp->len);
  482. p += XDR_QUADLEN(resp->len);
  483. }
  484. return xdr_ressize_check(rqstp, p);
  485. }
  486. /* READ */
  487. int
  488. nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
  489. struct nfsd3_readres *resp)
  490. {
  491. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  492. if (resp->status == 0) {
  493. *p++ = htonl(resp->count);
  494. *p++ = htonl(resp->eof);
  495. *p++ = htonl(resp->count); /* xdr opaque count */
  496. p += XDR_QUADLEN(resp->count);
  497. }
  498. return xdr_ressize_check(rqstp, p);
  499. }
  500. /* WRITE */
  501. int
  502. nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
  503. struct nfsd3_writeres *resp)
  504. {
  505. p = encode_wcc_data(rqstp, p, &resp->fh);
  506. if (resp->status == 0) {
  507. *p++ = htonl(resp->count);
  508. *p++ = htonl(resp->committed);
  509. *p++ = htonl(nfssvc_boot.tv_sec);
  510. *p++ = htonl(nfssvc_boot.tv_usec);
  511. }
  512. return xdr_ressize_check(rqstp, p);
  513. }
  514. /* CREATE, MKDIR, SYMLINK, MKNOD */
  515. int
  516. nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
  517. struct nfsd3_diropres *resp)
  518. {
  519. if (resp->status == 0) {
  520. *p++ = xdr_one;
  521. p = encode_fh(p, &resp->fh);
  522. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  523. }
  524. p = encode_wcc_data(rqstp, p, &resp->dirfh);
  525. return xdr_ressize_check(rqstp, p);
  526. }
  527. /* RENAME */
  528. int
  529. nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
  530. struct nfsd3_renameres *resp)
  531. {
  532. p = encode_wcc_data(rqstp, p, &resp->ffh);
  533. p = encode_wcc_data(rqstp, p, &resp->tfh);
  534. return xdr_ressize_check(rqstp, p);
  535. }
  536. /* LINK */
  537. int
  538. nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
  539. struct nfsd3_linkres *resp)
  540. {
  541. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  542. p = encode_wcc_data(rqstp, p, &resp->tfh);
  543. return xdr_ressize_check(rqstp, p);
  544. }
  545. /* READDIR */
  546. int
  547. nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
  548. struct nfsd3_readdirres *resp)
  549. {
  550. p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
  551. if (resp->status == 0) {
  552. /* stupid readdir cookie */
  553. memcpy(p, resp->verf, 8); p += 2;
  554. p += XDR_QUADLEN(resp->count);
  555. }
  556. return xdr_ressize_check(rqstp, p);
  557. }
  558. /*
  559.  * Encode a directory entry. This one works for both normal readdir
  560.  * and readdirplus.
  561.  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
  562.  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
  563.  * 
  564.  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
  565.  * file handle.
  566.  */
  567. #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
  568. #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
  569. static int
  570. encode_entry(struct readdir_cd *cd, const char *name,
  571.      int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
  572. {
  573. u32 *p = cd->buffer;
  574. int buflen, slen, elen;
  575. if (cd->offset)
  576. xdr_encode_hyper(cd->offset, (u64) offset);
  577. /* nfsd_readdir calls us with name == 0 when it wants us to
  578.  * set the last offset entry. */
  579. if (name == 0)
  580. return 0;
  581. /*
  582. dprintk("encode_entry(%.*s @%ld%s)n",
  583. namlen, name, (long) offset, plus? " plus" : "");
  584.  */
  585. /* truncate filename if too long */
  586. if (namlen > NFS3_MAXNAMLEN)
  587. namlen = NFS3_MAXNAMLEN;
  588. slen = XDR_QUADLEN(namlen);
  589. elen = slen + NFS3_ENTRY_BAGGAGE
  590. + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
  591. if ((buflen = cd->buflen - elen) < 0) {
  592. cd->eob = 1;
  593. return -EINVAL;
  594. }
  595. *p++ = xdr_one;  /* mark entry present */
  596. p    = xdr_encode_hyper(p, ino);  /* file id */
  597. p    = xdr_encode_array(p, name, namlen);/* name length & name */
  598. cd->offset = p; /* remember pointer */
  599. p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
  600. /* throw in readdirplus baggage */
  601. if (plus) {
  602. struct svc_fh fh;
  603. struct svc_export *exp;
  604. struct dentry *dparent, *dchild;
  605. dparent = cd->dirfh->fh_dentry;
  606. exp  = cd->dirfh->fh_export;
  607. fh_init(&fh, NFS3_FHSIZE);
  608. if (isdotent(name, namlen)) {
  609. dchild = dparent;
  610. if (namlen == 2)
  611. dchild = dchild->d_parent;
  612. dchild = dget(dchild);
  613. } else
  614. dchild = lookup_one_len(name, dparent,namlen);
  615. if (IS_ERR(dchild))
  616. goto noexec;
  617. if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
  618. goto noexec;
  619. p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
  620. *p++ = xdr_one; /* yes, a file handle follows */
  621. p = encode_fh(p, &fh);
  622. fh_put(&fh);
  623. }
  624. out:
  625. cd->buflen = buflen;
  626. cd->buffer = p;
  627. return 0;
  628. noexec:
  629. *p++ = 0;
  630. *p++ = 0;
  631. goto out;
  632. }
  633. int
  634. nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
  635.      int namlen, loff_t offset, ino_t ino, unsigned int d_type)
  636. {
  637. return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
  638. }
  639. int
  640. nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
  641.   int namlen, loff_t offset, ino_t ino, unsigned int d_type)
  642. {
  643. return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
  644. }
  645. /* FSSTAT */
  646. int
  647. nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
  648. struct nfsd3_fsstatres *resp)
  649. {
  650. struct statfs *s = &resp->stats;
  651. u64 bs = s->f_bsize;
  652. *p++ = xdr_zero; /* no post_op_attr */
  653. if (resp->status == 0) {
  654. p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
  655. p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
  656. p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
  657. p = xdr_encode_hyper(p, s->f_files); /* total inodes */
  658. p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
  659. p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
  660. *p++ = htonl(resp->invarsec); /* mean unchanged time */
  661. }
  662. return xdr_ressize_check(rqstp, p);
  663. }
  664. /* FSINFO */
  665. int
  666. nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
  667. struct nfsd3_fsinfores *resp)
  668. {
  669. *p++ = xdr_zero; /* no post_op_attr */
  670. if (resp->status == 0) {
  671. *p++ = htonl(resp->f_rtmax);
  672. *p++ = htonl(resp->f_rtpref);
  673. *p++ = htonl(resp->f_rtmult);
  674. *p++ = htonl(resp->f_wtmax);
  675. *p++ = htonl(resp->f_wtpref);
  676. *p++ = htonl(resp->f_wtmult);
  677. *p++ = htonl(resp->f_dtpref);
  678. p = xdr_encode_hyper(p, resp->f_maxfilesize);
  679. *p++ = xdr_one;
  680. *p++ = xdr_zero;
  681. *p++ = htonl(resp->f_properties);
  682. }
  683. return xdr_ressize_check(rqstp, p);
  684. }
  685. /* PATHCONF */
  686. int
  687. nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
  688. struct nfsd3_pathconfres *resp)
  689. {
  690. *p++ = xdr_zero; /* no post_op_attr */
  691. if (resp->status == 0) {
  692. *p++ = htonl(resp->p_link_max);
  693. *p++ = htonl(resp->p_name_max);
  694. *p++ = htonl(resp->p_no_trunc);
  695. *p++ = htonl(resp->p_chown_restricted);
  696. *p++ = htonl(resp->p_case_insensitive);
  697. *p++ = htonl(resp->p_case_preserving);
  698. }
  699. return xdr_ressize_check(rqstp, p);
  700. }
  701. /* COMMIT */
  702. int
  703. nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
  704. struct nfsd3_commitres *resp)
  705. {
  706. p = encode_wcc_data(rqstp, p, &resp->fh);
  707. /* Write verifier */
  708. if (resp->status == 0) {
  709. *p++ = htonl(nfssvc_boot.tv_sec);
  710. *p++ = htonl(nfssvc_boot.tv_usec);
  711. }
  712. return xdr_ressize_check(rqstp, p);
  713. }
  714. /*
  715.  * XDR release functions
  716.  */
  717. int
  718. nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
  719. struct nfsd3_attrstat *resp)
  720. {
  721. fh_put(&resp->fh);
  722. return 1;
  723. }
  724. int
  725. nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
  726. struct nfsd3_fhandle_pair *resp)
  727. {
  728. fh_put(&resp->fh1);
  729. fh_put(&resp->fh2);
  730. return 1;
  731. }