1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/fs/nfs/nfs2xdr.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * XDR functions to encode/decode NFS RPC arguments and results.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 1992, 1993, 1994 Rick Sladkey
8*4882a593Smuzhiyun * Copyright (C) 1996 Olaf Kirch
9*4882a593Smuzhiyun * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
10*4882a593Smuzhiyun * FIFO's need special handling in NFSv2
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/param.h>
14*4882a593Smuzhiyun #include <linux/time.h>
15*4882a593Smuzhiyun #include <linux/mm.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <linux/string.h>
18*4882a593Smuzhiyun #include <linux/in.h>
19*4882a593Smuzhiyun #include <linux/pagemap.h>
20*4882a593Smuzhiyun #include <linux/proc_fs.h>
21*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
22*4882a593Smuzhiyun #include <linux/nfs.h>
23*4882a593Smuzhiyun #include <linux/nfs2.h>
24*4882a593Smuzhiyun #include <linux/nfs_fs.h>
25*4882a593Smuzhiyun #include "nfstrace.h"
26*4882a593Smuzhiyun #include "internal.h"
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #define NFSDBG_FACILITY NFSDBG_XDR
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* Mapping from NFS error code to "errno" error code. */
31*4882a593Smuzhiyun #define errno_NFSERR_IO EIO
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * Declare the space requirements for NFS arguments and replies as
35*4882a593Smuzhiyun * number of 32bit-words
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun #define NFS_fhandle_sz (8)
38*4882a593Smuzhiyun #define NFS_sattr_sz (8)
39*4882a593Smuzhiyun #define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
40*4882a593Smuzhiyun #define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
41*4882a593Smuzhiyun #define NFS_fattr_sz (17)
42*4882a593Smuzhiyun #define NFS_info_sz (5)
43*4882a593Smuzhiyun #define NFS_entry_sz (NFS_filename_sz+3)
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
46*4882a593Smuzhiyun #define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
47*4882a593Smuzhiyun #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
48*4882a593Smuzhiyun #define NFS_readlinkargs_sz (NFS_fhandle_sz)
49*4882a593Smuzhiyun #define NFS_readargs_sz (NFS_fhandle_sz+3)
50*4882a593Smuzhiyun #define NFS_writeargs_sz (NFS_fhandle_sz+4)
51*4882a593Smuzhiyun #define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
52*4882a593Smuzhiyun #define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
53*4882a593Smuzhiyun #define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
54*4882a593Smuzhiyun #define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
55*4882a593Smuzhiyun #define NFS_readdirargs_sz (NFS_fhandle_sz+2)
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define NFS_attrstat_sz (1+NFS_fattr_sz)
58*4882a593Smuzhiyun #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
59*4882a593Smuzhiyun #define NFS_readlinkres_sz (2+1)
60*4882a593Smuzhiyun #define NFS_readres_sz (1+NFS_fattr_sz+1+1)
61*4882a593Smuzhiyun #define NFS_writeres_sz (NFS_attrstat_sz)
62*4882a593Smuzhiyun #define NFS_stat_sz (1)
63*4882a593Smuzhiyun #define NFS_readdirres_sz (1+1)
64*4882a593Smuzhiyun #define NFS_statfsres_sz (1+NFS_info_sz)
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static int nfs_stat_to_errno(enum nfs_stat);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun * Encode/decode NFSv2 basic data types
70*4882a593Smuzhiyun *
71*4882a593Smuzhiyun * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
72*4882a593Smuzhiyun * "NFS: Network File System Protocol Specification".
73*4882a593Smuzhiyun *
74*4882a593Smuzhiyun * Not all basic data types have their own encoding and decoding
75*4882a593Smuzhiyun * functions. For run-time efficiency, some data types are encoded
76*4882a593Smuzhiyun * or decoded inline.
77*4882a593Smuzhiyun */
78*4882a593Smuzhiyun
rpc_userns(const struct rpc_clnt * clnt)79*4882a593Smuzhiyun static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun if (clnt && clnt->cl_cred)
82*4882a593Smuzhiyun return clnt->cl_cred->user_ns;
83*4882a593Smuzhiyun return &init_user_ns;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
rpc_rqst_userns(const struct rpc_rqst * rqstp)86*4882a593Smuzhiyun static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun if (rqstp->rq_task)
89*4882a593Smuzhiyun return rpc_userns(rqstp->rq_task->tk_client);
90*4882a593Smuzhiyun return &init_user_ns;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun * typedef opaque nfsdata<>;
95*4882a593Smuzhiyun */
decode_nfsdata(struct xdr_stream * xdr,struct nfs_pgio_res * result)96*4882a593Smuzhiyun static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun u32 recvd, count;
99*4882a593Smuzhiyun __be32 *p;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
102*4882a593Smuzhiyun if (unlikely(!p))
103*4882a593Smuzhiyun return -EIO;
104*4882a593Smuzhiyun count = be32_to_cpup(p);
105*4882a593Smuzhiyun recvd = xdr_read_pages(xdr, count);
106*4882a593Smuzhiyun if (unlikely(count > recvd))
107*4882a593Smuzhiyun goto out_cheating;
108*4882a593Smuzhiyun out:
109*4882a593Smuzhiyun result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
110*4882a593Smuzhiyun result->count = count;
111*4882a593Smuzhiyun return count;
112*4882a593Smuzhiyun out_cheating:
113*4882a593Smuzhiyun dprintk("NFS: server cheating in read result: "
114*4882a593Smuzhiyun "count %u > recvd %u\n", count, recvd);
115*4882a593Smuzhiyun count = recvd;
116*4882a593Smuzhiyun goto out;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * enum stat {
121*4882a593Smuzhiyun * NFS_OK = 0,
122*4882a593Smuzhiyun * NFSERR_PERM = 1,
123*4882a593Smuzhiyun * NFSERR_NOENT = 2,
124*4882a593Smuzhiyun * NFSERR_IO = 5,
125*4882a593Smuzhiyun * NFSERR_NXIO = 6,
126*4882a593Smuzhiyun * NFSERR_ACCES = 13,
127*4882a593Smuzhiyun * NFSERR_EXIST = 17,
128*4882a593Smuzhiyun * NFSERR_NODEV = 19,
129*4882a593Smuzhiyun * NFSERR_NOTDIR = 20,
130*4882a593Smuzhiyun * NFSERR_ISDIR = 21,
131*4882a593Smuzhiyun * NFSERR_FBIG = 27,
132*4882a593Smuzhiyun * NFSERR_NOSPC = 28,
133*4882a593Smuzhiyun * NFSERR_ROFS = 30,
134*4882a593Smuzhiyun * NFSERR_NAMETOOLONG = 63,
135*4882a593Smuzhiyun * NFSERR_NOTEMPTY = 66,
136*4882a593Smuzhiyun * NFSERR_DQUOT = 69,
137*4882a593Smuzhiyun * NFSERR_STALE = 70,
138*4882a593Smuzhiyun * NFSERR_WFLUSH = 99
139*4882a593Smuzhiyun * };
140*4882a593Smuzhiyun */
decode_stat(struct xdr_stream * xdr,enum nfs_stat * status)141*4882a593Smuzhiyun static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun __be32 *p;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
146*4882a593Smuzhiyun if (unlikely(!p))
147*4882a593Smuzhiyun return -EIO;
148*4882a593Smuzhiyun if (unlikely(*p != cpu_to_be32(NFS_OK)))
149*4882a593Smuzhiyun goto out_status;
150*4882a593Smuzhiyun *status = 0;
151*4882a593Smuzhiyun return 0;
152*4882a593Smuzhiyun out_status:
153*4882a593Smuzhiyun *status = be32_to_cpup(p);
154*4882a593Smuzhiyun trace_nfs_xdr_status(xdr, (int)*status);
155*4882a593Smuzhiyun return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /*
159*4882a593Smuzhiyun * 2.3.2. ftype
160*4882a593Smuzhiyun *
161*4882a593Smuzhiyun * enum ftype {
162*4882a593Smuzhiyun * NFNON = 0,
163*4882a593Smuzhiyun * NFREG = 1,
164*4882a593Smuzhiyun * NFDIR = 2,
165*4882a593Smuzhiyun * NFBLK = 3,
166*4882a593Smuzhiyun * NFCHR = 4,
167*4882a593Smuzhiyun * NFLNK = 5
168*4882a593Smuzhiyun * };
169*4882a593Smuzhiyun *
170*4882a593Smuzhiyun */
xdr_decode_ftype(__be32 * p,u32 * type)171*4882a593Smuzhiyun static __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun *type = be32_to_cpup(p++);
174*4882a593Smuzhiyun if (unlikely(*type > NF2FIFO))
175*4882a593Smuzhiyun *type = NFBAD;
176*4882a593Smuzhiyun return p;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun * 2.3.3. fhandle
181*4882a593Smuzhiyun *
182*4882a593Smuzhiyun * typedef opaque fhandle[FHSIZE];
183*4882a593Smuzhiyun */
encode_fhandle(struct xdr_stream * xdr,const struct nfs_fh * fh)184*4882a593Smuzhiyun static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun __be32 *p;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun p = xdr_reserve_space(xdr, NFS2_FHSIZE);
189*4882a593Smuzhiyun memcpy(p, fh->data, NFS2_FHSIZE);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
decode_fhandle(struct xdr_stream * xdr,struct nfs_fh * fh)192*4882a593Smuzhiyun static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun __be32 *p;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS2_FHSIZE);
197*4882a593Smuzhiyun if (unlikely(!p))
198*4882a593Smuzhiyun return -EIO;
199*4882a593Smuzhiyun fh->size = NFS2_FHSIZE;
200*4882a593Smuzhiyun memcpy(fh->data, p, NFS2_FHSIZE);
201*4882a593Smuzhiyun return 0;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun * 2.3.4. timeval
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * struct timeval {
208*4882a593Smuzhiyun * unsigned int seconds;
209*4882a593Smuzhiyun * unsigned int useconds;
210*4882a593Smuzhiyun * };
211*4882a593Smuzhiyun */
xdr_encode_time(__be32 * p,const struct timespec64 * timep)212*4882a593Smuzhiyun static __be32 *xdr_encode_time(__be32 *p, const struct timespec64 *timep)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun *p++ = cpu_to_be32((u32)timep->tv_sec);
215*4882a593Smuzhiyun if (timep->tv_nsec != 0)
216*4882a593Smuzhiyun *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
217*4882a593Smuzhiyun else
218*4882a593Smuzhiyun *p++ = cpu_to_be32(0);
219*4882a593Smuzhiyun return p;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /*
223*4882a593Smuzhiyun * Passing the invalid value useconds=1000000 is a Sun convention for
224*4882a593Smuzhiyun * "set to current server time". It's needed to make permissions checks
225*4882a593Smuzhiyun * for the "touch" program across v2 mounts to Solaris and Irix servers
226*4882a593Smuzhiyun * work correctly. See description of sattr in section 6.1 of "NFS
227*4882a593Smuzhiyun * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
228*4882a593Smuzhiyun */
xdr_encode_current_server_time(__be32 * p,const struct timespec64 * timep)229*4882a593Smuzhiyun static __be32 *xdr_encode_current_server_time(__be32 *p,
230*4882a593Smuzhiyun const struct timespec64 *timep)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun *p++ = cpu_to_be32(timep->tv_sec);
233*4882a593Smuzhiyun *p++ = cpu_to_be32(1000000);
234*4882a593Smuzhiyun return p;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
xdr_decode_time(__be32 * p,struct timespec64 * timep)237*4882a593Smuzhiyun static __be32 *xdr_decode_time(__be32 *p, struct timespec64 *timep)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun timep->tv_sec = be32_to_cpup(p++);
240*4882a593Smuzhiyun timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
241*4882a593Smuzhiyun return p;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun /*
245*4882a593Smuzhiyun * 2.3.5. fattr
246*4882a593Smuzhiyun *
247*4882a593Smuzhiyun * struct fattr {
248*4882a593Smuzhiyun * ftype type;
249*4882a593Smuzhiyun * unsigned int mode;
250*4882a593Smuzhiyun * unsigned int nlink;
251*4882a593Smuzhiyun * unsigned int uid;
252*4882a593Smuzhiyun * unsigned int gid;
253*4882a593Smuzhiyun * unsigned int size;
254*4882a593Smuzhiyun * unsigned int blocksize;
255*4882a593Smuzhiyun * unsigned int rdev;
256*4882a593Smuzhiyun * unsigned int blocks;
257*4882a593Smuzhiyun * unsigned int fsid;
258*4882a593Smuzhiyun * unsigned int fileid;
259*4882a593Smuzhiyun * timeval atime;
260*4882a593Smuzhiyun * timeval mtime;
261*4882a593Smuzhiyun * timeval ctime;
262*4882a593Smuzhiyun * };
263*4882a593Smuzhiyun *
264*4882a593Smuzhiyun */
decode_fattr(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)265*4882a593Smuzhiyun static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
266*4882a593Smuzhiyun struct user_namespace *userns)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun u32 rdev, type;
269*4882a593Smuzhiyun __be32 *p;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
272*4882a593Smuzhiyun if (unlikely(!p))
273*4882a593Smuzhiyun return -EIO;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun fattr->valid |= NFS_ATTR_FATTR_V2;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun p = xdr_decode_ftype(p, &type);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun fattr->mode = be32_to_cpup(p++);
280*4882a593Smuzhiyun fattr->nlink = be32_to_cpup(p++);
281*4882a593Smuzhiyun fattr->uid = make_kuid(userns, be32_to_cpup(p++));
282*4882a593Smuzhiyun if (!uid_valid(fattr->uid))
283*4882a593Smuzhiyun goto out_uid;
284*4882a593Smuzhiyun fattr->gid = make_kgid(userns, be32_to_cpup(p++));
285*4882a593Smuzhiyun if (!gid_valid(fattr->gid))
286*4882a593Smuzhiyun goto out_gid;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun fattr->size = be32_to_cpup(p++);
289*4882a593Smuzhiyun fattr->du.nfs2.blocksize = be32_to_cpup(p++);
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun rdev = be32_to_cpup(p++);
292*4882a593Smuzhiyun fattr->rdev = new_decode_dev(rdev);
293*4882a593Smuzhiyun if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
294*4882a593Smuzhiyun fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
295*4882a593Smuzhiyun fattr->rdev = 0;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun fattr->du.nfs2.blocks = be32_to_cpup(p++);
299*4882a593Smuzhiyun fattr->fsid.major = be32_to_cpup(p++);
300*4882a593Smuzhiyun fattr->fsid.minor = 0;
301*4882a593Smuzhiyun fattr->fileid = be32_to_cpup(p++);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun p = xdr_decode_time(p, &fattr->atime);
304*4882a593Smuzhiyun p = xdr_decode_time(p, &fattr->mtime);
305*4882a593Smuzhiyun xdr_decode_time(p, &fattr->ctime);
306*4882a593Smuzhiyun fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun return 0;
309*4882a593Smuzhiyun out_uid:
310*4882a593Smuzhiyun dprintk("NFS: returned invalid uid\n");
311*4882a593Smuzhiyun return -EINVAL;
312*4882a593Smuzhiyun out_gid:
313*4882a593Smuzhiyun dprintk("NFS: returned invalid gid\n");
314*4882a593Smuzhiyun return -EINVAL;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /*
318*4882a593Smuzhiyun * 2.3.6. sattr
319*4882a593Smuzhiyun *
320*4882a593Smuzhiyun * struct sattr {
321*4882a593Smuzhiyun * unsigned int mode;
322*4882a593Smuzhiyun * unsigned int uid;
323*4882a593Smuzhiyun * unsigned int gid;
324*4882a593Smuzhiyun * unsigned int size;
325*4882a593Smuzhiyun * timeval atime;
326*4882a593Smuzhiyun * timeval mtime;
327*4882a593Smuzhiyun * };
328*4882a593Smuzhiyun */
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun #define NFS2_SATTR_NOT_SET (0xffffffff)
331*4882a593Smuzhiyun
xdr_time_not_set(__be32 * p)332*4882a593Smuzhiyun static __be32 *xdr_time_not_set(__be32 *p)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
335*4882a593Smuzhiyun *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
336*4882a593Smuzhiyun return p;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
encode_sattr(struct xdr_stream * xdr,const struct iattr * attr,struct user_namespace * userns)339*4882a593Smuzhiyun static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr,
340*4882a593Smuzhiyun struct user_namespace *userns)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun __be32 *p;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (attr->ia_valid & ATTR_MODE)
347*4882a593Smuzhiyun *p++ = cpu_to_be32(attr->ia_mode);
348*4882a593Smuzhiyun else
349*4882a593Smuzhiyun *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
350*4882a593Smuzhiyun if (attr->ia_valid & ATTR_UID)
351*4882a593Smuzhiyun *p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
352*4882a593Smuzhiyun else
353*4882a593Smuzhiyun *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
354*4882a593Smuzhiyun if (attr->ia_valid & ATTR_GID)
355*4882a593Smuzhiyun *p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
356*4882a593Smuzhiyun else
357*4882a593Smuzhiyun *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
358*4882a593Smuzhiyun if (attr->ia_valid & ATTR_SIZE)
359*4882a593Smuzhiyun *p++ = cpu_to_be32((u32)attr->ia_size);
360*4882a593Smuzhiyun else
361*4882a593Smuzhiyun *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun if (attr->ia_valid & ATTR_ATIME_SET)
364*4882a593Smuzhiyun p = xdr_encode_time(p, &attr->ia_atime);
365*4882a593Smuzhiyun else if (attr->ia_valid & ATTR_ATIME)
366*4882a593Smuzhiyun p = xdr_encode_current_server_time(p, &attr->ia_atime);
367*4882a593Smuzhiyun else
368*4882a593Smuzhiyun p = xdr_time_not_set(p);
369*4882a593Smuzhiyun if (attr->ia_valid & ATTR_MTIME_SET)
370*4882a593Smuzhiyun xdr_encode_time(p, &attr->ia_mtime);
371*4882a593Smuzhiyun else if (attr->ia_valid & ATTR_MTIME)
372*4882a593Smuzhiyun xdr_encode_current_server_time(p, &attr->ia_mtime);
373*4882a593Smuzhiyun else
374*4882a593Smuzhiyun xdr_time_not_set(p);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun /*
378*4882a593Smuzhiyun * 2.3.7. filename
379*4882a593Smuzhiyun *
380*4882a593Smuzhiyun * typedef string filename<MAXNAMLEN>;
381*4882a593Smuzhiyun */
encode_filename(struct xdr_stream * xdr,const char * name,u32 length)382*4882a593Smuzhiyun static void encode_filename(struct xdr_stream *xdr,
383*4882a593Smuzhiyun const char *name, u32 length)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun __be32 *p;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
388*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + length);
389*4882a593Smuzhiyun xdr_encode_opaque(p, name, length);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
decode_filename_inline(struct xdr_stream * xdr,const char ** name,u32 * length)392*4882a593Smuzhiyun static int decode_filename_inline(struct xdr_stream *xdr,
393*4882a593Smuzhiyun const char **name, u32 *length)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun __be32 *p;
396*4882a593Smuzhiyun u32 count;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
399*4882a593Smuzhiyun if (unlikely(!p))
400*4882a593Smuzhiyun return -EIO;
401*4882a593Smuzhiyun count = be32_to_cpup(p);
402*4882a593Smuzhiyun if (count > NFS3_MAXNAMLEN)
403*4882a593Smuzhiyun goto out_nametoolong;
404*4882a593Smuzhiyun p = xdr_inline_decode(xdr, count);
405*4882a593Smuzhiyun if (unlikely(!p))
406*4882a593Smuzhiyun return -EIO;
407*4882a593Smuzhiyun *name = (const char *)p;
408*4882a593Smuzhiyun *length = count;
409*4882a593Smuzhiyun return 0;
410*4882a593Smuzhiyun out_nametoolong:
411*4882a593Smuzhiyun dprintk("NFS: returned filename too long: %u\n", count);
412*4882a593Smuzhiyun return -ENAMETOOLONG;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun /*
416*4882a593Smuzhiyun * 2.3.8. path
417*4882a593Smuzhiyun *
418*4882a593Smuzhiyun * typedef string path<MAXPATHLEN>;
419*4882a593Smuzhiyun */
encode_path(struct xdr_stream * xdr,struct page ** pages,u32 length)420*4882a593Smuzhiyun static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun __be32 *p;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4);
425*4882a593Smuzhiyun *p = cpu_to_be32(length);
426*4882a593Smuzhiyun xdr_write_pages(xdr, pages, 0, length);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
decode_path(struct xdr_stream * xdr)429*4882a593Smuzhiyun static int decode_path(struct xdr_stream *xdr)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun u32 length, recvd;
432*4882a593Smuzhiyun __be32 *p;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
435*4882a593Smuzhiyun if (unlikely(!p))
436*4882a593Smuzhiyun return -EIO;
437*4882a593Smuzhiyun length = be32_to_cpup(p);
438*4882a593Smuzhiyun if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
439*4882a593Smuzhiyun goto out_size;
440*4882a593Smuzhiyun recvd = xdr_read_pages(xdr, length);
441*4882a593Smuzhiyun if (unlikely(length > recvd))
442*4882a593Smuzhiyun goto out_cheating;
443*4882a593Smuzhiyun xdr_terminate_string(xdr->buf, length);
444*4882a593Smuzhiyun return 0;
445*4882a593Smuzhiyun out_size:
446*4882a593Smuzhiyun dprintk("NFS: returned pathname too long: %u\n", length);
447*4882a593Smuzhiyun return -ENAMETOOLONG;
448*4882a593Smuzhiyun out_cheating:
449*4882a593Smuzhiyun dprintk("NFS: server cheating in pathname result: "
450*4882a593Smuzhiyun "length %u > received %u\n", length, recvd);
451*4882a593Smuzhiyun return -EIO;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun * 2.3.9. attrstat
456*4882a593Smuzhiyun *
457*4882a593Smuzhiyun * union attrstat switch (stat status) {
458*4882a593Smuzhiyun * case NFS_OK:
459*4882a593Smuzhiyun * fattr attributes;
460*4882a593Smuzhiyun * default:
461*4882a593Smuzhiyun * void;
462*4882a593Smuzhiyun * };
463*4882a593Smuzhiyun */
decode_attrstat(struct xdr_stream * xdr,struct nfs_fattr * result,__u32 * op_status,struct user_namespace * userns)464*4882a593Smuzhiyun static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
465*4882a593Smuzhiyun __u32 *op_status,
466*4882a593Smuzhiyun struct user_namespace *userns)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun enum nfs_stat status;
469*4882a593Smuzhiyun int error;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun error = decode_stat(xdr, &status);
472*4882a593Smuzhiyun if (unlikely(error))
473*4882a593Smuzhiyun goto out;
474*4882a593Smuzhiyun if (op_status)
475*4882a593Smuzhiyun *op_status = status;
476*4882a593Smuzhiyun if (status != NFS_OK)
477*4882a593Smuzhiyun goto out_default;
478*4882a593Smuzhiyun error = decode_fattr(xdr, result, userns);
479*4882a593Smuzhiyun out:
480*4882a593Smuzhiyun return error;
481*4882a593Smuzhiyun out_default:
482*4882a593Smuzhiyun return nfs_stat_to_errno(status);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun * 2.3.10. diropargs
487*4882a593Smuzhiyun *
488*4882a593Smuzhiyun * struct diropargs {
489*4882a593Smuzhiyun * fhandle dir;
490*4882a593Smuzhiyun * filename name;
491*4882a593Smuzhiyun * };
492*4882a593Smuzhiyun */
encode_diropargs(struct xdr_stream * xdr,const struct nfs_fh * fh,const char * name,u32 length)493*4882a593Smuzhiyun static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
494*4882a593Smuzhiyun const char *name, u32 length)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun encode_fhandle(xdr, fh);
497*4882a593Smuzhiyun encode_filename(xdr, name, length);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun /*
501*4882a593Smuzhiyun * 2.3.11. diropres
502*4882a593Smuzhiyun *
503*4882a593Smuzhiyun * union diropres switch (stat status) {
504*4882a593Smuzhiyun * case NFS_OK:
505*4882a593Smuzhiyun * struct {
506*4882a593Smuzhiyun * fhandle file;
507*4882a593Smuzhiyun * fattr attributes;
508*4882a593Smuzhiyun * } diropok;
509*4882a593Smuzhiyun * default:
510*4882a593Smuzhiyun * void;
511*4882a593Smuzhiyun * };
512*4882a593Smuzhiyun */
decode_diropok(struct xdr_stream * xdr,struct nfs_diropok * result,struct user_namespace * userns)513*4882a593Smuzhiyun static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result,
514*4882a593Smuzhiyun struct user_namespace *userns)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun int error;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun error = decode_fhandle(xdr, result->fh);
519*4882a593Smuzhiyun if (unlikely(error))
520*4882a593Smuzhiyun goto out;
521*4882a593Smuzhiyun error = decode_fattr(xdr, result->fattr, userns);
522*4882a593Smuzhiyun out:
523*4882a593Smuzhiyun return error;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
decode_diropres(struct xdr_stream * xdr,struct nfs_diropok * result,struct user_namespace * userns)526*4882a593Smuzhiyun static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result,
527*4882a593Smuzhiyun struct user_namespace *userns)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun enum nfs_stat status;
530*4882a593Smuzhiyun int error;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun error = decode_stat(xdr, &status);
533*4882a593Smuzhiyun if (unlikely(error))
534*4882a593Smuzhiyun goto out;
535*4882a593Smuzhiyun if (status != NFS_OK)
536*4882a593Smuzhiyun goto out_default;
537*4882a593Smuzhiyun error = decode_diropok(xdr, result, userns);
538*4882a593Smuzhiyun out:
539*4882a593Smuzhiyun return error;
540*4882a593Smuzhiyun out_default:
541*4882a593Smuzhiyun return nfs_stat_to_errno(status);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun /*
546*4882a593Smuzhiyun * NFSv2 XDR encode functions
547*4882a593Smuzhiyun *
548*4882a593Smuzhiyun * NFSv2 argument types are defined in section 2.2 of RFC 1094:
549*4882a593Smuzhiyun * "NFS: Network File System Protocol Specification".
550*4882a593Smuzhiyun */
551*4882a593Smuzhiyun
nfs2_xdr_enc_fhandle(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)552*4882a593Smuzhiyun static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
553*4882a593Smuzhiyun struct xdr_stream *xdr,
554*4882a593Smuzhiyun const void *data)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun const struct nfs_fh *fh = data;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun encode_fhandle(xdr, fh);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /*
562*4882a593Smuzhiyun * 2.2.3. sattrargs
563*4882a593Smuzhiyun *
564*4882a593Smuzhiyun * struct sattrargs {
565*4882a593Smuzhiyun * fhandle file;
566*4882a593Smuzhiyun * sattr attributes;
567*4882a593Smuzhiyun * };
568*4882a593Smuzhiyun */
nfs2_xdr_enc_sattrargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)569*4882a593Smuzhiyun static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
570*4882a593Smuzhiyun struct xdr_stream *xdr,
571*4882a593Smuzhiyun const void *data)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun const struct nfs_sattrargs *args = data;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun encode_fhandle(xdr, args->fh);
576*4882a593Smuzhiyun encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
nfs2_xdr_enc_diropargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)579*4882a593Smuzhiyun static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
580*4882a593Smuzhiyun struct xdr_stream *xdr,
581*4882a593Smuzhiyun const void *data)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun const struct nfs_diropargs *args = data;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun encode_diropargs(xdr, args->fh, args->name, args->len);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
nfs2_xdr_enc_readlinkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)588*4882a593Smuzhiyun static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
589*4882a593Smuzhiyun struct xdr_stream *xdr,
590*4882a593Smuzhiyun const void *data)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun const struct nfs_readlinkargs *args = data;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun encode_fhandle(xdr, args->fh);
595*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, args->pgbase,
596*4882a593Smuzhiyun args->pglen, NFS_readlinkres_sz);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun /*
600*4882a593Smuzhiyun * 2.2.7. readargs
601*4882a593Smuzhiyun *
602*4882a593Smuzhiyun * struct readargs {
603*4882a593Smuzhiyun * fhandle file;
604*4882a593Smuzhiyun * unsigned offset;
605*4882a593Smuzhiyun * unsigned count;
606*4882a593Smuzhiyun * unsigned totalcount;
607*4882a593Smuzhiyun * };
608*4882a593Smuzhiyun */
encode_readargs(struct xdr_stream * xdr,const struct nfs_pgio_args * args)609*4882a593Smuzhiyun static void encode_readargs(struct xdr_stream *xdr,
610*4882a593Smuzhiyun const struct nfs_pgio_args *args)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun u32 offset = args->offset;
613*4882a593Smuzhiyun u32 count = args->count;
614*4882a593Smuzhiyun __be32 *p;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun encode_fhandle(xdr, args->fh);
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + 4 + 4);
619*4882a593Smuzhiyun *p++ = cpu_to_be32(offset);
620*4882a593Smuzhiyun *p++ = cpu_to_be32(count);
621*4882a593Smuzhiyun *p = cpu_to_be32(count);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
nfs2_xdr_enc_readargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)624*4882a593Smuzhiyun static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
625*4882a593Smuzhiyun struct xdr_stream *xdr,
626*4882a593Smuzhiyun const void *data)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun const struct nfs_pgio_args *args = data;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun encode_readargs(xdr, args);
631*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, args->pgbase,
632*4882a593Smuzhiyun args->count, NFS_readres_sz);
633*4882a593Smuzhiyun req->rq_rcv_buf.flags |= XDRBUF_READ;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun /*
637*4882a593Smuzhiyun * 2.2.9. writeargs
638*4882a593Smuzhiyun *
639*4882a593Smuzhiyun * struct writeargs {
640*4882a593Smuzhiyun * fhandle file;
641*4882a593Smuzhiyun * unsigned beginoffset;
642*4882a593Smuzhiyun * unsigned offset;
643*4882a593Smuzhiyun * unsigned totalcount;
644*4882a593Smuzhiyun * nfsdata data;
645*4882a593Smuzhiyun * };
646*4882a593Smuzhiyun */
encode_writeargs(struct xdr_stream * xdr,const struct nfs_pgio_args * args)647*4882a593Smuzhiyun static void encode_writeargs(struct xdr_stream *xdr,
648*4882a593Smuzhiyun const struct nfs_pgio_args *args)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun u32 offset = args->offset;
651*4882a593Smuzhiyun u32 count = args->count;
652*4882a593Smuzhiyun __be32 *p;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun encode_fhandle(xdr, args->fh);
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
657*4882a593Smuzhiyun *p++ = cpu_to_be32(offset);
658*4882a593Smuzhiyun *p++ = cpu_to_be32(offset);
659*4882a593Smuzhiyun *p++ = cpu_to_be32(count);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun /* nfsdata */
662*4882a593Smuzhiyun *p = cpu_to_be32(count);
663*4882a593Smuzhiyun xdr_write_pages(xdr, args->pages, args->pgbase, count);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
nfs2_xdr_enc_writeargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)666*4882a593Smuzhiyun static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
667*4882a593Smuzhiyun struct xdr_stream *xdr,
668*4882a593Smuzhiyun const void *data)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun const struct nfs_pgio_args *args = data;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun encode_writeargs(xdr, args);
673*4882a593Smuzhiyun xdr->buf->flags |= XDRBUF_WRITE;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun /*
677*4882a593Smuzhiyun * 2.2.10. createargs
678*4882a593Smuzhiyun *
679*4882a593Smuzhiyun * struct createargs {
680*4882a593Smuzhiyun * diropargs where;
681*4882a593Smuzhiyun * sattr attributes;
682*4882a593Smuzhiyun * };
683*4882a593Smuzhiyun */
nfs2_xdr_enc_createargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)684*4882a593Smuzhiyun static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
685*4882a593Smuzhiyun struct xdr_stream *xdr,
686*4882a593Smuzhiyun const void *data)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun const struct nfs_createargs *args = data;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun encode_diropargs(xdr, args->fh, args->name, args->len);
691*4882a593Smuzhiyun encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
nfs2_xdr_enc_removeargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)694*4882a593Smuzhiyun static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
695*4882a593Smuzhiyun struct xdr_stream *xdr,
696*4882a593Smuzhiyun const void *data)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun const struct nfs_removeargs *args = data;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun /*
704*4882a593Smuzhiyun * 2.2.12. renameargs
705*4882a593Smuzhiyun *
706*4882a593Smuzhiyun * struct renameargs {
707*4882a593Smuzhiyun * diropargs from;
708*4882a593Smuzhiyun * diropargs to;
709*4882a593Smuzhiyun * };
710*4882a593Smuzhiyun */
nfs2_xdr_enc_renameargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)711*4882a593Smuzhiyun static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
712*4882a593Smuzhiyun struct xdr_stream *xdr,
713*4882a593Smuzhiyun const void *data)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun const struct nfs_renameargs *args = data;
716*4882a593Smuzhiyun const struct qstr *old = args->old_name;
717*4882a593Smuzhiyun const struct qstr *new = args->new_name;
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun encode_diropargs(xdr, args->old_dir, old->name, old->len);
720*4882a593Smuzhiyun encode_diropargs(xdr, args->new_dir, new->name, new->len);
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun /*
724*4882a593Smuzhiyun * 2.2.13. linkargs
725*4882a593Smuzhiyun *
726*4882a593Smuzhiyun * struct linkargs {
727*4882a593Smuzhiyun * fhandle from;
728*4882a593Smuzhiyun * diropargs to;
729*4882a593Smuzhiyun * };
730*4882a593Smuzhiyun */
nfs2_xdr_enc_linkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)731*4882a593Smuzhiyun static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
732*4882a593Smuzhiyun struct xdr_stream *xdr,
733*4882a593Smuzhiyun const void *data)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun const struct nfs_linkargs *args = data;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun encode_fhandle(xdr, args->fromfh);
738*4882a593Smuzhiyun encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun /*
742*4882a593Smuzhiyun * 2.2.14. symlinkargs
743*4882a593Smuzhiyun *
744*4882a593Smuzhiyun * struct symlinkargs {
745*4882a593Smuzhiyun * diropargs from;
746*4882a593Smuzhiyun * path to;
747*4882a593Smuzhiyun * sattr attributes;
748*4882a593Smuzhiyun * };
749*4882a593Smuzhiyun */
nfs2_xdr_enc_symlinkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)750*4882a593Smuzhiyun static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
751*4882a593Smuzhiyun struct xdr_stream *xdr,
752*4882a593Smuzhiyun const void *data)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun const struct nfs_symlinkargs *args = data;
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
757*4882a593Smuzhiyun encode_path(xdr, args->pages, args->pathlen);
758*4882a593Smuzhiyun encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun /*
762*4882a593Smuzhiyun * 2.2.17. readdirargs
763*4882a593Smuzhiyun *
764*4882a593Smuzhiyun * struct readdirargs {
765*4882a593Smuzhiyun * fhandle dir;
766*4882a593Smuzhiyun * nfscookie cookie;
767*4882a593Smuzhiyun * unsigned count;
768*4882a593Smuzhiyun * };
769*4882a593Smuzhiyun */
encode_readdirargs(struct xdr_stream * xdr,const struct nfs_readdirargs * args)770*4882a593Smuzhiyun static void encode_readdirargs(struct xdr_stream *xdr,
771*4882a593Smuzhiyun const struct nfs_readdirargs *args)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun __be32 *p;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun encode_fhandle(xdr, args->fh);
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + 4);
778*4882a593Smuzhiyun *p++ = cpu_to_be32(args->cookie);
779*4882a593Smuzhiyun *p = cpu_to_be32(args->count);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
nfs2_xdr_enc_readdirargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)782*4882a593Smuzhiyun static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
783*4882a593Smuzhiyun struct xdr_stream *xdr,
784*4882a593Smuzhiyun const void *data)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun const struct nfs_readdirargs *args = data;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun encode_readdirargs(xdr, args);
789*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, 0,
790*4882a593Smuzhiyun args->count, NFS_readdirres_sz);
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun /*
794*4882a593Smuzhiyun * NFSv2 XDR decode functions
795*4882a593Smuzhiyun *
796*4882a593Smuzhiyun * NFSv2 result types are defined in section 2.2 of RFC 1094:
797*4882a593Smuzhiyun * "NFS: Network File System Protocol Specification".
798*4882a593Smuzhiyun */
799*4882a593Smuzhiyun
nfs2_xdr_dec_stat(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)800*4882a593Smuzhiyun static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
801*4882a593Smuzhiyun void *__unused)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun enum nfs_stat status;
804*4882a593Smuzhiyun int error;
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun error = decode_stat(xdr, &status);
807*4882a593Smuzhiyun if (unlikely(error))
808*4882a593Smuzhiyun goto out;
809*4882a593Smuzhiyun if (status != NFS_OK)
810*4882a593Smuzhiyun goto out_default;
811*4882a593Smuzhiyun out:
812*4882a593Smuzhiyun return error;
813*4882a593Smuzhiyun out_default:
814*4882a593Smuzhiyun return nfs_stat_to_errno(status);
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
nfs2_xdr_dec_attrstat(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)817*4882a593Smuzhiyun static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
818*4882a593Smuzhiyun void *result)
819*4882a593Smuzhiyun {
820*4882a593Smuzhiyun return decode_attrstat(xdr, result, NULL, rpc_rqst_userns(req));
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
nfs2_xdr_dec_diropres(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)823*4882a593Smuzhiyun static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
824*4882a593Smuzhiyun void *result)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun return decode_diropres(xdr, result, rpc_rqst_userns(req));
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun /*
830*4882a593Smuzhiyun * 2.2.6. readlinkres
831*4882a593Smuzhiyun *
832*4882a593Smuzhiyun * union readlinkres switch (stat status) {
833*4882a593Smuzhiyun * case NFS_OK:
834*4882a593Smuzhiyun * path data;
835*4882a593Smuzhiyun * default:
836*4882a593Smuzhiyun * void;
837*4882a593Smuzhiyun * };
838*4882a593Smuzhiyun */
nfs2_xdr_dec_readlinkres(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)839*4882a593Smuzhiyun static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
840*4882a593Smuzhiyun struct xdr_stream *xdr, void *__unused)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun enum nfs_stat status;
843*4882a593Smuzhiyun int error;
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun error = decode_stat(xdr, &status);
846*4882a593Smuzhiyun if (unlikely(error))
847*4882a593Smuzhiyun goto out;
848*4882a593Smuzhiyun if (status != NFS_OK)
849*4882a593Smuzhiyun goto out_default;
850*4882a593Smuzhiyun error = decode_path(xdr);
851*4882a593Smuzhiyun out:
852*4882a593Smuzhiyun return error;
853*4882a593Smuzhiyun out_default:
854*4882a593Smuzhiyun return nfs_stat_to_errno(status);
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun /*
858*4882a593Smuzhiyun * 2.2.7. readres
859*4882a593Smuzhiyun *
860*4882a593Smuzhiyun * union readres switch (stat status) {
861*4882a593Smuzhiyun * case NFS_OK:
862*4882a593Smuzhiyun * fattr attributes;
863*4882a593Smuzhiyun * nfsdata data;
864*4882a593Smuzhiyun * default:
865*4882a593Smuzhiyun * void;
866*4882a593Smuzhiyun * };
867*4882a593Smuzhiyun */
nfs2_xdr_dec_readres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)868*4882a593Smuzhiyun static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
869*4882a593Smuzhiyun void *data)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun struct nfs_pgio_res *result = data;
872*4882a593Smuzhiyun enum nfs_stat status;
873*4882a593Smuzhiyun int error;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun error = decode_stat(xdr, &status);
876*4882a593Smuzhiyun if (unlikely(error))
877*4882a593Smuzhiyun goto out;
878*4882a593Smuzhiyun result->op_status = status;
879*4882a593Smuzhiyun if (status != NFS_OK)
880*4882a593Smuzhiyun goto out_default;
881*4882a593Smuzhiyun error = decode_fattr(xdr, result->fattr, rpc_rqst_userns(req));
882*4882a593Smuzhiyun if (unlikely(error))
883*4882a593Smuzhiyun goto out;
884*4882a593Smuzhiyun error = decode_nfsdata(xdr, result);
885*4882a593Smuzhiyun out:
886*4882a593Smuzhiyun return error;
887*4882a593Smuzhiyun out_default:
888*4882a593Smuzhiyun return nfs_stat_to_errno(status);
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun
nfs2_xdr_dec_writeres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)891*4882a593Smuzhiyun static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
892*4882a593Smuzhiyun void *data)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun struct nfs_pgio_res *result = data;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun /* All NFSv2 writes are "file sync" writes */
897*4882a593Smuzhiyun result->verf->committed = NFS_FILE_SYNC;
898*4882a593Smuzhiyun return decode_attrstat(xdr, result->fattr, &result->op_status,
899*4882a593Smuzhiyun rpc_rqst_userns(req));
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun /**
903*4882a593Smuzhiyun * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
904*4882a593Smuzhiyun * the local page cache.
905*4882a593Smuzhiyun * @xdr: XDR stream where entry resides
906*4882a593Smuzhiyun * @entry: buffer to fill in with entry data
907*4882a593Smuzhiyun * @plus: boolean indicating whether this should be a readdirplus entry
908*4882a593Smuzhiyun *
909*4882a593Smuzhiyun * Returns zero if successful, otherwise a negative errno value is
910*4882a593Smuzhiyun * returned.
911*4882a593Smuzhiyun *
912*4882a593Smuzhiyun * This function is not invoked during READDIR reply decoding, but
913*4882a593Smuzhiyun * rather whenever an application invokes the getdents(2) system call
914*4882a593Smuzhiyun * on a directory already in our cache.
915*4882a593Smuzhiyun *
916*4882a593Smuzhiyun * 2.2.17. entry
917*4882a593Smuzhiyun *
918*4882a593Smuzhiyun * struct entry {
919*4882a593Smuzhiyun * unsigned fileid;
920*4882a593Smuzhiyun * filename name;
921*4882a593Smuzhiyun * nfscookie cookie;
922*4882a593Smuzhiyun * entry *nextentry;
923*4882a593Smuzhiyun * };
924*4882a593Smuzhiyun */
nfs2_decode_dirent(struct xdr_stream * xdr,struct nfs_entry * entry,bool plus)925*4882a593Smuzhiyun int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
926*4882a593Smuzhiyun bool plus)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun __be32 *p;
929*4882a593Smuzhiyun int error;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
932*4882a593Smuzhiyun if (unlikely(!p))
933*4882a593Smuzhiyun return -EAGAIN;
934*4882a593Smuzhiyun if (*p++ == xdr_zero) {
935*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
936*4882a593Smuzhiyun if (unlikely(!p))
937*4882a593Smuzhiyun return -EAGAIN;
938*4882a593Smuzhiyun if (*p++ == xdr_zero)
939*4882a593Smuzhiyun return -EAGAIN;
940*4882a593Smuzhiyun entry->eof = 1;
941*4882a593Smuzhiyun return -EBADCOOKIE;
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
945*4882a593Smuzhiyun if (unlikely(!p))
946*4882a593Smuzhiyun return -EAGAIN;
947*4882a593Smuzhiyun entry->ino = be32_to_cpup(p);
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun error = decode_filename_inline(xdr, &entry->name, &entry->len);
950*4882a593Smuzhiyun if (unlikely(error))
951*4882a593Smuzhiyun return -EAGAIN;
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun /*
954*4882a593Smuzhiyun * The type (size and byte order) of nfscookie isn't defined in
955*4882a593Smuzhiyun * RFC 1094. This implementation assumes that it's an XDR uint32.
956*4882a593Smuzhiyun */
957*4882a593Smuzhiyun entry->prev_cookie = entry->cookie;
958*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
959*4882a593Smuzhiyun if (unlikely(!p))
960*4882a593Smuzhiyun return -EAGAIN;
961*4882a593Smuzhiyun entry->cookie = be32_to_cpup(p);
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun entry->d_type = DT_UNKNOWN;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun return 0;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun /*
969*4882a593Smuzhiyun * 2.2.17. readdirres
970*4882a593Smuzhiyun *
971*4882a593Smuzhiyun * union readdirres switch (stat status) {
972*4882a593Smuzhiyun * case NFS_OK:
973*4882a593Smuzhiyun * struct {
974*4882a593Smuzhiyun * entry *entries;
975*4882a593Smuzhiyun * bool eof;
976*4882a593Smuzhiyun * } readdirok;
977*4882a593Smuzhiyun * default:
978*4882a593Smuzhiyun * void;
979*4882a593Smuzhiyun * };
980*4882a593Smuzhiyun *
981*4882a593Smuzhiyun * Read the directory contents into the page cache, but don't
982*4882a593Smuzhiyun * touch them. The actual decoding is done by nfs2_decode_dirent()
983*4882a593Smuzhiyun * during subsequent nfs_readdir() calls.
984*4882a593Smuzhiyun */
decode_readdirok(struct xdr_stream * xdr)985*4882a593Smuzhiyun static int decode_readdirok(struct xdr_stream *xdr)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun return xdr_read_pages(xdr, xdr->buf->page_len);
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
nfs2_xdr_dec_readdirres(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)990*4882a593Smuzhiyun static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
991*4882a593Smuzhiyun struct xdr_stream *xdr, void *__unused)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun enum nfs_stat status;
994*4882a593Smuzhiyun int error;
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun error = decode_stat(xdr, &status);
997*4882a593Smuzhiyun if (unlikely(error))
998*4882a593Smuzhiyun goto out;
999*4882a593Smuzhiyun if (status != NFS_OK)
1000*4882a593Smuzhiyun goto out_default;
1001*4882a593Smuzhiyun error = decode_readdirok(xdr);
1002*4882a593Smuzhiyun out:
1003*4882a593Smuzhiyun return error;
1004*4882a593Smuzhiyun out_default:
1005*4882a593Smuzhiyun return nfs_stat_to_errno(status);
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /*
1009*4882a593Smuzhiyun * 2.2.18. statfsres
1010*4882a593Smuzhiyun *
1011*4882a593Smuzhiyun * union statfsres (stat status) {
1012*4882a593Smuzhiyun * case NFS_OK:
1013*4882a593Smuzhiyun * struct {
1014*4882a593Smuzhiyun * unsigned tsize;
1015*4882a593Smuzhiyun * unsigned bsize;
1016*4882a593Smuzhiyun * unsigned blocks;
1017*4882a593Smuzhiyun * unsigned bfree;
1018*4882a593Smuzhiyun * unsigned bavail;
1019*4882a593Smuzhiyun * } info;
1020*4882a593Smuzhiyun * default:
1021*4882a593Smuzhiyun * void;
1022*4882a593Smuzhiyun * };
1023*4882a593Smuzhiyun */
decode_info(struct xdr_stream * xdr,struct nfs2_fsstat * result)1024*4882a593Smuzhiyun static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun __be32 *p;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1029*4882a593Smuzhiyun if (unlikely(!p))
1030*4882a593Smuzhiyun return -EIO;
1031*4882a593Smuzhiyun result->tsize = be32_to_cpup(p++);
1032*4882a593Smuzhiyun result->bsize = be32_to_cpup(p++);
1033*4882a593Smuzhiyun result->blocks = be32_to_cpup(p++);
1034*4882a593Smuzhiyun result->bfree = be32_to_cpup(p++);
1035*4882a593Smuzhiyun result->bavail = be32_to_cpup(p);
1036*4882a593Smuzhiyun return 0;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun
nfs2_xdr_dec_statfsres(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1039*4882a593Smuzhiyun static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
1040*4882a593Smuzhiyun void *result)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun enum nfs_stat status;
1043*4882a593Smuzhiyun int error;
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun error = decode_stat(xdr, &status);
1046*4882a593Smuzhiyun if (unlikely(error))
1047*4882a593Smuzhiyun goto out;
1048*4882a593Smuzhiyun if (status != NFS_OK)
1049*4882a593Smuzhiyun goto out_default;
1050*4882a593Smuzhiyun error = decode_info(xdr, result);
1051*4882a593Smuzhiyun out:
1052*4882a593Smuzhiyun return error;
1053*4882a593Smuzhiyun out_default:
1054*4882a593Smuzhiyun return nfs_stat_to_errno(status);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun /*
1059*4882a593Smuzhiyun * We need to translate between nfs status return values and
1060*4882a593Smuzhiyun * the local errno values which may not be the same.
1061*4882a593Smuzhiyun */
1062*4882a593Smuzhiyun static const struct {
1063*4882a593Smuzhiyun int stat;
1064*4882a593Smuzhiyun int errno;
1065*4882a593Smuzhiyun } nfs_errtbl[] = {
1066*4882a593Smuzhiyun { NFS_OK, 0 },
1067*4882a593Smuzhiyun { NFSERR_PERM, -EPERM },
1068*4882a593Smuzhiyun { NFSERR_NOENT, -ENOENT },
1069*4882a593Smuzhiyun { NFSERR_IO, -errno_NFSERR_IO},
1070*4882a593Smuzhiyun { NFSERR_NXIO, -ENXIO },
1071*4882a593Smuzhiyun /* { NFSERR_EAGAIN, -EAGAIN }, */
1072*4882a593Smuzhiyun { NFSERR_ACCES, -EACCES },
1073*4882a593Smuzhiyun { NFSERR_EXIST, -EEXIST },
1074*4882a593Smuzhiyun { NFSERR_XDEV, -EXDEV },
1075*4882a593Smuzhiyun { NFSERR_NODEV, -ENODEV },
1076*4882a593Smuzhiyun { NFSERR_NOTDIR, -ENOTDIR },
1077*4882a593Smuzhiyun { NFSERR_ISDIR, -EISDIR },
1078*4882a593Smuzhiyun { NFSERR_INVAL, -EINVAL },
1079*4882a593Smuzhiyun { NFSERR_FBIG, -EFBIG },
1080*4882a593Smuzhiyun { NFSERR_NOSPC, -ENOSPC },
1081*4882a593Smuzhiyun { NFSERR_ROFS, -EROFS },
1082*4882a593Smuzhiyun { NFSERR_MLINK, -EMLINK },
1083*4882a593Smuzhiyun { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
1084*4882a593Smuzhiyun { NFSERR_NOTEMPTY, -ENOTEMPTY },
1085*4882a593Smuzhiyun { NFSERR_DQUOT, -EDQUOT },
1086*4882a593Smuzhiyun { NFSERR_STALE, -ESTALE },
1087*4882a593Smuzhiyun { NFSERR_REMOTE, -EREMOTE },
1088*4882a593Smuzhiyun #ifdef EWFLUSH
1089*4882a593Smuzhiyun { NFSERR_WFLUSH, -EWFLUSH },
1090*4882a593Smuzhiyun #endif
1091*4882a593Smuzhiyun { NFSERR_BADHANDLE, -EBADHANDLE },
1092*4882a593Smuzhiyun { NFSERR_NOT_SYNC, -ENOTSYNC },
1093*4882a593Smuzhiyun { NFSERR_BAD_COOKIE, -EBADCOOKIE },
1094*4882a593Smuzhiyun { NFSERR_NOTSUPP, -ENOTSUPP },
1095*4882a593Smuzhiyun { NFSERR_TOOSMALL, -ETOOSMALL },
1096*4882a593Smuzhiyun { NFSERR_SERVERFAULT, -EREMOTEIO },
1097*4882a593Smuzhiyun { NFSERR_BADTYPE, -EBADTYPE },
1098*4882a593Smuzhiyun { NFSERR_JUKEBOX, -EJUKEBOX },
1099*4882a593Smuzhiyun { -1, -EIO }
1100*4882a593Smuzhiyun };
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun /**
1103*4882a593Smuzhiyun * nfs_stat_to_errno - convert an NFS status code to a local errno
1104*4882a593Smuzhiyun * @status: NFS status code to convert
1105*4882a593Smuzhiyun *
1106*4882a593Smuzhiyun * Returns a local errno value, or -EIO if the NFS status code is
1107*4882a593Smuzhiyun * not recognized. This function is used jointly by NFSv2 and NFSv3.
1108*4882a593Smuzhiyun */
nfs_stat_to_errno(enum nfs_stat status)1109*4882a593Smuzhiyun static int nfs_stat_to_errno(enum nfs_stat status)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun int i;
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun for (i = 0; nfs_errtbl[i].stat != -1; i++) {
1114*4882a593Smuzhiyun if (nfs_errtbl[i].stat == (int)status)
1115*4882a593Smuzhiyun return nfs_errtbl[i].errno;
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun dprintk("NFS: Unrecognized nfs status value: %u\n", status);
1118*4882a593Smuzhiyun return nfs_errtbl[i].errno;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun #define PROC(proc, argtype, restype, timer) \
1122*4882a593Smuzhiyun [NFSPROC_##proc] = { \
1123*4882a593Smuzhiyun .p_proc = NFSPROC_##proc, \
1124*4882a593Smuzhiyun .p_encode = nfs2_xdr_enc_##argtype, \
1125*4882a593Smuzhiyun .p_decode = nfs2_xdr_dec_##restype, \
1126*4882a593Smuzhiyun .p_arglen = NFS_##argtype##_sz, \
1127*4882a593Smuzhiyun .p_replen = NFS_##restype##_sz, \
1128*4882a593Smuzhiyun .p_timer = timer, \
1129*4882a593Smuzhiyun .p_statidx = NFSPROC_##proc, \
1130*4882a593Smuzhiyun .p_name = #proc, \
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun const struct rpc_procinfo nfs_procedures[] = {
1133*4882a593Smuzhiyun PROC(GETATTR, fhandle, attrstat, 1),
1134*4882a593Smuzhiyun PROC(SETATTR, sattrargs, attrstat, 0),
1135*4882a593Smuzhiyun PROC(LOOKUP, diropargs, diropres, 2),
1136*4882a593Smuzhiyun PROC(READLINK, readlinkargs, readlinkres, 3),
1137*4882a593Smuzhiyun PROC(READ, readargs, readres, 3),
1138*4882a593Smuzhiyun PROC(WRITE, writeargs, writeres, 4),
1139*4882a593Smuzhiyun PROC(CREATE, createargs, diropres, 0),
1140*4882a593Smuzhiyun PROC(REMOVE, removeargs, stat, 0),
1141*4882a593Smuzhiyun PROC(RENAME, renameargs, stat, 0),
1142*4882a593Smuzhiyun PROC(LINK, linkargs, stat, 0),
1143*4882a593Smuzhiyun PROC(SYMLINK, symlinkargs, stat, 0),
1144*4882a593Smuzhiyun PROC(MKDIR, createargs, diropres, 0),
1145*4882a593Smuzhiyun PROC(RMDIR, diropargs, stat, 0),
1146*4882a593Smuzhiyun PROC(READDIR, readdirargs, readdirres, 3),
1147*4882a593Smuzhiyun PROC(STATFS, fhandle, statfsres, 0),
1148*4882a593Smuzhiyun };
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun static unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
1151*4882a593Smuzhiyun const struct rpc_version nfs_version2 = {
1152*4882a593Smuzhiyun .number = 2,
1153*4882a593Smuzhiyun .nrprocs = ARRAY_SIZE(nfs_procedures),
1154*4882a593Smuzhiyun .procs = nfs_procedures,
1155*4882a593Smuzhiyun .counts = nfs_version2_counts,
1156*4882a593Smuzhiyun };
1157