blob: 7fba7711e6b3a7d11c411565ceaebed583894fbd [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/nfs2xdr.c
4 *
5 * XDR functions to encode/decode NFS RPC arguments and results.
6 *
7 * Copyright (C) 1992, 1993, 1994 Rick Sladkey
8 * Copyright (C) 1996 Olaf Kirch
9 * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
10 * FIFO's need special handling in NFSv2
11 */
12
13#include <linux/param.h>
14#include <linux/time.h>
15#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/errno.h>
17#include <linux/string.h>
18#include <linux/in.h>
19#include <linux/pagemap.h>
20#include <linux/proc_fs.h>
21#include <linux/sunrpc/clnt.h>
22#include <linux/nfs.h>
23#include <linux/nfs2.h>
24#include <linux/nfs_fs.h>
Chuck Leverf23f6582019-02-11 11:24:26 -050025#include "nfstrace.h"
Trond Myklebust816724e2006-06-24 08:41:41 -040026#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28#define NFSDBG_FACILITY NFSDBG_XDR
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030/* Mapping from NFS error code to "errno" error code. */
31#define errno_NFSERR_IO EIO
32
33/*
34 * Declare the space requirements for NFS arguments and replies as
35 * number of 32bit-words
36 */
Trond Myklebust9ed5af262020-11-21 20:46:18 -050037#define NFS_pagepad_sz (1) /* Page padding */
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#define NFS_fhandle_sz (8)
39#define NFS_sattr_sz (8)
40#define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
41#define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
42#define NFS_fattr_sz (17)
43#define NFS_info_sz (5)
44#define NFS_entry_sz (NFS_filename_sz+3)
45
46#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040047#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
49#define NFS_readlinkargs_sz (NFS_fhandle_sz)
50#define NFS_readargs_sz (NFS_fhandle_sz+3)
51#define NFS_writeargs_sz (NFS_fhandle_sz+4)
52#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
53#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
54#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
Chuck Lever94a6d752006-08-22 20:06:23 -040055#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#define NFS_readdirargs_sz (NFS_fhandle_sz+2)
57
58#define NFS_attrstat_sz (1+NFS_fattr_sz)
59#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
Trond Myklebust9ed5af262020-11-21 20:46:18 -050060#define NFS_readlinkres_sz (2+NFS_pagepad_sz)
61#define NFS_readres_sz (1+NFS_fattr_sz+1+NFS_pagepad_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define NFS_writeres_sz (NFS_attrstat_sz)
63#define NFS_stat_sz (1)
Trond Myklebust9ed5af262020-11-21 20:46:18 -050064#define NFS_readdirres_sz (1+NFS_pagepad_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define NFS_statfsres_sz (1+NFS_info_sz)
66
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -040067static int nfs_stat_to_errno(enum nfs_stat);
Chuck Lever25a08662010-12-14 14:54:30 +000068
69/*
Chuck Lever25a08662010-12-14 14:54:30 +000070 * Encode/decode NFSv2 basic data types
71 *
72 * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
73 * "NFS: Network File System Protocol Specification".
74 *
75 * Not all basic data types have their own encoding and decoding
76 * functions. For run-time efficiency, some data types are encoded
77 * or decoded inline.
78 */
79
Trond Myklebustc207db22019-04-24 17:46:48 -040080static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
81{
82 if (clnt && clnt->cl_cred)
83 return clnt->cl_cred->user_ns;
84 return &init_user_ns;
85}
86
87static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
88{
89 if (rqstp->rq_task)
90 return rpc_userns(rqstp->rq_task->tk_client);
91 return &init_user_ns;
92}
93
Chuck Lever25a08662010-12-14 14:54:30 +000094/*
Chuck Leverf796f8b2010-12-14 14:55:10 +000095 * typedef opaque nfsdata<>;
96 */
Anna Schumaker9137bdf2014-05-06 09:12:25 -040097static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
Chuck Leverf796f8b2010-12-14 14:55:10 +000098{
99 u32 recvd, count;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000100 __be32 *p;
101
102 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500103 if (unlikely(!p))
104 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000105 count = be32_to_cpup(p);
Trond Myklebust64bd5772012-06-20 22:35:05 -0400106 recvd = xdr_read_pages(xdr, count);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000107 if (unlikely(count > recvd))
108 goto out_cheating;
109out:
Chuck Leverf796f8b2010-12-14 14:55:10 +0000110 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
111 result->count = count;
112 return count;
113out_cheating:
114 dprintk("NFS: server cheating in read result: "
115 "count %u > recvd %u\n", count, recvd);
116 count = recvd;
117 goto out;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000118}
119
120/*
121 * enum stat {
122 * NFS_OK = 0,
123 * NFSERR_PERM = 1,
124 * NFSERR_NOENT = 2,
125 * NFSERR_IO = 5,
126 * NFSERR_NXIO = 6,
127 * NFSERR_ACCES = 13,
128 * NFSERR_EXIST = 17,
129 * NFSERR_NODEV = 19,
130 * NFSERR_NOTDIR = 20,
131 * NFSERR_ISDIR = 21,
132 * NFSERR_FBIG = 27,
133 * NFSERR_NOSPC = 28,
134 * NFSERR_ROFS = 30,
135 * NFSERR_NAMETOOLONG = 63,
136 * NFSERR_NOTEMPTY = 66,
137 * NFSERR_DQUOT = 69,
138 * NFSERR_STALE = 70,
139 * NFSERR_WFLUSH = 99
140 * };
141 */
142static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
143{
144 __be32 *p;
145
146 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500147 if (unlikely(!p))
148 return -EIO;
Chuck Leverf23f6582019-02-11 11:24:26 -0500149 if (unlikely(*p != cpu_to_be32(NFS_OK)))
150 goto out_status;
151 *status = 0;
152 return 0;
153out_status:
Chuck Leverf796f8b2010-12-14 14:55:10 +0000154 *status = be32_to_cpup(p);
Chuck Lever62a92ba2019-06-19 10:34:09 -0400155 trace_nfs_xdr_status(xdr, (int)*status);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000156 return 0;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000157}
158
159/*
Chuck Lever5f96e5e2010-12-14 14:55:30 +0000160 * 2.3.2. ftype
161 *
162 * enum ftype {
163 * NFNON = 0,
164 * NFREG = 1,
165 * NFDIR = 2,
166 * NFBLK = 3,
167 * NFCHR = 4,
168 * NFLNK = 5
169 * };
170 *
171 */
172static __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
173{
174 *type = be32_to_cpup(p++);
175 if (unlikely(*type > NF2FIFO))
176 *type = NFBAD;
177 return p;
178}
179
180/*
Chuck Lever25a08662010-12-14 14:54:30 +0000181 * 2.3.3. fhandle
182 *
183 * typedef opaque fhandle[FHSIZE];
184 */
185static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
186{
187 __be32 *p;
188
Chuck Lever25a08662010-12-14 14:54:30 +0000189 p = xdr_reserve_space(xdr, NFS2_FHSIZE);
190 memcpy(p, fh->data, NFS2_FHSIZE);
191}
192
Chuck Leverf796f8b2010-12-14 14:55:10 +0000193static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
194{
195 __be32 *p;
196
197 p = xdr_inline_decode(xdr, NFS2_FHSIZE);
Chuck Levereb72f482019-02-11 11:24:21 -0500198 if (unlikely(!p))
199 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000200 fh->size = NFS2_FHSIZE;
201 memcpy(fh->data, p, NFS2_FHSIZE);
202 return 0;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000203}
204
Chuck Lever25a08662010-12-14 14:54:30 +0000205/*
Chuck Lever282ac2a2010-12-14 14:54:50 +0000206 * 2.3.4. timeval
207 *
208 * struct timeval {
209 * unsigned int seconds;
210 * unsigned int useconds;
211 * };
212 */
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400213static __be32 *xdr_encode_time(__be32 *p, const struct timespec64 *timep)
Chuck Lever282ac2a2010-12-14 14:54:50 +0000214{
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400215 *p++ = cpu_to_be32((u32)timep->tv_sec);
Chuck Lever282ac2a2010-12-14 14:54:50 +0000216 if (timep->tv_nsec != 0)
217 *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
218 else
219 *p++ = cpu_to_be32(0);
220 return p;
221}
222
223/*
224 * Passing the invalid value useconds=1000000 is a Sun convention for
225 * "set to current server time". It's needed to make permissions checks
226 * for the "touch" program across v2 mounts to Solaris and Irix servers
227 * work correctly. See description of sattr in section 6.1 of "NFS
228 * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
229 */
230static __be32 *xdr_encode_current_server_time(__be32 *p,
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400231 const struct timespec64 *timep)
Chuck Lever282ac2a2010-12-14 14:54:50 +0000232{
233 *p++ = cpu_to_be32(timep->tv_sec);
234 *p++ = cpu_to_be32(1000000);
235 return p;
236}
237
Trond Myklebuste86d5a02019-10-04 16:38:56 -0400238static __be32 *xdr_decode_time(__be32 *p, struct timespec64 *timep)
Chuck Lever5f96e5e2010-12-14 14:55:30 +0000239{
240 timep->tv_sec = be32_to_cpup(p++);
241 timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
242 return p;
243}
244
Chuck Lever282ac2a2010-12-14 14:54:50 +0000245/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000246 * 2.3.5. fattr
247 *
248 * struct fattr {
249 * ftype type;
250 * unsigned int mode;
251 * unsigned int nlink;
252 * unsigned int uid;
253 * unsigned int gid;
254 * unsigned int size;
255 * unsigned int blocksize;
256 * unsigned int rdev;
257 * unsigned int blocks;
258 * unsigned int fsid;
259 * unsigned int fileid;
260 * timeval atime;
261 * timeval mtime;
262 * timeval ctime;
263 * };
264 *
265 */
Trond Myklebustc207db22019-04-24 17:46:48 -0400266static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
267 struct user_namespace *userns)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000268{
Chuck Lever5f96e5e2010-12-14 14:55:30 +0000269 u32 rdev, type;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000270 __be32 *p;
271
272 p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
Chuck Levereb72f482019-02-11 11:24:21 -0500273 if (unlikely(!p))
274 return -EIO;
Chuck Lever5f96e5e2010-12-14 14:55:30 +0000275
276 fattr->valid |= NFS_ATTR_FATTR_V2;
277
278 p = xdr_decode_ftype(p, &type);
279
280 fattr->mode = be32_to_cpup(p++);
281 fattr->nlink = be32_to_cpup(p++);
Trond Myklebustc207db22019-04-24 17:46:48 -0400282 fattr->uid = make_kuid(userns, be32_to_cpup(p++));
Eric W. Biedermancfa08982013-02-01 03:45:54 -0800283 if (!uid_valid(fattr->uid))
284 goto out_uid;
Trond Myklebustc207db22019-04-24 17:46:48 -0400285 fattr->gid = make_kgid(userns, be32_to_cpup(p++));
Eric W. Biedermancfa08982013-02-01 03:45:54 -0800286 if (!gid_valid(fattr->gid))
287 goto out_gid;
288
Chuck Lever5f96e5e2010-12-14 14:55:30 +0000289 fattr->size = be32_to_cpup(p++);
290 fattr->du.nfs2.blocksize = be32_to_cpup(p++);
291
292 rdev = be32_to_cpup(p++);
293 fattr->rdev = new_decode_dev(rdev);
294 if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
295 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
296 fattr->rdev = 0;
297 }
298
299 fattr->du.nfs2.blocks = be32_to_cpup(p++);
300 fattr->fsid.major = be32_to_cpup(p++);
301 fattr->fsid.minor = 0;
302 fattr->fileid = be32_to_cpup(p++);
303
304 p = xdr_decode_time(p, &fattr->atime);
305 p = xdr_decode_time(p, &fattr->mtime);
306 xdr_decode_time(p, &fattr->ctime);
Trond Myklebust3a1556e2012-04-27 13:48:18 -0400307 fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
308
Chuck Leverf796f8b2010-12-14 14:55:10 +0000309 return 0;
Eric W. Biedermancfa08982013-02-01 03:45:54 -0800310out_uid:
311 dprintk("NFS: returned invalid uid\n");
312 return -EINVAL;
313out_gid:
314 dprintk("NFS: returned invalid gid\n");
315 return -EINVAL;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000316}
317
318/*
Chuck Lever25a08662010-12-14 14:54:30 +0000319 * 2.3.6. sattr
320 *
321 * struct sattr {
322 * unsigned int mode;
323 * unsigned int uid;
324 * unsigned int gid;
325 * unsigned int size;
326 * timeval atime;
327 * timeval mtime;
328 * };
329 */
330
331#define NFS2_SATTR_NOT_SET (0xffffffff)
332
333static __be32 *xdr_time_not_set(__be32 *p)
334{
335 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
336 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
337 return p;
338}
339
Trond Myklebustc207db22019-04-24 17:46:48 -0400340static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr,
341 struct user_namespace *userns)
Chuck Lever25a08662010-12-14 14:54:30 +0000342{
343 __be32 *p;
344
345 p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
346
347 if (attr->ia_valid & ATTR_MODE)
348 *p++ = cpu_to_be32(attr->ia_mode);
349 else
350 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
351 if (attr->ia_valid & ATTR_UID)
Trond Myklebustc207db22019-04-24 17:46:48 -0400352 *p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
Chuck Lever25a08662010-12-14 14:54:30 +0000353 else
354 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
355 if (attr->ia_valid & ATTR_GID)
Trond Myklebustc207db22019-04-24 17:46:48 -0400356 *p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
Chuck Lever25a08662010-12-14 14:54:30 +0000357 else
358 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
359 if (attr->ia_valid & ATTR_SIZE)
360 *p++ = cpu_to_be32((u32)attr->ia_size);
361 else
362 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
363
Arnd Bergmanne5189e92019-11-11 21:16:26 +0100364 if (attr->ia_valid & ATTR_ATIME_SET)
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400365 p = xdr_encode_time(p, &attr->ia_atime);
Arnd Bergmanne5189e92019-11-11 21:16:26 +0100366 else if (attr->ia_valid & ATTR_ATIME)
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400367 p = xdr_encode_current_server_time(p, &attr->ia_atime);
Arnd Bergmanne5189e92019-11-11 21:16:26 +0100368 else
Chuck Lever25a08662010-12-14 14:54:30 +0000369 p = xdr_time_not_set(p);
Arnd Bergmanne5189e92019-11-11 21:16:26 +0100370 if (attr->ia_valid & ATTR_MTIME_SET)
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400371 xdr_encode_time(p, &attr->ia_mtime);
Arnd Bergmanne5189e92019-11-11 21:16:26 +0100372 else if (attr->ia_valid & ATTR_MTIME)
Trond Myklebustc9dbfd92019-10-04 16:57:45 -0400373 xdr_encode_current_server_time(p, &attr->ia_mtime);
Arnd Bergmanne5189e92019-11-11 21:16:26 +0100374 else
Chuck Lever25a08662010-12-14 14:54:30 +0000375 xdr_time_not_set(p);
376}
377
378/*
379 * 2.3.7. filename
380 *
381 * typedef string filename<MAXNAMLEN>;
382 */
383static void encode_filename(struct xdr_stream *xdr,
384 const char *name, u32 length)
385{
386 __be32 *p;
387
Trond Myklebust7fc38842012-10-15 11:51:21 -0400388 WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
Chuck Lever25a08662010-12-14 14:54:30 +0000389 p = xdr_reserve_space(xdr, 4 + length);
390 xdr_encode_opaque(p, name, length);
391}
392
Chuck Leverf796f8b2010-12-14 14:55:10 +0000393static int decode_filename_inline(struct xdr_stream *xdr,
394 const char **name, u32 *length)
395{
396 __be32 *p;
397 u32 count;
398
399 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500400 if (unlikely(!p))
401 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000402 count = be32_to_cpup(p);
403 if (count > NFS3_MAXNAMLEN)
404 goto out_nametoolong;
405 p = xdr_inline_decode(xdr, count);
Chuck Levereb72f482019-02-11 11:24:21 -0500406 if (unlikely(!p))
407 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000408 *name = (const char *)p;
409 *length = count;
410 return 0;
411out_nametoolong:
412 dprintk("NFS: returned filename too long: %u\n", count);
413 return -ENAMETOOLONG;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000414}
415
Chuck Lever25a08662010-12-14 14:54:30 +0000416/*
417 * 2.3.8. path
418 *
419 * typedef string path<MAXPATHLEN>;
420 */
421static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
422{
423 __be32 *p;
424
Chuck Lever25a08662010-12-14 14:54:30 +0000425 p = xdr_reserve_space(xdr, 4);
426 *p = cpu_to_be32(length);
427 xdr_write_pages(xdr, pages, 0, length);
428}
429
Chuck Leverf796f8b2010-12-14 14:55:10 +0000430static int decode_path(struct xdr_stream *xdr)
431{
432 u32 length, recvd;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000433 __be32 *p;
434
435 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500436 if (unlikely(!p))
437 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000438 length = be32_to_cpup(p);
439 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
440 goto out_size;
Trond Myklebust64bd5772012-06-20 22:35:05 -0400441 recvd = xdr_read_pages(xdr, length);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000442 if (unlikely(length > recvd))
443 goto out_cheating;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000444 xdr_terminate_string(xdr->buf, length);
445 return 0;
446out_size:
447 dprintk("NFS: returned pathname too long: %u\n", length);
448 return -ENAMETOOLONG;
449out_cheating:
450 dprintk("NFS: server cheating in pathname result: "
451 "length %u > received %u\n", length, recvd);
452 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000453}
454
455/*
456 * 2.3.9. attrstat
457 *
458 * union attrstat switch (stat status) {
459 * case NFS_OK:
460 * fattr attributes;
461 * default:
462 * void;
463 * };
464 */
Peng Taoaabff4d2014-08-27 10:47:14 +0800465static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
Trond Myklebustc207db22019-04-24 17:46:48 -0400466 __u32 *op_status,
467 struct user_namespace *userns)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000468{
469 enum nfs_stat status;
470 int error;
471
472 error = decode_stat(xdr, &status);
473 if (unlikely(error))
474 goto out;
Peng Taoaabff4d2014-08-27 10:47:14 +0800475 if (op_status)
476 *op_status = status;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000477 if (status != NFS_OK)
478 goto out_default;
Trond Myklebustc207db22019-04-24 17:46:48 -0400479 error = decode_fattr(xdr, result, userns);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000480out:
481 return error;
482out_default:
483 return nfs_stat_to_errno(status);
484}
485
Chuck Lever25a08662010-12-14 14:54:30 +0000486/*
487 * 2.3.10. diropargs
488 *
489 * struct diropargs {
490 * fhandle dir;
491 * filename name;
492 * };
493 */
494static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
495 const char *name, u32 length)
496{
497 encode_fhandle(xdr, fh);
498 encode_filename(xdr, name, length);
499}
500
Chuck Leverf796f8b2010-12-14 14:55:10 +0000501/*
502 * 2.3.11. diropres
503 *
504 * union diropres switch (stat status) {
505 * case NFS_OK:
506 * struct {
507 * fhandle file;
508 * fattr attributes;
509 * } diropok;
510 * default:
511 * void;
512 * };
513 */
Trond Myklebustc207db22019-04-24 17:46:48 -0400514static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result,
515 struct user_namespace *userns)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000516{
517 int error;
518
519 error = decode_fhandle(xdr, result->fh);
520 if (unlikely(error))
521 goto out;
Trond Myklebustc207db22019-04-24 17:46:48 -0400522 error = decode_fattr(xdr, result->fattr, userns);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000523out:
524 return error;
525}
526
Trond Myklebustc207db22019-04-24 17:46:48 -0400527static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result,
528 struct user_namespace *userns)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000529{
530 enum nfs_stat status;
531 int error;
532
533 error = decode_stat(xdr, &status);
534 if (unlikely(error))
535 goto out;
536 if (status != NFS_OK)
537 goto out_default;
Trond Myklebustc207db22019-04-24 17:46:48 -0400538 error = decode_diropok(xdr, result, userns);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000539out:
540 return error;
541out_default:
542 return nfs_stat_to_errno(status);
543}
544
Chuck Lever25a08662010-12-14 14:54:30 +0000545
546/*
Chuck Lever2d70f532010-12-14 14:54:40 +0000547 * NFSv2 XDR encode functions
548 *
549 * NFSv2 argument types are defined in section 2.2 of RFC 1094:
550 * "NFS: Network File System Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Chuck Lever9f06c712010-12-14 14:59:18 +0000553static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
554 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200555 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000556{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200557 const struct nfs_fh *fh = data;
558
Chuck Lever9f06c712010-12-14 14:59:18 +0000559 encode_fhandle(xdr, fh);
Chuck Lever25a08662010-12-14 14:54:30 +0000560}
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562/*
Chuck Lever25a08662010-12-14 14:54:30 +0000563 * 2.2.3. sattrargs
564 *
565 * struct sattrargs {
566 * fhandle file;
567 * sattr attributes;
568 * };
569 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000570static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
571 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200572 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000573{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200574 const struct nfs_sattrargs *args = data;
575
Chuck Lever9f06c712010-12-14 14:59:18 +0000576 encode_fhandle(xdr, args->fh);
Trond Myklebustc207db22019-04-24 17:46:48 -0400577 encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
Chuck Lever25a08662010-12-14 14:54:30 +0000578}
579
Chuck Lever9f06c712010-12-14 14:59:18 +0000580static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
581 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200582 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000583{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200584 const struct nfs_diropargs *args = data;
585
Chuck Lever9f06c712010-12-14 14:59:18 +0000586 encode_diropargs(xdr, args->fh, args->name, args->len);
Chuck Lever25a08662010-12-14 14:54:30 +0000587}
588
Chuck Lever9f06c712010-12-14 14:59:18 +0000589static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
590 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200591 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000592{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200593 const struct nfs_readlinkargs *args = data;
594
Chuck Lever9f06c712010-12-14 14:59:18 +0000595 encode_fhandle(xdr, args->fh);
Trond Myklebust9ed5af262020-11-21 20:46:18 -0500596 rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->pglen,
597 NFS_readlinkres_sz - NFS_pagepad_sz);
Chuck Lever25a08662010-12-14 14:54:30 +0000598}
599
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400600/*
Chuck Lever25a08662010-12-14 14:54:30 +0000601 * 2.2.7. readargs
602 *
603 * struct readargs {
604 * fhandle file;
605 * unsigned offset;
606 * unsigned count;
607 * unsigned totalcount;
608 * };
609 */
610static void encode_readargs(struct xdr_stream *xdr,
Anna Schumaker3c6b8992014-05-06 09:12:24 -0400611 const struct nfs_pgio_args *args)
Chuck Lever25a08662010-12-14 14:54:30 +0000612{
613 u32 offset = args->offset;
614 u32 count = args->count;
615 __be32 *p;
616
617 encode_fhandle(xdr, args->fh);
618
619 p = xdr_reserve_space(xdr, 4 + 4 + 4);
620 *p++ = cpu_to_be32(offset);
621 *p++ = cpu_to_be32(count);
622 *p = cpu_to_be32(count);
623}
624
Chuck Lever9f06c712010-12-14 14:59:18 +0000625static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
626 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200627 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000628{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200629 const struct nfs_pgio_args *args = data;
630
Chuck Lever9f06c712010-12-14 14:59:18 +0000631 encode_readargs(xdr, args);
Trond Myklebust9ed5af262020-11-21 20:46:18 -0500632 rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->count,
633 NFS_readres_sz - NFS_pagepad_sz);
Chuck Lever25a08662010-12-14 14:54:30 +0000634 req->rq_rcv_buf.flags |= XDRBUF_READ;
Chuck Lever25a08662010-12-14 14:54:30 +0000635}
636
637/*
Chuck Lever25a08662010-12-14 14:54:30 +0000638 * 2.2.9. writeargs
639 *
640 * struct writeargs {
641 * fhandle file;
642 * unsigned beginoffset;
643 * unsigned offset;
644 * unsigned totalcount;
645 * nfsdata data;
646 * };
647 */
648static void encode_writeargs(struct xdr_stream *xdr,
Anna Schumaker3c6b8992014-05-06 09:12:24 -0400649 const struct nfs_pgio_args *args)
Chuck Lever25a08662010-12-14 14:54:30 +0000650{
651 u32 offset = args->offset;
652 u32 count = args->count;
653 __be32 *p;
654
655 encode_fhandle(xdr, args->fh);
656
657 p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
658 *p++ = cpu_to_be32(offset);
659 *p++ = cpu_to_be32(offset);
660 *p++ = cpu_to_be32(count);
661
662 /* nfsdata */
663 *p = cpu_to_be32(count);
664 xdr_write_pages(xdr, args->pages, args->pgbase, count);
665}
666
Chuck Lever9f06c712010-12-14 14:59:18 +0000667static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
668 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200669 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000670{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200671 const struct nfs_pgio_args *args = data;
672
Chuck Lever9f06c712010-12-14 14:59:18 +0000673 encode_writeargs(xdr, args);
674 xdr->buf->flags |= XDRBUF_WRITE;
Chuck Lever25a08662010-12-14 14:54:30 +0000675}
676
677/*
Chuck Lever25a08662010-12-14 14:54:30 +0000678 * 2.2.10. createargs
679 *
680 * struct createargs {
681 * diropargs where;
682 * sattr attributes;
683 * };
684 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000685static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
686 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200687 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000688{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200689 const struct nfs_createargs *args = data;
690
Chuck Lever9f06c712010-12-14 14:59:18 +0000691 encode_diropargs(xdr, args->fh, args->name, args->len);
Trond Myklebustc207db22019-04-24 17:46:48 -0400692 encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
Chuck Lever25a08662010-12-14 14:54:30 +0000693}
694
Chuck Lever9f06c712010-12-14 14:59:18 +0000695static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
696 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200697 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000698{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200699 const struct nfs_removeargs *args = data;
700
Chuck Lever9f06c712010-12-14 14:59:18 +0000701 encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
Chuck Lever25a08662010-12-14 14:54:30 +0000702}
703
704/*
Chuck Lever25a08662010-12-14 14:54:30 +0000705 * 2.2.12. renameargs
706 *
707 * struct renameargs {
708 * diropargs from;
709 * diropargs to;
710 * };
711 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000712static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
713 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200714 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000715{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200716 const struct nfs_renameargs *args = data;
Chuck Lever25a08662010-12-14 14:54:30 +0000717 const struct qstr *old = args->old_name;
718 const struct qstr *new = args->new_name;
Chuck Lever25a08662010-12-14 14:54:30 +0000719
Chuck Lever9f06c712010-12-14 14:59:18 +0000720 encode_diropargs(xdr, args->old_dir, old->name, old->len);
721 encode_diropargs(xdr, args->new_dir, new->name, new->len);
Chuck Lever25a08662010-12-14 14:54:30 +0000722}
723
724/*
Chuck Lever25a08662010-12-14 14:54:30 +0000725 * 2.2.13. linkargs
726 *
727 * struct linkargs {
728 * fhandle from;
729 * diropargs to;
730 * };
731 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000732static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
733 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200734 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000735{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200736 const struct nfs_linkargs *args = data;
737
Chuck Lever9f06c712010-12-14 14:59:18 +0000738 encode_fhandle(xdr, args->fromfh);
739 encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
Chuck Lever25a08662010-12-14 14:54:30 +0000740}
741
742/*
Chuck Lever25a08662010-12-14 14:54:30 +0000743 * 2.2.14. symlinkargs
744 *
745 * struct symlinkargs {
746 * diropargs from;
747 * path to;
748 * sattr attributes;
749 * };
750 */
Chuck Lever9f06c712010-12-14 14:59:18 +0000751static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
752 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200753 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000754{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200755 const struct nfs_symlinkargs *args = data;
756
Chuck Lever9f06c712010-12-14 14:59:18 +0000757 encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
758 encode_path(xdr, args->pages, args->pathlen);
Trond Myklebustc207db22019-04-24 17:46:48 -0400759 encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
Chuck Lever25a08662010-12-14 14:54:30 +0000760}
761
762/*
Chuck Lever25a08662010-12-14 14:54:30 +0000763 * 2.2.17. readdirargs
764 *
765 * struct readdirargs {
766 * fhandle dir;
767 * nfscookie cookie;
768 * unsigned count;
769 * };
770 */
771static void encode_readdirargs(struct xdr_stream *xdr,
772 const struct nfs_readdirargs *args)
773{
774 __be32 *p;
775
776 encode_fhandle(xdr, args->fh);
777
778 p = xdr_reserve_space(xdr, 4 + 4);
779 *p++ = cpu_to_be32(args->cookie);
780 *p = cpu_to_be32(args->count);
781}
782
Chuck Lever9f06c712010-12-14 14:59:18 +0000783static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
784 struct xdr_stream *xdr,
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200785 const void *data)
Chuck Lever25a08662010-12-14 14:54:30 +0000786{
Christoph Hellwigfcc85812017-05-08 10:01:49 +0200787 const struct nfs_readdirargs *args = data;
788
Chuck Lever9f06c712010-12-14 14:59:18 +0000789 encode_readdirargs(xdr, args);
Trond Myklebust9ed5af262020-11-21 20:46:18 -0500790 rpc_prepare_reply_pages(req, args->pages, 0, args->count,
791 NFS_readdirres_sz - NFS_pagepad_sz);
Chuck Lever25a08662010-12-14 14:54:30 +0000792}
793
794/*
Chuck Lever661ad422010-12-14 14:55:20 +0000795 * NFSv2 XDR decode functions
796 *
797 * NFSv2 result types are defined in section 2.2 of RFC 1094:
798 * "NFS: Network File System Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Chuck Leverbf269552010-12-14 14:59:29 +0000801static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
Chuck Leverf796f8b2010-12-14 14:55:10 +0000802 void *__unused)
803{
Chuck Leverf796f8b2010-12-14 14:55:10 +0000804 enum nfs_stat status;
805 int error;
806
Chuck Leverbf269552010-12-14 14:59:29 +0000807 error = decode_stat(xdr, &status);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000808 if (unlikely(error))
809 goto out;
810 if (status != NFS_OK)
811 goto out_default;
812out:
813 return error;
814out_default:
815 return nfs_stat_to_errno(status);
816}
817
Chuck Leverbf269552010-12-14 14:59:29 +0000818static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +0200819 void *result)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000820{
Trond Myklebustc207db22019-04-24 17:46:48 -0400821 return decode_attrstat(xdr, result, NULL, rpc_rqst_userns(req));
Chuck Leverf796f8b2010-12-14 14:55:10 +0000822}
823
Chuck Leverbf269552010-12-14 14:59:29 +0000824static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +0200825 void *result)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000826{
Trond Myklebustc207db22019-04-24 17:46:48 -0400827 return decode_diropres(xdr, result, rpc_rqst_userns(req));
Chuck Leverf796f8b2010-12-14 14:55:10 +0000828}
829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000831 * 2.2.6. readlinkres
832 *
833 * union readlinkres switch (stat status) {
834 * case NFS_OK:
835 * path data;
836 * default:
837 * void;
838 * };
839 */
Chuck Leverbf269552010-12-14 14:59:29 +0000840static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
841 struct xdr_stream *xdr, void *__unused)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000842{
Chuck Leverf796f8b2010-12-14 14:55:10 +0000843 enum nfs_stat status;
844 int error;
845
Chuck Leverbf269552010-12-14 14:59:29 +0000846 error = decode_stat(xdr, &status);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000847 if (unlikely(error))
848 goto out;
849 if (status != NFS_OK)
850 goto out_default;
Chuck Leverbf269552010-12-14 14:59:29 +0000851 error = decode_path(xdr);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000852out:
853 return error;
854out_default:
855 return nfs_stat_to_errno(status);
856}
857
858/*
859 * 2.2.7. readres
860 *
861 * union readres switch (stat status) {
862 * case NFS_OK:
863 * fattr attributes;
864 * nfsdata data;
865 * default:
866 * void;
867 * };
868 */
Chuck Leverbf269552010-12-14 14:59:29 +0000869static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +0200870 void *data)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000871{
Christoph Hellwigfc016482017-05-08 15:09:02 +0200872 struct nfs_pgio_res *result = data;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000873 enum nfs_stat status;
874 int error;
875
Chuck Leverbf269552010-12-14 14:59:29 +0000876 error = decode_stat(xdr, &status);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000877 if (unlikely(error))
878 goto out;
Peng Taoaabff4d2014-08-27 10:47:14 +0800879 result->op_status = status;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000880 if (status != NFS_OK)
881 goto out_default;
Trond Myklebustc207db22019-04-24 17:46:48 -0400882 error = decode_fattr(xdr, result->fattr, rpc_rqst_userns(req));
Chuck Leverf796f8b2010-12-14 14:55:10 +0000883 if (unlikely(error))
884 goto out;
Chuck Leverbf269552010-12-14 14:59:29 +0000885 error = decode_nfsdata(xdr, result);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000886out:
887 return error;
888out_default:
889 return nfs_stat_to_errno(status);
890}
891
Chuck Leverbf269552010-12-14 14:59:29 +0000892static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +0200893 void *data)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000894{
Christoph Hellwigfc016482017-05-08 15:09:02 +0200895 struct nfs_pgio_res *result = data;
896
Chuck Leverf796f8b2010-12-14 14:55:10 +0000897 /* All NFSv2 writes are "file sync" writes */
898 result->verf->committed = NFS_FILE_SYNC;
Trond Myklebustc207db22019-04-24 17:46:48 -0400899 return decode_attrstat(xdr, result->fattr, &result->op_status,
900 rpc_rqst_userns(req));
Chuck Leverf796f8b2010-12-14 14:55:10 +0000901}
902
903/**
904 * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
905 * the local page cache.
906 * @xdr: XDR stream where entry resides
907 * @entry: buffer to fill in with entry data
Chuck Leverf796f8b2010-12-14 14:55:10 +0000908 * @plus: boolean indicating whether this should be a readdirplus entry
909 *
Chuck Lever573c4e12010-12-14 14:58:11 +0000910 * Returns zero if successful, otherwise a negative errno value is
911 * returned.
Chuck Leverf796f8b2010-12-14 14:55:10 +0000912 *
913 * This function is not invoked during READDIR reply decoding, but
914 * rather whenever an application invokes the getdents(2) system call
915 * on a directory already in our cache.
916 *
917 * 2.2.17. entry
918 *
919 * struct entry {
920 * unsigned fileid;
921 * filename name;
922 * nfscookie cookie;
923 * entry *nextentry;
924 * };
925 */
Chuck Lever573c4e12010-12-14 14:58:11 +0000926int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -0400927 bool plus)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000928{
929 __be32 *p;
930 int error;
931
932 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500933 if (unlikely(!p))
934 return -EAGAIN;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000935 if (*p++ == xdr_zero) {
936 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500937 if (unlikely(!p))
938 return -EAGAIN;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000939 if (*p++ == xdr_zero)
Chuck Lever573c4e12010-12-14 14:58:11 +0000940 return -EAGAIN;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000941 entry->eof = 1;
Chuck Lever573c4e12010-12-14 14:58:11 +0000942 return -EBADCOOKIE;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000943 }
944
945 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500946 if (unlikely(!p))
947 return -EAGAIN;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000948 entry->ino = be32_to_cpup(p);
949
950 error = decode_filename_inline(xdr, &entry->name, &entry->len);
951 if (unlikely(error))
Chuck Lever573c4e12010-12-14 14:58:11 +0000952 return error;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000953
954 /*
955 * The type (size and byte order) of nfscookie isn't defined in
956 * RFC 1094. This implementation assumes that it's an XDR uint32.
957 */
958 entry->prev_cookie = entry->cookie;
959 p = xdr_inline_decode(xdr, 4);
Chuck Levereb72f482019-02-11 11:24:21 -0500960 if (unlikely(!p))
961 return -EAGAIN;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000962 entry->cookie = be32_to_cpup(p);
963
964 entry->d_type = DT_UNKNOWN;
965
Chuck Lever573c4e12010-12-14 14:58:11 +0000966 return 0;
Chuck Leverf796f8b2010-12-14 14:55:10 +0000967}
968
969/*
970 * 2.2.17. readdirres
971 *
972 * union readdirres switch (stat status) {
973 * case NFS_OK:
974 * struct {
975 * entry *entries;
976 * bool eof;
977 * } readdirok;
978 * default:
979 * void;
980 * };
981 *
982 * Read the directory contents into the page cache, but don't
983 * touch them. The actual decoding is done by nfs2_decode_dirent()
984 * during subsequent nfs_readdir() calls.
985 */
986static int decode_readdirok(struct xdr_stream *xdr)
987{
Trond Myklebust64bd5772012-06-20 22:35:05 -0400988 return xdr_read_pages(xdr, xdr->buf->page_len);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000989}
990
Chuck Leverbf269552010-12-14 14:59:29 +0000991static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
992 struct xdr_stream *xdr, void *__unused)
Chuck Leverf796f8b2010-12-14 14:55:10 +0000993{
Chuck Leverf796f8b2010-12-14 14:55:10 +0000994 enum nfs_stat status;
995 int error;
996
Chuck Leverbf269552010-12-14 14:59:29 +0000997 error = decode_stat(xdr, &status);
Chuck Leverf796f8b2010-12-14 14:55:10 +0000998 if (unlikely(error))
999 goto out;
1000 if (status != NFS_OK)
1001 goto out_default;
Chuck Leverbf269552010-12-14 14:59:29 +00001002 error = decode_readdirok(xdr);
Chuck Leverf796f8b2010-12-14 14:55:10 +00001003out:
1004 return error;
1005out_default:
1006 return nfs_stat_to_errno(status);
1007}
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009/*
Chuck Leverf796f8b2010-12-14 14:55:10 +00001010 * 2.2.18. statfsres
1011 *
1012 * union statfsres (stat status) {
1013 * case NFS_OK:
1014 * struct {
1015 * unsigned tsize;
1016 * unsigned bsize;
1017 * unsigned blocks;
1018 * unsigned bfree;
1019 * unsigned bavail;
1020 * } info;
1021 * default:
1022 * void;
1023 * };
1024 */
1025static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1026{
1027 __be32 *p;
1028
1029 p = xdr_inline_decode(xdr, NFS_info_sz << 2);
Chuck Levereb72f482019-02-11 11:24:21 -05001030 if (unlikely(!p))
1031 return -EIO;
Chuck Leverf796f8b2010-12-14 14:55:10 +00001032 result->tsize = be32_to_cpup(p++);
1033 result->bsize = be32_to_cpup(p++);
1034 result->blocks = be32_to_cpup(p++);
1035 result->bfree = be32_to_cpup(p++);
1036 result->bavail = be32_to_cpup(p);
1037 return 0;
Chuck Leverf796f8b2010-12-14 14:55:10 +00001038}
1039
Chuck Leverbf269552010-12-14 14:59:29 +00001040static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
Christoph Hellwigfc016482017-05-08 15:09:02 +02001041 void *result)
Chuck Leverf796f8b2010-12-14 14:55:10 +00001042{
Chuck Leverf796f8b2010-12-14 14:55:10 +00001043 enum nfs_stat status;
1044 int error;
1045
Chuck Leverbf269552010-12-14 14:59:29 +00001046 error = decode_stat(xdr, &status);
Chuck Leverf796f8b2010-12-14 14:55:10 +00001047 if (unlikely(error))
1048 goto out;
1049 if (status != NFS_OK)
1050 goto out_default;
Chuck Leverbf269552010-12-14 14:59:29 +00001051 error = decode_info(xdr, result);
Chuck Leverf796f8b2010-12-14 14:55:10 +00001052out:
1053 return error;
1054out_default:
1055 return nfs_stat_to_errno(status);
1056}
1057
1058
1059/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 * We need to translate between nfs status return values and
1061 * the local errno values which may not be the same.
1062 */
Chuck Lever85828492010-12-14 14:55:00 +00001063static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 int stat;
1065 int errno;
1066} nfs_errtbl[] = {
1067 { NFS_OK, 0 },
Benny Halevy856dff32008-03-31 17:39:06 +03001068 { NFSERR_PERM, -EPERM },
1069 { NFSERR_NOENT, -ENOENT },
1070 { NFSERR_IO, -errno_NFSERR_IO},
1071 { NFSERR_NXIO, -ENXIO },
1072/* { NFSERR_EAGAIN, -EAGAIN }, */
1073 { NFSERR_ACCES, -EACCES },
1074 { NFSERR_EXIST, -EEXIST },
1075 { NFSERR_XDEV, -EXDEV },
1076 { NFSERR_NODEV, -ENODEV },
1077 { NFSERR_NOTDIR, -ENOTDIR },
1078 { NFSERR_ISDIR, -EISDIR },
1079 { NFSERR_INVAL, -EINVAL },
1080 { NFSERR_FBIG, -EFBIG },
1081 { NFSERR_NOSPC, -ENOSPC },
1082 { NFSERR_ROFS, -EROFS },
1083 { NFSERR_MLINK, -EMLINK },
1084 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
1085 { NFSERR_NOTEMPTY, -ENOTEMPTY },
1086 { NFSERR_DQUOT, -EDQUOT },
1087 { NFSERR_STALE, -ESTALE },
1088 { NFSERR_REMOTE, -EREMOTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089#ifdef EWFLUSH
Benny Halevy856dff32008-03-31 17:39:06 +03001090 { NFSERR_WFLUSH, -EWFLUSH },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091#endif
Benny Halevy856dff32008-03-31 17:39:06 +03001092 { NFSERR_BADHANDLE, -EBADHANDLE },
1093 { NFSERR_NOT_SYNC, -ENOTSYNC },
1094 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
1095 { NFSERR_NOTSUPP, -ENOTSUPP },
1096 { NFSERR_TOOSMALL, -ETOOSMALL },
Trond Myklebustfdcb4572010-02-08 09:32:40 -05001097 { NFSERR_SERVERFAULT, -EREMOTEIO },
Benny Halevy856dff32008-03-31 17:39:06 +03001098 { NFSERR_BADTYPE, -EBADTYPE },
1099 { NFSERR_JUKEBOX, -EJUKEBOX },
1100 { -1, -EIO }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101};
1102
Chuck Lever85828492010-12-14 14:55:00 +00001103/**
1104 * nfs_stat_to_errno - convert an NFS status code to a local errno
1105 * @status: NFS status code to convert
1106 *
1107 * Returns a local errno value, or -EIO if the NFS status code is
1108 * not recognized. This function is used jointly by NFSv2 and NFSv3.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 */
Bryan Schumaker5e7e5a02012-05-10 16:47:18 -04001110static int nfs_stat_to_errno(enum nfs_stat status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111{
1112 int i;
1113
1114 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
Chuck Lever85828492010-12-14 14:55:00 +00001115 if (nfs_errtbl[i].stat == (int)status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return nfs_errtbl[i].errno;
1117 }
Chuck Lever85828492010-12-14 14:55:00 +00001118 dprintk("NFS: Unrecognized nfs status value: %u\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 return nfs_errtbl[i].errno;
1120}
1121
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122#define PROC(proc, argtype, restype, timer) \
1123[NFSPROC_##proc] = { \
1124 .p_proc = NFSPROC_##proc, \
Christoph Hellwigfcc85812017-05-08 10:01:49 +02001125 .p_encode = nfs2_xdr_enc_##argtype, \
Christoph Hellwigfc016482017-05-08 15:09:02 +02001126 .p_decode = nfs2_xdr_dec_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001127 .p_arglen = NFS_##argtype##_sz, \
1128 .p_replen = NFS_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001129 .p_timer = timer, \
1130 .p_statidx = NFSPROC_##proc, \
1131 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 }
Christoph Hellwig511e9362017-05-12 15:36:49 +02001133const struct rpc_procinfo nfs_procedures[] = {
Chuck Lever7d93bd712010-12-14 14:57:42 +00001134 PROC(GETATTR, fhandle, attrstat, 1),
1135 PROC(SETATTR, sattrargs, attrstat, 0),
1136 PROC(LOOKUP, diropargs, diropres, 2),
1137 PROC(READLINK, readlinkargs, readlinkres, 3),
1138 PROC(READ, readargs, readres, 3),
1139 PROC(WRITE, writeargs, writeres, 4),
1140 PROC(CREATE, createargs, diropres, 0),
1141 PROC(REMOVE, removeargs, stat, 0),
1142 PROC(RENAME, renameargs, stat, 0),
1143 PROC(LINK, linkargs, stat, 0),
1144 PROC(SYMLINK, symlinkargs, stat, 0),
1145 PROC(MKDIR, createargs, diropres, 0),
1146 PROC(RMDIR, diropargs, stat, 0),
1147 PROC(READDIR, readdirargs, readdirres, 3),
1148 PROC(STATFS, fhandle, statfsres, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149};
1150
Christoph Hellwigc5518582017-05-08 23:27:10 +02001151static unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
Trond Myklebusta613fa12012-01-20 13:53:56 -05001152const struct rpc_version nfs_version2 = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 .number = 2,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001154 .nrprocs = ARRAY_SIZE(nfs_procedures),
Christoph Hellwigc5518582017-05-08 23:27:10 +02001155 .procs = nfs_procedures,
1156 .counts = nfs_version2_counts,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157};