File: /usr/src/linux/fs/nfsd/nfs3xdr.c
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
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/nfs3.h>
12
13 #include <linux/sunrpc/xdr.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/nfsd/nfsd.h>
16 #include <linux/nfsd/xdr3.h>
17
18 #define NFSDDBG_FACILITY NFSDDBG_XDR
19
20 #ifdef NFSD_OPTIMIZE_SPACE
21 # define inline
22 #endif
23
24
25 /*
26 * Mapping of S_IF* types to NFS file types
27 */
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,
33 };
34
35 /*
36 * XDR functions for basic NFS types
37 */
38 static inline u32 *
39 encode_time3(u32 *p, time_t secs)
40 {
41 *p++ = htonl((u32) secs); *p++ = 0;
42 return p;
43 }
44
45 static inline u32 *
46 decode_time3(u32 *p, time_t *secp)
47 {
48 *secp = ntohl(*p++);
49 return p + 1;
50 }
51
52 static inline u32 *
53 decode_fh(u32 *p, struct svc_fh *fhp)
54 {
55 int size;
56 fh_init(fhp, NFS3_FHSIZE);
57 size = ntohl(*p++);
58 if (size > NFS3_FHSIZE)
59 return NULL;
60
61 memcpy(&fhp->fh_handle.fh_base, p, size);
62 fhp->fh_handle.fh_size = size;
63 return p + XDR_QUADLEN(size);
64 }
65
66 static inline u32 *
67 encode_fh(u32 *p, struct svc_fh *fhp)
68 {
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);
74 }
75
76 /*
77 * Decode a file name and make sure that the path contains
78 * no slashes or null bytes.
79 */
80 static inline u32 *
81 decode_filename(u32 *p, char **namp, int *lenp)
82 {
83 char *name;
84 int i;
85
86 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
87 for (i = 0, name = *namp; i < *lenp; i++, name++) {
88 if (*name == '\0' || *name == '/')
89 return NULL;
90 }
91 }
92
93 return p;
94 }
95
96 static inline u32 *
97 decode_pathname(u32 *p, char **namp, int *lenp)
98 {
99 char *name;
100 int i;
101
102 if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
103 for (i = 0, name = *namp; i < *lenp; i++, name++) {
104 if (*name == '\0')
105 return NULL;
106 }
107 }
108
109 return p;
110 }
111
112 static inline u32 *
113 decode_sattr3(u32 *p, struct iattr *iap)
114 {
115 u32 tmp;
116
117 iap->ia_valid = 0;
118
119 if (*p++) {
120 iap->ia_valid |= ATTR_MODE;
121 iap->ia_mode = ntohl(*p++);
122 }
123 if (*p++) {
124 iap->ia_valid |= ATTR_UID;
125 iap->ia_uid = ntohl(*p++);
126 }
127 if (*p++) {
128 iap->ia_valid |= ATTR_GID;
129 iap->ia_gid = ntohl(*p++);
130 }
131 if (*p++) {
132 u64 newsize;
133
134 iap->ia_valid |= ATTR_SIZE;
135 p = xdr_decode_hyper(p, &newsize);
136 if (newsize <= NFS_OFFSET_MAX)
137 iap->ia_size = newsize;
138 else
139 iap->ia_size = NFS_OFFSET_MAX;
140 }
141 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
142 iap->ia_valid |= ATTR_ATIME;
143 } else if (tmp == 2) { /* set to client time */
144 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
145 iap->ia_atime = ntohl(*p++), p++;
146 }
147 if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
148 iap->ia_valid |= ATTR_MTIME;
149 } else if (tmp == 2) { /* set to client time */
150 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
151 iap->ia_mtime = ntohl(*p++), p++;
152 }
153 return p;
154 }
155
156 static inline u32 *
157 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
158 {
159 struct inode *inode = dentry->d_inode;
160
161 *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
162 *p++ = htonl((u32) inode->i_mode);
163 *p++ = htonl((u32) inode->i_nlink);
164 *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
165 *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
166 if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
167 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
168 } else {
169 p = xdr_encode_hyper(p, (u64) inode->i_size);
170 }
171 if (inode->i_blksize == 0 && inode->i_blocks == 0)
172 /* Minix file system(?) i_size is (hopefully) close enough */
173 p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
174 else
175 p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
176 *p++ = htonl((u32) MAJOR(inode->i_rdev));
177 *p++ = htonl((u32) MINOR(inode->i_rdev));
178 p = xdr_encode_hyper(p, (u64) inode->i_dev);
179 p = xdr_encode_hyper(p, (u64) inode->i_ino);
180 p = encode_time3(p, inode->i_atime);
181 p = encode_time3(p, lease_get_mtime(inode));
182 p = encode_time3(p, inode->i_ctime);
183
184 return p;
185 }
186
187 static inline u32 *
188 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
189 {
190 struct inode *inode = fhp->fh_dentry->d_inode;
191
192 /* Attributes to follow */
193 *p++ = xdr_one;
194
195 *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
196 *p++ = htonl((u32) fhp->fh_post_mode);
197 *p++ = htonl((u32) fhp->fh_post_nlink);
198 *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
199 *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
200 if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
201 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
202 } else {
203 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
204 }
205 p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
206 *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
207 *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
208 p = xdr_encode_hyper(p, (u64) inode->i_dev);
209 p = xdr_encode_hyper(p, (u64) inode->i_ino);
210 p = encode_time3(p, fhp->fh_post_atime);
211 p = encode_time3(p, fhp->fh_post_mtime);
212 p = encode_time3(p, fhp->fh_post_ctime);
213
214 return p;
215 }
216
217 /*
218 * Encode post-operation attributes.
219 * The inode may be NULL if the call failed because of a stale file
220 * handle. In this case, no attributes are returned.
221 */
222 static u32 *
223 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
224 {
225 if (dentry && dentry->d_inode != NULL) {
226 *p++ = xdr_one; /* attributes follow */
227 return encode_fattr3(rqstp, p, dentry);
228 }
229 *p++ = xdr_zero;
230 return p;
231 }
232
233 /*
234 * Enocde weak cache consistency data
235 */
236 static u32 *
237 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
238 {
239 struct dentry *dentry = fhp->fh_dentry;
240
241 if (dentry && dentry->d_inode && fhp->fh_post_saved) {
242 if (fhp->fh_pre_saved) {
243 *p++ = xdr_one;
244 p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
245 p = encode_time3(p, fhp->fh_pre_mtime);
246 p = encode_time3(p, fhp->fh_pre_ctime);
247 } else {
248 *p++ = xdr_zero;
249 }
250 return encode_saved_post_attr(rqstp, p, fhp);
251 }
252 /* no pre- or post-attrs */
253 *p++ = xdr_zero;
254 return encode_post_op_attr(rqstp, p, dentry);
255 }
256
257 /*
258 * Check buffer bounds after decoding arguments
259 */
260 static inline int
261 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
262 {
263 struct svc_buf *buf = &rqstp->rq_argbuf;
264
265 return p - buf->base <= buf->buflen;
266 }
267
268 static inline int
269 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
270 {
271 struct svc_buf *buf = &rqstp->rq_resbuf;
272
273 buf->len = p - buf->base;
274 dprintk("nfsd: ressize_check p %p base %p len %d\n",
275 p, buf->base, buf->buflen);
276 return (buf->len <= buf->buflen);
277 }
278
279 /*
280 * XDR decode functions
281 */
282 int
283 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
284 {
285 if (!(p = decode_fh(p, fhp)))
286 return 0;
287 return xdr_argsize_check(rqstp, p);
288 }
289
290 int
291 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
292 struct nfsd3_sattrargs *args)
293 {
294 if (!(p = decode_fh(p, &args->fh))
295 || !(p = decode_sattr3(p, &args->attrs)))
296 return 0;
297
298 if ((args->check_guard = ntohl(*p++)) != 0)
299 p = decode_time3(p, &args->guardtime);
300
301 return xdr_argsize_check(rqstp, p);
302 }
303
304 int
305 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
306 struct nfsd3_diropargs *args)
307 {
308 if (!(p = decode_fh(p, &args->fh))
309 || !(p = decode_filename(p, &args->name, &args->len)))
310 return 0;
311
312 return xdr_argsize_check(rqstp, p);
313 }
314
315 int
316 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
317 struct nfsd3_accessargs *args)
318 {
319 if (!(p = decode_fh(p, &args->fh)))
320 return 0;
321 args->access = ntohl(*p++);
322
323 return xdr_argsize_check(rqstp, p);
324 }
325
326 int
327 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
328 struct nfsd3_readargs *args)
329 {
330 if (!(p = decode_fh(p, &args->fh))
331 || !(p = xdr_decode_hyper(p, &args->offset)))
332 return 0;
333
334 args->count = ntohl(*p++);
335 return xdr_argsize_check(rqstp, p);
336 }
337
338 int
339 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
340 struct nfsd3_writeargs *args)
341 {
342 if (!(p = decode_fh(p, &args->fh))
343 || !(p = xdr_decode_hyper(p, &args->offset)))
344 return 0;
345
346 args->count = ntohl(*p++);
347 args->stable = ntohl(*p++);
348 args->len = ntohl(*p++);
349 args->data = (char *) p;
350 p += XDR_QUADLEN(args->len);
351
352 return xdr_argsize_check(rqstp, p);
353 }
354
355 int
356 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
357 struct nfsd3_createargs *args)
358 {
359 if (!(p = decode_fh(p, &args->fh))
360 || !(p = decode_filename(p, &args->name, &args->len)))
361 return 0;
362
363 switch (args->createmode = ntohl(*p++)) {
364 case NFS3_CREATE_UNCHECKED:
365 case NFS3_CREATE_GUARDED:
366 if (!(p = decode_sattr3(p, &args->attrs)))
367 return 0;
368 break;
369 case NFS3_CREATE_EXCLUSIVE:
370 args->verf = p;
371 p += 2;
372 break;
373 default:
374 return 0;
375 }
376
377 return xdr_argsize_check(rqstp, p);
378 }
379 int
380 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
381 struct nfsd3_createargs *args)
382 {
383 if (!(p = decode_fh(p, &args->fh))
384 || !(p = decode_filename(p, &args->name, &args->len))
385 || !(p = decode_sattr3(p, &args->attrs)))
386 return 0;
387
388 return xdr_argsize_check(rqstp, p);
389 }
390
391 int
392 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
393 struct nfsd3_symlinkargs *args)
394 {
395 if (!(p = decode_fh(p, &args->ffh))
396 || !(p = decode_filename(p, &args->fname, &args->flen))
397 || !(p = decode_sattr3(p, &args->attrs))
398 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
399 return 0;
400
401 return xdr_argsize_check(rqstp, p);
402 }
403
404 int
405 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
406 struct nfsd3_mknodargs *args)
407 {
408 if (!(p = decode_fh(p, &args->fh))
409 || !(p = decode_filename(p, &args->name, &args->len)))
410 return 0;
411
412 args->ftype = ntohl(*p++);
413
414 if (args->ftype == NF3BLK || args->ftype == NF3CHR
415 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
416 if (!(p = decode_sattr3(p, &args->attrs)))
417 return 0;
418 }
419
420 if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
421 args->major = ntohl(*p++);
422 args->minor = ntohl(*p++);
423 }
424
425 return xdr_argsize_check(rqstp, p);
426 }
427
428 int
429 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
430 struct nfsd3_renameargs *args)
431 {
432 if (!(p = decode_fh(p, &args->ffh))
433 || !(p = decode_filename(p, &args->fname, &args->flen))
434 || !(p = decode_fh(p, &args->tfh))
435 || !(p = decode_filename(p, &args->tname, &args->tlen)))
436 return 0;
437
438 return xdr_argsize_check(rqstp, p);
439 }
440
441 int
442 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
443 struct nfsd3_linkargs *args)
444 {
445 if (!(p = decode_fh(p, &args->ffh))
446 || !(p = decode_fh(p, &args->tfh))
447 || !(p = decode_filename(p, &args->tname, &args->tlen)))
448 return 0;
449
450 return xdr_argsize_check(rqstp, p);
451 }
452
453 int
454 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
455 struct nfsd3_readdirargs *args)
456 {
457 if (!(p = decode_fh(p, &args->fh)))
458 return 0;
459 p = xdr_decode_hyper(p, &args->cookie);
460 args->verf = p; p += 2;
461 args->dircount = ~0;
462 args->count = ntohl(*p++);
463
464 return xdr_argsize_check(rqstp, p);
465 }
466
467 int
468 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
469 struct nfsd3_readdirargs *args)
470 {
471 if (!(p = decode_fh(p, &args->fh)))
472 return 0;
473 p = xdr_decode_hyper(p, &args->cookie);
474 args->verf = p; p += 2;
475 args->dircount = ntohl(*p++);
476 args->count = ntohl(*p++);
477
478 return xdr_argsize_check(rqstp, p);
479 }
480
481 int
482 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
483 struct nfsd3_commitargs *args)
484 {
485 if (!(p = decode_fh(p, &args->fh)))
486 return 0;
487 p = xdr_decode_hyper(p, &args->offset);
488 args->count = ntohl(*p++);
489
490 return xdr_argsize_check(rqstp, p);
491 }
492
493 /*
494 * XDR encode functions
495 */
496 /*
497 * There must be an encoding function for void results so svc_process
498 * will work properly.
499 */
500 int
501 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
502 {
503 return xdr_ressize_check(rqstp, p);
504 }
505
506 /* GETATTR */
507 int
508 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
509 struct nfsd3_attrstat *resp)
510 {
511 if (resp->status == 0)
512 p = encode_fattr3(rqstp, p, resp->fh.fh_dentry);
513 return xdr_ressize_check(rqstp, p);
514 }
515
516 /* SETATTR, REMOVE, RMDIR */
517 int
518 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
519 struct nfsd3_attrstat *resp)
520 {
521 p = encode_wcc_data(rqstp, p, &resp->fh);
522 return xdr_ressize_check(rqstp, p);
523 }
524
525 /* LOOKUP */
526 int
527 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
528 struct nfsd3_diropres *resp)
529 {
530 if (resp->status == 0) {
531 p = encode_fh(p, &resp->fh);
532 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
533 }
534 p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
535 return xdr_ressize_check(rqstp, p);
536 }
537
538 /* ACCESS */
539 int
540 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
541 struct nfsd3_accessres *resp)
542 {
543 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
544 if (resp->status == 0)
545 *p++ = htonl(resp->access);
546 return xdr_ressize_check(rqstp, p);
547 }
548
549 /* READLINK */
550 int
551 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
552 struct nfsd3_readlinkres *resp)
553 {
554 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
555 if (resp->status == 0) {
556 *p++ = htonl(resp->len);
557 p += XDR_QUADLEN(resp->len);
558 }
559 return xdr_ressize_check(rqstp, p);
560 }
561
562 /* READ */
563 int
564 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
565 struct nfsd3_readres *resp)
566 {
567 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
568 if (resp->status == 0) {
569 *p++ = htonl(resp->count);
570 *p++ = htonl(resp->eof);
571 *p++ = htonl(resp->count); /* xdr opaque count */
572 p += XDR_QUADLEN(resp->count);
573 }
574 return xdr_ressize_check(rqstp, p);
575 }
576
577 /* WRITE */
578 int
579 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
580 struct nfsd3_writeres *resp)
581 {
582 p = encode_wcc_data(rqstp, p, &resp->fh);
583 if (resp->status == 0) {
584 *p++ = htonl(resp->count);
585 *p++ = htonl(resp->committed);
586 *p++ = htonl(nfssvc_boot.tv_sec);
587 *p++ = htonl(nfssvc_boot.tv_usec);
588 }
589 return xdr_ressize_check(rqstp, p);
590 }
591
592 /* CREATE, MKDIR, SYMLINK, MKNOD */
593 int
594 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
595 struct nfsd3_diropres *resp)
596 {
597 if (resp->status == 0) {
598 *p++ = xdr_one;
599 p = encode_fh(p, &resp->fh);
600 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
601 }
602 p = encode_wcc_data(rqstp, p, &resp->dirfh);
603 return xdr_ressize_check(rqstp, p);
604 }
605
606 /* RENAME */
607 int
608 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
609 struct nfsd3_renameres *resp)
610 {
611 p = encode_wcc_data(rqstp, p, &resp->ffh);
612 p = encode_wcc_data(rqstp, p, &resp->tfh);
613 return xdr_ressize_check(rqstp, p);
614 }
615
616 /* LINK */
617 int
618 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
619 struct nfsd3_linkres *resp)
620 {
621 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
622 p = encode_wcc_data(rqstp, p, &resp->tfh);
623 return xdr_ressize_check(rqstp, p);
624 }
625
626 /* READDIR */
627 int
628 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
629 struct nfsd3_readdirres *resp)
630 {
631 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
632 if (resp->status == 0) {
633 /* stupid readdir cookie */
634 memcpy(p, resp->verf, 8); p += 2;
635 p += XDR_QUADLEN(resp->count);
636 }
637
638 return xdr_ressize_check(rqstp, p);
639 }
640
641 /*
642 * Encode a directory entry. This one works for both normal readdir
643 * and readdirplus.
644 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
645 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
646 *
647 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
648 * file handle.
649 */
650
651 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
652 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
653 static int
654 encode_entry(struct readdir_cd *cd, const char *name,
655 int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
656 {
657 u32 *p = cd->buffer;
658 int buflen, slen, elen;
659
660 if (cd->offset)
661 xdr_encode_hyper(cd->offset, (u64) offset);
662
663 /* nfsd_readdir calls us with name == 0 when it wants us to
664 * set the last offset entry. */
665 if (name == 0)
666 return 0;
667
668 /*
669 dprintk("encode_entry(%.*s @%ld%s)\n",
670 namlen, name, (long) offset, plus? " plus" : "");
671 */
672
673 /* truncate filename if too long */
674 if (namlen > NFS3_MAXNAMLEN)
675 namlen = NFS3_MAXNAMLEN;
676
677 slen = XDR_QUADLEN(namlen);
678 elen = slen + NFS3_ENTRY_BAGGAGE
679 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
680 if ((buflen = cd->buflen - elen) < 0) {
681 cd->eob = 1;
682 return -EINVAL;
683 }
684 *p++ = xdr_one; /* mark entry present */
685 p = xdr_encode_hyper(p, ino); /* file id */
686 p = xdr_encode_array(p, name, namlen);/* name length & name */
687
688 cd->offset = p; /* remember pointer */
689 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
690
691 /* throw in readdirplus baggage */
692 if (plus) {
693 struct svc_fh fh;
694 struct svc_export *exp;
695 struct dentry *dparent, *dchild;
696
697 dparent = cd->dirfh->fh_dentry;
698 exp = cd->dirfh->fh_export;
699
700 fh_init(&fh, NFS3_FHSIZE);
701 if (isdotent(name, namlen)) {
702 dchild = dparent;
703 if (namlen == 2)
704 dchild = dchild->d_parent;
705 dchild = dget(dchild);
706 } else
707 dchild = lookup_one_len(name, dparent,namlen);
708 if (IS_ERR(dchild))
709 goto noexec;
710 if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
711 goto noexec;
712 p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
713 *p++ = xdr_one; /* yes, a file handle follows */
714 p = encode_fh(p, &fh);
715 fh_put(&fh);
716 }
717
718 out:
719 cd->buflen = buflen;
720 cd->buffer = p;
721 return 0;
722
723 noexec:
724 *p++ = 0;
725 *p++ = 0;
726 goto out;
727 }
728
729 int
730 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
731 int namlen, loff_t offset, ino_t ino, unsigned int d_type)
732 {
733 return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
734 }
735
736 int
737 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
738 int namlen, loff_t offset, ino_t ino, unsigned int d_type)
739 {
740 return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
741 }
742
743 /* FSSTAT */
744 int
745 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
746 struct nfsd3_fsstatres *resp)
747 {
748 struct statfs *s = &resp->stats;
749 u64 bs = s->f_bsize;
750
751 *p++ = xdr_zero; /* no post_op_attr */
752
753 if (resp->status == 0) {
754 p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
755 p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
756 p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
757 p = xdr_encode_hyper(p, s->f_files); /* total inodes */
758 p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
759 p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
760 *p++ = htonl(resp->invarsec); /* mean unchanged time */
761 }
762 return xdr_ressize_check(rqstp, p);
763 }
764
765 /* FSINFO */
766 int
767 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
768 struct nfsd3_fsinfores *resp)
769 {
770 *p++ = xdr_zero; /* no post_op_attr */
771
772 if (resp->status == 0) {
773 *p++ = htonl(resp->f_rtmax);
774 *p++ = htonl(resp->f_rtpref);
775 *p++ = htonl(resp->f_rtmult);
776 *p++ = htonl(resp->f_wtmax);
777 *p++ = htonl(resp->f_wtpref);
778 *p++ = htonl(resp->f_wtmult);
779 *p++ = htonl(resp->f_dtpref);
780 p = xdr_encode_hyper(p, resp->f_maxfilesize);
781 *p++ = xdr_one;
782 *p++ = xdr_zero;
783 *p++ = htonl(resp->f_properties);
784 }
785
786 return xdr_ressize_check(rqstp, p);
787 }
788
789 /* PATHCONF */
790 int
791 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
792 struct nfsd3_pathconfres *resp)
793 {
794 *p++ = xdr_zero; /* no post_op_attr */
795
796 if (resp->status == 0) {
797 *p++ = htonl(resp->p_link_max);
798 *p++ = htonl(resp->p_name_max);
799 *p++ = htonl(resp->p_no_trunc);
800 *p++ = htonl(resp->p_chown_restricted);
801 *p++ = htonl(resp->p_case_insensitive);
802 *p++ = htonl(resp->p_case_preserving);
803 }
804
805 return xdr_ressize_check(rqstp, p);
806 }
807
808 /* COMMIT */
809 int
810 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
811 struct nfsd3_commitres *resp)
812 {
813 p = encode_wcc_data(rqstp, p, &resp->fh);
814 /* Write verifier */
815 if (resp->status == 0) {
816 *p++ = htonl(nfssvc_boot.tv_sec);
817 *p++ = htonl(nfssvc_boot.tv_usec);
818 }
819 return xdr_ressize_check(rqstp, p);
820 }
821
822 /*
823 * XDR release functions
824 */
825 int
826 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
827 struct nfsd3_attrstat *resp)
828 {
829 fh_put(&resp->fh);
830 return 1;
831 }
832
833 int
834 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
835 struct nfsd3_fhandle_pair *resp)
836 {
837 fh_put(&resp->fh1);
838 fh_put(&resp->fh2);
839 return 1;
840 }
841