File: /usr/src/linux/fs/nfs/nfs3xdr.c

1     /*
2      * linux/fs/nfs/nfs3xdr.c
3      *
4      * XDR functions to encode/decode NFSv3 RPC arguments and results.
5      *
6      * Copyright (C) 1996, 1997 Olaf Kirch
7      */
8     
9     #include <linux/param.h>
10     #include <linux/sched.h>
11     #include <linux/mm.h>
12     #include <linux/slab.h>
13     #include <linux/utsname.h>
14     #include <linux/errno.h>
15     #include <linux/string.h>
16     #include <linux/in.h>
17     #include <linux/pagemap.h>
18     #include <linux/proc_fs.h>
19     #include <linux/kdev_t.h>
20     #include <linux/sunrpc/clnt.h>
21     #include <linux/nfs.h>
22     #include <linux/nfs3.h>
23     #include <linux/nfs_fs.h>
24     
25     /* Uncomment this to support servers requiring longword lengths */
26     #define NFS_PAD_WRITES		1
27     
28     #define NFSDBG_FACILITY		NFSDBG_XDR
29     
30     /* Mapping from NFS error code to "errno" error code. */
31     #define errno_NFSERR_IO		EIO
32     
33     extern int			nfs_stat_to_errno(int);
34     
35     /*
36      * Declare the space requirements for NFS arguments and replies as
37      * number of 32bit-words
38      */
39     #define NFS3_fhandle_sz		1+16
40     #define NFS3_fh_sz		NFS3_fhandle_sz	/* shorthand */
41     #define NFS3_sattr_sz		15
42     #define NFS3_filename_sz	1+(NFS3_MAXNAMLEN>>2)
43     #define NFS3_path_sz		1+(NFS3_MAXPATHLEN>>2)
44     #define NFS3_fattr_sz		21
45     #define NFS3_wcc_attr_sz		6
46     #define NFS3_pre_op_attr_sz	1+NFS3_wcc_attr_sz
47     #define NFS3_post_op_attr_sz	1+NFS3_fattr_sz
48     #define NFS3_wcc_data_sz		NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
49     #define NFS3_fsstat_sz		
50     #define NFS3_fsinfo_sz		
51     #define NFS3_pathconf_sz		
52     #define NFS3_entry_sz		NFS3_filename_sz+3
53     
54     #define NFS3_enc_void_sz	0
55     #define NFS3_sattrargs_sz	NFS3_fh_sz+NFS3_sattr_sz+3
56     #define NFS3_diropargs_sz	NFS3_fh_sz+NFS3_filename_sz
57     #define NFS3_accessargs_sz	NFS3_fh_sz+1
58     #define NFS3_readlinkargs_sz	NFS3_fh_sz
59     #define NFS3_readargs_sz	NFS3_fh_sz+3
60     #define NFS3_writeargs_sz	NFS3_fh_sz+5
61     #define NFS3_createargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
62     #define NFS3_mkdirargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
63     #define NFS3_symlinkargs_sz	NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
64     #define NFS3_mknodargs_sz	NFS3_diropargs_sz+2+NFS3_sattr_sz
65     #define NFS3_renameargs_sz	NFS3_diropargs_sz+NFS3_diropargs_sz
66     #define NFS3_linkargs_sz		NFS3_fh_sz+NFS3_diropargs_sz
67     #define NFS3_readdirargs_sz	NFS3_fh_sz+2
68     #define NFS3_commitargs_sz	NFS3_fh_sz+3
69     
70     #define NFS3_dec_void_sz	0
71     #define NFS3_attrstat_sz	1+NFS3_fattr_sz
72     #define NFS3_wccstat_sz		1+NFS3_wcc_data_sz
73     #define NFS3_lookupres_sz	1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
74     #define NFS3_accessres_sz	1+NFS3_post_op_attr_sz+1
75     #define NFS3_readlinkres_sz	1+NFS3_post_op_attr_sz
76     #define NFS3_readres_sz		1+NFS3_post_op_attr_sz+3
77     #define NFS3_writeres_sz	1+NFS3_wcc_data_sz+4
78     #define NFS3_createres_sz	1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
79     #define NFS3_renameres_sz	1+(2 * NFS3_wcc_data_sz)
80     #define NFS3_linkres_sz		1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
81     #define NFS3_readdirres_sz	1+NFS3_post_op_attr_sz+2
82     #define NFS3_fsstatres_sz	1+NFS3_post_op_attr_sz+13
83     #define NFS3_fsinfores_sz	1+NFS3_post_op_attr_sz+12
84     #define NFS3_pathconfres_sz	1+NFS3_post_op_attr_sz+6
85     #define NFS3_commitres_sz	1+NFS3_wcc_data_sz+2
86     
87     /*
88      * Map file type to S_IFMT bits
89      */
90     static struct {
91     	unsigned int	mode;
92     	unsigned int	nfs2type;
93     } nfs_type2fmt[] = {
94           { 0,		NFNON	},
95           { S_IFREG,	NFREG	},
96           { S_IFDIR,	NFDIR	},
97           { S_IFBLK,	NFBLK	},
98           { S_IFCHR,	NFCHR	},
99           { S_IFLNK,	NFLNK	},
100           { S_IFSOCK,	NFSOCK	},
101           { S_IFIFO,	NFFIFO	},
102           { 0,		NFBAD	}
103     };
104     
105     /*
106      * Common NFS XDR functions as inlines
107      */
108     static inline u32 *
109     xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
110     {
111     	*p++ = htonl(fh->size);
112     	memcpy(p, fh->data, fh->size);
113     	return p + XDR_QUADLEN(fh->size);
114     }
115     
116     static inline u32 *
117     xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
118     {
119     	/*
120     	 * Zero all nonused bytes
121     	 */
122     	memset((u8 *)fh, 0, sizeof(*fh));
123     	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
124     		memcpy(fh->data, p, fh->size);
125     		return p + XDR_QUADLEN(fh->size);
126     	}
127     	return NULL;
128     }
129     
130     /*
131      * Encode/decode time.
132      * Since the VFS doesn't care for fractional times, we ignore the
133      * nanosecond field.
134      */
135     static inline u32 *
136     xdr_encode_time(u32 *p, time_t time)
137     {
138     	*p++ = htonl(time);
139     	*p++ = 0;
140     	return p;
141     }
142     
143     static inline u32 *
144     xdr_decode_time3(u32 *p, u64 *timep)
145     {
146     	u64 tmp = (u64)ntohl(*p++) << 32;
147     	*timep = tmp + (u64)ntohl(*p++);
148     	return p;
149     }
150     
151     static inline u32 *
152     xdr_encode_time3(u32 *p, u64 time)
153     {
154     	*p++ = htonl(time >> 32);
155     	*p++ = htonl(time & 0xFFFFFFFF);
156     	return p;
157     }
158     
159     static inline u32 *
160     xdr_decode_string2(u32 *p, char **string, unsigned int *len,
161     			unsigned int maxlen)
162     {
163     	*len = ntohl(*p++);
164     	if (*len > maxlen)
165     		return NULL;
166     	*string = (char *) p;
167     	return p + XDR_QUADLEN(*len);
168     }
169     
170     static inline u32 *
171     xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
172     {
173     	unsigned int	type;
174     	int		fmode;
175     
176     	type = ntohl(*p++);
177     	if (type >= NF3BAD)
178     		type = NF3BAD;
179     	fmode = nfs_type2fmt[type].mode;
180     	fattr->type = nfs_type2fmt[type].nfs2type;
181     	fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
182     	fattr->nlink = ntohl(*p++);
183     	fattr->uid = ntohl(*p++);
184     	fattr->gid = ntohl(*p++);
185     	p = xdr_decode_hyper(p, &fattr->size);
186     	p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
187     	/* Turn remote device info into Linux-specific dev_t */
188     	fattr->rdev = ntohl(*p++) << MINORBITS;
189     	fattr->rdev |= ntohl(*p++) & MINORMASK;
190     	p = xdr_decode_hyper(p, &fattr->fsid);
191     	p = xdr_decode_hyper(p, &fattr->fileid);
192     	p = xdr_decode_time3(p, &fattr->atime);
193     	p = xdr_decode_time3(p, &fattr->mtime);
194     	p = xdr_decode_time3(p, &fattr->ctime);
195     
196     	/* Update the mode bits */
197     	fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
198     	return p;
199     }
200     
201     static inline u32 *
202     xdr_encode_sattr(u32 *p, struct iattr *attr)
203     {
204     	if (attr->ia_valid & ATTR_MODE) {
205     		*p++ = xdr_one;
206     		*p++ = htonl(attr->ia_mode);
207     	} else {
208     		*p++ = xdr_zero;
209     	}
210     	if (attr->ia_valid & ATTR_UID) {
211     		*p++ = xdr_one;
212     		*p++ = htonl(attr->ia_uid);
213     	} else {
214     		*p++ = xdr_zero;
215     	}
216     	if (attr->ia_valid & ATTR_GID) {
217     		*p++ = xdr_one;
218     		*p++ = htonl(attr->ia_gid);
219     	} else {
220     		*p++ = xdr_zero;
221     	}
222     	if (attr->ia_valid & ATTR_SIZE) {
223     		*p++ = xdr_one;
224     		p = xdr_encode_hyper(p, (__u64) attr->ia_size);
225     	} else {
226     		*p++ = xdr_zero;
227     	}
228     	if (attr->ia_valid & ATTR_ATIME_SET) {
229     		*p++ = xdr_two;
230     		p = xdr_encode_time(p, attr->ia_atime);
231     	} else if (attr->ia_valid & ATTR_ATIME) {
232     		*p++ = xdr_one;
233     	} else {
234     		*p++ = xdr_zero;
235     	}
236     	if (attr->ia_valid & ATTR_MTIME_SET) {
237     		*p++ = xdr_two;
238     		p = xdr_encode_time(p, attr->ia_mtime);
239     	} else if (attr->ia_valid & ATTR_MTIME) {
240     		*p++ = xdr_one;
241     	} else {
242     		*p++ = xdr_zero;
243     	}
244     	return p;
245     }
246     
247     static inline u32 *
248     xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
249     {
250     	p = xdr_decode_hyper(p, &fattr->pre_size);
251     	p = xdr_decode_time3(p, &fattr->pre_mtime);
252     	p = xdr_decode_time3(p, &fattr->pre_ctime);
253     	fattr->valid |= NFS_ATTR_WCC;
254     	return p;
255     }
256     
257     static inline u32 *
258     xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
259     {
260     	if (*p++)
261     		p = xdr_decode_fattr(p, fattr);
262     	return p;
263     }
264     
265     static inline u32 *
266     xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
267     {
268     	if (*p++)
269     		return xdr_decode_wcc_attr(p, fattr);
270     	return p;
271     }
272     
273     
274     static inline u32 *
275     xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
276     {
277     	p = xdr_decode_pre_op_attr(p, fattr);
278     	return xdr_decode_post_op_attr(p, fattr);
279     }
280     
281     /*
282      * NFS encode functions
283      */
284     /*
285      * Encode void argument
286      */
287     static int
288     nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
289     {
290     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
291     	return 0;
292     }
293     
294     /*
295      * Encode file handle argument
296      */
297     static int
298     nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
299     {
300     	p = xdr_encode_fhandle(p, fh);
301     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
302     	return 0;
303     }
304     
305     /*
306      * Encode SETATTR arguments
307      */
308     static int
309     nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
310     {
311     	p = xdr_encode_fhandle(p, args->fh);
312     	p = xdr_encode_sattr(p, args->sattr);
313     	*p++ = htonl(args->guard);
314     	if (args->guard)
315     		p = xdr_encode_time3(p, args->guardtime);
316     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
317     	return 0;
318     }
319     
320     /*
321      * Encode directory ops argument
322      */
323     static int
324     nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
325     {
326     	p = xdr_encode_fhandle(p, args->fh);
327     	p = xdr_encode_array(p, args->name, args->len);
328     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
329     	return 0;
330     }
331     
332     /*
333      * Encode access() argument
334      */
335     static int
336     nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
337     {
338     	p = xdr_encode_fhandle(p, args->fh);
339     	*p++ = htonl(args->access);
340     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
341     	return 0;
342     }
343     
344     /*
345      * Arguments to a READ call. Since we read data directly into the page
346      * cache, we also set up the reply iovec here so that iov[1] points
347      * exactly to the page we want to fetch.
348      */
349     static int
350     nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
351     {
352     	struct rpc_auth	*auth = req->rq_task->tk_auth;
353     	int		buflen, replen;
354     	unsigned int	nr;
355     
356     	p = xdr_encode_fhandle(p, args->fh);
357     	p = xdr_encode_hyper(p, args->offset);
358     	*p++ = htonl(args->count);
359     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
360     
361     	/* Get the number of buffers in the receive iovec */
362     	nr = args->nriov;
363     
364     	if (nr+2 > MAX_IOVEC) {
365     		printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
366     		return -EINVAL;
367     	}
368     
369     	/* set up reply iovec */
370     	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
371     	buflen = req->rq_rvec[0].iov_len;
372     	req->rq_rvec[0].iov_len  = replen;
373     
374     	/* Copy the iovec */
375     	memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
376     
377     	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
378     	req->rq_rvec[nr+1].iov_len  = buflen - replen;
379     	req->rq_rlen = args->count + buflen;
380     	req->rq_rnr += nr+1;
381     
382     	return 0;
383     }
384     
385     /*
386      * Write arguments. Splice the buffer to be written into the iovec.
387      */
388     static int
389     nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
390     {
391     	unsigned int	nr;
392     	u32 count = args->count;
393     
394     	p = xdr_encode_fhandle(p, args->fh);
395     	p = xdr_encode_hyper(p, args->offset);
396     	*p++ = htonl(count);
397     	*p++ = htonl(args->stable);
398     	*p++ = htonl(count);
399     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
400     
401     	/* Get the number of buffers in the send iovec */
402     	nr = args->nriov;
403     
404     	if (nr+2 > MAX_IOVEC) {
405     		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
406     		return -EINVAL;
407     	}
408     
409     	/* Copy the iovec */
410     	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
411     
412     #ifdef NFS_PAD_WRITES
413     	/*
414     	 * Some old servers require that the message length
415     	 * be a multiple of 4, so we pad it here if needed.
416     	 */
417     	if (count & 3) {
418     		struct iovec	*iov = req->rq_svec + nr + 1;
419     		int		pad = 4 - (count & 3);
420     
421     		iov->iov_base = (void *) "\0\0\0";
422     		iov->iov_len  = pad;
423     		count += pad;
424     		nr++;
425     	}
426     #endif
427     	req->rq_slen += count;
428     	req->rq_snr  += nr;
429     
430     	return 0;
431     }
432     
433     /*
434      * Encode CREATE arguments
435      */
436     static int
437     nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
438     {
439     	p = xdr_encode_fhandle(p, args->fh);
440     	p = xdr_encode_array(p, args->name, args->len);
441     
442     	*p++ = htonl(args->createmode);
443     	if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
444     		*p++ = args->verifier[0];
445     		*p++ = args->verifier[1];
446     	} else
447     		p = xdr_encode_sattr(p, args->sattr);
448     
449     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
450     	return 0;
451     }
452     
453     /*
454      * Encode MKDIR arguments
455      */
456     static int
457     nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
458     {
459     	p = xdr_encode_fhandle(p, args->fh);
460     	p = xdr_encode_array(p, args->name, args->len);
461     	p = xdr_encode_sattr(p, args->sattr);
462     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
463     	return 0;
464     }
465     
466     /*
467      * Encode SYMLINK arguments
468      */
469     static int
470     nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
471     {
472     	p = xdr_encode_fhandle(p, args->fromfh);
473     	p = xdr_encode_array(p, args->fromname, args->fromlen);
474     	p = xdr_encode_sattr(p, args->sattr);
475     	p = xdr_encode_array(p, args->topath, args->tolen);
476     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
477     	return 0;
478     }
479     
480     /*
481      * Encode MKNOD arguments
482      */
483     static int
484     nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
485     {
486     	p = xdr_encode_fhandle(p, args->fh);
487     	p = xdr_encode_array(p, args->name, args->len);
488     	*p++ = htonl(args->type);
489     	p = xdr_encode_sattr(p, args->sattr);
490     	if (args->type == NF3CHR || args->type == NF3BLK) {
491     		*p++ = htonl(args->rdev >> MINORBITS);
492     		*p++ = htonl(args->rdev & MINORMASK);
493     	}
494     
495     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
496     	return 0;
497     }
498     
499     /*
500      * Encode RENAME arguments
501      */
502     static int
503     nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
504     {
505     	p = xdr_encode_fhandle(p, args->fromfh);
506     	p = xdr_encode_array(p, args->fromname, args->fromlen);
507     	p = xdr_encode_fhandle(p, args->tofh);
508     	p = xdr_encode_array(p, args->toname, args->tolen);
509     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
510     	return 0;
511     }
512     
513     /*
514      * Encode LINK arguments
515      */
516     static int
517     nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
518     {
519     	p = xdr_encode_fhandle(p, args->fromfh);
520     	p = xdr_encode_fhandle(p, args->tofh);
521     	p = xdr_encode_array(p, args->toname, args->tolen);
522     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
523     	return 0;
524     }
525     
526     /*
527      * Encode arguments to readdir call
528      */
529     static int
530     nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
531     {
532     	struct rpc_auth	*auth = req->rq_task->tk_auth;
533     	int		buflen, replen;
534     
535     	p = xdr_encode_fhandle(p, args->fh);
536     	p = xdr_encode_hyper(p, args->cookie);
537     	*p++ = args->verf[0];
538     	*p++ = args->verf[1];
539     	if (args->plus) {
540     		/* readdirplus: need dircount + buffer size.
541     		 * We just make sure we make dircount big enough */
542     		*p++ = htonl(args->bufsiz >> 3);
543     	}
544     	*p++ = htonl(args->bufsiz);
545     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
546     
547     	/* set up reply iovec */
548     	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
549     	buflen = req->rq_rvec[0].iov_len;
550     	req->rq_rvec[0].iov_len  = replen;
551     	req->rq_rvec[1].iov_base = args->buffer;
552     	req->rq_rvec[1].iov_len  = args->bufsiz;
553     	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
554     	req->rq_rvec[2].iov_len  = buflen - replen;
555     	req->rq_rlen = buflen + args->bufsiz;
556     	req->rq_rnr += 2;
557     
558     	return 0;
559     }
560     
561     /*
562      * Decode the result of a readdir call.
563      * We just check for syntactical correctness.
564      */
565     static int
566     nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
567     {
568     	struct iovec	*iov = req->rq_rvec;
569     	int		hdrlen;
570     	int		status, nr;
571     	unsigned int	len;
572     	u32		*entry, *end;
573     
574     	status = ntohl(*p++);
575     	/* Decode post_op_attrs */
576     	p = xdr_decode_post_op_attr(p, res->dir_attr);
577     	if (status)
578     		return -nfs_stat_to_errno(status);
579     	/* Decode verifier cookie */
580     	if (res->verf) {
581     		res->verf[0] = *p++;
582     		res->verf[1] = *p++;
583     	} else {
584     		p += 2;
585     	}
586     
587     	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
588     	if (iov->iov_len > hdrlen) {
589     		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
590     		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
591     	}
592     
593     	p   = (u32 *) iov[1].iov_base;
594     	end = (u32 *) ((u8 *) p + iov[1].iov_len);
595     	for (nr = 0; *p++; nr++) {
596     		entry = p - 1;
597     		p += 2;				/* inode # */
598     		len = ntohl(*p++);		/* string length */
599     		p += XDR_QUADLEN(len) + 2;	/* name + cookie */
600     		if (len > NFS3_MAXNAMLEN) {
601     			printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
602     						len);
603     			return -errno_NFSERR_IO;
604     		}
605     
606     		if (res->plus) {
607     			/* post_op_attr */
608     			if (*p++)
609     				p += 21;
610     			/* post_op_fh3 */
611     			if (*p++) {
612     				len = ntohl(*p++);
613     				if (len > NFS3_FHSIZE) {
614     					printk(KERN_WARNING "NFS: giant filehandle in "
615     						"readdir (len %x)!\n", len);
616     					return -errno_NFSERR_IO;
617     				}
618     				p += XDR_QUADLEN(len);
619     			}
620     		}
621     
622     		if (p + 2 > end) {
623     			printk(KERN_NOTICE
624     				"NFS: short packet in readdir reply!\n");
625     			/* truncate listing */
626     			entry[0] = entry[1] = 0;
627     			break;
628     		}
629     	}
630     
631     	return nr;
632     }
633     
634     u32 *
635     nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
636     {
637     	struct nfs_entry old = *entry;
638     
639     	if (!*p++) {
640     		if (!*p)
641     			return ERR_PTR(-EAGAIN);
642     		entry->eof = 1;
643     		return ERR_PTR(-EBADCOOKIE);
644     	}
645     
646     	p = xdr_decode_hyper(p, &entry->ino);
647     	entry->len  = ntohl(*p++);
648     	entry->name = (const char *) p;
649     	p += XDR_QUADLEN(entry->len);
650     	entry->prev_cookie = entry->cookie;
651     	p = xdr_decode_hyper(p, &entry->cookie);
652     
653     	if (plus) {
654     		p = xdr_decode_post_op_attr(p, &entry->fattr);
655     		/* In fact, a post_op_fh3: */
656     		if (*p++) {
657     			p = xdr_decode_fhandle(p, &entry->fh);
658     			/* Ugh -- server reply was truncated */
659     			if (p == NULL) {
660     				dprintk("NFS: FH truncated\n");
661     				*entry = old;
662     				return ERR_PTR(-EAGAIN);
663     			}
664     		} else {
665     			/* If we don't get a file handle, the attrs
666     			 * aren't worth a lot. */
667     			entry->fattr.valid = 0;
668     		}
669     	}
670     
671     	entry->eof = !p[0] && p[1];
672     	return p;
673     }
674     
675     /*
676      * Encode COMMIT arguments
677      */
678     static int
679     nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
680     {
681     	p = xdr_encode_fhandle(p, args->fh);
682     	p = xdr_encode_hyper(p, args->offset);
683     	*p++ = htonl(args->count);
684     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
685     	return 0;
686     }
687     
688     /*
689      * NFS XDR decode functions
690      */
691     /*
692      * Decode void reply
693      */
694     static int
695     nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
696     {
697     	return 0;
698     }
699     
700     /*
701      * Decode attrstat reply.
702      */
703     static int
704     nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
705     {
706     	int	status;
707     
708     	if ((status = ntohl(*p++)))
709     		return -nfs_stat_to_errno(status);
710     	xdr_decode_fattr(p, fattr);
711     	return 0;
712     }
713     
714     /*
715      * Decode status+wcc_data reply
716      * SATTR, REMOVE, RMDIR
717      */
718     static int
719     nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
720     {
721     	int	status;
722     
723     	if ((status = ntohl(*p++)))
724     		status = -nfs_stat_to_errno(status);
725     	xdr_decode_wcc_data(p, fattr);
726     	return status;
727     }
728     
729     /*
730      * Decode LOOKUP reply
731      */
732     static int
733     nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
734     {
735     	int	status;
736     
737     	if ((status = ntohl(*p++))) {
738     		status = -nfs_stat_to_errno(status);
739     	} else {
740     		if (!(p = xdr_decode_fhandle(p, res->fh)))
741     			return -errno_NFSERR_IO;
742     		p = xdr_decode_post_op_attr(p, res->fattr);
743     	}
744     	xdr_decode_post_op_attr(p, res->dir_attr);
745     	return status;
746     }
747     
748     /*
749      * Decode ACCESS reply
750      */
751     static int
752     nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
753     {
754     	int	status = ntohl(*p++);
755     
756     	p = xdr_decode_post_op_attr(p, res->fattr);
757     	if (status)
758     		return -nfs_stat_to_errno(status);
759     	res->access = ntohl(*p++);
760     	return 0;
761     }
762     
763     static int
764     nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
765     {
766     	struct rpc_task *task = req->rq_task;
767     	struct rpc_auth *auth = task->tk_auth;
768     	int		buflen, replen;
769     
770     	p = xdr_encode_fhandle(p, args->fh);
771     	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
772     	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
773     	buflen = req->rq_rvec[0].iov_len;
774     	req->rq_rvec[0].iov_len  = replen;
775     	req->rq_rvec[1].iov_base = args->buffer;
776     	req->rq_rvec[1].iov_len  = args->bufsiz;
777     	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
778     	req->rq_rvec[2].iov_len  = buflen - replen;
779     	req->rq_rlen = buflen + args->bufsiz;
780     	req->rq_rnr += 2;
781     	return 0;
782     }
783     
784     /*
785      * Decode READLINK reply
786      */
787     static int
788     nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
789     {
790     	struct iovec	*iov = req->rq_rvec;
791     	int		hdrlen;
792     	u32	*strlen;
793     	char	*string;
794     	int	status;
795     	unsigned int len;
796     
797     	status = ntohl(*p++);
798     	p = xdr_decode_post_op_attr(p, res->fattr);
799     
800     	if (status != 0)
801     		return -nfs_stat_to_errno(status);
802     
803     	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
804     	if (iov->iov_len > hdrlen) {
805     		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
806     		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
807     	}
808     
809     	strlen = (u32*)res->buffer;
810     	/* Convert length of symlink */
811     	len = ntohl(*strlen);
812     	if (len > res->bufsiz - 5)
813     		len = res->bufsiz - 5;
814     	*strlen = len;
815     	/* NULL terminate the string we got */
816     	string = (char *)(strlen + 1);
817     	string[len] = 0;
818     	return 0;
819     }
820     
821     /*
822      * Decode READ reply
823      */
824     static int
825     nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
826     {
827     	struct iovec *iov = req->rq_rvec;
828     	int	status, count, ocount, recvd, hdrlen;
829     
830     	status = ntohl(*p++);
831     	p = xdr_decode_post_op_attr(p, res->fattr);
832     
833     	if (status != 0)
834     		return -nfs_stat_to_errno(status);
835     
836     	/* Decode reply could and EOF flag. NFSv3 is somewhat redundant
837     	 * in that it puts the count both in the res struct and in the
838     	 * opaque data count. */
839     	count    = ntohl(*p++);
840     	res->eof = ntohl(*p++);
841     	ocount   = ntohl(*p++);
842     
843     	if (ocount != count) {
844     		printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
845     		return -errno_NFSERR_IO;
846     	}
847     
848     	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
849     	if (iov->iov_len > hdrlen) {
850     		dprintk("NFS: READ header is short. iovec will be shifted.\n");
851     		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
852     	}
853     
854     	recvd = req->rq_rlen - hdrlen;
855     	if (count > recvd) {
856     		printk(KERN_WARNING "NFS: server cheating in read reply: "
857     			"count %d > recvd %d\n", count, recvd);
858     		count = recvd;
859     	}
860     
861     	if (count < res->count) {
862     		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
863     		res->count = count;
864     	}
865     
866     	return count;
867     }
868     
869     /*
870      * Decode WRITE response
871      */
872     static int
873     nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
874     {
875     	int	status;
876     
877     	status = ntohl(*p++);
878     	p = xdr_decode_wcc_data(p, res->fattr);
879     
880     	if (status != 0)
881     		return -nfs_stat_to_errno(status);
882     
883     	res->count = ntohl(*p++);
884     	res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
885     	res->verf->verifier[0] = *p++;
886     	res->verf->verifier[1] = *p++;
887     
888     	return res->count;
889     }
890     
891     /*
892      * Decode a CREATE response
893      */
894     static int
895     nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
896     {
897     	int	status;
898     
899     	status = ntohl(*p++);
900     	if (status == 0) {
901     		if (*p++) {
902     			if (!(p = xdr_decode_fhandle(p, res->fh)))
903     				return -errno_NFSERR_IO;
904     			p = xdr_decode_post_op_attr(p, res->fattr);
905     		} else {
906     			memset(res->fh, 0, sizeof(*res->fh));
907     			/* Do decode post_op_attr but set it to NULL */
908     			p = xdr_decode_post_op_attr(p, res->fattr);
909     			res->fattr->valid = 0;
910     		}
911     	} else {
912     		status = -nfs_stat_to_errno(status);
913     	}
914     	p = xdr_decode_wcc_data(p, res->dir_attr);
915     	return status;
916     }
917     
918     /*
919      * Decode RENAME reply
920      */
921     static int
922     nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
923     {
924     	int	status;
925     
926     	if ((status = ntohl(*p++)) != 0)
927     		status = -nfs_stat_to_errno(status);
928     	p = xdr_decode_wcc_data(p, res->fromattr);
929     	p = xdr_decode_wcc_data(p, res->toattr);
930     	return status;
931     }
932     
933     /*
934      * Decode LINK reply
935      */
936     static int
937     nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
938     {
939     	int	status;
940     
941     	if ((status = ntohl(*p++)) != 0)
942     		status = -nfs_stat_to_errno(status);
943     	p = xdr_decode_post_op_attr(p, res->fattr);
944     	p = xdr_decode_wcc_data(p, res->dir_attr);
945     	return status;
946     }
947     
948     /*
949      * Decode FSSTAT reply
950      */
951     static int
952     nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
953     {
954     	struct nfs_fattr dummy;
955     	int		status;
956     
957     	status = ntohl(*p++);
958     
959     	p = xdr_decode_post_op_attr(p, &dummy);
960     	if (status != 0)
961     		return -nfs_stat_to_errno(status);
962     
963     	p = xdr_decode_hyper(p, &res->tbytes);
964     	p = xdr_decode_hyper(p, &res->fbytes);
965     	p = xdr_decode_hyper(p, &res->abytes);
966     	p = xdr_decode_hyper(p, &res->tfiles);
967     	p = xdr_decode_hyper(p, &res->ffiles);
968     	p = xdr_decode_hyper(p, &res->afiles);
969     
970     	/* ignore invarsec */
971     	return 0;
972     }
973     
974     /*
975      * Decode FSINFO reply
976      */
977     static int
978     nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
979     {
980     	struct nfs_fattr dummy;
981     	int		status;
982     
983     	status = ntohl(*p++);
984     
985     	p = xdr_decode_post_op_attr(p, &dummy);
986     	if (status != 0)
987     		return -nfs_stat_to_errno(status);
988     
989     	res->rtmax  = ntohl(*p++);
990     	res->rtpref = ntohl(*p++);
991     	res->rtmult = ntohl(*p++);
992     	res->wtmax  = ntohl(*p++);
993     	res->wtpref = ntohl(*p++);
994     	res->wtmult = ntohl(*p++);
995     	res->dtpref = ntohl(*p++);
996     	p = xdr_decode_hyper(p, &res->maxfilesize);
997     
998     	/* ignore time_delta and properties */
999     	return 0;
1000     }
1001     
1002     /*
1003      * Decode PATHCONF reply
1004      */
1005     static int
1006     nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
1007     {
1008     	struct nfs_fattr dummy;
1009     	int		status;
1010     
1011     	status = ntohl(*p++);
1012     
1013     	p = xdr_decode_post_op_attr(p, &dummy);
1014     	if (status != 0)
1015     		return -nfs_stat_to_errno(status);
1016     	res->linkmax = ntohl(*p++);
1017     	res->namelen = ntohl(*p++);
1018     
1019     	/* ignore remaining fields */
1020     	return 0;
1021     }
1022     
1023     /*
1024      * Decode COMMIT reply
1025      */
1026     static int
1027     nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
1028     {
1029     	int		status;
1030     
1031     	status = ntohl(*p++);
1032     	p = xdr_decode_wcc_data(p, res->fattr);
1033     	if (status != 0)
1034     		return -nfs_stat_to_errno(status);
1035     
1036     	res->verf->verifier[0] = *p++;
1037     	res->verf->verifier[1] = *p++;
1038     	return 0;
1039     }
1040     
1041     #ifndef MAX
1042     # define MAX(a, b)	(((a) > (b))? (a) : (b))
1043     #endif
1044     
1045     #define PROC(proc, argtype, restype)				\
1046         { "nfs3_" #proc,						\
1047           (kxdrproc_t) nfs3_xdr_##argtype,				\
1048           (kxdrproc_t) nfs3_xdr_##restype,				\
1049           MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
1050           0							\
1051         }
1052     
1053     static struct rpc_procinfo	nfs3_procedures[22] = {
1054       PROC(null,		enc_void,	dec_void),
1055       PROC(getattr,		fhandle,	attrstat),
1056       PROC(setattr, 	sattrargs,	wccstat),
1057       PROC(lookup,		diropargs,	lookupres),
1058       PROC(access,		accessargs,	accessres),
1059       PROC(readlink,	readlinkargs,	readlinkres),
1060       PROC(read,		readargs,	readres),
1061       PROC(write,		writeargs,	writeres),
1062       PROC(create,		createargs,	createres),
1063       PROC(mkdir,		mkdirargs,	createres),
1064       PROC(symlink,		symlinkargs,	createres),
1065       PROC(mknod,		mknodargs,	createres),
1066       PROC(remove,		diropargs,	wccstat),
1067       PROC(rmdir,		diropargs,	wccstat),
1068       PROC(rename,		renameargs,	renameres),
1069       PROC(link,		linkargs,	linkres),
1070       PROC(readdir,		readdirargs,	readdirres),
1071       PROC(readdirplus,	readdirargs,	readdirres),
1072       PROC(fsstat,		fhandle,	fsstatres),
1073       PROC(fsinfo,  	fhandle,	fsinfores),
1074       PROC(pathconf,	fhandle,	pathconfres),
1075       PROC(commit,		commitargs,	commitres),
1076     };
1077     
1078     struct rpc_version		nfs_version3 = {
1079     	3,
1080     	sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1081     	nfs3_procedures
1082     };
1083     
1084