Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / fs / nfsd / nfs3xdr.c
blob3c14a44c4d5b42be8981fe83980e311761d435c7
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
26 * Mapping of S_IF* types to NFS file types
28 static u32 nfs3_ftypes[] = {
29 NF3NON, NF3FIFO, NF3CHR, NF3BAD,
30 NF3DIR, NF3BAD, NF3BLK, NF3BAD,
31 NF3REG, NF3BAD, NF3LNK, NF3BAD,
32 NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
36 * XDR functions for basic NFS types
38 static inline u32 *
39 encode_time3(u32 *p, time_t secs)
41 *p++ = htonl((u32) secs); *p++ = 0;
42 return p;
45 static inline u32 *
46 decode_time3(u32 *p, time_t *secp)
48 *secp = ntohl(*p++);
49 return p + 1;
52 static inline u32 *
53 decode_fh(u32 *p, struct svc_fh *fhp)
55 int size;
56 fh_init(fhp, NFS3_FHSIZE);
57 size = ntohl(*p++);
58 if (size > NFS3_FHSIZE)
59 return NULL;
61 memcpy(&fhp->fh_handle.fh_base, p, size);
62 fhp->fh_handle.fh_size = size;
63 return p + XDR_QUADLEN(size);
66 static inline u32 *
67 encode_fh(u32 *p, struct svc_fh *fhp)
69 int size = fhp->fh_handle.fh_size;
70 *p++ = htonl(size);
71 if (size) p[XDR_QUADLEN(size)-1]=0;
72 memcpy(p, &fhp->fh_handle.fh_base, size);
73 return p + XDR_QUADLEN(size);
77 * Decode a file name and make sure that the path contains
78 * no slashes or null bytes.
80 static inline u32 *
81 decode_filename(u32 *p, char **namp, int *lenp)
83 char *name;
84 int i;
86 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
87 for (i = 0, name = *namp; i < *lenp; i++, name++) {
88 if (*name == '\0' || *name == '/')
89 return NULL;
91 *name = '\0';
94 return p;
97 static inline u32 *
98 decode_pathname(u32 *p, char **namp, int *lenp)
100 char *name;
101 int i;
103 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
104 for (i = 0, name = *namp; i < *lenp; i++, name++) {
105 if (*name == '\0')
106 return NULL;
108 *name = '\0';
111 return p;
114 static inline u32 *
115 decode_sattr3(u32 *p, struct iattr *iap)
117 u32 tmp;
119 iap->ia_valid = 0;
121 if (*p++) {
122 iap->ia_valid |= ATTR_MODE;
123 iap->ia_mode = ntohl(*p++);
125 if (*p++) {
126 iap->ia_valid |= ATTR_UID;
127 iap->ia_uid = ntohl(*p++);
129 if (*p++) {
130 iap->ia_valid |= ATTR_GID;
131 iap->ia_gid = ntohl(*p++);
133 if (*p++) {
134 u64 newsize;
136 iap->ia_valid |= ATTR_SIZE;
137 p = xdr_decode_hyper(p, &newsize);
138 if (newsize <= NFS_OFFSET_MAX)
139 iap->ia_size = newsize;
140 else
141 iap->ia_size = NFS_OFFSET_MAX;
143 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
144 iap->ia_valid |= ATTR_ATIME;
145 } else if (tmp == 2) { /* set to client time */
146 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
147 iap->ia_atime = ntohl(*p++), p++;
149 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
150 iap->ia_valid |= ATTR_MTIME;
151 } else if (tmp == 2) { /* set to client time */
152 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
153 iap->ia_mtime = ntohl(*p++), p++;
155 return p;
158 static inline u32 *
159 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
161 struct inode *inode = dentry->d_inode;
163 if (!inode) {
164 printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
165 return NULL;
168 *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
169 *p++ = htonl((u32) inode->i_mode);
170 *p++ = htonl((u32) inode->i_nlink);
171 *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
172 *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
173 if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
174 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
175 } else {
176 p = xdr_encode_hyper(p, (u64) inode->i_size);
178 if (inode->i_blksize == 0 && inode->i_blocks == 0)
179 /* Minix file system(?) i_size is (hopefully) close enough */
180 p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
181 else
182 p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
183 *p++ = htonl((u32) MAJOR(inode->i_rdev));
184 *p++ = htonl((u32) MINOR(inode->i_rdev));
185 p = xdr_encode_hyper(p, (u64) inode->i_dev);
186 p = xdr_encode_hyper(p, (u64) inode->i_ino);
187 p = encode_time3(p, inode->i_atime);
188 p = encode_time3(p, lease_get_mtime(inode));
189 p = encode_time3(p, inode->i_ctime);
191 return p;
194 static inline u32 *
195 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
197 struct inode *inode = fhp->fh_dentry->d_inode;
199 /* Attributes to follow */
200 *p++ = xdr_one;
202 *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
203 *p++ = htonl((u32) fhp->fh_post_mode);
204 *p++ = htonl((u32) fhp->fh_post_nlink);
205 *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
206 *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
207 if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
208 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
209 } else {
210 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
212 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
213 *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
214 *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
215 p = xdr_encode_hyper(p, (u64) inode->i_dev);
216 p = xdr_encode_hyper(p, (u64) inode->i_ino);
217 p = encode_time3(p, fhp->fh_post_atime);
218 p = encode_time3(p, fhp->fh_post_mtime);
219 p = encode_time3(p, fhp->fh_post_ctime);
221 return p;
225 * Encode post-operation attributes.
226 * The inode may be NULL if the call failed because of a stale file
227 * handle. In this case, no attributes are returned.
229 static u32 *
230 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
232 if (dentry && dentry->d_inode != NULL) {
233 *p++ = xdr_one; /* attributes follow */
234 return encode_fattr3(rqstp, p, dentry);
236 *p++ = xdr_zero;
237 return p;
241 * Enocde weak cache consistency data
243 static u32 *
244 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
246 struct dentry *dentry = fhp->fh_dentry;
248 if (dentry && dentry->d_inode && fhp->fh_post_saved) {
249 if (fhp->fh_pre_saved) {
250 *p++ = xdr_one;
251 p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
252 p = encode_time3(p, fhp->fh_pre_mtime);
253 p = encode_time3(p, fhp->fh_pre_ctime);
254 } else {
255 *p++ = xdr_zero;
257 return encode_saved_post_attr(rqstp, p, fhp);
259 /* no pre- or post-attrs */
260 *p++ = xdr_zero;
261 return encode_post_op_attr(rqstp, p, dentry);
265 * Check buffer bounds after decoding arguments
267 static inline int
268 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
270 struct svc_buf *buf = &rqstp->rq_argbuf;
272 return p - buf->base <= buf->buflen;
275 static inline int
276 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
278 struct svc_buf *buf = &rqstp->rq_resbuf;
280 buf->len = p - buf->base;
281 dprintk("nfsd: ressize_check p %p base %p len %d\n",
282 p, buf->base, buf->buflen);
283 return (buf->len <= buf->buflen);
287 * XDR decode functions
290 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
292 if (!(p = decode_fh(p, fhp)))
293 return 0;
294 return xdr_argsize_check(rqstp, p);
298 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
299 struct nfsd3_sattrargs *args)
301 if (!(p = decode_fh(p, &args->fh))
302 || !(p = decode_sattr3(p, &args->attrs)))
303 return 0;
305 if ((args->check_guard = ntohl(*p++)) != 0)
306 p = decode_time3(p, &args->guardtime);
308 return xdr_argsize_check(rqstp, p);
312 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
313 struct nfsd3_diropargs *args)
315 if (!(p = decode_fh(p, &args->fh))
316 || !(p = decode_filename(p, &args->name, &args->len)))
317 return 0;
319 return xdr_argsize_check(rqstp, p);
323 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
324 struct nfsd3_accessargs *args)
326 if (!(p = decode_fh(p, &args->fh)))
327 return 0;
328 args->access = ntohl(*p++);
330 return xdr_argsize_check(rqstp, p);
334 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
335 struct nfsd3_readargs *args)
337 if (!(p = decode_fh(p, &args->fh))
338 || !(p = xdr_decode_hyper(p, &args->offset)))
339 return 0;
341 args->count = ntohl(*p++);
342 return xdr_argsize_check(rqstp, p);
346 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
347 struct nfsd3_writeargs *args)
349 if (!(p = decode_fh(p, &args->fh))
350 || !(p = xdr_decode_hyper(p, &args->offset)))
351 return 0;
353 args->count = ntohl(*p++);
354 args->stable = ntohl(*p++);
355 args->len = ntohl(*p++);
356 args->data = (char *) p;
357 p += XDR_QUADLEN(args->len);
359 return xdr_argsize_check(rqstp, p);
363 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
364 struct nfsd3_createargs *args)
366 if (!(p = decode_fh(p, &args->fh))
367 || !(p = decode_filename(p, &args->name, &args->len)))
368 return 0;
370 switch (args->createmode = ntohl(*p++)) {
371 case NFS3_CREATE_UNCHECKED:
372 case NFS3_CREATE_GUARDED:
373 if (!(p = decode_sattr3(p, &args->attrs)))
374 return 0;
375 break;
376 case NFS3_CREATE_EXCLUSIVE:
377 args->verf = p;
378 p += 2;
379 break;
380 default:
381 return 0;
384 return xdr_argsize_check(rqstp, p);
387 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
388 struct nfsd3_createargs *args)
390 if (!(p = decode_fh(p, &args->fh))
391 || !(p = decode_filename(p, &args->name, &args->len))
392 || !(p = decode_sattr3(p, &args->attrs)))
393 return 0;
395 return xdr_argsize_check(rqstp, p);
399 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
400 struct nfsd3_symlinkargs *args)
402 if (!(p = decode_fh(p, &args->ffh))
403 || !(p = decode_filename(p, &args->fname, &args->flen))
404 || !(p = decode_sattr3(p, &args->attrs))
405 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
406 return 0;
408 return xdr_argsize_check(rqstp, p);
412 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
413 struct nfsd3_mknodargs *args)
415 if (!(p = decode_fh(p, &args->fh))
416 || !(p = decode_filename(p, &args->name, &args->len)))
417 return 0;
419 args->ftype = ntohl(*p++);
421 if (args->ftype == NF3BLK || args->ftype == NF3CHR
422 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
423 if (!(p = decode_sattr3(p, &args->attrs)))
424 return 0;
427 if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
428 args->major = ntohl(*p++);
429 args->minor = ntohl(*p++);
432 return xdr_argsize_check(rqstp, p);
436 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
437 struct nfsd3_renameargs *args)
439 if (!(p = decode_fh(p, &args->ffh))
440 || !(p = decode_filename(p, &args->fname, &args->flen))
441 || !(p = decode_fh(p, &args->tfh))
442 || !(p = decode_filename(p, &args->tname, &args->tlen)))
443 return 0;
445 return xdr_argsize_check(rqstp, p);
449 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
450 struct nfsd3_linkargs *args)
452 if (!(p = decode_fh(p, &args->ffh))
453 || !(p = decode_fh(p, &args->tfh))
454 || !(p = decode_filename(p, &args->tname, &args->tlen)))
455 return 0;
457 return xdr_argsize_check(rqstp, p);
461 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
462 struct nfsd3_readdirargs *args)
464 if (!(p = decode_fh(p, &args->fh)))
465 return 0;
466 p = xdr_decode_hyper(p, &args->cookie);
467 args->verf = p; p += 2;
468 args->dircount = ~0;
469 args->count = ntohl(*p++);
471 return xdr_argsize_check(rqstp, p);
475 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
476 struct nfsd3_readdirargs *args)
478 if (!(p = decode_fh(p, &args->fh)))
479 return 0;
480 p = xdr_decode_hyper(p, &args->cookie);
481 args->verf = p; p += 2;
482 args->dircount = ntohl(*p++);
483 args->count = ntohl(*p++);
485 return xdr_argsize_check(rqstp, p);
489 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
490 struct nfsd3_commitargs *args)
492 if (!(p = decode_fh(p, &args->fh)))
493 return 0;
494 p = xdr_decode_hyper(p, &args->offset);
495 args->count = ntohl(*p++);
497 return xdr_argsize_check(rqstp, p);
501 * XDR encode functions
504 * There must be an encoding function for void results so svc_process
505 * will work properly.
508 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
510 return xdr_ressize_check(rqstp, p);
513 /* GETATTR */
515 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
516 struct nfsd3_attrstat *resp)
518 if (resp->status == 0
519 && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
520 return 0;
521 return xdr_ressize_check(rqstp, p);
524 /* SETATTR, REMOVE, RMDIR */
526 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
527 struct nfsd3_attrstat *resp)
529 if (!(p = encode_wcc_data(rqstp, p, &resp->fh)))
530 return 0;
531 return xdr_ressize_check(rqstp, p);
534 /* LOOKUP */
536 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
537 struct nfsd3_diropres *resp)
539 if (resp->status == 0) {
540 p = encode_fh(p, &resp->fh);
541 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
543 p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
544 return xdr_ressize_check(rqstp, p);
547 /* ACCESS */
549 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
550 struct nfsd3_accessres *resp)
552 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
553 if (resp->status == 0)
554 *p++ = htonl(resp->access);
555 return xdr_ressize_check(rqstp, p);
558 /* READLINK */
560 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
561 struct nfsd3_readlinkres *resp)
563 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
564 if (resp->status == 0) {
565 *p++ = htonl(resp->len);
566 p += XDR_QUADLEN(resp->len);
568 return xdr_ressize_check(rqstp, p);
571 /* READ */
573 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
574 struct nfsd3_readres *resp)
576 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
577 if (resp->status == 0) {
578 *p++ = htonl(resp->count);
579 *p++ = htonl(resp->eof);
580 *p++ = htonl(resp->count); /* xdr opaque count */
581 p += XDR_QUADLEN(resp->count);
583 return xdr_ressize_check(rqstp, p);
586 /* WRITE */
588 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
589 struct nfsd3_writeres *resp)
591 p = encode_wcc_data(rqstp, p, &resp->fh);
592 if (resp->status == 0) {
593 *p++ = htonl(resp->count);
594 *p++ = htonl(resp->committed);
595 *p++ = htonl(nfssvc_boot.tv_sec);
596 *p++ = htonl(nfssvc_boot.tv_usec);
598 return xdr_ressize_check(rqstp, p);
601 /* CREATE, MKDIR, SYMLINK, MKNOD */
603 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
604 struct nfsd3_diropres *resp)
606 if (resp->status == 0) {
607 *p++ = xdr_one;
608 p = encode_fh(p, &resp->fh);
609 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
611 p = encode_wcc_data(rqstp, p, &resp->dirfh);
612 return xdr_ressize_check(rqstp, p);
615 /* RENAME */
617 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
618 struct nfsd3_renameres *resp)
620 p = encode_wcc_data(rqstp, p, &resp->ffh);
621 p = encode_wcc_data(rqstp, p, &resp->tfh);
622 return xdr_ressize_check(rqstp, p);
625 /* LINK */
627 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
628 struct nfsd3_linkres *resp)
630 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
631 p = encode_wcc_data(rqstp, p, &resp->tfh);
632 return xdr_ressize_check(rqstp, p);
635 /* READDIR */
637 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
638 struct nfsd3_readdirres *resp)
640 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
641 if (resp->status == 0) {
642 /* stupid readdir cookie */
643 memcpy(p, resp->verf, 8); p += 2;
644 p += XDR_QUADLEN(resp->count);
647 return xdr_ressize_check(rqstp, p);
651 * Encode a directory entry. This one works for both normal readdir
652 * and readdirplus.
653 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
654 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
656 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
657 * file handle.
660 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
661 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
662 static int
663 encode_entry(struct readdir_cd *cd, const char *name,
664 int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
666 u32 *p = cd->buffer;
667 int buflen, slen, elen;
669 if (cd->offset)
670 xdr_encode_hyper(cd->offset, (u64) offset);
672 /* nfsd_readdir calls us with name == 0 when it wants us to
673 * set the last offset entry. */
674 if (name == 0)
675 return 0;
678 dprintk("encode_entry(%.*s @%ld%s)\n",
679 namlen, name, (long) offset, plus? " plus" : "");
682 /* truncate filename if too long */
683 if (namlen > NFS3_MAXNAMLEN)
684 namlen = NFS3_MAXNAMLEN;
686 slen = XDR_QUADLEN(namlen);
687 elen = slen + NFS3_ENTRY_BAGGAGE
688 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
689 if ((buflen = cd->buflen - elen) < 0) {
690 cd->eob = 1;
691 return -EINVAL;
693 *p++ = xdr_one; /* mark entry present */
694 p = xdr_encode_hyper(p, ino); /* file id */
695 p = xdr_encode_array(p, name, namlen);/* name length & name */
697 cd->offset = p; /* remember pointer */
698 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
700 /* throw in readdirplus baggage */
701 if (plus) {
702 struct svc_fh fh;
703 struct svc_export *exp;
704 struct dentry *dparent, *dchild;
706 dparent = cd->dirfh->fh_dentry;
707 exp = cd->dirfh->fh_export;
709 fh_init(&fh, NFS3_FHSIZE);
710 if (fh_verify(cd->rqstp, cd->dirfh, S_IFDIR, MAY_EXEC) != 0)
711 goto noexec;
712 if (isdotent(name, namlen)) {
713 dchild = dparent;
714 if (namlen == 2)
715 dchild = dchild->d_parent;
716 dchild = dget(dchild);
717 } else
718 dchild = lookup_one(name, dparent);
719 if (IS_ERR(dchild))
720 goto noexec;
721 if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
722 goto noexec;
723 p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
724 *p++ = xdr_one; /* yes, a file handle follows */
725 p = encode_fh(p, &fh);
726 fh_put(&fh);
729 out:
730 cd->buflen = buflen;
731 cd->buffer = p;
732 return 0;
734 noexec:
735 *p++ = 0;
736 *p++ = 0;
737 goto out;
741 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
742 int namlen, off_t offset, ino_t ino, unsigned int d_type)
744 return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
748 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
749 int namlen, off_t offset, ino_t ino, unsigned int d_type)
751 return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
754 /* FSSTAT */
756 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
757 struct nfsd3_fsstatres *resp)
759 struct statfs *s = &resp->stats;
760 u64 bs = s->f_bsize;
762 *p++ = xdr_zero; /* no post_op_attr */
764 if (resp->status == 0) {
765 p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
766 p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
767 p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
768 p = xdr_encode_hyper(p, s->f_files); /* total inodes */
769 p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
770 p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
771 *p++ = htonl(resp->invarsec); /* mean unchanged time */
773 return xdr_ressize_check(rqstp, p);
776 /* FSINFO */
778 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
779 struct nfsd3_fsinfores *resp)
781 *p++ = xdr_zero; /* no post_op_attr */
783 if (resp->status == 0) {
784 *p++ = htonl(resp->f_rtmax);
785 *p++ = htonl(resp->f_rtpref);
786 *p++ = htonl(resp->f_rtmult);
787 *p++ = htonl(resp->f_wtmax);
788 *p++ = htonl(resp->f_wtpref);
789 *p++ = htonl(resp->f_wtmult);
790 *p++ = htonl(resp->f_dtpref);
791 p = xdr_encode_hyper(p, resp->f_maxfilesize);
792 *p++ = xdr_one;
793 *p++ = xdr_zero;
794 *p++ = htonl(resp->f_properties);
797 return xdr_ressize_check(rqstp, p);
800 /* PATHCONF */
802 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
803 struct nfsd3_pathconfres *resp)
805 *p++ = xdr_zero; /* no post_op_attr */
807 if (resp->status == 0) {
808 *p++ = htonl(resp->p_link_max);
809 *p++ = htonl(resp->p_name_max);
810 *p++ = htonl(resp->p_no_trunc);
811 *p++ = htonl(resp->p_chown_restricted);
812 *p++ = htonl(resp->p_case_insensitive);
813 *p++ = htonl(resp->p_case_preserving);
816 return xdr_ressize_check(rqstp, p);
819 /* COMMIT */
821 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
822 struct nfsd3_commitres *resp)
824 p = encode_wcc_data(rqstp, p, &resp->fh);
825 /* Write verifier */
826 if (resp->status == 0) {
827 *p++ = htonl(nfssvc_boot.tv_sec);
828 *p++ = htonl(nfssvc_boot.tv_usec);
830 return xdr_ressize_check(rqstp, p);
834 * XDR release functions
837 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
838 struct nfsd3_attrstat *resp)
840 fh_put(&resp->fh);
841 return 1;
845 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
846 struct nfsd3_fhandle_pair *resp)
848 fh_put(&resp->fh1);
849 fh_put(&resp->fh2);
850 return 1;