]>
git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - fs/nfsd/nfsxdr.c
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
12 #define NFSDDBG_FACILITY NFSDDBG_XDR
15 * Mapping of S_IF* types to NFS file types
17 static u32 nfs_ftypes
[] = {
18 NFNON
, NFCHR
, NFCHR
, NFBAD
,
19 NFDIR
, NFBAD
, NFBLK
, NFBAD
,
20 NFREG
, NFBAD
, NFLNK
, NFBAD
,
21 NFSOCK
, NFBAD
, NFLNK
, NFBAD
,
26 * XDR functions for basic NFS types
29 decode_fh(__be32
*p
, struct svc_fh
*fhp
)
31 fh_init(fhp
, NFS_FHSIZE
);
32 memcpy(&fhp
->fh_handle
.fh_base
, p
, NFS_FHSIZE
);
33 fhp
->fh_handle
.fh_size
= NFS_FHSIZE
;
35 /* FIXME: Look up export pointer here and verify
36 * Sun Secure RPC if requested */
37 return p
+ (NFS_FHSIZE
>> 2);
40 /* Helper function for NFSv2 ACL code */
41 __be32
*nfs2svc_decode_fh(__be32
*p
, struct svc_fh
*fhp
)
43 return decode_fh(p
, fhp
);
47 encode_fh(__be32
*p
, struct svc_fh
*fhp
)
49 memcpy(p
, &fhp
->fh_handle
.fh_base
, NFS_FHSIZE
);
50 return p
+ (NFS_FHSIZE
>> 2);
54 * Decode a file name and make sure that the path contains
55 * no slashes or null bytes.
58 decode_filename(__be32
*p
, char **namp
, unsigned int *lenp
)
63 if ((p
= xdr_decode_string_inplace(p
, namp
, lenp
, NFS_MAXNAMLEN
)) != NULL
) {
64 for (i
= 0, name
= *namp
; i
< *lenp
; i
++, name
++) {
65 if (*name
== '\0' || *name
== '/')
74 decode_sattr(__be32
*p
, struct iattr
*iap
, struct user_namespace
*userns
)
80 /* Sun client bug compatibility check: some sun clients seem to
81 * put 0xffff in the mode field when they mean 0xffffffff.
82 * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah.
84 if ((tmp
= ntohl(*p
++)) != (u32
)-1 && tmp
!= 0xffff) {
85 iap
->ia_valid
|= ATTR_MODE
;
88 if ((tmp
= ntohl(*p
++)) != (u32
)-1) {
89 iap
->ia_uid
= make_kuid(userns
, tmp
);
90 if (uid_valid(iap
->ia_uid
))
91 iap
->ia_valid
|= ATTR_UID
;
93 if ((tmp
= ntohl(*p
++)) != (u32
)-1) {
94 iap
->ia_gid
= make_kgid(userns
, tmp
);
95 if (gid_valid(iap
->ia_gid
))
96 iap
->ia_valid
|= ATTR_GID
;
98 if ((tmp
= ntohl(*p
++)) != (u32
)-1) {
99 iap
->ia_valid
|= ATTR_SIZE
;
102 tmp
= ntohl(*p
++); tmp1
= ntohl(*p
++);
103 if (tmp
!= (u32
)-1 && tmp1
!= (u32
)-1) {
104 iap
->ia_valid
|= ATTR_ATIME
| ATTR_ATIME_SET
;
105 iap
->ia_atime
.tv_sec
= tmp
;
106 iap
->ia_atime
.tv_nsec
= tmp1
* 1000;
108 tmp
= ntohl(*p
++); tmp1
= ntohl(*p
++);
109 if (tmp
!= (u32
)-1 && tmp1
!= (u32
)-1) {
110 iap
->ia_valid
|= ATTR_MTIME
| ATTR_MTIME_SET
;
111 iap
->ia_mtime
.tv_sec
= tmp
;
112 iap
->ia_mtime
.tv_nsec
= tmp1
* 1000;
114 * Passing the invalid value useconds=1000000 for mtime
115 * is a Sun convention for "set both mtime and atime to
116 * current server time". It's needed to make permissions
117 * checks for the "touch" program across v2 mounts to
118 * Solaris and Irix boxes work correctly. See description of
119 * sattr in section 6.1 of "NFS Illustrated" by
120 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
123 iap
->ia_valid
&= ~(ATTR_ATIME_SET
|ATTR_MTIME_SET
);
129 encode_fattr(struct svc_rqst
*rqstp
, __be32
*p
, struct svc_fh
*fhp
,
132 struct user_namespace
*userns
= nfsd_user_namespace(rqstp
);
133 struct dentry
*dentry
= fhp
->fh_dentry
;
135 struct timespec64 time
;
138 type
= (stat
->mode
& S_IFMT
);
140 *p
++ = htonl(nfs_ftypes
[type
>> 12]);
141 *p
++ = htonl((u32
) stat
->mode
);
142 *p
++ = htonl((u32
) stat
->nlink
);
143 *p
++ = htonl((u32
) from_kuid_munged(userns
, stat
->uid
));
144 *p
++ = htonl((u32
) from_kgid_munged(userns
, stat
->gid
));
146 if (S_ISLNK(type
) && stat
->size
> NFS_MAXPATHLEN
) {
147 *p
++ = htonl(NFS_MAXPATHLEN
);
149 *p
++ = htonl((u32
) stat
->size
);
151 *p
++ = htonl((u32
) stat
->blksize
);
152 if (S_ISCHR(type
) || S_ISBLK(type
))
153 *p
++ = htonl(new_encode_dev(stat
->rdev
));
155 *p
++ = htonl(0xffffffff);
156 *p
++ = htonl((u32
) stat
->blocks
);
157 switch (fsid_source(fhp
)) {
160 *p
++ = htonl(new_encode_dev(stat
->dev
));
162 case FSIDSOURCE_FSID
:
163 *p
++ = htonl((u32
) fhp
->fh_export
->ex_fsid
);
165 case FSIDSOURCE_UUID
:
166 f
= ((u32
*)fhp
->fh_export
->ex_uuid
)[0];
167 f
^= ((u32
*)fhp
->fh_export
->ex_uuid
)[1];
168 f
^= ((u32
*)fhp
->fh_export
->ex_uuid
)[2];
169 f
^= ((u32
*)fhp
->fh_export
->ex_uuid
)[3];
173 *p
++ = htonl((u32
) stat
->ino
);
174 *p
++ = htonl((u32
) stat
->atime
.tv_sec
);
175 *p
++ = htonl(stat
->atime
.tv_nsec
? stat
->atime
.tv_nsec
/ 1000 : 0);
177 lease_get_mtime(d_inode(dentry
), &time
);
178 *p
++ = htonl((u32
) time
.tv_sec
);
179 *p
++ = htonl(time
.tv_nsec
? time
.tv_nsec
/ 1000 : 0);
180 *p
++ = htonl((u32
) stat
->ctime
.tv_sec
);
181 *p
++ = htonl(stat
->ctime
.tv_nsec
? stat
->ctime
.tv_nsec
/ 1000 : 0);
186 /* Helper function for NFSv2 ACL code */
187 __be32
*nfs2svc_encode_fattr(struct svc_rqst
*rqstp
, __be32
*p
, struct svc_fh
*fhp
, struct kstat
*stat
)
189 return encode_fattr(rqstp
, p
, fhp
, stat
);
193 * XDR decode functions
197 nfssvc_decode_fhandle(struct svc_rqst
*rqstp
, __be32
*p
)
199 struct nfsd_fhandle
*args
= rqstp
->rq_argp
;
201 p
= decode_fh(p
, &args
->fh
);
204 return xdr_argsize_check(rqstp
, p
);
208 nfssvc_decode_sattrargs(struct svc_rqst
*rqstp
, __be32
*p
)
210 struct nfsd_sattrargs
*args
= rqstp
->rq_argp
;
212 p
= decode_fh(p
, &args
->fh
);
215 p
= decode_sattr(p
, &args
->attrs
, nfsd_user_namespace(rqstp
));
217 return xdr_argsize_check(rqstp
, p
);
221 nfssvc_decode_diropargs(struct svc_rqst
*rqstp
, __be32
*p
)
223 struct nfsd_diropargs
*args
= rqstp
->rq_argp
;
225 if (!(p
= decode_fh(p
, &args
->fh
))
226 || !(p
= decode_filename(p
, &args
->name
, &args
->len
)))
229 return xdr_argsize_check(rqstp
, p
);
233 nfssvc_decode_readargs(struct svc_rqst
*rqstp
, __be32
*p
)
235 struct nfsd_readargs
*args
= rqstp
->rq_argp
;
238 p
= decode_fh(p
, &args
->fh
);
242 args
->offset
= ntohl(*p
++);
243 len
= args
->count
= ntohl(*p
++);
244 p
++; /* totalcount - unused */
246 len
= min_t(unsigned int, len
, NFSSVC_MAXBLKSIZE_V2
);
248 /* set up somewhere to store response.
249 * We take pages, put them on reslist and include in iovec
253 struct page
*p
= *(rqstp
->rq_next_page
++);
255 rqstp
->rq_vec
[v
].iov_base
= page_address(p
);
256 rqstp
->rq_vec
[v
].iov_len
= min_t(unsigned int, len
, PAGE_SIZE
);
257 len
-= rqstp
->rq_vec
[v
].iov_len
;
261 return xdr_argsize_check(rqstp
, p
);
265 nfssvc_decode_writeargs(struct svc_rqst
*rqstp
, __be32
*p
)
267 struct nfsd_writeargs
*args
= rqstp
->rq_argp
;
268 unsigned int len
, hdr
, dlen
;
269 struct kvec
*head
= rqstp
->rq_arg
.head
;
271 p
= decode_fh(p
, &args
->fh
);
275 p
++; /* beginoffset */
276 args
->offset
= ntohl(*p
++); /* offset */
277 p
++; /* totalcount */
278 len
= args
->len
= ntohl(*p
++);
280 * The protocol specifies a maximum of 8192 bytes.
282 if (len
> NFSSVC_MAXBLKSIZE_V2
)
286 * Check to make sure that we got the right number of
289 hdr
= (void*)p
- head
->iov_base
;
290 if (hdr
> head
->iov_len
)
292 dlen
= head
->iov_len
+ rqstp
->rq_arg
.page_len
- hdr
;
295 * Round the length of the data which was specified up to
296 * the next multiple of XDR units and then compare that
297 * against the length which was actually received.
298 * Note that when RPCSEC/GSS (for example) is used, the
299 * data buffer can be padded so dlen might be larger
300 * than required. It must never be smaller.
302 if (dlen
< XDR_QUADLEN(len
)*4)
305 args
->first
.iov_base
= (void *)p
;
306 args
->first
.iov_len
= head
->iov_len
- hdr
;
311 nfssvc_decode_createargs(struct svc_rqst
*rqstp
, __be32
*p
)
313 struct nfsd_createargs
*args
= rqstp
->rq_argp
;
315 if ( !(p
= decode_fh(p
, &args
->fh
))
316 || !(p
= decode_filename(p
, &args
->name
, &args
->len
)))
318 p
= decode_sattr(p
, &args
->attrs
, nfsd_user_namespace(rqstp
));
320 return xdr_argsize_check(rqstp
, p
);
324 nfssvc_decode_renameargs(struct svc_rqst
*rqstp
, __be32
*p
)
326 struct nfsd_renameargs
*args
= rqstp
->rq_argp
;
328 if (!(p
= decode_fh(p
, &args
->ffh
))
329 || !(p
= decode_filename(p
, &args
->fname
, &args
->flen
))
330 || !(p
= decode_fh(p
, &args
->tfh
))
331 || !(p
= decode_filename(p
, &args
->tname
, &args
->tlen
)))
334 return xdr_argsize_check(rqstp
, p
);
338 nfssvc_decode_readlinkargs(struct svc_rqst
*rqstp
, __be32
*p
)
340 struct nfsd_readlinkargs
*args
= rqstp
->rq_argp
;
342 p
= decode_fh(p
, &args
->fh
);
345 args
->buffer
= page_address(*(rqstp
->rq_next_page
++));
347 return xdr_argsize_check(rqstp
, p
);
351 nfssvc_decode_linkargs(struct svc_rqst
*rqstp
, __be32
*p
)
353 struct nfsd_linkargs
*args
= rqstp
->rq_argp
;
355 if (!(p
= decode_fh(p
, &args
->ffh
))
356 || !(p
= decode_fh(p
, &args
->tfh
))
357 || !(p
= decode_filename(p
, &args
->tname
, &args
->tlen
)))
360 return xdr_argsize_check(rqstp
, p
);
364 nfssvc_decode_symlinkargs(struct svc_rqst
*rqstp
, __be32
*p
)
366 struct nfsd_symlinkargs
*args
= rqstp
->rq_argp
;
367 char *base
= (char *)p
;
370 if ( !(p
= decode_fh(p
, &args
->ffh
))
371 || !(p
= decode_filename(p
, &args
->fname
, &args
->flen
)))
374 args
->tlen
= ntohl(*p
++);
378 args
->first
.iov_base
= p
;
379 args
->first
.iov_len
= rqstp
->rq_arg
.head
[0].iov_len
;
380 args
->first
.iov_len
-= (char *)p
- base
;
382 /* This request is never larger than a page. Therefore,
383 * transport will deliver either:
384 * 1. pathname in the pagelist -> sattr is in the tail.
385 * 2. everything in the head buffer -> sattr is in the head.
387 if (rqstp
->rq_arg
.page_len
) {
388 if (args
->tlen
!= rqstp
->rq_arg
.page_len
)
390 p
= rqstp
->rq_arg
.tail
[0].iov_base
;
392 xdrlen
= XDR_QUADLEN(args
->tlen
);
393 if (xdrlen
> args
->first
.iov_len
- (8 * sizeof(__be32
)))
397 decode_sattr(p
, &args
->attrs
, nfsd_user_namespace(rqstp
));
403 nfssvc_decode_readdirargs(struct svc_rqst
*rqstp
, __be32
*p
)
405 struct nfsd_readdirargs
*args
= rqstp
->rq_argp
;
407 p
= decode_fh(p
, &args
->fh
);
410 args
->cookie
= ntohl(*p
++);
411 args
->count
= ntohl(*p
++);
412 args
->count
= min_t(u32
, args
->count
, PAGE_SIZE
);
413 args
->buffer
= page_address(*(rqstp
->rq_next_page
++));
415 return xdr_argsize_check(rqstp
, p
);
419 * XDR encode functions
423 nfssvc_encode_stat(struct svc_rqst
*rqstp
, __be32
*p
)
425 struct nfsd_stat
*resp
= rqstp
->rq_resp
;
428 return xdr_ressize_check(rqstp
, p
);
432 nfssvc_encode_attrstat(struct svc_rqst
*rqstp
, __be32
*p
)
434 struct nfsd_attrstat
*resp
= rqstp
->rq_resp
;
437 if (resp
->status
!= nfs_ok
)
439 p
= encode_fattr(rqstp
, p
, &resp
->fh
, &resp
->stat
);
441 return xdr_ressize_check(rqstp
, p
);
445 nfssvc_encode_diropres(struct svc_rqst
*rqstp
, __be32
*p
)
447 struct nfsd_diropres
*resp
= rqstp
->rq_resp
;
450 if (resp
->status
!= nfs_ok
)
452 p
= encode_fh(p
, &resp
->fh
);
453 p
= encode_fattr(rqstp
, p
, &resp
->fh
, &resp
->stat
);
455 return xdr_ressize_check(rqstp
, p
);
459 nfssvc_encode_readlinkres(struct svc_rqst
*rqstp
, __be32
*p
)
461 struct nfsd_readlinkres
*resp
= rqstp
->rq_resp
;
462 struct kvec
*head
= rqstp
->rq_res
.head
;
465 if (resp
->status
!= nfs_ok
)
466 return xdr_ressize_check(rqstp
, p
);
468 *p
++ = htonl(resp
->len
);
469 xdr_ressize_check(rqstp
, p
);
470 rqstp
->rq_res
.page_len
= resp
->len
;
472 /* need to pad the tail */
473 rqstp
->rq_res
.tail
[0].iov_base
= p
;
475 rqstp
->rq_res
.tail
[0].iov_len
= 4 - (resp
->len
&3);
477 if (svc_encode_result_payload(rqstp
, head
->iov_len
, resp
->len
))
483 nfssvc_encode_readres(struct svc_rqst
*rqstp
, __be32
*p
)
485 struct nfsd_readres
*resp
= rqstp
->rq_resp
;
486 struct kvec
*head
= rqstp
->rq_res
.head
;
489 if (resp
->status
!= nfs_ok
)
490 return xdr_ressize_check(rqstp
, p
);
492 p
= encode_fattr(rqstp
, p
, &resp
->fh
, &resp
->stat
);
493 *p
++ = htonl(resp
->count
);
494 xdr_ressize_check(rqstp
, p
);
496 /* now update rqstp->rq_res to reflect data as well */
497 rqstp
->rq_res
.page_len
= resp
->count
;
498 if (resp
->count
& 3) {
499 /* need to pad the tail */
500 rqstp
->rq_res
.tail
[0].iov_base
= p
;
502 rqstp
->rq_res
.tail
[0].iov_len
= 4 - (resp
->count
&3);
504 if (svc_encode_result_payload(rqstp
, head
->iov_len
, resp
->count
))
510 nfssvc_encode_readdirres(struct svc_rqst
*rqstp
, __be32
*p
)
512 struct nfsd_readdirres
*resp
= rqstp
->rq_resp
;
515 if (resp
->status
!= nfs_ok
)
516 return xdr_ressize_check(rqstp
, p
);
518 xdr_ressize_check(rqstp
, p
);
520 *p
++ = 0; /* no more entries */
521 *p
++ = htonl((resp
->common
.err
== nfserr_eof
));
522 rqstp
->rq_res
.page_len
= (((unsigned long)p
-1) & ~PAGE_MASK
)+1;
528 nfssvc_encode_statfsres(struct svc_rqst
*rqstp
, __be32
*p
)
530 struct nfsd_statfsres
*resp
= rqstp
->rq_resp
;
531 struct kstatfs
*stat
= &resp
->stats
;
534 if (resp
->status
!= nfs_ok
)
535 return xdr_ressize_check(rqstp
, p
);
537 *p
++ = htonl(NFSSVC_MAXBLKSIZE_V2
); /* max transfer size */
538 *p
++ = htonl(stat
->f_bsize
);
539 *p
++ = htonl(stat
->f_blocks
);
540 *p
++ = htonl(stat
->f_bfree
);
541 *p
++ = htonl(stat
->f_bavail
);
542 return xdr_ressize_check(rqstp
, p
);
546 nfssvc_encode_entry(void *ccdv
, const char *name
,
547 int namlen
, loff_t offset
, u64 ino
, unsigned int d_type
)
549 struct readdir_cd
*ccd
= ccdv
;
550 struct nfsd_readdirres
*cd
= container_of(ccd
, struct nfsd_readdirres
, common
);
551 __be32
*p
= cd
->buffer
;
555 dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
556 namlen, name, offset, ino);
559 if (offset
> ~((u32
) 0)) {
560 cd
->common
.err
= nfserr_fbig
;
564 *cd
->offset
= htonl(offset
);
566 /* truncate filename */
567 namlen
= min(namlen
, NFS2_MAXNAMLEN
);
568 slen
= XDR_QUADLEN(namlen
);
570 if ((buflen
= cd
->buflen
- slen
- 4) < 0) {
571 cd
->common
.err
= nfserr_toosmall
;
574 if (ino
> ~((u32
) 0)) {
575 cd
->common
.err
= nfserr_fbig
;
578 *p
++ = xdr_one
; /* mark entry present */
579 *p
++ = htonl((u32
) ino
); /* file id */
580 p
= xdr_encode_array(p
, name
, namlen
);/* name length & name */
581 cd
->offset
= p
; /* remember pointer */
582 *p
++ = htonl(~0U); /* offset of next entry */
586 cd
->common
.err
= nfs_ok
;
591 * XDR release functions
593 void nfssvc_release_attrstat(struct svc_rqst
*rqstp
)
595 struct nfsd_attrstat
*resp
= rqstp
->rq_resp
;
600 void nfssvc_release_diropres(struct svc_rqst
*rqstp
)
602 struct nfsd_diropres
*resp
= rqstp
->rq_resp
;
607 void nfssvc_release_readres(struct svc_rqst
*rqstp
)
609 struct nfsd_readres
*resp
= rqstp
->rq_resp
;