1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/fs/nfs/nfs3xdr.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * XDR functions to encode/decode NFSv3 RPC arguments and results.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (C) 1996, 1997 Olaf Kirch
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/param.h>
11*4882a593Smuzhiyun #include <linux/time.h>
12*4882a593Smuzhiyun #include <linux/mm.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/string.h>
15*4882a593Smuzhiyun #include <linux/in.h>
16*4882a593Smuzhiyun #include <linux/pagemap.h>
17*4882a593Smuzhiyun #include <linux/proc_fs.h>
18*4882a593Smuzhiyun #include <linux/kdev_t.h>
19*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
20*4882a593Smuzhiyun #include <linux/nfs.h>
21*4882a593Smuzhiyun #include <linux/nfs3.h>
22*4882a593Smuzhiyun #include <linux/nfs_fs.h>
23*4882a593Smuzhiyun #include <linux/nfsacl.h>
24*4882a593Smuzhiyun #include "nfstrace.h"
25*4882a593Smuzhiyun #include "internal.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define NFSDBG_FACILITY NFSDBG_XDR
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /* Mapping from NFS error code to "errno" error code. */
30*4882a593Smuzhiyun #define errno_NFSERR_IO EIO
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun * Declare the space requirements for NFS arguments and replies as
34*4882a593Smuzhiyun * number of 32bit-words
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun #define NFS3_fhandle_sz (1+16)
37*4882a593Smuzhiyun #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
38*4882a593Smuzhiyun #define NFS3_post_op_fh_sz (1+NFS3_fh_sz)
39*4882a593Smuzhiyun #define NFS3_sattr_sz (15)
40*4882a593Smuzhiyun #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
41*4882a593Smuzhiyun #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
42*4882a593Smuzhiyun #define NFS3_fattr_sz (21)
43*4882a593Smuzhiyun #define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2)
44*4882a593Smuzhiyun #define NFS3_wcc_attr_sz (6)
45*4882a593Smuzhiyun #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
46*4882a593Smuzhiyun #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
47*4882a593Smuzhiyun #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
48*4882a593Smuzhiyun #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun #define NFS3_getattrargs_sz (NFS3_fh_sz)
51*4882a593Smuzhiyun #define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
52*4882a593Smuzhiyun #define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz)
53*4882a593Smuzhiyun #define NFS3_accessargs_sz (NFS3_fh_sz+1)
54*4882a593Smuzhiyun #define NFS3_readlinkargs_sz (NFS3_fh_sz)
55*4882a593Smuzhiyun #define NFS3_readargs_sz (NFS3_fh_sz+3)
56*4882a593Smuzhiyun #define NFS3_writeargs_sz (NFS3_fh_sz+5)
57*4882a593Smuzhiyun #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58*4882a593Smuzhiyun #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
59*4882a593Smuzhiyun #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
60*4882a593Smuzhiyun #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
61*4882a593Smuzhiyun #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
62*4882a593Smuzhiyun #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
63*4882a593Smuzhiyun #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
64*4882a593Smuzhiyun #define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
65*4882a593Smuzhiyun #define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
66*4882a593Smuzhiyun #define NFS3_commitargs_sz (NFS3_fh_sz+3)
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun #define NFS3_getattrres_sz (1+NFS3_fattr_sz)
69*4882a593Smuzhiyun #define NFS3_setattrres_sz (1+NFS3_wcc_data_sz)
70*4882a593Smuzhiyun #define NFS3_removeres_sz (NFS3_setattrres_sz)
71*4882a593Smuzhiyun #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
72*4882a593Smuzhiyun #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
73*4882a593Smuzhiyun #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1+1)
74*4882a593Smuzhiyun #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3+1)
75*4882a593Smuzhiyun #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
76*4882a593Smuzhiyun #define NFS3_createres_sz (1+NFS3_post_op_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
77*4882a593Smuzhiyun #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
78*4882a593Smuzhiyun #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
79*4882a593Smuzhiyun #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2+1)
80*4882a593Smuzhiyun #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
81*4882a593Smuzhiyun #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
82*4882a593Smuzhiyun #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
83*4882a593Smuzhiyun #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
86*4882a593Smuzhiyun #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
87*4882a593Smuzhiyun XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
88*4882a593Smuzhiyun #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
89*4882a593Smuzhiyun XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)+1)
90*4882a593Smuzhiyun #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static int nfs3_stat_to_errno(enum nfs_stat);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun * Map file type to S_IFMT bits
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun static const umode_t nfs_type2fmt[] = {
98*4882a593Smuzhiyun [NF3BAD] = 0,
99*4882a593Smuzhiyun [NF3REG] = S_IFREG,
100*4882a593Smuzhiyun [NF3DIR] = S_IFDIR,
101*4882a593Smuzhiyun [NF3BLK] = S_IFBLK,
102*4882a593Smuzhiyun [NF3CHR] = S_IFCHR,
103*4882a593Smuzhiyun [NF3LNK] = S_IFLNK,
104*4882a593Smuzhiyun [NF3SOCK] = S_IFSOCK,
105*4882a593Smuzhiyun [NF3FIFO] = S_IFIFO,
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
rpc_userns(const struct rpc_clnt * clnt)108*4882a593Smuzhiyun static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun if (clnt && clnt->cl_cred)
111*4882a593Smuzhiyun return clnt->cl_cred->user_ns;
112*4882a593Smuzhiyun return &init_user_ns;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
rpc_rqst_userns(const struct rpc_rqst * rqstp)115*4882a593Smuzhiyun static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun if (rqstp->rq_task)
118*4882a593Smuzhiyun return rpc_userns(rqstp->rq_task->tk_client);
119*4882a593Smuzhiyun return &init_user_ns;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /*
123*4882a593Smuzhiyun * Encode/decode NFSv3 basic data types
124*4882a593Smuzhiyun *
125*4882a593Smuzhiyun * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
126*4882a593Smuzhiyun * "NFS Version 3 Protocol Specification".
127*4882a593Smuzhiyun *
128*4882a593Smuzhiyun * Not all basic data types have their own encoding and decoding
129*4882a593Smuzhiyun * functions. For run-time efficiency, some data types are encoded
130*4882a593Smuzhiyun * or decoded inline.
131*4882a593Smuzhiyun */
132*4882a593Smuzhiyun
encode_uint32(struct xdr_stream * xdr,u32 value)133*4882a593Smuzhiyun static void encode_uint32(struct xdr_stream *xdr, u32 value)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun __be32 *p = xdr_reserve_space(xdr, 4);
136*4882a593Smuzhiyun *p = cpu_to_be32(value);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
decode_uint32(struct xdr_stream * xdr,u32 * value)139*4882a593Smuzhiyun static int decode_uint32(struct xdr_stream *xdr, u32 *value)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun __be32 *p;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
144*4882a593Smuzhiyun if (unlikely(!p))
145*4882a593Smuzhiyun return -EIO;
146*4882a593Smuzhiyun *value = be32_to_cpup(p);
147*4882a593Smuzhiyun return 0;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
decode_uint64(struct xdr_stream * xdr,u64 * value)150*4882a593Smuzhiyun static int decode_uint64(struct xdr_stream *xdr, u64 *value)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun __be32 *p;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 8);
155*4882a593Smuzhiyun if (unlikely(!p))
156*4882a593Smuzhiyun return -EIO;
157*4882a593Smuzhiyun xdr_decode_hyper(p, value);
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /*
162*4882a593Smuzhiyun * fileid3
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * typedef uint64 fileid3;
165*4882a593Smuzhiyun */
xdr_decode_fileid3(__be32 * p,u64 * fileid)166*4882a593Smuzhiyun static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun return xdr_decode_hyper(p, fileid);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
decode_fileid3(struct xdr_stream * xdr,u64 * fileid)171*4882a593Smuzhiyun static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun return decode_uint64(xdr, fileid);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /*
177*4882a593Smuzhiyun * filename3
178*4882a593Smuzhiyun *
179*4882a593Smuzhiyun * typedef string filename3<>;
180*4882a593Smuzhiyun */
encode_filename3(struct xdr_stream * xdr,const char * name,u32 length)181*4882a593Smuzhiyun static void encode_filename3(struct xdr_stream *xdr,
182*4882a593Smuzhiyun const char *name, u32 length)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun __be32 *p;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun WARN_ON_ONCE(length > NFS3_MAXNAMLEN);
187*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + length);
188*4882a593Smuzhiyun xdr_encode_opaque(p, name, length);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
decode_inline_filename3(struct xdr_stream * xdr,const char ** name,u32 * length)191*4882a593Smuzhiyun static int decode_inline_filename3(struct xdr_stream *xdr,
192*4882a593Smuzhiyun const char **name, u32 *length)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun __be32 *p;
195*4882a593Smuzhiyun u32 count;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
198*4882a593Smuzhiyun if (unlikely(!p))
199*4882a593Smuzhiyun return -EIO;
200*4882a593Smuzhiyun count = be32_to_cpup(p);
201*4882a593Smuzhiyun if (count > NFS3_MAXNAMLEN)
202*4882a593Smuzhiyun goto out_nametoolong;
203*4882a593Smuzhiyun p = xdr_inline_decode(xdr, count);
204*4882a593Smuzhiyun if (unlikely(!p))
205*4882a593Smuzhiyun return -EIO;
206*4882a593Smuzhiyun *name = (const char *)p;
207*4882a593Smuzhiyun *length = count;
208*4882a593Smuzhiyun return 0;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun out_nametoolong:
211*4882a593Smuzhiyun dprintk("NFS: returned filename too long: %u\n", count);
212*4882a593Smuzhiyun return -ENAMETOOLONG;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /*
216*4882a593Smuzhiyun * nfspath3
217*4882a593Smuzhiyun *
218*4882a593Smuzhiyun * typedef string nfspath3<>;
219*4882a593Smuzhiyun */
encode_nfspath3(struct xdr_stream * xdr,struct page ** pages,const u32 length)220*4882a593Smuzhiyun static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
221*4882a593Smuzhiyun const u32 length)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun encode_uint32(xdr, length);
224*4882a593Smuzhiyun xdr_write_pages(xdr, pages, 0, length);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
decode_nfspath3(struct xdr_stream * xdr)227*4882a593Smuzhiyun static int decode_nfspath3(struct xdr_stream *xdr)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun u32 recvd, count;
230*4882a593Smuzhiyun __be32 *p;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
233*4882a593Smuzhiyun if (unlikely(!p))
234*4882a593Smuzhiyun return -EIO;
235*4882a593Smuzhiyun count = be32_to_cpup(p);
236*4882a593Smuzhiyun if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
237*4882a593Smuzhiyun goto out_nametoolong;
238*4882a593Smuzhiyun recvd = xdr_read_pages(xdr, count);
239*4882a593Smuzhiyun if (unlikely(count > recvd))
240*4882a593Smuzhiyun goto out_cheating;
241*4882a593Smuzhiyun xdr_terminate_string(xdr->buf, count);
242*4882a593Smuzhiyun return 0;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun out_nametoolong:
245*4882a593Smuzhiyun dprintk("NFS: returned pathname too long: %u\n", count);
246*4882a593Smuzhiyun return -ENAMETOOLONG;
247*4882a593Smuzhiyun out_cheating:
248*4882a593Smuzhiyun dprintk("NFS: server cheating in pathname result: "
249*4882a593Smuzhiyun "count %u > recvd %u\n", count, recvd);
250*4882a593Smuzhiyun return -EIO;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /*
254*4882a593Smuzhiyun * cookie3
255*4882a593Smuzhiyun *
256*4882a593Smuzhiyun * typedef uint64 cookie3
257*4882a593Smuzhiyun */
xdr_encode_cookie3(__be32 * p,u64 cookie)258*4882a593Smuzhiyun static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun return xdr_encode_hyper(p, cookie);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
decode_cookie3(struct xdr_stream * xdr,u64 * cookie)263*4882a593Smuzhiyun static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun return decode_uint64(xdr, cookie);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /*
269*4882a593Smuzhiyun * cookieverf3
270*4882a593Smuzhiyun *
271*4882a593Smuzhiyun * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
272*4882a593Smuzhiyun */
xdr_encode_cookieverf3(__be32 * p,const __be32 * verifier)273*4882a593Smuzhiyun static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
276*4882a593Smuzhiyun return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
decode_cookieverf3(struct xdr_stream * xdr,__be32 * verifier)279*4882a593Smuzhiyun static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun __be32 *p;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
284*4882a593Smuzhiyun if (unlikely(!p))
285*4882a593Smuzhiyun return -EIO;
286*4882a593Smuzhiyun memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
287*4882a593Smuzhiyun return 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /*
291*4882a593Smuzhiyun * createverf3
292*4882a593Smuzhiyun *
293*4882a593Smuzhiyun * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
294*4882a593Smuzhiyun */
encode_createverf3(struct xdr_stream * xdr,const __be32 * verifier)295*4882a593Smuzhiyun static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun __be32 *p;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
300*4882a593Smuzhiyun memcpy(p, verifier, NFS3_CREATEVERFSIZE);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
decode_writeverf3(struct xdr_stream * xdr,struct nfs_write_verifier * verifier)303*4882a593Smuzhiyun static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun __be32 *p;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
308*4882a593Smuzhiyun if (unlikely(!p))
309*4882a593Smuzhiyun return -EIO;
310*4882a593Smuzhiyun memcpy(verifier->data, p, NFS3_WRITEVERFSIZE);
311*4882a593Smuzhiyun return 0;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /*
315*4882a593Smuzhiyun * size3
316*4882a593Smuzhiyun *
317*4882a593Smuzhiyun * typedef uint64 size3;
318*4882a593Smuzhiyun */
xdr_decode_size3(__be32 * p,u64 * size)319*4882a593Smuzhiyun static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun return xdr_decode_hyper(p, size);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /*
325*4882a593Smuzhiyun * nfsstat3
326*4882a593Smuzhiyun *
327*4882a593Smuzhiyun * enum nfsstat3 {
328*4882a593Smuzhiyun * NFS3_OK = 0,
329*4882a593Smuzhiyun * ...
330*4882a593Smuzhiyun * }
331*4882a593Smuzhiyun */
332*4882a593Smuzhiyun #define NFS3_OK NFS_OK
333*4882a593Smuzhiyun
decode_nfsstat3(struct xdr_stream * xdr,enum nfs_stat * status)334*4882a593Smuzhiyun static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun __be32 *p;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
339*4882a593Smuzhiyun if (unlikely(!p))
340*4882a593Smuzhiyun return -EIO;
341*4882a593Smuzhiyun if (unlikely(*p != cpu_to_be32(NFS3_OK)))
342*4882a593Smuzhiyun goto out_status;
343*4882a593Smuzhiyun *status = 0;
344*4882a593Smuzhiyun return 0;
345*4882a593Smuzhiyun out_status:
346*4882a593Smuzhiyun *status = be32_to_cpup(p);
347*4882a593Smuzhiyun trace_nfs_xdr_status(xdr, (int)*status);
348*4882a593Smuzhiyun return 0;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /*
352*4882a593Smuzhiyun * ftype3
353*4882a593Smuzhiyun *
354*4882a593Smuzhiyun * enum ftype3 {
355*4882a593Smuzhiyun * NF3REG = 1,
356*4882a593Smuzhiyun * NF3DIR = 2,
357*4882a593Smuzhiyun * NF3BLK = 3,
358*4882a593Smuzhiyun * NF3CHR = 4,
359*4882a593Smuzhiyun * NF3LNK = 5,
360*4882a593Smuzhiyun * NF3SOCK = 6,
361*4882a593Smuzhiyun * NF3FIFO = 7
362*4882a593Smuzhiyun * };
363*4882a593Smuzhiyun */
encode_ftype3(struct xdr_stream * xdr,const u32 type)364*4882a593Smuzhiyun static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun encode_uint32(xdr, type);
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
xdr_decode_ftype3(__be32 * p,umode_t * mode)369*4882a593Smuzhiyun static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun u32 type;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun type = be32_to_cpup(p++);
374*4882a593Smuzhiyun if (type > NF3FIFO)
375*4882a593Smuzhiyun type = NF3NON;
376*4882a593Smuzhiyun *mode = nfs_type2fmt[type];
377*4882a593Smuzhiyun return p;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /*
381*4882a593Smuzhiyun * specdata3
382*4882a593Smuzhiyun *
383*4882a593Smuzhiyun * struct specdata3 {
384*4882a593Smuzhiyun * uint32 specdata1;
385*4882a593Smuzhiyun * uint32 specdata2;
386*4882a593Smuzhiyun * };
387*4882a593Smuzhiyun */
encode_specdata3(struct xdr_stream * xdr,const dev_t rdev)388*4882a593Smuzhiyun static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun __be32 *p;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 8);
393*4882a593Smuzhiyun *p++ = cpu_to_be32(MAJOR(rdev));
394*4882a593Smuzhiyun *p = cpu_to_be32(MINOR(rdev));
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
xdr_decode_specdata3(__be32 * p,dev_t * rdev)397*4882a593Smuzhiyun static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun unsigned int major, minor;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun major = be32_to_cpup(p++);
402*4882a593Smuzhiyun minor = be32_to_cpup(p++);
403*4882a593Smuzhiyun *rdev = MKDEV(major, minor);
404*4882a593Smuzhiyun if (MAJOR(*rdev) != major || MINOR(*rdev) != minor)
405*4882a593Smuzhiyun *rdev = 0;
406*4882a593Smuzhiyun return p;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /*
410*4882a593Smuzhiyun * nfs_fh3
411*4882a593Smuzhiyun *
412*4882a593Smuzhiyun * struct nfs_fh3 {
413*4882a593Smuzhiyun * opaque data<NFS3_FHSIZE>;
414*4882a593Smuzhiyun * };
415*4882a593Smuzhiyun */
encode_nfs_fh3(struct xdr_stream * xdr,const struct nfs_fh * fh)416*4882a593Smuzhiyun static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun __be32 *p;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun WARN_ON_ONCE(fh->size > NFS3_FHSIZE);
421*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + fh->size);
422*4882a593Smuzhiyun xdr_encode_opaque(p, fh->data, fh->size);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
decode_nfs_fh3(struct xdr_stream * xdr,struct nfs_fh * fh)425*4882a593Smuzhiyun static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun u32 length;
428*4882a593Smuzhiyun __be32 *p;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
431*4882a593Smuzhiyun if (unlikely(!p))
432*4882a593Smuzhiyun return -EIO;
433*4882a593Smuzhiyun length = be32_to_cpup(p++);
434*4882a593Smuzhiyun if (unlikely(length > NFS3_FHSIZE))
435*4882a593Smuzhiyun goto out_toobig;
436*4882a593Smuzhiyun p = xdr_inline_decode(xdr, length);
437*4882a593Smuzhiyun if (unlikely(!p))
438*4882a593Smuzhiyun return -EIO;
439*4882a593Smuzhiyun fh->size = length;
440*4882a593Smuzhiyun memcpy(fh->data, p, length);
441*4882a593Smuzhiyun return 0;
442*4882a593Smuzhiyun out_toobig:
443*4882a593Smuzhiyun dprintk("NFS: file handle size (%u) too big\n", length);
444*4882a593Smuzhiyun return -E2BIG;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
zero_nfs_fh3(struct nfs_fh * fh)447*4882a593Smuzhiyun static void zero_nfs_fh3(struct nfs_fh *fh)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun memset(fh, 0, sizeof(*fh));
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /*
453*4882a593Smuzhiyun * nfstime3
454*4882a593Smuzhiyun *
455*4882a593Smuzhiyun * struct nfstime3 {
456*4882a593Smuzhiyun * uint32 seconds;
457*4882a593Smuzhiyun * uint32 nseconds;
458*4882a593Smuzhiyun * };
459*4882a593Smuzhiyun */
xdr_encode_nfstime3(__be32 * p,const struct timespec64 * timep)460*4882a593Smuzhiyun static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec64 *timep)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun *p++ = cpu_to_be32((u32)timep->tv_sec);
463*4882a593Smuzhiyun *p++ = cpu_to_be32(timep->tv_nsec);
464*4882a593Smuzhiyun return p;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
xdr_decode_nfstime3(__be32 * p,struct timespec64 * timep)467*4882a593Smuzhiyun static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec64 *timep)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun timep->tv_sec = be32_to_cpup(p++);
470*4882a593Smuzhiyun timep->tv_nsec = be32_to_cpup(p++);
471*4882a593Smuzhiyun return p;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun /*
475*4882a593Smuzhiyun * sattr3
476*4882a593Smuzhiyun *
477*4882a593Smuzhiyun * enum time_how {
478*4882a593Smuzhiyun * DONT_CHANGE = 0,
479*4882a593Smuzhiyun * SET_TO_SERVER_TIME = 1,
480*4882a593Smuzhiyun * SET_TO_CLIENT_TIME = 2
481*4882a593Smuzhiyun * };
482*4882a593Smuzhiyun *
483*4882a593Smuzhiyun * union set_mode3 switch (bool set_it) {
484*4882a593Smuzhiyun * case TRUE:
485*4882a593Smuzhiyun * mode3 mode;
486*4882a593Smuzhiyun * default:
487*4882a593Smuzhiyun * void;
488*4882a593Smuzhiyun * };
489*4882a593Smuzhiyun *
490*4882a593Smuzhiyun * union set_uid3 switch (bool set_it) {
491*4882a593Smuzhiyun * case TRUE:
492*4882a593Smuzhiyun * uid3 uid;
493*4882a593Smuzhiyun * default:
494*4882a593Smuzhiyun * void;
495*4882a593Smuzhiyun * };
496*4882a593Smuzhiyun *
497*4882a593Smuzhiyun * union set_gid3 switch (bool set_it) {
498*4882a593Smuzhiyun * case TRUE:
499*4882a593Smuzhiyun * gid3 gid;
500*4882a593Smuzhiyun * default:
501*4882a593Smuzhiyun * void;
502*4882a593Smuzhiyun * };
503*4882a593Smuzhiyun *
504*4882a593Smuzhiyun * union set_size3 switch (bool set_it) {
505*4882a593Smuzhiyun * case TRUE:
506*4882a593Smuzhiyun * size3 size;
507*4882a593Smuzhiyun * default:
508*4882a593Smuzhiyun * void;
509*4882a593Smuzhiyun * };
510*4882a593Smuzhiyun *
511*4882a593Smuzhiyun * union set_atime switch (time_how set_it) {
512*4882a593Smuzhiyun * case SET_TO_CLIENT_TIME:
513*4882a593Smuzhiyun * nfstime3 atime;
514*4882a593Smuzhiyun * default:
515*4882a593Smuzhiyun * void;
516*4882a593Smuzhiyun * };
517*4882a593Smuzhiyun *
518*4882a593Smuzhiyun * union set_mtime switch (time_how set_it) {
519*4882a593Smuzhiyun * case SET_TO_CLIENT_TIME:
520*4882a593Smuzhiyun * nfstime3 mtime;
521*4882a593Smuzhiyun * default:
522*4882a593Smuzhiyun * void;
523*4882a593Smuzhiyun * };
524*4882a593Smuzhiyun *
525*4882a593Smuzhiyun * struct sattr3 {
526*4882a593Smuzhiyun * set_mode3 mode;
527*4882a593Smuzhiyun * set_uid3 uid;
528*4882a593Smuzhiyun * set_gid3 gid;
529*4882a593Smuzhiyun * set_size3 size;
530*4882a593Smuzhiyun * set_atime atime;
531*4882a593Smuzhiyun * set_mtime mtime;
532*4882a593Smuzhiyun * };
533*4882a593Smuzhiyun */
encode_sattr3(struct xdr_stream * xdr,const struct iattr * attr,struct user_namespace * userns)534*4882a593Smuzhiyun static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr,
535*4882a593Smuzhiyun struct user_namespace *userns)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun u32 nbytes;
538*4882a593Smuzhiyun __be32 *p;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /*
541*4882a593Smuzhiyun * In order to make only a single xdr_reserve_space() call,
542*4882a593Smuzhiyun * pre-compute the total number of bytes to be reserved.
543*4882a593Smuzhiyun * Six boolean values, one for each set_foo field, are always
544*4882a593Smuzhiyun * present in the encoded result, so start there.
545*4882a593Smuzhiyun */
546*4882a593Smuzhiyun nbytes = 6 * 4;
547*4882a593Smuzhiyun if (attr->ia_valid & ATTR_MODE)
548*4882a593Smuzhiyun nbytes += 4;
549*4882a593Smuzhiyun if (attr->ia_valid & ATTR_UID)
550*4882a593Smuzhiyun nbytes += 4;
551*4882a593Smuzhiyun if (attr->ia_valid & ATTR_GID)
552*4882a593Smuzhiyun nbytes += 4;
553*4882a593Smuzhiyun if (attr->ia_valid & ATTR_SIZE)
554*4882a593Smuzhiyun nbytes += 8;
555*4882a593Smuzhiyun if (attr->ia_valid & ATTR_ATIME_SET)
556*4882a593Smuzhiyun nbytes += 8;
557*4882a593Smuzhiyun if (attr->ia_valid & ATTR_MTIME_SET)
558*4882a593Smuzhiyun nbytes += 8;
559*4882a593Smuzhiyun p = xdr_reserve_space(xdr, nbytes);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun if (attr->ia_valid & ATTR_MODE) {
562*4882a593Smuzhiyun *p++ = xdr_one;
563*4882a593Smuzhiyun *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
564*4882a593Smuzhiyun } else
565*4882a593Smuzhiyun *p++ = xdr_zero;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun if (attr->ia_valid & ATTR_UID) {
568*4882a593Smuzhiyun *p++ = xdr_one;
569*4882a593Smuzhiyun *p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
570*4882a593Smuzhiyun } else
571*4882a593Smuzhiyun *p++ = xdr_zero;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun if (attr->ia_valid & ATTR_GID) {
574*4882a593Smuzhiyun *p++ = xdr_one;
575*4882a593Smuzhiyun *p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
576*4882a593Smuzhiyun } else
577*4882a593Smuzhiyun *p++ = xdr_zero;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun if (attr->ia_valid & ATTR_SIZE) {
580*4882a593Smuzhiyun *p++ = xdr_one;
581*4882a593Smuzhiyun p = xdr_encode_hyper(p, (u64)attr->ia_size);
582*4882a593Smuzhiyun } else
583*4882a593Smuzhiyun *p++ = xdr_zero;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (attr->ia_valid & ATTR_ATIME_SET) {
586*4882a593Smuzhiyun *p++ = xdr_two;
587*4882a593Smuzhiyun p = xdr_encode_nfstime3(p, &attr->ia_atime);
588*4882a593Smuzhiyun } else if (attr->ia_valid & ATTR_ATIME) {
589*4882a593Smuzhiyun *p++ = xdr_one;
590*4882a593Smuzhiyun } else
591*4882a593Smuzhiyun *p++ = xdr_zero;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (attr->ia_valid & ATTR_MTIME_SET) {
594*4882a593Smuzhiyun *p++ = xdr_two;
595*4882a593Smuzhiyun xdr_encode_nfstime3(p, &attr->ia_mtime);
596*4882a593Smuzhiyun } else if (attr->ia_valid & ATTR_MTIME) {
597*4882a593Smuzhiyun *p = xdr_one;
598*4882a593Smuzhiyun } else
599*4882a593Smuzhiyun *p = xdr_zero;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /*
603*4882a593Smuzhiyun * fattr3
604*4882a593Smuzhiyun *
605*4882a593Smuzhiyun * struct fattr3 {
606*4882a593Smuzhiyun * ftype3 type;
607*4882a593Smuzhiyun * mode3 mode;
608*4882a593Smuzhiyun * uint32 nlink;
609*4882a593Smuzhiyun * uid3 uid;
610*4882a593Smuzhiyun * gid3 gid;
611*4882a593Smuzhiyun * size3 size;
612*4882a593Smuzhiyun * size3 used;
613*4882a593Smuzhiyun * specdata3 rdev;
614*4882a593Smuzhiyun * uint64 fsid;
615*4882a593Smuzhiyun * fileid3 fileid;
616*4882a593Smuzhiyun * nfstime3 atime;
617*4882a593Smuzhiyun * nfstime3 mtime;
618*4882a593Smuzhiyun * nfstime3 ctime;
619*4882a593Smuzhiyun * };
620*4882a593Smuzhiyun */
decode_fattr3(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)621*4882a593Smuzhiyun static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr,
622*4882a593Smuzhiyun struct user_namespace *userns)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun umode_t fmode;
625*4882a593Smuzhiyun __be32 *p;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
628*4882a593Smuzhiyun if (unlikely(!p))
629*4882a593Smuzhiyun return -EIO;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun p = xdr_decode_ftype3(p, &fmode);
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
634*4882a593Smuzhiyun fattr->nlink = be32_to_cpup(p++);
635*4882a593Smuzhiyun fattr->uid = make_kuid(userns, be32_to_cpup(p++));
636*4882a593Smuzhiyun if (!uid_valid(fattr->uid))
637*4882a593Smuzhiyun goto out_uid;
638*4882a593Smuzhiyun fattr->gid = make_kgid(userns, be32_to_cpup(p++));
639*4882a593Smuzhiyun if (!gid_valid(fattr->gid))
640*4882a593Smuzhiyun goto out_gid;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun p = xdr_decode_size3(p, &fattr->size);
643*4882a593Smuzhiyun p = xdr_decode_size3(p, &fattr->du.nfs3.used);
644*4882a593Smuzhiyun p = xdr_decode_specdata3(p, &fattr->rdev);
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun p = xdr_decode_hyper(p, &fattr->fsid.major);
647*4882a593Smuzhiyun fattr->fsid.minor = 0;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun p = xdr_decode_fileid3(p, &fattr->fileid);
650*4882a593Smuzhiyun p = xdr_decode_nfstime3(p, &fattr->atime);
651*4882a593Smuzhiyun p = xdr_decode_nfstime3(p, &fattr->mtime);
652*4882a593Smuzhiyun xdr_decode_nfstime3(p, &fattr->ctime);
653*4882a593Smuzhiyun fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun fattr->valid |= NFS_ATTR_FATTR_V3;
656*4882a593Smuzhiyun return 0;
657*4882a593Smuzhiyun out_uid:
658*4882a593Smuzhiyun dprintk("NFS: returned invalid uid\n");
659*4882a593Smuzhiyun return -EINVAL;
660*4882a593Smuzhiyun out_gid:
661*4882a593Smuzhiyun dprintk("NFS: returned invalid gid\n");
662*4882a593Smuzhiyun return -EINVAL;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun /*
666*4882a593Smuzhiyun * post_op_attr
667*4882a593Smuzhiyun *
668*4882a593Smuzhiyun * union post_op_attr switch (bool attributes_follow) {
669*4882a593Smuzhiyun * case TRUE:
670*4882a593Smuzhiyun * fattr3 attributes;
671*4882a593Smuzhiyun * case FALSE:
672*4882a593Smuzhiyun * void;
673*4882a593Smuzhiyun * };
674*4882a593Smuzhiyun */
decode_post_op_attr(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)675*4882a593Smuzhiyun static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
676*4882a593Smuzhiyun struct user_namespace *userns)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun __be32 *p;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
681*4882a593Smuzhiyun if (unlikely(!p))
682*4882a593Smuzhiyun return -EIO;
683*4882a593Smuzhiyun if (*p != xdr_zero)
684*4882a593Smuzhiyun return decode_fattr3(xdr, fattr, userns);
685*4882a593Smuzhiyun return 0;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun /*
689*4882a593Smuzhiyun * wcc_attr
690*4882a593Smuzhiyun * struct wcc_attr {
691*4882a593Smuzhiyun * size3 size;
692*4882a593Smuzhiyun * nfstime3 mtime;
693*4882a593Smuzhiyun * nfstime3 ctime;
694*4882a593Smuzhiyun * };
695*4882a593Smuzhiyun */
decode_wcc_attr(struct xdr_stream * xdr,struct nfs_fattr * fattr)696*4882a593Smuzhiyun static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun __be32 *p;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
701*4882a593Smuzhiyun if (unlikely(!p))
702*4882a593Smuzhiyun return -EIO;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun fattr->valid |= NFS_ATTR_FATTR_PRESIZE
705*4882a593Smuzhiyun | NFS_ATTR_FATTR_PRECHANGE
706*4882a593Smuzhiyun | NFS_ATTR_FATTR_PREMTIME
707*4882a593Smuzhiyun | NFS_ATTR_FATTR_PRECTIME;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun p = xdr_decode_size3(p, &fattr->pre_size);
710*4882a593Smuzhiyun p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
711*4882a593Smuzhiyun xdr_decode_nfstime3(p, &fattr->pre_ctime);
712*4882a593Smuzhiyun fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun return 0;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun /*
718*4882a593Smuzhiyun * pre_op_attr
719*4882a593Smuzhiyun * union pre_op_attr switch (bool attributes_follow) {
720*4882a593Smuzhiyun * case TRUE:
721*4882a593Smuzhiyun * wcc_attr attributes;
722*4882a593Smuzhiyun * case FALSE:
723*4882a593Smuzhiyun * void;
724*4882a593Smuzhiyun * };
725*4882a593Smuzhiyun *
726*4882a593Smuzhiyun * wcc_data
727*4882a593Smuzhiyun *
728*4882a593Smuzhiyun * struct wcc_data {
729*4882a593Smuzhiyun * pre_op_attr before;
730*4882a593Smuzhiyun * post_op_attr after;
731*4882a593Smuzhiyun * };
732*4882a593Smuzhiyun */
decode_pre_op_attr(struct xdr_stream * xdr,struct nfs_fattr * fattr)733*4882a593Smuzhiyun static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun __be32 *p;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
738*4882a593Smuzhiyun if (unlikely(!p))
739*4882a593Smuzhiyun return -EIO;
740*4882a593Smuzhiyun if (*p != xdr_zero)
741*4882a593Smuzhiyun return decode_wcc_attr(xdr, fattr);
742*4882a593Smuzhiyun return 0;
743*4882a593Smuzhiyun }
744*4882a593Smuzhiyun
decode_wcc_data(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)745*4882a593Smuzhiyun static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr,
746*4882a593Smuzhiyun struct user_namespace *userns)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun int error;
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun error = decode_pre_op_attr(xdr, fattr);
751*4882a593Smuzhiyun if (unlikely(error))
752*4882a593Smuzhiyun goto out;
753*4882a593Smuzhiyun error = decode_post_op_attr(xdr, fattr, userns);
754*4882a593Smuzhiyun out:
755*4882a593Smuzhiyun return error;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun /*
759*4882a593Smuzhiyun * post_op_fh3
760*4882a593Smuzhiyun *
761*4882a593Smuzhiyun * union post_op_fh3 switch (bool handle_follows) {
762*4882a593Smuzhiyun * case TRUE:
763*4882a593Smuzhiyun * nfs_fh3 handle;
764*4882a593Smuzhiyun * case FALSE:
765*4882a593Smuzhiyun * void;
766*4882a593Smuzhiyun * };
767*4882a593Smuzhiyun */
decode_post_op_fh3(struct xdr_stream * xdr,struct nfs_fh * fh)768*4882a593Smuzhiyun static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun __be32 *p = xdr_inline_decode(xdr, 4);
771*4882a593Smuzhiyun if (unlikely(!p))
772*4882a593Smuzhiyun return -EIO;
773*4882a593Smuzhiyun if (*p != xdr_zero)
774*4882a593Smuzhiyun return decode_nfs_fh3(xdr, fh);
775*4882a593Smuzhiyun zero_nfs_fh3(fh);
776*4882a593Smuzhiyun return 0;
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun /*
780*4882a593Smuzhiyun * diropargs3
781*4882a593Smuzhiyun *
782*4882a593Smuzhiyun * struct diropargs3 {
783*4882a593Smuzhiyun * nfs_fh3 dir;
784*4882a593Smuzhiyun * filename3 name;
785*4882a593Smuzhiyun * };
786*4882a593Smuzhiyun */
encode_diropargs3(struct xdr_stream * xdr,const struct nfs_fh * fh,const char * name,u32 length)787*4882a593Smuzhiyun static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
788*4882a593Smuzhiyun const char *name, u32 length)
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun encode_nfs_fh3(xdr, fh);
791*4882a593Smuzhiyun encode_filename3(xdr, name, length);
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun /*
796*4882a593Smuzhiyun * NFSv3 XDR encode functions
797*4882a593Smuzhiyun *
798*4882a593Smuzhiyun * NFSv3 argument types are defined in section 3.3 of RFC 1813:
799*4882a593Smuzhiyun * "NFS Version 3 Protocol Specification".
800*4882a593Smuzhiyun */
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun /*
803*4882a593Smuzhiyun * 3.3.1 GETATTR3args
804*4882a593Smuzhiyun *
805*4882a593Smuzhiyun * struct GETATTR3args {
806*4882a593Smuzhiyun * nfs_fh3 object;
807*4882a593Smuzhiyun * };
808*4882a593Smuzhiyun */
nfs3_xdr_enc_getattr3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)809*4882a593Smuzhiyun static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
810*4882a593Smuzhiyun struct xdr_stream *xdr,
811*4882a593Smuzhiyun const void *data)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun const struct nfs_fh *fh = data;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun encode_nfs_fh3(xdr, fh);
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun /*
819*4882a593Smuzhiyun * 3.3.2 SETATTR3args
820*4882a593Smuzhiyun *
821*4882a593Smuzhiyun * union sattrguard3 switch (bool check) {
822*4882a593Smuzhiyun * case TRUE:
823*4882a593Smuzhiyun * nfstime3 obj_ctime;
824*4882a593Smuzhiyun * case FALSE:
825*4882a593Smuzhiyun * void;
826*4882a593Smuzhiyun * };
827*4882a593Smuzhiyun *
828*4882a593Smuzhiyun * struct SETATTR3args {
829*4882a593Smuzhiyun * nfs_fh3 object;
830*4882a593Smuzhiyun * sattr3 new_attributes;
831*4882a593Smuzhiyun * sattrguard3 guard;
832*4882a593Smuzhiyun * };
833*4882a593Smuzhiyun */
encode_sattrguard3(struct xdr_stream * xdr,const struct nfs3_sattrargs * args)834*4882a593Smuzhiyun static void encode_sattrguard3(struct xdr_stream *xdr,
835*4882a593Smuzhiyun const struct nfs3_sattrargs *args)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun __be32 *p;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun if (args->guard) {
840*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + 8);
841*4882a593Smuzhiyun *p++ = xdr_one;
842*4882a593Smuzhiyun xdr_encode_nfstime3(p, &args->guardtime);
843*4882a593Smuzhiyun } else {
844*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4);
845*4882a593Smuzhiyun *p = xdr_zero;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
nfs3_xdr_enc_setattr3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)849*4882a593Smuzhiyun static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
850*4882a593Smuzhiyun struct xdr_stream *xdr,
851*4882a593Smuzhiyun const void *data)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun const struct nfs3_sattrargs *args = data;
854*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
855*4882a593Smuzhiyun encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
856*4882a593Smuzhiyun encode_sattrguard3(xdr, args);
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun /*
860*4882a593Smuzhiyun * 3.3.3 LOOKUP3args
861*4882a593Smuzhiyun *
862*4882a593Smuzhiyun * struct LOOKUP3args {
863*4882a593Smuzhiyun * diropargs3 what;
864*4882a593Smuzhiyun * };
865*4882a593Smuzhiyun */
nfs3_xdr_enc_lookup3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)866*4882a593Smuzhiyun static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
867*4882a593Smuzhiyun struct xdr_stream *xdr,
868*4882a593Smuzhiyun const void *data)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun const struct nfs3_diropargs *args = data;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun encode_diropargs3(xdr, args->fh, args->name, args->len);
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun /*
876*4882a593Smuzhiyun * 3.3.4 ACCESS3args
877*4882a593Smuzhiyun *
878*4882a593Smuzhiyun * struct ACCESS3args {
879*4882a593Smuzhiyun * nfs_fh3 object;
880*4882a593Smuzhiyun * uint32 access;
881*4882a593Smuzhiyun * };
882*4882a593Smuzhiyun */
encode_access3args(struct xdr_stream * xdr,const struct nfs3_accessargs * args)883*4882a593Smuzhiyun static void encode_access3args(struct xdr_stream *xdr,
884*4882a593Smuzhiyun const struct nfs3_accessargs *args)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
887*4882a593Smuzhiyun encode_uint32(xdr, args->access);
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun
nfs3_xdr_enc_access3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)890*4882a593Smuzhiyun static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
891*4882a593Smuzhiyun struct xdr_stream *xdr,
892*4882a593Smuzhiyun const void *data)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun const struct nfs3_accessargs *args = data;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun encode_access3args(xdr, args);
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun /*
900*4882a593Smuzhiyun * 3.3.5 READLINK3args
901*4882a593Smuzhiyun *
902*4882a593Smuzhiyun * struct READLINK3args {
903*4882a593Smuzhiyun * nfs_fh3 symlink;
904*4882a593Smuzhiyun * };
905*4882a593Smuzhiyun */
nfs3_xdr_enc_readlink3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)906*4882a593Smuzhiyun static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
907*4882a593Smuzhiyun struct xdr_stream *xdr,
908*4882a593Smuzhiyun const void *data)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun const struct nfs3_readlinkargs *args = data;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
913*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, args->pgbase,
914*4882a593Smuzhiyun args->pglen, NFS3_readlinkres_sz);
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun /*
918*4882a593Smuzhiyun * 3.3.6 READ3args
919*4882a593Smuzhiyun *
920*4882a593Smuzhiyun * struct READ3args {
921*4882a593Smuzhiyun * nfs_fh3 file;
922*4882a593Smuzhiyun * offset3 offset;
923*4882a593Smuzhiyun * count3 count;
924*4882a593Smuzhiyun * };
925*4882a593Smuzhiyun */
encode_read3args(struct xdr_stream * xdr,const struct nfs_pgio_args * args)926*4882a593Smuzhiyun static void encode_read3args(struct xdr_stream *xdr,
927*4882a593Smuzhiyun const struct nfs_pgio_args *args)
928*4882a593Smuzhiyun {
929*4882a593Smuzhiyun __be32 *p;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 8 + 4);
934*4882a593Smuzhiyun p = xdr_encode_hyper(p, args->offset);
935*4882a593Smuzhiyun *p = cpu_to_be32(args->count);
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun
nfs3_xdr_enc_read3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)938*4882a593Smuzhiyun static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
939*4882a593Smuzhiyun struct xdr_stream *xdr,
940*4882a593Smuzhiyun const void *data)
941*4882a593Smuzhiyun {
942*4882a593Smuzhiyun const struct nfs_pgio_args *args = data;
943*4882a593Smuzhiyun unsigned int replen = args->replen ? args->replen : NFS3_readres_sz;
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun encode_read3args(xdr, args);
946*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, args->pgbase,
947*4882a593Smuzhiyun args->count, replen);
948*4882a593Smuzhiyun req->rq_rcv_buf.flags |= XDRBUF_READ;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun /*
952*4882a593Smuzhiyun * 3.3.7 WRITE3args
953*4882a593Smuzhiyun *
954*4882a593Smuzhiyun * enum stable_how {
955*4882a593Smuzhiyun * UNSTABLE = 0,
956*4882a593Smuzhiyun * DATA_SYNC = 1,
957*4882a593Smuzhiyun * FILE_SYNC = 2
958*4882a593Smuzhiyun * };
959*4882a593Smuzhiyun *
960*4882a593Smuzhiyun * struct WRITE3args {
961*4882a593Smuzhiyun * nfs_fh3 file;
962*4882a593Smuzhiyun * offset3 offset;
963*4882a593Smuzhiyun * count3 count;
964*4882a593Smuzhiyun * stable_how stable;
965*4882a593Smuzhiyun * opaque data<>;
966*4882a593Smuzhiyun * };
967*4882a593Smuzhiyun */
encode_write3args(struct xdr_stream * xdr,const struct nfs_pgio_args * args)968*4882a593Smuzhiyun static void encode_write3args(struct xdr_stream *xdr,
969*4882a593Smuzhiyun const struct nfs_pgio_args *args)
970*4882a593Smuzhiyun {
971*4882a593Smuzhiyun __be32 *p;
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
976*4882a593Smuzhiyun p = xdr_encode_hyper(p, args->offset);
977*4882a593Smuzhiyun *p++ = cpu_to_be32(args->count);
978*4882a593Smuzhiyun *p++ = cpu_to_be32(args->stable);
979*4882a593Smuzhiyun *p = cpu_to_be32(args->count);
980*4882a593Smuzhiyun xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
981*4882a593Smuzhiyun }
982*4882a593Smuzhiyun
nfs3_xdr_enc_write3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)983*4882a593Smuzhiyun static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
984*4882a593Smuzhiyun struct xdr_stream *xdr,
985*4882a593Smuzhiyun const void *data)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun const struct nfs_pgio_args *args = data;
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun encode_write3args(xdr, args);
990*4882a593Smuzhiyun xdr->buf->flags |= XDRBUF_WRITE;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun /*
994*4882a593Smuzhiyun * 3.3.8 CREATE3args
995*4882a593Smuzhiyun *
996*4882a593Smuzhiyun * enum createmode3 {
997*4882a593Smuzhiyun * UNCHECKED = 0,
998*4882a593Smuzhiyun * GUARDED = 1,
999*4882a593Smuzhiyun * EXCLUSIVE = 2
1000*4882a593Smuzhiyun * };
1001*4882a593Smuzhiyun *
1002*4882a593Smuzhiyun * union createhow3 switch (createmode3 mode) {
1003*4882a593Smuzhiyun * case UNCHECKED:
1004*4882a593Smuzhiyun * case GUARDED:
1005*4882a593Smuzhiyun * sattr3 obj_attributes;
1006*4882a593Smuzhiyun * case EXCLUSIVE:
1007*4882a593Smuzhiyun * createverf3 verf;
1008*4882a593Smuzhiyun * };
1009*4882a593Smuzhiyun *
1010*4882a593Smuzhiyun * struct CREATE3args {
1011*4882a593Smuzhiyun * diropargs3 where;
1012*4882a593Smuzhiyun * createhow3 how;
1013*4882a593Smuzhiyun * };
1014*4882a593Smuzhiyun */
encode_createhow3(struct xdr_stream * xdr,const struct nfs3_createargs * args,struct user_namespace * userns)1015*4882a593Smuzhiyun static void encode_createhow3(struct xdr_stream *xdr,
1016*4882a593Smuzhiyun const struct nfs3_createargs *args,
1017*4882a593Smuzhiyun struct user_namespace *userns)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun encode_uint32(xdr, args->createmode);
1020*4882a593Smuzhiyun switch (args->createmode) {
1021*4882a593Smuzhiyun case NFS3_CREATE_UNCHECKED:
1022*4882a593Smuzhiyun case NFS3_CREATE_GUARDED:
1023*4882a593Smuzhiyun encode_sattr3(xdr, args->sattr, userns);
1024*4882a593Smuzhiyun break;
1025*4882a593Smuzhiyun case NFS3_CREATE_EXCLUSIVE:
1026*4882a593Smuzhiyun encode_createverf3(xdr, args->verifier);
1027*4882a593Smuzhiyun break;
1028*4882a593Smuzhiyun default:
1029*4882a593Smuzhiyun BUG();
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun
nfs3_xdr_enc_create3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1033*4882a593Smuzhiyun static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
1034*4882a593Smuzhiyun struct xdr_stream *xdr,
1035*4882a593Smuzhiyun const void *data)
1036*4882a593Smuzhiyun {
1037*4882a593Smuzhiyun const struct nfs3_createargs *args = data;
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun encode_diropargs3(xdr, args->fh, args->name, args->len);
1040*4882a593Smuzhiyun encode_createhow3(xdr, args, rpc_rqst_userns(req));
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun /*
1044*4882a593Smuzhiyun * 3.3.9 MKDIR3args
1045*4882a593Smuzhiyun *
1046*4882a593Smuzhiyun * struct MKDIR3args {
1047*4882a593Smuzhiyun * diropargs3 where;
1048*4882a593Smuzhiyun * sattr3 attributes;
1049*4882a593Smuzhiyun * };
1050*4882a593Smuzhiyun */
nfs3_xdr_enc_mkdir3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1051*4882a593Smuzhiyun static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
1052*4882a593Smuzhiyun struct xdr_stream *xdr,
1053*4882a593Smuzhiyun const void *data)
1054*4882a593Smuzhiyun {
1055*4882a593Smuzhiyun const struct nfs3_mkdirargs *args = data;
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun encode_diropargs3(xdr, args->fh, args->name, args->len);
1058*4882a593Smuzhiyun encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun /*
1062*4882a593Smuzhiyun * 3.3.10 SYMLINK3args
1063*4882a593Smuzhiyun *
1064*4882a593Smuzhiyun * struct symlinkdata3 {
1065*4882a593Smuzhiyun * sattr3 symlink_attributes;
1066*4882a593Smuzhiyun * nfspath3 symlink_data;
1067*4882a593Smuzhiyun * };
1068*4882a593Smuzhiyun *
1069*4882a593Smuzhiyun * struct SYMLINK3args {
1070*4882a593Smuzhiyun * diropargs3 where;
1071*4882a593Smuzhiyun * symlinkdata3 symlink;
1072*4882a593Smuzhiyun * };
1073*4882a593Smuzhiyun */
encode_symlinkdata3(struct xdr_stream * xdr,const void * data,struct user_namespace * userns)1074*4882a593Smuzhiyun static void encode_symlinkdata3(struct xdr_stream *xdr,
1075*4882a593Smuzhiyun const void *data,
1076*4882a593Smuzhiyun struct user_namespace *userns)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun const struct nfs3_symlinkargs *args = data;
1079*4882a593Smuzhiyun
1080*4882a593Smuzhiyun encode_sattr3(xdr, args->sattr, userns);
1081*4882a593Smuzhiyun encode_nfspath3(xdr, args->pages, args->pathlen);
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun
nfs3_xdr_enc_symlink3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1084*4882a593Smuzhiyun static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
1085*4882a593Smuzhiyun struct xdr_stream *xdr,
1086*4882a593Smuzhiyun const void *data)
1087*4882a593Smuzhiyun {
1088*4882a593Smuzhiyun const struct nfs3_symlinkargs *args = data;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
1091*4882a593Smuzhiyun encode_symlinkdata3(xdr, args, rpc_rqst_userns(req));
1092*4882a593Smuzhiyun xdr->buf->flags |= XDRBUF_WRITE;
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun /*
1096*4882a593Smuzhiyun * 3.3.11 MKNOD3args
1097*4882a593Smuzhiyun *
1098*4882a593Smuzhiyun * struct devicedata3 {
1099*4882a593Smuzhiyun * sattr3 dev_attributes;
1100*4882a593Smuzhiyun * specdata3 spec;
1101*4882a593Smuzhiyun * };
1102*4882a593Smuzhiyun *
1103*4882a593Smuzhiyun * union mknoddata3 switch (ftype3 type) {
1104*4882a593Smuzhiyun * case NF3CHR:
1105*4882a593Smuzhiyun * case NF3BLK:
1106*4882a593Smuzhiyun * devicedata3 device;
1107*4882a593Smuzhiyun * case NF3SOCK:
1108*4882a593Smuzhiyun * case NF3FIFO:
1109*4882a593Smuzhiyun * sattr3 pipe_attributes;
1110*4882a593Smuzhiyun * default:
1111*4882a593Smuzhiyun * void;
1112*4882a593Smuzhiyun * };
1113*4882a593Smuzhiyun *
1114*4882a593Smuzhiyun * struct MKNOD3args {
1115*4882a593Smuzhiyun * diropargs3 where;
1116*4882a593Smuzhiyun * mknoddata3 what;
1117*4882a593Smuzhiyun * };
1118*4882a593Smuzhiyun */
encode_devicedata3(struct xdr_stream * xdr,const struct nfs3_mknodargs * args,struct user_namespace * userns)1119*4882a593Smuzhiyun static void encode_devicedata3(struct xdr_stream *xdr,
1120*4882a593Smuzhiyun const struct nfs3_mknodargs *args,
1121*4882a593Smuzhiyun struct user_namespace *userns)
1122*4882a593Smuzhiyun {
1123*4882a593Smuzhiyun encode_sattr3(xdr, args->sattr, userns);
1124*4882a593Smuzhiyun encode_specdata3(xdr, args->rdev);
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun
encode_mknoddata3(struct xdr_stream * xdr,const struct nfs3_mknodargs * args,struct user_namespace * userns)1127*4882a593Smuzhiyun static void encode_mknoddata3(struct xdr_stream *xdr,
1128*4882a593Smuzhiyun const struct nfs3_mknodargs *args,
1129*4882a593Smuzhiyun struct user_namespace *userns)
1130*4882a593Smuzhiyun {
1131*4882a593Smuzhiyun encode_ftype3(xdr, args->type);
1132*4882a593Smuzhiyun switch (args->type) {
1133*4882a593Smuzhiyun case NF3CHR:
1134*4882a593Smuzhiyun case NF3BLK:
1135*4882a593Smuzhiyun encode_devicedata3(xdr, args, userns);
1136*4882a593Smuzhiyun break;
1137*4882a593Smuzhiyun case NF3SOCK:
1138*4882a593Smuzhiyun case NF3FIFO:
1139*4882a593Smuzhiyun encode_sattr3(xdr, args->sattr, userns);
1140*4882a593Smuzhiyun break;
1141*4882a593Smuzhiyun case NF3REG:
1142*4882a593Smuzhiyun case NF3DIR:
1143*4882a593Smuzhiyun break;
1144*4882a593Smuzhiyun default:
1145*4882a593Smuzhiyun BUG();
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun }
1148*4882a593Smuzhiyun
nfs3_xdr_enc_mknod3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1149*4882a593Smuzhiyun static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
1150*4882a593Smuzhiyun struct xdr_stream *xdr,
1151*4882a593Smuzhiyun const void *data)
1152*4882a593Smuzhiyun {
1153*4882a593Smuzhiyun const struct nfs3_mknodargs *args = data;
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun encode_diropargs3(xdr, args->fh, args->name, args->len);
1156*4882a593Smuzhiyun encode_mknoddata3(xdr, args, rpc_rqst_userns(req));
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun /*
1160*4882a593Smuzhiyun * 3.3.12 REMOVE3args
1161*4882a593Smuzhiyun *
1162*4882a593Smuzhiyun * struct REMOVE3args {
1163*4882a593Smuzhiyun * diropargs3 object;
1164*4882a593Smuzhiyun * };
1165*4882a593Smuzhiyun */
nfs3_xdr_enc_remove3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1166*4882a593Smuzhiyun static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
1167*4882a593Smuzhiyun struct xdr_stream *xdr,
1168*4882a593Smuzhiyun const void *data)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun const struct nfs_removeargs *args = data;
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun /*
1176*4882a593Smuzhiyun * 3.3.14 RENAME3args
1177*4882a593Smuzhiyun *
1178*4882a593Smuzhiyun * struct RENAME3args {
1179*4882a593Smuzhiyun * diropargs3 from;
1180*4882a593Smuzhiyun * diropargs3 to;
1181*4882a593Smuzhiyun * };
1182*4882a593Smuzhiyun */
nfs3_xdr_enc_rename3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1183*4882a593Smuzhiyun static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
1184*4882a593Smuzhiyun struct xdr_stream *xdr,
1185*4882a593Smuzhiyun const void *data)
1186*4882a593Smuzhiyun {
1187*4882a593Smuzhiyun const struct nfs_renameargs *args = data;
1188*4882a593Smuzhiyun const struct qstr *old = args->old_name;
1189*4882a593Smuzhiyun const struct qstr *new = args->new_name;
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun encode_diropargs3(xdr, args->old_dir, old->name, old->len);
1192*4882a593Smuzhiyun encode_diropargs3(xdr, args->new_dir, new->name, new->len);
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun /*
1196*4882a593Smuzhiyun * 3.3.15 LINK3args
1197*4882a593Smuzhiyun *
1198*4882a593Smuzhiyun * struct LINK3args {
1199*4882a593Smuzhiyun * nfs_fh3 file;
1200*4882a593Smuzhiyun * diropargs3 link;
1201*4882a593Smuzhiyun * };
1202*4882a593Smuzhiyun */
nfs3_xdr_enc_link3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1203*4882a593Smuzhiyun static void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
1204*4882a593Smuzhiyun struct xdr_stream *xdr,
1205*4882a593Smuzhiyun const void *data)
1206*4882a593Smuzhiyun {
1207*4882a593Smuzhiyun const struct nfs3_linkargs *args = data;
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fromfh);
1210*4882a593Smuzhiyun encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun /*
1214*4882a593Smuzhiyun * 3.3.16 READDIR3args
1215*4882a593Smuzhiyun *
1216*4882a593Smuzhiyun * struct READDIR3args {
1217*4882a593Smuzhiyun * nfs_fh3 dir;
1218*4882a593Smuzhiyun * cookie3 cookie;
1219*4882a593Smuzhiyun * cookieverf3 cookieverf;
1220*4882a593Smuzhiyun * count3 count;
1221*4882a593Smuzhiyun * };
1222*4882a593Smuzhiyun */
encode_readdir3args(struct xdr_stream * xdr,const struct nfs3_readdirargs * args)1223*4882a593Smuzhiyun static void encode_readdir3args(struct xdr_stream *xdr,
1224*4882a593Smuzhiyun const struct nfs3_readdirargs *args)
1225*4882a593Smuzhiyun {
1226*4882a593Smuzhiyun __be32 *p;
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1231*4882a593Smuzhiyun p = xdr_encode_cookie3(p, args->cookie);
1232*4882a593Smuzhiyun p = xdr_encode_cookieverf3(p, args->verf);
1233*4882a593Smuzhiyun *p = cpu_to_be32(args->count);
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun
nfs3_xdr_enc_readdir3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1236*4882a593Smuzhiyun static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
1237*4882a593Smuzhiyun struct xdr_stream *xdr,
1238*4882a593Smuzhiyun const void *data)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun const struct nfs3_readdirargs *args = data;
1241*4882a593Smuzhiyun
1242*4882a593Smuzhiyun encode_readdir3args(xdr, args);
1243*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, 0,
1244*4882a593Smuzhiyun args->count, NFS3_readdirres_sz);
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
1247*4882a593Smuzhiyun /*
1248*4882a593Smuzhiyun * 3.3.17 READDIRPLUS3args
1249*4882a593Smuzhiyun *
1250*4882a593Smuzhiyun * struct READDIRPLUS3args {
1251*4882a593Smuzhiyun * nfs_fh3 dir;
1252*4882a593Smuzhiyun * cookie3 cookie;
1253*4882a593Smuzhiyun * cookieverf3 cookieverf;
1254*4882a593Smuzhiyun * count3 dircount;
1255*4882a593Smuzhiyun * count3 maxcount;
1256*4882a593Smuzhiyun * };
1257*4882a593Smuzhiyun */
encode_readdirplus3args(struct xdr_stream * xdr,const struct nfs3_readdirargs * args)1258*4882a593Smuzhiyun static void encode_readdirplus3args(struct xdr_stream *xdr,
1259*4882a593Smuzhiyun const struct nfs3_readdirargs *args)
1260*4882a593Smuzhiyun {
1261*4882a593Smuzhiyun __be32 *p;
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
1264*4882a593Smuzhiyun
1265*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1266*4882a593Smuzhiyun p = xdr_encode_cookie3(p, args->cookie);
1267*4882a593Smuzhiyun p = xdr_encode_cookieverf3(p, args->verf);
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun /*
1270*4882a593Smuzhiyun * readdirplus: need dircount + buffer size.
1271*4882a593Smuzhiyun * We just make sure we make dircount big enough
1272*4882a593Smuzhiyun */
1273*4882a593Smuzhiyun *p++ = cpu_to_be32(args->count >> 3);
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun *p = cpu_to_be32(args->count);
1276*4882a593Smuzhiyun }
1277*4882a593Smuzhiyun
nfs3_xdr_enc_readdirplus3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1278*4882a593Smuzhiyun static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
1279*4882a593Smuzhiyun struct xdr_stream *xdr,
1280*4882a593Smuzhiyun const void *data)
1281*4882a593Smuzhiyun {
1282*4882a593Smuzhiyun const struct nfs3_readdirargs *args = data;
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun encode_readdirplus3args(xdr, args);
1285*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, 0,
1286*4882a593Smuzhiyun args->count, NFS3_readdirres_sz);
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun /*
1290*4882a593Smuzhiyun * 3.3.21 COMMIT3args
1291*4882a593Smuzhiyun *
1292*4882a593Smuzhiyun * struct COMMIT3args {
1293*4882a593Smuzhiyun * nfs_fh3 file;
1294*4882a593Smuzhiyun * offset3 offset;
1295*4882a593Smuzhiyun * count3 count;
1296*4882a593Smuzhiyun * };
1297*4882a593Smuzhiyun */
encode_commit3args(struct xdr_stream * xdr,const struct nfs_commitargs * args)1298*4882a593Smuzhiyun static void encode_commit3args(struct xdr_stream *xdr,
1299*4882a593Smuzhiyun const struct nfs_commitargs *args)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun __be32 *p;
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 8 + 4);
1306*4882a593Smuzhiyun p = xdr_encode_hyper(p, args->offset);
1307*4882a593Smuzhiyun *p = cpu_to_be32(args->count);
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
nfs3_xdr_enc_commit3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1310*4882a593Smuzhiyun static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
1311*4882a593Smuzhiyun struct xdr_stream *xdr,
1312*4882a593Smuzhiyun const void *data)
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun const struct nfs_commitargs *args = data;
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun encode_commit3args(xdr, args);
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun #ifdef CONFIG_NFS_V3_ACL
1320*4882a593Smuzhiyun
nfs3_xdr_enc_getacl3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1321*4882a593Smuzhiyun static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
1322*4882a593Smuzhiyun struct xdr_stream *xdr,
1323*4882a593Smuzhiyun const void *data)
1324*4882a593Smuzhiyun {
1325*4882a593Smuzhiyun const struct nfs3_getaclargs *args = data;
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun encode_nfs_fh3(xdr, args->fh);
1328*4882a593Smuzhiyun encode_uint32(xdr, args->mask);
1329*4882a593Smuzhiyun if (args->mask & (NFS_ACL | NFS_DFACL)) {
1330*4882a593Smuzhiyun rpc_prepare_reply_pages(req, args->pages, 0,
1331*4882a593Smuzhiyun NFSACL_MAXPAGES << PAGE_SHIFT,
1332*4882a593Smuzhiyun ACL3_getaclres_sz);
1333*4882a593Smuzhiyun req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun
nfs3_xdr_enc_setacl3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)1337*4882a593Smuzhiyun static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
1338*4882a593Smuzhiyun struct xdr_stream *xdr,
1339*4882a593Smuzhiyun const void *data)
1340*4882a593Smuzhiyun {
1341*4882a593Smuzhiyun const struct nfs3_setaclargs *args = data;
1342*4882a593Smuzhiyun unsigned int base;
1343*4882a593Smuzhiyun int error;
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun encode_nfs_fh3(xdr, NFS_FH(args->inode));
1346*4882a593Smuzhiyun encode_uint32(xdr, args->mask);
1347*4882a593Smuzhiyun
1348*4882a593Smuzhiyun base = req->rq_slen;
1349*4882a593Smuzhiyun if (args->npages != 0)
1350*4882a593Smuzhiyun xdr_write_pages(xdr, args->pages, 0, args->len);
1351*4882a593Smuzhiyun else
1352*4882a593Smuzhiyun xdr_reserve_space(xdr, args->len);
1353*4882a593Smuzhiyun
1354*4882a593Smuzhiyun error = nfsacl_encode(xdr->buf, base, args->inode,
1355*4882a593Smuzhiyun (args->mask & NFS_ACL) ?
1356*4882a593Smuzhiyun args->acl_access : NULL, 1, 0);
1357*4882a593Smuzhiyun /* FIXME: this is just broken */
1358*4882a593Smuzhiyun BUG_ON(error < 0);
1359*4882a593Smuzhiyun error = nfsacl_encode(xdr->buf, base + error, args->inode,
1360*4882a593Smuzhiyun (args->mask & NFS_DFACL) ?
1361*4882a593Smuzhiyun args->acl_default : NULL, 1,
1362*4882a593Smuzhiyun NFS_ACL_DEFAULT);
1363*4882a593Smuzhiyun BUG_ON(error < 0);
1364*4882a593Smuzhiyun }
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun #endif /* CONFIG_NFS_V3_ACL */
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun /*
1369*4882a593Smuzhiyun * NFSv3 XDR decode functions
1370*4882a593Smuzhiyun *
1371*4882a593Smuzhiyun * NFSv3 result types are defined in section 3.3 of RFC 1813:
1372*4882a593Smuzhiyun * "NFS Version 3 Protocol Specification".
1373*4882a593Smuzhiyun */
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /*
1376*4882a593Smuzhiyun * 3.3.1 GETATTR3res
1377*4882a593Smuzhiyun *
1378*4882a593Smuzhiyun * struct GETATTR3resok {
1379*4882a593Smuzhiyun * fattr3 obj_attributes;
1380*4882a593Smuzhiyun * };
1381*4882a593Smuzhiyun *
1382*4882a593Smuzhiyun * union GETATTR3res switch (nfsstat3 status) {
1383*4882a593Smuzhiyun * case NFS3_OK:
1384*4882a593Smuzhiyun * GETATTR3resok resok;
1385*4882a593Smuzhiyun * default:
1386*4882a593Smuzhiyun * void;
1387*4882a593Smuzhiyun * };
1388*4882a593Smuzhiyun */
nfs3_xdr_dec_getattr3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1389*4882a593Smuzhiyun static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
1390*4882a593Smuzhiyun struct xdr_stream *xdr,
1391*4882a593Smuzhiyun void *result)
1392*4882a593Smuzhiyun {
1393*4882a593Smuzhiyun enum nfs_stat status;
1394*4882a593Smuzhiyun int error;
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1397*4882a593Smuzhiyun if (unlikely(error))
1398*4882a593Smuzhiyun goto out;
1399*4882a593Smuzhiyun if (status != NFS3_OK)
1400*4882a593Smuzhiyun goto out_default;
1401*4882a593Smuzhiyun error = decode_fattr3(xdr, result, rpc_rqst_userns(req));
1402*4882a593Smuzhiyun out:
1403*4882a593Smuzhiyun return error;
1404*4882a593Smuzhiyun out_default:
1405*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1406*4882a593Smuzhiyun }
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun /*
1409*4882a593Smuzhiyun * 3.3.2 SETATTR3res
1410*4882a593Smuzhiyun *
1411*4882a593Smuzhiyun * struct SETATTR3resok {
1412*4882a593Smuzhiyun * wcc_data obj_wcc;
1413*4882a593Smuzhiyun * };
1414*4882a593Smuzhiyun *
1415*4882a593Smuzhiyun * struct SETATTR3resfail {
1416*4882a593Smuzhiyun * wcc_data obj_wcc;
1417*4882a593Smuzhiyun * };
1418*4882a593Smuzhiyun *
1419*4882a593Smuzhiyun * union SETATTR3res switch (nfsstat3 status) {
1420*4882a593Smuzhiyun * case NFS3_OK:
1421*4882a593Smuzhiyun * SETATTR3resok resok;
1422*4882a593Smuzhiyun * default:
1423*4882a593Smuzhiyun * SETATTR3resfail resfail;
1424*4882a593Smuzhiyun * };
1425*4882a593Smuzhiyun */
nfs3_xdr_dec_setattr3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1426*4882a593Smuzhiyun static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
1427*4882a593Smuzhiyun struct xdr_stream *xdr,
1428*4882a593Smuzhiyun void *result)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun enum nfs_stat status;
1431*4882a593Smuzhiyun int error;
1432*4882a593Smuzhiyun
1433*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1434*4882a593Smuzhiyun if (unlikely(error))
1435*4882a593Smuzhiyun goto out;
1436*4882a593Smuzhiyun error = decode_wcc_data(xdr, result, rpc_rqst_userns(req));
1437*4882a593Smuzhiyun if (unlikely(error))
1438*4882a593Smuzhiyun goto out;
1439*4882a593Smuzhiyun if (status != NFS3_OK)
1440*4882a593Smuzhiyun goto out_status;
1441*4882a593Smuzhiyun out:
1442*4882a593Smuzhiyun return error;
1443*4882a593Smuzhiyun out_status:
1444*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun /*
1448*4882a593Smuzhiyun * 3.3.3 LOOKUP3res
1449*4882a593Smuzhiyun *
1450*4882a593Smuzhiyun * struct LOOKUP3resok {
1451*4882a593Smuzhiyun * nfs_fh3 object;
1452*4882a593Smuzhiyun * post_op_attr obj_attributes;
1453*4882a593Smuzhiyun * post_op_attr dir_attributes;
1454*4882a593Smuzhiyun * };
1455*4882a593Smuzhiyun *
1456*4882a593Smuzhiyun * struct LOOKUP3resfail {
1457*4882a593Smuzhiyun * post_op_attr dir_attributes;
1458*4882a593Smuzhiyun * };
1459*4882a593Smuzhiyun *
1460*4882a593Smuzhiyun * union LOOKUP3res switch (nfsstat3 status) {
1461*4882a593Smuzhiyun * case NFS3_OK:
1462*4882a593Smuzhiyun * LOOKUP3resok resok;
1463*4882a593Smuzhiyun * default:
1464*4882a593Smuzhiyun * LOOKUP3resfail resfail;
1465*4882a593Smuzhiyun * };
1466*4882a593Smuzhiyun */
nfs3_xdr_dec_lookup3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1467*4882a593Smuzhiyun static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
1468*4882a593Smuzhiyun struct xdr_stream *xdr,
1469*4882a593Smuzhiyun void *data)
1470*4882a593Smuzhiyun {
1471*4882a593Smuzhiyun struct user_namespace *userns = rpc_rqst_userns(req);
1472*4882a593Smuzhiyun struct nfs3_diropres *result = data;
1473*4882a593Smuzhiyun enum nfs_stat status;
1474*4882a593Smuzhiyun int error;
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1477*4882a593Smuzhiyun if (unlikely(error))
1478*4882a593Smuzhiyun goto out;
1479*4882a593Smuzhiyun if (status != NFS3_OK)
1480*4882a593Smuzhiyun goto out_default;
1481*4882a593Smuzhiyun error = decode_nfs_fh3(xdr, result->fh);
1482*4882a593Smuzhiyun if (unlikely(error))
1483*4882a593Smuzhiyun goto out;
1484*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, userns);
1485*4882a593Smuzhiyun if (unlikely(error))
1486*4882a593Smuzhiyun goto out;
1487*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->dir_attr, userns);
1488*4882a593Smuzhiyun out:
1489*4882a593Smuzhiyun return error;
1490*4882a593Smuzhiyun out_default:
1491*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->dir_attr, userns);
1492*4882a593Smuzhiyun if (unlikely(error))
1493*4882a593Smuzhiyun goto out;
1494*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1495*4882a593Smuzhiyun }
1496*4882a593Smuzhiyun
1497*4882a593Smuzhiyun /*
1498*4882a593Smuzhiyun * 3.3.4 ACCESS3res
1499*4882a593Smuzhiyun *
1500*4882a593Smuzhiyun * struct ACCESS3resok {
1501*4882a593Smuzhiyun * post_op_attr obj_attributes;
1502*4882a593Smuzhiyun * uint32 access;
1503*4882a593Smuzhiyun * };
1504*4882a593Smuzhiyun *
1505*4882a593Smuzhiyun * struct ACCESS3resfail {
1506*4882a593Smuzhiyun * post_op_attr obj_attributes;
1507*4882a593Smuzhiyun * };
1508*4882a593Smuzhiyun *
1509*4882a593Smuzhiyun * union ACCESS3res switch (nfsstat3 status) {
1510*4882a593Smuzhiyun * case NFS3_OK:
1511*4882a593Smuzhiyun * ACCESS3resok resok;
1512*4882a593Smuzhiyun * default:
1513*4882a593Smuzhiyun * ACCESS3resfail resfail;
1514*4882a593Smuzhiyun * };
1515*4882a593Smuzhiyun */
nfs3_xdr_dec_access3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1516*4882a593Smuzhiyun static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
1517*4882a593Smuzhiyun struct xdr_stream *xdr,
1518*4882a593Smuzhiyun void *data)
1519*4882a593Smuzhiyun {
1520*4882a593Smuzhiyun struct nfs3_accessres *result = data;
1521*4882a593Smuzhiyun enum nfs_stat status;
1522*4882a593Smuzhiyun int error;
1523*4882a593Smuzhiyun
1524*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1525*4882a593Smuzhiyun if (unlikely(error))
1526*4882a593Smuzhiyun goto out;
1527*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
1528*4882a593Smuzhiyun if (unlikely(error))
1529*4882a593Smuzhiyun goto out;
1530*4882a593Smuzhiyun if (status != NFS3_OK)
1531*4882a593Smuzhiyun goto out_default;
1532*4882a593Smuzhiyun error = decode_uint32(xdr, &result->access);
1533*4882a593Smuzhiyun out:
1534*4882a593Smuzhiyun return error;
1535*4882a593Smuzhiyun out_default:
1536*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1537*4882a593Smuzhiyun }
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun /*
1540*4882a593Smuzhiyun * 3.3.5 READLINK3res
1541*4882a593Smuzhiyun *
1542*4882a593Smuzhiyun * struct READLINK3resok {
1543*4882a593Smuzhiyun * post_op_attr symlink_attributes;
1544*4882a593Smuzhiyun * nfspath3 data;
1545*4882a593Smuzhiyun * };
1546*4882a593Smuzhiyun *
1547*4882a593Smuzhiyun * struct READLINK3resfail {
1548*4882a593Smuzhiyun * post_op_attr symlink_attributes;
1549*4882a593Smuzhiyun * };
1550*4882a593Smuzhiyun *
1551*4882a593Smuzhiyun * union READLINK3res switch (nfsstat3 status) {
1552*4882a593Smuzhiyun * case NFS3_OK:
1553*4882a593Smuzhiyun * READLINK3resok resok;
1554*4882a593Smuzhiyun * default:
1555*4882a593Smuzhiyun * READLINK3resfail resfail;
1556*4882a593Smuzhiyun * };
1557*4882a593Smuzhiyun */
nfs3_xdr_dec_readlink3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1558*4882a593Smuzhiyun static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
1559*4882a593Smuzhiyun struct xdr_stream *xdr,
1560*4882a593Smuzhiyun void *result)
1561*4882a593Smuzhiyun {
1562*4882a593Smuzhiyun enum nfs_stat status;
1563*4882a593Smuzhiyun int error;
1564*4882a593Smuzhiyun
1565*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1566*4882a593Smuzhiyun if (unlikely(error))
1567*4882a593Smuzhiyun goto out;
1568*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
1569*4882a593Smuzhiyun if (unlikely(error))
1570*4882a593Smuzhiyun goto out;
1571*4882a593Smuzhiyun if (status != NFS3_OK)
1572*4882a593Smuzhiyun goto out_default;
1573*4882a593Smuzhiyun error = decode_nfspath3(xdr);
1574*4882a593Smuzhiyun out:
1575*4882a593Smuzhiyun return error;
1576*4882a593Smuzhiyun out_default:
1577*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun
1580*4882a593Smuzhiyun /*
1581*4882a593Smuzhiyun * 3.3.6 READ3res
1582*4882a593Smuzhiyun *
1583*4882a593Smuzhiyun * struct READ3resok {
1584*4882a593Smuzhiyun * post_op_attr file_attributes;
1585*4882a593Smuzhiyun * count3 count;
1586*4882a593Smuzhiyun * bool eof;
1587*4882a593Smuzhiyun * opaque data<>;
1588*4882a593Smuzhiyun * };
1589*4882a593Smuzhiyun *
1590*4882a593Smuzhiyun * struct READ3resfail {
1591*4882a593Smuzhiyun * post_op_attr file_attributes;
1592*4882a593Smuzhiyun * };
1593*4882a593Smuzhiyun *
1594*4882a593Smuzhiyun * union READ3res switch (nfsstat3 status) {
1595*4882a593Smuzhiyun * case NFS3_OK:
1596*4882a593Smuzhiyun * READ3resok resok;
1597*4882a593Smuzhiyun * default:
1598*4882a593Smuzhiyun * READ3resfail resfail;
1599*4882a593Smuzhiyun * };
1600*4882a593Smuzhiyun */
decode_read3resok(struct xdr_stream * xdr,struct nfs_pgio_res * result)1601*4882a593Smuzhiyun static int decode_read3resok(struct xdr_stream *xdr,
1602*4882a593Smuzhiyun struct nfs_pgio_res *result)
1603*4882a593Smuzhiyun {
1604*4882a593Smuzhiyun u32 eof, count, ocount, recvd;
1605*4882a593Smuzhiyun __be32 *p;
1606*4882a593Smuzhiyun
1607*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4 + 4 + 4);
1608*4882a593Smuzhiyun if (unlikely(!p))
1609*4882a593Smuzhiyun return -EIO;
1610*4882a593Smuzhiyun count = be32_to_cpup(p++);
1611*4882a593Smuzhiyun eof = be32_to_cpup(p++);
1612*4882a593Smuzhiyun ocount = be32_to_cpup(p++);
1613*4882a593Smuzhiyun if (unlikely(ocount != count))
1614*4882a593Smuzhiyun goto out_mismatch;
1615*4882a593Smuzhiyun recvd = xdr_read_pages(xdr, count);
1616*4882a593Smuzhiyun if (unlikely(count > recvd))
1617*4882a593Smuzhiyun goto out_cheating;
1618*4882a593Smuzhiyun out:
1619*4882a593Smuzhiyun result->eof = eof;
1620*4882a593Smuzhiyun result->count = count;
1621*4882a593Smuzhiyun return count;
1622*4882a593Smuzhiyun out_mismatch:
1623*4882a593Smuzhiyun dprintk("NFS: READ count doesn't match length of opaque: "
1624*4882a593Smuzhiyun "count %u != ocount %u\n", count, ocount);
1625*4882a593Smuzhiyun return -EIO;
1626*4882a593Smuzhiyun out_cheating:
1627*4882a593Smuzhiyun dprintk("NFS: server cheating in read result: "
1628*4882a593Smuzhiyun "count %u > recvd %u\n", count, recvd);
1629*4882a593Smuzhiyun count = recvd;
1630*4882a593Smuzhiyun eof = 0;
1631*4882a593Smuzhiyun goto out;
1632*4882a593Smuzhiyun }
1633*4882a593Smuzhiyun
nfs3_xdr_dec_read3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1634*4882a593Smuzhiyun static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1635*4882a593Smuzhiyun void *data)
1636*4882a593Smuzhiyun {
1637*4882a593Smuzhiyun struct nfs_pgio_res *result = data;
1638*4882a593Smuzhiyun unsigned int pos;
1639*4882a593Smuzhiyun enum nfs_stat status;
1640*4882a593Smuzhiyun int error;
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun pos = xdr_stream_pos(xdr);
1643*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1644*4882a593Smuzhiyun if (unlikely(error))
1645*4882a593Smuzhiyun goto out;
1646*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
1647*4882a593Smuzhiyun if (unlikely(error))
1648*4882a593Smuzhiyun goto out;
1649*4882a593Smuzhiyun result->op_status = status;
1650*4882a593Smuzhiyun if (status != NFS3_OK)
1651*4882a593Smuzhiyun goto out_status;
1652*4882a593Smuzhiyun result->replen = 4 + ((xdr_stream_pos(xdr) - pos) >> 2);
1653*4882a593Smuzhiyun error = decode_read3resok(xdr, result);
1654*4882a593Smuzhiyun out:
1655*4882a593Smuzhiyun return error;
1656*4882a593Smuzhiyun out_status:
1657*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1658*4882a593Smuzhiyun }
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun /*
1661*4882a593Smuzhiyun * 3.3.7 WRITE3res
1662*4882a593Smuzhiyun *
1663*4882a593Smuzhiyun * enum stable_how {
1664*4882a593Smuzhiyun * UNSTABLE = 0,
1665*4882a593Smuzhiyun * DATA_SYNC = 1,
1666*4882a593Smuzhiyun * FILE_SYNC = 2
1667*4882a593Smuzhiyun * };
1668*4882a593Smuzhiyun *
1669*4882a593Smuzhiyun * struct WRITE3resok {
1670*4882a593Smuzhiyun * wcc_data file_wcc;
1671*4882a593Smuzhiyun * count3 count;
1672*4882a593Smuzhiyun * stable_how committed;
1673*4882a593Smuzhiyun * writeverf3 verf;
1674*4882a593Smuzhiyun * };
1675*4882a593Smuzhiyun *
1676*4882a593Smuzhiyun * struct WRITE3resfail {
1677*4882a593Smuzhiyun * wcc_data file_wcc;
1678*4882a593Smuzhiyun * };
1679*4882a593Smuzhiyun *
1680*4882a593Smuzhiyun * union WRITE3res switch (nfsstat3 status) {
1681*4882a593Smuzhiyun * case NFS3_OK:
1682*4882a593Smuzhiyun * WRITE3resok resok;
1683*4882a593Smuzhiyun * default:
1684*4882a593Smuzhiyun * WRITE3resfail resfail;
1685*4882a593Smuzhiyun * };
1686*4882a593Smuzhiyun */
decode_write3resok(struct xdr_stream * xdr,struct nfs_pgio_res * result)1687*4882a593Smuzhiyun static int decode_write3resok(struct xdr_stream *xdr,
1688*4882a593Smuzhiyun struct nfs_pgio_res *result)
1689*4882a593Smuzhiyun {
1690*4882a593Smuzhiyun __be32 *p;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4 + 4);
1693*4882a593Smuzhiyun if (unlikely(!p))
1694*4882a593Smuzhiyun return -EIO;
1695*4882a593Smuzhiyun result->count = be32_to_cpup(p++);
1696*4882a593Smuzhiyun result->verf->committed = be32_to_cpup(p++);
1697*4882a593Smuzhiyun if (unlikely(result->verf->committed > NFS_FILE_SYNC))
1698*4882a593Smuzhiyun goto out_badvalue;
1699*4882a593Smuzhiyun if (decode_writeverf3(xdr, &result->verf->verifier))
1700*4882a593Smuzhiyun return -EIO;
1701*4882a593Smuzhiyun return result->count;
1702*4882a593Smuzhiyun out_badvalue:
1703*4882a593Smuzhiyun dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
1704*4882a593Smuzhiyun return -EIO;
1705*4882a593Smuzhiyun }
1706*4882a593Smuzhiyun
nfs3_xdr_dec_write3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1707*4882a593Smuzhiyun static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1708*4882a593Smuzhiyun void *data)
1709*4882a593Smuzhiyun {
1710*4882a593Smuzhiyun struct nfs_pgio_res *result = data;
1711*4882a593Smuzhiyun enum nfs_stat status;
1712*4882a593Smuzhiyun int error;
1713*4882a593Smuzhiyun
1714*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1715*4882a593Smuzhiyun if (unlikely(error))
1716*4882a593Smuzhiyun goto out;
1717*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
1718*4882a593Smuzhiyun if (unlikely(error))
1719*4882a593Smuzhiyun goto out;
1720*4882a593Smuzhiyun result->op_status = status;
1721*4882a593Smuzhiyun if (status != NFS3_OK)
1722*4882a593Smuzhiyun goto out_status;
1723*4882a593Smuzhiyun error = decode_write3resok(xdr, result);
1724*4882a593Smuzhiyun out:
1725*4882a593Smuzhiyun return error;
1726*4882a593Smuzhiyun out_status:
1727*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1728*4882a593Smuzhiyun }
1729*4882a593Smuzhiyun
1730*4882a593Smuzhiyun /*
1731*4882a593Smuzhiyun * 3.3.8 CREATE3res
1732*4882a593Smuzhiyun *
1733*4882a593Smuzhiyun * struct CREATE3resok {
1734*4882a593Smuzhiyun * post_op_fh3 obj;
1735*4882a593Smuzhiyun * post_op_attr obj_attributes;
1736*4882a593Smuzhiyun * wcc_data dir_wcc;
1737*4882a593Smuzhiyun * };
1738*4882a593Smuzhiyun *
1739*4882a593Smuzhiyun * struct CREATE3resfail {
1740*4882a593Smuzhiyun * wcc_data dir_wcc;
1741*4882a593Smuzhiyun * };
1742*4882a593Smuzhiyun *
1743*4882a593Smuzhiyun * union CREATE3res switch (nfsstat3 status) {
1744*4882a593Smuzhiyun * case NFS3_OK:
1745*4882a593Smuzhiyun * CREATE3resok resok;
1746*4882a593Smuzhiyun * default:
1747*4882a593Smuzhiyun * CREATE3resfail resfail;
1748*4882a593Smuzhiyun * };
1749*4882a593Smuzhiyun */
decode_create3resok(struct xdr_stream * xdr,struct nfs3_diropres * result,struct user_namespace * userns)1750*4882a593Smuzhiyun static int decode_create3resok(struct xdr_stream *xdr,
1751*4882a593Smuzhiyun struct nfs3_diropres *result,
1752*4882a593Smuzhiyun struct user_namespace *userns)
1753*4882a593Smuzhiyun {
1754*4882a593Smuzhiyun int error;
1755*4882a593Smuzhiyun
1756*4882a593Smuzhiyun error = decode_post_op_fh3(xdr, result->fh);
1757*4882a593Smuzhiyun if (unlikely(error))
1758*4882a593Smuzhiyun goto out;
1759*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, userns);
1760*4882a593Smuzhiyun if (unlikely(error))
1761*4882a593Smuzhiyun goto out;
1762*4882a593Smuzhiyun /* The server isn't required to return a file handle.
1763*4882a593Smuzhiyun * If it didn't, force the client to perform a LOOKUP
1764*4882a593Smuzhiyun * to determine the correct file handle and attribute
1765*4882a593Smuzhiyun * values for the new object. */
1766*4882a593Smuzhiyun if (result->fh->size == 0)
1767*4882a593Smuzhiyun result->fattr->valid = 0;
1768*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->dir_attr, userns);
1769*4882a593Smuzhiyun out:
1770*4882a593Smuzhiyun return error;
1771*4882a593Smuzhiyun }
1772*4882a593Smuzhiyun
nfs3_xdr_dec_create3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1773*4882a593Smuzhiyun static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
1774*4882a593Smuzhiyun struct xdr_stream *xdr,
1775*4882a593Smuzhiyun void *data)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun struct user_namespace *userns = rpc_rqst_userns(req);
1778*4882a593Smuzhiyun struct nfs3_diropres *result = data;
1779*4882a593Smuzhiyun enum nfs_stat status;
1780*4882a593Smuzhiyun int error;
1781*4882a593Smuzhiyun
1782*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1783*4882a593Smuzhiyun if (unlikely(error))
1784*4882a593Smuzhiyun goto out;
1785*4882a593Smuzhiyun if (status != NFS3_OK)
1786*4882a593Smuzhiyun goto out_default;
1787*4882a593Smuzhiyun error = decode_create3resok(xdr, result, userns);
1788*4882a593Smuzhiyun out:
1789*4882a593Smuzhiyun return error;
1790*4882a593Smuzhiyun out_default:
1791*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->dir_attr, userns);
1792*4882a593Smuzhiyun if (unlikely(error))
1793*4882a593Smuzhiyun goto out;
1794*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1795*4882a593Smuzhiyun }
1796*4882a593Smuzhiyun
1797*4882a593Smuzhiyun /*
1798*4882a593Smuzhiyun * 3.3.12 REMOVE3res
1799*4882a593Smuzhiyun *
1800*4882a593Smuzhiyun * struct REMOVE3resok {
1801*4882a593Smuzhiyun * wcc_data dir_wcc;
1802*4882a593Smuzhiyun * };
1803*4882a593Smuzhiyun *
1804*4882a593Smuzhiyun * struct REMOVE3resfail {
1805*4882a593Smuzhiyun * wcc_data dir_wcc;
1806*4882a593Smuzhiyun * };
1807*4882a593Smuzhiyun *
1808*4882a593Smuzhiyun * union REMOVE3res switch (nfsstat3 status) {
1809*4882a593Smuzhiyun * case NFS3_OK:
1810*4882a593Smuzhiyun * REMOVE3resok resok;
1811*4882a593Smuzhiyun * default:
1812*4882a593Smuzhiyun * REMOVE3resfail resfail;
1813*4882a593Smuzhiyun * };
1814*4882a593Smuzhiyun */
nfs3_xdr_dec_remove3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1815*4882a593Smuzhiyun static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
1816*4882a593Smuzhiyun struct xdr_stream *xdr,
1817*4882a593Smuzhiyun void *data)
1818*4882a593Smuzhiyun {
1819*4882a593Smuzhiyun struct nfs_removeres *result = data;
1820*4882a593Smuzhiyun enum nfs_stat status;
1821*4882a593Smuzhiyun int error;
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1824*4882a593Smuzhiyun if (unlikely(error))
1825*4882a593Smuzhiyun goto out;
1826*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->dir_attr, rpc_rqst_userns(req));
1827*4882a593Smuzhiyun if (unlikely(error))
1828*4882a593Smuzhiyun goto out;
1829*4882a593Smuzhiyun if (status != NFS3_OK)
1830*4882a593Smuzhiyun goto out_status;
1831*4882a593Smuzhiyun out:
1832*4882a593Smuzhiyun return error;
1833*4882a593Smuzhiyun out_status:
1834*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1835*4882a593Smuzhiyun }
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun /*
1838*4882a593Smuzhiyun * 3.3.14 RENAME3res
1839*4882a593Smuzhiyun *
1840*4882a593Smuzhiyun * struct RENAME3resok {
1841*4882a593Smuzhiyun * wcc_data fromdir_wcc;
1842*4882a593Smuzhiyun * wcc_data todir_wcc;
1843*4882a593Smuzhiyun * };
1844*4882a593Smuzhiyun *
1845*4882a593Smuzhiyun * struct RENAME3resfail {
1846*4882a593Smuzhiyun * wcc_data fromdir_wcc;
1847*4882a593Smuzhiyun * wcc_data todir_wcc;
1848*4882a593Smuzhiyun * };
1849*4882a593Smuzhiyun *
1850*4882a593Smuzhiyun * union RENAME3res switch (nfsstat3 status) {
1851*4882a593Smuzhiyun * case NFS3_OK:
1852*4882a593Smuzhiyun * RENAME3resok resok;
1853*4882a593Smuzhiyun * default:
1854*4882a593Smuzhiyun * RENAME3resfail resfail;
1855*4882a593Smuzhiyun * };
1856*4882a593Smuzhiyun */
nfs3_xdr_dec_rename3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1857*4882a593Smuzhiyun static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
1858*4882a593Smuzhiyun struct xdr_stream *xdr,
1859*4882a593Smuzhiyun void *data)
1860*4882a593Smuzhiyun {
1861*4882a593Smuzhiyun struct user_namespace *userns = rpc_rqst_userns(req);
1862*4882a593Smuzhiyun struct nfs_renameres *result = data;
1863*4882a593Smuzhiyun enum nfs_stat status;
1864*4882a593Smuzhiyun int error;
1865*4882a593Smuzhiyun
1866*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1867*4882a593Smuzhiyun if (unlikely(error))
1868*4882a593Smuzhiyun goto out;
1869*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->old_fattr, userns);
1870*4882a593Smuzhiyun if (unlikely(error))
1871*4882a593Smuzhiyun goto out;
1872*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->new_fattr, userns);
1873*4882a593Smuzhiyun if (unlikely(error))
1874*4882a593Smuzhiyun goto out;
1875*4882a593Smuzhiyun if (status != NFS3_OK)
1876*4882a593Smuzhiyun goto out_status;
1877*4882a593Smuzhiyun out:
1878*4882a593Smuzhiyun return error;
1879*4882a593Smuzhiyun out_status:
1880*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1881*4882a593Smuzhiyun }
1882*4882a593Smuzhiyun
1883*4882a593Smuzhiyun /*
1884*4882a593Smuzhiyun * 3.3.15 LINK3res
1885*4882a593Smuzhiyun *
1886*4882a593Smuzhiyun * struct LINK3resok {
1887*4882a593Smuzhiyun * post_op_attr file_attributes;
1888*4882a593Smuzhiyun * wcc_data linkdir_wcc;
1889*4882a593Smuzhiyun * };
1890*4882a593Smuzhiyun *
1891*4882a593Smuzhiyun * struct LINK3resfail {
1892*4882a593Smuzhiyun * post_op_attr file_attributes;
1893*4882a593Smuzhiyun * wcc_data linkdir_wcc;
1894*4882a593Smuzhiyun * };
1895*4882a593Smuzhiyun *
1896*4882a593Smuzhiyun * union LINK3res switch (nfsstat3 status) {
1897*4882a593Smuzhiyun * case NFS3_OK:
1898*4882a593Smuzhiyun * LINK3resok resok;
1899*4882a593Smuzhiyun * default:
1900*4882a593Smuzhiyun * LINK3resfail resfail;
1901*4882a593Smuzhiyun * };
1902*4882a593Smuzhiyun */
nfs3_xdr_dec_link3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1903*4882a593Smuzhiyun static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1904*4882a593Smuzhiyun void *data)
1905*4882a593Smuzhiyun {
1906*4882a593Smuzhiyun struct user_namespace *userns = rpc_rqst_userns(req);
1907*4882a593Smuzhiyun struct nfs3_linkres *result = data;
1908*4882a593Smuzhiyun enum nfs_stat status;
1909*4882a593Smuzhiyun int error;
1910*4882a593Smuzhiyun
1911*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
1912*4882a593Smuzhiyun if (unlikely(error))
1913*4882a593Smuzhiyun goto out;
1914*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, userns);
1915*4882a593Smuzhiyun if (unlikely(error))
1916*4882a593Smuzhiyun goto out;
1917*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->dir_attr, userns);
1918*4882a593Smuzhiyun if (unlikely(error))
1919*4882a593Smuzhiyun goto out;
1920*4882a593Smuzhiyun if (status != NFS3_OK)
1921*4882a593Smuzhiyun goto out_status;
1922*4882a593Smuzhiyun out:
1923*4882a593Smuzhiyun return error;
1924*4882a593Smuzhiyun out_status:
1925*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
1926*4882a593Smuzhiyun }
1927*4882a593Smuzhiyun
1928*4882a593Smuzhiyun /**
1929*4882a593Smuzhiyun * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
1930*4882a593Smuzhiyun * the local page cache
1931*4882a593Smuzhiyun * @xdr: XDR stream where entry resides
1932*4882a593Smuzhiyun * @entry: buffer to fill in with entry data
1933*4882a593Smuzhiyun * @plus: boolean indicating whether this should be a readdirplus entry
1934*4882a593Smuzhiyun *
1935*4882a593Smuzhiyun * Returns zero if successful, otherwise a negative errno value is
1936*4882a593Smuzhiyun * returned.
1937*4882a593Smuzhiyun *
1938*4882a593Smuzhiyun * This function is not invoked during READDIR reply decoding, but
1939*4882a593Smuzhiyun * rather whenever an application invokes the getdents(2) system call
1940*4882a593Smuzhiyun * on a directory already in our cache.
1941*4882a593Smuzhiyun *
1942*4882a593Smuzhiyun * 3.3.16 entry3
1943*4882a593Smuzhiyun *
1944*4882a593Smuzhiyun * struct entry3 {
1945*4882a593Smuzhiyun * fileid3 fileid;
1946*4882a593Smuzhiyun * filename3 name;
1947*4882a593Smuzhiyun * cookie3 cookie;
1948*4882a593Smuzhiyun * fhandle3 filehandle;
1949*4882a593Smuzhiyun * post_op_attr3 attributes;
1950*4882a593Smuzhiyun * entry3 *nextentry;
1951*4882a593Smuzhiyun * };
1952*4882a593Smuzhiyun *
1953*4882a593Smuzhiyun * 3.3.17 entryplus3
1954*4882a593Smuzhiyun * struct entryplus3 {
1955*4882a593Smuzhiyun * fileid3 fileid;
1956*4882a593Smuzhiyun * filename3 name;
1957*4882a593Smuzhiyun * cookie3 cookie;
1958*4882a593Smuzhiyun * post_op_attr name_attributes;
1959*4882a593Smuzhiyun * post_op_fh3 name_handle;
1960*4882a593Smuzhiyun * entryplus3 *nextentry;
1961*4882a593Smuzhiyun * };
1962*4882a593Smuzhiyun */
nfs3_decode_dirent(struct xdr_stream * xdr,struct nfs_entry * entry,bool plus)1963*4882a593Smuzhiyun int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1964*4882a593Smuzhiyun bool plus)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun struct user_namespace *userns = rpc_userns(entry->server->client);
1967*4882a593Smuzhiyun __be32 *p;
1968*4882a593Smuzhiyun int error;
1969*4882a593Smuzhiyun u64 new_cookie;
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
1972*4882a593Smuzhiyun if (unlikely(!p))
1973*4882a593Smuzhiyun return -EAGAIN;
1974*4882a593Smuzhiyun if (*p == xdr_zero) {
1975*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
1976*4882a593Smuzhiyun if (unlikely(!p))
1977*4882a593Smuzhiyun return -EAGAIN;
1978*4882a593Smuzhiyun if (*p == xdr_zero)
1979*4882a593Smuzhiyun return -EAGAIN;
1980*4882a593Smuzhiyun entry->eof = 1;
1981*4882a593Smuzhiyun return -EBADCOOKIE;
1982*4882a593Smuzhiyun }
1983*4882a593Smuzhiyun
1984*4882a593Smuzhiyun error = decode_fileid3(xdr, &entry->ino);
1985*4882a593Smuzhiyun if (unlikely(error))
1986*4882a593Smuzhiyun return -EAGAIN;
1987*4882a593Smuzhiyun
1988*4882a593Smuzhiyun error = decode_inline_filename3(xdr, &entry->name, &entry->len);
1989*4882a593Smuzhiyun if (unlikely(error))
1990*4882a593Smuzhiyun return -EAGAIN;
1991*4882a593Smuzhiyun
1992*4882a593Smuzhiyun error = decode_cookie3(xdr, &new_cookie);
1993*4882a593Smuzhiyun if (unlikely(error))
1994*4882a593Smuzhiyun return -EAGAIN;
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun entry->d_type = DT_UNKNOWN;
1997*4882a593Smuzhiyun
1998*4882a593Smuzhiyun if (plus) {
1999*4882a593Smuzhiyun entry->fattr->valid = 0;
2000*4882a593Smuzhiyun error = decode_post_op_attr(xdr, entry->fattr, userns);
2001*4882a593Smuzhiyun if (unlikely(error))
2002*4882a593Smuzhiyun return -EAGAIN;
2003*4882a593Smuzhiyun if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
2004*4882a593Smuzhiyun entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
2005*4882a593Smuzhiyun
2006*4882a593Smuzhiyun if (entry->fattr->fileid != entry->ino) {
2007*4882a593Smuzhiyun entry->fattr->mounted_on_fileid = entry->ino;
2008*4882a593Smuzhiyun entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
2009*4882a593Smuzhiyun }
2010*4882a593Smuzhiyun
2011*4882a593Smuzhiyun /* In fact, a post_op_fh3: */
2012*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
2013*4882a593Smuzhiyun if (unlikely(!p))
2014*4882a593Smuzhiyun return -EAGAIN;
2015*4882a593Smuzhiyun if (*p != xdr_zero) {
2016*4882a593Smuzhiyun error = decode_nfs_fh3(xdr, entry->fh);
2017*4882a593Smuzhiyun if (unlikely(error))
2018*4882a593Smuzhiyun return -EAGAIN;
2019*4882a593Smuzhiyun } else
2020*4882a593Smuzhiyun zero_nfs_fh3(entry->fh);
2021*4882a593Smuzhiyun }
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun entry->prev_cookie = entry->cookie;
2024*4882a593Smuzhiyun entry->cookie = new_cookie;
2025*4882a593Smuzhiyun
2026*4882a593Smuzhiyun return 0;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun
2029*4882a593Smuzhiyun /*
2030*4882a593Smuzhiyun * 3.3.16 READDIR3res
2031*4882a593Smuzhiyun *
2032*4882a593Smuzhiyun * struct dirlist3 {
2033*4882a593Smuzhiyun * entry3 *entries;
2034*4882a593Smuzhiyun * bool eof;
2035*4882a593Smuzhiyun * };
2036*4882a593Smuzhiyun *
2037*4882a593Smuzhiyun * struct READDIR3resok {
2038*4882a593Smuzhiyun * post_op_attr dir_attributes;
2039*4882a593Smuzhiyun * cookieverf3 cookieverf;
2040*4882a593Smuzhiyun * dirlist3 reply;
2041*4882a593Smuzhiyun * };
2042*4882a593Smuzhiyun *
2043*4882a593Smuzhiyun * struct READDIR3resfail {
2044*4882a593Smuzhiyun * post_op_attr dir_attributes;
2045*4882a593Smuzhiyun * };
2046*4882a593Smuzhiyun *
2047*4882a593Smuzhiyun * union READDIR3res switch (nfsstat3 status) {
2048*4882a593Smuzhiyun * case NFS3_OK:
2049*4882a593Smuzhiyun * READDIR3resok resok;
2050*4882a593Smuzhiyun * default:
2051*4882a593Smuzhiyun * READDIR3resfail resfail;
2052*4882a593Smuzhiyun * };
2053*4882a593Smuzhiyun *
2054*4882a593Smuzhiyun * Read the directory contents into the page cache, but otherwise
2055*4882a593Smuzhiyun * don't touch them. The actual decoding is done by nfs3_decode_entry()
2056*4882a593Smuzhiyun * during subsequent nfs_readdir() calls.
2057*4882a593Smuzhiyun */
decode_dirlist3(struct xdr_stream * xdr)2058*4882a593Smuzhiyun static int decode_dirlist3(struct xdr_stream *xdr)
2059*4882a593Smuzhiyun {
2060*4882a593Smuzhiyun return xdr_read_pages(xdr, xdr->buf->page_len);
2061*4882a593Smuzhiyun }
2062*4882a593Smuzhiyun
decode_readdir3resok(struct xdr_stream * xdr,struct nfs3_readdirres * result,struct user_namespace * userns)2063*4882a593Smuzhiyun static int decode_readdir3resok(struct xdr_stream *xdr,
2064*4882a593Smuzhiyun struct nfs3_readdirres *result,
2065*4882a593Smuzhiyun struct user_namespace *userns)
2066*4882a593Smuzhiyun {
2067*4882a593Smuzhiyun int error;
2068*4882a593Smuzhiyun
2069*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->dir_attr, userns);
2070*4882a593Smuzhiyun if (unlikely(error))
2071*4882a593Smuzhiyun goto out;
2072*4882a593Smuzhiyun /* XXX: do we need to check if result->verf != NULL ? */
2073*4882a593Smuzhiyun error = decode_cookieverf3(xdr, result->verf);
2074*4882a593Smuzhiyun if (unlikely(error))
2075*4882a593Smuzhiyun goto out;
2076*4882a593Smuzhiyun error = decode_dirlist3(xdr);
2077*4882a593Smuzhiyun out:
2078*4882a593Smuzhiyun return error;
2079*4882a593Smuzhiyun }
2080*4882a593Smuzhiyun
nfs3_xdr_dec_readdir3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2081*4882a593Smuzhiyun static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
2082*4882a593Smuzhiyun struct xdr_stream *xdr,
2083*4882a593Smuzhiyun void *data)
2084*4882a593Smuzhiyun {
2085*4882a593Smuzhiyun struct nfs3_readdirres *result = data;
2086*4882a593Smuzhiyun enum nfs_stat status;
2087*4882a593Smuzhiyun int error;
2088*4882a593Smuzhiyun
2089*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2090*4882a593Smuzhiyun if (unlikely(error))
2091*4882a593Smuzhiyun goto out;
2092*4882a593Smuzhiyun if (status != NFS3_OK)
2093*4882a593Smuzhiyun goto out_default;
2094*4882a593Smuzhiyun error = decode_readdir3resok(xdr, result, rpc_rqst_userns(req));
2095*4882a593Smuzhiyun out:
2096*4882a593Smuzhiyun return error;
2097*4882a593Smuzhiyun out_default:
2098*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req));
2099*4882a593Smuzhiyun if (unlikely(error))
2100*4882a593Smuzhiyun goto out;
2101*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2102*4882a593Smuzhiyun }
2103*4882a593Smuzhiyun
2104*4882a593Smuzhiyun /*
2105*4882a593Smuzhiyun * 3.3.18 FSSTAT3res
2106*4882a593Smuzhiyun *
2107*4882a593Smuzhiyun * struct FSSTAT3resok {
2108*4882a593Smuzhiyun * post_op_attr obj_attributes;
2109*4882a593Smuzhiyun * size3 tbytes;
2110*4882a593Smuzhiyun * size3 fbytes;
2111*4882a593Smuzhiyun * size3 abytes;
2112*4882a593Smuzhiyun * size3 tfiles;
2113*4882a593Smuzhiyun * size3 ffiles;
2114*4882a593Smuzhiyun * size3 afiles;
2115*4882a593Smuzhiyun * uint32 invarsec;
2116*4882a593Smuzhiyun * };
2117*4882a593Smuzhiyun *
2118*4882a593Smuzhiyun * struct FSSTAT3resfail {
2119*4882a593Smuzhiyun * post_op_attr obj_attributes;
2120*4882a593Smuzhiyun * };
2121*4882a593Smuzhiyun *
2122*4882a593Smuzhiyun * union FSSTAT3res switch (nfsstat3 status) {
2123*4882a593Smuzhiyun * case NFS3_OK:
2124*4882a593Smuzhiyun * FSSTAT3resok resok;
2125*4882a593Smuzhiyun * default:
2126*4882a593Smuzhiyun * FSSTAT3resfail resfail;
2127*4882a593Smuzhiyun * };
2128*4882a593Smuzhiyun */
decode_fsstat3resok(struct xdr_stream * xdr,struct nfs_fsstat * result)2129*4882a593Smuzhiyun static int decode_fsstat3resok(struct xdr_stream *xdr,
2130*4882a593Smuzhiyun struct nfs_fsstat *result)
2131*4882a593Smuzhiyun {
2132*4882a593Smuzhiyun __be32 *p;
2133*4882a593Smuzhiyun
2134*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 8 * 6 + 4);
2135*4882a593Smuzhiyun if (unlikely(!p))
2136*4882a593Smuzhiyun return -EIO;
2137*4882a593Smuzhiyun p = xdr_decode_size3(p, &result->tbytes);
2138*4882a593Smuzhiyun p = xdr_decode_size3(p, &result->fbytes);
2139*4882a593Smuzhiyun p = xdr_decode_size3(p, &result->abytes);
2140*4882a593Smuzhiyun p = xdr_decode_size3(p, &result->tfiles);
2141*4882a593Smuzhiyun p = xdr_decode_size3(p, &result->ffiles);
2142*4882a593Smuzhiyun xdr_decode_size3(p, &result->afiles);
2143*4882a593Smuzhiyun /* ignore invarsec */
2144*4882a593Smuzhiyun return 0;
2145*4882a593Smuzhiyun }
2146*4882a593Smuzhiyun
nfs3_xdr_dec_fsstat3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2147*4882a593Smuzhiyun static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
2148*4882a593Smuzhiyun struct xdr_stream *xdr,
2149*4882a593Smuzhiyun void *data)
2150*4882a593Smuzhiyun {
2151*4882a593Smuzhiyun struct nfs_fsstat *result = data;
2152*4882a593Smuzhiyun enum nfs_stat status;
2153*4882a593Smuzhiyun int error;
2154*4882a593Smuzhiyun
2155*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2156*4882a593Smuzhiyun if (unlikely(error))
2157*4882a593Smuzhiyun goto out;
2158*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
2159*4882a593Smuzhiyun if (unlikely(error))
2160*4882a593Smuzhiyun goto out;
2161*4882a593Smuzhiyun if (status != NFS3_OK)
2162*4882a593Smuzhiyun goto out_status;
2163*4882a593Smuzhiyun error = decode_fsstat3resok(xdr, result);
2164*4882a593Smuzhiyun out:
2165*4882a593Smuzhiyun return error;
2166*4882a593Smuzhiyun out_status:
2167*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2168*4882a593Smuzhiyun }
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun /*
2171*4882a593Smuzhiyun * 3.3.19 FSINFO3res
2172*4882a593Smuzhiyun *
2173*4882a593Smuzhiyun * struct FSINFO3resok {
2174*4882a593Smuzhiyun * post_op_attr obj_attributes;
2175*4882a593Smuzhiyun * uint32 rtmax;
2176*4882a593Smuzhiyun * uint32 rtpref;
2177*4882a593Smuzhiyun * uint32 rtmult;
2178*4882a593Smuzhiyun * uint32 wtmax;
2179*4882a593Smuzhiyun * uint32 wtpref;
2180*4882a593Smuzhiyun * uint32 wtmult;
2181*4882a593Smuzhiyun * uint32 dtpref;
2182*4882a593Smuzhiyun * size3 maxfilesize;
2183*4882a593Smuzhiyun * nfstime3 time_delta;
2184*4882a593Smuzhiyun * uint32 properties;
2185*4882a593Smuzhiyun * };
2186*4882a593Smuzhiyun *
2187*4882a593Smuzhiyun * struct FSINFO3resfail {
2188*4882a593Smuzhiyun * post_op_attr obj_attributes;
2189*4882a593Smuzhiyun * };
2190*4882a593Smuzhiyun *
2191*4882a593Smuzhiyun * union FSINFO3res switch (nfsstat3 status) {
2192*4882a593Smuzhiyun * case NFS3_OK:
2193*4882a593Smuzhiyun * FSINFO3resok resok;
2194*4882a593Smuzhiyun * default:
2195*4882a593Smuzhiyun * FSINFO3resfail resfail;
2196*4882a593Smuzhiyun * };
2197*4882a593Smuzhiyun */
decode_fsinfo3resok(struct xdr_stream * xdr,struct nfs_fsinfo * result)2198*4882a593Smuzhiyun static int decode_fsinfo3resok(struct xdr_stream *xdr,
2199*4882a593Smuzhiyun struct nfs_fsinfo *result)
2200*4882a593Smuzhiyun {
2201*4882a593Smuzhiyun __be32 *p;
2202*4882a593Smuzhiyun
2203*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
2204*4882a593Smuzhiyun if (unlikely(!p))
2205*4882a593Smuzhiyun return -EIO;
2206*4882a593Smuzhiyun result->rtmax = be32_to_cpup(p++);
2207*4882a593Smuzhiyun result->rtpref = be32_to_cpup(p++);
2208*4882a593Smuzhiyun result->rtmult = be32_to_cpup(p++);
2209*4882a593Smuzhiyun result->wtmax = be32_to_cpup(p++);
2210*4882a593Smuzhiyun result->wtpref = be32_to_cpup(p++);
2211*4882a593Smuzhiyun result->wtmult = be32_to_cpup(p++);
2212*4882a593Smuzhiyun result->dtpref = be32_to_cpup(p++);
2213*4882a593Smuzhiyun p = xdr_decode_size3(p, &result->maxfilesize);
2214*4882a593Smuzhiyun xdr_decode_nfstime3(p, &result->time_delta);
2215*4882a593Smuzhiyun
2216*4882a593Smuzhiyun /* ignore properties */
2217*4882a593Smuzhiyun result->lease_time = 0;
2218*4882a593Smuzhiyun return 0;
2219*4882a593Smuzhiyun }
2220*4882a593Smuzhiyun
nfs3_xdr_dec_fsinfo3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2221*4882a593Smuzhiyun static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
2222*4882a593Smuzhiyun struct xdr_stream *xdr,
2223*4882a593Smuzhiyun void *data)
2224*4882a593Smuzhiyun {
2225*4882a593Smuzhiyun struct nfs_fsinfo *result = data;
2226*4882a593Smuzhiyun enum nfs_stat status;
2227*4882a593Smuzhiyun int error;
2228*4882a593Smuzhiyun
2229*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2230*4882a593Smuzhiyun if (unlikely(error))
2231*4882a593Smuzhiyun goto out;
2232*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
2233*4882a593Smuzhiyun if (unlikely(error))
2234*4882a593Smuzhiyun goto out;
2235*4882a593Smuzhiyun if (status != NFS3_OK)
2236*4882a593Smuzhiyun goto out_status;
2237*4882a593Smuzhiyun error = decode_fsinfo3resok(xdr, result);
2238*4882a593Smuzhiyun out:
2239*4882a593Smuzhiyun return error;
2240*4882a593Smuzhiyun out_status:
2241*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2242*4882a593Smuzhiyun }
2243*4882a593Smuzhiyun
2244*4882a593Smuzhiyun /*
2245*4882a593Smuzhiyun * 3.3.20 PATHCONF3res
2246*4882a593Smuzhiyun *
2247*4882a593Smuzhiyun * struct PATHCONF3resok {
2248*4882a593Smuzhiyun * post_op_attr obj_attributes;
2249*4882a593Smuzhiyun * uint32 linkmax;
2250*4882a593Smuzhiyun * uint32 name_max;
2251*4882a593Smuzhiyun * bool no_trunc;
2252*4882a593Smuzhiyun * bool chown_restricted;
2253*4882a593Smuzhiyun * bool case_insensitive;
2254*4882a593Smuzhiyun * bool case_preserving;
2255*4882a593Smuzhiyun * };
2256*4882a593Smuzhiyun *
2257*4882a593Smuzhiyun * struct PATHCONF3resfail {
2258*4882a593Smuzhiyun * post_op_attr obj_attributes;
2259*4882a593Smuzhiyun * };
2260*4882a593Smuzhiyun *
2261*4882a593Smuzhiyun * union PATHCONF3res switch (nfsstat3 status) {
2262*4882a593Smuzhiyun * case NFS3_OK:
2263*4882a593Smuzhiyun * PATHCONF3resok resok;
2264*4882a593Smuzhiyun * default:
2265*4882a593Smuzhiyun * PATHCONF3resfail resfail;
2266*4882a593Smuzhiyun * };
2267*4882a593Smuzhiyun */
decode_pathconf3resok(struct xdr_stream * xdr,struct nfs_pathconf * result)2268*4882a593Smuzhiyun static int decode_pathconf3resok(struct xdr_stream *xdr,
2269*4882a593Smuzhiyun struct nfs_pathconf *result)
2270*4882a593Smuzhiyun {
2271*4882a593Smuzhiyun __be32 *p;
2272*4882a593Smuzhiyun
2273*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4 * 6);
2274*4882a593Smuzhiyun if (unlikely(!p))
2275*4882a593Smuzhiyun return -EIO;
2276*4882a593Smuzhiyun result->max_link = be32_to_cpup(p++);
2277*4882a593Smuzhiyun result->max_namelen = be32_to_cpup(p);
2278*4882a593Smuzhiyun /* ignore remaining fields */
2279*4882a593Smuzhiyun return 0;
2280*4882a593Smuzhiyun }
2281*4882a593Smuzhiyun
nfs3_xdr_dec_pathconf3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2282*4882a593Smuzhiyun static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
2283*4882a593Smuzhiyun struct xdr_stream *xdr,
2284*4882a593Smuzhiyun void *data)
2285*4882a593Smuzhiyun {
2286*4882a593Smuzhiyun struct nfs_pathconf *result = data;
2287*4882a593Smuzhiyun enum nfs_stat status;
2288*4882a593Smuzhiyun int error;
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2291*4882a593Smuzhiyun if (unlikely(error))
2292*4882a593Smuzhiyun goto out;
2293*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
2294*4882a593Smuzhiyun if (unlikely(error))
2295*4882a593Smuzhiyun goto out;
2296*4882a593Smuzhiyun if (status != NFS3_OK)
2297*4882a593Smuzhiyun goto out_status;
2298*4882a593Smuzhiyun error = decode_pathconf3resok(xdr, result);
2299*4882a593Smuzhiyun out:
2300*4882a593Smuzhiyun return error;
2301*4882a593Smuzhiyun out_status:
2302*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2303*4882a593Smuzhiyun }
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun /*
2306*4882a593Smuzhiyun * 3.3.21 COMMIT3res
2307*4882a593Smuzhiyun *
2308*4882a593Smuzhiyun * struct COMMIT3resok {
2309*4882a593Smuzhiyun * wcc_data file_wcc;
2310*4882a593Smuzhiyun * writeverf3 verf;
2311*4882a593Smuzhiyun * };
2312*4882a593Smuzhiyun *
2313*4882a593Smuzhiyun * struct COMMIT3resfail {
2314*4882a593Smuzhiyun * wcc_data file_wcc;
2315*4882a593Smuzhiyun * };
2316*4882a593Smuzhiyun *
2317*4882a593Smuzhiyun * union COMMIT3res switch (nfsstat3 status) {
2318*4882a593Smuzhiyun * case NFS3_OK:
2319*4882a593Smuzhiyun * COMMIT3resok resok;
2320*4882a593Smuzhiyun * default:
2321*4882a593Smuzhiyun * COMMIT3resfail resfail;
2322*4882a593Smuzhiyun * };
2323*4882a593Smuzhiyun */
nfs3_xdr_dec_commit3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2324*4882a593Smuzhiyun static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
2325*4882a593Smuzhiyun struct xdr_stream *xdr,
2326*4882a593Smuzhiyun void *data)
2327*4882a593Smuzhiyun {
2328*4882a593Smuzhiyun struct nfs_commitres *result = data;
2329*4882a593Smuzhiyun struct nfs_writeverf *verf = result->verf;
2330*4882a593Smuzhiyun enum nfs_stat status;
2331*4882a593Smuzhiyun int error;
2332*4882a593Smuzhiyun
2333*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2334*4882a593Smuzhiyun if (unlikely(error))
2335*4882a593Smuzhiyun goto out;
2336*4882a593Smuzhiyun error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
2337*4882a593Smuzhiyun if (unlikely(error))
2338*4882a593Smuzhiyun goto out;
2339*4882a593Smuzhiyun result->op_status = status;
2340*4882a593Smuzhiyun if (status != NFS3_OK)
2341*4882a593Smuzhiyun goto out_status;
2342*4882a593Smuzhiyun error = decode_writeverf3(xdr, &verf->verifier);
2343*4882a593Smuzhiyun if (!error)
2344*4882a593Smuzhiyun verf->committed = NFS_FILE_SYNC;
2345*4882a593Smuzhiyun out:
2346*4882a593Smuzhiyun return error;
2347*4882a593Smuzhiyun out_status:
2348*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2349*4882a593Smuzhiyun }
2350*4882a593Smuzhiyun
2351*4882a593Smuzhiyun #ifdef CONFIG_NFS_V3_ACL
2352*4882a593Smuzhiyun
decode_getacl3resok(struct xdr_stream * xdr,struct nfs3_getaclres * result,struct user_namespace * userns)2353*4882a593Smuzhiyun static inline int decode_getacl3resok(struct xdr_stream *xdr,
2354*4882a593Smuzhiyun struct nfs3_getaclres *result,
2355*4882a593Smuzhiyun struct user_namespace *userns)
2356*4882a593Smuzhiyun {
2357*4882a593Smuzhiyun struct posix_acl **acl;
2358*4882a593Smuzhiyun unsigned int *aclcnt;
2359*4882a593Smuzhiyun size_t hdrlen;
2360*4882a593Smuzhiyun int error;
2361*4882a593Smuzhiyun
2362*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result->fattr, userns);
2363*4882a593Smuzhiyun if (unlikely(error))
2364*4882a593Smuzhiyun goto out;
2365*4882a593Smuzhiyun error = decode_uint32(xdr, &result->mask);
2366*4882a593Smuzhiyun if (unlikely(error))
2367*4882a593Smuzhiyun goto out;
2368*4882a593Smuzhiyun error = -EINVAL;
2369*4882a593Smuzhiyun if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2370*4882a593Smuzhiyun goto out;
2371*4882a593Smuzhiyun
2372*4882a593Smuzhiyun hdrlen = xdr_stream_pos(xdr);
2373*4882a593Smuzhiyun
2374*4882a593Smuzhiyun acl = NULL;
2375*4882a593Smuzhiyun if (result->mask & NFS_ACL)
2376*4882a593Smuzhiyun acl = &result->acl_access;
2377*4882a593Smuzhiyun aclcnt = NULL;
2378*4882a593Smuzhiyun if (result->mask & NFS_ACLCNT)
2379*4882a593Smuzhiyun aclcnt = &result->acl_access_count;
2380*4882a593Smuzhiyun error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
2381*4882a593Smuzhiyun if (unlikely(error <= 0))
2382*4882a593Smuzhiyun goto out;
2383*4882a593Smuzhiyun
2384*4882a593Smuzhiyun acl = NULL;
2385*4882a593Smuzhiyun if (result->mask & NFS_DFACL)
2386*4882a593Smuzhiyun acl = &result->acl_default;
2387*4882a593Smuzhiyun aclcnt = NULL;
2388*4882a593Smuzhiyun if (result->mask & NFS_DFACLCNT)
2389*4882a593Smuzhiyun aclcnt = &result->acl_default_count;
2390*4882a593Smuzhiyun error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
2391*4882a593Smuzhiyun if (unlikely(error <= 0))
2392*4882a593Smuzhiyun return error;
2393*4882a593Smuzhiyun error = 0;
2394*4882a593Smuzhiyun out:
2395*4882a593Smuzhiyun return error;
2396*4882a593Smuzhiyun }
2397*4882a593Smuzhiyun
nfs3_xdr_dec_getacl3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)2398*4882a593Smuzhiyun static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
2399*4882a593Smuzhiyun struct xdr_stream *xdr,
2400*4882a593Smuzhiyun void *result)
2401*4882a593Smuzhiyun {
2402*4882a593Smuzhiyun enum nfs_stat status;
2403*4882a593Smuzhiyun int error;
2404*4882a593Smuzhiyun
2405*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2406*4882a593Smuzhiyun if (unlikely(error))
2407*4882a593Smuzhiyun goto out;
2408*4882a593Smuzhiyun if (status != NFS3_OK)
2409*4882a593Smuzhiyun goto out_default;
2410*4882a593Smuzhiyun error = decode_getacl3resok(xdr, result, rpc_rqst_userns(req));
2411*4882a593Smuzhiyun out:
2412*4882a593Smuzhiyun return error;
2413*4882a593Smuzhiyun out_default:
2414*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun
nfs3_xdr_dec_setacl3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)2417*4882a593Smuzhiyun static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
2418*4882a593Smuzhiyun struct xdr_stream *xdr,
2419*4882a593Smuzhiyun void *result)
2420*4882a593Smuzhiyun {
2421*4882a593Smuzhiyun enum nfs_stat status;
2422*4882a593Smuzhiyun int error;
2423*4882a593Smuzhiyun
2424*4882a593Smuzhiyun error = decode_nfsstat3(xdr, &status);
2425*4882a593Smuzhiyun if (unlikely(error))
2426*4882a593Smuzhiyun goto out;
2427*4882a593Smuzhiyun if (status != NFS3_OK)
2428*4882a593Smuzhiyun goto out_default;
2429*4882a593Smuzhiyun error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
2430*4882a593Smuzhiyun out:
2431*4882a593Smuzhiyun return error;
2432*4882a593Smuzhiyun out_default:
2433*4882a593Smuzhiyun return nfs3_stat_to_errno(status);
2434*4882a593Smuzhiyun }
2435*4882a593Smuzhiyun
2436*4882a593Smuzhiyun #endif /* CONFIG_NFS_V3_ACL */
2437*4882a593Smuzhiyun
2438*4882a593Smuzhiyun
2439*4882a593Smuzhiyun /*
2440*4882a593Smuzhiyun * We need to translate between nfs status return values and
2441*4882a593Smuzhiyun * the local errno values which may not be the same.
2442*4882a593Smuzhiyun */
2443*4882a593Smuzhiyun static const struct {
2444*4882a593Smuzhiyun int stat;
2445*4882a593Smuzhiyun int errno;
2446*4882a593Smuzhiyun } nfs_errtbl[] = {
2447*4882a593Smuzhiyun { NFS_OK, 0 },
2448*4882a593Smuzhiyun { NFSERR_PERM, -EPERM },
2449*4882a593Smuzhiyun { NFSERR_NOENT, -ENOENT },
2450*4882a593Smuzhiyun { NFSERR_IO, -errno_NFSERR_IO},
2451*4882a593Smuzhiyun { NFSERR_NXIO, -ENXIO },
2452*4882a593Smuzhiyun /* { NFSERR_EAGAIN, -EAGAIN }, */
2453*4882a593Smuzhiyun { NFSERR_ACCES, -EACCES },
2454*4882a593Smuzhiyun { NFSERR_EXIST, -EEXIST },
2455*4882a593Smuzhiyun { NFSERR_XDEV, -EXDEV },
2456*4882a593Smuzhiyun { NFSERR_NODEV, -ENODEV },
2457*4882a593Smuzhiyun { NFSERR_NOTDIR, -ENOTDIR },
2458*4882a593Smuzhiyun { NFSERR_ISDIR, -EISDIR },
2459*4882a593Smuzhiyun { NFSERR_INVAL, -EINVAL },
2460*4882a593Smuzhiyun { NFSERR_FBIG, -EFBIG },
2461*4882a593Smuzhiyun { NFSERR_NOSPC, -ENOSPC },
2462*4882a593Smuzhiyun { NFSERR_ROFS, -EROFS },
2463*4882a593Smuzhiyun { NFSERR_MLINK, -EMLINK },
2464*4882a593Smuzhiyun { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
2465*4882a593Smuzhiyun { NFSERR_NOTEMPTY, -ENOTEMPTY },
2466*4882a593Smuzhiyun { NFSERR_DQUOT, -EDQUOT },
2467*4882a593Smuzhiyun { NFSERR_STALE, -ESTALE },
2468*4882a593Smuzhiyun { NFSERR_REMOTE, -EREMOTE },
2469*4882a593Smuzhiyun #ifdef EWFLUSH
2470*4882a593Smuzhiyun { NFSERR_WFLUSH, -EWFLUSH },
2471*4882a593Smuzhiyun #endif
2472*4882a593Smuzhiyun { NFSERR_BADHANDLE, -EBADHANDLE },
2473*4882a593Smuzhiyun { NFSERR_NOT_SYNC, -ENOTSYNC },
2474*4882a593Smuzhiyun { NFSERR_BAD_COOKIE, -EBADCOOKIE },
2475*4882a593Smuzhiyun { NFSERR_NOTSUPP, -ENOTSUPP },
2476*4882a593Smuzhiyun { NFSERR_TOOSMALL, -ETOOSMALL },
2477*4882a593Smuzhiyun { NFSERR_SERVERFAULT, -EREMOTEIO },
2478*4882a593Smuzhiyun { NFSERR_BADTYPE, -EBADTYPE },
2479*4882a593Smuzhiyun { NFSERR_JUKEBOX, -EJUKEBOX },
2480*4882a593Smuzhiyun { -1, -EIO }
2481*4882a593Smuzhiyun };
2482*4882a593Smuzhiyun
2483*4882a593Smuzhiyun /**
2484*4882a593Smuzhiyun * nfs3_stat_to_errno - convert an NFS status code to a local errno
2485*4882a593Smuzhiyun * @status: NFS status code to convert
2486*4882a593Smuzhiyun *
2487*4882a593Smuzhiyun * Returns a local errno value, or -EIO if the NFS status code is
2488*4882a593Smuzhiyun * not recognized. This function is used jointly by NFSv2 and NFSv3.
2489*4882a593Smuzhiyun */
nfs3_stat_to_errno(enum nfs_stat status)2490*4882a593Smuzhiyun static int nfs3_stat_to_errno(enum nfs_stat status)
2491*4882a593Smuzhiyun {
2492*4882a593Smuzhiyun int i;
2493*4882a593Smuzhiyun
2494*4882a593Smuzhiyun for (i = 0; nfs_errtbl[i].stat != -1; i++) {
2495*4882a593Smuzhiyun if (nfs_errtbl[i].stat == (int)status)
2496*4882a593Smuzhiyun return nfs_errtbl[i].errno;
2497*4882a593Smuzhiyun }
2498*4882a593Smuzhiyun dprintk("NFS: Unrecognized nfs status value: %u\n", status);
2499*4882a593Smuzhiyun return nfs_errtbl[i].errno;
2500*4882a593Smuzhiyun }
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun
2503*4882a593Smuzhiyun #define PROC(proc, argtype, restype, timer) \
2504*4882a593Smuzhiyun [NFS3PROC_##proc] = { \
2505*4882a593Smuzhiyun .p_proc = NFS3PROC_##proc, \
2506*4882a593Smuzhiyun .p_encode = nfs3_xdr_enc_##argtype##3args, \
2507*4882a593Smuzhiyun .p_decode = nfs3_xdr_dec_##restype##3res, \
2508*4882a593Smuzhiyun .p_arglen = NFS3_##argtype##args_sz, \
2509*4882a593Smuzhiyun .p_replen = NFS3_##restype##res_sz, \
2510*4882a593Smuzhiyun .p_timer = timer, \
2511*4882a593Smuzhiyun .p_statidx = NFS3PROC_##proc, \
2512*4882a593Smuzhiyun .p_name = #proc, \
2513*4882a593Smuzhiyun }
2514*4882a593Smuzhiyun
2515*4882a593Smuzhiyun const struct rpc_procinfo nfs3_procedures[] = {
2516*4882a593Smuzhiyun PROC(GETATTR, getattr, getattr, 1),
2517*4882a593Smuzhiyun PROC(SETATTR, setattr, setattr, 0),
2518*4882a593Smuzhiyun PROC(LOOKUP, lookup, lookup, 2),
2519*4882a593Smuzhiyun PROC(ACCESS, access, access, 1),
2520*4882a593Smuzhiyun PROC(READLINK, readlink, readlink, 3),
2521*4882a593Smuzhiyun PROC(READ, read, read, 3),
2522*4882a593Smuzhiyun PROC(WRITE, write, write, 4),
2523*4882a593Smuzhiyun PROC(CREATE, create, create, 0),
2524*4882a593Smuzhiyun PROC(MKDIR, mkdir, create, 0),
2525*4882a593Smuzhiyun PROC(SYMLINK, symlink, create, 0),
2526*4882a593Smuzhiyun PROC(MKNOD, mknod, create, 0),
2527*4882a593Smuzhiyun PROC(REMOVE, remove, remove, 0),
2528*4882a593Smuzhiyun PROC(RMDIR, lookup, setattr, 0),
2529*4882a593Smuzhiyun PROC(RENAME, rename, rename, 0),
2530*4882a593Smuzhiyun PROC(LINK, link, link, 0),
2531*4882a593Smuzhiyun PROC(READDIR, readdir, readdir, 3),
2532*4882a593Smuzhiyun PROC(READDIRPLUS, readdirplus, readdir, 3),
2533*4882a593Smuzhiyun PROC(FSSTAT, getattr, fsstat, 0),
2534*4882a593Smuzhiyun PROC(FSINFO, getattr, fsinfo, 0),
2535*4882a593Smuzhiyun PROC(PATHCONF, getattr, pathconf, 0),
2536*4882a593Smuzhiyun PROC(COMMIT, commit, commit, 5),
2537*4882a593Smuzhiyun };
2538*4882a593Smuzhiyun
2539*4882a593Smuzhiyun static unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)];
2540*4882a593Smuzhiyun const struct rpc_version nfs_version3 = {
2541*4882a593Smuzhiyun .number = 3,
2542*4882a593Smuzhiyun .nrprocs = ARRAY_SIZE(nfs3_procedures),
2543*4882a593Smuzhiyun .procs = nfs3_procedures,
2544*4882a593Smuzhiyun .counts = nfs_version3_counts,
2545*4882a593Smuzhiyun };
2546*4882a593Smuzhiyun
2547*4882a593Smuzhiyun #ifdef CONFIG_NFS_V3_ACL
2548*4882a593Smuzhiyun static const struct rpc_procinfo nfs3_acl_procedures[] = {
2549*4882a593Smuzhiyun [ACLPROC3_GETACL] = {
2550*4882a593Smuzhiyun .p_proc = ACLPROC3_GETACL,
2551*4882a593Smuzhiyun .p_encode = nfs3_xdr_enc_getacl3args,
2552*4882a593Smuzhiyun .p_decode = nfs3_xdr_dec_getacl3res,
2553*4882a593Smuzhiyun .p_arglen = ACL3_getaclargs_sz,
2554*4882a593Smuzhiyun .p_replen = ACL3_getaclres_sz,
2555*4882a593Smuzhiyun .p_timer = 1,
2556*4882a593Smuzhiyun .p_name = "GETACL",
2557*4882a593Smuzhiyun },
2558*4882a593Smuzhiyun [ACLPROC3_SETACL] = {
2559*4882a593Smuzhiyun .p_proc = ACLPROC3_SETACL,
2560*4882a593Smuzhiyun .p_encode = nfs3_xdr_enc_setacl3args,
2561*4882a593Smuzhiyun .p_decode = nfs3_xdr_dec_setacl3res,
2562*4882a593Smuzhiyun .p_arglen = ACL3_setaclargs_sz,
2563*4882a593Smuzhiyun .p_replen = ACL3_setaclres_sz,
2564*4882a593Smuzhiyun .p_timer = 0,
2565*4882a593Smuzhiyun .p_name = "SETACL",
2566*4882a593Smuzhiyun },
2567*4882a593Smuzhiyun };
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun static unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)];
2570*4882a593Smuzhiyun const struct rpc_version nfsacl_version3 = {
2571*4882a593Smuzhiyun .number = 3,
2572*4882a593Smuzhiyun .nrprocs = ARRAY_SIZE(nfs3_acl_procedures),
2573*4882a593Smuzhiyun .procs = nfs3_acl_procedures,
2574*4882a593Smuzhiyun .counts = nfs3_acl_counts,
2575*4882a593Smuzhiyun };
2576*4882a593Smuzhiyun #endif /* CONFIG_NFS_V3_ACL */
2577