Blame view

fs/nfs/nfs2xdr.c 26.4 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * linux/fs/nfs/nfs2xdr.c
   *
   * XDR functions to encode/decode NFS RPC arguments and results.
   *
   * Copyright (C) 1992, 1993, 1994  Rick Sladkey
   * Copyright (C) 1996 Olaf Kirch
   * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
   * 		FIFO's need special handling in NFSv2
   */
  
  #include <linux/param.h>
  #include <linux/time.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
23
24
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/in.h>
  #include <linux/pagemap.h>
  #include <linux/proc_fs.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/nfs.h>
  #include <linux/nfs2.h>
  #include <linux/nfs_fs.h>
816724e65   Trond Myklebust   Merge branch 'mas...
25
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  
  #define NFSDBG_FACILITY		NFSDBG_XDR
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  /* Mapping from NFS error code to "errno" error code. */
  #define errno_NFSERR_IO		EIO
  
  /*
   * Declare the space requirements for NFS arguments and replies as
   * number of 32bit-words
   */
  #define NFS_fhandle_sz		(8)
  #define NFS_sattr_sz		(8)
  #define NFS_filename_sz		(1+(NFS2_MAXNAMLEN>>2))
  #define NFS_path_sz		(1+(NFS2_MAXPATHLEN>>2))
  #define NFS_fattr_sz		(17)
  #define NFS_info_sz		(5)
  #define NFS_entry_sz		(NFS_filename_sz+3)
  
  #define NFS_diropargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
45
  #define NFS_removeargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
51
52
  #define NFS_sattrargs_sz	(NFS_fhandle_sz+NFS_sattr_sz)
  #define NFS_readlinkargs_sz	(NFS_fhandle_sz)
  #define NFS_readargs_sz		(NFS_fhandle_sz+3)
  #define NFS_writeargs_sz	(NFS_fhandle_sz+4)
  #define NFS_createargs_sz	(NFS_diropargs_sz+NFS_sattr_sz)
  #define NFS_renameargs_sz	(NFS_diropargs_sz+NFS_diropargs_sz)
  #define NFS_linkargs_sz		(NFS_fhandle_sz+NFS_diropargs_sz)
94a6d7532   Chuck Lever   NFS: Use cached p...
53
  #define NFS_symlinkargs_sz	(NFS_diropargs_sz+1+NFS_sattr_sz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
58
59
60
61
62
63
  #define NFS_readdirargs_sz	(NFS_fhandle_sz+2)
  
  #define NFS_attrstat_sz		(1+NFS_fattr_sz)
  #define NFS_diropres_sz		(1+NFS_fhandle_sz+NFS_fattr_sz)
  #define NFS_readlinkres_sz	(2)
  #define NFS_readres_sz		(1+NFS_fattr_sz+1)
  #define NFS_writeres_sz         (NFS_attrstat_sz)
  #define NFS_stat_sz		(1)
  #define NFS_readdirres_sz	(1)
  #define NFS_statfsres_sz	(1+NFS_info_sz)
5e7e5a0da   Bryan Schumaker   NFS: Create an NF...
64
  static int nfs_stat_to_errno(enum nfs_stat);
25a0866cc   Chuck Lever   NFS: Introduce ne...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  
  /*
   * While encoding arguments, set up the reply buffer in advance to
   * receive reply data directly into the page cache.
   */
  static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
  				 unsigned int base, unsigned int len,
  				 unsigned int bufsize)
  {
  	struct rpc_auth	*auth = req->rq_cred->cr_auth;
  	unsigned int replen;
  
  	replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
  	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
  }
f796f8b3a   Chuck Lever   NFS: Introduce ne...
80
81
82
83
84
85
86
87
88
89
  /*
   * Handle decode buffer overflows out-of-line.
   */
  static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
  {
  	dprintk("NFS: %s prematurely hit the end of our receive buffer. "
  		"Remaining buffer length is %tu words.
  ",
  		func, xdr->end - xdr->p);
  }
25a0866cc   Chuck Lever   NFS: Introduce ne...
90

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
92
93
94
95
96
97
98
99
100
101
102
   * Encode/decode NFSv2 basic data types
   *
   * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
   * "NFS: Network File System Protocol Specification".
   *
   * Not all basic data types have their own encoding and decoding
   * functions.  For run-time efficiency, some data types are encoded
   * or decoded inline.
   */
  
  /*
f796f8b3a   Chuck Lever   NFS: Introduce ne...
103
104
   *	typedef opaque	nfsdata<>;
   */
9137bdf3d   Anna Schumaker   NFS: Create a com...
105
  static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
106
107
  {
  	u32 recvd, count;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
108
109
110
111
112
113
  	__be32 *p;
  
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	count = be32_to_cpup(p);
64bd577ea   Trond Myklebust   NFS: Let xdr_read...
114
  	recvd = xdr_read_pages(xdr, count);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
115
116
117
  	if (unlikely(count > recvd))
  		goto out_cheating;
  out:
f796f8b3a   Chuck Lever   NFS: Introduce ne...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  	result->eof = 0;	/* NFSv2 does not pass EOF flag on the wire. */
  	result->count = count;
  	return count;
  out_cheating:
  	dprintk("NFS: server cheating in read result: "
  		"count %u > recvd %u
  ", count, recvd);
  	count = recvd;
  	goto out;
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
  
  /*
   *	enum stat {
   *		NFS_OK = 0,
   *		NFSERR_PERM = 1,
   *		NFSERR_NOENT = 2,
   *		NFSERR_IO = 5,
   *		NFSERR_NXIO = 6,
   *		NFSERR_ACCES = 13,
   *		NFSERR_EXIST = 17,
   *		NFSERR_NODEV = 19,
   *		NFSERR_NOTDIR = 20,
   *		NFSERR_ISDIR = 21,
   *		NFSERR_FBIG = 27,
   *		NFSERR_NOSPC = 28,
   *		NFSERR_ROFS = 30,
   *		NFSERR_NAMETOOLONG = 63,
   *		NFSERR_NOTEMPTY = 66,
   *		NFSERR_DQUOT = 69,
   *		NFSERR_STALE = 70,
   *		NFSERR_WFLUSH = 99
   *	};
   */
  static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
  {
  	__be32 *p;
  
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	*status = be32_to_cpup(p);
  	return 0;
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
  
  /*
5f96e5e31   Chuck Lever   NFS: Move and upd...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
   * 2.3.2.  ftype
   *
   *	enum ftype {
   *		NFNON = 0,
   *		NFREG = 1,
   *		NFDIR = 2,
   *		NFBLK = 3,
   *		NFCHR = 4,
   *		NFLNK = 5
   *	};
   *
   */
  static __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
  {
  	*type = be32_to_cpup(p++);
  	if (unlikely(*type > NF2FIFO))
  		*type = NFBAD;
  	return p;
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
190
191
192
193
194
195
196
   * 2.3.3.  fhandle
   *
   *	typedef opaque fhandle[FHSIZE];
   */
  static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
  {
  	__be32 *p;
25a0866cc   Chuck Lever   NFS: Introduce ne...
197
198
199
  	p = xdr_reserve_space(xdr, NFS2_FHSIZE);
  	memcpy(p, fh->data, NFS2_FHSIZE);
  }
f796f8b3a   Chuck Lever   NFS: Introduce ne...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
  {
  	__be32 *p;
  
  	p = xdr_inline_decode(xdr, NFS2_FHSIZE);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	fh->size = NFS2_FHSIZE;
  	memcpy(fh->data, p, NFS2_FHSIZE);
  	return 0;
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
25a0866cc   Chuck Lever   NFS: Introduce ne...
214
  /*
282ac2a57   Chuck Lever   NFS: Update xdr_e...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
   * 2.3.4.  timeval
   *
   *	struct timeval {
   *		unsigned int seconds;
   *		unsigned int useconds;
   *	};
   */
  static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep)
  {
  	*p++ = cpu_to_be32(timep->tv_sec);
  	if (timep->tv_nsec != 0)
  		*p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
  	else
  		*p++ = cpu_to_be32(0);
  	return p;
  }
  
  /*
   * Passing the invalid value useconds=1000000 is a Sun convention for
   * "set to current server time".  It's needed to make permissions checks
   * for the "touch" program across v2 mounts to Solaris and Irix servers
   * work correctly.  See description of sattr in section 6.1 of "NFS
   * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
   */
  static __be32 *xdr_encode_current_server_time(__be32 *p,
  					      const struct timespec *timep)
  {
  	*p++ = cpu_to_be32(timep->tv_sec);
  	*p++ = cpu_to_be32(1000000);
  	return p;
  }
5f96e5e31   Chuck Lever   NFS: Move and upd...
246
247
248
249
250
251
  static __be32 *xdr_decode_time(__be32 *p, struct timespec *timep)
  {
  	timep->tv_sec = be32_to_cpup(p++);
  	timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
  	return p;
  }
282ac2a57   Chuck Lever   NFS: Update xdr_e...
252
  /*
f796f8b3a   Chuck Lever   NFS: Introduce ne...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
   * 2.3.5.  fattr
   *
   *	struct fattr {
   *		ftype		type;
   *		unsigned int	mode;
   *		unsigned int	nlink;
   *		unsigned int	uid;
   *		unsigned int	gid;
   *		unsigned int	size;
   *		unsigned int	blocksize;
   *		unsigned int	rdev;
   *		unsigned int	blocks;
   *		unsigned int	fsid;
   *		unsigned int	fileid;
   *		timeval		atime;
   *		timeval		mtime;
   *		timeval		ctime;
   *	};
   *
   */
  static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
  {
5f96e5e31   Chuck Lever   NFS: Move and upd...
275
  	u32 rdev, type;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
276
277
278
279
280
  	__be32 *p;
  
  	p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
  	if (unlikely(p == NULL))
  		goto out_overflow;
5f96e5e31   Chuck Lever   NFS: Move and upd...
281
282
283
284
285
286
287
  
  	fattr->valid |= NFS_ATTR_FATTR_V2;
  
  	p = xdr_decode_ftype(p, &type);
  
  	fattr->mode = be32_to_cpup(p++);
  	fattr->nlink = be32_to_cpup(p++);
cfa0898d4   Eric W. Biederman   nfs: Convert nfs2...
288
289
290
291
292
293
294
  	fattr->uid = make_kuid(&init_user_ns, be32_to_cpup(p++));
  	if (!uid_valid(fattr->uid))
  		goto out_uid;
  	fattr->gid = make_kgid(&init_user_ns, be32_to_cpup(p++));
  	if (!gid_valid(fattr->gid))
  		goto out_gid;
  		
5f96e5e31   Chuck Lever   NFS: Move and upd...
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  	fattr->size = be32_to_cpup(p++);
  	fattr->du.nfs2.blocksize = be32_to_cpup(p++);
  
  	rdev = be32_to_cpup(p++);
  	fattr->rdev = new_decode_dev(rdev);
  	if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
  		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
  		fattr->rdev = 0;
  	}
  
  	fattr->du.nfs2.blocks = be32_to_cpup(p++);
  	fattr->fsid.major = be32_to_cpup(p++);
  	fattr->fsid.minor = 0;
  	fattr->fileid = be32_to_cpup(p++);
  
  	p = xdr_decode_time(p, &fattr->atime);
  	p = xdr_decode_time(p, &fattr->mtime);
  	xdr_decode_time(p, &fattr->ctime);
3a1556e86   Trond Myklebust   NFSv2/v3: Simulat...
313
  	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
314
  	return 0;
cfa0898d4   Eric W. Biederman   nfs: Convert nfs2...
315
316
317
318
319
320
321
322
  out_uid:
  	dprintk("NFS: returned invalid uid
  ");
  	return -EINVAL;
  out_gid:
  	dprintk("NFS: returned invalid gid
  ");
  	return -EINVAL;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
323
324
325
326
327
328
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
   * 2.3.6.  sattr
   *
   *	struct sattr {
   *		unsigned int	mode;
   *		unsigned int	uid;
   *		unsigned int	gid;
   *		unsigned int	size;
   *		timeval		atime;
   *		timeval		mtime;
   *	};
   */
  
  #define NFS2_SATTR_NOT_SET	(0xffffffff)
  
  static __be32 *xdr_time_not_set(__be32 *p)
  {
  	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
  	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
  	return p;
  }
  
  static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
  {
  	__be32 *p;
  
  	p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
  
  	if (attr->ia_valid & ATTR_MODE)
  		*p++ = cpu_to_be32(attr->ia_mode);
  	else
  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
  	if (attr->ia_valid & ATTR_UID)
cfa0898d4   Eric W. Biederman   nfs: Convert nfs2...
361
  		*p++ = cpu_to_be32(from_kuid(&init_user_ns, attr->ia_uid));
25a0866cc   Chuck Lever   NFS: Introduce ne...
362
363
364
  	else
  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
  	if (attr->ia_valid & ATTR_GID)
cfa0898d4   Eric W. Biederman   nfs: Convert nfs2...
365
  		*p++ = cpu_to_be32(from_kgid(&init_user_ns, attr->ia_gid));
25a0866cc   Chuck Lever   NFS: Introduce ne...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
  	else
  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
  	if (attr->ia_valid & ATTR_SIZE)
  		*p++ = cpu_to_be32((u32)attr->ia_size);
  	else
  		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
  
  	if (attr->ia_valid & ATTR_ATIME_SET)
  		p = xdr_encode_time(p, &attr->ia_atime);
  	else if (attr->ia_valid & ATTR_ATIME)
  		p = xdr_encode_current_server_time(p, &attr->ia_atime);
  	else
  		p = xdr_time_not_set(p);
  	if (attr->ia_valid & ATTR_MTIME_SET)
  		xdr_encode_time(p, &attr->ia_mtime);
  	else if (attr->ia_valid & ATTR_MTIME)
  		xdr_encode_current_server_time(p, &attr->ia_mtime);
  	else
  		xdr_time_not_set(p);
  }
  
  /*
   * 2.3.7.  filename
   *
   *	typedef string filename<MAXNAMLEN>;
   */
  static void encode_filename(struct xdr_stream *xdr,
  			    const char *name, u32 length)
  {
  	__be32 *p;
7fc388460   Trond Myklebust   NFS: Remove asser...
396
  	WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
25a0866cc   Chuck Lever   NFS: Introduce ne...
397
398
399
  	p = xdr_reserve_space(xdr, 4 + length);
  	xdr_encode_opaque(p, name, length);
  }
f796f8b3a   Chuck Lever   NFS: Introduce ne...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  static int decode_filename_inline(struct xdr_stream *xdr,
  				  const char **name, u32 *length)
  {
  	__be32 *p;
  	u32 count;
  
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	count = be32_to_cpup(p);
  	if (count > NFS3_MAXNAMLEN)
  		goto out_nametoolong;
  	p = xdr_inline_decode(xdr, count);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	*name = (const char *)p;
  	*length = count;
  	return 0;
  out_nametoolong:
  	dprintk("NFS: returned filename too long: %u
  ", count);
  	return -ENAMETOOLONG;
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
25a0866cc   Chuck Lever   NFS: Introduce ne...
426
427
428
429
430
431
432
433
  /*
   * 2.3.8.  path
   *
   *	typedef string path<MAXPATHLEN>;
   */
  static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
  {
  	__be32 *p;
25a0866cc   Chuck Lever   NFS: Introduce ne...
434
435
436
437
  	p = xdr_reserve_space(xdr, 4);
  	*p = cpu_to_be32(length);
  	xdr_write_pages(xdr, pages, 0, length);
  }
f796f8b3a   Chuck Lever   NFS: Introduce ne...
438
439
440
  static int decode_path(struct xdr_stream *xdr)
  {
  	u32 length, recvd;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
441
442
443
444
445
446
447
448
  	__be32 *p;
  
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	length = be32_to_cpup(p);
  	if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
  		goto out_size;
64bd577ea   Trond Myklebust   NFS: Let xdr_read...
449
  	recvd = xdr_read_pages(xdr, length);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
450
451
  	if (unlikely(length > recvd))
  		goto out_cheating;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  	xdr_terminate_string(xdr->buf, length);
  	return 0;
  out_size:
  	dprintk("NFS: returned pathname too long: %u
  ", length);
  	return -ENAMETOOLONG;
  out_cheating:
  	dprintk("NFS: server cheating in pathname result: "
  		"length %u > received %u
  ", length, recvd);
  	return -EIO;
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
  
  /*
   * 2.3.9.  attrstat
   *
   *	union attrstat switch (stat status) {
   *	case NFS_OK:
   *		fattr attributes;
   *	default:
   *		void;
   *	};
   */
aabff4ddc   Peng Tao   nfs: save server ...
478
479
  static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
  			   __u32 *op_status)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
480
481
482
483
484
485
486
  {
  	enum nfs_stat status;
  	int error;
  
  	error = decode_stat(xdr, &status);
  	if (unlikely(error))
  		goto out;
aabff4ddc   Peng Tao   nfs: save server ...
487
488
  	if (op_status)
  		*op_status = status;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
489
490
491
492
493
494
495
496
  	if (status != NFS_OK)
  		goto out_default;
  	error = decode_fattr(xdr, result);
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
25a0866cc   Chuck Lever   NFS: Introduce ne...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  /*
   * 2.3.10.  diropargs
   *
   *	struct diropargs {
   *		fhandle  dir;
   *		filename name;
   *	};
   */
  static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
  			     const char *name, u32 length)
  {
  	encode_fhandle(xdr, fh);
  	encode_filename(xdr, name, length);
  }
f796f8b3a   Chuck Lever   NFS: Introduce ne...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  /*
   * 2.3.11.  diropres
   *
   *	union diropres switch (stat status) {
   *	case NFS_OK:
   *		struct {
   *			fhandle file;
   *			fattr   attributes;
   *		} diropok;
   *	default:
   *		void;
   *	};
   */
  static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
  {
  	int error;
  
  	error = decode_fhandle(xdr, result->fh);
  	if (unlikely(error))
  		goto out;
  	error = decode_fattr(xdr, result->fattr);
  out:
  	return error;
  }
  
  static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
  {
  	enum nfs_stat status;
  	int error;
  
  	error = decode_stat(xdr, &status);
  	if (unlikely(error))
  		goto out;
  	if (status != NFS_OK)
  		goto out_default;
  	error = decode_diropok(xdr, result);
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
25a0866cc   Chuck Lever   NFS: Introduce ne...
552
553
  
  /*
2d70f533e   Chuck Lever   NFS: Remove old N...
554
555
556
557
   * NFSv2 XDR encode functions
   *
   * NFSv2 argument types are defined in section 2.2 of RFC 1094:
   * "NFS: Network File System Protocol Specification".
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
560
561
  static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
  				 struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
562
  				 const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
563
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
564
  	const struct nfs_fh *fh = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
565
  	encode_fhandle(xdr, fh);
25a0866cc   Chuck Lever   NFS: Introduce ne...
566
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
568
569
570
571
572
573
574
   * 2.2.3.  sattrargs
   *
   *	struct sattrargs {
   *		fhandle file;
   *		sattr attributes;
   *	};
   */
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
575
576
  static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
  				   struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
577
  				   const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
578
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
579
  	const struct nfs_sattrargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
580
581
  	encode_fhandle(xdr, args->fh);
  	encode_sattr(xdr, args->sattr);
25a0866cc   Chuck Lever   NFS: Introduce ne...
582
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
583
584
  static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
  				   struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
585
  				   const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
586
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
587
  	const struct nfs_diropargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
588
  	encode_diropargs(xdr, args->fh, args->name, args->len);
25a0866cc   Chuck Lever   NFS: Introduce ne...
589
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
590
591
  static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
  				      struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
592
  				      const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
593
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
594
  	const struct nfs_readlinkargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
595
  	encode_fhandle(xdr, args->fh);
25a0866cc   Chuck Lever   NFS: Introduce ne...
596
597
  	prepare_reply_buffer(req, args->pages, args->pgbase,
  					args->pglen, NFS_readlinkres_sz);
25a0866cc   Chuck Lever   NFS: Introduce ne...
598
  }
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
599
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
600
601
602
603
604
605
606
607
608
609
   * 2.2.7.  readargs
   *
   *	struct readargs {
   *		fhandle file;
   *		unsigned offset;
   *		unsigned count;
   *		unsigned totalcount;
   *	};
   */
  static void encode_readargs(struct xdr_stream *xdr,
3c6b899c4   Anna Schumaker   NFS: Create a com...
610
  			    const struct nfs_pgio_args *args)
25a0866cc   Chuck Lever   NFS: Introduce ne...
611
612
613
614
615
616
617
618
619
620
621
622
  {
  	u32 offset = args->offset;
  	u32 count = args->count;
  	__be32 *p;
  
  	encode_fhandle(xdr, args->fh);
  
  	p = xdr_reserve_space(xdr, 4 + 4 + 4);
  	*p++ = cpu_to_be32(offset);
  	*p++ = cpu_to_be32(count);
  	*p = cpu_to_be32(count);
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
623
624
  static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
  				  struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
625
  				  const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
626
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
627
  	const struct nfs_pgio_args *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
628
  	encode_readargs(xdr, args);
25a0866cc   Chuck Lever   NFS: Introduce ne...
629
630
631
  	prepare_reply_buffer(req, args->pages, args->pgbase,
  					args->count, NFS_readres_sz);
  	req->rq_rcv_buf.flags |= XDRBUF_READ;
25a0866cc   Chuck Lever   NFS: Introduce ne...
632
633
634
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
635
636
637
638
639
640
641
642
643
644
645
   * 2.2.9.  writeargs
   *
   *	struct writeargs {
   *		fhandle file;
   *		unsigned beginoffset;
   *		unsigned offset;
   *		unsigned totalcount;
   *		nfsdata data;
   *	};
   */
  static void encode_writeargs(struct xdr_stream *xdr,
3c6b899c4   Anna Schumaker   NFS: Create a com...
646
  			     const struct nfs_pgio_args *args)
25a0866cc   Chuck Lever   NFS: Introduce ne...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  {
  	u32 offset = args->offset;
  	u32 count = args->count;
  	__be32 *p;
  
  	encode_fhandle(xdr, args->fh);
  
  	p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
  	*p++ = cpu_to_be32(offset);
  	*p++ = cpu_to_be32(offset);
  	*p++ = cpu_to_be32(count);
  
  	/* nfsdata */
  	*p = cpu_to_be32(count);
  	xdr_write_pages(xdr, args->pages, args->pgbase, count);
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
663
664
  static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
  				   struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
665
  				   const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
666
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
667
  	const struct nfs_pgio_args *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
668
669
  	encode_writeargs(xdr, args);
  	xdr->buf->flags |= XDRBUF_WRITE;
25a0866cc   Chuck Lever   NFS: Introduce ne...
670
671
672
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
673
674
675
676
677
678
679
   * 2.2.10.  createargs
   *
   *	struct createargs {
   *		diropargs where;
   *		sattr attributes;
   *	};
   */
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
680
681
  static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
  				    struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
682
  				    const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
683
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
684
  	const struct nfs_createargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
685
686
  	encode_diropargs(xdr, args->fh, args->name, args->len);
  	encode_sattr(xdr, args->sattr);
25a0866cc   Chuck Lever   NFS: Introduce ne...
687
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
688
689
  static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
  				    struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
690
  				    const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
691
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
692
  	const struct nfs_removeargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
693
  	encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
25a0866cc   Chuck Lever   NFS: Introduce ne...
694
695
696
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
697
698
699
700
701
702
703
   * 2.2.12.  renameargs
   *
   *	struct renameargs {
   *		diropargs from;
   *		diropargs to;
   *	};
   */
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
704
705
  static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
  				    struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
706
  				    const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
707
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
708
  	const struct nfs_renameargs *args = data;
25a0866cc   Chuck Lever   NFS: Introduce ne...
709
710
  	const struct qstr *old = args->old_name;
  	const struct qstr *new = args->new_name;
25a0866cc   Chuck Lever   NFS: Introduce ne...
711

9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
712
713
  	encode_diropargs(xdr, args->old_dir, old->name, old->len);
  	encode_diropargs(xdr, args->new_dir, new->name, new->len);
25a0866cc   Chuck Lever   NFS: Introduce ne...
714
715
716
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
717
718
719
720
721
722
723
   * 2.2.13.  linkargs
   *
   *	struct linkargs {
   *		fhandle from;
   *		diropargs to;
   *	};
   */
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
724
725
  static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
  				  struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
726
  				  const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
727
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
728
  	const struct nfs_linkargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
729
730
  	encode_fhandle(xdr, args->fromfh);
  	encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
25a0866cc   Chuck Lever   NFS: Introduce ne...
731
732
733
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
734
735
736
737
738
739
740
741
   * 2.2.14.  symlinkargs
   *
   *	struct symlinkargs {
   *		diropargs from;
   *		path to;
   *		sattr attributes;
   *	};
   */
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
742
743
  static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
  				     struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
744
  				     const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
745
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
746
  	const struct nfs_symlinkargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
747
748
749
  	encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
  	encode_path(xdr, args->pages, args->pathlen);
  	encode_sattr(xdr, args->sattr);
25a0866cc   Chuck Lever   NFS: Introduce ne...
750
751
752
  }
  
  /*
25a0866cc   Chuck Lever   NFS: Introduce ne...
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
   * 2.2.17.  readdirargs
   *
   *	struct readdirargs {
   *		fhandle dir;
   *		nfscookie cookie;
   *		unsigned count;
   *	};
   */
  static void encode_readdirargs(struct xdr_stream *xdr,
  			       const struct nfs_readdirargs *args)
  {
  	__be32 *p;
  
  	encode_fhandle(xdr, args->fh);
  
  	p = xdr_reserve_space(xdr, 4 + 4);
  	*p++ = cpu_to_be32(args->cookie);
  	*p = cpu_to_be32(args->count);
  }
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
772
773
  static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
  				     struct xdr_stream *xdr,
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
774
  				     const void *data)
25a0866cc   Chuck Lever   NFS: Introduce ne...
775
  {
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
776
  	const struct nfs_readdirargs *args = data;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
777
  	encode_readdirargs(xdr, args);
25a0866cc   Chuck Lever   NFS: Introduce ne...
778
779
  	prepare_reply_buffer(req, args->pages, 0,
  					args->count, NFS_readdirres_sz);
25a0866cc   Chuck Lever   NFS: Introduce ne...
780
781
782
  }
  
  /*
661ad4239   Chuck Lever   NFS: Replace old ...
783
784
785
786
   * NFSv2 XDR decode functions
   *
   * NFSv2 result types are defined in section 2.2 of RFC 1094:
   * "NFS: Network File System Protocol Specification".
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788

bf2695516   Chuck Lever   SUNRPC: New xdr_s...
789
  static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
f796f8b3a   Chuck Lever   NFS: Introduce ne...
790
791
  			     void *__unused)
  {
f796f8b3a   Chuck Lever   NFS: Introduce ne...
792
793
  	enum nfs_stat status;
  	int error;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
794
  	error = decode_stat(xdr, &status);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
795
796
797
798
799
800
801
802
803
  	if (unlikely(error))
  		goto out;
  	if (status != NFS_OK)
  		goto out_default;
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
804
  static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
fc016483e   Christoph Hellwig   nfs: fix decoder ...
805
  				 void *result)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
806
  {
aabff4ddc   Peng Tao   nfs: save server ...
807
  	return decode_attrstat(xdr, result, NULL);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
808
  }
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
809
  static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
fc016483e   Christoph Hellwig   nfs: fix decoder ...
810
  				 void *result)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
811
  {
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
812
  	return decode_diropres(xdr, result);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
813
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  /*
f796f8b3a   Chuck Lever   NFS: Introduce ne...
815
816
817
818
819
820
821
822
823
   * 2.2.6.  readlinkres
   *
   *	union readlinkres switch (stat status) {
   *	case NFS_OK:
   *		path data;
   *	default:
   *		void;
   *	};
   */
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
824
825
  static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
  				    struct xdr_stream *xdr, void *__unused)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
826
  {
f796f8b3a   Chuck Lever   NFS: Introduce ne...
827
828
  	enum nfs_stat status;
  	int error;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
829
  	error = decode_stat(xdr, &status);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
830
831
832
833
  	if (unlikely(error))
  		goto out;
  	if (status != NFS_OK)
  		goto out_default;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
834
  	error = decode_path(xdr);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
  
  /*
   * 2.2.7.  readres
   *
   *	union readres switch (stat status) {
   *	case NFS_OK:
   *		fattr attributes;
   *		nfsdata data;
   *	default:
   *		void;
   *	};
   */
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
852
  static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
fc016483e   Christoph Hellwig   nfs: fix decoder ...
853
  				void *data)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
854
  {
fc016483e   Christoph Hellwig   nfs: fix decoder ...
855
  	struct nfs_pgio_res *result = data;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
856
857
  	enum nfs_stat status;
  	int error;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
858
  	error = decode_stat(xdr, &status);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
859
860
  	if (unlikely(error))
  		goto out;
aabff4ddc   Peng Tao   nfs: save server ...
861
  	result->op_status = status;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
862
863
  	if (status != NFS_OK)
  		goto out_default;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
864
  	error = decode_fattr(xdr, result->fattr);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
865
866
  	if (unlikely(error))
  		goto out;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
867
  	error = decode_nfsdata(xdr, result);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
868
869
870
871
872
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
873
  static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
fc016483e   Christoph Hellwig   nfs: fix decoder ...
874
  				 void *data)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
875
  {
fc016483e   Christoph Hellwig   nfs: fix decoder ...
876
  	struct nfs_pgio_res *result = data;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
877
878
  	/* All NFSv2 writes are "file sync" writes */
  	result->verf->committed = NFS_FILE_SYNC;
aabff4ddc   Peng Tao   nfs: save server ...
879
  	return decode_attrstat(xdr, result->fattr, &result->op_status);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
880
881
882
883
884
885
886
  }
  
  /**
   * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
   *                      the local page cache.
   * @xdr: XDR stream where entry resides
   * @entry: buffer to fill in with entry data
f796f8b3a   Chuck Lever   NFS: Introduce ne...
887
888
   * @plus: boolean indicating whether this should be a readdirplus entry
   *
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
889
890
   * Returns zero if successful, otherwise a negative errno value is
   * returned.
f796f8b3a   Chuck Lever   NFS: Introduce ne...
891
892
893
894
895
896
897
898
899
900
901
902
903
904
   *
   * This function is not invoked during READDIR reply decoding, but
   * rather whenever an application invokes the getdents(2) system call
   * on a directory already in our cache.
   *
   * 2.2.17.  entry
   *
   *	struct entry {
   *		unsigned	fileid;
   *		filename	name;
   *		nfscookie	cookie;
   *		entry		*nextentry;
   *	};
   */
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
905
  int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
a7a3b1e97   Benjamin Coddington   NFS: convert flag...
906
  		       bool plus)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
907
908
909
910
911
912
913
914
915
916
917
918
  {
  	__be32 *p;
  	int error;
  
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	if (*p++ == xdr_zero) {
  		p = xdr_inline_decode(xdr, 4);
  		if (unlikely(p == NULL))
  			goto out_overflow;
  		if (*p++ == xdr_zero)
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
919
  			return -EAGAIN;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
920
  		entry->eof = 1;
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
921
  		return -EBADCOOKIE;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
922
923
924
925
926
927
928
929
930
  	}
  
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	entry->ino = be32_to_cpup(p);
  
  	error = decode_filename_inline(xdr, &entry->name, &entry->len);
  	if (unlikely(error))
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
931
  		return error;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
932
933
934
935
936
937
938
939
940
941
942
943
  
  	/*
  	 * The type (size and byte order) of nfscookie isn't defined in
  	 * RFC 1094.  This implementation assumes that it's an XDR uint32.
  	 */
  	entry->prev_cookie = entry->cookie;
  	p = xdr_inline_decode(xdr, 4);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	entry->cookie = be32_to_cpup(p);
  
  	entry->d_type = DT_UNKNOWN;
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
944
  	return 0;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
945
946
947
  
  out_overflow:
  	print_overflow_msg(__func__, xdr);
573c4e1ef   Chuck Lever   NFS: Simplify ->d...
948
  	return -EAGAIN;
f796f8b3a   Chuck Lever   NFS: Introduce ne...
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
  }
  
  /*
   * 2.2.17.  readdirres
   *
   *	union readdirres switch (stat status) {
   *	case NFS_OK:
   *		struct {
   *			entry *entries;
   *			bool eof;
   *		} readdirok;
   *	default:
   *		void;
   *	};
   *
   * Read the directory contents into the page cache, but don't
   * touch them.  The actual decoding is done by nfs2_decode_dirent()
   * during subsequent nfs_readdir() calls.
   */
  static int decode_readdirok(struct xdr_stream *xdr)
  {
64bd577ea   Trond Myklebust   NFS: Let xdr_read...
970
  	return xdr_read_pages(xdr, xdr->buf->page_len);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
971
  }
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
972
973
  static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
  				   struct xdr_stream *xdr, void *__unused)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
974
  {
f796f8b3a   Chuck Lever   NFS: Introduce ne...
975
976
  	enum nfs_stat status;
  	int error;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
977
  	error = decode_stat(xdr, &status);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
978
979
980
981
  	if (unlikely(error))
  		goto out;
  	if (status != NFS_OK)
  		goto out_default;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
982
  	error = decode_readdirok(xdr);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
983
984
985
986
987
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
  /*
f796f8b3a   Chuck Lever   NFS: Introduce ne...
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
   * 2.2.18.  statfsres
   *
   *	union statfsres (stat status) {
   *	case NFS_OK:
   *		struct {
   *			unsigned tsize;
   *			unsigned bsize;
   *			unsigned blocks;
   *			unsigned bfree;
   *			unsigned bavail;
   *		} info;
   *	default:
   *		void;
   *	};
   */
  static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
  {
  	__be32 *p;
  
  	p = xdr_inline_decode(xdr, NFS_info_sz << 2);
  	if (unlikely(p == NULL))
  		goto out_overflow;
  	result->tsize  = be32_to_cpup(p++);
  	result->bsize  = be32_to_cpup(p++);
  	result->blocks = be32_to_cpup(p++);
  	result->bfree  = be32_to_cpup(p++);
  	result->bavail = be32_to_cpup(p);
  	return 0;
  out_overflow:
  	print_overflow_msg(__func__, xdr);
  	return -EIO;
  }
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
1021
  static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
fc016483e   Christoph Hellwig   nfs: fix decoder ...
1022
  				  void *result)
f796f8b3a   Chuck Lever   NFS: Introduce ne...
1023
  {
f796f8b3a   Chuck Lever   NFS: Introduce ne...
1024
1025
  	enum nfs_stat status;
  	int error;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
1026
  	error = decode_stat(xdr, &status);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
1027
1028
1029
1030
  	if (unlikely(error))
  		goto out;
  	if (status != NFS_OK)
  		goto out_default;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
1031
  	error = decode_info(xdr, result);
f796f8b3a   Chuck Lever   NFS: Introduce ne...
1032
1033
1034
1035
1036
1037
1038
1039
  out:
  	return error;
  out_default:
  	return nfs_stat_to_errno(status);
  }
  
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1040
1041
1042
   * We need to translate between nfs status return values and
   * the local errno values which may not be the same.
   */
858284932   Chuck Lever   NFS: Use the "nfs...
1043
  static const struct {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
1045
1046
1047
  	int stat;
  	int errno;
  } nfs_errtbl[] = {
  	{ NFS_OK,		0		},
856dff3d3   Benny Halevy   nfs: return negat...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
  	{ NFSERR_PERM,		-EPERM		},
  	{ NFSERR_NOENT,		-ENOENT		},
  	{ NFSERR_IO,		-errno_NFSERR_IO},
  	{ NFSERR_NXIO,		-ENXIO		},
  /*	{ NFSERR_EAGAIN,	-EAGAIN		}, */
  	{ NFSERR_ACCES,		-EACCES		},
  	{ NFSERR_EXIST,		-EEXIST		},
  	{ NFSERR_XDEV,		-EXDEV		},
  	{ NFSERR_NODEV,		-ENODEV		},
  	{ NFSERR_NOTDIR,	-ENOTDIR	},
  	{ NFSERR_ISDIR,		-EISDIR		},
  	{ NFSERR_INVAL,		-EINVAL		},
  	{ NFSERR_FBIG,		-EFBIG		},
  	{ NFSERR_NOSPC,		-ENOSPC		},
  	{ NFSERR_ROFS,		-EROFS		},
  	{ NFSERR_MLINK,		-EMLINK		},
  	{ NFSERR_NAMETOOLONG,	-ENAMETOOLONG	},
  	{ NFSERR_NOTEMPTY,	-ENOTEMPTY	},
  	{ NFSERR_DQUOT,		-EDQUOT		},
  	{ NFSERR_STALE,		-ESTALE		},
  	{ NFSERR_REMOTE,	-EREMOTE	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1069
  #ifdef EWFLUSH
856dff3d3   Benny Halevy   nfs: return negat...
1070
  	{ NFSERR_WFLUSH,	-EWFLUSH	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1071
  #endif
856dff3d3   Benny Halevy   nfs: return negat...
1072
1073
1074
1075
1076
  	{ NFSERR_BADHANDLE,	-EBADHANDLE	},
  	{ NFSERR_NOT_SYNC,	-ENOTSYNC	},
  	{ NFSERR_BAD_COOKIE,	-EBADCOOKIE	},
  	{ NFSERR_NOTSUPP,	-ENOTSUPP	},
  	{ NFSERR_TOOSMALL,	-ETOOSMALL	},
fdcb45777   Trond Myklebust   NFS: Fix the mapp...
1077
  	{ NFSERR_SERVERFAULT,	-EREMOTEIO	},
856dff3d3   Benny Halevy   nfs: return negat...
1078
1079
1080
  	{ NFSERR_BADTYPE,	-EBADTYPE	},
  	{ NFSERR_JUKEBOX,	-EJUKEBOX	},
  	{ -1,			-EIO		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
  };
858284932   Chuck Lever   NFS: Use the "nfs...
1082
1083
1084
1085
1086
1087
  /**
   * nfs_stat_to_errno - convert an NFS status code to a local errno
   * @status: NFS status code to convert
   *
   * Returns a local errno value, or -EIO if the NFS status code is
   * not recognized.  This function is used jointly by NFSv2 and NFSv3.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
   */
5e7e5a0da   Bryan Schumaker   NFS: Create an NF...
1089
  static int nfs_stat_to_errno(enum nfs_stat status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
1091
1092
1093
  {
  	int i;
  
  	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
858284932   Chuck Lever   NFS: Use the "nfs...
1094
  		if (nfs_errtbl[i].stat == (int)status)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
  			return nfs_errtbl[i].errno;
  	}
858284932   Chuck Lever   NFS: Use the "nfs...
1097
1098
  	dprintk("NFS: Unrecognized nfs status value: %u
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1099
1100
  	return nfs_errtbl[i].errno;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
1103
  #define PROC(proc, argtype, restype, timer)				\
  [NFSPROC_##proc] = {							\
  	.p_proc	    =  NFSPROC_##proc,					\
fcc85819e   Christoph Hellwig   nfs: fix encoder ...
1104
  	.p_encode   =  nfs2_xdr_enc_##argtype,				\
fc016483e   Christoph Hellwig   nfs: fix decoder ...
1105
  	.p_decode   =  nfs2_xdr_dec_##restype,				\
2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
1106
1107
  	.p_arglen   =  NFS_##argtype##_sz,				\
  	.p_replen   =  NFS_##restype##_sz,				\
cc0175c1d   Chuck Lever   SUNRPC: display h...
1108
1109
1110
  	.p_timer    =  timer,						\
  	.p_statidx  =  NFSPROC_##proc,					\
  	.p_name     =  #proc,						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1111
  	}
511e936bf   Christoph Hellwig   sunrpc: mark all ...
1112
  const struct rpc_procinfo nfs_procedures[] = {
7d93bd71c   Chuck Lever   NFS: Repair white...
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  	PROC(GETATTR,	fhandle,	attrstat,	1),
  	PROC(SETATTR,	sattrargs,	attrstat,	0),
  	PROC(LOOKUP,	diropargs,	diropres,	2),
  	PROC(READLINK,	readlinkargs,	readlinkres,	3),
  	PROC(READ,	readargs,	readres,	3),
  	PROC(WRITE,	writeargs,	writeres,	4),
  	PROC(CREATE,	createargs,	diropres,	0),
  	PROC(REMOVE,	removeargs,	stat,		0),
  	PROC(RENAME,	renameargs,	stat,		0),
  	PROC(LINK,	linkargs,	stat,		0),
  	PROC(SYMLINK,	symlinkargs,	stat,		0),
  	PROC(MKDIR,	createargs,	diropres,	0),
  	PROC(RMDIR,	diropargs,	stat,		0),
  	PROC(READDIR,	readdirargs,	readdirres,	3),
  	PROC(STATFS,	fhandle,	statfsres,	0),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
  };
c551858a8   Christoph Hellwig   sunrpc: move p_co...
1129
  static unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
a613fa168   Trond Myklebust   SUNRPC: constify ...
1130
  const struct rpc_version nfs_version2 = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
  	.number			= 2,
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
1132
  	.nrprocs		= ARRAY_SIZE(nfs_procedures),
c551858a8   Christoph Hellwig   sunrpc: move p_co...
1133
1134
  	.procs			= nfs_procedures,
  	.counts			= nfs_version2_counts,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135
  };