1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * XDR support for nfsd/protocol version 3.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/namei.h>
11*4882a593Smuzhiyun #include <linux/sunrpc/svc_xprt.h>
12*4882a593Smuzhiyun #include "xdr3.h"
13*4882a593Smuzhiyun #include "auth.h"
14*4882a593Smuzhiyun #include "netns.h"
15*4882a593Smuzhiyun #include "vfs.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define NFSDDBG_FACILITY NFSDDBG_XDR
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun * Mapping of S_IF* types to NFS file types
22*4882a593Smuzhiyun */
23*4882a593Smuzhiyun static u32 nfs3_ftypes[] = {
24*4882a593Smuzhiyun NF3NON, NF3FIFO, NF3CHR, NF3BAD,
25*4882a593Smuzhiyun NF3DIR, NF3BAD, NF3BLK, NF3BAD,
26*4882a593Smuzhiyun NF3REG, NF3BAD, NF3LNK, NF3BAD,
27*4882a593Smuzhiyun NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun * XDR functions for basic NFS types
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun static __be32 *
encode_time3(__be32 * p,struct timespec64 * time)35*4882a593Smuzhiyun encode_time3(__be32 *p, struct timespec64 *time)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
38*4882a593Smuzhiyun return p;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun static __be32 *
decode_time3(__be32 * p,struct timespec64 * time)42*4882a593Smuzhiyun decode_time3(__be32 *p, struct timespec64 *time)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun time->tv_sec = ntohl(*p++);
45*4882a593Smuzhiyun time->tv_nsec = ntohl(*p++);
46*4882a593Smuzhiyun return p;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static __be32 *
decode_fh(__be32 * p,struct svc_fh * fhp)50*4882a593Smuzhiyun decode_fh(__be32 *p, struct svc_fh *fhp)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun unsigned int size;
53*4882a593Smuzhiyun fh_init(fhp, NFS3_FHSIZE);
54*4882a593Smuzhiyun size = ntohl(*p++);
55*4882a593Smuzhiyun if (size > NFS3_FHSIZE)
56*4882a593Smuzhiyun return NULL;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun memcpy(&fhp->fh_handle.fh_base, p, size);
59*4882a593Smuzhiyun fhp->fh_handle.fh_size = size;
60*4882a593Smuzhiyun return p + XDR_QUADLEN(size);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* Helper function for NFSv3 ACL code */
nfs3svc_decode_fh(__be32 * p,struct svc_fh * fhp)64*4882a593Smuzhiyun __be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun return decode_fh(p, fhp);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun static __be32 *
encode_fh(__be32 * p,struct svc_fh * fhp)70*4882a593Smuzhiyun encode_fh(__be32 *p, struct svc_fh *fhp)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun unsigned int size = fhp->fh_handle.fh_size;
73*4882a593Smuzhiyun *p++ = htonl(size);
74*4882a593Smuzhiyun if (size) p[XDR_QUADLEN(size)-1]=0;
75*4882a593Smuzhiyun memcpy(p, &fhp->fh_handle.fh_base, size);
76*4882a593Smuzhiyun return p + XDR_QUADLEN(size);
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /*
80*4882a593Smuzhiyun * Decode a file name and make sure that the path contains
81*4882a593Smuzhiyun * no slashes or null bytes.
82*4882a593Smuzhiyun */
83*4882a593Smuzhiyun static __be32 *
decode_filename(__be32 * p,char ** namp,unsigned int * lenp)84*4882a593Smuzhiyun decode_filename(__be32 *p, char **namp, unsigned int *lenp)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun char *name;
87*4882a593Smuzhiyun unsigned int i;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
90*4882a593Smuzhiyun for (i = 0, name = *namp; i < *lenp; i++, name++) {
91*4882a593Smuzhiyun if (*name == '\0' || *name == '/')
92*4882a593Smuzhiyun return NULL;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return p;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static __be32 *
decode_sattr3(__be32 * p,struct iattr * iap,struct user_namespace * userns)100*4882a593Smuzhiyun decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun u32 tmp;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun iap->ia_valid = 0;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (*p++) {
107*4882a593Smuzhiyun iap->ia_valid |= ATTR_MODE;
108*4882a593Smuzhiyun iap->ia_mode = ntohl(*p++);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun if (*p++) {
111*4882a593Smuzhiyun iap->ia_uid = make_kuid(userns, ntohl(*p++));
112*4882a593Smuzhiyun if (uid_valid(iap->ia_uid))
113*4882a593Smuzhiyun iap->ia_valid |= ATTR_UID;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun if (*p++) {
116*4882a593Smuzhiyun iap->ia_gid = make_kgid(userns, ntohl(*p++));
117*4882a593Smuzhiyun if (gid_valid(iap->ia_gid))
118*4882a593Smuzhiyun iap->ia_valid |= ATTR_GID;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun if (*p++) {
121*4882a593Smuzhiyun u64 newsize;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun iap->ia_valid |= ATTR_SIZE;
124*4882a593Smuzhiyun p = xdr_decode_hyper(p, &newsize);
125*4882a593Smuzhiyun iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
128*4882a593Smuzhiyun iap->ia_valid |= ATTR_ATIME;
129*4882a593Smuzhiyun } else if (tmp == 2) { /* set to client time */
130*4882a593Smuzhiyun iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
131*4882a593Smuzhiyun iap->ia_atime.tv_sec = ntohl(*p++);
132*4882a593Smuzhiyun iap->ia_atime.tv_nsec = ntohl(*p++);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
135*4882a593Smuzhiyun iap->ia_valid |= ATTR_MTIME;
136*4882a593Smuzhiyun } else if (tmp == 2) { /* set to client time */
137*4882a593Smuzhiyun iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
138*4882a593Smuzhiyun iap->ia_mtime.tv_sec = ntohl(*p++);
139*4882a593Smuzhiyun iap->ia_mtime.tv_nsec = ntohl(*p++);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun return p;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
encode_fsid(__be32 * p,struct svc_fh * fhp)144*4882a593Smuzhiyun static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun u64 f;
147*4882a593Smuzhiyun switch(fsid_source(fhp)) {
148*4882a593Smuzhiyun default:
149*4882a593Smuzhiyun case FSIDSOURCE_DEV:
150*4882a593Smuzhiyun p = xdr_encode_hyper(p, (u64)huge_encode_dev
151*4882a593Smuzhiyun (fhp->fh_dentry->d_sb->s_dev));
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun case FSIDSOURCE_FSID:
154*4882a593Smuzhiyun p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
155*4882a593Smuzhiyun break;
156*4882a593Smuzhiyun case FSIDSOURCE_UUID:
157*4882a593Smuzhiyun f = ((u64*)fhp->fh_export->ex_uuid)[0];
158*4882a593Smuzhiyun f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
159*4882a593Smuzhiyun p = xdr_encode_hyper(p, f);
160*4882a593Smuzhiyun break;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun return p;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun static __be32 *
encode_fattr3(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp,struct kstat * stat)166*4882a593Smuzhiyun encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
167*4882a593Smuzhiyun struct kstat *stat)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct user_namespace *userns = nfsd_user_namespace(rqstp);
170*4882a593Smuzhiyun *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
171*4882a593Smuzhiyun *p++ = htonl((u32) (stat->mode & S_IALLUGO));
172*4882a593Smuzhiyun *p++ = htonl((u32) stat->nlink);
173*4882a593Smuzhiyun *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
174*4882a593Smuzhiyun *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
175*4882a593Smuzhiyun if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
176*4882a593Smuzhiyun p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
177*4882a593Smuzhiyun } else {
178*4882a593Smuzhiyun p = xdr_encode_hyper(p, (u64) stat->size);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
181*4882a593Smuzhiyun *p++ = htonl((u32) MAJOR(stat->rdev));
182*4882a593Smuzhiyun *p++ = htonl((u32) MINOR(stat->rdev));
183*4882a593Smuzhiyun p = encode_fsid(p, fhp);
184*4882a593Smuzhiyun p = xdr_encode_hyper(p, stat->ino);
185*4882a593Smuzhiyun p = encode_time3(p, &stat->atime);
186*4882a593Smuzhiyun p = encode_time3(p, &stat->mtime);
187*4882a593Smuzhiyun p = encode_time3(p, &stat->ctime);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return p;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun static __be32 *
encode_saved_post_attr(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp)193*4882a593Smuzhiyun encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun /* Attributes to follow */
196*4882a593Smuzhiyun *p++ = xdr_one;
197*4882a593Smuzhiyun return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * Encode post-operation attributes.
202*4882a593Smuzhiyun * The inode may be NULL if the call failed because of a stale file
203*4882a593Smuzhiyun * handle. In this case, no attributes are returned.
204*4882a593Smuzhiyun */
205*4882a593Smuzhiyun static __be32 *
encode_post_op_attr(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp)206*4882a593Smuzhiyun encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun struct dentry *dentry = fhp->fh_dentry;
209*4882a593Smuzhiyun if (dentry && d_really_is_positive(dentry)) {
210*4882a593Smuzhiyun __be32 err;
211*4882a593Smuzhiyun struct kstat stat;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun err = fh_getattr(fhp, &stat);
214*4882a593Smuzhiyun if (!err) {
215*4882a593Smuzhiyun *p++ = xdr_one; /* attributes follow */
216*4882a593Smuzhiyun lease_get_mtime(d_inode(dentry), &stat.mtime);
217*4882a593Smuzhiyun return encode_fattr3(rqstp, p, fhp, &stat);
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun *p++ = xdr_zero;
221*4882a593Smuzhiyun return p;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* Helper for NFSv3 ACLs */
225*4882a593Smuzhiyun __be32 *
nfs3svc_encode_post_op_attr(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp)226*4882a593Smuzhiyun nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun return encode_post_op_attr(rqstp, p, fhp);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /*
232*4882a593Smuzhiyun * Enocde weak cache consistency data
233*4882a593Smuzhiyun */
234*4882a593Smuzhiyun static __be32 *
encode_wcc_data(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp)235*4882a593Smuzhiyun encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun struct dentry *dentry = fhp->fh_dentry;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) {
240*4882a593Smuzhiyun if (fhp->fh_pre_saved) {
241*4882a593Smuzhiyun *p++ = xdr_one;
242*4882a593Smuzhiyun p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
243*4882a593Smuzhiyun p = encode_time3(p, &fhp->fh_pre_mtime);
244*4882a593Smuzhiyun p = encode_time3(p, &fhp->fh_pre_ctime);
245*4882a593Smuzhiyun } else {
246*4882a593Smuzhiyun *p++ = xdr_zero;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun return encode_saved_post_attr(rqstp, p, fhp);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun /* no pre- or post-attrs */
251*4882a593Smuzhiyun *p++ = xdr_zero;
252*4882a593Smuzhiyun return encode_post_op_attr(rqstp, p, fhp);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /*
256*4882a593Smuzhiyun * Fill in the pre_op attr for the wcc data
257*4882a593Smuzhiyun */
fill_pre_wcc(struct svc_fh * fhp)258*4882a593Smuzhiyun void fill_pre_wcc(struct svc_fh *fhp)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun struct inode *inode;
261*4882a593Smuzhiyun struct kstat stat;
262*4882a593Smuzhiyun __be32 err;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (fhp->fh_pre_saved)
265*4882a593Smuzhiyun return;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun inode = d_inode(fhp->fh_dentry);
268*4882a593Smuzhiyun err = fh_getattr(fhp, &stat);
269*4882a593Smuzhiyun if (err) {
270*4882a593Smuzhiyun /* Grab the times from inode anyway */
271*4882a593Smuzhiyun stat.mtime = inode->i_mtime;
272*4882a593Smuzhiyun stat.ctime = inode->i_ctime;
273*4882a593Smuzhiyun stat.size = inode->i_size;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun fhp->fh_pre_mtime = stat.mtime;
277*4882a593Smuzhiyun fhp->fh_pre_ctime = stat.ctime;
278*4882a593Smuzhiyun fhp->fh_pre_size = stat.size;
279*4882a593Smuzhiyun fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
280*4882a593Smuzhiyun fhp->fh_pre_saved = true;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /*
284*4882a593Smuzhiyun * Fill in the post_op attr for the wcc data
285*4882a593Smuzhiyun */
fill_post_wcc(struct svc_fh * fhp)286*4882a593Smuzhiyun void fill_post_wcc(struct svc_fh *fhp)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun __be32 err;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (fhp->fh_post_saved)
291*4882a593Smuzhiyun printk("nfsd: inode locked twice during operation.\n");
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun err = fh_getattr(fhp, &fhp->fh_post_attr);
294*4882a593Smuzhiyun fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
295*4882a593Smuzhiyun d_inode(fhp->fh_dentry));
296*4882a593Smuzhiyun if (err) {
297*4882a593Smuzhiyun fhp->fh_post_saved = false;
298*4882a593Smuzhiyun /* Grab the ctime anyway - set_change_info might use it */
299*4882a593Smuzhiyun fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
300*4882a593Smuzhiyun } else
301*4882a593Smuzhiyun fhp->fh_post_saved = true;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /*
305*4882a593Smuzhiyun * XDR decode functions
306*4882a593Smuzhiyun */
307*4882a593Smuzhiyun int
nfs3svc_decode_voidarg(struct svc_rqst * rqstp,__be32 * p)308*4882a593Smuzhiyun nfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun return 1;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun int
nfs3svc_decode_fhandle(struct svc_rqst * rqstp,__be32 * p)314*4882a593Smuzhiyun nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun struct nfsd_fhandle *args = rqstp->rq_argp;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
319*4882a593Smuzhiyun if (!p)
320*4882a593Smuzhiyun return 0;
321*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun int
nfs3svc_decode_sattrargs(struct svc_rqst * rqstp,__be32 * p)325*4882a593Smuzhiyun nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun struct nfsd3_sattrargs *args = rqstp->rq_argp;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
330*4882a593Smuzhiyun if (!p)
331*4882a593Smuzhiyun return 0;
332*4882a593Smuzhiyun p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if ((args->check_guard = ntohl(*p++)) != 0) {
335*4882a593Smuzhiyun struct timespec64 time;
336*4882a593Smuzhiyun p = decode_time3(p, &time);
337*4882a593Smuzhiyun args->guardtime = time.tv_sec;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun int
nfs3svc_decode_diropargs(struct svc_rqst * rqstp,__be32 * p)344*4882a593Smuzhiyun nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun struct nfsd3_diropargs *args = rqstp->rq_argp;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->fh))
349*4882a593Smuzhiyun || !(p = decode_filename(p, &args->name, &args->len)))
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun int
nfs3svc_decode_accessargs(struct svc_rqst * rqstp,__be32 * p)356*4882a593Smuzhiyun nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun struct nfsd3_accessargs *args = rqstp->rq_argp;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
361*4882a593Smuzhiyun if (!p)
362*4882a593Smuzhiyun return 0;
363*4882a593Smuzhiyun args->access = ntohl(*p++);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun int
nfs3svc_decode_readargs(struct svc_rqst * rqstp,__be32 * p)369*4882a593Smuzhiyun nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct nfsd3_readargs *args = rqstp->rq_argp;
372*4882a593Smuzhiyun unsigned int len;
373*4882a593Smuzhiyun int v;
374*4882a593Smuzhiyun u32 max_blocksize = svc_max_payload(rqstp);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
377*4882a593Smuzhiyun if (!p)
378*4882a593Smuzhiyun return 0;
379*4882a593Smuzhiyun p = xdr_decode_hyper(p, &args->offset);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun args->count = ntohl(*p++);
382*4882a593Smuzhiyun len = min(args->count, max_blocksize);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* set up the kvec */
385*4882a593Smuzhiyun v=0;
386*4882a593Smuzhiyun while (len > 0) {
387*4882a593Smuzhiyun struct page *p = *(rqstp->rq_next_page++);
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun rqstp->rq_vec[v].iov_base = page_address(p);
390*4882a593Smuzhiyun rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
391*4882a593Smuzhiyun len -= rqstp->rq_vec[v].iov_len;
392*4882a593Smuzhiyun v++;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun args->vlen = v;
395*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun int
nfs3svc_decode_writeargs(struct svc_rqst * rqstp,__be32 * p)399*4882a593Smuzhiyun nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun struct nfsd3_writeargs *args = rqstp->rq_argp;
402*4882a593Smuzhiyun unsigned int len, hdr, dlen;
403*4882a593Smuzhiyun u32 max_blocksize = svc_max_payload(rqstp);
404*4882a593Smuzhiyun struct kvec *head = rqstp->rq_arg.head;
405*4882a593Smuzhiyun struct kvec *tail = rqstp->rq_arg.tail;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
408*4882a593Smuzhiyun if (!p)
409*4882a593Smuzhiyun return 0;
410*4882a593Smuzhiyun p = xdr_decode_hyper(p, &args->offset);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun args->count = ntohl(*p++);
413*4882a593Smuzhiyun args->stable = ntohl(*p++);
414*4882a593Smuzhiyun len = args->len = ntohl(*p++);
415*4882a593Smuzhiyun if ((void *)p > head->iov_base + head->iov_len)
416*4882a593Smuzhiyun return 0;
417*4882a593Smuzhiyun /*
418*4882a593Smuzhiyun * The count must equal the amount of data passed.
419*4882a593Smuzhiyun */
420*4882a593Smuzhiyun if (args->count != args->len)
421*4882a593Smuzhiyun return 0;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun /*
424*4882a593Smuzhiyun * Check to make sure that we got the right number of
425*4882a593Smuzhiyun * bytes.
426*4882a593Smuzhiyun */
427*4882a593Smuzhiyun hdr = (void*)p - head->iov_base;
428*4882a593Smuzhiyun dlen = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len - hdr;
429*4882a593Smuzhiyun /*
430*4882a593Smuzhiyun * Round the length of the data which was specified up to
431*4882a593Smuzhiyun * the next multiple of XDR units and then compare that
432*4882a593Smuzhiyun * against the length which was actually received.
433*4882a593Smuzhiyun * Note that when RPCSEC/GSS (for example) is used, the
434*4882a593Smuzhiyun * data buffer can be padded so dlen might be larger
435*4882a593Smuzhiyun * than required. It must never be smaller.
436*4882a593Smuzhiyun */
437*4882a593Smuzhiyun if (dlen < XDR_QUADLEN(len)*4)
438*4882a593Smuzhiyun return 0;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (args->count > max_blocksize) {
441*4882a593Smuzhiyun args->count = max_blocksize;
442*4882a593Smuzhiyun len = args->len = max_blocksize;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun args->first.iov_base = (void *)p;
446*4882a593Smuzhiyun args->first.iov_len = head->iov_len - hdr;
447*4882a593Smuzhiyun return 1;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun int
nfs3svc_decode_createargs(struct svc_rqst * rqstp,__be32 * p)451*4882a593Smuzhiyun nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun struct nfsd3_createargs *args = rqstp->rq_argp;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->fh))
456*4882a593Smuzhiyun || !(p = decode_filename(p, &args->name, &args->len)))
457*4882a593Smuzhiyun return 0;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun switch (args->createmode = ntohl(*p++)) {
460*4882a593Smuzhiyun case NFS3_CREATE_UNCHECKED:
461*4882a593Smuzhiyun case NFS3_CREATE_GUARDED:
462*4882a593Smuzhiyun p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
463*4882a593Smuzhiyun break;
464*4882a593Smuzhiyun case NFS3_CREATE_EXCLUSIVE:
465*4882a593Smuzhiyun args->verf = p;
466*4882a593Smuzhiyun p += 2;
467*4882a593Smuzhiyun break;
468*4882a593Smuzhiyun default:
469*4882a593Smuzhiyun return 0;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun int
nfs3svc_decode_mkdirargs(struct svc_rqst * rqstp,__be32 * p)476*4882a593Smuzhiyun nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun struct nfsd3_createargs *args = rqstp->rq_argp;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->fh)) ||
481*4882a593Smuzhiyun !(p = decode_filename(p, &args->name, &args->len)))
482*4882a593Smuzhiyun return 0;
483*4882a593Smuzhiyun p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun int
nfs3svc_decode_symlinkargs(struct svc_rqst * rqstp,__be32 * p)489*4882a593Smuzhiyun nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun struct nfsd3_symlinkargs *args = rqstp->rq_argp;
492*4882a593Smuzhiyun char *base = (char *)p;
493*4882a593Smuzhiyun size_t dlen;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->ffh)) ||
496*4882a593Smuzhiyun !(p = decode_filename(p, &args->fname, &args->flen)))
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun args->tlen = ntohl(*p++);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun args->first.iov_base = p;
503*4882a593Smuzhiyun args->first.iov_len = rqstp->rq_arg.head[0].iov_len;
504*4882a593Smuzhiyun args->first.iov_len -= (char *)p - base;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun dlen = args->first.iov_len + rqstp->rq_arg.page_len +
507*4882a593Smuzhiyun rqstp->rq_arg.tail[0].iov_len;
508*4882a593Smuzhiyun if (dlen < XDR_QUADLEN(args->tlen) << 2)
509*4882a593Smuzhiyun return 0;
510*4882a593Smuzhiyun return 1;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun int
nfs3svc_decode_mknodargs(struct svc_rqst * rqstp,__be32 * p)514*4882a593Smuzhiyun nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun struct nfsd3_mknodargs *args = rqstp->rq_argp;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->fh))
519*4882a593Smuzhiyun || !(p = decode_filename(p, &args->name, &args->len)))
520*4882a593Smuzhiyun return 0;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun args->ftype = ntohl(*p++);
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun if (args->ftype == NF3BLK || args->ftype == NF3CHR
525*4882a593Smuzhiyun || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
526*4882a593Smuzhiyun p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
529*4882a593Smuzhiyun args->major = ntohl(*p++);
530*4882a593Smuzhiyun args->minor = ntohl(*p++);
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun int
nfs3svc_decode_renameargs(struct svc_rqst * rqstp,__be32 * p)537*4882a593Smuzhiyun nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun struct nfsd3_renameargs *args = rqstp->rq_argp;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->ffh))
542*4882a593Smuzhiyun || !(p = decode_filename(p, &args->fname, &args->flen))
543*4882a593Smuzhiyun || !(p = decode_fh(p, &args->tfh))
544*4882a593Smuzhiyun || !(p = decode_filename(p, &args->tname, &args->tlen)))
545*4882a593Smuzhiyun return 0;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun int
nfs3svc_decode_readlinkargs(struct svc_rqst * rqstp,__be32 * p)551*4882a593Smuzhiyun nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun struct nfsd3_readlinkargs *args = rqstp->rq_argp;
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
556*4882a593Smuzhiyun if (!p)
557*4882a593Smuzhiyun return 0;
558*4882a593Smuzhiyun args->buffer = page_address(*(rqstp->rq_next_page++));
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun int
nfs3svc_decode_linkargs(struct svc_rqst * rqstp,__be32 * p)564*4882a593Smuzhiyun nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun struct nfsd3_linkargs *args = rqstp->rq_argp;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (!(p = decode_fh(p, &args->ffh))
569*4882a593Smuzhiyun || !(p = decode_fh(p, &args->tfh))
570*4882a593Smuzhiyun || !(p = decode_filename(p, &args->tname, &args->tlen)))
571*4882a593Smuzhiyun return 0;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun int
nfs3svc_decode_readdirargs(struct svc_rqst * rqstp,__be32 * p)577*4882a593Smuzhiyun nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun struct nfsd3_readdirargs *args = rqstp->rq_argp;
580*4882a593Smuzhiyun int len;
581*4882a593Smuzhiyun u32 max_blocksize = svc_max_payload(rqstp);
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
584*4882a593Smuzhiyun if (!p)
585*4882a593Smuzhiyun return 0;
586*4882a593Smuzhiyun p = xdr_decode_hyper(p, &args->cookie);
587*4882a593Smuzhiyun args->verf = p; p += 2;
588*4882a593Smuzhiyun args->dircount = ~0;
589*4882a593Smuzhiyun args->count = ntohl(*p++);
590*4882a593Smuzhiyun len = args->count = min_t(u32, args->count, max_blocksize);
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun while (len > 0) {
593*4882a593Smuzhiyun struct page *p = *(rqstp->rq_next_page++);
594*4882a593Smuzhiyun if (!args->buffer)
595*4882a593Smuzhiyun args->buffer = page_address(p);
596*4882a593Smuzhiyun len -= PAGE_SIZE;
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun int
nfs3svc_decode_readdirplusargs(struct svc_rqst * rqstp,__be32 * p)603*4882a593Smuzhiyun nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun struct nfsd3_readdirargs *args = rqstp->rq_argp;
606*4882a593Smuzhiyun int len;
607*4882a593Smuzhiyun u32 max_blocksize = svc_max_payload(rqstp);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
610*4882a593Smuzhiyun if (!p)
611*4882a593Smuzhiyun return 0;
612*4882a593Smuzhiyun p = xdr_decode_hyper(p, &args->cookie);
613*4882a593Smuzhiyun args->verf = p; p += 2;
614*4882a593Smuzhiyun args->dircount = ntohl(*p++);
615*4882a593Smuzhiyun args->count = ntohl(*p++);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun len = args->count = min(args->count, max_blocksize);
618*4882a593Smuzhiyun while (len > 0) {
619*4882a593Smuzhiyun struct page *p = *(rqstp->rq_next_page++);
620*4882a593Smuzhiyun if (!args->buffer)
621*4882a593Smuzhiyun args->buffer = page_address(p);
622*4882a593Smuzhiyun len -= PAGE_SIZE;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun int
nfs3svc_decode_commitargs(struct svc_rqst * rqstp,__be32 * p)629*4882a593Smuzhiyun nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun struct nfsd3_commitargs *args = rqstp->rq_argp;
632*4882a593Smuzhiyun p = decode_fh(p, &args->fh);
633*4882a593Smuzhiyun if (!p)
634*4882a593Smuzhiyun return 0;
635*4882a593Smuzhiyun p = xdr_decode_hyper(p, &args->offset);
636*4882a593Smuzhiyun args->count = ntohl(*p++);
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun return xdr_argsize_check(rqstp, p);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun /*
642*4882a593Smuzhiyun * XDR encode functions
643*4882a593Smuzhiyun */
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun int
nfs3svc_encode_voidres(struct svc_rqst * rqstp,__be32 * p)646*4882a593Smuzhiyun nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun /* GETATTR */
652*4882a593Smuzhiyun int
nfs3svc_encode_attrstat(struct svc_rqst * rqstp,__be32 * p)653*4882a593Smuzhiyun nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun struct nfsd3_attrstat *resp = rqstp->rq_resp;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun *p++ = resp->status;
658*4882a593Smuzhiyun if (resp->status == 0) {
659*4882a593Smuzhiyun lease_get_mtime(d_inode(resp->fh.fh_dentry),
660*4882a593Smuzhiyun &resp->stat.mtime);
661*4882a593Smuzhiyun p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun /* SETATTR, REMOVE, RMDIR */
667*4882a593Smuzhiyun int
nfs3svc_encode_wccstat(struct svc_rqst * rqstp,__be32 * p)668*4882a593Smuzhiyun nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun struct nfsd3_attrstat *resp = rqstp->rq_resp;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun *p++ = resp->status;
673*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->fh);
674*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* LOOKUP */
678*4882a593Smuzhiyun int
nfs3svc_encode_diropres(struct svc_rqst * rqstp,__be32 * p)679*4882a593Smuzhiyun nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
680*4882a593Smuzhiyun {
681*4882a593Smuzhiyun struct nfsd3_diropres *resp = rqstp->rq_resp;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun *p++ = resp->status;
684*4882a593Smuzhiyun if (resp->status == 0) {
685*4882a593Smuzhiyun p = encode_fh(p, &resp->fh);
686*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->dirfh);
689*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun /* ACCESS */
693*4882a593Smuzhiyun int
nfs3svc_encode_accessres(struct svc_rqst * rqstp,__be32 * p)694*4882a593Smuzhiyun nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun struct nfsd3_accessres *resp = rqstp->rq_resp;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun *p++ = resp->status;
699*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
700*4882a593Smuzhiyun if (resp->status == 0)
701*4882a593Smuzhiyun *p++ = htonl(resp->access);
702*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun /* READLINK */
706*4882a593Smuzhiyun int
nfs3svc_encode_readlinkres(struct svc_rqst * rqstp,__be32 * p)707*4882a593Smuzhiyun nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun struct nfsd3_readlinkres *resp = rqstp->rq_resp;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun *p++ = resp->status;
712*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
713*4882a593Smuzhiyun if (resp->status == 0) {
714*4882a593Smuzhiyun *p++ = htonl(resp->len);
715*4882a593Smuzhiyun xdr_ressize_check(rqstp, p);
716*4882a593Smuzhiyun rqstp->rq_res.page_len = resp->len;
717*4882a593Smuzhiyun if (resp->len & 3) {
718*4882a593Smuzhiyun /* need to pad the tail */
719*4882a593Smuzhiyun rqstp->rq_res.tail[0].iov_base = p;
720*4882a593Smuzhiyun *p = 0;
721*4882a593Smuzhiyun rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun return 1;
724*4882a593Smuzhiyun } else
725*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /* READ */
729*4882a593Smuzhiyun int
nfs3svc_encode_readres(struct svc_rqst * rqstp,__be32 * p)730*4882a593Smuzhiyun nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun struct nfsd3_readres *resp = rqstp->rq_resp;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun *p++ = resp->status;
735*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
736*4882a593Smuzhiyun if (resp->status == 0) {
737*4882a593Smuzhiyun *p++ = htonl(resp->count);
738*4882a593Smuzhiyun *p++ = htonl(resp->eof);
739*4882a593Smuzhiyun *p++ = htonl(resp->count); /* xdr opaque count */
740*4882a593Smuzhiyun xdr_ressize_check(rqstp, p);
741*4882a593Smuzhiyun /* now update rqstp->rq_res to reflect data as well */
742*4882a593Smuzhiyun rqstp->rq_res.page_len = resp->count;
743*4882a593Smuzhiyun if (resp->count & 3) {
744*4882a593Smuzhiyun /* need to pad the tail */
745*4882a593Smuzhiyun rqstp->rq_res.tail[0].iov_base = p;
746*4882a593Smuzhiyun *p = 0;
747*4882a593Smuzhiyun rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun return 1;
750*4882a593Smuzhiyun } else
751*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /* WRITE */
755*4882a593Smuzhiyun int
nfs3svc_encode_writeres(struct svc_rqst * rqstp,__be32 * p)756*4882a593Smuzhiyun nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun struct nfsd3_writeres *resp = rqstp->rq_resp;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun *p++ = resp->status;
761*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->fh);
762*4882a593Smuzhiyun if (resp->status == 0) {
763*4882a593Smuzhiyun *p++ = htonl(resp->count);
764*4882a593Smuzhiyun *p++ = htonl(resp->committed);
765*4882a593Smuzhiyun *p++ = resp->verf[0];
766*4882a593Smuzhiyun *p++ = resp->verf[1];
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun /* CREATE, MKDIR, SYMLINK, MKNOD */
772*4882a593Smuzhiyun int
nfs3svc_encode_createres(struct svc_rqst * rqstp,__be32 * p)773*4882a593Smuzhiyun nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
774*4882a593Smuzhiyun {
775*4882a593Smuzhiyun struct nfsd3_diropres *resp = rqstp->rq_resp;
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun *p++ = resp->status;
778*4882a593Smuzhiyun if (resp->status == 0) {
779*4882a593Smuzhiyun *p++ = xdr_one;
780*4882a593Smuzhiyun p = encode_fh(p, &resp->fh);
781*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->dirfh);
784*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun /* RENAME */
788*4882a593Smuzhiyun int
nfs3svc_encode_renameres(struct svc_rqst * rqstp,__be32 * p)789*4882a593Smuzhiyun nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
790*4882a593Smuzhiyun {
791*4882a593Smuzhiyun struct nfsd3_renameres *resp = rqstp->rq_resp;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun *p++ = resp->status;
794*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->ffh);
795*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->tfh);
796*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun /* LINK */
800*4882a593Smuzhiyun int
nfs3svc_encode_linkres(struct svc_rqst * rqstp,__be32 * p)801*4882a593Smuzhiyun nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun struct nfsd3_linkres *resp = rqstp->rq_resp;
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun *p++ = resp->status;
806*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
807*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->tfh);
808*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun /* READDIR */
812*4882a593Smuzhiyun int
nfs3svc_encode_readdirres(struct svc_rqst * rqstp,__be32 * p)813*4882a593Smuzhiyun nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun struct nfsd3_readdirres *resp = rqstp->rq_resp;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun *p++ = resp->status;
818*4882a593Smuzhiyun p = encode_post_op_attr(rqstp, p, &resp->fh);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun if (resp->status == 0) {
821*4882a593Smuzhiyun /* stupid readdir cookie */
822*4882a593Smuzhiyun memcpy(p, resp->verf, 8); p += 2;
823*4882a593Smuzhiyun xdr_ressize_check(rqstp, p);
824*4882a593Smuzhiyun if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
825*4882a593Smuzhiyun return 1; /*No room for trailer */
826*4882a593Smuzhiyun rqstp->rq_res.page_len = (resp->count) << 2;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun /* add the 'tail' to the end of the 'head' page - page 0. */
829*4882a593Smuzhiyun rqstp->rq_res.tail[0].iov_base = p;
830*4882a593Smuzhiyun *p++ = 0; /* no more entries */
831*4882a593Smuzhiyun *p++ = htonl(resp->common.err == nfserr_eof);
832*4882a593Smuzhiyun rqstp->rq_res.tail[0].iov_len = 2<<2;
833*4882a593Smuzhiyun return 1;
834*4882a593Smuzhiyun } else
835*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun static __be32 *
encode_entry_baggage(struct nfsd3_readdirres * cd,__be32 * p,const char * name,int namlen,u64 ino)839*4882a593Smuzhiyun encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
840*4882a593Smuzhiyun int namlen, u64 ino)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun *p++ = xdr_one; /* mark entry present */
843*4882a593Smuzhiyun p = xdr_encode_hyper(p, ino); /* file id */
844*4882a593Smuzhiyun p = xdr_encode_array(p, name, namlen);/* name length & name */
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun cd->offset = p; /* remember pointer */
847*4882a593Smuzhiyun p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun return p;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun static __be32
compose_entry_fh(struct nfsd3_readdirres * cd,struct svc_fh * fhp,const char * name,int namlen,u64 ino)853*4882a593Smuzhiyun compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
854*4882a593Smuzhiyun const char *name, int namlen, u64 ino)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun struct svc_export *exp;
857*4882a593Smuzhiyun struct dentry *dparent, *dchild;
858*4882a593Smuzhiyun __be32 rv = nfserr_noent;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun dparent = cd->fh.fh_dentry;
861*4882a593Smuzhiyun exp = cd->fh.fh_export;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun if (isdotent(name, namlen)) {
864*4882a593Smuzhiyun if (namlen == 2) {
865*4882a593Smuzhiyun dchild = dget_parent(dparent);
866*4882a593Smuzhiyun /*
867*4882a593Smuzhiyun * Don't return filehandle for ".." if we're at
868*4882a593Smuzhiyun * the filesystem or export root:
869*4882a593Smuzhiyun */
870*4882a593Smuzhiyun if (dchild == dparent)
871*4882a593Smuzhiyun goto out;
872*4882a593Smuzhiyun if (dparent == exp->ex_path.dentry)
873*4882a593Smuzhiyun goto out;
874*4882a593Smuzhiyun } else
875*4882a593Smuzhiyun dchild = dget(dparent);
876*4882a593Smuzhiyun } else
877*4882a593Smuzhiyun dchild = lookup_positive_unlocked(name, dparent, namlen);
878*4882a593Smuzhiyun if (IS_ERR(dchild))
879*4882a593Smuzhiyun return rv;
880*4882a593Smuzhiyun if (d_mountpoint(dchild))
881*4882a593Smuzhiyun goto out;
882*4882a593Smuzhiyun if (dchild->d_inode->i_ino != ino)
883*4882a593Smuzhiyun goto out;
884*4882a593Smuzhiyun rv = fh_compose(fhp, exp, dchild, &cd->fh);
885*4882a593Smuzhiyun out:
886*4882a593Smuzhiyun dput(dchild);
887*4882a593Smuzhiyun return rv;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun
encode_entryplus_baggage(struct nfsd3_readdirres * cd,__be32 * p,const char * name,int namlen,u64 ino)890*4882a593Smuzhiyun static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino)
891*4882a593Smuzhiyun {
892*4882a593Smuzhiyun struct svc_fh *fh = &cd->scratch;
893*4882a593Smuzhiyun __be32 err;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun fh_init(fh, NFS3_FHSIZE);
896*4882a593Smuzhiyun err = compose_entry_fh(cd, fh, name, namlen, ino);
897*4882a593Smuzhiyun if (err) {
898*4882a593Smuzhiyun *p++ = 0;
899*4882a593Smuzhiyun *p++ = 0;
900*4882a593Smuzhiyun goto out;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun p = encode_post_op_attr(cd->rqstp, p, fh);
903*4882a593Smuzhiyun *p++ = xdr_one; /* yes, a file handle follows */
904*4882a593Smuzhiyun p = encode_fh(p, fh);
905*4882a593Smuzhiyun out:
906*4882a593Smuzhiyun fh_put(fh);
907*4882a593Smuzhiyun return p;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun /*
911*4882a593Smuzhiyun * Encode a directory entry. This one works for both normal readdir
912*4882a593Smuzhiyun * and readdirplus.
913*4882a593Smuzhiyun * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
914*4882a593Smuzhiyun * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
915*4882a593Smuzhiyun *
916*4882a593Smuzhiyun * The readdirplus baggage is 1+21 words for post_op_attr, plus the
917*4882a593Smuzhiyun * file handle.
918*4882a593Smuzhiyun */
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
921*4882a593Smuzhiyun #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
922*4882a593Smuzhiyun static int
encode_entry(struct readdir_cd * ccd,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type,int plus)923*4882a593Smuzhiyun encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
924*4882a593Smuzhiyun loff_t offset, u64 ino, unsigned int d_type, int plus)
925*4882a593Smuzhiyun {
926*4882a593Smuzhiyun struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
927*4882a593Smuzhiyun common);
928*4882a593Smuzhiyun __be32 *p = cd->buffer;
929*4882a593Smuzhiyun caddr_t curr_page_addr = NULL;
930*4882a593Smuzhiyun struct page ** page;
931*4882a593Smuzhiyun int slen; /* string (name) length */
932*4882a593Smuzhiyun int elen; /* estimated entry length in words */
933*4882a593Smuzhiyun int num_entry_words = 0; /* actual number of words */
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun if (cd->offset) {
936*4882a593Smuzhiyun u64 offset64 = offset;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun if (unlikely(cd->offset1)) {
939*4882a593Smuzhiyun /* we ended up with offset on a page boundary */
940*4882a593Smuzhiyun *cd->offset = htonl(offset64 >> 32);
941*4882a593Smuzhiyun *cd->offset1 = htonl(offset64 & 0xffffffff);
942*4882a593Smuzhiyun cd->offset1 = NULL;
943*4882a593Smuzhiyun } else {
944*4882a593Smuzhiyun xdr_encode_hyper(cd->offset, offset64);
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun cd->offset = NULL;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun /*
950*4882a593Smuzhiyun dprintk("encode_entry(%.*s @%ld%s)\n",
951*4882a593Smuzhiyun namlen, name, (long) offset, plus? " plus" : "");
952*4882a593Smuzhiyun */
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun /* truncate filename if too long */
955*4882a593Smuzhiyun namlen = min(namlen, NFS3_MAXNAMLEN);
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun slen = XDR_QUADLEN(namlen);
958*4882a593Smuzhiyun elen = slen + NFS3_ENTRY_BAGGAGE
959*4882a593Smuzhiyun + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun if (cd->buflen < elen) {
962*4882a593Smuzhiyun cd->common.err = nfserr_toosmall;
963*4882a593Smuzhiyun return -EINVAL;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun /* determine which page in rq_respages[] we are currently filling */
967*4882a593Smuzhiyun for (page = cd->rqstp->rq_respages + 1;
968*4882a593Smuzhiyun page < cd->rqstp->rq_next_page; page++) {
969*4882a593Smuzhiyun curr_page_addr = page_address(*page);
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun if (((caddr_t)cd->buffer >= curr_page_addr) &&
972*4882a593Smuzhiyun ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE))
973*4882a593Smuzhiyun break;
974*4882a593Smuzhiyun }
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
977*4882a593Smuzhiyun /* encode entry in current page */
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun p = encode_entry_baggage(cd, p, name, namlen, ino);
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun if (plus)
982*4882a593Smuzhiyun p = encode_entryplus_baggage(cd, p, name, namlen, ino);
983*4882a593Smuzhiyun num_entry_words = p - cd->buffer;
984*4882a593Smuzhiyun } else if (*(page+1) != NULL) {
985*4882a593Smuzhiyun /* temporarily encode entry into next page, then move back to
986*4882a593Smuzhiyun * current and next page in rq_respages[] */
987*4882a593Smuzhiyun __be32 *p1, *tmp;
988*4882a593Smuzhiyun int len1, len2;
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun /* grab next page for temporary storage of entry */
991*4882a593Smuzhiyun p1 = tmp = page_address(*(page+1));
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun if (plus)
996*4882a593Smuzhiyun p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino);
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun /* determine entry word length and lengths to go in pages */
999*4882a593Smuzhiyun num_entry_words = p1 - tmp;
1000*4882a593Smuzhiyun len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
1001*4882a593Smuzhiyun if ((num_entry_words << 2) < len1) {
1002*4882a593Smuzhiyun /* the actual number of words in the entry is less
1003*4882a593Smuzhiyun * than elen and can still fit in the current page
1004*4882a593Smuzhiyun */
1005*4882a593Smuzhiyun memmove(p, tmp, num_entry_words << 2);
1006*4882a593Smuzhiyun p += num_entry_words;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /* update offset */
1009*4882a593Smuzhiyun cd->offset = cd->buffer + (cd->offset - tmp);
1010*4882a593Smuzhiyun } else {
1011*4882a593Smuzhiyun unsigned int offset_r = (cd->offset - tmp) << 2;
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun /* update pointer to offset location.
1014*4882a593Smuzhiyun * This is a 64bit quantity, so we need to
1015*4882a593Smuzhiyun * deal with 3 cases:
1016*4882a593Smuzhiyun * - entirely in first page
1017*4882a593Smuzhiyun * - entirely in second page
1018*4882a593Smuzhiyun * - 4 bytes in each page
1019*4882a593Smuzhiyun */
1020*4882a593Smuzhiyun if (offset_r + 8 <= len1) {
1021*4882a593Smuzhiyun cd->offset = p + (cd->offset - tmp);
1022*4882a593Smuzhiyun } else if (offset_r >= len1) {
1023*4882a593Smuzhiyun cd->offset -= len1 >> 2;
1024*4882a593Smuzhiyun } else {
1025*4882a593Smuzhiyun /* sitting on the fence */
1026*4882a593Smuzhiyun BUG_ON(offset_r != len1 - 4);
1027*4882a593Smuzhiyun cd->offset = p + (cd->offset - tmp);
1028*4882a593Smuzhiyun cd->offset1 = tmp;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun len2 = (num_entry_words << 2) - len1;
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun /* move from temp page to current and next pages */
1034*4882a593Smuzhiyun memmove(p, tmp, len1);
1035*4882a593Smuzhiyun memmove(tmp, (caddr_t)tmp+len1, len2);
1036*4882a593Smuzhiyun
1037*4882a593Smuzhiyun p = tmp + (len2 >> 2);
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun else {
1041*4882a593Smuzhiyun cd->common.err = nfserr_toosmall;
1042*4882a593Smuzhiyun return -EINVAL;
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun cd->buflen -= num_entry_words;
1046*4882a593Smuzhiyun cd->buffer = p;
1047*4882a593Smuzhiyun cd->common.err = nfs_ok;
1048*4882a593Smuzhiyun return 0;
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun int
nfs3svc_encode_entry(void * cd,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)1053*4882a593Smuzhiyun nfs3svc_encode_entry(void *cd, const char *name,
1054*4882a593Smuzhiyun int namlen, loff_t offset, u64 ino, unsigned int d_type)
1055*4882a593Smuzhiyun {
1056*4882a593Smuzhiyun return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun int
nfs3svc_encode_entry_plus(void * cd,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)1060*4882a593Smuzhiyun nfs3svc_encode_entry_plus(void *cd, const char *name,
1061*4882a593Smuzhiyun int namlen, loff_t offset, u64 ino,
1062*4882a593Smuzhiyun unsigned int d_type)
1063*4882a593Smuzhiyun {
1064*4882a593Smuzhiyun return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun /* FSSTAT */
1068*4882a593Smuzhiyun int
nfs3svc_encode_fsstatres(struct svc_rqst * rqstp,__be32 * p)1069*4882a593Smuzhiyun nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
1070*4882a593Smuzhiyun {
1071*4882a593Smuzhiyun struct nfsd3_fsstatres *resp = rqstp->rq_resp;
1072*4882a593Smuzhiyun struct kstatfs *s = &resp->stats;
1073*4882a593Smuzhiyun u64 bs = s->f_bsize;
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun *p++ = resp->status;
1076*4882a593Smuzhiyun *p++ = xdr_zero; /* no post_op_attr */
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun if (resp->status == 0) {
1079*4882a593Smuzhiyun p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
1080*4882a593Smuzhiyun p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
1081*4882a593Smuzhiyun p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
1082*4882a593Smuzhiyun p = xdr_encode_hyper(p, s->f_files); /* total inodes */
1083*4882a593Smuzhiyun p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
1084*4882a593Smuzhiyun p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
1085*4882a593Smuzhiyun *p++ = htonl(resp->invarsec); /* mean unchanged time */
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun /* FSINFO */
1091*4882a593Smuzhiyun int
nfs3svc_encode_fsinfores(struct svc_rqst * rqstp,__be32 * p)1092*4882a593Smuzhiyun nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun struct nfsd3_fsinfores *resp = rqstp->rq_resp;
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun *p++ = resp->status;
1097*4882a593Smuzhiyun *p++ = xdr_zero; /* no post_op_attr */
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun if (resp->status == 0) {
1100*4882a593Smuzhiyun *p++ = htonl(resp->f_rtmax);
1101*4882a593Smuzhiyun *p++ = htonl(resp->f_rtpref);
1102*4882a593Smuzhiyun *p++ = htonl(resp->f_rtmult);
1103*4882a593Smuzhiyun *p++ = htonl(resp->f_wtmax);
1104*4882a593Smuzhiyun *p++ = htonl(resp->f_wtpref);
1105*4882a593Smuzhiyun *p++ = htonl(resp->f_wtmult);
1106*4882a593Smuzhiyun *p++ = htonl(resp->f_dtpref);
1107*4882a593Smuzhiyun p = xdr_encode_hyper(p, resp->f_maxfilesize);
1108*4882a593Smuzhiyun *p++ = xdr_one;
1109*4882a593Smuzhiyun *p++ = xdr_zero;
1110*4882a593Smuzhiyun *p++ = htonl(resp->f_properties);
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun /* PATHCONF */
1117*4882a593Smuzhiyun int
nfs3svc_encode_pathconfres(struct svc_rqst * rqstp,__be32 * p)1118*4882a593Smuzhiyun nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p)
1119*4882a593Smuzhiyun {
1120*4882a593Smuzhiyun struct nfsd3_pathconfres *resp = rqstp->rq_resp;
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun *p++ = resp->status;
1123*4882a593Smuzhiyun *p++ = xdr_zero; /* no post_op_attr */
1124*4882a593Smuzhiyun
1125*4882a593Smuzhiyun if (resp->status == 0) {
1126*4882a593Smuzhiyun *p++ = htonl(resp->p_link_max);
1127*4882a593Smuzhiyun *p++ = htonl(resp->p_name_max);
1128*4882a593Smuzhiyun *p++ = htonl(resp->p_no_trunc);
1129*4882a593Smuzhiyun *p++ = htonl(resp->p_chown_restricted);
1130*4882a593Smuzhiyun *p++ = htonl(resp->p_case_insensitive);
1131*4882a593Smuzhiyun *p++ = htonl(resp->p_case_preserving);
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun /* COMMIT */
1138*4882a593Smuzhiyun int
nfs3svc_encode_commitres(struct svc_rqst * rqstp,__be32 * p)1139*4882a593Smuzhiyun nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
1140*4882a593Smuzhiyun {
1141*4882a593Smuzhiyun struct nfsd3_commitres *resp = rqstp->rq_resp;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun *p++ = resp->status;
1144*4882a593Smuzhiyun p = encode_wcc_data(rqstp, p, &resp->fh);
1145*4882a593Smuzhiyun /* Write verifier */
1146*4882a593Smuzhiyun if (resp->status == 0) {
1147*4882a593Smuzhiyun *p++ = resp->verf[0];
1148*4882a593Smuzhiyun *p++ = resp->verf[1];
1149*4882a593Smuzhiyun }
1150*4882a593Smuzhiyun return xdr_ressize_check(rqstp, p);
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun /*
1154*4882a593Smuzhiyun * XDR release functions
1155*4882a593Smuzhiyun */
1156*4882a593Smuzhiyun void
nfs3svc_release_fhandle(struct svc_rqst * rqstp)1157*4882a593Smuzhiyun nfs3svc_release_fhandle(struct svc_rqst *rqstp)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun struct nfsd3_attrstat *resp = rqstp->rq_resp;
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun fh_put(&resp->fh);
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun void
nfs3svc_release_fhandle2(struct svc_rqst * rqstp)1165*4882a593Smuzhiyun nfs3svc_release_fhandle2(struct svc_rqst *rqstp)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun struct nfsd3_fhandle_pair *resp = rqstp->rq_resp;
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun fh_put(&resp->fh1);
1170*4882a593Smuzhiyun fh_put(&resp->fh2);
1171*4882a593Smuzhiyun }
1172