1 // SPDX-License-Identifier: GPL-2.0
3 * XDR support for nfsd/protocol version 3.
5 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
7 * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
10 #include <linux/namei.h>
11 #include <linux/sunrpc/svc_xprt.h>
18 * Force construction of an empty post-op attr
20 static const struct svc_fh nfs3svc_null_fh
= {
25 * time_delta. {1, 0} means the server is accurate only
26 * to the nearest second.
28 static const struct timespec64 nfs3svc_time_delta
= {
34 * Mapping of S_IF* types to NFS file types
36 static const u32 nfs3_ftypes
[] = {
37 NF3NON
, NF3FIFO
, NF3CHR
, NF3BAD
,
38 NF3DIR
, NF3BAD
, NF3BLK
, NF3BAD
,
39 NF3REG
, NF3BAD
, NF3LNK
, NF3BAD
,
40 NF3SOCK
, NF3BAD
, NF3LNK
, NF3BAD
,
45 * Basic NFSv3 data types (RFC 1813 Sections 2.5 and 2.6)
49 encode_nfstime3(__be32
*p
, const struct timespec64
*time
)
51 *p
++ = cpu_to_be32((u32
)time
->tv_sec
);
52 *p
++ = cpu_to_be32(time
->tv_nsec
);
58 svcxdr_decode_nfstime3(struct xdr_stream
*xdr
, struct timespec64
*timep
)
62 p
= xdr_inline_decode(xdr
, XDR_UNIT
* 2);
65 timep
->tv_sec
= be32_to_cpup(p
++);
66 timep
->tv_nsec
= be32_to_cpup(p
);
72 * svcxdr_decode_nfs_fh3 - Decode an NFSv3 file handle
73 * @xdr: XDR stream positioned at an undecoded NFSv3 FH
74 * @fhp: OUT: filled-in server file handle
77 * %false: The encoded file handle was not valid
78 * %true: @fhp has been initialized
81 svcxdr_decode_nfs_fh3(struct xdr_stream
*xdr
, struct svc_fh
*fhp
)
86 if (xdr_stream_decode_u32(xdr
, &size
) < 0)
88 if (size
== 0 || size
> NFS3_FHSIZE
)
90 p
= xdr_inline_decode(xdr
, size
);
93 fh_init(fhp
, NFS3_FHSIZE
);
94 fhp
->fh_handle
.fh_size
= size
;
95 memcpy(&fhp
->fh_handle
.fh_raw
, p
, size
);
101 * svcxdr_encode_nfsstat3 - Encode an NFSv3 status code
103 * @status: status value to encode
106 * %false: Send buffer space was exhausted
110 svcxdr_encode_nfsstat3(struct xdr_stream
*xdr
, __be32 status
)
114 p
= xdr_reserve_space(xdr
, sizeof(status
));
123 svcxdr_encode_nfs_fh3(struct xdr_stream
*xdr
, const struct svc_fh
*fhp
)
125 u32 size
= fhp
->fh_handle
.fh_size
;
128 p
= xdr_reserve_space(xdr
, XDR_UNIT
+ size
);
131 *p
++ = cpu_to_be32(size
);
133 p
[XDR_QUADLEN(size
) - 1] = 0;
134 memcpy(p
, &fhp
->fh_handle
.fh_raw
, size
);
140 svcxdr_encode_post_op_fh3(struct xdr_stream
*xdr
, const struct svc_fh
*fhp
)
142 if (xdr_stream_encode_item_present(xdr
) < 0)
144 if (!svcxdr_encode_nfs_fh3(xdr
, fhp
))
151 svcxdr_encode_cookieverf3(struct xdr_stream
*xdr
, const __be32
*verf
)
155 p
= xdr_reserve_space(xdr
, NFS3_COOKIEVERFSIZE
);
158 memcpy(p
, verf
, NFS3_COOKIEVERFSIZE
);
164 svcxdr_encode_writeverf3(struct xdr_stream
*xdr
, const __be32
*verf
)
168 p
= xdr_reserve_space(xdr
, NFS3_WRITEVERFSIZE
);
171 memcpy(p
, verf
, NFS3_WRITEVERFSIZE
);
177 svcxdr_decode_filename3(struct xdr_stream
*xdr
, char **name
, unsigned int *len
)
183 if (xdr_stream_decode_u32(xdr
, &size
) < 0)
185 if (size
== 0 || size
> NFS3_MAXNAMLEN
)
187 p
= xdr_inline_decode(xdr
, size
);
193 for (i
= 0, c
= *name
; i
< size
; i
++, c
++) {
194 if (*c
== '\0' || *c
== '/')
202 svcxdr_decode_diropargs3(struct xdr_stream
*xdr
, struct svc_fh
*fhp
,
203 char **name
, unsigned int *len
)
205 return svcxdr_decode_nfs_fh3(xdr
, fhp
) &&
206 svcxdr_decode_filename3(xdr
, name
, len
);
210 svcxdr_decode_sattr3(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
,
217 if (xdr_stream_decode_bool(xdr
, &set_it
) < 0)
222 if (xdr_stream_decode_u32(xdr
, &mode
) < 0)
224 iap
->ia_valid
|= ATTR_MODE
;
227 if (xdr_stream_decode_bool(xdr
, &set_it
) < 0)
232 if (xdr_stream_decode_u32(xdr
, &uid
) < 0)
234 iap
->ia_uid
= make_kuid(nfsd_user_namespace(rqstp
), uid
);
235 if (uid_valid(iap
->ia_uid
))
236 iap
->ia_valid
|= ATTR_UID
;
238 if (xdr_stream_decode_bool(xdr
, &set_it
) < 0)
243 if (xdr_stream_decode_u32(xdr
, &gid
) < 0)
245 iap
->ia_gid
= make_kgid(nfsd_user_namespace(rqstp
), gid
);
246 if (gid_valid(iap
->ia_gid
))
247 iap
->ia_valid
|= ATTR_GID
;
249 if (xdr_stream_decode_bool(xdr
, &set_it
) < 0)
254 if (xdr_stream_decode_u64(xdr
, &newsize
) < 0)
256 iap
->ia_valid
|= ATTR_SIZE
;
257 iap
->ia_size
= newsize
;
259 if (xdr_stream_decode_u32(xdr
, &set_it
) < 0)
264 case SET_TO_SERVER_TIME
:
265 iap
->ia_valid
|= ATTR_ATIME
;
267 case SET_TO_CLIENT_TIME
:
268 if (!svcxdr_decode_nfstime3(xdr
, &iap
->ia_atime
))
270 iap
->ia_valid
|= ATTR_ATIME
| ATTR_ATIME_SET
;
275 if (xdr_stream_decode_u32(xdr
, &set_it
) < 0)
280 case SET_TO_SERVER_TIME
:
281 iap
->ia_valid
|= ATTR_MTIME
;
283 case SET_TO_CLIENT_TIME
:
284 if (!svcxdr_decode_nfstime3(xdr
, &iap
->ia_mtime
))
286 iap
->ia_valid
|= ATTR_MTIME
| ATTR_MTIME_SET
;
296 svcxdr_decode_sattrguard3(struct xdr_stream
*xdr
, struct nfsd3_sattrargs
*args
)
300 if (xdr_stream_decode_bool(xdr
, &check
) < 0)
303 if (!svcxdr_decode_nfstime3(xdr
, &args
->guardtime
))
305 args
->check_guard
= 1;
307 args
->check_guard
= 0;
313 svcxdr_decode_specdata3(struct xdr_stream
*xdr
, struct nfsd3_mknodargs
*args
)
317 p
= xdr_inline_decode(xdr
, XDR_UNIT
* 2);
320 args
->major
= be32_to_cpup(p
++);
321 args
->minor
= be32_to_cpup(p
);
327 svcxdr_decode_devicedata3(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
,
328 struct nfsd3_mknodargs
*args
)
330 return svcxdr_decode_sattr3(rqstp
, xdr
, &args
->attrs
) &&
331 svcxdr_decode_specdata3(xdr
, args
);
335 svcxdr_encode_fattr3(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
,
336 const struct svc_fh
*fhp
, const struct kstat
*stat
)
338 struct user_namespace
*userns
= nfsd_user_namespace(rqstp
);
342 p
= xdr_reserve_space(xdr
, XDR_UNIT
* 21);
346 *p
++ = cpu_to_be32(nfs3_ftypes
[(stat
->mode
& S_IFMT
) >> 12]);
347 *p
++ = cpu_to_be32((u32
)(stat
->mode
& S_IALLUGO
));
348 *p
++ = cpu_to_be32((u32
)stat
->nlink
);
349 *p
++ = cpu_to_be32((u32
)from_kuid_munged(userns
, stat
->uid
));
350 *p
++ = cpu_to_be32((u32
)from_kgid_munged(userns
, stat
->gid
));
351 if (S_ISLNK(stat
->mode
) && stat
->size
> NFS3_MAXPATHLEN
)
352 p
= xdr_encode_hyper(p
, (u64
)NFS3_MAXPATHLEN
);
354 p
= xdr_encode_hyper(p
, (u64
)stat
->size
);
357 p
= xdr_encode_hyper(p
, ((u64
)stat
->blocks
) << 9);
360 *p
++ = cpu_to_be32((u32
)MAJOR(stat
->rdev
));
361 *p
++ = cpu_to_be32((u32
)MINOR(stat
->rdev
));
363 switch(fsid_source(fhp
)) {
364 case FSIDSOURCE_FSID
:
365 fsid
= (u64
)fhp
->fh_export
->ex_fsid
;
367 case FSIDSOURCE_UUID
:
368 fsid
= ((u64
*)fhp
->fh_export
->ex_uuid
)[0];
369 fsid
^= ((u64
*)fhp
->fh_export
->ex_uuid
)[1];
372 fsid
= (u64
)huge_encode_dev(fhp
->fh_dentry
->d_sb
->s_dev
);
374 p
= xdr_encode_hyper(p
, fsid
);
377 p
= xdr_encode_hyper(p
, stat
->ino
);
379 p
= encode_nfstime3(p
, &stat
->atime
);
380 p
= encode_nfstime3(p
, &stat
->mtime
);
381 encode_nfstime3(p
, &stat
->ctime
);
387 svcxdr_encode_wcc_attr(struct xdr_stream
*xdr
, const struct svc_fh
*fhp
)
391 p
= xdr_reserve_space(xdr
, XDR_UNIT
* 6);
394 p
= xdr_encode_hyper(p
, (u64
)fhp
->fh_pre_size
);
395 p
= encode_nfstime3(p
, &fhp
->fh_pre_mtime
);
396 encode_nfstime3(p
, &fhp
->fh_pre_ctime
);
402 svcxdr_encode_pre_op_attr(struct xdr_stream
*xdr
, const struct svc_fh
*fhp
)
404 if (!fhp
->fh_pre_saved
) {
405 if (xdr_stream_encode_item_absent(xdr
) < 0)
410 if (xdr_stream_encode_item_present(xdr
) < 0)
412 return svcxdr_encode_wcc_attr(xdr
, fhp
);
416 * svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes
417 * @rqstp: Context of a completed RPC transaction
419 * @fhp: File handle to encode
422 * %false: Send buffer space was exhausted
426 svcxdr_encode_post_op_attr(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
,
427 const struct svc_fh
*fhp
)
429 struct dentry
*dentry
= fhp
->fh_dentry
;
433 * The inode may be NULL if the call failed because of a
434 * stale file handle. In this case, no attributes are
437 if (fhp
->fh_no_wcc
|| !dentry
|| !d_really_is_positive(dentry
))
438 goto no_post_op_attrs
;
439 if (fh_getattr(fhp
, &stat
) != nfs_ok
)
440 goto no_post_op_attrs
;
442 if (xdr_stream_encode_item_present(xdr
) < 0)
444 lease_get_mtime(d_inode(dentry
), &stat
.mtime
);
445 if (!svcxdr_encode_fattr3(rqstp
, xdr
, fhp
, &stat
))
451 return xdr_stream_encode_item_absent(xdr
) > 0;
455 * Encode weak cache consistency data
458 svcxdr_encode_wcc_data(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
,
459 const struct svc_fh
*fhp
)
461 struct dentry
*dentry
= fhp
->fh_dentry
;
463 if (!dentry
|| !d_really_is_positive(dentry
) || !fhp
->fh_post_saved
)
467 if (!svcxdr_encode_pre_op_attr(xdr
, fhp
))
471 if (xdr_stream_encode_item_present(xdr
) < 0)
473 if (!svcxdr_encode_fattr3(rqstp
, xdr
, fhp
, &fhp
->fh_post_attr
))
479 if (xdr_stream_encode_item_absent(xdr
) < 0)
481 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, fhp
))
488 * XDR decode functions
492 nfs3svc_decode_fhandleargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
494 struct nfsd_fhandle
*args
= rqstp
->rq_argp
;
496 return svcxdr_decode_nfs_fh3(xdr
, &args
->fh
);
500 nfs3svc_decode_sattrargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
502 struct nfsd3_sattrargs
*args
= rqstp
->rq_argp
;
504 return svcxdr_decode_nfs_fh3(xdr
, &args
->fh
) &&
505 svcxdr_decode_sattr3(rqstp
, xdr
, &args
->attrs
) &&
506 svcxdr_decode_sattrguard3(xdr
, args
);
510 nfs3svc_decode_diropargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
512 struct nfsd3_diropargs
*args
= rqstp
->rq_argp
;
514 return svcxdr_decode_diropargs3(xdr
, &args
->fh
, &args
->name
, &args
->len
);
518 nfs3svc_decode_accessargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
520 struct nfsd3_accessargs
*args
= rqstp
->rq_argp
;
522 if (!svcxdr_decode_nfs_fh3(xdr
, &args
->fh
))
524 if (xdr_stream_decode_u32(xdr
, &args
->access
) < 0)
531 nfs3svc_decode_readargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
533 struct nfsd3_readargs
*args
= rqstp
->rq_argp
;
535 if (!svcxdr_decode_nfs_fh3(xdr
, &args
->fh
))
537 if (xdr_stream_decode_u64(xdr
, &args
->offset
) < 0)
539 if (xdr_stream_decode_u32(xdr
, &args
->count
) < 0)
546 nfs3svc_decode_writeargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
548 struct nfsd3_writeargs
*args
= rqstp
->rq_argp
;
549 u32 max_blocksize
= svc_max_payload(rqstp
);
551 if (!svcxdr_decode_nfs_fh3(xdr
, &args
->fh
))
553 if (xdr_stream_decode_u64(xdr
, &args
->offset
) < 0)
555 if (xdr_stream_decode_u32(xdr
, &args
->count
) < 0)
557 if (xdr_stream_decode_u32(xdr
, &args
->stable
) < 0)
561 if (xdr_stream_decode_u32(xdr
, &args
->len
) < 0)
565 if (args
->count
!= args
->len
)
567 if (args
->count
> max_blocksize
) {
568 args
->count
= max_blocksize
;
569 args
->len
= max_blocksize
;
572 return xdr_stream_subsegment(xdr
, &args
->payload
, args
->count
);
576 nfs3svc_decode_createargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
578 struct nfsd3_createargs
*args
= rqstp
->rq_argp
;
580 if (!svcxdr_decode_diropargs3(xdr
, &args
->fh
, &args
->name
, &args
->len
))
582 if (xdr_stream_decode_u32(xdr
, &args
->createmode
) < 0)
584 switch (args
->createmode
) {
585 case NFS3_CREATE_UNCHECKED
:
586 case NFS3_CREATE_GUARDED
:
587 return svcxdr_decode_sattr3(rqstp
, xdr
, &args
->attrs
);
588 case NFS3_CREATE_EXCLUSIVE
:
589 args
->verf
= xdr_inline_decode(xdr
, NFS3_CREATEVERFSIZE
);
600 nfs3svc_decode_mkdirargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
602 struct nfsd3_createargs
*args
= rqstp
->rq_argp
;
604 return svcxdr_decode_diropargs3(xdr
, &args
->fh
,
605 &args
->name
, &args
->len
) &&
606 svcxdr_decode_sattr3(rqstp
, xdr
, &args
->attrs
);
610 nfs3svc_decode_symlinkargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
612 struct nfsd3_symlinkargs
*args
= rqstp
->rq_argp
;
613 struct kvec
*head
= rqstp
->rq_arg
.head
;
615 if (!svcxdr_decode_diropargs3(xdr
, &args
->ffh
, &args
->fname
, &args
->flen
))
617 if (!svcxdr_decode_sattr3(rqstp
, xdr
, &args
->attrs
))
619 if (xdr_stream_decode_u32(xdr
, &args
->tlen
) < 0)
623 args
->first
.iov_len
= head
->iov_len
- xdr_stream_pos(xdr
);
624 args
->first
.iov_base
= xdr_inline_decode(xdr
, args
->tlen
);
625 return args
->first
.iov_base
!= NULL
;
629 nfs3svc_decode_mknodargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
631 struct nfsd3_mknodargs
*args
= rqstp
->rq_argp
;
633 if (!svcxdr_decode_diropargs3(xdr
, &args
->fh
, &args
->name
, &args
->len
))
635 if (xdr_stream_decode_u32(xdr
, &args
->ftype
) < 0)
637 switch (args
->ftype
) {
640 return svcxdr_decode_devicedata3(rqstp
, xdr
, args
);
643 return svcxdr_decode_sattr3(rqstp
, xdr
, &args
->attrs
);
647 /* Valid XDR but illegal file types */
657 nfs3svc_decode_renameargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
659 struct nfsd3_renameargs
*args
= rqstp
->rq_argp
;
661 return svcxdr_decode_diropargs3(xdr
, &args
->ffh
,
662 &args
->fname
, &args
->flen
) &&
663 svcxdr_decode_diropargs3(xdr
, &args
->tfh
,
664 &args
->tname
, &args
->tlen
);
668 nfs3svc_decode_linkargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
670 struct nfsd3_linkargs
*args
= rqstp
->rq_argp
;
672 return svcxdr_decode_nfs_fh3(xdr
, &args
->ffh
) &&
673 svcxdr_decode_diropargs3(xdr
, &args
->tfh
,
674 &args
->tname
, &args
->tlen
);
678 nfs3svc_decode_readdirargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
680 struct nfsd3_readdirargs
*args
= rqstp
->rq_argp
;
682 if (!svcxdr_decode_nfs_fh3(xdr
, &args
->fh
))
684 if (xdr_stream_decode_u64(xdr
, &args
->cookie
) < 0)
686 args
->verf
= xdr_inline_decode(xdr
, NFS3_COOKIEVERFSIZE
);
689 if (xdr_stream_decode_u32(xdr
, &args
->count
) < 0)
696 nfs3svc_decode_readdirplusargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
698 struct nfsd3_readdirargs
*args
= rqstp
->rq_argp
;
701 if (!svcxdr_decode_nfs_fh3(xdr
, &args
->fh
))
703 if (xdr_stream_decode_u64(xdr
, &args
->cookie
) < 0)
705 args
->verf
= xdr_inline_decode(xdr
, NFS3_COOKIEVERFSIZE
);
708 /* dircount is ignored */
709 if (xdr_stream_decode_u32(xdr
, &dircount
) < 0)
711 if (xdr_stream_decode_u32(xdr
, &args
->count
) < 0)
718 nfs3svc_decode_commitargs(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
720 struct nfsd3_commitargs
*args
= rqstp
->rq_argp
;
722 if (!svcxdr_decode_nfs_fh3(xdr
, &args
->fh
))
724 if (xdr_stream_decode_u64(xdr
, &args
->offset
) < 0)
726 if (xdr_stream_decode_u32(xdr
, &args
->count
) < 0)
733 * XDR encode functions
738 nfs3svc_encode_getattrres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
740 struct nfsd3_attrstat
*resp
= rqstp
->rq_resp
;
742 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
744 switch (resp
->status
) {
746 lease_get_mtime(d_inode(resp
->fh
.fh_dentry
), &resp
->stat
.mtime
);
747 if (!svcxdr_encode_fattr3(rqstp
, xdr
, &resp
->fh
, &resp
->stat
))
755 /* SETATTR, REMOVE, RMDIR */
757 nfs3svc_encode_wccstat(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
759 struct nfsd3_attrstat
*resp
= rqstp
->rq_resp
;
761 return svcxdr_encode_nfsstat3(xdr
, resp
->status
) &&
762 svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->fh
);
767 nfs3svc_encode_lookupres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
769 struct nfsd3_diropres
*resp
= rqstp
->rq_resp
;
771 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
773 switch (resp
->status
) {
775 if (!svcxdr_encode_nfs_fh3(xdr
, &resp
->fh
))
777 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
779 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->dirfh
))
783 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->dirfh
))
792 nfs3svc_encode_accessres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
794 struct nfsd3_accessres
*resp
= rqstp
->rq_resp
;
796 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
798 switch (resp
->status
) {
800 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
802 if (xdr_stream_encode_u32(xdr
, resp
->access
) < 0)
806 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
815 nfs3svc_encode_readlinkres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
817 struct nfsd3_readlinkres
*resp
= rqstp
->rq_resp
;
818 struct kvec
*head
= rqstp
->rq_res
.head
;
820 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
822 switch (resp
->status
) {
824 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
826 if (xdr_stream_encode_u32(xdr
, resp
->len
) < 0)
828 svcxdr_encode_opaque_pages(rqstp
, xdr
, resp
->pages
, 0,
830 if (svc_encode_result_payload(rqstp
, head
->iov_len
, resp
->len
) < 0)
834 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
843 nfs3svc_encode_readres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
845 struct nfsd3_readres
*resp
= rqstp
->rq_resp
;
846 struct kvec
*head
= rqstp
->rq_res
.head
;
848 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
850 switch (resp
->status
) {
852 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
854 if (xdr_stream_encode_u32(xdr
, resp
->count
) < 0)
856 if (xdr_stream_encode_bool(xdr
, resp
->eof
) < 0)
858 if (xdr_stream_encode_u32(xdr
, resp
->count
) < 0)
860 svcxdr_encode_opaque_pages(rqstp
, xdr
, resp
->pages
,
861 rqstp
->rq_res
.page_base
,
863 if (svc_encode_result_payload(rqstp
, head
->iov_len
, resp
->count
) < 0)
867 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
876 nfs3svc_encode_writeres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
878 struct nfsd3_writeres
*resp
= rqstp
->rq_resp
;
880 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
882 switch (resp
->status
) {
884 if (!svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->fh
))
886 if (xdr_stream_encode_u32(xdr
, resp
->count
) < 0)
888 if (xdr_stream_encode_u32(xdr
, resp
->committed
) < 0)
890 if (!svcxdr_encode_writeverf3(xdr
, resp
->verf
))
894 if (!svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->fh
))
901 /* CREATE, MKDIR, SYMLINK, MKNOD */
903 nfs3svc_encode_createres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
905 struct nfsd3_diropres
*resp
= rqstp
->rq_resp
;
907 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
909 switch (resp
->status
) {
911 if (!svcxdr_encode_post_op_fh3(xdr
, &resp
->fh
))
913 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
915 if (!svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->dirfh
))
919 if (!svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->dirfh
))
928 nfs3svc_encode_renameres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
930 struct nfsd3_renameres
*resp
= rqstp
->rq_resp
;
932 return svcxdr_encode_nfsstat3(xdr
, resp
->status
) &&
933 svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->ffh
) &&
934 svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->tfh
);
939 nfs3svc_encode_linkres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
941 struct nfsd3_linkres
*resp
= rqstp
->rq_resp
;
943 return svcxdr_encode_nfsstat3(xdr
, resp
->status
) &&
944 svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
) &&
945 svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->tfh
);
950 nfs3svc_encode_readdirres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
952 struct nfsd3_readdirres
*resp
= rqstp
->rq_resp
;
953 struct xdr_buf
*dirlist
= &resp
->dirlist
;
955 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
957 switch (resp
->status
) {
959 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
961 if (!svcxdr_encode_cookieverf3(xdr
, resp
->verf
))
963 svcxdr_encode_opaque_pages(rqstp
, xdr
, dirlist
->pages
, 0,
965 /* no more entries */
966 if (xdr_stream_encode_item_absent(xdr
) < 0)
968 if (xdr_stream_encode_bool(xdr
, resp
->common
.err
== nfserr_eof
) < 0)
972 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &resp
->fh
))
980 compose_entry_fh(struct nfsd3_readdirres
*cd
, struct svc_fh
*fhp
,
981 const char *name
, int namlen
, u64 ino
)
983 struct svc_export
*exp
;
984 struct dentry
*dparent
, *dchild
;
985 __be32 rv
= nfserr_noent
;
987 dparent
= cd
->fh
.fh_dentry
;
988 exp
= cd
->fh
.fh_export
;
990 if (isdotent(name
, namlen
)) {
992 dchild
= dget_parent(dparent
);
994 * Don't return filehandle for ".." if we're at
995 * the filesystem or export root:
997 if (dchild
== dparent
)
999 if (dparent
== exp
->ex_path
.dentry
)
1002 dchild
= dget(dparent
);
1004 dchild
= lookup_positive_unlocked(name
, dparent
, namlen
);
1007 if (d_mountpoint(dchild
))
1009 if (dchild
->d_inode
->i_ino
!= ino
)
1011 rv
= fh_compose(fhp
, exp
, dchild
, &cd
->fh
);
1018 * nfs3svc_encode_cookie3 - Encode a directory offset cookie
1019 * @resp: readdir result context
1020 * @offset: offset cookie to encode
1022 * The buffer space for the offset cookie has already been reserved
1023 * by svcxdr_encode_entry3_common().
1025 void nfs3svc_encode_cookie3(struct nfsd3_readdirres
*resp
, u64 offset
)
1027 __be64 cookie
= cpu_to_be64(offset
);
1029 if (!resp
->cookie_offset
)
1031 write_bytes_to_xdr_buf(&resp
->dirlist
, resp
->cookie_offset
, &cookie
,
1033 resp
->cookie_offset
= 0;
1037 svcxdr_encode_entry3_common(struct nfsd3_readdirres
*resp
, const char *name
,
1038 int namlen
, loff_t offset
, u64 ino
)
1040 struct xdr_buf
*dirlist
= &resp
->dirlist
;
1041 struct xdr_stream
*xdr
= &resp
->xdr
;
1043 if (xdr_stream_encode_item_present(xdr
) < 0)
1046 if (xdr_stream_encode_u64(xdr
, ino
) < 0)
1049 if (xdr_stream_encode_opaque(xdr
, name
, min(namlen
, NFS3_MAXNAMLEN
)) < 0)
1052 resp
->cookie_offset
= dirlist
->len
;
1053 if (xdr_stream_encode_u64(xdr
, OFFSET_MAX
) < 0)
1060 * nfs3svc_encode_entry3 - encode one NFSv3 READDIR entry
1061 * @data: directory context
1062 * @name: name of the object to be encoded
1063 * @namlen: length of that name, in bytes
1064 * @offset: the offset of the previous entry
1065 * @ino: the fileid of this entry
1069 * %0: Entry was successfully encoded.
1070 * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
1072 * On exit, the following fields are updated:
1074 * - resp->common.err
1075 * - resp->cookie_offset
1077 int nfs3svc_encode_entry3(void *data
, const char *name
, int namlen
,
1078 loff_t offset
, u64 ino
, unsigned int d_type
)
1080 struct readdir_cd
*ccd
= data
;
1081 struct nfsd3_readdirres
*resp
= container_of(ccd
,
1082 struct nfsd3_readdirres
,
1084 unsigned int starting_length
= resp
->dirlist
.len
;
1086 /* The offset cookie for the previous entry */
1087 nfs3svc_encode_cookie3(resp
, offset
);
1089 if (!svcxdr_encode_entry3_common(resp
, name
, namlen
, offset
, ino
))
1092 xdr_commit_encode(&resp
->xdr
);
1093 resp
->common
.err
= nfs_ok
;
1097 resp
->cookie_offset
= 0;
1098 resp
->common
.err
= nfserr_toosmall
;
1099 resp
->dirlist
.len
= starting_length
;
1104 svcxdr_encode_entry3_plus(struct nfsd3_readdirres
*resp
, const char *name
,
1105 int namlen
, u64 ino
)
1107 struct xdr_stream
*xdr
= &resp
->xdr
;
1108 struct svc_fh
*fhp
= &resp
->scratch
;
1112 fh_init(fhp
, NFS3_FHSIZE
);
1113 if (compose_entry_fh(resp
, fhp
, name
, namlen
, ino
) != nfs_ok
)
1116 if (!svcxdr_encode_post_op_attr(resp
->rqstp
, xdr
, fhp
))
1118 if (!svcxdr_encode_post_op_fh3(xdr
, fhp
))
1127 if (xdr_stream_encode_item_absent(xdr
) < 0)
1129 if (xdr_stream_encode_item_absent(xdr
) < 0)
1135 * nfs3svc_encode_entryplus3 - encode one NFSv3 READDIRPLUS entry
1136 * @data: directory context
1137 * @name: name of the object to be encoded
1138 * @namlen: length of that name, in bytes
1139 * @offset: the offset of the previous entry
1140 * @ino: the fileid of this entry
1144 * %0: Entry was successfully encoded.
1145 * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
1147 * On exit, the following fields are updated:
1149 * - resp->common.err
1150 * - resp->cookie_offset
1152 int nfs3svc_encode_entryplus3(void *data
, const char *name
, int namlen
,
1153 loff_t offset
, u64 ino
, unsigned int d_type
)
1155 struct readdir_cd
*ccd
= data
;
1156 struct nfsd3_readdirres
*resp
= container_of(ccd
,
1157 struct nfsd3_readdirres
,
1159 unsigned int starting_length
= resp
->dirlist
.len
;
1161 /* The offset cookie for the previous entry */
1162 nfs3svc_encode_cookie3(resp
, offset
);
1164 if (!svcxdr_encode_entry3_common(resp
, name
, namlen
, offset
, ino
))
1166 if (!svcxdr_encode_entry3_plus(resp
, name
, namlen
, ino
))
1169 xdr_commit_encode(&resp
->xdr
);
1170 resp
->common
.err
= nfs_ok
;
1174 resp
->cookie_offset
= 0;
1175 resp
->common
.err
= nfserr_toosmall
;
1176 resp
->dirlist
.len
= starting_length
;
1181 svcxdr_encode_fsstat3resok(struct xdr_stream
*xdr
,
1182 const struct nfsd3_fsstatres
*resp
)
1184 const struct kstatfs
*s
= &resp
->stats
;
1185 u64 bs
= s
->f_bsize
;
1188 p
= xdr_reserve_space(xdr
, XDR_UNIT
* 13);
1191 p
= xdr_encode_hyper(p
, bs
* s
->f_blocks
); /* total bytes */
1192 p
= xdr_encode_hyper(p
, bs
* s
->f_bfree
); /* free bytes */
1193 p
= xdr_encode_hyper(p
, bs
* s
->f_bavail
); /* user available bytes */
1194 p
= xdr_encode_hyper(p
, s
->f_files
); /* total inodes */
1195 p
= xdr_encode_hyper(p
, s
->f_ffree
); /* free inodes */
1196 p
= xdr_encode_hyper(p
, s
->f_ffree
); /* user available inodes */
1197 *p
= cpu_to_be32(resp
->invarsec
); /* mean unchanged time */
1204 nfs3svc_encode_fsstatres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
1206 struct nfsd3_fsstatres
*resp
= rqstp
->rq_resp
;
1208 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
1210 switch (resp
->status
) {
1212 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &nfs3svc_null_fh
))
1214 if (!svcxdr_encode_fsstat3resok(xdr
, resp
))
1218 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &nfs3svc_null_fh
))
1226 svcxdr_encode_fsinfo3resok(struct xdr_stream
*xdr
,
1227 const struct nfsd3_fsinfores
*resp
)
1231 p
= xdr_reserve_space(xdr
, XDR_UNIT
* 12);
1234 *p
++ = cpu_to_be32(resp
->f_rtmax
);
1235 *p
++ = cpu_to_be32(resp
->f_rtpref
);
1236 *p
++ = cpu_to_be32(resp
->f_rtmult
);
1237 *p
++ = cpu_to_be32(resp
->f_wtmax
);
1238 *p
++ = cpu_to_be32(resp
->f_wtpref
);
1239 *p
++ = cpu_to_be32(resp
->f_wtmult
);
1240 *p
++ = cpu_to_be32(resp
->f_dtpref
);
1241 p
= xdr_encode_hyper(p
, resp
->f_maxfilesize
);
1242 p
= encode_nfstime3(p
, &nfs3svc_time_delta
);
1243 *p
= cpu_to_be32(resp
->f_properties
);
1250 nfs3svc_encode_fsinfores(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
1252 struct nfsd3_fsinfores
*resp
= rqstp
->rq_resp
;
1254 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
1256 switch (resp
->status
) {
1258 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &nfs3svc_null_fh
))
1260 if (!svcxdr_encode_fsinfo3resok(xdr
, resp
))
1264 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &nfs3svc_null_fh
))
1272 svcxdr_encode_pathconf3resok(struct xdr_stream
*xdr
,
1273 const struct nfsd3_pathconfres
*resp
)
1277 p
= xdr_reserve_space(xdr
, XDR_UNIT
* 6);
1280 *p
++ = cpu_to_be32(resp
->p_link_max
);
1281 *p
++ = cpu_to_be32(resp
->p_name_max
);
1282 p
= xdr_encode_bool(p
, resp
->p_no_trunc
);
1283 p
= xdr_encode_bool(p
, resp
->p_chown_restricted
);
1284 p
= xdr_encode_bool(p
, resp
->p_case_insensitive
);
1285 xdr_encode_bool(p
, resp
->p_case_preserving
);
1292 nfs3svc_encode_pathconfres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
1294 struct nfsd3_pathconfres
*resp
= rqstp
->rq_resp
;
1296 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
1298 switch (resp
->status
) {
1300 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &nfs3svc_null_fh
))
1302 if (!svcxdr_encode_pathconf3resok(xdr
, resp
))
1306 if (!svcxdr_encode_post_op_attr(rqstp
, xdr
, &nfs3svc_null_fh
))
1315 nfs3svc_encode_commitres(struct svc_rqst
*rqstp
, struct xdr_stream
*xdr
)
1317 struct nfsd3_commitres
*resp
= rqstp
->rq_resp
;
1319 if (!svcxdr_encode_nfsstat3(xdr
, resp
->status
))
1321 switch (resp
->status
) {
1323 if (!svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->fh
))
1325 if (!svcxdr_encode_writeverf3(xdr
, resp
->verf
))
1329 if (!svcxdr_encode_wcc_data(rqstp
, xdr
, &resp
->fh
))
1337 * XDR release functions
1340 nfs3svc_release_fhandle(struct svc_rqst
*rqstp
)
1342 struct nfsd3_attrstat
*resp
= rqstp
->rq_resp
;
1348 nfs3svc_release_fhandle2(struct svc_rqst
*rqstp
)
1350 struct nfsd3_fhandle_pair
*resp
= rqstp
->rq_resp
;