blob: ca10072644ff26bb6a7bbd2a95d5594c8ab4228e [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/fs/nfs/nfs3xdr.c
4 *
5 * XDR functions to encode/decode NFSv3 RPC arguments and results.
6 *
7 * Copyright (C) 1996, 1997 Olaf Kirch
8 */
9
10#include <linux/param.h>
11#include <linux/time.h>
12#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/in.h>
16#include <linux/pagemap.h>
17#include <linux/proc_fs.h>
18#include <linux/kdev_t.h>
19#include <linux/sunrpc/clnt.h>
20#include <linux/nfs.h>
21#include <linux/nfs3.h>
22#include <linux/nfs_fs.h>
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000023#include <linux/nfsacl.h>
Chuck Leverf23f6582019-02-11 11:24:26 -050024#include "nfstrace.h"
David Howellsf7b422b2006-06-09 09:34:33 -040025#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#define NFSDBG_FACILITY NFSDBG_XDR
28
29/* Mapping from NFS error code to "errno" error code. */
30#define errno_NFSERR_IO EIO
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032/*
33 * Declare the space requirements for NFS arguments and replies as
34 * number of 32bit-words
35 */
Trond Myklebust9ed5af262020-11-21 20:46:18 -050036#define NFS3_pagepad_sz (1) /* Page padding */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define NFS3_fhandle_sz (1+16)
38#define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
39#define NFS3_sattr_sz (15)
40#define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
41#define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
42#define NFS3_fattr_sz (21)
Chuck Leverd9c407b2010-12-14 14:55:50 +000043#define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2)
Chuck Leverf5fc3c502010-12-14 14:56:42 +000044#define NFS3_wcc_attr_sz (6)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
46#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
Chuck Leverf5fc3c502010-12-14 14:56:42 +000047#define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Chuck Leverad96b5b2010-12-14 14:56:01 +000049
50#define NFS3_getattrargs_sz (NFS3_fh_sz)
51#define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
52#define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define NFS3_accessargs_sz (NFS3_fh_sz+1)
54#define NFS3_readlinkargs_sz (NFS3_fh_sz)
55#define NFS3_readargs_sz (NFS3_fh_sz+3)
56#define NFS3_writeargs_sz (NFS3_fh_sz+5)
57#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
Chuck Lever94a6d752006-08-22 20:06:23 -040059#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
Chuck Leverad96b5b2010-12-14 14:56:01 +000061#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
63#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
Chuck Leverd9c407b2010-12-14 14:55:50 +000064#define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
65#define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define NFS3_commitargs_sz (NFS3_fh_sz+3)
67
Chuck Leverf5fc3c502010-12-14 14:56:42 +000068#define NFS3_getattrres_sz (1+NFS3_fattr_sz)
69#define NFS3_setattrres_sz (1+NFS3_wcc_data_sz)
70#define NFS3_removeres_sz (NFS3_setattrres_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
72#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
Trond Myklebust9ed5af262020-11-21 20:46:18 -050073#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1+NFS3_pagepad_sz)
74#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3+NFS3_pagepad_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
76#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
77#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
78#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
Trond Myklebust9ed5af262020-11-21 20:46:18 -050079#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2+NFS3_pagepad_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
81#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
82#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
83#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
84
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000085#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
Trond Myklebustae46141f2009-03-10 20:33:18 -040086#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
87 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
88#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
Trond Myklebust9ed5af262020-11-21 20:46:18 -050089 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)+\
90 NFS3_pagepad_sz)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000091#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
92
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -040093static int nfs3_stat_to_errno(enum nfs_stat);
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095/*
96 * Map file type to S_IFMT bits
97 */
Trond Myklebustbca79472009-03-11 14:10:26 -040098static const umode_t nfs_type2fmt[] = {
99 [NF3BAD] = 0,
100 [NF3REG] = S_IFREG,
101 [NF3DIR] = S_IFDIR,
102 [NF3BLK] = S_IFBLK,
103 [NF3CHR] = S_IFCHR,
104 [NF3LNK] = S_IFLNK,
105 [NF3SOCK] = S_IFSOCK,
106 [NF3FIFO] = S_IFIFO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107};
108
Trond Myklebust264d9482019-04-24 17:46:46 -0400109static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
110{
111 if (clnt && clnt->cl_cred)
112 return clnt->cl_cred->user_ns;
113 return &init_user_ns;
114}
115
116static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
117{
118 if (rqstp->rq_task)
119 return rpc_userns(rqstp->rq_task->tk_client);
120 return &init_user_ns;
121}
122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000124 * Encode/decode NFSv3 basic data types
125 *
126 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
127 * "NFS Version 3 Protocol Specification".
128 *
129 * Not all basic data types have their own encoding and decoding
130 * functions. For run-time efficiency, some data types are encoded
131 * or decoded inline.
132 */
133
134static void encode_uint32(struct xdr_stream *xdr, u32 value)
135{
136 __be32 *p = xdr_reserve_space(xdr, 4);
137 *p = cpu_to_be32(value);
138}
139
Chuck Levere4f93232010-12-14 14:56:30 +0000140static int decode_uint32(struct xdr_stream *xdr, u32 *value)
141{
142 __be32 *p;
143
144 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500145 if (unlikely(!p))
146 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000147 *value = be32_to_cpup(p);
148 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000149}
150
151static int decode_uint64(struct xdr_stream *xdr, u64 *value)
152{
153 __be32 *p;
154
155 p = xdr_inline_decode(xdr, 8);
Chuck Levereb72f482019-02-11 11:24:21 -0500156 if (unlikely(!p))
157 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000158 xdr_decode_hyper(p, value);
159 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000160}
161
162/*
163 * fileid3
164 *
165 * typedef uint64 fileid3;
166 */
Chuck Leverf6048702010-12-14 14:57:02 +0000167static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid)
168{
169 return xdr_decode_hyper(p, fileid);
170}
171
Chuck Levere4f93232010-12-14 14:56:30 +0000172static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
173{
174 return decode_uint64(xdr, fileid);
175}
176
Chuck Leverd9c407b2010-12-14 14:55:50 +0000177/*
178 * filename3
179 *
180 * typedef string filename3<>;
181 */
182static void encode_filename3(struct xdr_stream *xdr,
183 const char *name, u32 length)
184{
185 __be32 *p;
186
Trond Myklebust7fc38842012-10-15 11:51:21 -0400187 WARN_ON_ONCE(length > NFS3_MAXNAMLEN);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000188 p = xdr_reserve_space(xdr, 4 + length);
189 xdr_encode_opaque(p, name, length);
190}
191
Chuck Levere4f93232010-12-14 14:56:30 +0000192static int decode_inline_filename3(struct xdr_stream *xdr,
193 const char **name, u32 *length)
194{
195 __be32 *p;
196 u32 count;
197
198 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500199 if (unlikely(!p))
200 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000201 count = be32_to_cpup(p);
202 if (count > NFS3_MAXNAMLEN)
203 goto out_nametoolong;
204 p = xdr_inline_decode(xdr, count);
Chuck Levereb72f482019-02-11 11:24:21 -0500205 if (unlikely(!p))
206 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000207 *name = (const char *)p;
208 *length = count;
209 return 0;
210
211out_nametoolong:
212 dprintk("NFS: returned filename too long: %u\n", count);
213 return -ENAMETOOLONG;
Chuck Levere4f93232010-12-14 14:56:30 +0000214}
215
Chuck Leverd9c407b2010-12-14 14:55:50 +0000216/*
217 * nfspath3
218 *
219 * typedef string nfspath3<>;
220 */
221static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
222 const u32 length)
223{
Chuck Leverd9c407b2010-12-14 14:55:50 +0000224 encode_uint32(xdr, length);
225 xdr_write_pages(xdr, pages, 0, length);
226}
227
Chuck Levere4f93232010-12-14 14:56:30 +0000228static int decode_nfspath3(struct xdr_stream *xdr)
229{
230 u32 recvd, count;
Chuck Levere4f93232010-12-14 14:56:30 +0000231 __be32 *p;
232
233 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500234 if (unlikely(!p))
235 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000236 count = be32_to_cpup(p);
237 if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
238 goto out_nametoolong;
Trond Myklebust64bd5772012-06-20 22:35:05 -0400239 recvd = xdr_read_pages(xdr, count);
Chuck Levere4f93232010-12-14 14:56:30 +0000240 if (unlikely(count > recvd))
241 goto out_cheating;
Chuck Levere4f93232010-12-14 14:56:30 +0000242 xdr_terminate_string(xdr->buf, count);
243 return 0;
244
245out_nametoolong:
246 dprintk("NFS: returned pathname too long: %u\n", count);
247 return -ENAMETOOLONG;
248out_cheating:
249 dprintk("NFS: server cheating in pathname result: "
250 "count %u > recvd %u\n", count, recvd);
251 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000252}
253
Chuck Leverd9c407b2010-12-14 14:55:50 +0000254/*
255 * cookie3
256 *
257 * typedef uint64 cookie3
258 */
259static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
260{
261 return xdr_encode_hyper(p, cookie);
262}
263
Chuck Levere4f93232010-12-14 14:56:30 +0000264static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
265{
266 return decode_uint64(xdr, cookie);
267}
268
Chuck Leverd9c407b2010-12-14 14:55:50 +0000269/*
270 * cookieverf3
271 *
272 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
273 */
274static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
275{
276 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
277 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
278}
279
Chuck Levere4f93232010-12-14 14:56:30 +0000280static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
281{
282 __be32 *p;
283
284 p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
Chuck Levereb72f482019-02-11 11:24:21 -0500285 if (unlikely(!p))
286 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000287 memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
288 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000289}
290
Chuck Leverd9c407b2010-12-14 14:55:50 +0000291/*
292 * createverf3
293 *
294 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
295 */
296static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
297{
298 __be32 *p;
299
300 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
301 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
302}
303
Trond Myklebust2f2c63b2012-06-08 11:56:09 -0400304static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
Chuck Levere4f93232010-12-14 14:56:30 +0000305{
306 __be32 *p;
307
308 p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
Chuck Levereb72f482019-02-11 11:24:21 -0500309 if (unlikely(!p))
310 return -EIO;
Trond Myklebust2f2c63b2012-06-08 11:56:09 -0400311 memcpy(verifier->data, p, NFS3_WRITEVERFSIZE);
Chuck Levere4f93232010-12-14 14:56:30 +0000312 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000313}
314
315/*
316 * size3
317 *
318 * typedef uint64 size3;
319 */
320static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
321{
322 return xdr_decode_hyper(p, size);
323}
324
325/*
326 * nfsstat3
327 *
328 * enum nfsstat3 {
329 * NFS3_OK = 0,
330 * ...
331 * }
332 */
333#define NFS3_OK NFS_OK
334
335static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
336{
337 __be32 *p;
338
339 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500340 if (unlikely(!p))
341 return -EIO;
Chuck Leverf23f6582019-02-11 11:24:26 -0500342 if (unlikely(*p != cpu_to_be32(NFS3_OK)))
343 goto out_status;
344 *status = 0;
345 return 0;
346out_status:
Chuck Levere4f93232010-12-14 14:56:30 +0000347 *status = be32_to_cpup(p);
Chuck Lever62a92ba2019-06-19 10:34:09 -0400348 trace_nfs_xdr_status(xdr, (int)*status);
Chuck Levere4f93232010-12-14 14:56:30 +0000349 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000350}
351
Chuck Leverd9c407b2010-12-14 14:55:50 +0000352/*
353 * ftype3
354 *
355 * enum ftype3 {
356 * NF3REG = 1,
357 * NF3DIR = 2,
358 * NF3BLK = 3,
359 * NF3CHR = 4,
360 * NF3LNK = 5,
361 * NF3SOCK = 6,
362 * NF3FIFO = 7
363 * };
364 */
365static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
366{
Chuck Leverd9c407b2010-12-14 14:55:50 +0000367 encode_uint32(xdr, type);
368}
369
Chuck Leverf6048702010-12-14 14:57:02 +0000370static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode)
371{
372 u32 type;
373
374 type = be32_to_cpup(p++);
375 if (type > NF3FIFO)
376 type = NF3NON;
377 *mode = nfs_type2fmt[type];
378 return p;
379}
380
Chuck Leverd9c407b2010-12-14 14:55:50 +0000381/*
382 * specdata3
383 *
384 * struct specdata3 {
385 * uint32 specdata1;
386 * uint32 specdata2;
387 * };
388 */
389static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
390{
391 __be32 *p;
392
393 p = xdr_reserve_space(xdr, 8);
394 *p++ = cpu_to_be32(MAJOR(rdev));
395 *p = cpu_to_be32(MINOR(rdev));
396}
397
Chuck Leverf6048702010-12-14 14:57:02 +0000398static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev)
399{
400 unsigned int major, minor;
401
402 major = be32_to_cpup(p++);
403 minor = be32_to_cpup(p++);
404 *rdev = MKDEV(major, minor);
405 if (MAJOR(*rdev) != major || MINOR(*rdev) != minor)
406 *rdev = 0;
407 return p;
408}
409
Chuck Leverd9c407b2010-12-14 14:55:50 +0000410/*
411 * nfs_fh3
412 *
413 * struct nfs_fh3 {
414 * opaque data<NFS3_FHSIZE>;
415 * };
416 */
417static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
418{
419 __be32 *p;
420
Trond Myklebust7fc38842012-10-15 11:51:21 -0400421 WARN_ON_ONCE(fh->size > NFS3_FHSIZE);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000422 p = xdr_reserve_space(xdr, 4 + fh->size);
423 xdr_encode_opaque(p, fh->data, fh->size);
424}
425
Chuck Levere4f93232010-12-14 14:56:30 +0000426static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
427{
428 u32 length;
429 __be32 *p;
430
431 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500432 if (unlikely(!p))
433 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000434 length = be32_to_cpup(p++);
435 if (unlikely(length > NFS3_FHSIZE))
436 goto out_toobig;
437 p = xdr_inline_decode(xdr, length);
Chuck Levereb72f482019-02-11 11:24:21 -0500438 if (unlikely(!p))
439 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000440 fh->size = length;
441 memcpy(fh->data, p, length);
442 return 0;
443out_toobig:
444 dprintk("NFS: file handle size (%u) too big\n", length);
445 return -E2BIG;
Chuck Levere4f93232010-12-14 14:56:30 +0000446}
447
448static void zero_nfs_fh3(struct nfs_fh *fh)
449{
450 memset(fh, 0, sizeof(*fh));
451}
452
Chuck Leverd9c407b2010-12-14 14:55:50 +0000453/*
Chuck Lever9d5a6432010-12-14 14:56:20 +0000454 * nfstime3
455 *
456 * struct nfstime3 {
457 * uint32 seconds;
458 * uint32 nseconds;
459 * };
460 */
Trond Myklebust6430b322019-10-04 17:00:02 -0400461static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec64 *timep)
Chuck Lever9d5a6432010-12-14 14:56:20 +0000462{
Trond Myklebust6430b322019-10-04 17:00:02 -0400463 *p++ = cpu_to_be32((u32)timep->tv_sec);
Chuck Lever9d5a6432010-12-14 14:56:20 +0000464 *p++ = cpu_to_be32(timep->tv_nsec);
465 return p;
466}
467
Trond Myklebuste86d5a02019-10-04 16:38:56 -0400468static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec64 *timep)
Chuck Leverf6048702010-12-14 14:57:02 +0000469{
470 timep->tv_sec = be32_to_cpup(p++);
471 timep->tv_nsec = be32_to_cpup(p++);
472 return p;
473}
474
Chuck Lever9d5a6432010-12-14 14:56:20 +0000475/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000476 * sattr3
477 *
478 * enum time_how {
479 * DONT_CHANGE = 0,
480 * SET_TO_SERVER_TIME = 1,
481 * SET_TO_CLIENT_TIME = 2
482 * };
483 *
484 * union set_mode3 switch (bool set_it) {
485 * case TRUE:
486 * mode3 mode;
487 * default:
488 * void;
489 * };
490 *
491 * union set_uid3 switch (bool set_it) {
492 * case TRUE:
493 * uid3 uid;
494 * default:
495 * void;
496 * };
497 *
498 * union set_gid3 switch (bool set_it) {
499 * case TRUE:
500 * gid3 gid;
501 * default:
502 * void;
503 * };
504 *
505 * union set_size3 switch (bool set_it) {
506 * case TRUE:
507 * size3 size;
508 * default:
509 * void;
510 * };
511 *
512 * union set_atime switch (time_how set_it) {
513 * case SET_TO_CLIENT_TIME:
514 * nfstime3 atime;
515 * default:
516 * void;
517 * };
518 *
519 * union set_mtime switch (time_how set_it) {
520 * case SET_TO_CLIENT_TIME:
521 * nfstime3 mtime;
522 * default:
523 * void;
524 * };
525 *
526 * struct sattr3 {
527 * set_mode3 mode;
528 * set_uid3 uid;
529 * set_gid3 gid;
530 * set_size3 size;
531 * set_atime atime;
532 * set_mtime mtime;
533 * };
534 */
Trond Myklebust264d9482019-04-24 17:46:46 -0400535static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr,
536 struct user_namespace *userns)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000537{
538 u32 nbytes;
539 __be32 *p;
540
541 /*
542 * In order to make only a single xdr_reserve_space() call,
543 * pre-compute the total number of bytes to be reserved.
544 * Six boolean values, one for each set_foo field, are always
545 * present in the encoded result, so start there.
546 */
547 nbytes = 6 * 4;
548 if (attr->ia_valid & ATTR_MODE)
549 nbytes += 4;
550 if (attr->ia_valid & ATTR_UID)
551 nbytes += 4;
552 if (attr->ia_valid & ATTR_GID)
553 nbytes += 4;
554 if (attr->ia_valid & ATTR_SIZE)
555 nbytes += 8;
556 if (attr->ia_valid & ATTR_ATIME_SET)
557 nbytes += 8;
558 if (attr->ia_valid & ATTR_MTIME_SET)
559 nbytes += 8;
560 p = xdr_reserve_space(xdr, nbytes);
561
Chuck Lever9d5a6432010-12-14 14:56:20 +0000562 if (attr->ia_valid & ATTR_MODE) {
563 *p++ = xdr_one;
564 *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
565 } else
566 *p++ = xdr_zero;
567
568 if (attr->ia_valid & ATTR_UID) {
569 *p++ = xdr_one;
Trond Myklebust264d9482019-04-24 17:46:46 -0400570 *p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
Chuck Lever9d5a6432010-12-14 14:56:20 +0000571 } else
572 *p++ = xdr_zero;
573
574 if (attr->ia_valid & ATTR_GID) {
575 *p++ = xdr_one;
Trond Myklebust264d9482019-04-24 17:46:46 -0400576 *p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
Chuck Lever9d5a6432010-12-14 14:56:20 +0000577 } else
578 *p++ = xdr_zero;
579
580 if (attr->ia_valid & ATTR_SIZE) {
581 *p++ = xdr_one;
582 p = xdr_encode_hyper(p, (u64)attr->ia_size);
583 } else
584 *p++ = xdr_zero;
585
586 if (attr->ia_valid & ATTR_ATIME_SET) {
587 *p++ = xdr_two;
Trond Myklebust6430b322019-10-04 17:00:02 -0400588 p = xdr_encode_nfstime3(p, &attr->ia_atime);
Chuck Lever9d5a6432010-12-14 14:56:20 +0000589 } else if (attr->ia_valid & ATTR_ATIME) {
590 *p++ = xdr_one;
591 } else
592 *p++ = xdr_zero;
593
594 if (attr->ia_valid & ATTR_MTIME_SET) {
595 *p++ = xdr_two;
Trond Myklebust6430b322019-10-04 17:00:02 -0400596 xdr_encode_nfstime3(p, &attr->ia_mtime);
Chuck Lever9d5a6432010-12-14 14:56:20 +0000597 } else if (attr->ia_valid & ATTR_MTIME) {
598 *p = xdr_one;
599 } else
600 *p = xdr_zero;
Chuck Leverd9c407b2010-12-14 14:55:50 +0000601}
602
603/*
Chuck Levere4f93232010-12-14 14:56:30 +0000604 * fattr3
605 *
606 * struct fattr3 {
607 * ftype3 type;
608 * mode3 mode;
609 * uint32 nlink;
610 * uid3 uid;
611 * gid3 gid;
612 * size3 size;
613 * size3 used;
614 * specdata3 rdev;
615 * uint64 fsid;
616 * fileid3 fileid;
617 * nfstime3 atime;
618 * nfstime3 mtime;
619 * nfstime3 ctime;
620 * };
621 */
Trond Myklebust264d9482019-04-24 17:46:46 -0400622static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr,
623 struct user_namespace *userns)
Chuck Levere4f93232010-12-14 14:56:30 +0000624{
Chuck Leverf6048702010-12-14 14:57:02 +0000625 umode_t fmode;
Chuck Levere4f93232010-12-14 14:56:30 +0000626 __be32 *p;
627
628 p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
Chuck Levereb72f482019-02-11 11:24:21 -0500629 if (unlikely(!p))
630 return -EIO;
Chuck Leverf6048702010-12-14 14:57:02 +0000631
632 p = xdr_decode_ftype3(p, &fmode);
633
634 fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
635 fattr->nlink = be32_to_cpup(p++);
Trond Myklebust264d9482019-04-24 17:46:46 -0400636 fattr->uid = make_kuid(userns, be32_to_cpup(p++));
Eric W. Biederman57a38da2013-02-01 03:50:00 -0800637 if (!uid_valid(fattr->uid))
638 goto out_uid;
Trond Myklebust264d9482019-04-24 17:46:46 -0400639 fattr->gid = make_kgid(userns, be32_to_cpup(p++));
Eric W. Biederman57a38da2013-02-01 03:50:00 -0800640 if (!gid_valid(fattr->gid))
641 goto out_gid;
Chuck Leverf6048702010-12-14 14:57:02 +0000642
643 p = xdr_decode_size3(p, &fattr->size);
644 p = xdr_decode_size3(p, &fattr->du.nfs3.used);
645 p = xdr_decode_specdata3(p, &fattr->rdev);
646
647 p = xdr_decode_hyper(p, &fattr->fsid.major);
648 fattr->fsid.minor = 0;
649
650 p = xdr_decode_fileid3(p, &fattr->fileid);
651 p = xdr_decode_nfstime3(p, &fattr->atime);
652 p = xdr_decode_nfstime3(p, &fattr->mtime);
653 xdr_decode_nfstime3(p, &fattr->ctime);
Trond Myklebust3a1556e2012-04-27 13:48:18 -0400654 fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
Chuck Leverf6048702010-12-14 14:57:02 +0000655
656 fattr->valid |= NFS_ATTR_FATTR_V3;
Chuck Levere4f93232010-12-14 14:56:30 +0000657 return 0;
Eric W. Biederman57a38da2013-02-01 03:50:00 -0800658out_uid:
659 dprintk("NFS: returned invalid uid\n");
660 return -EINVAL;
661out_gid:
662 dprintk("NFS: returned invalid gid\n");
663 return -EINVAL;
Chuck Levere4f93232010-12-14 14:56:30 +0000664}
665
666/*
667 * post_op_attr
668 *
669 * union post_op_attr switch (bool attributes_follow) {
670 * case TRUE:
671 * fattr3 attributes;
672 * case FALSE:
673 * void;
674 * };
675 */
Trond Myklebust264d9482019-04-24 17:46:46 -0400676static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
677 struct user_namespace *userns)
Chuck Levere4f93232010-12-14 14:56:30 +0000678{
679 __be32 *p;
680
681 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500682 if (unlikely(!p))
683 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000684 if (*p != xdr_zero)
Trond Myklebust264d9482019-04-24 17:46:46 -0400685 return decode_fattr3(xdr, fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +0000686 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000687}
688
689/*
690 * wcc_attr
691 * struct wcc_attr {
692 * size3 size;
693 * nfstime3 mtime;
694 * nfstime3 ctime;
695 * };
696 */
697static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
698{
699 __be32 *p;
700
701 p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
Chuck Levereb72f482019-02-11 11:24:21 -0500702 if (unlikely(!p))
703 return -EIO;
Chuck Leverf6048702010-12-14 14:57:02 +0000704
705 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
Trond Myklebust3a1556e2012-04-27 13:48:18 -0400706 | NFS_ATTR_FATTR_PRECHANGE
Chuck Leverf6048702010-12-14 14:57:02 +0000707 | NFS_ATTR_FATTR_PREMTIME
708 | NFS_ATTR_FATTR_PRECTIME;
709
710 p = xdr_decode_size3(p, &fattr->pre_size);
711 p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
712 xdr_decode_nfstime3(p, &fattr->pre_ctime);
Trond Myklebust3a1556e2012-04-27 13:48:18 -0400713 fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime);
Chuck Leverf6048702010-12-14 14:57:02 +0000714
Chuck Levere4f93232010-12-14 14:56:30 +0000715 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000716}
717
718/*
719 * pre_op_attr
720 * union pre_op_attr switch (bool attributes_follow) {
721 * case TRUE:
722 * wcc_attr attributes;
723 * case FALSE:
724 * void;
725 * };
726 *
727 * wcc_data
728 *
729 * struct wcc_data {
730 * pre_op_attr before;
731 * post_op_attr after;
732 * };
733 */
734static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
735{
736 __be32 *p;
737
738 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500739 if (unlikely(!p))
740 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000741 if (*p != xdr_zero)
742 return decode_wcc_attr(xdr, fattr);
743 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000744}
745
Trond Myklebust264d9482019-04-24 17:46:46 -0400746static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr,
747 struct user_namespace *userns)
Chuck Levere4f93232010-12-14 14:56:30 +0000748{
749 int error;
750
751 error = decode_pre_op_attr(xdr, fattr);
752 if (unlikely(error))
753 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -0400754 error = decode_post_op_attr(xdr, fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +0000755out:
756 return error;
757}
758
759/*
760 * post_op_fh3
761 *
762 * union post_op_fh3 switch (bool handle_follows) {
763 * case TRUE:
764 * nfs_fh3 handle;
765 * case FALSE:
766 * void;
767 * };
768 */
769static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
770{
771 __be32 *p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500772 if (unlikely(!p))
773 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +0000774 if (*p != xdr_zero)
775 return decode_nfs_fh3(xdr, fh);
776 zero_nfs_fh3(fh);
777 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +0000778}
779
780/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000781 * diropargs3
782 *
783 * struct diropargs3 {
784 * nfs_fh3 dir;
785 * filename3 name;
786 * };
787 */
788static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
789 const char *name, u32 length)
790{
791 encode_nfs_fh3(xdr, fh);
792 encode_filename3(xdr, name, length);
793}
794
795
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796/*
Chuck Lever499ff712010-12-14 14:56:10 +0000797 * NFSv3 XDR encode functions
798 *
799 * NFSv3 argument types are defined in section 3.3 of RFC 1813:
800 * "NFS Version 3 Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 */
802
803/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000804 * 3.3.1 GETATTR3args
805 *
806 * struct GETATTR3args {
807 * nfs_fh3 object;
808 * };
809 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000810static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
811 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200812 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000813{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200814 const struct nfs_fh *fh = data;
815
Chuck Lever9f06c712010-12-14 14:59:18 +0000816 encode_nfs_fh3(xdr, fh);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000817}
818
819/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000820 * 3.3.2 SETATTR3args
821 *
822 * union sattrguard3 switch (bool check) {
823 * case TRUE:
824 * nfstime3 obj_ctime;
825 * case FALSE:
826 * void;
827 * };
828 *
829 * struct SETATTR3args {
830 * nfs_fh3 object;
831 * sattr3 new_attributes;
832 * sattrguard3 guard;
833 * };
834 */
835static void encode_sattrguard3(struct xdr_stream *xdr,
836 const struct nfs3_sattrargs *args)
837{
838 __be32 *p;
839
840 if (args->guard) {
841 p = xdr_reserve_space(xdr, 4 + 8);
842 *p++ = xdr_one;
Chuck Lever9d5a6432010-12-14 14:56:20 +0000843 xdr_encode_nfstime3(p, &args->guardtime);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000844 } else {
845 p = xdr_reserve_space(xdr, 4);
846 *p = xdr_zero;
847 }
848}
849
Chuck Lever9f06c712010-12-14 14:59:18 +0000850static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
851 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200852 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000853{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200854 const struct nfs3_sattrargs *args = data;
Chuck Lever9f06c712010-12-14 14:59:18 +0000855 encode_nfs_fh3(xdr, args->fh);
Trond Myklebust264d9482019-04-24 17:46:46 -0400856 encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
Chuck Lever9f06c712010-12-14 14:59:18 +0000857 encode_sattrguard3(xdr, args);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000858}
859
860/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000861 * 3.3.3 LOOKUP3args
862 *
863 * struct LOOKUP3args {
864 * diropargs3 what;
865 * };
866 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000867static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
868 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200869 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000870{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200871 const struct nfs3_diropargs *args = data;
872
Chuck Lever9f06c712010-12-14 14:59:18 +0000873 encode_diropargs3(xdr, args->fh, args->name, args->len);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000874}
875
876/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000877 * 3.3.4 ACCESS3args
878 *
879 * struct ACCESS3args {
880 * nfs_fh3 object;
881 * uint32 access;
882 * };
883 */
884static void encode_access3args(struct xdr_stream *xdr,
885 const struct nfs3_accessargs *args)
886{
887 encode_nfs_fh3(xdr, args->fh);
888 encode_uint32(xdr, args->access);
889}
890
Chuck Lever9f06c712010-12-14 14:59:18 +0000891static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
892 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200893 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000894{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200895 const struct nfs3_accessargs *args = data;
896
Chuck Lever9f06c712010-12-14 14:59:18 +0000897 encode_access3args(xdr, args);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000898}
899
900/*
901 * 3.3.5 READLINK3args
902 *
903 * struct READLINK3args {
904 * nfs_fh3 symlink;
905 * };
906 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000907static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
908 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200909 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000910{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200911 const struct nfs3_readlinkargs *args = data;
912
Chuck Lever9f06c712010-12-14 14:59:18 +0000913 encode_nfs_fh3(xdr, args->fh);
Trond Myklebust9ed5af262020-11-21 20:46:18 -0500914 rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->pglen,
915 NFS3_readlinkres_sz - NFS3_pagepad_sz);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000916}
917
918/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000919 * 3.3.6 READ3args
920 *
921 * struct READ3args {
922 * nfs_fh3 file;
923 * offset3 offset;
924 * count3 count;
925 * };
926 */
927static void encode_read3args(struct xdr_stream *xdr,
Anna Schumaker3c6b8992014-05-06 09:12:24 -0400928 const struct nfs_pgio_args *args)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000929{
930 __be32 *p;
931
932 encode_nfs_fh3(xdr, args->fh);
933
934 p = xdr_reserve_space(xdr, 8 + 4);
935 p = xdr_encode_hyper(p, args->offset);
936 *p = cpu_to_be32(args->count);
937}
938
Chuck Lever9f06c712010-12-14 14:59:18 +0000939static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
940 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200941 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000942{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200943 const struct nfs_pgio_args *args = data;
Trond Myklebust9ed5af262020-11-21 20:46:18 -0500944 unsigned int replen = args->replen ? args->replen :
945 NFS3_readres_sz - NFS3_pagepad_sz;
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200946
Chuck Lever9f06c712010-12-14 14:59:18 +0000947 encode_read3args(xdr, args);
Chuck Levercf500ba2019-02-11 11:25:20 -0500948 rpc_prepare_reply_pages(req, args->pages, args->pgbase,
949 args->count, replen);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000950 req->rq_rcv_buf.flags |= XDRBUF_READ;
Chuck Leverd9c407b2010-12-14 14:55:50 +0000951}
952
953/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000954 * 3.3.7 WRITE3args
955 *
956 * enum stable_how {
957 * UNSTABLE = 0,
958 * DATA_SYNC = 1,
959 * FILE_SYNC = 2
960 * };
961 *
962 * struct WRITE3args {
963 * nfs_fh3 file;
964 * offset3 offset;
965 * count3 count;
966 * stable_how stable;
967 * opaque data<>;
968 * };
969 */
970static void encode_write3args(struct xdr_stream *xdr,
Anna Schumaker3c6b8992014-05-06 09:12:24 -0400971 const struct nfs_pgio_args *args)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000972{
973 __be32 *p;
974
975 encode_nfs_fh3(xdr, args->fh);
976
977 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
978 p = xdr_encode_hyper(p, args->offset);
979 *p++ = cpu_to_be32(args->count);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000980 *p++ = cpu_to_be32(args->stable);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000981 *p = cpu_to_be32(args->count);
982 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
983}
984
Chuck Lever9f06c712010-12-14 14:59:18 +0000985static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
986 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200987 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +0000988{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200989 const struct nfs_pgio_args *args = data;
990
Chuck Lever9f06c712010-12-14 14:59:18 +0000991 encode_write3args(xdr, args);
992 xdr->buf->flags |= XDRBUF_WRITE;
Chuck Leverd9c407b2010-12-14 14:55:50 +0000993}
994
995/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000996 * 3.3.8 CREATE3args
997 *
998 * enum createmode3 {
999 * UNCHECKED = 0,
1000 * GUARDED = 1,
1001 * EXCLUSIVE = 2
1002 * };
1003 *
1004 * union createhow3 switch (createmode3 mode) {
1005 * case UNCHECKED:
1006 * case GUARDED:
1007 * sattr3 obj_attributes;
1008 * case EXCLUSIVE:
1009 * createverf3 verf;
1010 * };
1011 *
1012 * struct CREATE3args {
1013 * diropargs3 where;
1014 * createhow3 how;
1015 * };
1016 */
1017static void encode_createhow3(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04001018 const struct nfs3_createargs *args,
1019 struct user_namespace *userns)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001020{
1021 encode_uint32(xdr, args->createmode);
1022 switch (args->createmode) {
1023 case NFS3_CREATE_UNCHECKED:
1024 case NFS3_CREATE_GUARDED:
Trond Myklebust264d9482019-04-24 17:46:46 -04001025 encode_sattr3(xdr, args->sattr, userns);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001026 break;
1027 case NFS3_CREATE_EXCLUSIVE:
1028 encode_createverf3(xdr, args->verifier);
1029 break;
1030 default:
1031 BUG();
1032 }
1033}
1034
Chuck Lever9f06c712010-12-14 14:59:18 +00001035static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
1036 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001037 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001038{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001039 const struct nfs3_createargs *args = data;
1040
Chuck Lever9f06c712010-12-14 14:59:18 +00001041 encode_diropargs3(xdr, args->fh, args->name, args->len);
Trond Myklebust264d9482019-04-24 17:46:46 -04001042 encode_createhow3(xdr, args, rpc_rqst_userns(req));
Chuck Leverd9c407b2010-12-14 14:55:50 +00001043}
1044
1045/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001046 * 3.3.9 MKDIR3args
1047 *
1048 * struct MKDIR3args {
1049 * diropargs3 where;
1050 * sattr3 attributes;
1051 * };
1052 */
Chuck Lever9f06c712010-12-14 14:59:18 +00001053static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
1054 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001055 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001056{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001057 const struct nfs3_mkdirargs *args = data;
1058
Chuck Lever9f06c712010-12-14 14:59:18 +00001059 encode_diropargs3(xdr, args->fh, args->name, args->len);
Trond Myklebust264d9482019-04-24 17:46:46 -04001060 encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
Chuck Leverd9c407b2010-12-14 14:55:50 +00001061}
1062
1063/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001064 * 3.3.10 SYMLINK3args
1065 *
1066 * struct symlinkdata3 {
1067 * sattr3 symlink_attributes;
1068 * nfspath3 symlink_data;
1069 * };
1070 *
1071 * struct SYMLINK3args {
1072 * diropargs3 where;
1073 * symlinkdata3 symlink;
1074 * };
1075 */
1076static void encode_symlinkdata3(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04001077 const void *data,
1078 struct user_namespace *userns)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001079{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001080 const struct nfs3_symlinkargs *args = data;
1081
Trond Myklebust264d9482019-04-24 17:46:46 -04001082 encode_sattr3(xdr, args->sattr, userns);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001083 encode_nfspath3(xdr, args->pages, args->pathlen);
1084}
1085
Chuck Lever9f06c712010-12-14 14:59:18 +00001086static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
1087 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001088 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001089{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001090 const struct nfs3_symlinkargs *args = data;
1091
Chuck Lever9f06c712010-12-14 14:59:18 +00001092 encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
Trond Myklebust264d9482019-04-24 17:46:46 -04001093 encode_symlinkdata3(xdr, args, rpc_rqst_userns(req));
Chuck Lever2fcc2132015-08-03 13:04:26 -04001094 xdr->buf->flags |= XDRBUF_WRITE;
Chuck Leverd9c407b2010-12-14 14:55:50 +00001095}
1096
1097/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001098 * 3.3.11 MKNOD3args
1099 *
1100 * struct devicedata3 {
1101 * sattr3 dev_attributes;
1102 * specdata3 spec;
1103 * };
1104 *
1105 * union mknoddata3 switch (ftype3 type) {
1106 * case NF3CHR:
1107 * case NF3BLK:
1108 * devicedata3 device;
1109 * case NF3SOCK:
1110 * case NF3FIFO:
1111 * sattr3 pipe_attributes;
1112 * default:
1113 * void;
1114 * };
1115 *
1116 * struct MKNOD3args {
1117 * diropargs3 where;
1118 * mknoddata3 what;
1119 * };
1120 */
1121static void encode_devicedata3(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04001122 const struct nfs3_mknodargs *args,
1123 struct user_namespace *userns)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001124{
Trond Myklebust264d9482019-04-24 17:46:46 -04001125 encode_sattr3(xdr, args->sattr, userns);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001126 encode_specdata3(xdr, args->rdev);
1127}
1128
1129static void encode_mknoddata3(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04001130 const struct nfs3_mknodargs *args,
1131 struct user_namespace *userns)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001132{
1133 encode_ftype3(xdr, args->type);
1134 switch (args->type) {
1135 case NF3CHR:
1136 case NF3BLK:
Trond Myklebust264d9482019-04-24 17:46:46 -04001137 encode_devicedata3(xdr, args, userns);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001138 break;
1139 case NF3SOCK:
1140 case NF3FIFO:
Trond Myklebust264d9482019-04-24 17:46:46 -04001141 encode_sattr3(xdr, args->sattr, userns);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001142 break;
1143 case NF3REG:
1144 case NF3DIR:
1145 break;
1146 default:
1147 BUG();
1148 }
1149}
1150
Chuck Lever9f06c712010-12-14 14:59:18 +00001151static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
1152 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001153 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001154{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001155 const struct nfs3_mknodargs *args = data;
1156
Chuck Lever9f06c712010-12-14 14:59:18 +00001157 encode_diropargs3(xdr, args->fh, args->name, args->len);
Trond Myklebust264d9482019-04-24 17:46:46 -04001158 encode_mknoddata3(xdr, args, rpc_rqst_userns(req));
Chuck Leverd9c407b2010-12-14 14:55:50 +00001159}
1160
1161/*
1162 * 3.3.12 REMOVE3args
1163 *
1164 * struct REMOVE3args {
1165 * diropargs3 object;
1166 * };
1167 */
Chuck Lever9f06c712010-12-14 14:59:18 +00001168static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
1169 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001170 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001171{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001172 const struct nfs_removeargs *args = data;
1173
Chuck Lever9f06c712010-12-14 14:59:18 +00001174 encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001175}
1176
1177/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001178 * 3.3.14 RENAME3args
1179 *
1180 * struct RENAME3args {
1181 * diropargs3 from;
1182 * diropargs3 to;
1183 * };
1184 */
Chuck Lever9f06c712010-12-14 14:59:18 +00001185static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
1186 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001187 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001188{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001189 const struct nfs_renameargs *args = data;
Chuck Leverd9c407b2010-12-14 14:55:50 +00001190 const struct qstr *old = args->old_name;
1191 const struct qstr *new = args->new_name;
Chuck Leverd9c407b2010-12-14 14:55:50 +00001192
Chuck Lever9f06c712010-12-14 14:59:18 +00001193 encode_diropargs3(xdr, args->old_dir, old->name, old->len);
1194 encode_diropargs3(xdr, args->new_dir, new->name, new->len);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001195}
1196
1197/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001198 * 3.3.15 LINK3args
1199 *
1200 * struct LINK3args {
1201 * nfs_fh3 file;
1202 * diropargs3 link;
1203 * };
1204 */
Chuck Lever9f06c712010-12-14 14:59:18 +00001205static void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
1206 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001207 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001208{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001209 const struct nfs3_linkargs *args = data;
1210
Chuck Lever9f06c712010-12-14 14:59:18 +00001211 encode_nfs_fh3(xdr, args->fromfh);
1212 encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001213}
1214
1215/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001216 * 3.3.16 READDIR3args
1217 *
1218 * struct READDIR3args {
1219 * nfs_fh3 dir;
1220 * cookie3 cookie;
1221 * cookieverf3 cookieverf;
1222 * count3 count;
1223 * };
1224 */
1225static void encode_readdir3args(struct xdr_stream *xdr,
1226 const struct nfs3_readdirargs *args)
1227{
1228 __be32 *p;
1229
1230 encode_nfs_fh3(xdr, args->fh);
1231
1232 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1233 p = xdr_encode_cookie3(p, args->cookie);
1234 p = xdr_encode_cookieverf3(p, args->verf);
1235 *p = cpu_to_be32(args->count);
1236}
1237
Chuck Lever9f06c712010-12-14 14:59:18 +00001238static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
1239 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001240 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001241{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001242 const struct nfs3_readdirargs *args = data;
1243
Chuck Lever9f06c712010-12-14 14:59:18 +00001244 encode_readdir3args(xdr, args);
Trond Myklebust9ed5af262020-11-21 20:46:18 -05001245 rpc_prepare_reply_pages(req, args->pages, 0, args->count,
1246 NFS3_readdirres_sz - NFS3_pagepad_sz);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001247}
1248
1249/*
1250 * 3.3.17 READDIRPLUS3args
1251 *
1252 * struct READDIRPLUS3args {
1253 * nfs_fh3 dir;
1254 * cookie3 cookie;
1255 * cookieverf3 cookieverf;
1256 * count3 dircount;
1257 * count3 maxcount;
1258 * };
1259 */
1260static void encode_readdirplus3args(struct xdr_stream *xdr,
1261 const struct nfs3_readdirargs *args)
1262{
1263 __be32 *p;
1264
1265 encode_nfs_fh3(xdr, args->fh);
1266
1267 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1268 p = xdr_encode_cookie3(p, args->cookie);
1269 p = xdr_encode_cookieverf3(p, args->verf);
1270
1271 /*
1272 * readdirplus: need dircount + buffer size.
1273 * We just make sure we make dircount big enough
1274 */
1275 *p++ = cpu_to_be32(args->count >> 3);
1276
1277 *p = cpu_to_be32(args->count);
1278}
1279
Chuck Lever9f06c712010-12-14 14:59:18 +00001280static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
1281 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001282 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001283{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001284 const struct nfs3_readdirargs *args = data;
1285
Chuck Lever9f06c712010-12-14 14:59:18 +00001286 encode_readdirplus3args(xdr, args);
Trond Myklebust9ed5af262020-11-21 20:46:18 -05001287 rpc_prepare_reply_pages(req, args->pages, 0, args->count,
1288 NFS3_readdirres_sz - NFS3_pagepad_sz);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001289}
1290
1291/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001292 * 3.3.21 COMMIT3args
1293 *
1294 * struct COMMIT3args {
1295 * nfs_fh3 file;
1296 * offset3 offset;
1297 * count3 count;
1298 * };
1299 */
1300static void encode_commit3args(struct xdr_stream *xdr,
Fred Isaman0b7c0152012-04-20 14:47:39 -04001301 const struct nfs_commitargs *args)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001302{
1303 __be32 *p;
1304
1305 encode_nfs_fh3(xdr, args->fh);
1306
1307 p = xdr_reserve_space(xdr, 8 + 4);
1308 p = xdr_encode_hyper(p, args->offset);
1309 *p = cpu_to_be32(args->count);
1310}
1311
Chuck Lever9f06c712010-12-14 14:59:18 +00001312static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
1313 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001314 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001315{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001316 const struct nfs_commitargs *args = data;
1317
Chuck Lever9f06c712010-12-14 14:59:18 +00001318 encode_commit3args(xdr, args);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001319}
1320
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001321#ifdef CONFIG_NFS_V3_ACL
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001322
Chuck Lever9f06c712010-12-14 14:59:18 +00001323static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
1324 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001325 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001326{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001327 const struct nfs3_getaclargs *args = data;
1328
Chuck Lever9f06c712010-12-14 14:59:18 +00001329 encode_nfs_fh3(xdr, args->fh);
1330 encode_uint32(xdr, args->mask);
Trond Myklebust431f6eb2018-09-16 00:08:20 -04001331 if (args->mask & (NFS_ACL | NFS_DFACL)) {
Chuck Levercf500ba2019-02-11 11:25:20 -05001332 rpc_prepare_reply_pages(req, args->pages, 0,
Chuck Leverd9c407b2010-12-14 14:55:50 +00001333 NFSACL_MAXPAGES << PAGE_SHIFT,
Trond Myklebust9ed5af262020-11-21 20:46:18 -05001334 ACL3_getaclres_sz - NFS3_pagepad_sz);
Trond Myklebust431f6eb2018-09-16 00:08:20 -04001335 req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
1336 }
Chuck Leverd9c407b2010-12-14 14:55:50 +00001337}
1338
Chuck Lever9f06c712010-12-14 14:59:18 +00001339static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
1340 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001341 const void *data)
Chuck Leverd9c407b2010-12-14 14:55:50 +00001342{
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001343 const struct nfs3_setaclargs *args = data;
Chuck Leverd9c407b2010-12-14 14:55:50 +00001344 unsigned int base;
1345 int error;
1346
Chuck Lever9f06c712010-12-14 14:59:18 +00001347 encode_nfs_fh3(xdr, NFS_FH(args->inode));
1348 encode_uint32(xdr, args->mask);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001349
1350 base = req->rq_slen;
Chuck Leveree5dc772011-01-21 03:05:18 +00001351 if (args->npages != 0)
1352 xdr_write_pages(xdr, args->pages, 0, args->len);
1353 else
Chuck Leverd683cc42015-05-26 11:53:52 -04001354 xdr_reserve_space(xdr, args->len);
Chuck Leveree5dc772011-01-21 03:05:18 +00001355
Chuck Lever9f06c712010-12-14 14:59:18 +00001356 error = nfsacl_encode(xdr->buf, base, args->inode,
Chuck Leverd9c407b2010-12-14 14:55:50 +00001357 (args->mask & NFS_ACL) ?
1358 args->acl_access : NULL, 1, 0);
Trond Myklebust7fc38842012-10-15 11:51:21 -04001359 /* FIXME: this is just broken */
Chuck Leverd9c407b2010-12-14 14:55:50 +00001360 BUG_ON(error < 0);
Chuck Lever9f06c712010-12-14 14:59:18 +00001361 error = nfsacl_encode(xdr->buf, base + error, args->inode,
Chuck Leverd9c407b2010-12-14 14:55:50 +00001362 (args->mask & NFS_DFACL) ?
1363 args->acl_default : NULL, 1,
1364 NFS_ACL_DEFAULT);
1365 BUG_ON(error < 0);
Chuck Leverd9c407b2010-12-14 14:55:50 +00001366}
1367
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001368#endif /* CONFIG_NFS_V3_ACL */
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370/*
Chuck Leverb2cdd9c2010-12-14 14:56:52 +00001371 * NFSv3 XDR decode functions
1372 *
1373 * NFSv3 result types are defined in section 3.3 of RFC 1813:
1374 * "NFS Version 3 Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 */
1376
1377/*
Chuck Levere4f93232010-12-14 14:56:30 +00001378 * 3.3.1 GETATTR3res
1379 *
1380 * struct GETATTR3resok {
1381 * fattr3 obj_attributes;
1382 * };
1383 *
1384 * union GETATTR3res switch (nfsstat3 status) {
1385 * case NFS3_OK:
1386 * GETATTR3resok resok;
1387 * default:
1388 * void;
1389 * };
1390 */
Chuck Leverbf269552010-12-14 14:59:29 +00001391static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
1392 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001393 void *result)
Chuck Levere4f93232010-12-14 14:56:30 +00001394{
Chuck Levere4f93232010-12-14 14:56:30 +00001395 enum nfs_stat status;
1396 int error;
1397
Chuck Leverbf269552010-12-14 14:59:29 +00001398 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001399 if (unlikely(error))
1400 goto out;
1401 if (status != NFS3_OK)
1402 goto out_default;
Trond Myklebust264d9482019-04-24 17:46:46 -04001403 error = decode_fattr3(xdr, result, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001404out:
1405 return error;
1406out_default:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001407 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001408}
1409
1410/*
Chuck Levere4f93232010-12-14 14:56:30 +00001411 * 3.3.2 SETATTR3res
1412 *
1413 * struct SETATTR3resok {
1414 * wcc_data obj_wcc;
1415 * };
1416 *
1417 * struct SETATTR3resfail {
1418 * wcc_data obj_wcc;
1419 * };
1420 *
1421 * union SETATTR3res switch (nfsstat3 status) {
1422 * case NFS3_OK:
1423 * SETATTR3resok resok;
1424 * default:
1425 * SETATTR3resfail resfail;
1426 * };
1427 */
Chuck Leverbf269552010-12-14 14:59:29 +00001428static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
1429 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001430 void *result)
Chuck Levere4f93232010-12-14 14:56:30 +00001431{
Chuck Levere4f93232010-12-14 14:56:30 +00001432 enum nfs_stat status;
1433 int error;
1434
Chuck Leverbf269552010-12-14 14:59:29 +00001435 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001436 if (unlikely(error))
1437 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001438 error = decode_wcc_data(xdr, result, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001439 if (unlikely(error))
1440 goto out;
1441 if (status != NFS3_OK)
1442 goto out_status;
1443out:
1444 return error;
1445out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001446 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001447}
1448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449/*
Chuck Levere4f93232010-12-14 14:56:30 +00001450 * 3.3.3 LOOKUP3res
1451 *
1452 * struct LOOKUP3resok {
1453 * nfs_fh3 object;
1454 * post_op_attr obj_attributes;
1455 * post_op_attr dir_attributes;
1456 * };
1457 *
1458 * struct LOOKUP3resfail {
1459 * post_op_attr dir_attributes;
1460 * };
1461 *
1462 * union LOOKUP3res switch (nfsstat3 status) {
1463 * case NFS3_OK:
1464 * LOOKUP3resok resok;
1465 * default:
1466 * LOOKUP3resfail resfail;
1467 * };
1468 */
Chuck Leverbf269552010-12-14 14:59:29 +00001469static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
1470 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001471 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001472{
Trond Myklebust264d9482019-04-24 17:46:46 -04001473 struct user_namespace *userns = rpc_rqst_userns(req);
Christoph Hellwigfc016482017-05-08 15:09:02 +02001474 struct nfs3_diropres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001475 enum nfs_stat status;
1476 int error;
1477
Chuck Leverbf269552010-12-14 14:59:29 +00001478 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001479 if (unlikely(error))
1480 goto out;
1481 if (status != NFS3_OK)
1482 goto out_default;
Chuck Leverbf269552010-12-14 14:59:29 +00001483 error = decode_nfs_fh3(xdr, result->fh);
Chuck Levere4f93232010-12-14 14:56:30 +00001484 if (unlikely(error))
1485 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001486 error = decode_post_op_attr(xdr, result->fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001487 if (unlikely(error))
1488 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001489 error = decode_post_op_attr(xdr, result->dir_attr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001490out:
1491 return error;
1492out_default:
Trond Myklebust264d9482019-04-24 17:46:46 -04001493 error = decode_post_op_attr(xdr, result->dir_attr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001494 if (unlikely(error))
1495 goto out;
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001496 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001497}
1498
1499/*
Chuck Levere4f93232010-12-14 14:56:30 +00001500 * 3.3.4 ACCESS3res
1501 *
1502 * struct ACCESS3resok {
1503 * post_op_attr obj_attributes;
1504 * uint32 access;
1505 * };
1506 *
1507 * struct ACCESS3resfail {
1508 * post_op_attr obj_attributes;
1509 * };
1510 *
1511 * union ACCESS3res switch (nfsstat3 status) {
1512 * case NFS3_OK:
1513 * ACCESS3resok resok;
1514 * default:
1515 * ACCESS3resfail resfail;
1516 * };
1517 */
Chuck Leverbf269552010-12-14 14:59:29 +00001518static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
1519 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001520 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001521{
Christoph Hellwigfc016482017-05-08 15:09:02 +02001522 struct nfs3_accessres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001523 enum nfs_stat status;
1524 int error;
1525
Chuck Leverbf269552010-12-14 14:59:29 +00001526 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001527 if (unlikely(error))
1528 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001529 error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001530 if (unlikely(error))
1531 goto out;
1532 if (status != NFS3_OK)
1533 goto out_default;
Chuck Leverbf269552010-12-14 14:59:29 +00001534 error = decode_uint32(xdr, &result->access);
Chuck Levere4f93232010-12-14 14:56:30 +00001535out:
1536 return error;
1537out_default:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001538 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001539}
1540
1541/*
Chuck Levere4f93232010-12-14 14:56:30 +00001542 * 3.3.5 READLINK3res
1543 *
1544 * struct READLINK3resok {
1545 * post_op_attr symlink_attributes;
1546 * nfspath3 data;
1547 * };
1548 *
1549 * struct READLINK3resfail {
1550 * post_op_attr symlink_attributes;
1551 * };
1552 *
1553 * union READLINK3res switch (nfsstat3 status) {
1554 * case NFS3_OK:
1555 * READLINK3resok resok;
1556 * default:
1557 * READLINK3resfail resfail;
1558 * };
1559 */
Chuck Leverbf269552010-12-14 14:59:29 +00001560static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
1561 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001562 void *result)
Chuck Levere4f93232010-12-14 14:56:30 +00001563{
Chuck Levere4f93232010-12-14 14:56:30 +00001564 enum nfs_stat status;
1565 int error;
1566
Chuck Leverbf269552010-12-14 14:59:29 +00001567 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001568 if (unlikely(error))
1569 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001570 error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001571 if (unlikely(error))
1572 goto out;
1573 if (status != NFS3_OK)
1574 goto out_default;
Chuck Leverbf269552010-12-14 14:59:29 +00001575 error = decode_nfspath3(xdr);
Chuck Levere4f93232010-12-14 14:56:30 +00001576out:
1577 return error;
1578out_default:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001579 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001580}
1581
1582/*
Chuck Levere4f93232010-12-14 14:56:30 +00001583 * 3.3.6 READ3res
1584 *
1585 * struct READ3resok {
1586 * post_op_attr file_attributes;
1587 * count3 count;
1588 * bool eof;
1589 * opaque data<>;
1590 * };
1591 *
1592 * struct READ3resfail {
1593 * post_op_attr file_attributes;
1594 * };
1595 *
1596 * union READ3res switch (nfsstat3 status) {
1597 * case NFS3_OK:
1598 * READ3resok resok;
1599 * default:
1600 * READ3resfail resfail;
1601 * };
1602 */
1603static int decode_read3resok(struct xdr_stream *xdr,
Anna Schumaker9137bdf2014-05-06 09:12:25 -04001604 struct nfs_pgio_res *result)
Chuck Levere4f93232010-12-14 14:56:30 +00001605{
1606 u32 eof, count, ocount, recvd;
Chuck Levere4f93232010-12-14 14:56:30 +00001607 __be32 *p;
1608
1609 p = xdr_inline_decode(xdr, 4 + 4 + 4);
Chuck Levereb72f482019-02-11 11:24:21 -05001610 if (unlikely(!p))
1611 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00001612 count = be32_to_cpup(p++);
1613 eof = be32_to_cpup(p++);
1614 ocount = be32_to_cpup(p++);
1615 if (unlikely(ocount != count))
1616 goto out_mismatch;
Trond Myklebust64bd5772012-06-20 22:35:05 -04001617 recvd = xdr_read_pages(xdr, count);
Chuck Levere4f93232010-12-14 14:56:30 +00001618 if (unlikely(count > recvd))
1619 goto out_cheating;
Chuck Levere4f93232010-12-14 14:56:30 +00001620out:
Chuck Levere4f93232010-12-14 14:56:30 +00001621 result->eof = eof;
1622 result->count = count;
1623 return count;
1624out_mismatch:
1625 dprintk("NFS: READ count doesn't match length of opaque: "
1626 "count %u != ocount %u\n", count, ocount);
1627 return -EIO;
1628out_cheating:
1629 dprintk("NFS: server cheating in read result: "
1630 "count %u > recvd %u\n", count, recvd);
1631 count = recvd;
1632 eof = 0;
1633 goto out;
Chuck Levere4f93232010-12-14 14:56:30 +00001634}
1635
Chuck Leverbf269552010-12-14 14:59:29 +00001636static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001637 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001638{
Christoph Hellwigfc016482017-05-08 15:09:02 +02001639 struct nfs_pgio_res *result = data;
Trond Myklebust8d8928d2018-03-05 12:03:00 -05001640 unsigned int pos;
Chuck Levere4f93232010-12-14 14:56:30 +00001641 enum nfs_stat status;
1642 int error;
1643
Trond Myklebust8d8928d2018-03-05 12:03:00 -05001644 pos = xdr_stream_pos(xdr);
Chuck Leverbf269552010-12-14 14:59:29 +00001645 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001646 if (unlikely(error))
1647 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001648 error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001649 if (unlikely(error))
1650 goto out;
Peng Taoaabff4d2014-08-27 10:47:14 +08001651 result->op_status = status;
Chuck Levere4f93232010-12-14 14:56:30 +00001652 if (status != NFS3_OK)
1653 goto out_status;
Trond Myklebust9ed5af262020-11-21 20:46:18 -05001654 result->replen = 3 + ((xdr_stream_pos(xdr) - pos) >> 2);
Chuck Leverbf269552010-12-14 14:59:29 +00001655 error = decode_read3resok(xdr, result);
Chuck Levere4f93232010-12-14 14:56:30 +00001656out:
1657 return error;
1658out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001659 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001660}
1661
1662/*
Chuck Levere4f93232010-12-14 14:56:30 +00001663 * 3.3.7 WRITE3res
1664 *
1665 * enum stable_how {
1666 * UNSTABLE = 0,
1667 * DATA_SYNC = 1,
1668 * FILE_SYNC = 2
1669 * };
1670 *
1671 * struct WRITE3resok {
1672 * wcc_data file_wcc;
1673 * count3 count;
1674 * stable_how committed;
1675 * writeverf3 verf;
1676 * };
1677 *
1678 * struct WRITE3resfail {
1679 * wcc_data file_wcc;
1680 * };
1681 *
1682 * union WRITE3res switch (nfsstat3 status) {
1683 * case NFS3_OK:
1684 * WRITE3resok resok;
1685 * default:
1686 * WRITE3resfail resfail;
1687 * };
1688 */
1689static int decode_write3resok(struct xdr_stream *xdr,
Anna Schumaker9137bdf2014-05-06 09:12:25 -04001690 struct nfs_pgio_res *result)
Chuck Levere4f93232010-12-14 14:56:30 +00001691{
1692 __be32 *p;
1693
Trond Myklebust2f2c63b2012-06-08 11:56:09 -04001694 p = xdr_inline_decode(xdr, 4 + 4);
Chuck Levereb72f482019-02-11 11:24:21 -05001695 if (unlikely(!p))
1696 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00001697 result->count = be32_to_cpup(p++);
1698 result->verf->committed = be32_to_cpup(p++);
1699 if (unlikely(result->verf->committed > NFS_FILE_SYNC))
1700 goto out_badvalue;
Trond Myklebust2f2c63b2012-06-08 11:56:09 -04001701 if (decode_writeverf3(xdr, &result->verf->verifier))
Chuck Levereb72f482019-02-11 11:24:21 -05001702 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00001703 return result->count;
1704out_badvalue:
1705 dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
1706 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00001707}
1708
Chuck Leverbf269552010-12-14 14:59:29 +00001709static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001710 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001711{
Christoph Hellwigfc016482017-05-08 15:09:02 +02001712 struct nfs_pgio_res *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001713 enum nfs_stat status;
1714 int error;
1715
Chuck Leverbf269552010-12-14 14:59:29 +00001716 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001717 if (unlikely(error))
1718 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001719 error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001720 if (unlikely(error))
1721 goto out;
Peng Taoaabff4d2014-08-27 10:47:14 +08001722 result->op_status = status;
Chuck Levere4f93232010-12-14 14:56:30 +00001723 if (status != NFS3_OK)
1724 goto out_status;
Chuck Leverbf269552010-12-14 14:59:29 +00001725 error = decode_write3resok(xdr, result);
Chuck Levere4f93232010-12-14 14:56:30 +00001726out:
1727 return error;
1728out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001729 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001730}
1731
1732/*
Chuck Levere4f93232010-12-14 14:56:30 +00001733 * 3.3.8 CREATE3res
1734 *
1735 * struct CREATE3resok {
1736 * post_op_fh3 obj;
1737 * post_op_attr obj_attributes;
1738 * wcc_data dir_wcc;
1739 * };
1740 *
1741 * struct CREATE3resfail {
1742 * wcc_data dir_wcc;
1743 * };
1744 *
1745 * union CREATE3res switch (nfsstat3 status) {
1746 * case NFS3_OK:
1747 * CREATE3resok resok;
1748 * default:
1749 * CREATE3resfail resfail;
1750 * };
1751 */
1752static int decode_create3resok(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04001753 struct nfs3_diropres *result,
1754 struct user_namespace *userns)
Chuck Levere4f93232010-12-14 14:56:30 +00001755{
1756 int error;
1757
1758 error = decode_post_op_fh3(xdr, result->fh);
1759 if (unlikely(error))
1760 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001761 error = decode_post_op_attr(xdr, result->fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001762 if (unlikely(error))
1763 goto out;
1764 /* The server isn't required to return a file handle.
1765 * If it didn't, force the client to perform a LOOKUP
1766 * to determine the correct file handle and attribute
1767 * values for the new object. */
1768 if (result->fh->size == 0)
1769 result->fattr->valid = 0;
Trond Myklebust264d9482019-04-24 17:46:46 -04001770 error = decode_wcc_data(xdr, result->dir_attr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001771out:
1772 return error;
1773}
1774
Chuck Leverbf269552010-12-14 14:59:29 +00001775static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
1776 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001777 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001778{
Trond Myklebust264d9482019-04-24 17:46:46 -04001779 struct user_namespace *userns = rpc_rqst_userns(req);
Christoph Hellwigfc016482017-05-08 15:09:02 +02001780 struct nfs3_diropres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001781 enum nfs_stat status;
1782 int error;
1783
Chuck Leverbf269552010-12-14 14:59:29 +00001784 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001785 if (unlikely(error))
1786 goto out;
1787 if (status != NFS3_OK)
1788 goto out_default;
Trond Myklebust264d9482019-04-24 17:46:46 -04001789 error = decode_create3resok(xdr, result, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001790out:
1791 return error;
1792out_default:
Trond Myklebust264d9482019-04-24 17:46:46 -04001793 error = decode_wcc_data(xdr, result->dir_attr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001794 if (unlikely(error))
1795 goto out;
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001796 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001797}
1798
1799/*
1800 * 3.3.12 REMOVE3res
1801 *
1802 * struct REMOVE3resok {
1803 * wcc_data dir_wcc;
1804 * };
1805 *
1806 * struct REMOVE3resfail {
1807 * wcc_data dir_wcc;
1808 * };
1809 *
1810 * union REMOVE3res switch (nfsstat3 status) {
1811 * case NFS3_OK:
1812 * REMOVE3resok resok;
1813 * default:
1814 * REMOVE3resfail resfail;
1815 * };
1816 */
Chuck Leverbf269552010-12-14 14:59:29 +00001817static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
1818 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001819 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001820{
Christoph Hellwigfc016482017-05-08 15:09:02 +02001821 struct nfs_removeres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001822 enum nfs_stat status;
1823 int error;
1824
Chuck Leverbf269552010-12-14 14:59:29 +00001825 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001826 if (unlikely(error))
1827 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001828 error = decode_wcc_data(xdr, result->dir_attr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00001829 if (unlikely(error))
1830 goto out;
1831 if (status != NFS3_OK)
1832 goto out_status;
1833out:
1834 return error;
1835out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001836 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001837}
1838
1839/*
Chuck Levere4f93232010-12-14 14:56:30 +00001840 * 3.3.14 RENAME3res
1841 *
1842 * struct RENAME3resok {
1843 * wcc_data fromdir_wcc;
1844 * wcc_data todir_wcc;
1845 * };
1846 *
1847 * struct RENAME3resfail {
1848 * wcc_data fromdir_wcc;
1849 * wcc_data todir_wcc;
1850 * };
1851 *
1852 * union RENAME3res switch (nfsstat3 status) {
1853 * case NFS3_OK:
1854 * RENAME3resok resok;
1855 * default:
1856 * RENAME3resfail resfail;
1857 * };
1858 */
Chuck Leverbf269552010-12-14 14:59:29 +00001859static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
1860 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001861 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001862{
Trond Myklebust264d9482019-04-24 17:46:46 -04001863 struct user_namespace *userns = rpc_rqst_userns(req);
Christoph Hellwigfc016482017-05-08 15:09:02 +02001864 struct nfs_renameres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001865 enum nfs_stat status;
1866 int error;
1867
Chuck Leverbf269552010-12-14 14:59:29 +00001868 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001869 if (unlikely(error))
1870 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001871 error = decode_wcc_data(xdr, result->old_fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001872 if (unlikely(error))
1873 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001874 error = decode_wcc_data(xdr, result->new_fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001875 if (unlikely(error))
1876 goto out;
1877 if (status != NFS3_OK)
1878 goto out_status;
1879out:
1880 return error;
1881out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001882 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001883}
1884
1885/*
Chuck Levere4f93232010-12-14 14:56:30 +00001886 * 3.3.15 LINK3res
1887 *
1888 * struct LINK3resok {
1889 * post_op_attr file_attributes;
1890 * wcc_data linkdir_wcc;
1891 * };
1892 *
1893 * struct LINK3resfail {
1894 * post_op_attr file_attributes;
1895 * wcc_data linkdir_wcc;
1896 * };
1897 *
1898 * union LINK3res switch (nfsstat3 status) {
1899 * case NFS3_OK:
1900 * LINK3resok resok;
1901 * default:
1902 * LINK3resfail resfail;
1903 * };
1904 */
Chuck Leverbf269552010-12-14 14:59:29 +00001905static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001906 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00001907{
Trond Myklebust264d9482019-04-24 17:46:46 -04001908 struct user_namespace *userns = rpc_rqst_userns(req);
Christoph Hellwigfc016482017-05-08 15:09:02 +02001909 struct nfs3_linkres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00001910 enum nfs_stat status;
1911 int error;
1912
Chuck Leverbf269552010-12-14 14:59:29 +00001913 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00001914 if (unlikely(error))
1915 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001916 error = decode_post_op_attr(xdr, result->fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001917 if (unlikely(error))
1918 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04001919 error = decode_wcc_data(xdr, result->dir_attr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00001920 if (unlikely(error))
1921 goto out;
1922 if (status != NFS3_OK)
1923 goto out_status;
1924out:
1925 return error;
1926out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001927 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00001928}
1929
1930/**
1931 * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
1932 * the local page cache
1933 * @xdr: XDR stream where entry resides
1934 * @entry: buffer to fill in with entry data
Chuck Levere4f93232010-12-14 14:56:30 +00001935 * @plus: boolean indicating whether this should be a readdirplus entry
1936 *
Chuck Lever573c4e12010-12-14 14:58:11 +00001937 * Returns zero if successful, otherwise a negative errno value is
1938 * returned.
Chuck Levere4f93232010-12-14 14:56:30 +00001939 *
1940 * This function is not invoked during READDIR reply decoding, but
1941 * rather whenever an application invokes the getdents(2) system call
1942 * on a directory already in our cache.
1943 *
1944 * 3.3.16 entry3
1945 *
1946 * struct entry3 {
1947 * fileid3 fileid;
1948 * filename3 name;
1949 * cookie3 cookie;
1950 * fhandle3 filehandle;
1951 * post_op_attr3 attributes;
1952 * entry3 *nextentry;
1953 * };
1954 *
1955 * 3.3.17 entryplus3
1956 * struct entryplus3 {
1957 * fileid3 fileid;
1958 * filename3 name;
1959 * cookie3 cookie;
1960 * post_op_attr name_attributes;
1961 * post_op_fh3 name_handle;
1962 * entryplus3 *nextentry;
1963 * };
1964 */
Chuck Lever573c4e12010-12-14 14:58:11 +00001965int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04001966 bool plus)
Chuck Levere4f93232010-12-14 14:56:30 +00001967{
Trond Myklebust264d9482019-04-24 17:46:46 -04001968 struct user_namespace *userns = rpc_userns(entry->server->client);
Chuck Levere4f93232010-12-14 14:56:30 +00001969 struct nfs_entry old = *entry;
1970 __be32 *p;
1971 int error;
Frank Sorenson98de9ce2018-04-02 16:12:45 -05001972 u64 new_cookie;
Chuck Levere4f93232010-12-14 14:56:30 +00001973
1974 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -05001975 if (unlikely(!p))
1976 return -EAGAIN;
Chuck Levere4f93232010-12-14 14:56:30 +00001977 if (*p == xdr_zero) {
1978 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -05001979 if (unlikely(!p))
1980 return -EAGAIN;
Chuck Levere4f93232010-12-14 14:56:30 +00001981 if (*p == xdr_zero)
Chuck Lever573c4e12010-12-14 14:58:11 +00001982 return -EAGAIN;
Chuck Levere4f93232010-12-14 14:56:30 +00001983 entry->eof = 1;
Chuck Lever573c4e12010-12-14 14:58:11 +00001984 return -EBADCOOKIE;
Chuck Levere4f93232010-12-14 14:56:30 +00001985 }
1986
1987 error = decode_fileid3(xdr, &entry->ino);
1988 if (unlikely(error))
Chuck Lever573c4e12010-12-14 14:58:11 +00001989 return error;
Chuck Levere4f93232010-12-14 14:56:30 +00001990
1991 error = decode_inline_filename3(xdr, &entry->name, &entry->len);
1992 if (unlikely(error))
Chuck Lever573c4e12010-12-14 14:58:11 +00001993 return error;
Chuck Levere4f93232010-12-14 14:56:30 +00001994
Frank Sorenson98de9ce2018-04-02 16:12:45 -05001995 error = decode_cookie3(xdr, &new_cookie);
Chuck Levere4f93232010-12-14 14:56:30 +00001996 if (unlikely(error))
Chuck Lever573c4e12010-12-14 14:58:11 +00001997 return error;
Chuck Levere4f93232010-12-14 14:56:30 +00001998
1999 entry->d_type = DT_UNKNOWN;
2000
2001 if (plus) {
2002 entry->fattr->valid = 0;
Trond Myklebust264d9482019-04-24 17:46:46 -04002003 error = decode_post_op_attr(xdr, entry->fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00002004 if (unlikely(error))
Chuck Lever573c4e12010-12-14 14:58:11 +00002005 return error;
Chuck Levere4f93232010-12-14 14:56:30 +00002006 if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
2007 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
2008
Trond Myklebust1ae04b22015-02-23 16:15:00 -05002009 if (entry->fattr->fileid != entry->ino) {
2010 entry->fattr->mounted_on_fileid = entry->ino;
2011 entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
2012 }
2013
Chuck Levere4f93232010-12-14 14:56:30 +00002014 /* In fact, a post_op_fh3: */
2015 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -05002016 if (unlikely(!p))
2017 return -EAGAIN;
Chuck Levere4f93232010-12-14 14:56:30 +00002018 if (*p != xdr_zero) {
2019 error = decode_nfs_fh3(xdr, entry->fh);
2020 if (unlikely(error)) {
2021 if (error == -E2BIG)
2022 goto out_truncated;
Chuck Lever573c4e12010-12-14 14:58:11 +00002023 return error;
Chuck Levere4f93232010-12-14 14:56:30 +00002024 }
2025 } else
2026 zero_nfs_fh3(entry->fh);
2027 }
2028
Frank Sorenson98de9ce2018-04-02 16:12:45 -05002029 entry->prev_cookie = entry->cookie;
2030 entry->cookie = new_cookie;
2031
Chuck Lever573c4e12010-12-14 14:58:11 +00002032 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +00002033
Chuck Levere4f93232010-12-14 14:56:30 +00002034out_truncated:
2035 dprintk("NFS: directory entry contains invalid file handle\n");
2036 *entry = old;
Chuck Lever573c4e12010-12-14 14:58:11 +00002037 return -EAGAIN;
Chuck Levere4f93232010-12-14 14:56:30 +00002038}
2039
2040/*
2041 * 3.3.16 READDIR3res
2042 *
2043 * struct dirlist3 {
2044 * entry3 *entries;
2045 * bool eof;
2046 * };
2047 *
2048 * struct READDIR3resok {
2049 * post_op_attr dir_attributes;
2050 * cookieverf3 cookieverf;
2051 * dirlist3 reply;
2052 * };
2053 *
2054 * struct READDIR3resfail {
2055 * post_op_attr dir_attributes;
2056 * };
2057 *
2058 * union READDIR3res switch (nfsstat3 status) {
2059 * case NFS3_OK:
2060 * READDIR3resok resok;
2061 * default:
2062 * READDIR3resfail resfail;
2063 * };
2064 *
2065 * Read the directory contents into the page cache, but otherwise
2066 * don't touch them. The actual decoding is done by nfs3_decode_entry()
2067 * during subsequent nfs_readdir() calls.
2068 */
2069static int decode_dirlist3(struct xdr_stream *xdr)
2070{
Trond Myklebust64bd5772012-06-20 22:35:05 -04002071 return xdr_read_pages(xdr, xdr->buf->page_len);
Chuck Levere4f93232010-12-14 14:56:30 +00002072}
2073
2074static int decode_readdir3resok(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04002075 struct nfs3_readdirres *result,
2076 struct user_namespace *userns)
Chuck Levere4f93232010-12-14 14:56:30 +00002077{
2078 int error;
2079
Trond Myklebust264d9482019-04-24 17:46:46 -04002080 error = decode_post_op_attr(xdr, result->dir_attr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00002081 if (unlikely(error))
2082 goto out;
2083 /* XXX: do we need to check if result->verf != NULL ? */
2084 error = decode_cookieverf3(xdr, result->verf);
2085 if (unlikely(error))
2086 goto out;
2087 error = decode_dirlist3(xdr);
2088out:
2089 return error;
2090}
2091
Chuck Leverbf269552010-12-14 14:59:29 +00002092static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
2093 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002094 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00002095{
Christoph Hellwigfc016482017-05-08 15:09:02 +02002096 struct nfs3_readdirres *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00002097 enum nfs_stat status;
2098 int error;
2099
Chuck Leverbf269552010-12-14 14:59:29 +00002100 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002101 if (unlikely(error))
2102 goto out;
2103 if (status != NFS3_OK)
2104 goto out_default;
Trond Myklebust264d9482019-04-24 17:46:46 -04002105 error = decode_readdir3resok(xdr, result, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002106out:
2107 return error;
2108out_default:
Trond Myklebust264d9482019-04-24 17:46:46 -04002109 error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002110 if (unlikely(error))
2111 goto out;
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002112 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002113}
2114
2115/*
Chuck Levere4f93232010-12-14 14:56:30 +00002116 * 3.3.18 FSSTAT3res
2117 *
2118 * struct FSSTAT3resok {
2119 * post_op_attr obj_attributes;
2120 * size3 tbytes;
2121 * size3 fbytes;
2122 * size3 abytes;
2123 * size3 tfiles;
2124 * size3 ffiles;
2125 * size3 afiles;
2126 * uint32 invarsec;
2127 * };
2128 *
2129 * struct FSSTAT3resfail {
2130 * post_op_attr obj_attributes;
2131 * };
2132 *
2133 * union FSSTAT3res switch (nfsstat3 status) {
2134 * case NFS3_OK:
2135 * FSSTAT3resok resok;
2136 * default:
2137 * FSSTAT3resfail resfail;
2138 * };
2139 */
2140static int decode_fsstat3resok(struct xdr_stream *xdr,
2141 struct nfs_fsstat *result)
2142{
2143 __be32 *p;
2144
2145 p = xdr_inline_decode(xdr, 8 * 6 + 4);
Chuck Levereb72f482019-02-11 11:24:21 -05002146 if (unlikely(!p))
2147 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00002148 p = xdr_decode_size3(p, &result->tbytes);
2149 p = xdr_decode_size3(p, &result->fbytes);
2150 p = xdr_decode_size3(p, &result->abytes);
2151 p = xdr_decode_size3(p, &result->tfiles);
2152 p = xdr_decode_size3(p, &result->ffiles);
2153 xdr_decode_size3(p, &result->afiles);
2154 /* ignore invarsec */
2155 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +00002156}
2157
Chuck Leverbf269552010-12-14 14:59:29 +00002158static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
2159 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002160 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00002161{
Christoph Hellwigfc016482017-05-08 15:09:02 +02002162 struct nfs_fsstat *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00002163 enum nfs_stat status;
2164 int error;
2165
Chuck Leverbf269552010-12-14 14:59:29 +00002166 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002167 if (unlikely(error))
2168 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04002169 error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002170 if (unlikely(error))
2171 goto out;
2172 if (status != NFS3_OK)
2173 goto out_status;
Chuck Leverbf269552010-12-14 14:59:29 +00002174 error = decode_fsstat3resok(xdr, result);
Chuck Levere4f93232010-12-14 14:56:30 +00002175out:
2176 return error;
2177out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002178 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002179}
2180
2181/*
Chuck Levere4f93232010-12-14 14:56:30 +00002182 * 3.3.19 FSINFO3res
2183 *
2184 * struct FSINFO3resok {
2185 * post_op_attr obj_attributes;
2186 * uint32 rtmax;
2187 * uint32 rtpref;
2188 * uint32 rtmult;
2189 * uint32 wtmax;
2190 * uint32 wtpref;
2191 * uint32 wtmult;
2192 * uint32 dtpref;
2193 * size3 maxfilesize;
2194 * nfstime3 time_delta;
2195 * uint32 properties;
2196 * };
2197 *
2198 * struct FSINFO3resfail {
2199 * post_op_attr obj_attributes;
2200 * };
2201 *
2202 * union FSINFO3res switch (nfsstat3 status) {
2203 * case NFS3_OK:
2204 * FSINFO3resok resok;
2205 * default:
2206 * FSINFO3resfail resfail;
2207 * };
2208 */
2209static int decode_fsinfo3resok(struct xdr_stream *xdr,
2210 struct nfs_fsinfo *result)
2211{
2212 __be32 *p;
2213
2214 p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
Chuck Levereb72f482019-02-11 11:24:21 -05002215 if (unlikely(!p))
2216 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00002217 result->rtmax = be32_to_cpup(p++);
2218 result->rtpref = be32_to_cpup(p++);
2219 result->rtmult = be32_to_cpup(p++);
2220 result->wtmax = be32_to_cpup(p++);
2221 result->wtpref = be32_to_cpup(p++);
2222 result->wtmult = be32_to_cpup(p++);
2223 result->dtpref = be32_to_cpup(p++);
2224 p = xdr_decode_size3(p, &result->maxfilesize);
Chuck Leverf6048702010-12-14 14:57:02 +00002225 xdr_decode_nfstime3(p, &result->time_delta);
Chuck Levere4f93232010-12-14 14:56:30 +00002226
2227 /* ignore properties */
2228 result->lease_time = 0;
2229 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +00002230}
2231
Chuck Leverbf269552010-12-14 14:59:29 +00002232static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
2233 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002234 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00002235{
Christoph Hellwigfc016482017-05-08 15:09:02 +02002236 struct nfs_fsinfo *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00002237 enum nfs_stat status;
2238 int error;
2239
Chuck Leverbf269552010-12-14 14:59:29 +00002240 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002241 if (unlikely(error))
2242 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04002243 error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002244 if (unlikely(error))
2245 goto out;
2246 if (status != NFS3_OK)
2247 goto out_status;
Chuck Leverbf269552010-12-14 14:59:29 +00002248 error = decode_fsinfo3resok(xdr, result);
Chuck Levere4f93232010-12-14 14:56:30 +00002249out:
2250 return error;
2251out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002252 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002253}
2254
2255/*
Chuck Levere4f93232010-12-14 14:56:30 +00002256 * 3.3.20 PATHCONF3res
2257 *
2258 * struct PATHCONF3resok {
2259 * post_op_attr obj_attributes;
2260 * uint32 linkmax;
2261 * uint32 name_max;
2262 * bool no_trunc;
2263 * bool chown_restricted;
2264 * bool case_insensitive;
2265 * bool case_preserving;
2266 * };
2267 *
2268 * struct PATHCONF3resfail {
2269 * post_op_attr obj_attributes;
2270 * };
2271 *
2272 * union PATHCONF3res switch (nfsstat3 status) {
2273 * case NFS3_OK:
2274 * PATHCONF3resok resok;
2275 * default:
2276 * PATHCONF3resfail resfail;
2277 * };
2278 */
2279static int decode_pathconf3resok(struct xdr_stream *xdr,
2280 struct nfs_pathconf *result)
2281{
2282 __be32 *p;
2283
2284 p = xdr_inline_decode(xdr, 4 * 6);
Chuck Levereb72f482019-02-11 11:24:21 -05002285 if (unlikely(!p))
2286 return -EIO;
Chuck Levere4f93232010-12-14 14:56:30 +00002287 result->max_link = be32_to_cpup(p++);
2288 result->max_namelen = be32_to_cpup(p);
2289 /* ignore remaining fields */
2290 return 0;
Chuck Levere4f93232010-12-14 14:56:30 +00002291}
2292
Chuck Leverbf269552010-12-14 14:59:29 +00002293static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
2294 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002295 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00002296{
Christoph Hellwigfc016482017-05-08 15:09:02 +02002297 struct nfs_pathconf *result = data;
Chuck Levere4f93232010-12-14 14:56:30 +00002298 enum nfs_stat status;
2299 int error;
2300
Chuck Leverbf269552010-12-14 14:59:29 +00002301 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002302 if (unlikely(error))
2303 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04002304 error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002305 if (unlikely(error))
2306 goto out;
2307 if (status != NFS3_OK)
2308 goto out_status;
Chuck Leverbf269552010-12-14 14:59:29 +00002309 error = decode_pathconf3resok(xdr, result);
Chuck Levere4f93232010-12-14 14:56:30 +00002310out:
2311 return error;
2312out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002313 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002314}
2315
2316/*
Chuck Levere4f93232010-12-14 14:56:30 +00002317 * 3.3.21 COMMIT3res
2318 *
2319 * struct COMMIT3resok {
2320 * wcc_data file_wcc;
2321 * writeverf3 verf;
2322 * };
2323 *
2324 * struct COMMIT3resfail {
2325 * wcc_data file_wcc;
2326 * };
2327 *
2328 * union COMMIT3res switch (nfsstat3 status) {
2329 * case NFS3_OK:
2330 * COMMIT3resok resok;
2331 * default:
2332 * COMMIT3resfail resfail;
2333 * };
2334 */
Chuck Leverbf269552010-12-14 14:59:29 +00002335static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
2336 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002337 void *data)
Chuck Levere4f93232010-12-14 14:56:30 +00002338{
Christoph Hellwigfc016482017-05-08 15:09:02 +02002339 struct nfs_commitres *result = data;
Trond Myklebust221203c2020-01-06 15:25:04 -05002340 struct nfs_writeverf *verf = result->verf;
Chuck Levere4f93232010-12-14 14:56:30 +00002341 enum nfs_stat status;
2342 int error;
2343
Chuck Leverbf269552010-12-14 14:59:29 +00002344 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002345 if (unlikely(error))
2346 goto out;
Trond Myklebust264d9482019-04-24 17:46:46 -04002347 error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002348 if (unlikely(error))
2349 goto out;
Peng Taoaabff4d2014-08-27 10:47:14 +08002350 result->op_status = status;
Chuck Levere4f93232010-12-14 14:56:30 +00002351 if (status != NFS3_OK)
2352 goto out_status;
Trond Myklebust221203c2020-01-06 15:25:04 -05002353 error = decode_writeverf3(xdr, &verf->verifier);
2354 if (!error)
2355 verf->committed = NFS_FILE_SYNC;
Chuck Levere4f93232010-12-14 14:56:30 +00002356out:
2357 return error;
2358out_status:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002359 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002360}
2361
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002362#ifdef CONFIG_NFS_V3_ACL
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002363
Chuck Levere4f93232010-12-14 14:56:30 +00002364static inline int decode_getacl3resok(struct xdr_stream *xdr,
Trond Myklebust264d9482019-04-24 17:46:46 -04002365 struct nfs3_getaclres *result,
2366 struct user_namespace *userns)
Chuck Levere4f93232010-12-14 14:56:30 +00002367{
2368 struct posix_acl **acl;
2369 unsigned int *aclcnt;
2370 size_t hdrlen;
2371 int error;
2372
Trond Myklebust264d9482019-04-24 17:46:46 -04002373 error = decode_post_op_attr(xdr, result->fattr, userns);
Chuck Levere4f93232010-12-14 14:56:30 +00002374 if (unlikely(error))
2375 goto out;
2376 error = decode_uint32(xdr, &result->mask);
2377 if (unlikely(error))
2378 goto out;
2379 error = -EINVAL;
2380 if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2381 goto out;
2382
Trond Myklebust1aecca32012-06-21 11:41:29 -04002383 hdrlen = xdr_stream_pos(xdr);
Chuck Levere4f93232010-12-14 14:56:30 +00002384
2385 acl = NULL;
2386 if (result->mask & NFS_ACL)
2387 acl = &result->acl_access;
2388 aclcnt = NULL;
2389 if (result->mask & NFS_ACLCNT)
2390 aclcnt = &result->acl_access_count;
2391 error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
2392 if (unlikely(error <= 0))
2393 goto out;
2394
2395 acl = NULL;
2396 if (result->mask & NFS_DFACL)
2397 acl = &result->acl_default;
2398 aclcnt = NULL;
2399 if (result->mask & NFS_DFACLCNT)
2400 aclcnt = &result->acl_default_count;
2401 error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
2402 if (unlikely(error <= 0))
2403 return error;
2404 error = 0;
2405out:
2406 return error;
2407}
2408
Chuck Leverbf269552010-12-14 14:59:29 +00002409static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
2410 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002411 void *result)
Chuck Levere4f93232010-12-14 14:56:30 +00002412{
Chuck Levere4f93232010-12-14 14:56:30 +00002413 enum nfs_stat status;
2414 int error;
2415
Chuck Leverbf269552010-12-14 14:59:29 +00002416 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002417 if (unlikely(error))
2418 goto out;
2419 if (status != NFS3_OK)
2420 goto out_default;
Trond Myklebust264d9482019-04-24 17:46:46 -04002421 error = decode_getacl3resok(xdr, result, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002422out:
2423 return error;
2424out_default:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002425 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002426}
2427
Chuck Leverbf269552010-12-14 14:59:29 +00002428static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
2429 struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002430 void *result)
Chuck Levere4f93232010-12-14 14:56:30 +00002431{
Chuck Levere4f93232010-12-14 14:56:30 +00002432 enum nfs_stat status;
2433 int error;
2434
Chuck Leverbf269552010-12-14 14:59:29 +00002435 error = decode_nfsstat3(xdr, &status);
Chuck Levere4f93232010-12-14 14:56:30 +00002436 if (unlikely(error))
2437 goto out;
2438 if (status != NFS3_OK)
2439 goto out_default;
Trond Myklebust264d9482019-04-24 17:46:46 -04002440 error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
Chuck Levere4f93232010-12-14 14:56:30 +00002441out:
2442 return error;
2443out_default:
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002444 return nfs3_stat_to_errno(status);
Chuck Levere4f93232010-12-14 14:56:30 +00002445}
2446
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002447#endif /* CONFIG_NFS_V3_ACL */
2448
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04002449
2450/*
2451 * We need to translate between nfs status return values and
2452 * the local errno values which may not be the same.
2453 */
2454static const struct {
2455 int stat;
2456 int errno;
2457} nfs_errtbl[] = {
2458 { NFS_OK, 0 },
2459 { NFSERR_PERM, -EPERM },
2460 { NFSERR_NOENT, -ENOENT },
2461 { NFSERR_IO, -errno_NFSERR_IO},
2462 { NFSERR_NXIO, -ENXIO },
2463/* { NFSERR_EAGAIN, -EAGAIN }, */
2464 { NFSERR_ACCES, -EACCES },
2465 { NFSERR_EXIST, -EEXIST },
2466 { NFSERR_XDEV, -EXDEV },
2467 { NFSERR_NODEV, -ENODEV },
2468 { NFSERR_NOTDIR, -ENOTDIR },
2469 { NFSERR_ISDIR, -EISDIR },
2470 { NFSERR_INVAL, -EINVAL },
2471 { NFSERR_FBIG, -EFBIG },
2472 { NFSERR_NOSPC, -ENOSPC },
2473 { NFSERR_ROFS, -EROFS },
2474 { NFSERR_MLINK, -EMLINK },
2475 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
2476 { NFSERR_NOTEMPTY, -ENOTEMPTY },
2477 { NFSERR_DQUOT, -EDQUOT },
2478 { NFSERR_STALE, -ESTALE },
2479 { NFSERR_REMOTE, -EREMOTE },
2480#ifdef EWFLUSH
2481 { NFSERR_WFLUSH, -EWFLUSH },
2482#endif
2483 { NFSERR_BADHANDLE, -EBADHANDLE },
2484 { NFSERR_NOT_SYNC, -ENOTSYNC },
2485 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
2486 { NFSERR_NOTSUPP, -ENOTSUPP },
2487 { NFSERR_TOOSMALL, -ETOOSMALL },
2488 { NFSERR_SERVERFAULT, -EREMOTEIO },
2489 { NFSERR_BADTYPE, -EBADTYPE },
2490 { NFSERR_JUKEBOX, -EJUKEBOX },
2491 { -1, -EIO }
2492};
2493
2494/**
2495 * nfs3_stat_to_errno - convert an NFS status code to a local errno
2496 * @status: NFS status code to convert
2497 *
2498 * Returns a local errno value, or -EIO if the NFS status code is
2499 * not recognized. This function is used jointly by NFSv2 and NFSv3.
2500 */
2501static int nfs3_stat_to_errno(enum nfs_stat status)
2502{
2503 int i;
2504
2505 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
2506 if (nfs_errtbl[i].stat == (int)status)
2507 return nfs_errtbl[i].errno;
2508 }
2509 dprintk("NFS: Unrecognized nfs status value: %u\n", status);
2510 return nfs_errtbl[i].errno;
2511}
2512
2513
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514#define PROC(proc, argtype, restype, timer) \
2515[NFS3PROC_##proc] = { \
2516 .p_proc = NFS3PROC_##proc, \
Christoph Hellwigfcc85812017-05-08 10:01:49 +02002517 .p_encode = nfs3_xdr_enc_##argtype##3args, \
Christoph Hellwigfc016482017-05-08 15:09:02 +02002518 .p_decode = nfs3_xdr_dec_##restype##3res, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00002519 .p_arglen = NFS3_##argtype##args_sz, \
Chuck Leverf5fc3c502010-12-14 14:56:42 +00002520 .p_replen = NFS3_##restype##res_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05002521 .p_timer = timer, \
2522 .p_statidx = NFS3PROC_##proc, \
2523 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
2525
Christoph Hellwig511e9362017-05-12 15:36:49 +02002526const struct rpc_procinfo nfs3_procedures[] = {
Chuck Leverf5fc3c502010-12-14 14:56:42 +00002527 PROC(GETATTR, getattr, getattr, 1),
2528 PROC(SETATTR, setattr, setattr, 0),
2529 PROC(LOOKUP, lookup, lookup, 2),
2530 PROC(ACCESS, access, access, 1),
2531 PROC(READLINK, readlink, readlink, 3),
2532 PROC(READ, read, read, 3),
2533 PROC(WRITE, write, write, 4),
2534 PROC(CREATE, create, create, 0),
2535 PROC(MKDIR, mkdir, create, 0),
2536 PROC(SYMLINK, symlink, create, 0),
2537 PROC(MKNOD, mknod, create, 0),
2538 PROC(REMOVE, remove, remove, 0),
2539 PROC(RMDIR, lookup, setattr, 0),
2540 PROC(RENAME, rename, rename, 0),
2541 PROC(LINK, link, link, 0),
2542 PROC(READDIR, readdir, readdir, 3),
2543 PROC(READDIRPLUS, readdirplus, readdir, 3),
2544 PROC(FSSTAT, getattr, fsstat, 0),
2545 PROC(FSINFO, getattr, fsinfo, 0),
2546 PROC(PATHCONF, getattr, pathconf, 0),
2547 PROC(COMMIT, commit, commit, 5),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548};
2549
Christoph Hellwigc5518582017-05-08 23:27:10 +02002550static unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)];
Trond Myklebusta613fa12012-01-20 13:53:56 -05002551const struct rpc_version nfs_version3 = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08002553 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Christoph Hellwigc5518582017-05-08 23:27:10 +02002554 .procs = nfs3_procedures,
2555 .counts = nfs_version3_counts,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556};
2557
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002558#ifdef CONFIG_NFS_V3_ACL
Christoph Hellwig511e9362017-05-12 15:36:49 +02002559static const struct rpc_procinfo nfs3_acl_procedures[] = {
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002560 [ACLPROC3_GETACL] = {
2561 .p_proc = ACLPROC3_GETACL,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02002562 .p_encode = nfs3_xdr_enc_getacl3args,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002563 .p_decode = nfs3_xdr_dec_getacl3res,
Chuck Lever2bea90d2007-03-29 16:47:53 -04002564 .p_arglen = ACL3_getaclargs_sz,
2565 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002566 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05002567 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002568 },
2569 [ACLPROC3_SETACL] = {
2570 .p_proc = ACLPROC3_SETACL,
Christoph Hellwigfcc85812017-05-08 10:01:49 +02002571 .p_encode = nfs3_xdr_enc_setacl3args,
Christoph Hellwigfc016482017-05-08 15:09:02 +02002572 .p_decode = nfs3_xdr_dec_setacl3res,
Chuck Lever2bea90d2007-03-29 16:47:53 -04002573 .p_arglen = ACL3_setaclargs_sz,
2574 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002575 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05002576 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002577 },
2578};
2579
Christoph Hellwigc5518582017-05-08 23:27:10 +02002580static unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)];
Trond Myklebusta613fa12012-01-20 13:53:56 -05002581const struct rpc_version nfsacl_version3 = {
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002582 .number = 3,
Christoph Hellwig9ae7d8f2017-05-12 15:51:24 +02002583 .nrprocs = ARRAY_SIZE(nfs3_acl_procedures),
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002584 .procs = nfs3_acl_procedures,
Christoph Hellwigc5518582017-05-08 23:27:10 +02002585 .counts = nfs3_acl_counts,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002586};
2587#endif /* CONFIG_NFS_V3_ACL */