Import 2.3.47pre4
[davej-history.git] / fs / nfsd / nfs3xdr.c
blob8c3f8b525b17d487523f026dfc6966a43bc406e4
1 /*
2 * linux/fs/nfsd/nfs3xdr.c
4 * XDR support for nfsd/protocol version 3.
6 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
7 */
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/nfs3.h>
13 #include <linux/sunrpc/xdr.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/nfsd/nfsd.h>
16 #include <linux/nfsd/xdr3.h>
18 #define NFSDDBG_FACILITY NFSDDBG_XDR
20 #ifdef NFSD_OPTIMIZE_SPACE
21 # define inline
22 #endif
25 * Size of encoded NFS3 file handle, in words
27 #define NFS3_FHANDLE_WORDS (1 + XDR_QUADLEN(sizeof(struct knfs_fh)))
30 * Mapping of S_IF* types to NFS file types
32 static u32 nfs3_ftypes[] = {
33 NF3NON, NF3FIFO, NF3CHR, NF3BAD,
34 NF3DIR, NF3BAD, NF3BLK, NF3BAD,
35 NF3REG, NF3BAD, NF3LNK, NF3BAD,
36 NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
40 * XDR functions for basic NFS types
42 static inline u32 *
43 dec64(u32 *p, u64 *valp)
45 *valp = ((u64) ntohl(*p++)) << 32;
46 *valp |= ntohl(*p++);
47 return p;
50 static inline u32 *
51 encode_time3(u32 *p, time_t secs)
53 *p++ = htonl((u32) secs); *p++ = 0;
54 return p;
57 static inline u32 *
58 decode_time3(u32 *p, time_t *secp)
60 *secp = ntohl(*p++);
61 return p + 1;
64 static inline u32 *
65 decode_fh(u32 *p, struct svc_fh *fhp)
67 if (ntohl(*p++) != sizeof(struct knfs_fh))
68 return NULL;
70 memcpy(&fhp->fh_handle, p, sizeof(struct knfs_fh));
71 return p + (sizeof(struct knfs_fh) >> 2);
74 static inline u32 *
75 encode_fh(u32 *p, struct svc_fh *fhp)
77 *p++ = htonl(sizeof(struct knfs_fh));
78 memcpy(p, &fhp->fh_handle, sizeof(struct knfs_fh));
79 return p + (sizeof(struct knfs_fh) >> 2);
83 * Decode a file name and make sure that the path contains
84 * no slashes or null bytes.
86 static inline u32 *
87 decode_filename(u32 *p, char **namp, int *lenp)
89 char *name;
90 int i;
92 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
93 for (i = 0, name = *namp; i < *lenp; i++, name++) {
94 if (*name == '\0' || *name == '/')
95 return NULL;
97 *name = '\0';
100 return p;
103 static inline u32 *
104 decode_pathname(u32 *p, char **namp, int *lenp)
106 char *name;
107 int i;
109 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
110 for (i = 0, name = *namp; i < *lenp; i++, name++) {
111 if (*name == '\0')
112 return NULL;
114 *name = '\0';
117 return p;
120 static inline u32 *
121 decode_sattr3(u32 *p, struct iattr *iap)
123 u32 tmp;
125 iap->ia_valid = 0;
127 if (*p++) {
128 iap->ia_valid |= ATTR_MODE;
129 iap->ia_mode = ntohl(*p++);
131 if (*p++) {
132 iap->ia_valid |= ATTR_UID;
133 iap->ia_uid = ntohl(*p++);
135 if (*p++) {
136 iap->ia_valid |= ATTR_GID;
137 iap->ia_gid = ntohl(*p++);
139 if (*p++) {
140 u64 newsize;
142 iap->ia_valid |= ATTR_SIZE;
143 p = dec64(p, &newsize);
144 if (newsize <= NFS_OFFSET_MAX)
145 iap->ia_size = (u32) newsize;
146 else
147 iap->ia_size = ~(size_t) 0;
149 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
150 iap->ia_valid |= ATTR_ATIME;
151 } else if (tmp == 2) { /* set to client time */
152 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
153 iap->ia_atime = ntohl(*p++), p++;
155 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
156 iap->ia_valid |= ATTR_MTIME;
157 } else if (tmp == 2) { /* set to client time */
158 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
159 iap->ia_mtime = ntohl(*p++), p++;
161 return p;
164 static inline u32 *
165 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
167 struct inode *inode = dentry->d_inode;
169 if (!inode) {
170 printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
171 return NULL;
174 *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
175 *p++ = htonl((u32) inode->i_mode);
176 *p++ = htonl((u32) inode->i_nlink);
177 *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
178 *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
179 if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
180 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
181 } else {
182 p = xdr_encode_hyper(p, (u64) inode->i_size);
184 p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
185 *p++ = htonl((u32) MAJOR(inode->i_rdev));
186 *p++ = htonl((u32) MINOR(inode->i_rdev));
187 p = xdr_encode_hyper(p, (u64) inode->i_dev);
188 p = xdr_encode_hyper(p, (u64) inode->i_ino);
189 p = encode_time3(p, inode->i_atime);
190 p = encode_time3(p, inode->i_mtime);
191 p = encode_time3(p, inode->i_ctime);
193 return p;
196 static inline u32 *
197 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
199 struct inode *inode = fhp->fh_dentry->d_inode;
201 /* Attributes to follow */
202 *p++ = xdr_one;
204 *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
205 *p++ = htonl((u32) fhp->fh_post_mode);
206 *p++ = htonl((u32) fhp->fh_post_nlink);
207 *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
208 *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
209 if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
210 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
211 } else {
212 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
214 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
215 *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
216 *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
217 p = xdr_encode_hyper(p, (u64) inode->i_dev);
218 p = xdr_encode_hyper(p, (u64) inode->i_ino);
219 p = encode_time3(p, fhp->fh_post_atime);
220 p = encode_time3(p, fhp->fh_post_mtime);
221 p = encode_time3(p, fhp->fh_post_ctime);
223 return p;
227 * Encode post-operation attributes.
228 * The inode may be NULL if the call failed because of a stale file
229 * handle. In this case, no attributes are returned.
231 static u32 *
232 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
234 if (dentry && dentry->d_inode != NULL) {
235 *p++ = xdr_one; /* attributes follow */
236 return encode_fattr3(rqstp, p, dentry);
238 *p++ = xdr_zero;
239 return p;
243 * Enocde weak cache consistency data
245 static u32 *
246 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
248 struct dentry *dentry = fhp->fh_dentry;
250 if (dentry && dentry->d_inode && fhp->fh_post_saved) {
251 if (fhp->fh_pre_saved) {
252 *p++ = xdr_one;
253 p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
254 p = encode_time3(p, fhp->fh_pre_mtime);
255 p = encode_time3(p, fhp->fh_pre_ctime);
256 } else {
257 *p++ = xdr_zero;
259 return encode_saved_post_attr(rqstp, p, fhp);
261 /* no pre- or post-attrs */
262 *p++ = xdr_zero;
263 return encode_post_op_attr(rqstp, p, dentry);
267 * Check buffer bounds after decoding arguments
269 static inline int
270 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
272 struct svc_buf *buf = &rqstp->rq_argbuf;
274 return p - buf->base <= buf->buflen;
277 static inline int
278 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
280 struct svc_buf *buf = &rqstp->rq_resbuf;
282 buf->len = p - buf->base;
283 dprintk("nfsd: ressize_check p %p base %p len %d\n",
284 p, buf->base, buf->buflen);
285 return (buf->len <= buf->buflen);
289 * XDR decode functions
292 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
294 if (!(p = decode_fh(p, fhp)))
295 return 0;
296 return xdr_argsize_check(rqstp, p);
300 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
301 struct nfsd3_sattrargs *args)
303 if (!(p = decode_fh(p, &args->fh))
304 || !(p = decode_sattr3(p, &args->attrs)))
305 return 0;
307 if ((args->check_guard = ntohl(*p++)) != 0)
308 p = decode_time3(p, &args->guardtime);
310 return xdr_argsize_check(rqstp, p);
314 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
315 struct nfsd3_diropargs *args)
317 if (!(p = decode_fh(p, &args->fh))
318 || !(p = decode_filename(p, &args->name, &args->len)))
319 return 0;
321 return xdr_argsize_check(rqstp, p);
325 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
326 struct nfsd3_accessargs *args)
328 if (!(p = decode_fh(p, &args->fh)))
329 return 0;
330 args->access = ntohl(*p++);
332 return xdr_argsize_check(rqstp, p);
336 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
337 struct nfsd3_readargs *args)
339 if (!(p = decode_fh(p, &args->fh))
340 || !(p = dec64(p, &args->offset)))
341 return 0;
343 args->count = ntohl(*p++);
344 return xdr_argsize_check(rqstp, p);
348 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
349 struct nfsd3_writeargs *args)
351 if (!(p = decode_fh(p, &args->fh))
352 || !(p = dec64(p, &args->offset)))
353 return 0;
355 args->count = ntohl(*p++);
356 args->stable = ntohl(*p++);
357 args->len = ntohl(*p++);
358 args->data = (char *) p;
359 p += XDR_QUADLEN(args->len);
361 return xdr_argsize_check(rqstp, p);
365 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
366 struct nfsd3_createargs *args)
368 if (!(p = decode_fh(p, &args->fh))
369 || !(p = decode_filename(p, &args->name, &args->len)))
370 return 0;
372 switch (args->createmode = ntohl(*p++)) {
373 case NFS3_CREATE_UNCHECKED:
374 case NFS3_CREATE_GUARDED:
375 if (!(p = decode_sattr3(p, &args->attrs)))
376 return 0;
377 break;
378 case NFS3_CREATE_EXCLUSIVE:
379 args->verf = p;
380 p += 2;
381 break;
382 default:
383 return 0;
386 return xdr_argsize_check(rqstp, p);
389 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
390 struct nfsd3_createargs *args)
392 if (!(p = decode_fh(p, &args->fh))
393 || !(p = decode_filename(p, &args->name, &args->len))
394 || !(p = decode_sattr3(p, &args->attrs)))
395 return 0;
397 return xdr_argsize_check(rqstp, p);
401 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
402 struct nfsd3_symlinkargs *args)
404 if (!(p = decode_fh(p, &args->ffh))
405 || !(p = decode_filename(p, &args->fname, &args->flen))
406 || !(p = decode_sattr3(p, &args->attrs))
407 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
408 return 0;
410 return xdr_argsize_check(rqstp, p);
414 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
415 struct nfsd3_mknodargs *args)
417 if (!(p = decode_fh(p, &args->fh))
418 || !(p = decode_filename(p, &args->name, &args->len)))
419 return 0;
421 args->ftype = ntohl(*p++);
423 if (args->ftype == NF3BLK || args->ftype == NF3CHR
424 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
425 if (!(p = decode_sattr3(p, &args->attrs)))
426 return 0;
429 if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
430 args->major = ntohl(*p++);
431 args->minor = ntohl(*p++);
434 return xdr_argsize_check(rqstp, p);
438 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
439 struct nfsd3_renameargs *args)
441 if (!(p = decode_fh(p, &args->ffh))
442 || !(p = decode_filename(p, &args->fname, &args->flen))
443 || !(p = decode_fh(p, &args->tfh))
444 || !(p = decode_filename(p, &args->tname, &args->tlen)))
445 return 0;
447 return xdr_argsize_check(rqstp, p);
451 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
452 struct nfsd3_linkargs *args)
454 if (!(p = decode_fh(p, &args->ffh))
455 || !(p = decode_fh(p, &args->tfh))
456 || !(p = decode_filename(p, &args->tname, &args->tlen)))
457 return 0;
459 return xdr_argsize_check(rqstp, p);
463 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
464 struct nfsd3_readdirargs *args)
466 if (!(p = decode_fh(p, &args->fh)))
467 return 0;
468 p = dec64(p, &args->cookie);
469 args->verf = p; p += 2;
470 args->dircount = ~0;
471 args->count = ntohl(*p++);
473 return xdr_argsize_check(rqstp, p);
477 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
478 struct nfsd3_readdirargs *args)
480 if (!(p = decode_fh(p, &args->fh)))
481 return 0;
482 p = dec64(p, &args->cookie);
483 args->verf = p; p += 2;
484 args->dircount = ntohl(*p++);
485 args->count = ntohl(*p++);
487 return xdr_argsize_check(rqstp, p);
491 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
492 struct nfsd3_commitargs *args)
494 if (!(p = decode_fh(p, &args->fh)))
495 return 0;
496 p = dec64(p, &args->offset);
497 args->count = ntohl(*p++);
499 return xdr_argsize_check(rqstp, p);
503 * XDR encode functions
506 * There must be an encoding function for void results so svc_process
507 * will work properly.
510 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
512 return xdr_ressize_check(rqstp, p);
515 /* GETATTR */
517 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
518 struct nfsd3_attrstat *resp)
520 if (resp->status == 0
521 && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
522 return 0;
523 return xdr_ressize_check(rqstp, p);
526 /* SETATTR, REMOVE, RMDIR */
528 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
529 struct nfsd3_attrstat *resp)
531 if (!(p = encode_wcc_data(rqstp, p, &resp->fh)))
532 return 0;
533 return xdr_ressize_check(rqstp, p);
536 /* LOOKUP */
538 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
539 struct nfsd3_diropres *resp)
541 if (resp->status == 0) {
542 p = encode_fh(p, &resp->fh);
543 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
545 p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
546 return xdr_ressize_check(rqstp, p);
549 /* ACCESS */
551 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
552 struct nfsd3_accessres *resp)
554 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
555 if (resp->status == 0)
556 *p++ = htonl(resp->access);
557 return xdr_ressize_check(rqstp, p);
560 /* READLINK */
562 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
563 struct nfsd3_readlinkres *resp)
565 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
566 if (resp->status == 0) {
567 *p++ = htonl(resp->len);
568 p += XDR_QUADLEN(resp->len);
570 return xdr_ressize_check(rqstp, p);
573 /* READ */
575 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
576 struct nfsd3_readres *resp)
578 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
579 if (resp->status == 0) {
580 *p++ = htonl(resp->count);
581 *p++ = htonl(resp->eof);
582 *p++ = htonl(resp->count); /* xdr opaque count */
583 p += XDR_QUADLEN(resp->count);
585 return xdr_ressize_check(rqstp, p);
588 /* WRITE */
590 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
591 struct nfsd3_writeres *resp)
593 p = encode_wcc_data(rqstp, p, &resp->fh);
594 if (resp->status == 0) {
595 *p++ = htonl(resp->count);
596 *p++ = htonl(resp->committed);
597 *p++ = htonl(nfssvc_boot.tv_sec);
598 *p++ = htonl(nfssvc_boot.tv_usec);
600 return xdr_ressize_check(rqstp, p);
603 /* CREATE, MKDIR, SYMLINK, MKNOD */
605 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
606 struct nfsd3_diropres *resp)
608 if (resp->status == 0) {
609 *p++ = xdr_one;
610 p = encode_fh(p, &resp->fh);
611 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
613 p = encode_wcc_data(rqstp, p, &resp->dirfh);
614 return xdr_ressize_check(rqstp, p);
617 /* RENAME */
619 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
620 struct nfsd3_renameres *resp)
622 p = encode_wcc_data(rqstp, p, &resp->ffh);
623 p = encode_wcc_data(rqstp, p, &resp->tfh);
624 return xdr_ressize_check(rqstp, p);
627 /* LINK */
629 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
630 struct nfsd3_linkres *resp)
632 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
633 p = encode_wcc_data(rqstp, p, &resp->tfh);
634 return xdr_ressize_check(rqstp, p);
637 /* READDIR */
639 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
640 struct nfsd3_readdirres *resp)
642 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
643 if (resp->status == 0) {
644 /* stupid readdir cookie */
645 memcpy(p, resp->verf, 8); p += 2;
646 p += XDR_QUADLEN(resp->count);
649 return xdr_ressize_check(rqstp, p);
653 * Encode a directory entry. This one works for both normal readdir
654 * and readdirplus.
655 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
656 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
658 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
659 * file handle.
662 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
663 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
664 static int
665 encode_entry(struct readdir_cd *cd, const char *name,
666 int namlen, off_t offset, ino_t ino, int plus)
668 u32 *p = cd->buffer;
669 int buflen, slen, elen;
671 if (cd->offset)
672 xdr_encode_hyper(cd->offset, (u64) offset);
674 /* nfsd_readdir calls us with name == 0 when it wants us to
675 * set the last offset entry. */
676 if (name == 0)
677 return 0;
680 dprintk("encode_entry(%.*s @%ld%s)\n",
681 namlen, name, (long) offset, plus? " plus" : "");
684 /* truncate filename if too long */
685 if (namlen > NFS3_MAXNAMLEN)
686 namlen = NFS3_MAXNAMLEN;
688 slen = XDR_QUADLEN(namlen);
689 elen = slen + NFS3_ENTRY_BAGGAGE
690 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
691 if ((buflen = cd->buflen - elen) < 0) {
692 cd->eob = 1;
693 return -EINVAL;
695 *p++ = xdr_one; /* mark entry present */
696 p = xdr_encode_hyper(p, ino); /* file id */
697 #ifdef XDR_ENCODE_STRING_TAKES_LENGTH
698 p = xdr_encode_string(p, name, namlen); /* name length & name */
699 #else
700 /* just like nfsproc.c */
701 *p++ = htonl((u32) namlen);
702 memcpy(p, name, namlen);
703 p += slen;
704 #endif
705 p[slen - 1] = 0; /* don't leak kernel data */
707 cd->offset = p; /* remember pointer */
708 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
710 /* throw in readdirplus baggage */
711 if (plus) {
712 struct svc_fh fh;
714 fh_init(&fh);
715 /* Disabled for now because of lock-up */
716 if (0 && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh) == 0) {
717 p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
718 p = encode_fh(p, &fh);
719 fh_put(&fh);
720 } else {
721 /* Didn't find this entry... weird.
722 * Proceed without the attrs anf fh anyway.
724 *p++ = 0;
725 *p++ = 0;
729 cd->buflen = buflen;
730 cd->buffer = p;
731 return 0;
735 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
736 int namlen, off_t offset, ino_t ino)
738 return encode_entry(cd, name, namlen, offset, ino, 0);
742 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
743 int namlen, off_t offset, ino_t ino)
745 return encode_entry(cd, name, namlen, offset, ino, 1);
748 /* FSSTAT */
750 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
751 struct nfsd3_fsstatres *resp)
753 struct statfs *s = &resp->stats;
754 u64 bs = s->f_bsize;
756 *p++ = xdr_zero; /* no post_op_attr */
758 if (resp->status == 0) {
759 p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
760 p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
761 p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
762 p = xdr_encode_hyper(p, s->f_files); /* total inodes */
763 p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
764 p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
765 *p++ = htonl(resp->invarsec); /* mean unchanged time */
767 return xdr_ressize_check(rqstp, p);
770 /* FSINFO */
772 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
773 struct nfsd3_fsinfores *resp)
775 *p++ = xdr_zero; /* no post_op_attr */
777 if (resp->status == 0) {
778 *p++ = htonl(resp->f_rtmax);
779 *p++ = htonl(resp->f_rtpref);
780 *p++ = htonl(resp->f_rtmult);
781 *p++ = htonl(resp->f_wtmax);
782 *p++ = htonl(resp->f_wtpref);
783 *p++ = htonl(resp->f_wtmult);
784 *p++ = htonl(resp->f_dtpref);
785 p = xdr_encode_hyper(p, resp->f_maxfilesize);
786 *p++ = xdr_one;
787 *p++ = xdr_zero;
788 *p++ = htonl(resp->f_properties);
791 return xdr_ressize_check(rqstp, p);
794 /* PATHCONF */
796 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
797 struct nfsd3_pathconfres *resp)
799 *p++ = xdr_zero; /* no post_op_attr */
801 if (resp->status == 0) {
802 *p++ = htonl(resp->p_link_max);
803 *p++ = htonl(resp->p_name_max);
804 *p++ = htonl(resp->p_no_trunc);
805 *p++ = htonl(resp->p_chown_restricted);
806 *p++ = htonl(resp->p_case_insensitive);
807 *p++ = htonl(resp->p_case_preserving);
810 return xdr_ressize_check(rqstp, p);
813 /* COMMIT */
815 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
816 struct nfsd3_commitres *resp)
818 p = encode_wcc_data(rqstp, p, &resp->fh);
819 /* Write verifier */
820 if (resp->status == 0) {
821 *p++ = htonl(nfssvc_boot.tv_sec);
822 *p++ = htonl(nfssvc_boot.tv_usec);
824 return xdr_ressize_check(rqstp, p);
828 * XDR release functions
831 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
832 struct nfsd3_attrstat *resp)
834 fh_put(&resp->fh);
835 return 1;
839 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
840 struct nfsd3_fhandle_pair *resp)
842 fh_put(&resp->fh1);
843 fh_put(&resp->fh2);
844 return 1;