.. | .. |
---|
27 | 27 | NF3SOCK, NF3BAD, NF3LNK, NF3BAD, |
---|
28 | 28 | }; |
---|
29 | 29 | |
---|
| 30 | + |
---|
30 | 31 | /* |
---|
31 | 32 | * XDR functions for basic NFS types |
---|
32 | 33 | */ |
---|
33 | 34 | static __be32 * |
---|
34 | | -encode_time3(__be32 *p, struct timespec *time) |
---|
| 35 | +encode_time3(__be32 *p, struct timespec64 *time) |
---|
35 | 36 | { |
---|
36 | 37 | *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); |
---|
37 | 38 | return p; |
---|
38 | 39 | } |
---|
39 | 40 | |
---|
40 | 41 | static __be32 * |
---|
41 | | -decode_time3(__be32 *p, struct timespec *time) |
---|
| 42 | +decode_time3(__be32 *p, struct timespec64 *time) |
---|
42 | 43 | { |
---|
43 | 44 | time->tv_sec = ntohl(*p++); |
---|
44 | 45 | time->tv_nsec = ntohl(*p++); |
---|
.. | .. |
---|
96 | 97 | } |
---|
97 | 98 | |
---|
98 | 99 | static __be32 * |
---|
99 | | -decode_sattr3(__be32 *p, struct iattr *iap) |
---|
| 100 | +decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns) |
---|
100 | 101 | { |
---|
101 | 102 | u32 tmp; |
---|
102 | 103 | |
---|
.. | .. |
---|
107 | 108 | iap->ia_mode = ntohl(*p++); |
---|
108 | 109 | } |
---|
109 | 110 | if (*p++) { |
---|
110 | | - iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++)); |
---|
| 111 | + iap->ia_uid = make_kuid(userns, ntohl(*p++)); |
---|
111 | 112 | if (uid_valid(iap->ia_uid)) |
---|
112 | 113 | iap->ia_valid |= ATTR_UID; |
---|
113 | 114 | } |
---|
114 | 115 | if (*p++) { |
---|
115 | | - iap->ia_gid = make_kgid(&init_user_ns, ntohl(*p++)); |
---|
| 116 | + iap->ia_gid = make_kgid(userns, ntohl(*p++)); |
---|
116 | 117 | if (gid_valid(iap->ia_gid)) |
---|
117 | 118 | iap->ia_valid |= ATTR_GID; |
---|
118 | 119 | } |
---|
.. | .. |
---|
165 | 166 | encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, |
---|
166 | 167 | struct kstat *stat) |
---|
167 | 168 | { |
---|
168 | | - struct timespec ts; |
---|
| 169 | + struct user_namespace *userns = nfsd_user_namespace(rqstp); |
---|
169 | 170 | *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); |
---|
170 | 171 | *p++ = htonl((u32) (stat->mode & S_IALLUGO)); |
---|
171 | 172 | *p++ = htonl((u32) stat->nlink); |
---|
172 | | - *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid)); |
---|
173 | | - *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid)); |
---|
| 173 | + *p++ = htonl((u32) from_kuid_munged(userns, stat->uid)); |
---|
| 174 | + *p++ = htonl((u32) from_kgid_munged(userns, stat->gid)); |
---|
174 | 175 | if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { |
---|
175 | 176 | p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); |
---|
176 | 177 | } else { |
---|
.. | .. |
---|
181 | 182 | *p++ = htonl((u32) MINOR(stat->rdev)); |
---|
182 | 183 | p = encode_fsid(p, fhp); |
---|
183 | 184 | p = xdr_encode_hyper(p, stat->ino); |
---|
184 | | - ts = timespec64_to_timespec(stat->atime); |
---|
185 | | - p = encode_time3(p, &ts); |
---|
186 | | - ts = timespec64_to_timespec(stat->mtime); |
---|
187 | | - p = encode_time3(p, &ts); |
---|
188 | | - ts = timespec64_to_timespec(stat->ctime); |
---|
189 | | - p = encode_time3(p, &ts); |
---|
| 185 | + p = encode_time3(p, &stat->atime); |
---|
| 186 | + p = encode_time3(p, &stat->mtime); |
---|
| 187 | + p = encode_time3(p, &stat->ctime); |
---|
190 | 188 | |
---|
191 | 189 | return p; |
---|
192 | 190 | } |
---|
.. | .. |
---|
275 | 273 | stat.size = inode->i_size; |
---|
276 | 274 | } |
---|
277 | 275 | |
---|
278 | | - fhp->fh_pre_mtime = timespec64_to_timespec(stat.mtime); |
---|
279 | | - fhp->fh_pre_ctime = timespec64_to_timespec(stat.ctime); |
---|
| 276 | + fhp->fh_pre_mtime = stat.mtime; |
---|
| 277 | + fhp->fh_pre_ctime = stat.ctime; |
---|
280 | 278 | fhp->fh_pre_size = stat.size; |
---|
281 | 279 | fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); |
---|
282 | 280 | fhp->fh_pre_saved = true; |
---|
.. | .. |
---|
307 | 305 | * XDR decode functions |
---|
308 | 306 | */ |
---|
309 | 307 | int |
---|
| 308 | +nfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) |
---|
| 309 | +{ |
---|
| 310 | + return 1; |
---|
| 311 | +} |
---|
| 312 | + |
---|
| 313 | +int |
---|
310 | 314 | nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) |
---|
311 | 315 | { |
---|
312 | 316 | struct nfsd_fhandle *args = rqstp->rq_argp; |
---|
.. | .. |
---|
325 | 329 | p = decode_fh(p, &args->fh); |
---|
326 | 330 | if (!p) |
---|
327 | 331 | return 0; |
---|
328 | | - p = decode_sattr3(p, &args->attrs); |
---|
| 332 | + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); |
---|
329 | 333 | |
---|
330 | 334 | if ((args->check_guard = ntohl(*p++)) != 0) { |
---|
331 | | - struct timespec time; |
---|
| 335 | + struct timespec64 time; |
---|
332 | 336 | p = decode_time3(p, &time); |
---|
333 | 337 | args->guardtime = time.tv_sec; |
---|
334 | 338 | } |
---|
.. | .. |
---|
455 | 459 | switch (args->createmode = ntohl(*p++)) { |
---|
456 | 460 | case NFS3_CREATE_UNCHECKED: |
---|
457 | 461 | case NFS3_CREATE_GUARDED: |
---|
458 | | - p = decode_sattr3(p, &args->attrs); |
---|
| 462 | + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); |
---|
459 | 463 | break; |
---|
460 | 464 | case NFS3_CREATE_EXCLUSIVE: |
---|
461 | 465 | args->verf = p; |
---|
.. | .. |
---|
476 | 480 | if (!(p = decode_fh(p, &args->fh)) || |
---|
477 | 481 | !(p = decode_filename(p, &args->name, &args->len))) |
---|
478 | 482 | return 0; |
---|
479 | | - p = decode_sattr3(p, &args->attrs); |
---|
| 483 | + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); |
---|
480 | 484 | |
---|
481 | 485 | return xdr_argsize_check(rqstp, p); |
---|
482 | 486 | } |
---|
.. | .. |
---|
491 | 495 | if (!(p = decode_fh(p, &args->ffh)) || |
---|
492 | 496 | !(p = decode_filename(p, &args->fname, &args->flen))) |
---|
493 | 497 | return 0; |
---|
494 | | - p = decode_sattr3(p, &args->attrs); |
---|
| 498 | + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); |
---|
495 | 499 | |
---|
496 | 500 | args->tlen = ntohl(*p++); |
---|
497 | 501 | |
---|
.. | .. |
---|
519 | 523 | |
---|
520 | 524 | if (args->ftype == NF3BLK || args->ftype == NF3CHR |
---|
521 | 525 | || args->ftype == NF3SOCK || args->ftype == NF3FIFO) |
---|
522 | | - p = decode_sattr3(p, &args->attrs); |
---|
| 526 | + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); |
---|
523 | 527 | |
---|
524 | 528 | if (args->ftype == NF3BLK || args->ftype == NF3CHR) { |
---|
525 | 529 | args->major = ntohl(*p++); |
---|
.. | .. |
---|
573 | 577 | nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) |
---|
574 | 578 | { |
---|
575 | 579 | struct nfsd3_readdirargs *args = rqstp->rq_argp; |
---|
| 580 | + int len; |
---|
| 581 | + u32 max_blocksize = svc_max_payload(rqstp); |
---|
| 582 | + |
---|
576 | 583 | p = decode_fh(p, &args->fh); |
---|
577 | 584 | if (!p) |
---|
578 | 585 | return 0; |
---|
.. | .. |
---|
580 | 587 | args->verf = p; p += 2; |
---|
581 | 588 | args->dircount = ~0; |
---|
582 | 589 | args->count = ntohl(*p++); |
---|
583 | | - args->count = min_t(u32, args->count, PAGE_SIZE); |
---|
584 | | - args->buffer = page_address(*(rqstp->rq_next_page++)); |
---|
| 590 | + len = args->count = min_t(u32, args->count, max_blocksize); |
---|
| 591 | + |
---|
| 592 | + while (len > 0) { |
---|
| 593 | + struct page *p = *(rqstp->rq_next_page++); |
---|
| 594 | + if (!args->buffer) |
---|
| 595 | + args->buffer = page_address(p); |
---|
| 596 | + len -= PAGE_SIZE; |
---|
| 597 | + } |
---|
585 | 598 | |
---|
586 | 599 | return xdr_argsize_check(rqstp, p); |
---|
587 | 600 | } |
---|
.. | .. |
---|
628 | 641 | /* |
---|
629 | 642 | * XDR encode functions |
---|
630 | 643 | */ |
---|
631 | | -/* |
---|
632 | | - * There must be an encoding function for void results so svc_process |
---|
633 | | - * will work properly. |
---|
634 | | - */ |
---|
| 644 | + |
---|
635 | 645 | int |
---|
636 | 646 | nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) |
---|
637 | 647 | { |
---|
.. | .. |
---|
644 | 654 | { |
---|
645 | 655 | struct nfsd3_attrstat *resp = rqstp->rq_resp; |
---|
646 | 656 | |
---|
| 657 | + *p++ = resp->status; |
---|
647 | 658 | if (resp->status == 0) { |
---|
648 | 659 | lease_get_mtime(d_inode(resp->fh.fh_dentry), |
---|
649 | 660 | &resp->stat.mtime); |
---|
.. | .. |
---|
658 | 669 | { |
---|
659 | 670 | struct nfsd3_attrstat *resp = rqstp->rq_resp; |
---|
660 | 671 | |
---|
| 672 | + *p++ = resp->status; |
---|
661 | 673 | p = encode_wcc_data(rqstp, p, &resp->fh); |
---|
662 | 674 | return xdr_ressize_check(rqstp, p); |
---|
663 | 675 | } |
---|
.. | .. |
---|
668 | 680 | { |
---|
669 | 681 | struct nfsd3_diropres *resp = rqstp->rq_resp; |
---|
670 | 682 | |
---|
| 683 | + *p++ = resp->status; |
---|
671 | 684 | if (resp->status == 0) { |
---|
672 | 685 | p = encode_fh(p, &resp->fh); |
---|
673 | 686 | p = encode_post_op_attr(rqstp, p, &resp->fh); |
---|
.. | .. |
---|
682 | 695 | { |
---|
683 | 696 | struct nfsd3_accessres *resp = rqstp->rq_resp; |
---|
684 | 697 | |
---|
| 698 | + *p++ = resp->status; |
---|
685 | 699 | p = encode_post_op_attr(rqstp, p, &resp->fh); |
---|
686 | 700 | if (resp->status == 0) |
---|
687 | 701 | *p++ = htonl(resp->access); |
---|
.. | .. |
---|
694 | 708 | { |
---|
695 | 709 | struct nfsd3_readlinkres *resp = rqstp->rq_resp; |
---|
696 | 710 | |
---|
| 711 | + *p++ = resp->status; |
---|
697 | 712 | p = encode_post_op_attr(rqstp, p, &resp->fh); |
---|
698 | 713 | if (resp->status == 0) { |
---|
699 | 714 | *p++ = htonl(resp->len); |
---|
.. | .. |
---|
716 | 731 | { |
---|
717 | 732 | struct nfsd3_readres *resp = rqstp->rq_resp; |
---|
718 | 733 | |
---|
| 734 | + *p++ = resp->status; |
---|
719 | 735 | p = encode_post_op_attr(rqstp, p, &resp->fh); |
---|
720 | 736 | if (resp->status == 0) { |
---|
721 | 737 | *p++ = htonl(resp->count); |
---|
.. | .. |
---|
740 | 756 | nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) |
---|
741 | 757 | { |
---|
742 | 758 | struct nfsd3_writeres *resp = rqstp->rq_resp; |
---|
743 | | - struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
---|
744 | 759 | |
---|
| 760 | + *p++ = resp->status; |
---|
745 | 761 | p = encode_wcc_data(rqstp, p, &resp->fh); |
---|
746 | 762 | if (resp->status == 0) { |
---|
747 | 763 | *p++ = htonl(resp->count); |
---|
748 | 764 | *p++ = htonl(resp->committed); |
---|
749 | | - /* unique identifier, y2038 overflow can be ignored */ |
---|
750 | | - *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); |
---|
751 | | - *p++ = htonl(nn->nfssvc_boot.tv_nsec); |
---|
| 765 | + *p++ = resp->verf[0]; |
---|
| 766 | + *p++ = resp->verf[1]; |
---|
752 | 767 | } |
---|
753 | 768 | return xdr_ressize_check(rqstp, p); |
---|
754 | 769 | } |
---|
.. | .. |
---|
759 | 774 | { |
---|
760 | 775 | struct nfsd3_diropres *resp = rqstp->rq_resp; |
---|
761 | 776 | |
---|
| 777 | + *p++ = resp->status; |
---|
762 | 778 | if (resp->status == 0) { |
---|
763 | 779 | *p++ = xdr_one; |
---|
764 | 780 | p = encode_fh(p, &resp->fh); |
---|
.. | .. |
---|
774 | 790 | { |
---|
775 | 791 | struct nfsd3_renameres *resp = rqstp->rq_resp; |
---|
776 | 792 | |
---|
| 793 | + *p++ = resp->status; |
---|
777 | 794 | p = encode_wcc_data(rqstp, p, &resp->ffh); |
---|
778 | 795 | p = encode_wcc_data(rqstp, p, &resp->tfh); |
---|
779 | 796 | return xdr_ressize_check(rqstp, p); |
---|
.. | .. |
---|
785 | 802 | { |
---|
786 | 803 | struct nfsd3_linkres *resp = rqstp->rq_resp; |
---|
787 | 804 | |
---|
| 805 | + *p++ = resp->status; |
---|
788 | 806 | p = encode_post_op_attr(rqstp, p, &resp->fh); |
---|
789 | 807 | p = encode_wcc_data(rqstp, p, &resp->tfh); |
---|
790 | 808 | return xdr_ressize_check(rqstp, p); |
---|
.. | .. |
---|
796 | 814 | { |
---|
797 | 815 | struct nfsd3_readdirres *resp = rqstp->rq_resp; |
---|
798 | 816 | |
---|
| 817 | + *p++ = resp->status; |
---|
799 | 818 | p = encode_post_op_attr(rqstp, p, &resp->fh); |
---|
800 | 819 | |
---|
801 | 820 | if (resp->status == 0) { |
---|
.. | .. |
---|
855 | 874 | } else |
---|
856 | 875 | dchild = dget(dparent); |
---|
857 | 876 | } else |
---|
858 | | - dchild = lookup_one_len_unlocked(name, dparent, namlen); |
---|
| 877 | + dchild = lookup_positive_unlocked(name, dparent, namlen); |
---|
859 | 878 | if (IS_ERR(dchild)) |
---|
860 | 879 | return rv; |
---|
861 | 880 | if (d_mountpoint(dchild)) |
---|
862 | | - goto out; |
---|
863 | | - if (d_really_is_negative(dchild)) |
---|
864 | 881 | goto out; |
---|
865 | 882 | if (dchild->d_inode->i_ino != ino) |
---|
866 | 883 | goto out; |
---|
.. | .. |
---|
1055 | 1072 | struct kstatfs *s = &resp->stats; |
---|
1056 | 1073 | u64 bs = s->f_bsize; |
---|
1057 | 1074 | |
---|
| 1075 | + *p++ = resp->status; |
---|
1058 | 1076 | *p++ = xdr_zero; /* no post_op_attr */ |
---|
1059 | 1077 | |
---|
1060 | 1078 | if (resp->status == 0) { |
---|
.. | .. |
---|
1075 | 1093 | { |
---|
1076 | 1094 | struct nfsd3_fsinfores *resp = rqstp->rq_resp; |
---|
1077 | 1095 | |
---|
| 1096 | + *p++ = resp->status; |
---|
1078 | 1097 | *p++ = xdr_zero; /* no post_op_attr */ |
---|
1079 | 1098 | |
---|
1080 | 1099 | if (resp->status == 0) { |
---|
.. | .. |
---|
1100 | 1119 | { |
---|
1101 | 1120 | struct nfsd3_pathconfres *resp = rqstp->rq_resp; |
---|
1102 | 1121 | |
---|
| 1122 | + *p++ = resp->status; |
---|
1103 | 1123 | *p++ = xdr_zero; /* no post_op_attr */ |
---|
1104 | 1124 | |
---|
1105 | 1125 | if (resp->status == 0) { |
---|
.. | .. |
---|
1119 | 1139 | nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) |
---|
1120 | 1140 | { |
---|
1121 | 1141 | struct nfsd3_commitres *resp = rqstp->rq_resp; |
---|
1122 | | - struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
---|
1123 | 1142 | |
---|
| 1143 | + *p++ = resp->status; |
---|
1124 | 1144 | p = encode_wcc_data(rqstp, p, &resp->fh); |
---|
1125 | 1145 | /* Write verifier */ |
---|
1126 | 1146 | if (resp->status == 0) { |
---|
1127 | | - /* unique identifier, y2038 overflow can be ignored */ |
---|
1128 | | - *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); |
---|
1129 | | - *p++ = htonl(nn->nfssvc_boot.tv_nsec); |
---|
| 1147 | + *p++ = resp->verf[0]; |
---|
| 1148 | + *p++ = resp->verf[1]; |
---|
1130 | 1149 | } |
---|
1131 | 1150 | return xdr_ressize_check(rqstp, p); |
---|
1132 | 1151 | } |
---|