Linux-2.4.0-test2
[davej-history.git] / fs / nfsd / nfs3xdr.c
blob948566a6e91bcfdee32afd9d5ae3ccf9f3199cb0
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 dec64(u32 *p, u64 *valp)
41 *valp = ((u64) ntohl(*p++)) << 32;
42 *valp |= ntohl(*p++);
43 return p;
46 static inline u32 *
47 encode_time3(u32 *p, time_t secs)
49 *p++ = htonl((u32) secs); *p++ = 0;
50 return p;
53 static inline u32 *
54 decode_time3(u32 *p, time_t *secp)
56 *secp = ntohl(*p++);
57 return p + 1;
60 static inline u32 *
61 decode_fh(u32 *p, struct svc_fh *fhp)
63 int size;
64 fh_init(fhp, NFS3_FHSIZE);
65 size = ntohl(*p++);
66 if (size > NFS3_FHSIZE)
67 return NULL;
69 memcpy(&fhp->fh_handle.fh_base, p, size);
70 fhp->fh_handle.fh_size = size;
71 return p + XDR_QUADLEN(size);
74 static inline u32 *
75 encode_fh(u32 *p, struct svc_fh *fhp)
77 int size = fhp->fh_handle.fh_size;
78 *p++ = htonl(size);
79 if (size) p[XDR_QUADLEN(size)-1]=0;
80 memcpy(p, &fhp->fh_handle.fh_base, size);
81 return p + XDR_QUADLEN(size);
85 * Decode a file name and make sure that the path contains
86 * no slashes or null bytes.
88 static inline u32 *
89 decode_filename(u32 *p, char **namp, int *lenp)
91 char *name;
92 int i;
94 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
95 for (i = 0, name = *namp; i < *lenp; i++, name++) {
96 if (*name == '\0' || *name == '/')
97 return NULL;
99 *name = '\0';
102 return p;
105 static inline u32 *
106 decode_pathname(u32 *p, char **namp, int *lenp)
108 char *name;
109 int i;
111 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
112 for (i = 0, name = *namp; i < *lenp; i++, name++) {
113 if (*name == '\0')
114 return NULL;
116 *name = '\0';
119 return p;
122 static inline u32 *
123 decode_sattr3(u32 *p, struct iattr *iap)
125 u32 tmp;
127 iap->ia_valid = 0;
129 if (*p++) {
130 iap->ia_valid |= ATTR_MODE;
131 iap->ia_mode = ntohl(*p++);
133 if (*p++) {
134 iap->ia_valid |= ATTR_UID;
135 iap->ia_uid = ntohl(*p++);
137 if (*p++) {
138 iap->ia_valid |= ATTR_GID;
139 iap->ia_gid = ntohl(*p++);
141 if (*p++) {
142 u64 newsize;
144 iap->ia_valid |= ATTR_SIZE;
145 p = dec64(p, &newsize);
146 if (newsize <= NFS_OFFSET_MAX)
147 iap->ia_size = (u32) newsize;
148 else
149 iap->ia_size = ~(size_t) 0;
151 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
152 iap->ia_valid |= ATTR_ATIME;
153 } else if (tmp == 2) { /* set to client time */
154 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
155 iap->ia_atime = ntohl(*p++), p++;
157 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
158 iap->ia_valid |= ATTR_MTIME;
159 } else if (tmp == 2) { /* set to client time */
160 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
161 iap->ia_mtime = ntohl(*p++), p++;
163 return p;
166 static inline u32 *
167 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
169 struct inode *inode = dentry->d_inode;
171 if (!inode) {
172 printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
173 return NULL;
176 *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
177 *p++ = htonl((u32) inode->i_mode);
178 *p++ = htonl((u32) inode->i_nlink);
179 *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
180 *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
181 if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
182 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
183 } else {
184 p = xdr_encode_hyper(p, (u64) inode->i_size);
186 if (inode->i_blksize == 0 && inode->i_blocks == 0)
187 /* Minix file system(?) i_size is (hopefully) close enough */
188 p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
189 else
190 p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
191 *p++ = htonl((u32) MAJOR(inode->i_rdev));
192 *p++ = htonl((u32) MINOR(inode->i_rdev));
193 p = xdr_encode_hyper(p, (u64) inode->i_dev);
194 p = xdr_encode_hyper(p, (u64) inode->i_ino);
195 p = encode_time3(p, inode->i_atime);
196 p = encode_time3(p, inode->i_mtime);
197 p = encode_time3(p, inode->i_ctime);
199 return p;
202 static inline u32 *
203 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
205 struct inode *inode = fhp->fh_dentry->d_inode;
207 /* Attributes to follow */
208 *p++ = xdr_one;
210 *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
211 *p++ = htonl((u32) fhp->fh_post_mode);
212 *p++ = htonl((u32) fhp->fh_post_nlink);
213 *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
214 *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
215 if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
216 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
217 } else {
218 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
220 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
221 *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
222 *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
223 p = xdr_encode_hyper(p, (u64) inode->i_dev);
224 p = xdr_encode_hyper(p, (u64) inode->i_ino);
225 p = encode_time3(p, fhp->fh_post_atime);
226 p = encode_time3(p, fhp->fh_post_mtime);
227 p = encode_time3(p, fhp->fh_post_ctime);
229 return p;
233 * Encode post-operation attributes.
234 * The inode may be NULL if the call failed because of a stale file
235 * handle. In this case, no attributes are returned.
237 static u32 *
238 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
240 if (dentry && dentry->d_inode != NULL) {
241 *p++ = xdr_one; /* attributes follow */
242 return encode_fattr3(rqstp, p, dentry);
244 *p++ = xdr_zero;
245 return p;
249 * Enocde weak cache consistency data
251 static u32 *
252 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
254 struct dentry *dentry = fhp->fh_dentry;
256 if (dentry && dentry->d_inode && fhp->fh_post_saved) {
257 if (fhp->fh_pre_saved) {
258 *p++ = xdr_one;
259 p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
260 p = encode_time3(p, fhp->fh_pre_mtime);
261 p = encode_time3(p, fhp->fh_pre_ctime);
262 } else {
263 *p++ = xdr_zero;
265 return encode_saved_post_attr(rqstp, p, fhp);
267 /* no pre- or post-attrs */
268 *p++ = xdr_zero;
269 return encode_post_op_attr(rqstp, p, dentry);
273 * Check buffer bounds after decoding arguments
275 static inline int
276 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
278 struct svc_buf *buf = &rqstp->rq_argbuf;
280 return p - buf->base <= buf->buflen;
283 static inline int
284 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
286 struct svc_buf *buf = &rqstp->rq_resbuf;
288 buf->len = p - buf->base;
289 dprintk("nfsd: ressize_check p %p base %p len %d\n",
290 p, buf->base, buf->buflen);
291 return (buf->len <= buf->buflen);
295 * XDR decode functions
298 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
300 if (!(p = decode_fh(p, fhp)))
301 return 0;
302 return xdr_argsize_check(rqstp, p);
306 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
307 struct nfsd3_sattrargs *args)
309 if (!(p = decode_fh(p, &args->fh))
310 || !(p = decode_sattr3(p, &args->attrs)))
311 return 0;
313 if ((args->check_guard = ntohl(*p++)) != 0)
314 p = decode_time3(p, &args->guardtime);
316 return xdr_argsize_check(rqstp, p);
320 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
321 struct nfsd3_diropargs *args)
323 if (!(p = decode_fh(p, &args->fh))
324 || !(p = decode_filename(p, &args->name, &args->len)))
325 return 0;
327 return xdr_argsize_check(rqstp, p);
331 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
332 struct nfsd3_accessargs *args)
334 if (!(p = decode_fh(p, &args->fh)))
335 return 0;
336 args->access = ntohl(*p++);
338 return xdr_argsize_check(rqstp, p);
342 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
343 struct nfsd3_readargs *args)
345 if (!(p = decode_fh(p, &args->fh))
346 || !(p = dec64(p, &args->offset)))
347 return 0;
349 args->count = ntohl(*p++);
350 return xdr_argsize_check(rqstp, p);
354 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
355 struct nfsd3_writeargs *args)
357 if (!(p = decode_fh(p, &args->fh))
358 || !(p = dec64(p, &args->offset)))
359 return 0;
361 args->count = ntohl(*p++);
362 args->stable = ntohl(*p++);
363 args->len = ntohl(*p++);
364 args->data = (char *) p;
365 p += XDR_QUADLEN(args->len);
367 return xdr_argsize_check(rqstp, p);
371 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
372 struct nfsd3_createargs *args)
374 if (!(p = decode_fh(p, &args->fh))
375 || !(p = decode_filename(p, &args->name, &args->len)))
376 return 0;
378 switch (args->createmode = ntohl(*p++)) {
379 case NFS3_CREATE_UNCHECKED:
380 case NFS3_CREATE_GUARDED:
381 if (!(p = decode_sattr3(p, &args->attrs)))
382 return 0;
383 break;
384 case NFS3_CREATE_EXCLUSIVE:
385 args->verf = p;
386 p += 2;
387 break;
388 default:
389 return 0;
392 return xdr_argsize_check(rqstp, p);
395 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
396 struct nfsd3_createargs *args)
398 if (!(p = decode_fh(p, &args->fh))
399 || !(p = decode_filename(p, &args->name, &args->len))
400 || !(p = decode_sattr3(p, &args->attrs)))
401 return 0;
403 return xdr_argsize_check(rqstp, p);
407 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
408 struct nfsd3_symlinkargs *args)
410 if (!(p = decode_fh(p, &args->ffh))
411 || !(p = decode_filename(p, &args->fname, &args->flen))
412 || !(p = decode_sattr3(p, &args->attrs))
413 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
414 return 0;
416 return xdr_argsize_check(rqstp, p);
420 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
421 struct nfsd3_mknodargs *args)
423 if (!(p = decode_fh(p, &args->fh))
424 || !(p = decode_filename(p, &args->name, &args->len)))
425 return 0;
427 args->ftype = ntohl(*p++);
429 if (args->ftype == NF3BLK || args->ftype == NF3CHR
430 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
431 if (!(p = decode_sattr3(p, &args->attrs)))
432 return 0;
435 if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
436 args->major = ntohl(*p++);
437 args->minor = ntohl(*p++);
440 return xdr_argsize_check(rqstp, p);
444 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
445 struct nfsd3_renameargs *args)
447 if (!(p = decode_fh(p, &args->ffh))
448 || !(p = decode_filename(p, &args->fname, &args->flen))
449 || !(p = decode_fh(p, &args->tfh))
450 || !(p = decode_filename(p, &args->tname, &args->tlen)))
451 return 0;
453 return xdr_argsize_check(rqstp, p);
457 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
458 struct nfsd3_linkargs *args)
460 if (!(p = decode_fh(p, &args->ffh))
461 || !(p = decode_fh(p, &args->tfh))
462 || !(p = decode_filename(p, &args->tname, &args->tlen)))
463 return 0;
465 return xdr_argsize_check(rqstp, p);
469 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
470 struct nfsd3_readdirargs *args)
472 if (!(p = decode_fh(p, &args->fh)))
473 return 0;
474 p = dec64(p, &args->cookie);
475 args->verf = p; p += 2;
476 args->dircount = ~0;
477 args->count = ntohl(*p++);
479 return xdr_argsize_check(rqstp, p);
483 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
484 struct nfsd3_readdirargs *args)
486 if (!(p = decode_fh(p, &args->fh)))
487 return 0;
488 p = dec64(p, &args->cookie);
489 args->verf = p; p += 2;
490 args->dircount = ntohl(*p++);
491 args->count = ntohl(*p++);
493 return xdr_argsize_check(rqstp, p);
497 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
498 struct nfsd3_commitargs *args)
500 if (!(p = decode_fh(p, &args->fh)))
501 return 0;
502 p = dec64(p, &args->offset);
503 args->count = ntohl(*p++);
505 return xdr_argsize_check(rqstp, p);
509 * XDR encode functions
512 * There must be an encoding function for void results so svc_process
513 * will work properly.
516 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
518 return xdr_ressize_check(rqstp, p);
521 /* GETATTR */
523 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
524 struct nfsd3_attrstat *resp)
526 if (resp->status == 0
527 && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
528 return 0;
529 return xdr_ressize_check(rqstp, p);
532 /* SETATTR, REMOVE, RMDIR */
534 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
535 struct nfsd3_attrstat *resp)
537 if (!(p = encode_wcc_data(rqstp, p, &resp->fh)))
538 return 0;
539 return xdr_ressize_check(rqstp, p);
542 /* LOOKUP */
544 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
545 struct nfsd3_diropres *resp)
547 if (resp->status == 0) {
548 p = encode_fh(p, &resp->fh);
549 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
551 p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
552 return xdr_ressize_check(rqstp, p);
555 /* ACCESS */
557 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
558 struct nfsd3_accessres *resp)
560 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
561 if (resp->status == 0)
562 *p++ = htonl(resp->access);
563 return xdr_ressize_check(rqstp, p);
566 /* READLINK */
568 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
569 struct nfsd3_readlinkres *resp)
571 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
572 if (resp->status == 0) {
573 *p++ = htonl(resp->len);
574 p += XDR_QUADLEN(resp->len);
576 return xdr_ressize_check(rqstp, p);
579 /* READ */
581 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
582 struct nfsd3_readres *resp)
584 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
585 if (resp->status == 0) {
586 *p++ = htonl(resp->count);
587 *p++ = htonl(resp->eof);
588 *p++ = htonl(resp->count); /* xdr opaque count */
589 p += XDR_QUADLEN(resp->count);
591 return xdr_ressize_check(rqstp, p);
594 /* WRITE */
596 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
597 struct nfsd3_writeres *resp)
599 p = encode_wcc_data(rqstp, p, &resp->fh);
600 if (resp->status == 0) {
601 *p++ = htonl(resp->count);
602 *p++ = htonl(resp->committed);
603 *p++ = htonl(nfssvc_boot.tv_sec);
604 *p++ = htonl(nfssvc_boot.tv_usec);
606 return xdr_ressize_check(rqstp, p);
609 /* CREATE, MKDIR, SYMLINK, MKNOD */
611 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
612 struct nfsd3_diropres *resp)
614 if (resp->status == 0) {
615 *p++ = xdr_one;
616 p = encode_fh(p, &resp->fh);
617 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
619 p = encode_wcc_data(rqstp, p, &resp->dirfh);
620 return xdr_ressize_check(rqstp, p);
623 /* RENAME */
625 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
626 struct nfsd3_renameres *resp)
628 p = encode_wcc_data(rqstp, p, &resp->ffh);
629 p = encode_wcc_data(rqstp, p, &resp->tfh);
630 return xdr_ressize_check(rqstp, p);
633 /* LINK */
635 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
636 struct nfsd3_linkres *resp)
638 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
639 p = encode_wcc_data(rqstp, p, &resp->tfh);
640 return xdr_ressize_check(rqstp, p);
643 /* READDIR */
645 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
646 struct nfsd3_readdirres *resp)
648 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
649 if (resp->status == 0) {
650 /* stupid readdir cookie */
651 memcpy(p, resp->verf, 8); p += 2;
652 p += XDR_QUADLEN(resp->count);
655 return xdr_ressize_check(rqstp, p);
659 * Encode a directory entry. This one works for both normal readdir
660 * and readdirplus.
661 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
662 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
664 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
665 * file handle.
668 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
669 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
670 static int
671 encode_entry(struct readdir_cd *cd, const char *name,
672 int namlen, off_t offset, ino_t ino, int plus)
674 u32 *p = cd->buffer;
675 int buflen, slen, elen;
677 if (cd->offset)
678 xdr_encode_hyper(cd->offset, (u64) offset);
680 /* nfsd_readdir calls us with name == 0 when it wants us to
681 * set the last offset entry. */
682 if (name == 0)
683 return 0;
686 dprintk("encode_entry(%.*s @%ld%s)\n",
687 namlen, name, (long) offset, plus? " plus" : "");
690 /* truncate filename if too long */
691 if (namlen > NFS3_MAXNAMLEN)
692 namlen = NFS3_MAXNAMLEN;
694 slen = XDR_QUADLEN(namlen);
695 elen = slen + NFS3_ENTRY_BAGGAGE
696 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
697 if ((buflen = cd->buflen - elen) < 0) {
698 cd->eob = 1;
699 return -EINVAL;
701 *p++ = xdr_one; /* mark entry present */
702 p = xdr_encode_hyper(p, ino); /* file id */
703 p = xdr_encode_array(p, name, namlen);/* name length & name */
705 cd->offset = p; /* remember pointer */
706 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
708 /* throw in readdirplus baggage */
709 if (plus) {
710 struct svc_fh fh;
711 struct svc_export *exp;
712 struct dentry *dparent, *dchild;
714 dparent = cd->dirfh->fh_dentry;
715 exp = cd->dirfh->fh_export;
717 fh_init(&fh, NFS3_FHSIZE);
718 if (fh_verify(cd->rqstp, cd->dirfh, S_IFDIR, MAY_EXEC) != 0)
719 goto noexec;
720 if (isdotent(name, namlen)) {
721 dchild = dparent;
722 if (namlen == 2)
723 dchild = dchild->d_parent;
724 dchild = dget(dchild);
725 } else
726 dchild = lookup_one(name, dparent);
727 if (IS_ERR(dchild))
728 goto noexec;
729 if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
730 goto noexec;
731 p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
732 *p++ = xdr_one; /* yes, a file handle follows */
733 p = encode_fh(p, &fh);
734 fh_put(&fh);
737 out:
738 cd->buflen = buflen;
739 cd->buffer = p;
740 return 0;
742 noexec:
743 *p++ = 0;
744 *p++ = 0;
745 goto out;
749 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
750 int namlen, off_t offset, ino_t ino)
752 return encode_entry(cd, name, namlen, offset, ino, 0);
756 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
757 int namlen, off_t offset, ino_t ino)
759 return encode_entry(cd, name, namlen, offset, ino, 1);
762 /* FSSTAT */
764 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
765 struct nfsd3_fsstatres *resp)
767 struct statfs *s = &resp->stats;
768 u64 bs = s->f_bsize;
770 *p++ = xdr_zero; /* no post_op_attr */
772 if (resp->status == 0) {
773 p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
774 p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
775 p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
776 p = xdr_encode_hyper(p, s->f_files); /* total inodes */
777 p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
778 p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
779 *p++ = htonl(resp->invarsec); /* mean unchanged time */
781 return xdr_ressize_check(rqstp, p);
784 /* FSINFO */
786 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
787 struct nfsd3_fsinfores *resp)
789 *p++ = xdr_zero; /* no post_op_attr */
791 if (resp->status == 0) {
792 *p++ = htonl(resp->f_rtmax);
793 *p++ = htonl(resp->f_rtpref);
794 *p++ = htonl(resp->f_rtmult);
795 *p++ = htonl(resp->f_wtmax);
796 *p++ = htonl(resp->f_wtpref);
797 *p++ = htonl(resp->f_wtmult);
798 *p++ = htonl(resp->f_dtpref);
799 p = xdr_encode_hyper(p, resp->f_maxfilesize);
800 *p++ = xdr_one;
801 *p++ = xdr_zero;
802 *p++ = htonl(resp->f_properties);
805 return xdr_ressize_check(rqstp, p);
808 /* PATHCONF */
810 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
811 struct nfsd3_pathconfres *resp)
813 *p++ = xdr_zero; /* no post_op_attr */
815 if (resp->status == 0) {
816 *p++ = htonl(resp->p_link_max);
817 *p++ = htonl(resp->p_name_max);
818 *p++ = htonl(resp->p_no_trunc);
819 *p++ = htonl(resp->p_chown_restricted);
820 *p++ = htonl(resp->p_case_insensitive);
821 *p++ = htonl(resp->p_case_preserving);
824 return xdr_ressize_check(rqstp, p);
827 /* COMMIT */
829 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
830 struct nfsd3_commitres *resp)
832 p = encode_wcc_data(rqstp, p, &resp->fh);
833 /* Write verifier */
834 if (resp->status == 0) {
835 *p++ = htonl(nfssvc_boot.tv_sec);
836 *p++ = htonl(nfssvc_boot.tv_usec);
838 return xdr_ressize_check(rqstp, p);
842 * XDR release functions
845 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
846 struct nfsd3_attrstat *resp)
848 fh_put(&resp->fh);
849 return 1;
853 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
854 struct nfsd3_fhandle_pair *resp)
856 fh_put(&resp->fh1);
857 fh_put(&resp->fh2);
858 return 1;