1
2
3
4
5
6
7
8
9#include <linux/types.h>
10#include <linux/time.h>
11#include <linux/nfs3.h>
12#include <linux/list.h>
13#include <linux/spinlock.h>
14#include <linux/dcache.h>
15#include <linux/namei.h>
16
17#include <linux/sunrpc/xdr.h>
18#include <linux/sunrpc/svc.h>
19#include <linux/nfsd/nfsd.h>
20#include <linux/nfsd/xdr3.h>
21
22#define NFSDDBG_FACILITY NFSDDBG_XDR
23
24#ifdef NFSD_OPTIMIZE_SPACE
25# define inline
26#endif
27
28
29
30
31
32static u32 nfs3_ftypes[] = {
33 NF3NON, NF3FIFO, NF3CHR, NF3BAD,
34 NF3DIR, NF3BAD, NF3BLK, NF3BAD,
35 NF3REG, NF3BAD, NF3LNK, NF3BAD,
36 NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
37};
38
39
40
41
42static inline u32 *
43encode_time3(u32 *p, time_t secs)
44{
45 *p++ = htonl((u32) secs); *p++ = 0;
46 return p;
47}
48
49static inline u32 *
50decode_time3(u32 *p, time_t *secp)
51{
52 *secp = ntohl(*p++);
53 return p + 1;
54}
55
56static inline u32 *
57decode_fh(u32 *p, struct svc_fh *fhp)
58{
59 int size;
60 fh_init(fhp, NFS3_FHSIZE);
61 size = ntohl(*p++);
62 if (size > NFS3_FHSIZE)
63 return NULL;
64
65 memcpy(&fhp->fh_handle.fh_base, p, size);
66 fhp->fh_handle.fh_size = size;
67 return p + XDR_QUADLEN(size);
68}
69
70static inline u32 *
71encode_fh(u32 *p, struct svc_fh *fhp)
72{
73 int size = fhp->fh_handle.fh_size;
74 *p++ = htonl(size);
75 if (size) p[XDR_QUADLEN(size)-1]=0;
76 memcpy(p, &fhp->fh_handle.fh_base, size);
77 return p + XDR_QUADLEN(size);
78}
79
80
81
82
83
84static inline u32 *
85decode_filename(u32 *p, char **namp, int *lenp)
86{
87 char *name;
88 int i;
89
90 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
91 for (i = 0, name = *namp; i < *lenp; i++, name++) {
92 if (*name == '\0' || *name == '/')
93 return NULL;
94 }
95 }
96
97 return p;
98}
99
100static inline u32 *
101decode_pathname(u32 *p, char **namp, int *lenp)
102{
103 char *name;
104 int i;
105
106 if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
107 for (i = 0, name = *namp; i < *lenp; i++, name++) {
108 if (*name == '\0')
109 return NULL;
110 }
111 }
112
113 return p;
114}
115
116static inline u32 *
117decode_sattr3(u32 *p, struct iattr *iap)
118{
119 u32 tmp;
120
121 iap->ia_valid = 0;
122
123 if (*p++) {
124 iap->ia_valid |= ATTR_MODE;
125 iap->ia_mode = ntohl(*p++);
126 }
127 if (*p++) {
128 iap->ia_valid |= ATTR_UID;
129 iap->ia_uid = ntohl(*p++);
130 }
131 if (*p++) {
132 iap->ia_valid |= ATTR_GID;
133 iap->ia_gid = ntohl(*p++);
134 }
135 if (*p++) {
136 u64 newsize;
137
138 iap->ia_valid |= ATTR_SIZE;
139 p = xdr_decode_hyper(p, &newsize);
140 if (newsize <= NFS_OFFSET_MAX)
141 iap->ia_size = newsize;
142 else
143 iap->ia_size = NFS_OFFSET_MAX;
144 }
145 if ((tmp = ntohl(*p++)) == 1) {
146 iap->ia_valid |= ATTR_ATIME;
147 } else if (tmp == 2) {
148 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
149 iap->ia_atime = ntohl(*p++), p++;
150 }
151 if ((tmp = ntohl(*p++)) == 1) {
152 iap->ia_valid |= ATTR_MTIME;
153 } else if (tmp == 2) {
154 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
155 iap->ia_mtime = ntohl(*p++), p++;
156 }
157 return p;
158}
159
160static inline u32 *
161encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
162{
163 struct vfsmount *mnt = fhp->fh_export->ex_mnt;
164 struct dentry *dentry = fhp->fh_dentry;
165 struct kstat stat;
166
167 vfs_getattr(mnt, dentry, &stat);
168
169 *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
170 *p++ = htonl((u32) stat.mode);
171 *p++ = htonl((u32) stat.nlink);
172 *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
173 *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
174 if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
175 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
176 } else {
177 p = xdr_encode_hyper(p, (u64) stat.size);
178 }
179 p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9);
180 *p++ = htonl((u32) MAJOR(stat.rdev));
181 *p++ = htonl((u32) MINOR(stat.rdev));
182 if (rqstp->rq_reffh->fh_version == 1
183 && rqstp->rq_reffh->fh_fsid_type == 1
184 && (fhp->fh_export->ex_flags & NFSEXP_FSID))
185 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
186 else
187 p = xdr_encode_hyper(p, (u64) stat.dev);
188 p = xdr_encode_hyper(p, (u64) stat.ino);
189 p = encode_time3(p, stat.atime);
190 p = encode_time3(p, lease_get_mtime(dentry->d_inode));
191 p = encode_time3(p, stat.ctime);
192
193 return p;
194}
195
196static inline u32 *
197encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
198{
199 struct inode *inode = fhp->fh_dentry->d_inode;
200
201
202 *p++ = xdr_one;
203
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);
213 }
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 if (rqstp->rq_reffh->fh_version == 1
218 && rqstp->rq_reffh->fh_fsid_type == 1
219 && (fhp->fh_export->ex_flags & NFSEXP_FSID))
220 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
221 else
222 p = xdr_encode_hyper(p, (u64) inode->i_dev);
223 p = xdr_encode_hyper(p, (u64) inode->i_ino);
224 p = encode_time3(p, fhp->fh_post_atime);
225 p = encode_time3(p, fhp->fh_post_mtime);
226 p = encode_time3(p, fhp->fh_post_ctime);
227
228 return p;
229}
230
231
232
233
234
235
236static u32 *
237encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
238{
239 struct dentry *dentry = fhp->fh_dentry;
240 if (dentry && dentry->d_inode != NULL) {
241 *p++ = xdr_one;
242 return encode_fattr3(rqstp, p, fhp);
243 }
244 *p++ = xdr_zero;
245 return p;
246}
247
248
249
250
251static u32 *
252encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
253{
254 struct dentry *dentry = fhp->fh_dentry;
255
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;
264 }
265 return encode_saved_post_attr(rqstp, p, fhp);
266 }
267
268 *p++ = xdr_zero;
269 return encode_post_op_attr(rqstp, p, fhp);
270}
271
272
273
274
275static inline int
276xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
277{
278 struct svc_buf *buf = &rqstp->rq_argbuf;
279
280 return p - buf->base <= buf->buflen;
281}
282
283static inline int
284xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
285{
286 struct svc_buf *buf = &rqstp->rq_resbuf;
287
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);
292}
293
294
295
296
297int
298nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
299{
300 if (!(p = decode_fh(p, fhp)))
301 return 0;
302 return xdr_argsize_check(rqstp, p);
303}
304
305int
306nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
307 struct nfsd3_sattrargs *args)
308{
309 if (!(p = decode_fh(p, &args->fh))
310 || !(p = decode_sattr3(p, &args->attrs)))
311 return 0;
312
313 if ((args->check_guard = ntohl(*p++)) != 0)
314 p = decode_time3(p, &args->guardtime);
315
316 return xdr_argsize_check(rqstp, p);
317}
318
319int
320nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
321 struct nfsd3_diropargs *args)
322{
323 if (!(p = decode_fh(p, &args->fh))
324 || !(p = decode_filename(p, &args->name, &args->len)))
325 return 0;
326
327 return xdr_argsize_check(rqstp, p);
328}
329
330int
331nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
332 struct nfsd3_accessargs *args)
333{
334 if (!(p = decode_fh(p, &args->fh)))
335 return 0;
336 args->access = ntohl(*p++);
337
338 return xdr_argsize_check(rqstp, p);
339}
340
341int
342nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
343 struct nfsd3_readargs *args)
344{
345 if (!(p = decode_fh(p, &args->fh))
346 || !(p = xdr_decode_hyper(p, &args->offset)))
347 return 0;
348
349 args->count = ntohl(*p++);
350 return xdr_argsize_check(rqstp, p);
351}
352
353int
354nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
355 struct nfsd3_writeargs *args)
356{
357 if (!(p = decode_fh(p, &args->fh))
358 || !(p = xdr_decode_hyper(p, &args->offset)))
359 return 0;
360
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);
366
367 return xdr_argsize_check(rqstp, p);
368}
369
370int
371nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
372 struct nfsd3_createargs *args)
373{
374 if (!(p = decode_fh(p, &args->fh))
375 || !(p = decode_filename(p, &args->name, &args->len)))
376 return 0;
377
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;
390 }
391
392 return xdr_argsize_check(rqstp, p);
393}
394int
395nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
396 struct nfsd3_createargs *args)
397{
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;
402
403 return xdr_argsize_check(rqstp, p);
404}
405
406int
407nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
408 struct nfsd3_symlinkargs *args)
409{
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;
415
416 return xdr_argsize_check(rqstp, p);
417}
418
419int
420nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
421 struct nfsd3_mknodargs *args)
422{
423 if (!(p = decode_fh(p, &args->fh))
424 || !(p = decode_filename(p, &args->name, &args->len)))
425 return 0;
426
427 args->ftype = ntohl(*p++);
428
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;
433 }
434
435 if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
436 args->major = ntohl(*p++);
437 args->minor = ntohl(*p++);
438 }
439
440 return xdr_argsize_check(rqstp, p);
441}
442
443int
444nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
445 struct nfsd3_renameargs *args)
446{
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;
452
453 return xdr_argsize_check(rqstp, p);
454}
455
456int
457nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
458 struct nfsd3_linkargs *args)
459{
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;
464
465 return xdr_argsize_check(rqstp, p);
466}
467
468int
469nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
470 struct nfsd3_readdirargs *args)
471{
472 if (!(p = decode_fh(p, &args->fh)))
473 return 0;
474 p = xdr_decode_hyper(p, &args->cookie);
475 args->verf = p; p += 2;
476 args->dircount = ~0;
477 args->count = ntohl(*p++);
478
479 return xdr_argsize_check(rqstp, p);
480}
481
482int
483nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
484 struct nfsd3_readdirargs *args)
485{
486 if (!(p = decode_fh(p, &args->fh)))
487 return 0;
488 p = xdr_decode_hyper(p, &args->cookie);
489 args->verf = p; p += 2;
490 args->dircount = ntohl(*p++);
491 args->count = ntohl(*p++);
492
493 return xdr_argsize_check(rqstp, p);
494}
495
496int
497nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
498 struct nfsd3_commitargs *args)
499{
500 if (!(p = decode_fh(p, &args->fh)))
501 return 0;
502 p = xdr_decode_hyper(p, &args->offset);
503 args->count = ntohl(*p++);
504
505 return xdr_argsize_check(rqstp, p);
506}
507
508
509
510
511
512
513
514
515int
516nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
517{
518 return xdr_ressize_check(rqstp, p);
519}
520
521
522int
523nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
524 struct nfsd3_attrstat *resp)
525{
526 if (resp->status == 0)
527 p = encode_fattr3(rqstp, p, &resp->fh);
528 return xdr_ressize_check(rqstp, p);
529}
530
531
532int
533nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
534 struct nfsd3_attrstat *resp)
535{
536 p = encode_wcc_data(rqstp, p, &resp->fh);
537 return xdr_ressize_check(rqstp, p);
538}
539
540
541int
542nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
543 struct nfsd3_diropres *resp)
544{
545 if (resp->status == 0) {
546 p = encode_fh(p, &resp->fh);
547 p = encode_post_op_attr(rqstp, p, &resp->fh);
548 }
549 p = encode_post_op_attr(rqstp, p, &resp->dirfh);
550 return xdr_ressize_check(rqstp, p);
551}
552
553
554int
555nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
556 struct nfsd3_accessres *resp)
557{
558 p = encode_post_op_attr(rqstp, p, &resp->fh);
559 if (resp->status == 0)
560 *p++ = htonl(resp->access);
561 return xdr_ressize_check(rqstp, p);
562}
563
564
565int
566nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
567 struct nfsd3_readlinkres *resp)
568{
569 p = encode_post_op_attr(rqstp, p, &resp->fh);
570 if (resp->status == 0) {
571 *p++ = htonl(resp->len);
572 p += XDR_QUADLEN(resp->len);
573 }
574 return xdr_ressize_check(rqstp, p);
575}
576
577
578int
579nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
580 struct nfsd3_readres *resp)
581{
582 p = encode_post_op_attr(rqstp, p, &resp->fh);
583 if (resp->status == 0) {
584 *p++ = htonl(resp->count);
585 *p++ = htonl(resp->eof);
586 *p++ = htonl(resp->count);
587 p += XDR_QUADLEN(resp->count);
588 }
589 return xdr_ressize_check(rqstp, p);
590}
591
592
593int
594nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
595 struct nfsd3_writeres *resp)
596{
597 p = encode_wcc_data(rqstp, p, &resp->fh);
598 if (resp->status == 0) {
599 *p++ = htonl(resp->count);
600 *p++ = htonl(resp->committed);
601 *p++ = htonl(nfssvc_boot.tv_sec);
602 *p++ = htonl(nfssvc_boot.tv_usec);
603 }
604 return xdr_ressize_check(rqstp, p);
605}
606
607
608int
609nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
610 struct nfsd3_diropres *resp)
611{
612 if (resp->status == 0) {
613 *p++ = xdr_one;
614 p = encode_fh(p, &resp->fh);
615 p = encode_post_op_attr(rqstp, p, &resp->fh);
616 }
617 p = encode_wcc_data(rqstp, p, &resp->dirfh);
618 return xdr_ressize_check(rqstp, p);
619}
620
621
622int
623nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
624 struct nfsd3_renameres *resp)
625{
626 p = encode_wcc_data(rqstp, p, &resp->ffh);
627 p = encode_wcc_data(rqstp, p, &resp->tfh);
628 return xdr_ressize_check(rqstp, p);
629}
630
631
632int
633nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
634 struct nfsd3_linkres *resp)
635{
636 p = encode_post_op_attr(rqstp, p, &resp->fh);
637 p = encode_wcc_data(rqstp, p, &resp->tfh);
638 return xdr_ressize_check(rqstp, p);
639}
640
641
642int
643nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
644 struct nfsd3_readdirres *resp)
645{
646 p = encode_post_op_attr(rqstp, p, &resp->fh);
647 if (resp->status == 0) {
648
649 memcpy(p, resp->verf, 8); p += 2;
650 p += XDR_QUADLEN(resp->count);
651 }
652
653 return xdr_ressize_check(rqstp, p);
654}
655
656
657
658
659
660
661
662
663
664
665
666#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
667#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
668static int
669encode_entry(struct readdir_cd *cd, const char *name,
670 int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
671{
672 u32 *p = cd->buffer;
673 int buflen, slen, elen;
674
675 if (cd->offset)
676 xdr_encode_hyper(cd->offset, (u64) offset);
677
678
679
680 if (name == 0)
681 return 0;
682
683
684
685
686
687
688
689 if (namlen > NFS3_MAXNAMLEN)
690 namlen = NFS3_MAXNAMLEN;
691
692 slen = XDR_QUADLEN(namlen);
693 elen = slen + NFS3_ENTRY_BAGGAGE
694 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
695 if ((buflen = cd->buflen - elen) < 0) {
696 cd->eob = 1;
697 return -EINVAL;
698 }
699 *p++ = xdr_one;
700 p = xdr_encode_hyper(p, ino);
701 p = xdr_encode_array(p, name, namlen);
702
703 cd->offset = p;
704 p = xdr_encode_hyper(p, NFS_OFFSET_MAX);
705
706
707 if (plus) {
708 struct svc_fh fh;
709 struct svc_export *exp;
710 struct dentry *dparent, *dchild;
711
712 dparent = cd->dirfh->fh_dentry;
713 exp = cd->dirfh->fh_export;
714
715 fh_init(&fh, NFS3_FHSIZE);
716 if (isdotent(name, namlen)) {
717 if (namlen == 2) {
718 read_lock(&dparent_lock);
719 dchild = dget(dparent->d_parent);
720 read_unlock(&dparent_lock);
721 } else
722 dchild = dget(dparent);
723 } else
724 dchild = lookup_one_len(name, dparent,namlen);
725 if (IS_ERR(dchild))
726 goto noexec;
727 if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
728 goto noexec;
729 p = encode_post_op_attr(cd->rqstp, p, &fh);
730 *p++ = xdr_one;
731 p = encode_fh(p, &fh);
732 fh_put(&fh);
733 }
734
735out:
736 cd->buflen = buflen;
737 cd->buffer = p;
738 return 0;
739
740noexec:
741 *p++ = 0;
742 *p++ = 0;
743 goto out;
744}
745
746int
747nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
748 int namlen, loff_t offset, ino_t ino, unsigned int d_type)
749{
750 return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
751}
752
753int
754nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
755 int namlen, loff_t offset, ino_t ino, unsigned int d_type)
756{
757 return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
758}
759
760
761int
762nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
763 struct nfsd3_fsstatres *resp)
764{
765 struct statfs *s = &resp->stats;
766 u64 bs = s->f_bsize;
767
768 *p++ = xdr_zero;
769
770 if (resp->status == 0) {
771 p = xdr_encode_hyper(p, bs * s->f_blocks);
772 p = xdr_encode_hyper(p, bs * s->f_bfree);
773 p = xdr_encode_hyper(p, bs * s->f_bavail);
774 p = xdr_encode_hyper(p, s->f_files);
775 p = xdr_encode_hyper(p, s->f_ffree);
776 p = xdr_encode_hyper(p, s->f_ffree);
777 *p++ = htonl(resp->invarsec);
778 }
779 return xdr_ressize_check(rqstp, p);
780}
781
782
783int
784nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
785 struct nfsd3_fsinfores *resp)
786{
787 *p++ = xdr_zero;
788
789 if (resp->status == 0) {
790 *p++ = htonl(resp->f_rtmax);
791 *p++ = htonl(resp->f_rtpref);
792 *p++ = htonl(resp->f_rtmult);
793 *p++ = htonl(resp->f_wtmax);
794 *p++ = htonl(resp->f_wtpref);
795 *p++ = htonl(resp->f_wtmult);
796 *p++ = htonl(resp->f_dtpref);
797 p = xdr_encode_hyper(p, resp->f_maxfilesize);
798 *p++ = xdr_one;
799 *p++ = xdr_zero;
800 *p++ = htonl(resp->f_properties);
801 }
802
803 return xdr_ressize_check(rqstp, p);
804}
805
806
807int
808nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
809 struct nfsd3_pathconfres *resp)
810{
811 *p++ = xdr_zero;
812
813 if (resp->status == 0) {
814 *p++ = htonl(resp->p_link_max);
815 *p++ = htonl(resp->p_name_max);
816 *p++ = htonl(resp->p_no_trunc);
817 *p++ = htonl(resp->p_chown_restricted);
818 *p++ = htonl(resp->p_case_insensitive);
819 *p++ = htonl(resp->p_case_preserving);
820 }
821
822 return xdr_ressize_check(rqstp, p);
823}
824
825
826int
827nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
828 struct nfsd3_commitres *resp)
829{
830 p = encode_wcc_data(rqstp, p, &resp->fh);
831
832 if (resp->status == 0) {
833 *p++ = htonl(nfssvc_boot.tv_sec);
834 *p++ = htonl(nfssvc_boot.tv_usec);
835 }
836 return xdr_ressize_check(rqstp, p);
837}
838
839
840
841
842int
843nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
844 struct nfsd3_attrstat *resp)
845{
846 fh_put(&resp->fh);
847 return 1;
848}
849
850int
851nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
852 struct nfsd3_fhandle_pair *resp)
853{
854 fh_put(&resp->fh1);
855 fh_put(&resp->fh2);
856 return 1;
857}
858