blob: 869e2151a2b1a7372f1158123eaffa390d773b8e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/nfs/nfs2xdr.c
3 *
4 * XDR functions to encode/decode NFS RPC arguments and results.
5 *
6 * Copyright (C) 1992, 1993, 1994 Rick Sladkey
7 * Copyright (C) 1996 Olaf Kirch
8 * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
9 * FIFO's need special handling in NFSv2
10 */
11
12#include <linux/param.h>
13#include <linux/time.h>
14#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/in.h>
18#include <linux/pagemap.h>
19#include <linux/proc_fs.h>
20#include <linux/sunrpc/clnt.h>
21#include <linux/nfs.h>
22#include <linux/nfs2.h>
23#include <linux/nfs_fs.h>
Trond Myklebust816724e2006-06-24 08:41:41 -040024#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#define NFSDBG_FACILITY NFSDBG_XDR
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Linus Torvalds1da177e2005-04-16 15:20:36 -070028/* Mapping from NFS error code to "errno" error code. */
29#define errno_NFSERR_IO EIO
30
31/*
32 * Declare the space requirements for NFS arguments and replies as
33 * number of 32bit-words
34 */
35#define NFS_fhandle_sz (8)
36#define NFS_sattr_sz (8)
37#define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
38#define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
39#define NFS_fattr_sz (17)
40#define NFS_info_sz (5)
41#define NFS_entry_sz (NFS_filename_sz+3)
42
43#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040044#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
46#define NFS_readlinkargs_sz (NFS_fhandle_sz)
47#define NFS_readargs_sz (NFS_fhandle_sz+3)
48#define NFS_writeargs_sz (NFS_fhandle_sz+4)
49#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
50#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
51#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
Chuck Lever94a6d752006-08-22 20:06:23 -040052#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define NFS_readdirargs_sz (NFS_fhandle_sz+2)
54
55#define NFS_attrstat_sz (1+NFS_fattr_sz)
56#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
57#define NFS_readlinkres_sz (2)
58#define NFS_readres_sz (1+NFS_fattr_sz+1)
59#define NFS_writeres_sz (NFS_attrstat_sz)
60#define NFS_stat_sz (1)
61#define NFS_readdirres_sz (1)
62#define NFS_statfsres_sz (1+NFS_info_sz)
63
Chuck Lever25a08662010-12-14 14:54:30 +000064
65/*
66 * While encoding arguments, set up the reply buffer in advance to
67 * receive reply data directly into the page cache.
68 */
69static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
70 unsigned int base, unsigned int len,
71 unsigned int bufsize)
72{
73 struct rpc_auth *auth = req->rq_cred->cr_auth;
74 unsigned int replen;
75
76 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
77 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
78}
79
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*
82 * Common NFS XDR functions as inlines
83 */
Al Viro9d787a72006-10-19 23:28:47 -070084static inline __be32 *
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040085xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
87 memcpy(p, fhandle->data, NFS2_FHSIZE);
88 return p + XDR_QUADLEN(NFS2_FHSIZE);
89}
90
Al Viro9d787a72006-10-19 23:28:47 -070091static inline __be32 *
92xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 /* NFSv2 handles have a fixed length */
95 fhandle->size = NFS2_FHSIZE;
96 memcpy(fhandle->data, p, NFS2_FHSIZE);
97 return p + XDR_QUADLEN(NFS2_FHSIZE);
98}
99
Al Viro9d787a72006-10-19 23:28:47 -0700100static inline __be32*
Chuck Lever25a08662010-12-14 14:54:30 +0000101xdr_encode_time(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 *p++ = htonl(timep->tv_sec);
104 /* Convert nanoseconds into microseconds */
105 *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
106 return p;
107}
108
Al Viro9d787a72006-10-19 23:28:47 -0700109static inline __be32*
Chuck Lever25a08662010-12-14 14:54:30 +0000110xdr_encode_current_server_time(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
112 /*
113 * Passing the invalid value useconds=1000000 is a
114 * Sun convention for "set to current server time".
115 * It's needed to make permissions checks for the
116 * "touch" program across v2 mounts to Solaris and
117 * Irix boxes work correctly. See description of
118 * sattr in section 6.1 of "NFS Illustrated" by
119 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
120 */
121 *p++ = htonl(timep->tv_sec);
122 *p++ = htonl(1000000);
123 return p;
124}
125
Al Viro9d787a72006-10-19 23:28:47 -0700126static inline __be32*
127xdr_decode_time(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
129 timep->tv_sec = ntohl(*p++);
130 /* Convert microseconds into nanoseconds */
131 timep->tv_nsec = ntohl(*p++) * 1000;
132 return p;
133}
134
Al Viro9d787a72006-10-19 23:28:47 -0700135static __be32 *
136xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Trond Myklebustbca79472009-03-11 14:10:26 -0400138 u32 rdev, type;
139 type = ntohl(*p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 fattr->mode = ntohl(*p++);
141 fattr->nlink = ntohl(*p++);
142 fattr->uid = ntohl(*p++);
143 fattr->gid = ntohl(*p++);
144 fattr->size = ntohl(*p++);
145 fattr->du.nfs2.blocksize = ntohl(*p++);
146 rdev = ntohl(*p++);
147 fattr->du.nfs2.blocks = ntohl(*p++);
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400148 fattr->fsid.major = ntohl(*p++);
149 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 fattr->fileid = ntohl(*p++);
151 p = xdr_decode_time(p, &fattr->atime);
152 p = xdr_decode_time(p, &fattr->mtime);
153 p = xdr_decode_time(p, &fattr->ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400154 fattr->valid |= NFS_ATTR_FATTR_V2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 fattr->rdev = new_decode_dev(rdev);
Trond Myklebustbca79472009-03-11 14:10:26 -0400156 if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
158 fattr->rdev = 0;
159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 return p;
161}
162
Al Viro9d787a72006-10-19 23:28:47 -0700163static inline __be32 *
164xdr_encode_sattr(__be32 *p, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
Al Viro9d787a72006-10-19 23:28:47 -0700166 const __be32 not_set = __constant_htonl(0xFFFFFFFF);
Trond Myklebusteadb8c12006-01-03 09:55:54 +0100167
168 *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
169 *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
170 *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
171 *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 if (attr->ia_valid & ATTR_ATIME_SET) {
174 p = xdr_encode_time(p, &attr->ia_atime);
175 } else if (attr->ia_valid & ATTR_ATIME) {
176 p = xdr_encode_current_server_time(p, &attr->ia_atime);
177 } else {
Trond Myklebusteadb8c12006-01-03 09:55:54 +0100178 *p++ = not_set;
179 *p++ = not_set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181
182 if (attr->ia_valid & ATTR_MTIME_SET) {
183 p = xdr_encode_time(p, &attr->ia_mtime);
184 } else if (attr->ia_valid & ATTR_MTIME) {
185 p = xdr_encode_current_server_time(p, &attr->ia_mtime);
186 } else {
Trond Myklebusteadb8c12006-01-03 09:55:54 +0100187 *p++ = not_set;
188 *p++ = not_set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
190 return p;
191}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193/*
Chuck Lever25a08662010-12-14 14:54:30 +0000194 * Encode/decode NFSv2 basic data types
195 *
196 * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
197 * "NFS: Network File System Protocol Specification".
198 *
199 * Not all basic data types have their own encoding and decoding
200 * functions. For run-time efficiency, some data types are encoded
201 * or decoded inline.
202 */
203
204/*
205 * 2.3.3. fhandle
206 *
207 * typedef opaque fhandle[FHSIZE];
208 */
209static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
210{
211 __be32 *p;
212
213 BUG_ON(fh->size != NFS2_FHSIZE);
214 p = xdr_reserve_space(xdr, NFS2_FHSIZE);
215 memcpy(p, fh->data, NFS2_FHSIZE);
216}
217
218/*
219 * 2.3.6. sattr
220 *
221 * struct sattr {
222 * unsigned int mode;
223 * unsigned int uid;
224 * unsigned int gid;
225 * unsigned int size;
226 * timeval atime;
227 * timeval mtime;
228 * };
229 */
230
231#define NFS2_SATTR_NOT_SET (0xffffffff)
232
233static __be32 *xdr_time_not_set(__be32 *p)
234{
235 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
236 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
237 return p;
238}
239
240static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
241{
242 __be32 *p;
243
244 p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
245
246 if (attr->ia_valid & ATTR_MODE)
247 *p++ = cpu_to_be32(attr->ia_mode);
248 else
249 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
250 if (attr->ia_valid & ATTR_UID)
251 *p++ = cpu_to_be32(attr->ia_uid);
252 else
253 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
254 if (attr->ia_valid & ATTR_GID)
255 *p++ = cpu_to_be32(attr->ia_gid);
256 else
257 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
258 if (attr->ia_valid & ATTR_SIZE)
259 *p++ = cpu_to_be32((u32)attr->ia_size);
260 else
261 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
262
263 if (attr->ia_valid & ATTR_ATIME_SET)
264 p = xdr_encode_time(p, &attr->ia_atime);
265 else if (attr->ia_valid & ATTR_ATIME)
266 p = xdr_encode_current_server_time(p, &attr->ia_atime);
267 else
268 p = xdr_time_not_set(p);
269 if (attr->ia_valid & ATTR_MTIME_SET)
270 xdr_encode_time(p, &attr->ia_mtime);
271 else if (attr->ia_valid & ATTR_MTIME)
272 xdr_encode_current_server_time(p, &attr->ia_mtime);
273 else
274 xdr_time_not_set(p);
275}
276
277/*
278 * 2.3.7. filename
279 *
280 * typedef string filename<MAXNAMLEN>;
281 */
282static void encode_filename(struct xdr_stream *xdr,
283 const char *name, u32 length)
284{
285 __be32 *p;
286
287 BUG_ON(length > NFS2_MAXNAMLEN);
288 p = xdr_reserve_space(xdr, 4 + length);
289 xdr_encode_opaque(p, name, length);
290}
291
292/*
293 * 2.3.8. path
294 *
295 * typedef string path<MAXPATHLEN>;
296 */
297static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
298{
299 __be32 *p;
300
301 BUG_ON(length > NFS2_MAXPATHLEN);
302 p = xdr_reserve_space(xdr, 4);
303 *p = cpu_to_be32(length);
304 xdr_write_pages(xdr, pages, 0, length);
305}
306
307/*
308 * 2.3.10. diropargs
309 *
310 * struct diropargs {
311 * fhandle dir;
312 * filename name;
313 * };
314 */
315static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
316 const char *name, u32 length)
317{
318 encode_fhandle(xdr, fh);
319 encode_filename(xdr, name, length);
320}
321
322
323/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 * NFS encode functions
325 */
326/*
327 * Encode file handle argument
328 * GETATTR, READLINK, STATFS
329 */
330static int
Al Viro9d787a72006-10-19 23:28:47 -0700331nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 p = xdr_encode_fhandle(p, fh);
334 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
335 return 0;
336}
337
Chuck Lever25a08662010-12-14 14:54:30 +0000338static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p,
339 const struct nfs_fh *fh)
340{
341 struct xdr_stream xdr;
342
343 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
344 encode_fhandle(&xdr, fh);
345 return 0;
346}
347
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348/*
349 * Encode SETATTR arguments
350 */
351static int
Al Viro9d787a72006-10-19 23:28:47 -0700352nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 p = xdr_encode_fhandle(p, args->fh);
355 p = xdr_encode_sattr(p, args->sattr);
356 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
357 return 0;
358}
359
360/*
Chuck Lever25a08662010-12-14 14:54:30 +0000361 * 2.2.3. sattrargs
362 *
363 * struct sattrargs {
364 * fhandle file;
365 * sattr attributes;
366 * };
367 */
368static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p,
369 const struct nfs_sattrargs *args)
370{
371 struct xdr_stream xdr;
372
373 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
374 encode_fhandle(&xdr, args->fh);
375 encode_sattr(&xdr, args->sattr);
376 return 0;
377}
378
379/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 * Encode directory ops argument
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400381 * LOOKUP, RMDIR
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 */
383static int
Al Viro9d787a72006-10-19 23:28:47 -0700384nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386 p = xdr_encode_fhandle(p, args->fh);
387 p = xdr_encode_array(p, args->name, args->len);
388 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
389 return 0;
390}
391
Chuck Lever25a08662010-12-14 14:54:30 +0000392static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p,
393 const struct nfs_diropargs *args)
394{
395 struct xdr_stream xdr;
396
397 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
398 encode_diropargs(&xdr, args->fh, args->name, args->len);
399 return 0;
400}
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402/*
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400403 * Encode REMOVE argument
404 */
405static int
406nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
407{
408 p = xdr_encode_fhandle(p, args->fh);
409 p = xdr_encode_array(p, args->name.name, args->name.len);
410 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
411 return 0;
412}
413
Chuck Lever25a08662010-12-14 14:54:30 +0000414static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p,
415 const struct nfs_readlinkargs *args)
416{
417 struct xdr_stream xdr;
418
419 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
420 encode_fhandle(&xdr, args->fh);
421 prepare_reply_buffer(req, args->pages, args->pgbase,
422 args->pglen, NFS_readlinkres_sz);
423 return 0;
424}
425
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400426/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 * Arguments to a READ call. Since we read data directly into the page
428 * cache, we also set up the reply iovec here so that iov[1] points
429 * exactly to the page we want to fetch.
430 */
431static int
Al Viro9d787a72006-10-19 23:28:47 -0700432nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400434 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 unsigned int replen;
436 u32 offset = (u32)args->offset;
437 u32 count = args->count;
438
439 p = xdr_encode_fhandle(p, args->fh);
440 *p++ = htonl(offset);
441 *p++ = htonl(count);
442 *p++ = htonl(count);
443 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
444
445 /* Inline the page array */
446 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
447 xdr_inline_pages(&req->rq_rcv_buf, replen,
448 args->pages, args->pgbase, count);
\"Talpey, Thomas\4f22ccc2007-09-10 13:44:58 -0400449 req->rq_rcv_buf.flags |= XDRBUF_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return 0;
451}
452
453/*
Chuck Lever25a08662010-12-14 14:54:30 +0000454 * 2.2.7. readargs
455 *
456 * struct readargs {
457 * fhandle file;
458 * unsigned offset;
459 * unsigned count;
460 * unsigned totalcount;
461 * };
462 */
463static void encode_readargs(struct xdr_stream *xdr,
464 const struct nfs_readargs *args)
465{
466 u32 offset = args->offset;
467 u32 count = args->count;
468 __be32 *p;
469
470 encode_fhandle(xdr, args->fh);
471
472 p = xdr_reserve_space(xdr, 4 + 4 + 4);
473 *p++ = cpu_to_be32(offset);
474 *p++ = cpu_to_be32(count);
475 *p = cpu_to_be32(count);
476}
477
478static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p,
479 const struct nfs_readargs *args)
480{
481 struct xdr_stream xdr;
482
483 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
484 encode_readargs(&xdr, args);
485 prepare_reply_buffer(req, args->pages, args->pgbase,
486 args->count, NFS_readres_sz);
487 req->rq_rcv_buf.flags |= XDRBUF_READ;
488 return 0;
489}
490
491/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 * Decode READ reply
493 */
494static int
Al Viro9d787a72006-10-19 23:28:47 -0700495nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
497 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400498 size_t hdrlen;
499 u32 count, recvd;
500 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300503 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 p = xdr_decode_fattr(p, res->fattr);
505
506 count = ntohl(*p++);
507 res->eof = 0;
508 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
509 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400510 dprintk("NFS: READ reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400511 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return -errno_NFSERR_IO;
513 } else if (iov->iov_len != hdrlen) {
514 dprintk("NFS: READ header is short. iovec will be shifted.\n");
515 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
516 }
517
518 recvd = req->rq_rcv_buf.len - hdrlen;
519 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400520 dprintk("NFS: server cheating in read reply: "
Chuck Lever6232dbb2007-10-26 13:31:52 -0400521 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 count = recvd;
523 }
524
Chuck Lever6232dbb2007-10-26 13:31:52 -0400525 dprintk("RPC: readres OK count %u\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (count < res->count)
527 res->count = count;
528
529 return count;
530}
531
532
533/*
534 * Write arguments. Splice the buffer to be written into the iovec.
535 */
536static int
Al Viro9d787a72006-10-19 23:28:47 -0700537nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
539 struct xdr_buf *sndbuf = &req->rq_snd_buf;
540 u32 offset = (u32)args->offset;
541 u32 count = args->count;
542
543 p = xdr_encode_fhandle(p, args->fh);
544 *p++ = htonl(offset);
545 *p++ = htonl(offset);
546 *p++ = htonl(count);
547 *p++ = htonl(count);
548 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
549
550 /* Copy the page array */
551 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
\"Talpey, Thomas\4f22ccc2007-09-10 13:44:58 -0400552 sndbuf->flags |= XDRBUF_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 return 0;
554}
555
556/*
Chuck Lever25a08662010-12-14 14:54:30 +0000557 * 2.2.9. writeargs
558 *
559 * struct writeargs {
560 * fhandle file;
561 * unsigned beginoffset;
562 * unsigned offset;
563 * unsigned totalcount;
564 * nfsdata data;
565 * };
566 */
567static void encode_writeargs(struct xdr_stream *xdr,
568 const struct nfs_writeargs *args)
569{
570 u32 offset = args->offset;
571 u32 count = args->count;
572 __be32 *p;
573
574 encode_fhandle(xdr, args->fh);
575
576 p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
577 *p++ = cpu_to_be32(offset);
578 *p++ = cpu_to_be32(offset);
579 *p++ = cpu_to_be32(count);
580
581 /* nfsdata */
582 *p = cpu_to_be32(count);
583 xdr_write_pages(xdr, args->pages, args->pgbase, count);
584}
585
586static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p,
587 const struct nfs_writeargs *args)
588{
589 struct xdr_stream xdr;
590
591 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
592 encode_writeargs(&xdr, args);
593 xdr.buf->flags |= XDRBUF_WRITE;
594 return 0;
595}
596
597/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 * Encode create arguments
599 * CREATE, MKDIR
600 */
601static int
Al Viro9d787a72006-10-19 23:28:47 -0700602nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
604 p = xdr_encode_fhandle(p, args->fh);
605 p = xdr_encode_array(p, args->name, args->len);
606 p = xdr_encode_sattr(p, args->sattr);
607 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
608 return 0;
609}
610
611/*
Chuck Lever25a08662010-12-14 14:54:30 +0000612 * 2.2.10. createargs
613 *
614 * struct createargs {
615 * diropargs where;
616 * sattr attributes;
617 * };
618 */
619static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p,
620 const struct nfs_createargs *args)
621{
622 struct xdr_stream xdr;
623
624 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
625 encode_diropargs(&xdr, args->fh, args->name, args->len);
626 encode_sattr(&xdr, args->sattr);
627 return 0;
628}
629
630static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p,
631 const struct nfs_removeargs *args)
632{
633 struct xdr_stream xdr;
634
635 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
636 encode_diropargs(&xdr, args->fh, args->name.name, args->name.len);
637 return 0;
638}
639
640/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 * Encode RENAME arguments
642 */
643static int
Al Viro9d787a72006-10-19 23:28:47 -0700644nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
Jeff Layton920769f2010-09-17 17:30:25 -0400646 p = xdr_encode_fhandle(p, args->old_dir);
647 p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
648 p = xdr_encode_fhandle(p, args->new_dir);
649 p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
651 return 0;
652}
653
654/*
Chuck Lever25a08662010-12-14 14:54:30 +0000655 * 2.2.12. renameargs
656 *
657 * struct renameargs {
658 * diropargs from;
659 * diropargs to;
660 * };
661 */
662static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p,
663 const struct nfs_renameargs *args)
664{
665 const struct qstr *old = args->old_name;
666 const struct qstr *new = args->new_name;
667 struct xdr_stream xdr;
668
669 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
670 encode_diropargs(&xdr, args->old_dir, old->name, old->len);
671 encode_diropargs(&xdr, args->new_dir, new->name, new->len);
672 return 0;
673}
674
675/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 * Encode LINK arguments
677 */
678static int
Al Viro9d787a72006-10-19 23:28:47 -0700679nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 p = xdr_encode_fhandle(p, args->fromfh);
682 p = xdr_encode_fhandle(p, args->tofh);
683 p = xdr_encode_array(p, args->toname, args->tolen);
684 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
685 return 0;
686}
687
688/*
Chuck Lever25a08662010-12-14 14:54:30 +0000689 * 2.2.13. linkargs
690 *
691 * struct linkargs {
692 * fhandle from;
693 * diropargs to;
694 * };
695 */
696static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p,
697 const struct nfs_linkargs *args)
698{
699 struct xdr_stream xdr;
700
701 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
702 encode_fhandle(&xdr, args->fromfh);
703 encode_diropargs(&xdr, args->tofh, args->toname, args->tolen);
704 return 0;
705}
706
707/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 * Encode SYMLINK arguments
709 */
710static int
Al Viro9d787a72006-10-19 23:28:47 -0700711nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712{
Chuck Lever94a6d752006-08-22 20:06:23 -0400713 struct xdr_buf *sndbuf = &req->rq_snd_buf;
714 size_t pad;
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 p = xdr_encode_fhandle(p, args->fromfh);
717 p = xdr_encode_array(p, args->fromname, args->fromlen);
Chuck Lever94a6d752006-08-22 20:06:23 -0400718 *p++ = htonl(args->pathlen);
719 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
720
721 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
722
723 /*
724 * xdr_encode_pages may have added a few bytes to ensure the
725 * pathname ends on a 4-byte boundary. Start encoding the
726 * attributes after the pad bytes.
727 */
728 pad = sndbuf->tail->iov_len;
729 if (pad > 0)
730 p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 p = xdr_encode_sattr(p, args->sattr);
Chuck Lever94a6d752006-08-22 20:06:23 -0400732 sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return 0;
734}
735
736/*
Chuck Lever25a08662010-12-14 14:54:30 +0000737 * 2.2.14. symlinkargs
738 *
739 * struct symlinkargs {
740 * diropargs from;
741 * path to;
742 * sattr attributes;
743 * };
744 */
745static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p,
746 const struct nfs_symlinkargs *args)
747{
748 struct xdr_stream xdr;
749
750 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
751 encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen);
752 encode_path(&xdr, args->pages, args->pathlen);
753 encode_sattr(&xdr, args->sattr);
754 return 0;
755}
756
757/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 * Encode arguments to readdir call
759 */
760static int
Al Viro9d787a72006-10-19 23:28:47 -0700761nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400763 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 unsigned int replen;
765 u32 count = args->count;
766
767 p = xdr_encode_fhandle(p, args->fh);
768 *p++ = htonl(args->cookie);
769 *p++ = htonl(count); /* see above */
770 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
771
772 /* Inline the page array */
773 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
774 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
775 return 0;
776}
777
778/*
Chuck Lever25a08662010-12-14 14:54:30 +0000779 * 2.2.17. readdirargs
780 *
781 * struct readdirargs {
782 * fhandle dir;
783 * nfscookie cookie;
784 * unsigned count;
785 * };
786 */
787static void encode_readdirargs(struct xdr_stream *xdr,
788 const struct nfs_readdirargs *args)
789{
790 __be32 *p;
791
792 encode_fhandle(xdr, args->fh);
793
794 p = xdr_reserve_space(xdr, 4 + 4);
795 *p++ = cpu_to_be32(args->cookie);
796 *p = cpu_to_be32(args->count);
797}
798
799static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p,
800 const struct nfs_readdirargs *args)
801{
802 struct xdr_stream xdr;
803
804 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
805 encode_readdirargs(&xdr, args);
806 prepare_reply_buffer(req, args->pages, 0,
807 args->count, NFS_readdirres_sz);
808 return 0;
809}
810
811/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 * Decode the result of a readdir call.
813 * We're not really decoding anymore, we just leave the buffer untouched
814 * and only check that it is syntactically correct.
815 * The real decoding happens in nfs_decode_entry below, called directly
816 * from nfs_readdir for each entry.
817 */
818static int
Al Viro9d787a72006-10-19 23:28:47 -0700819nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
821 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
822 struct kvec *iov = rcvbuf->head;
823 struct page **page;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400824 size_t hdrlen;
825 unsigned int pglen, recvd;
Trond Myklebustac396122010-11-15 20:26:22 -0500826 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
828 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300829 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
831 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
832 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400833 dprintk("NFS: READDIR reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400834 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return -errno_NFSERR_IO;
836 } else if (iov->iov_len != hdrlen) {
837 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
838 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
839 }
840
841 pglen = rcvbuf->page_len;
842 recvd = rcvbuf->len - hdrlen;
843 if (pglen > recvd)
844 pglen = recvd;
845 page = rcvbuf->pages;
Trond Myklebustac396122010-11-15 20:26:22 -0500846 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847}
848
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400849static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850{
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400851 dprintk("nfs: %s: prematurely hit end of receive buffer. "
852 "Remaining buffer length is %tu words.\n",
853 func, xdr->end - xdr->p);
854}
855
856__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -0400857nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400858{
859 __be32 *p;
860 p = xdr_inline_decode(xdr, 4);
861 if (unlikely(!p))
862 goto out_overflow;
863 if (!ntohl(*p++)) {
864 p = xdr_inline_decode(xdr, 4);
865 if (unlikely(!p))
866 goto out_overflow;
867 if (!ntohl(*p++))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 return ERR_PTR(-EAGAIN);
869 entry->eof = 1;
870 return ERR_PTR(-EBADCOOKIE);
871 }
872
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400873 p = xdr_inline_decode(xdr, 8);
874 if (unlikely(!p))
875 goto out_overflow;
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 entry->ino = ntohl(*p++);
878 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400879
880 p = xdr_inline_decode(xdr, entry->len + 4);
881 if (unlikely(!p))
882 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 entry->name = (const char *) p;
884 p += XDR_QUADLEN(entry->len);
885 entry->prev_cookie = entry->cookie;
886 entry->cookie = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400887
Trond Myklebust0b26a0b2010-11-20 14:26:44 -0500888 entry->d_type = DT_UNKNOWN;
889
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400890 p = xdr_inline_peek(xdr, 8);
891 if (p != NULL)
892 entry->eof = !p[0] && p[1];
893 else
894 entry->eof = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400897
898out_overflow:
899 print_overflow_msg(__func__, xdr);
Trond Myklebust463a3762010-11-20 12:22:20 -0500900 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901}
902
903/*
904 * NFS XDR decode functions
905 */
906/*
907 * Decode simple status reply
908 */
909static int
Al Viro9d787a72006-10-19 23:28:47 -0700910nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
912 int status;
913
914 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +0300915 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 return status;
917}
918
919/*
920 * Decode attrstat reply
921 * GETATTR, SETATTR, WRITE
922 */
923static int
Al Viro9d787a72006-10-19 23:28:47 -0700924nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
926 int status;
927
928 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300929 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 xdr_decode_fattr(p, fattr);
931 return 0;
932}
933
934/*
935 * Decode diropres reply
936 * LOOKUP, CREATE, MKDIR
937 */
938static int
Al Viro9d787a72006-10-19 23:28:47 -0700939nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
941 int status;
942
943 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300944 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 p = xdr_decode_fhandle(p, res->fh);
946 xdr_decode_fattr(p, res->fattr);
947 return 0;
948}
949
950/*
951 * Encode READLINK args
952 */
953static int
Al Viro9d787a72006-10-19 23:28:47 -0700954nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400956 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 unsigned int replen;
958
959 p = xdr_encode_fhandle(p, args->fh);
960 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
961
962 /* Inline the page array */
963 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
964 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
965 return 0;
966}
967
968/*
969 * Decode READLINK reply
970 */
971static int
Al Viro9d787a72006-10-19 23:28:47 -0700972nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
975 struct kvec *iov = rcvbuf->head;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400976 size_t hdrlen;
977 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 int status;
979
980 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300981 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 /* Convert length of symlink */
983 len = ntohl(*p++);
Chuck Lever6232dbb2007-10-26 13:31:52 -0400984 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400985 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 return -ENAMETOOLONG;
987 }
988 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
989 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400990 dprintk("NFS: READLINK reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400991 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 return -errno_NFSERR_IO;
993 } else if (iov->iov_len != hdrlen) {
994 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
995 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
996 }
997 recvd = req->rq_rcv_buf.len - hdrlen;
998 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400999 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 "count %u > recvd %u\n", len, recvd);
1001 return -EIO;
1002 }
1003
Chuck Leverb4687da2010-09-21 16:55:48 -04001004 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return 0;
1006}
1007
1008/*
1009 * Decode WRITE reply
1010 */
1011static int
Al Viro9d787a72006-10-19 23:28:47 -07001012nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013{
1014 res->verf->committed = NFS_FILE_SYNC;
1015 return nfs_xdr_attrstat(req, p, res->fattr);
1016}
1017
1018/*
1019 * Decode STATFS reply
1020 */
1021static int
Al Viro9d787a72006-10-19 23:28:47 -07001022nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023{
1024 int status;
1025
1026 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001027 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
1029 res->tsize = ntohl(*p++);
1030 res->bsize = ntohl(*p++);
1031 res->blocks = ntohl(*p++);
1032 res->bfree = ntohl(*p++);
1033 res->bavail = ntohl(*p++);
1034 return 0;
1035}
1036
1037/*
1038 * We need to translate between nfs status return values and
1039 * the local errno values which may not be the same.
1040 */
1041static struct {
1042 int stat;
1043 int errno;
1044} nfs_errtbl[] = {
1045 { NFS_OK, 0 },
Benny Halevy856dff32008-03-31 17:39:06 +03001046 { NFSERR_PERM, -EPERM },
1047 { NFSERR_NOENT, -ENOENT },
1048 { NFSERR_IO, -errno_NFSERR_IO},
1049 { NFSERR_NXIO, -ENXIO },
1050/* { NFSERR_EAGAIN, -EAGAIN }, */
1051 { NFSERR_ACCES, -EACCES },
1052 { NFSERR_EXIST, -EEXIST },
1053 { NFSERR_XDEV, -EXDEV },
1054 { NFSERR_NODEV, -ENODEV },
1055 { NFSERR_NOTDIR, -ENOTDIR },
1056 { NFSERR_ISDIR, -EISDIR },
1057 { NFSERR_INVAL, -EINVAL },
1058 { NFSERR_FBIG, -EFBIG },
1059 { NFSERR_NOSPC, -ENOSPC },
1060 { NFSERR_ROFS, -EROFS },
1061 { NFSERR_MLINK, -EMLINK },
1062 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
1063 { NFSERR_NOTEMPTY, -ENOTEMPTY },
1064 { NFSERR_DQUOT, -EDQUOT },
1065 { NFSERR_STALE, -ESTALE },
1066 { NFSERR_REMOTE, -EREMOTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067#ifdef EWFLUSH
Benny Halevy856dff32008-03-31 17:39:06 +03001068 { NFSERR_WFLUSH, -EWFLUSH },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069#endif
Benny Halevy856dff32008-03-31 17:39:06 +03001070 { NFSERR_BADHANDLE, -EBADHANDLE },
1071 { NFSERR_NOT_SYNC, -ENOTSYNC },
1072 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
1073 { NFSERR_NOTSUPP, -ENOTSUPP },
1074 { NFSERR_TOOSMALL, -ETOOSMALL },
Trond Myklebustfdcb4572010-02-08 09:32:40 -05001075 { NFSERR_SERVERFAULT, -EREMOTEIO },
Benny Halevy856dff32008-03-31 17:39:06 +03001076 { NFSERR_BADTYPE, -EBADTYPE },
1077 { NFSERR_JUKEBOX, -EJUKEBOX },
1078 { -1, -EIO }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079};
1080
1081/*
1082 * Convert an NFS error code to a local one.
1083 * This one is used jointly by NFSv2 and NFSv3.
1084 */
1085int
1086nfs_stat_to_errno(int stat)
1087{
1088 int i;
1089
1090 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
1091 if (nfs_errtbl[i].stat == stat)
1092 return nfs_errtbl[i].errno;
1093 }
Chuck Leverfe82a182007-09-11 18:01:10 -04001094 dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return nfs_errtbl[i].errno;
1096}
1097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098#define PROC(proc, argtype, restype, timer) \
1099[NFSPROC_##proc] = { \
1100 .p_proc = NFSPROC_##proc, \
Chuck Lever25a08662010-12-14 14:54:30 +00001101 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001103 .p_arglen = NFS_##argtype##_sz, \
1104 .p_replen = NFS_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001105 .p_timer = timer, \
1106 .p_statidx = NFSPROC_##proc, \
1107 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
1109struct rpc_procinfo nfs_procedures[] = {
1110 PROC(GETATTR, fhandle, attrstat, 1),
1111 PROC(SETATTR, sattrargs, attrstat, 0),
1112 PROC(LOOKUP, diropargs, diropres, 2),
1113 PROC(READLINK, readlinkargs, readlinkres, 3),
1114 PROC(READ, readargs, readres, 3),
1115 PROC(WRITE, writeargs, writeres, 4),
1116 PROC(CREATE, createargs, diropres, 0),
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001117 PROC(REMOVE, removeargs, stat, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 PROC(RENAME, renameargs, stat, 0),
1119 PROC(LINK, linkargs, stat, 0),
1120 PROC(SYMLINK, symlinkargs, stat, 0),
1121 PROC(MKDIR, createargs, diropres, 0),
1122 PROC(RMDIR, diropargs, stat, 0),
1123 PROC(READDIR, readdirargs, readdirres, 3),
1124 PROC(STATFS, fhandle, statfsres, 0),
1125};
1126
1127struct rpc_version nfs_version2 = {
1128 .number = 2,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001129 .nrprocs = ARRAY_SIZE(nfs_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 .procs = nfs_procedures
1131};