Blame view

fs/nfsd/nfsxdr.c 13 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
   * XDR support for nfsd
   *
   * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   */
9a74af213   Boaz Harrosh   nfsd: Move privat...
6
  #include "xdr.h"
2e8138a27   J. Bruce Fields   nfsd: move nfsd/a...
7
  #include "auth.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
  
  #define NFSDDBG_FACILITY		NFSDDBG_XDR
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   * Mapping of S_IF* types to NFS file types
   */
  static u32	nfs_ftypes[] = {
  	NFNON,  NFCHR,  NFCHR, NFBAD,
  	NFDIR,  NFBAD,  NFBLK, NFBAD,
  	NFREG,  NFBAD,  NFLNK, NFBAD,
  	NFSOCK, NFBAD,  NFLNK, NFBAD,
  };
  
  
  /*
   * XDR functions for basic NFS types
   */
131a21c21   Al Viro   [PATCH] xdr annot...
24
25
  static __be32 *
  decode_fh(__be32 *p, struct svc_fh *fhp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
33
34
  {
  	fh_init(fhp, NFS_FHSIZE);
  	memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
  	fhp->fh_handle.fh_size = NFS_FHSIZE;
  
  	/* FIXME: Look up export pointer here and verify
  	 * Sun Secure RPC if requested */
  	return p + (NFS_FHSIZE >> 2);
  }
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
35
  /* Helper function for NFSv2 ACL code */
131a21c21   Al Viro   [PATCH] xdr annot...
36
  __be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
37
38
39
  {
  	return decode_fh(p, fhp);
  }
3ee6f61ca   Adrian Bunk   [PATCH] remove NF...
40
  static __be32 *
131a21c21   Al Viro   [PATCH] xdr annot...
41
  encode_fh(__be32 *p, struct svc_fh *fhp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
  {
  	memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
  	return p + (NFS_FHSIZE>> 2);
  }
  
  /*
   * Decode a file name and make sure that the path contains
   * no slashes or null bytes.
   */
3ee6f61ca   Adrian Bunk   [PATCH] remove NF...
51
  static __be32 *
ee1a95b3b   Chuck Lever   NFSD: Use unsigne...
52
  decode_filename(__be32 *p, char **namp, unsigned int *lenp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
  {
  	char		*name;
ee1a95b3b   Chuck Lever   NFSD: Use unsigne...
55
  	unsigned int	i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
63
64
65
  
  	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
  		for (i = 0, name = *namp; i < *lenp; i++, name++) {
  			if (*name == '\0' || *name == '/')
  				return NULL;
  		}
  	}
  
  	return p;
  }
3ee6f61ca   Adrian Bunk   [PATCH] remove NF...
66
  static __be32 *
9c7544d3a   Chuck Lever   NFSD: Use unsigne...
67
  decode_pathname(__be32 *p, char **namp, unsigned int *lenp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  {
  	char		*name;
9c7544d3a   Chuck Lever   NFSD: Use unsigne...
70
  	unsigned int	i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
  
  	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXPATHLEN)) != NULL) {
  		for (i = 0, name = *namp; i < *lenp; i++, name++) {
  			if (*name == '\0')
  				return NULL;
  		}
  	}
  
  	return p;
  }
3ee6f61ca   Adrian Bunk   [PATCH] remove NF...
81
  static __be32 *
131a21c21   Al Viro   [PATCH] xdr annot...
82
  decode_sattr(__be32 *p, struct iattr *iap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  {
  	u32	tmp, tmp1;
  
  	iap->ia_valid = 0;
  
  	/* Sun client bug compatibility check: some sun clients seem to
  	 * put 0xffff in the mode field when they mean 0xffffffff.
  	 * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah.
  	 */
  	if ((tmp = ntohl(*p++)) != (u32)-1 && tmp != 0xffff) {
  		iap->ia_valid |= ATTR_MODE;
  		iap->ia_mode = tmp;
  	}
  	if ((tmp = ntohl(*p++)) != (u32)-1) {
  		iap->ia_valid |= ATTR_UID;
  		iap->ia_uid = tmp;
  	}
  	if ((tmp = ntohl(*p++)) != (u32)-1) {
  		iap->ia_valid |= ATTR_GID;
  		iap->ia_gid = tmp;
  	}
  	if ((tmp = ntohl(*p++)) != (u32)-1) {
  		iap->ia_valid |= ATTR_SIZE;
  		iap->ia_size = tmp;
  	}
  	tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
  	if (tmp != (u32)-1 && tmp1 != (u32)-1) {
  		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
  		iap->ia_atime.tv_sec = tmp;
  		iap->ia_atime.tv_nsec = tmp1 * 1000; 
  	}
  	tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
  	if (tmp != (u32)-1 && tmp1 != (u32)-1) {
  		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
  		iap->ia_mtime.tv_sec = tmp;
  		iap->ia_mtime.tv_nsec = tmp1 * 1000; 
  		/*
  		 * Passing the invalid value useconds=1000000 for mtime
  		 * is a Sun convention for "set both mtime and atime to
  		 * current server time".  It's needed to make permissions
  		 * checks for the "touch" program across v2 mounts to
  		 * Solaris and Irix boxes work correctly. See description of
  		 * sattr in section 6.1 of "NFS Illustrated" by
  		 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
  		 */
  		if (tmp1 == 1000000)
  			iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
  	}
  	return p;
  }
131a21c21   Al Viro   [PATCH] xdr annot...
133
134
  static __be32 *
  encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
a334de286   David Shaw   [PATCH] knfsd: ch...
135
  	     struct kstat *stat)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  	struct dentry	*dentry = fhp->fh_dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
  	int type;
  	struct timespec time;
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
140
  	u32 f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

a334de286   David Shaw   [PATCH] knfsd: ch...
142
  	type = (stat->mode & S_IFMT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  
  	*p++ = htonl(nfs_ftypes[type >> 12]);
a334de286   David Shaw   [PATCH] knfsd: ch...
145
146
147
148
  	*p++ = htonl((u32) stat->mode);
  	*p++ = htonl((u32) stat->nlink);
  	*p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
  	*p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

a334de286   David Shaw   [PATCH] knfsd: ch...
150
  	if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
  		*p++ = htonl(NFS_MAXPATHLEN);
  	} else {
a334de286   David Shaw   [PATCH] knfsd: ch...
153
  		*p++ = htonl((u32) stat->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  	}
a334de286   David Shaw   [PATCH] knfsd: ch...
155
  	*p++ = htonl((u32) stat->blksize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  	if (S_ISCHR(type) || S_ISBLK(type))
a334de286   David Shaw   [PATCH] knfsd: ch...
157
  		*p++ = htonl(new_encode_dev(stat->rdev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
  	else
  		*p++ = htonl(0xffffffff);
a334de286   David Shaw   [PATCH] knfsd: ch...
160
  	*p++ = htonl((u32) stat->blocks);
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
161
162
163
  	switch (fsid_source(fhp)) {
  	default:
  	case FSIDSOURCE_DEV:
a334de286   David Shaw   [PATCH] knfsd: ch...
164
  		*p++ = htonl(new_encode_dev(stat->dev));
af6a4e280   NeilBrown   [PATCH] knfsd: ad...
165
166
167
168
169
170
171
172
173
174
175
176
  		break;
  	case FSIDSOURCE_FSID:
  		*p++ = htonl((u32) fhp->fh_export->ex_fsid);
  		break;
  	case FSIDSOURCE_UUID:
  		f = ((u32*)fhp->fh_export->ex_uuid)[0];
  		f ^= ((u32*)fhp->fh_export->ex_uuid)[1];
  		f ^= ((u32*)fhp->fh_export->ex_uuid)[2];
  		f ^= ((u32*)fhp->fh_export->ex_uuid)[3];
  		*p++ = htonl(f);
  		break;
  	}
a334de286   David Shaw   [PATCH] knfsd: ch...
177
178
179
  	*p++ = htonl((u32) stat->ino);
  	*p++ = htonl((u32) stat->atime.tv_sec);
  	*p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  	lease_get_mtime(dentry->d_inode, &time); 
  	*p++ = htonl((u32) time.tv_sec);
  	*p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0); 
a334de286   David Shaw   [PATCH] knfsd: ch...
183
184
  	*p++ = htonl((u32) stat->ctime.tv_sec);
  	*p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  
  	return p;
  }
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
188
  /* Helper function for NFSv2 ACL code */
131a21c21   Al Viro   [PATCH] xdr annot...
189
  __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
190
  {
a334de286   David Shaw   [PATCH] knfsd: ch...
191
  	struct kstat stat;
547754916   Jan Blunck   Use struct path i...
192
  	vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, &stat);
a334de286   David Shaw   [PATCH] knfsd: ch...
193
  	return encode_fattr(rqstp, p, fhp, &stat);
a257cdd0e   Andreas Gruenbacher   [PATCH] NFSD: Add...
194
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
199
  
  /*
   * XDR decode functions
   */
  int
131a21c21   Al Viro   [PATCH] xdr annot...
200
  nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
  {
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
206
  nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
  {
  	if (!(p = decode_fh(p, &args->fh)))
  		return 0;
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
214
  nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
  					struct nfsd_sattrargs *args)
  {
072f62ed8   NeilBrown   knfsd: various nf...
217
218
  	p = decode_fh(p, &args->fh);
  	if (!p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  		return 0;
072f62ed8   NeilBrown   knfsd: various nf...
220
  	p = decode_sattr(p, &args->attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
226
  nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
231
232
233
234
235
236
  					struct nfsd_diropargs *args)
  {
  	if (!(p = decode_fh(p, &args->fh))
  	 || !(p = decode_filename(p, &args->name, &args->len)))
  		return 0;
  
  	 return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
237
  nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
244
245
246
247
  					struct nfsd_readargs *args)
  {
  	unsigned int len;
  	int v,pn;
  	if (!(p = decode_fh(p, &args->fh)))
  		return 0;
  
  	args->offset    = ntohl(*p++);
  	len = args->count     = ntohl(*p++);
  	p++; /* totalcount - unused */
7adae489f   Greg Banks   [PATCH] knfsd: Pr...
248
249
  	if (len > NFSSVC_MAXBLKSIZE_V2)
  		len = NFSSVC_MAXBLKSIZE_V2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
  
  	/* set up somewhere to store response.
  	 * We take pages, put them on reslist and include in iovec
  	 */
  	v=0;
  	while (len > 0) {
445243594   NeilBrown   [PATCH] knfsd: Re...
256
  		pn = rqstp->rq_resused++;
3cc03b164   NeilBrown   [PATCH] knfsd: Av...
257
258
259
  		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
  		rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
  		len -= rqstp->rq_vec[v].iov_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
265
266
  		v++;
  	}
  	args->vlen = v;
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
267
  nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  					struct nfsd_writeargs *args)
  {
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
270
  	unsigned int len, hdr, dlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	int v;
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
272

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
277
278
279
  	if (!(p = decode_fh(p, &args->fh)))
  		return 0;
  
  	p++;				/* beginoffset */
  	args->offset = ntohl(*p++);	/* offset */
  	p++;				/* totalcount */
  	len = args->len = ntohl(*p++);
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
280
281
282
  	/*
  	 * The protocol specifies a maximum of 8192 bytes.
  	 */
7adae489f   Greg Banks   [PATCH] knfsd: Pr...
283
  	if (len > NFSSVC_MAXBLKSIZE_V2)
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
284
285
286
287
288
  		return 0;
  
  	/*
  	 * Check to make sure that we got the right number of
  	 * bytes.
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
289
290
  	 */
  	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
072f62ed8   NeilBrown   knfsd: various nf...
291
292
  	dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
  		- hdr;
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
293
294
295
296
  	/*
  	 * Round the length of the data which was specified up to
  	 * the next multiple of XDR units and then compare that
  	 * against the length which was actually received.
ba67a39ef   NeilBrown   knfsd: Allow NFSv...
297
298
299
  	 * Note that when RPCSEC/GSS (for example) is used, the
  	 * data buffer can be padded so dlen might be larger
  	 * than required.  It must never be smaller.
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
300
  	 */
ba67a39ef   NeilBrown   knfsd: Allow NFSv...
301
  	if (dlen < XDR_QUADLEN(len)*4)
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
302
303
304
305
  		return 0;
  
  	rqstp->rq_vec[0].iov_base = (void*)p;
  	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  	v = 0;
3cc03b164   NeilBrown   [PATCH] knfsd: Av...
307
308
  	while (len > rqstp->rq_vec[v].iov_len) {
  		len -= rqstp->rq_vec[v].iov_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  		v++;
3cc03b164   NeilBrown   [PATCH] knfsd: Av...
310
311
  		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
  		rqstp->rq_vec[v].iov_len = PAGE_SIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  	}
3cc03b164   NeilBrown   [PATCH] knfsd: Av...
313
  	rqstp->rq_vec[v].iov_len = len;
f34b95689   Peter Staubach   The NFSv2/NFSv3 s...
314
315
  	args->vlen = v + 1;
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
319
  nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
  					struct nfsd_createargs *args)
  {
072f62ed8   NeilBrown   knfsd: various nf...
322
323
  	if (   !(p = decode_fh(p, &args->fh))
  	    || !(p = decode_filename(p, &args->name, &args->len)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  		return 0;
072f62ed8   NeilBrown   knfsd: various nf...
325
  	p = decode_sattr(p, &args->attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
331
  nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
339
340
341
342
343
  					struct nfsd_renameargs *args)
  {
  	if (!(p = decode_fh(p, &args->ffh))
  	 || !(p = decode_filename(p, &args->fname, &args->flen))
  	 || !(p = decode_fh(p, &args->tfh))
  	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
  		return 0;
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
344
  nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
347
  {
  	if (!(p = decode_fh(p, &args->fh)))
  		return 0;
445243594   NeilBrown   [PATCH] knfsd: Re...
348
  	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
354
  nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
358
359
360
361
362
363
364
365
  					struct nfsd_linkargs *args)
  {
  	if (!(p = decode_fh(p, &args->ffh))
  	 || !(p = decode_fh(p, &args->tfh))
  	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
  		return 0;
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
366
  nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
  					struct nfsd_symlinkargs *args)
  {
072f62ed8   NeilBrown   knfsd: various nf...
369
370
371
  	if (   !(p = decode_fh(p, &args->ffh))
  	    || !(p = decode_filename(p, &args->fname, &args->flen))
  	    || !(p = decode_pathname(p, &args->tname, &args->tlen)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  		return 0;
072f62ed8   NeilBrown   knfsd: various nf...
373
  	p = decode_sattr(p, &args->attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
375
376
377
378
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
379
  nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
  					struct nfsd_readdirargs *args)
  {
  	if (!(p = decode_fh(p, &args->fh)))
  		return 0;
  	args->cookie = ntohl(*p++);
  	args->count  = ntohl(*p++);
  	if (args->count > PAGE_SIZE)
  		args->count = PAGE_SIZE;
445243594   NeilBrown   [PATCH] knfsd: Re...
388
  	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
394
395
396
  
  	return xdr_argsize_check(rqstp, p);
  }
  
  /*
   * XDR encode functions
   */
  int
131a21c21   Al Viro   [PATCH] xdr annot...
397
  nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
  {
  	return xdr_ressize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
403
  nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  					struct nfsd_attrstat *resp)
  {
a334de286   David Shaw   [PATCH] knfsd: ch...
406
  	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
  	return xdr_ressize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
411
  nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
  					struct nfsd_diropres *resp)
  {
  	p = encode_fh(p, &resp->fh);
a334de286   David Shaw   [PATCH] knfsd: ch...
415
  	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
  	return xdr_ressize_check(rqstp, p);
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
420
  nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
  					struct nfsd_readlinkres *resp)
  {
  	*p++ = htonl(resp->len);
  	xdr_ressize_check(rqstp, p);
  	rqstp->rq_res.page_len = resp->len;
  	if (resp->len & 3) {
  		/* need to pad the tail */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
431
432
433
434
435
  		rqstp->rq_res.tail[0].iov_base = p;
  		*p = 0;
  		rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
  	}
  	return 1;
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
436
  nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
  					struct nfsd_readres *resp)
  {
a334de286   David Shaw   [PATCH] knfsd: ch...
439
  	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  	*p++ = htonl(resp->count);
  	xdr_ressize_check(rqstp, p);
25985edce   Lucas De Marchi   Fix common misspe...
442
  	/* now update rqstp->rq_res to reflect data as well */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
  	rqstp->rq_res.page_len = resp->count;
  	if (resp->count & 3) {
  		/* need to pad the tail */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
447
448
449
450
451
452
453
  		rqstp->rq_res.tail[0].iov_base = p;
  		*p = 0;
  		rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
  	}
  	return 1;
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
454
  nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
463
464
465
466
  					struct nfsd_readdirres *resp)
  {
  	xdr_ressize_check(rqstp, p);
  	p = resp->buffer;
  	*p++ = 0;			/* no more entries */
  	*p++ = htonl((resp->common.err == nfserr_eof));
  	rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1;
  
  	return 1;
  }
  
  int
131a21c21   Al Viro   [PATCH] xdr annot...
467
  nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
  					struct nfsd_statfsres *resp)
  {
  	struct kstatfs	*stat = &resp->stats;
7adae489f   Greg Banks   [PATCH] knfsd: Pr...
471
  	*p++ = htonl(NFSSVC_MAXBLKSIZE_V2);	/* max transfer size */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
479
  	*p++ = htonl(stat->f_bsize);
  	*p++ = htonl(stat->f_blocks);
  	*p++ = htonl(stat->f_bfree);
  	*p++ = htonl(stat->f_bavail);
  	return xdr_ressize_check(rqstp, p);
  }
  
  int
a0ad13ef6   NeilBrown   [PATCH] knfsd: Fi...
480
481
  nfssvc_encode_entry(void *ccdv, const char *name,
  		    int namlen, loff_t offset, u64 ino, unsigned int d_type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  {
a0ad13ef6   NeilBrown   [PATCH] knfsd: Fi...
483
  	struct readdir_cd *ccd = ccdv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  	struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
131a21c21   Al Viro   [PATCH] xdr annot...
485
  	__be32	*p = cd->buffer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  	int	buflen, slen;
  
  	/*
  	dprintk("nfsd: entry(%.*s off %ld ino %ld)
  ",
  			namlen, name, offset, ino);
  	 */
  
  	if (offset > ~((u32) 0)) {
  		cd->common.err = nfserr_fbig;
  		return -EINVAL;
  	}
  	if (cd->offset)
  		*cd->offset = htonl(offset);
  	if (namlen > NFS2_MAXNAMLEN)
  		namlen = NFS2_MAXNAMLEN;/* truncate filename */
  
  	slen = XDR_QUADLEN(namlen);
  	if ((buflen = cd->buflen - slen - 4) < 0) {
  		cd->common.err = nfserr_toosmall;
  		return -EINVAL;
  	}
40ee5dc6a   Peter Staubach   knfsd: 64 bit ino...
508
509
510
511
  	if (ino > ~((u32) 0)) {
  		cd->common.err = nfserr_fbig;
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
  	*p++ = xdr_one;				/* mark entry present */
  	*p++ = htonl((u32) ino);		/* file id */
  	p    = xdr_encode_array(p, name, namlen);/* name length & name */
  	cd->offset = p;			/* remember pointer */
131a21c21   Al Viro   [PATCH] xdr annot...
516
  	*p++ = htonl(~0U);		/* offset of next entry */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
521
522
523
524
525
526
527
  
  	cd->buflen = buflen;
  	cd->buffer = p;
  	cd->common.err = nfs_ok;
  	return 0;
  }
  
  /*
   * XDR release functions
   */
  int
131a21c21   Al Viro   [PATCH] xdr annot...
528
  nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
  					struct nfsd_fhandle *resp)
  {
  	fh_put(&resp->fh);
  	return 1;
  }