Blame view

fs/nfs/callback_xdr.c 24.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * linux/fs/nfs/callback_xdr.c
   *
   * Copyright (C) 2004 Trond Myklebust
   *
   * NFSv4 callback encode/decode procedures
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
  #include <linux/kernel.h>
  #include <linux/sunrpc/svc.h>
  #include <linux/nfs4.h>
  #include <linux/nfs_fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
c36fca52f   Andy Adamson   NFS refactor nfs_...
13
  #include <linux/sunrpc/bc_xprt.h>
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
14
  #include "nfs4_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include "callback.h"
c36fca52f   Andy Adamson   NFS refactor nfs_...
16
  #include "internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
23
24
  
  #define CB_OP_TAGLEN_MAXSZ	(512)
  #define CB_OP_HDR_RES_MAXSZ	(2 + CB_OP_TAGLEN_MAXSZ)
  #define CB_OP_GETATTR_BITMAP_MAXSZ	(4)
  #define CB_OP_GETATTR_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ + \
  				CB_OP_GETATTR_BITMAP_MAXSZ + \
  				2 + 2 + 3 + 3)
  #define CB_OP_RECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
25
  #if defined(CONFIG_NFS_V4_1)
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
26
  #define CB_OP_LAYOUTRECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
1be5683b0   Marc Eshel   pnfs: CB_NOTIFY_D...
27
  #define CB_OP_DEVICENOTIFY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
28
29
  #define CB_OP_SEQUENCE_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ + \
  					4 + 1 + 3)
31f096077   Alexandros Batsakis   nfs41: V2 initial...
30
  #define CB_OP_RECALLANY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
b9efa1b27   Andy Adamson   nfs41: implement ...
31
  #define CB_OP_RECALLSLOT_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
32
  #endif /* CONFIG_NFS_V4_1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #define NFSDBG_FACILITY NFSDBG_CALLBACK
31d2b4356   Andy Adamson   nfs41: fix wrong ...
34
35
  /* Internal error code */
  #define NFS4ERR_RESOURCE_HDR	11050
c36fca52f   Andy Adamson   NFS refactor nfs_...
36
37
  typedef __be32 (*callback_process_op_t)(void *, void *,
  					struct cb_process_state *);
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
38
39
  typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
  typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
47
48
49
  
  
  struct callback_op {
  	callback_process_op_t process_op;
  	callback_decode_arg_t decode_args;
  	callback_encode_res_t encode_res;
  	long res_maxsize;
  };
  
  static struct callback_op callback_ops[];
7111c66e4   Al Viro   [PATCH] fix svc_p...
50
  static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
  {
  	return htonl(NFS4_OK);
  }
5704fdeb4   Al Viro   [PATCH] xdr annot...
54
  static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
  {
  	return xdr_argsize_check(rqstp, p);
  }
5704fdeb4   Al Viro   [PATCH] xdr annot...
58
  static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
  {
  	return xdr_ressize_check(rqstp, p);
  }
5704fdeb4   Al Viro   [PATCH] xdr annot...
62
  static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
64
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
70
71
  
  	p = xdr_inline_decode(xdr, nbytes);
  	if (unlikely(p == NULL))
  		printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!
  ");
  	return p;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
72
  static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
74
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	*len = ntohl(*p);
  
  	if (*len != 0) {
  		p = read_buf(xdr, *len);
  		if (unlikely(p == NULL))
  			return htonl(NFS4ERR_RESOURCE);
  		*str = (const char *)p;
  	} else
  		*str = NULL;
  
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
91
  static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
93
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	fh->size = ntohl(*p);
  	if (fh->size > NFS4_FHSIZE)
  		return htonl(NFS4ERR_BADHANDLE);
  	p = read_buf(xdr, fh->size);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	memcpy(&fh->data[0], p, fh->size);
  	memset(&fh->data[fh->size], 0, sizeof(fh->data) - fh->size);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
108
  static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
110
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  	unsigned int attrlen;
  
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	attrlen = ntohl(*p);
  	p = read_buf(xdr, attrlen << 2);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	if (likely(attrlen > 0))
  		bitmap[0] = ntohl(*p++);
  	if (attrlen > 1)
  		bitmap[1] = ntohl(*p);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
126
  static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
128
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
133
134
135
  
  	p = read_buf(xdr, 16);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	memcpy(stateid->data, p, 16);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
136
  static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
138
  	__be32 *p;
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
139
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
  
  	status = decode_string(xdr, &hdr->taglen, &hdr->tag);
  	if (unlikely(status != 0))
  		return status;
  	/* We do not like overly long tags! */
5cce428d9   Chuck Lever   NFS: Remove an un...
145
  	if (hdr->taglen > CB_OP_TAGLEN_MAXSZ - 12) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  		printk("NFSv4 CALLBACK %s: client sent tag of length %u
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
148
  				__func__, hdr->taglen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
152
153
  		return htonl(NFS4ERR_RESOURCE);
  	}
  	p = read_buf(xdr, 12);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
b8f2ef84b   Benny Halevy   nfs41: store mino...
154
  	hdr->minorversion = ntohl(*p++);
48a9e2d22   Benny Halevy   nfs41: decode min...
155
156
  	/* Check minor version is zero or one. */
  	if (hdr->minorversion <= 1) {
c36fca52f   Andy Adamson   NFS refactor nfs_...
157
  		hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
48a9e2d22   Benny Halevy   nfs41: decode min...
158
  	} else {
b8f2ef84b   Benny Halevy   nfs41: store mino...
159
160
161
162
  		printk(KERN_WARNING "%s: NFSv4 server callback with "
  			"illegal minor version %u!
  ",
  			__func__, hdr->minorversion);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
  		return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  	hdr->nops = ntohl(*p);
b8f2ef84b   Benny Halevy   nfs41: store mino...
166
167
168
  	dprintk("%s: minorversion %d nops %d
  ", __func__,
  		hdr->minorversion, hdr->nops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
171
  static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
173
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL))
31d2b4356   Andy Adamson   nfs41: fix wrong ...
176
  		return htonl(NFS4ERR_RESOURCE_HDR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
  	*op = ntohl(*p);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
180
  static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
182
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
  
  	status = decode_fh(xdr, &args->fh);
  	if (unlikely(status != 0))
  		goto out;
671beed7e   Chuck Lever   NFS: Change cb_ge...
187
  	args->addr = svc_addr(rqstp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
  	status = decode_bitmap(xdr, args->bitmap);
  out:
3110ff804   Harvey Harrison   nfs: replace rema...
190
191
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
  	return status;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
194
  static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
196
  	__be32 *p;
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
197
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198

c1d358665   Chuck Lever   NFS: Change cb_re...
199
  	args->addr = svc_addr(rqstp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
209
210
  	status = decode_stateid(xdr, &args->stateid);
  	if (unlikely(status != 0))
  		goto out;
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL)) {
  		status = htonl(NFS4ERR_RESOURCE);
  		goto out;
  	}
  	args->truncate = ntohl(*p);
  	status = decode_fh(xdr, &args->fh);
  out:
3110ff804   Harvey Harrison   nfs: replace rema...
211
212
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
3873bc50e   Alexey Dobriyan   NFSv4: really ret...
213
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  }
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
215
  #if defined(CONFIG_NFS_V4_1)
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
  				       struct xdr_stream *xdr,
  				       struct cb_layoutrecallargs *args)
  {
  	__be32 *p;
  	__be32 status = 0;
  	uint32_t iomode;
  
  	args->cbl_addr = svc_addr(rqstp);
  	p = read_buf(xdr, 4 * sizeof(uint32_t));
  	if (unlikely(p == NULL)) {
  		status = htonl(NFS4ERR_BADXDR);
  		goto out;
  	}
  
  	args->cbl_layout_type = ntohl(*p++);
  	/* Depite the spec's xdr, iomode really belongs in the FILE switch,
25985edce   Lucas De Marchi   Fix common misspe...
233
  	 * as it is unusable and ignored with the other types.
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  	 */
  	iomode = ntohl(*p++);
  	args->cbl_layoutchanged = ntohl(*p++);
  	args->cbl_recall_type = ntohl(*p++);
  
  	if (args->cbl_recall_type == RETURN_FILE) {
  		args->cbl_range.iomode = iomode;
  		status = decode_fh(xdr, &args->cbl_fh);
  		if (unlikely(status != 0))
  			goto out;
  
  		p = read_buf(xdr, 2 * sizeof(uint64_t));
  		if (unlikely(p == NULL)) {
  			status = htonl(NFS4ERR_BADXDR);
  			goto out;
  		}
  		p = xdr_decode_hyper(p, &args->cbl_range.offset);
  		p = xdr_decode_hyper(p, &args->cbl_range.length);
  		status = decode_stateid(xdr, &args->cbl_stateid);
  		if (unlikely(status != 0))
  			goto out;
  	} else if (args->cbl_recall_type == RETURN_FSID) {
  		p = read_buf(xdr, 2 * sizeof(uint64_t));
  		if (unlikely(p == NULL)) {
  			status = htonl(NFS4ERR_BADXDR);
  			goto out;
  		}
  		p = xdr_decode_hyper(p, &args->cbl_fsid.major);
  		p = xdr_decode_hyper(p, &args->cbl_fsid.minor);
  	} else if (args->cbl_recall_type != RETURN_ALL) {
  		status = htonl(NFS4ERR_BADXDR);
  		goto out;
  	}
  	dprintk("%s: ltype 0x%x iomode %d changed %d recall_type %d
  ",
  		__func__,
  		args->cbl_layout_type, iomode,
  		args->cbl_layoutchanged, args->cbl_recall_type);
  out:
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
  	return status;
  }
1be5683b0   Marc Eshel   pnfs: CB_NOTIFY_D...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  static
  __be32 decode_devicenotify_args(struct svc_rqst *rqstp,
  				struct xdr_stream *xdr,
  				struct cb_devicenotifyargs *args)
  {
  	__be32 *p;
  	__be32 status = 0;
  	u32 tmp;
  	int n, i;
  	args->ndevs = 0;
  
  	/* Num of device notifications */
  	p = read_buf(xdr, sizeof(uint32_t));
  	if (unlikely(p == NULL)) {
  		status = htonl(NFS4ERR_BADXDR);
  		goto out;
  	}
  	n = ntohl(*p++);
  	if (n <= 0)
  		goto out;
  
  	args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
  	if (!args->devs) {
  		status = htonl(NFS4ERR_DELAY);
  		goto out;
  	}
  
  	/* Decode each dev notification */
  	for (i = 0; i < n; i++) {
  		struct cb_devicenotifyitem *dev = &args->devs[i];
  
  		p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE);
  		if (unlikely(p == NULL)) {
  			status = htonl(NFS4ERR_BADXDR);
  			goto err;
  		}
  
  		tmp = ntohl(*p++);	/* bitmap size */
  		if (tmp != 1) {
  			status = htonl(NFS4ERR_INVAL);
  			goto err;
  		}
  		dev->cbd_notify_type = ntohl(*p++);
  		if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE &&
  		    dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) {
  			status = htonl(NFS4ERR_INVAL);
  			goto err;
  		}
  
  		tmp = ntohl(*p++);	/* opaque size */
  		if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) &&
  		     (tmp != NFS4_DEVICEID4_SIZE + 8)) ||
  		    ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) &&
  		     (tmp != NFS4_DEVICEID4_SIZE + 4))) {
  			status = htonl(NFS4ERR_INVAL);
  			goto err;
  		}
  		dev->cbd_layout_type = ntohl(*p++);
  		memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE);
  		p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
  
  		if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
  			p = read_buf(xdr, sizeof(uint32_t));
  			if (unlikely(p == NULL)) {
  				status = htonl(NFS4ERR_BADXDR);
  				goto err;
  			}
  			dev->cbd_immediate = ntohl(*p++);
  		} else {
  			dev->cbd_immediate = 0;
  		}
  
  		args->ndevs++;
  
  		dprintk("%s: type %d layout 0x%x immediate %d
  ",
  			__func__, dev->cbd_notify_type, dev->cbd_layout_type,
  			dev->cbd_immediate);
  	}
  out:
  	dprintk("%s: status %d ndevs %d
  ",
  		__func__, ntohl(status), args->ndevs);
  	return status;
  err:
  	kfree(args->devs);
  	goto out;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
365
  static __be32 decode_sessionid(struct xdr_stream *xdr,
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
366
367
  				 struct nfs4_sessionid *sid)
  {
9733f0d92   Andy Adamson   nfs41: cleanup ca...
368
  	__be32 *p;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
369
370
371
372
  	int len = NFS4_MAX_SESSIONID_LEN;
  
  	p = read_buf(xdr, len);
  	if (unlikely(p == NULL))
a419aef8b   Joe Perches   trivial: remove u...
373
  		return htonl(NFS4ERR_RESOURCE);
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
374
375
376
377
  
  	memcpy(sid->data, p, len);
  	return 0;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
378
  static __be32 decode_rc_list(struct xdr_stream *xdr,
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
379
380
  			       struct referring_call_list *rc_list)
  {
9733f0d92   Andy Adamson   nfs41: cleanup ca...
381
  	__be32 *p;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
382
  	int i;
9733f0d92   Andy Adamson   nfs41: cleanup ca...
383
  	__be32 status;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  
  	status = decode_sessionid(xdr, &rc_list->rcl_sessionid);
  	if (status)
  		goto out;
  
  	status = htonl(NFS4ERR_RESOURCE);
  	p = read_buf(xdr, sizeof(uint32_t));
  	if (unlikely(p == NULL))
  		goto out;
  
  	rc_list->rcl_nrefcalls = ntohl(*p++);
  	if (rc_list->rcl_nrefcalls) {
  		p = read_buf(xdr,
  			     rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t));
  		if (unlikely(p == NULL))
  			goto out;
  		rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls *
  						sizeof(*rc_list->rcl_refcalls),
  						GFP_KERNEL);
  		if (unlikely(rc_list->rcl_refcalls == NULL))
  			goto out;
  		for (i = 0; i < rc_list->rcl_nrefcalls; i++) {
  			rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++);
  			rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++);
  		}
  	}
  	status = 0;
  
  out:
  	return status;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
415
  static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp,
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
416
417
418
  					struct xdr_stream *xdr,
  					struct cb_sequenceargs *args)
  {
9733f0d92   Andy Adamson   nfs41: cleanup ca...
419
  	__be32 *p;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
420
  	int i;
9733f0d92   Andy Adamson   nfs41: cleanup ca...
421
  	__be32 status;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
422
423
424
425
426
427
428
429
430
  
  	status = decode_sessionid(xdr, &args->csa_sessionid);
  	if (status)
  		goto out;
  
  	status = htonl(NFS4ERR_RESOURCE);
  	p = read_buf(xdr, 5 * sizeof(uint32_t));
  	if (unlikely(p == NULL))
  		goto out;
65fc64e54   Ricardo Labiaga   nfs41: Backchanne...
431
  	args->csa_addr = svc_addr(rqstp);
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  	args->csa_sequenceid = ntohl(*p++);
  	args->csa_slotid = ntohl(*p++);
  	args->csa_highestslotid = ntohl(*p++);
  	args->csa_cachethis = ntohl(*p++);
  	args->csa_nrclists = ntohl(*p++);
  	args->csa_rclists = NULL;
  	if (args->csa_nrclists) {
  		args->csa_rclists = kmalloc(args->csa_nrclists *
  					    sizeof(*args->csa_rclists),
  					    GFP_KERNEL);
  		if (unlikely(args->csa_rclists == NULL))
  			goto out;
  
  		for (i = 0; i < args->csa_nrclists; i++) {
  			status = decode_rc_list(xdr, &args->csa_rclists[i]);
  			if (status)
  				goto out_free;
  		}
  	}
  	status = 0;
  
  	dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u "
  		"highestslotid %u cachethis %d nrclists %u
  ",
  		__func__,
  		((u32 *)&args->csa_sessionid)[0],
  		((u32 *)&args->csa_sessionid)[1],
  		((u32 *)&args->csa_sessionid)[2],
  		((u32 *)&args->csa_sessionid)[3],
  		args->csa_sequenceid, args->csa_slotid,
  		args->csa_highestslotid, args->csa_cachethis,
  		args->csa_nrclists);
  out:
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
  	return status;
  
  out_free:
  	for (i = 0; i < args->csa_nrclists; i++)
  		kfree(args->csa_rclists[i].rcl_refcalls);
  	kfree(args->csa_rclists);
  	goto out;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
475
  static __be32 decode_recallany_args(struct svc_rqst *rqstp,
31f096077   Alexandros Batsakis   nfs41: V2 initial...
476
477
478
  				      struct xdr_stream *xdr,
  				      struct cb_recallanyargs *args)
  {
d743c3c9c   Peng Tao   NFS4: fix cb_reca...
479
480
  	uint32_t bitmap[2];
  	__be32 *p, status;
31f096077   Alexandros Batsakis   nfs41: V2 initial...
481
482
483
484
485
486
  
  	args->craa_addr = svc_addr(rqstp);
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_BADXDR);
  	args->craa_objs_to_keep = ntohl(*p++);
d743c3c9c   Peng Tao   NFS4: fix cb_reca...
487
488
489
490
  	status = decode_bitmap(xdr, bitmap);
  	if (unlikely(status))
  		return status;
  	args->craa_type_mask = bitmap[0];
31f096077   Alexandros Batsakis   nfs41: V2 initial...
491
492
493
  
  	return 0;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
494
  static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
b9efa1b27   Andy Adamson   nfs41: implement ...
495
496
497
498
499
500
501
502
503
504
505
506
  					struct xdr_stream *xdr,
  					struct cb_recallslotargs *args)
  {
  	__be32 *p;
  
  	args->crsa_addr = svc_addr(rqstp);
  	p = read_buf(xdr, 4);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_BADXDR);
  	args->crsa_target_max_slots = ntohl(*p++);
  	return 0;
  }
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
507
  #endif /* CONFIG_NFS_V4_1 */
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
508
  static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
510
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
519
520
  
  	p = xdr_reserve_space(xdr, 4 + len);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	xdr_encode_opaque(p, str, len);
  	return 0;
  }
  
  #define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
  #define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
5704fdeb4   Al Viro   [PATCH] xdr annot...
521
  static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
523
524
  	__be32 bm[2];
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  
  	bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
  	bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
  	if (bm[1] != 0) {
  		p = xdr_reserve_space(xdr, 16);
  		if (unlikely(p == NULL))
  			return htonl(NFS4ERR_RESOURCE);
  		*p++ = htonl(2);
  		*p++ = bm[0];
  		*p++ = bm[1];
  	} else if (bm[0] != 0) {
  		p = xdr_reserve_space(xdr, 12);
  		if (unlikely(p == NULL))
  			return htonl(NFS4ERR_RESOURCE);
  		*p++ = htonl(1);
  		*p++ = bm[0];
  	} else {
  		p = xdr_reserve_space(xdr, 8);
  		if (unlikely(p == NULL))
  			return htonl(NFS4ERR_RESOURCE);
  		*p++ = htonl(0);
  	}
  	*savep = p;
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
550
  static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
552
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
  
  	if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
  		return 0;
  	p = xdr_reserve_space(xdr, 8);
90dc7d279   Harvey Harrison   nfs: fix sparse w...
557
  	if (unlikely(!p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
561
  		return htonl(NFS4ERR_RESOURCE);
  	p = xdr_encode_hyper(p, change);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
562
  static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
564
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
  
  	if (!(bitmap[0] & FATTR4_WORD0_SIZE))
  		return 0;
  	p = xdr_reserve_space(xdr, 8);
90dc7d279   Harvey Harrison   nfs: fix sparse w...
569
  	if (unlikely(!p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
  		return htonl(NFS4ERR_RESOURCE);
  	p = xdr_encode_hyper(p, size);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
574
  static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
576
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
  
  	p = xdr_reserve_space(xdr, 12);
90dc7d279   Harvey Harrison   nfs: fix sparse w...
579
  	if (unlikely(!p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
581
582
583
584
  		return htonl(NFS4ERR_RESOURCE);
  	p = xdr_encode_hyper(p, time->tv_sec);
  	*p = htonl(time->tv_nsec);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
585
  static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
  {
  	if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
  		return 0;
  	return encode_attr_time(xdr,time);
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
591
  static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
596
  {
  	if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
  		return 0;
  	return encode_attr_time(xdr,time);
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
597
  static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  {
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
599
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
606
607
608
609
610
611
  
  	hdr->status = xdr_reserve_space(xdr, 4);
  	if (unlikely(hdr->status == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	status = encode_string(xdr, hdr->taglen, hdr->tag);
  	if (unlikely(status != 0))
  		return status;
  	hdr->nops = xdr_reserve_space(xdr, 4);
  	if (unlikely(hdr->nops == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
612
  static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
614
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
616
617
  	
  	p = xdr_reserve_space(xdr, 8);
  	if (unlikely(p == NULL))
31d2b4356   Andy Adamson   nfs41: fix wrong ...
618
  		return htonl(NFS4ERR_RESOURCE_HDR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
  	*p++ = htonl(op);
  	*p = res;
  	return 0;
  }
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
623
  static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  {
5704fdeb4   Al Viro   [PATCH] xdr annot...
625
  	__be32 *savep = NULL;
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
626
  	__be32 status = res->status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
  	
  	if (unlikely(status != 0))
  		goto out;
  	status = encode_attr_bitmap(xdr, res->bitmap, &savep);
  	if (unlikely(status != 0))
  		goto out;
  	status = encode_attr_change(xdr, res->bitmap, res->change_attr);
  	if (unlikely(status != 0))
  		goto out;
  	status = encode_attr_size(xdr, res->bitmap, res->size);
  	if (unlikely(status != 0))
  		goto out;
  	status = encode_attr_ctime(xdr, res->bitmap, &res->ctime);
  	if (unlikely(status != 0))
  		goto out;
  	status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
  	*savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
  out:
3110ff804   Harvey Harrison   nfs: replace rema...
645
646
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  	return status;
  }
34bc47c94   Benny Halevy   nfs41: consider m...
649
  #if defined(CONFIG_NFS_V4_1)
9733f0d92   Andy Adamson   nfs41: cleanup ca...
650
  static __be32 encode_sessionid(struct xdr_stream *xdr,
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
651
652
  				 const struct nfs4_sessionid *sid)
  {
9733f0d92   Andy Adamson   nfs41: cleanup ca...
653
  	__be32 *p;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
654
655
656
657
658
659
660
661
662
  	int len = NFS4_MAX_SESSIONID_LEN;
  
  	p = xdr_reserve_space(xdr, len);
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  
  	memcpy(p, sid, len);
  	return 0;
  }
9733f0d92   Andy Adamson   nfs41: cleanup ca...
663
  static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp,
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
664
665
666
  				       struct xdr_stream *xdr,
  				       const struct cb_sequenceres *res)
  {
9733f0d92   Andy Adamson   nfs41: cleanup ca...
667
  	__be32 *p;
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  	unsigned status = res->csr_status;
  
  	if (unlikely(status != 0))
  		goto out;
  
  	encode_sessionid(xdr, &res->csr_sessionid);
  
  	p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t));
  	if (unlikely(p == NULL))
  		return htonl(NFS4ERR_RESOURCE);
  
  	*p++ = htonl(res->csr_sequenceid);
  	*p++ = htonl(res->csr_slotid);
  	*p++ = htonl(res->csr_highestslotid);
  	*p++ = htonl(res->csr_target_highestslotid);
  out:
  	dprintk("%s: exit with status = %d
  ", __func__, ntohl(status));
  	return status;
  }
34bc47c94   Benny Halevy   nfs41: consider m...
688
689
690
  static __be32
  preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
  {
281fe15dc   Benny Halevy   nfs41: verify CB_...
691
692
693
694
695
696
697
  	if (op_nr == OP_CB_SEQUENCE) {
  		if (nop != 0)
  			return htonl(NFS4ERR_SEQUENCE_POS);
  	} else {
  		if (nop == 0)
  			return htonl(NFS4ERR_OP_NOT_IN_SESSION);
  	}
34bc47c94   Benny Halevy   nfs41: consider m...
698
699
700
  	switch (op_nr) {
  	case OP_CB_GETATTR:
  	case OP_CB_RECALL:
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
701
  	case OP_CB_SEQUENCE:
31f096077   Alexandros Batsakis   nfs41: V2 initial...
702
  	case OP_CB_RECALL_ANY:
b9efa1b27   Andy Adamson   nfs41: implement ...
703
  	case OP_CB_RECALL_SLOT:
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
704
  	case OP_CB_LAYOUTRECALL:
1be5683b0   Marc Eshel   pnfs: CB_NOTIFY_D...
705
  	case OP_CB_NOTIFY_DEVICEID:
34bc47c94   Benny Halevy   nfs41: consider m...
706
707
  		*op = &callback_ops[op_nr];
  		break;
34bc47c94   Benny Halevy   nfs41: consider m...
708
709
  	case OP_CB_NOTIFY:
  	case OP_CB_PUSH_DELEG:
34bc47c94   Benny Halevy   nfs41: consider m...
710
  	case OP_CB_RECALLABLE_OBJ_AVAIL:
34bc47c94   Benny Halevy   nfs41: consider m...
711
712
713
714
715
716
717
718
719
720
  	case OP_CB_WANTS_CANCELLED:
  	case OP_CB_NOTIFY_LOCK:
  		return htonl(NFS4ERR_NOTSUPP);
  
  	default:
  		return htonl(NFS4ERR_OP_ILLEGAL);
  	}
  
  	return htonl(NFS_OK);
  }
42acd0218   Andy Adamson   NFS add session b...
721
722
723
724
725
726
727
728
729
  static void nfs4_callback_free_slot(struct nfs4_session *session)
  {
  	struct nfs4_slot_table *tbl = &session->bc_slot_table;
  
  	spin_lock(&tbl->slot_tbl_lock);
  	/*
  	 * Let the state manager know callback processing done.
  	 * A single slot, so highest used slotid is either 0 or -1
  	 */
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
730
  	tbl->highest_used_slotid = -1;
42acd0218   Andy Adamson   NFS add session b...
731
732
733
  	nfs4_check_drain_bc_complete(session);
  	spin_unlock(&tbl->slot_tbl_lock);
  }
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
734
  static void nfs4_cb_free_slot(struct cb_process_state *cps)
42acd0218   Andy Adamson   NFS add session b...
735
  {
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
736
737
  	if (cps->slotid != -1)
  		nfs4_callback_free_slot(cps->clp->cl_session);
42acd0218   Andy Adamson   NFS add session b...
738
  }
34bc47c94   Benny Halevy   nfs41: consider m...
739
740
741
742
743
744
745
  #else /* CONFIG_NFS_V4_1 */
  
  static __be32
  preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
  {
  	return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
  }
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
746
  static void nfs4_cb_free_slot(struct cb_process_state *cps)
42acd0218   Andy Adamson   NFS add session b...
747
748
  {
  }
34bc47c94   Benny Halevy   nfs41: consider m...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  #endif /* CONFIG_NFS_V4_1 */
  
  static __be32
  preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
  {
  	switch (op_nr) {
  	case OP_CB_GETATTR:
  	case OP_CB_RECALL:
  		*op = &callback_ops[op_nr];
  		break;
  	default:
  		return htonl(NFS4ERR_OP_ILLEGAL);
  	}
  
  	return htonl(NFS_OK);
  }
  
  static __be32 process_op(uint32_t minorversion, int nop,
  		struct svc_rqst *rqstp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  		struct xdr_stream *xdr_in, void *argp,
c36fca52f   Andy Adamson   NFS refactor nfs_...
769
770
  		struct xdr_stream *xdr_out, void *resp,
  		struct cb_process_state *cps)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  {
a162a6b80   Trond Myklebust   NFSv4: Kill brain...
772
  	struct callback_op *op = &callback_ops[0];
31d2b4356   Andy Adamson   nfs41: fix wrong ...
773
  	unsigned int op_nr;
34bc47c94   Benny Halevy   nfs41: consider m...
774
  	__be32 status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  	long maxlen;
e6f684f64   Al Viro   [PATCH] fs/nfs/ca...
776
  	__be32 res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777

3110ff804   Harvey Harrison   nfs: replace rema...
778
779
  	dprintk("%s: start
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
  	status = decode_op_hdr(xdr_in, &op_nr);
31d2b4356   Andy Adamson   nfs41: fix wrong ...
781
782
  	if (unlikely(status))
  		return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783

34bc47c94   Benny Halevy   nfs41: consider m...
784
785
786
787
788
789
790
791
  	dprintk("%s: minorversion=%d nop=%d op_nr=%u
  ",
  		__func__, minorversion, nop, op_nr);
  
  	status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) :
  				preprocess_nfs4_op(op_nr, &op);
  	if (status == htonl(NFS4ERR_OP_ILLEGAL))
  		op_nr = OP_CB_ILLEGAL;
b92b30190   Andy Adamson   nfs41: directly e...
792
793
  	if (status)
  		goto encode_hdr;
31d2b4356   Andy Adamson   nfs41: fix wrong ...
794

c36fca52f   Andy Adamson   NFS refactor nfs_...
795
796
  	if (cps->drc_status) {
  		status = cps->drc_status;
4911096f1   Andy Adamson   nfs41: back chann...
797
798
  		goto encode_hdr;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  	maxlen = xdr_out->end - xdr_out->p;
  	if (maxlen > 0 && maxlen < PAGE_SIZE) {
e95e60dae   Andy Adamson   nfs41: remove une...
801
802
  		status = op->decode_args(rqstp, xdr_in, argp);
  		if (likely(status == 0))
c36fca52f   Andy Adamson   NFS refactor nfs_...
803
  			status = op->process_op(argp, resp, cps);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
  	} else
  		status = htonl(NFS4ERR_RESOURCE);
b92b30190   Andy Adamson   nfs41: directly e...
806
  encode_hdr:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	res = encode_op_hdr(xdr_out, op_nr, status);
31d2b4356   Andy Adamson   nfs41: fix wrong ...
808
809
  	if (unlikely(res))
  		return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
  	if (op->encode_res != NULL && status == 0)
  		status = op->encode_res(rqstp, xdr_out, resp);
3110ff804   Harvey Harrison   nfs: replace rema...
812
813
  	dprintk("%s: done, status = %d
  ", __func__, ntohl(status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
815
816
817
818
819
  	return status;
  }
  
  /*
   * Decode, process and encode a COMPOUND
   */
7111c66e4   Al Viro   [PATCH] fix svc_p...
820
  static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
  {
3a6258e1f   Trond Myklebust   NFSv4: Check the ...
822
823
  	struct cb_compound_hdr_arg hdr_arg = { 0 };
  	struct cb_compound_hdr_res hdr_res = { NULL };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  	struct xdr_stream xdr_in, xdr_out;
c36fca52f   Andy Adamson   NFS refactor nfs_...
825
826
827
828
  	__be32 *p, status;
  	struct cb_process_state cps = {
  		.drc_status = 0,
  		.clp = NULL,
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
829
  		.slotid = -1,
c36fca52f   Andy Adamson   NFS refactor nfs_...
830
  	};
3a6258e1f   Trond Myklebust   NFSv4: Check the ...
831
  	unsigned int nops = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832

3110ff804   Harvey Harrison   nfs: replace rema...
833
834
  	dprintk("%s: start
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
  
  	xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
5704fdeb4   Al Viro   [PATCH] xdr annot...
837
  	p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
  	xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
3a6258e1f   Trond Myklebust   NFSv4: Check the ...
839
840
841
  	status = decode_compound_hdr_arg(&xdr_in, &hdr_arg);
  	if (status == __constant_htonl(NFS4ERR_RESOURCE))
  		return rpc_garbage_args;
c36fca52f   Andy Adamson   NFS refactor nfs_...
842
843
  	if (hdr_arg.minorversion == 0) {
  		cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
778be232a   Andy Adamson   NFS do not find c...
844
  		if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
c36fca52f   Andy Adamson   NFS refactor nfs_...
845
  			return rpc_drop_reply;
778be232a   Andy Adamson   NFS do not find c...
846
  	}
c36fca52f   Andy Adamson   NFS refactor nfs_...
847

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
  	hdr_res.taglen = hdr_arg.taglen;
  	hdr_res.tag = hdr_arg.tag;
3a6258e1f   Trond Myklebust   NFSv4: Check the ...
850
851
  	if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
  		return rpc_system_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852

3a6258e1f   Trond Myklebust   NFSv4: Check the ...
853
  	while (status == 0 && nops != hdr_arg.nops) {
4911096f1   Andy Adamson   nfs41: back chann...
854
  		status = process_op(hdr_arg.minorversion, nops, rqstp,
c36fca52f   Andy Adamson   NFS refactor nfs_...
855
  				    &xdr_in, argp, &xdr_out, resp, &cps);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  		nops++;
  	}
3a6258e1f   Trond Myklebust   NFSv4: Check the ...
858

31d2b4356   Andy Adamson   nfs41: fix wrong ...
859
860
861
862
863
864
  	/* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return
  	* resource error in cb_compound status without returning op */
  	if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) {
  		status = htonl(NFS4ERR_RESOURCE);
  		nops--;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  	*hdr_res.status = status;
  	*hdr_res.nops = htonl(nops);
55a673990   Trond Myklebust   NFSv4.1: Fix the ...
867
  	nfs4_cb_free_slot(&cps);
c36fca52f   Andy Adamson   NFS refactor nfs_...
868
  	nfs_put_client(cps.clp);
3110ff804   Harvey Harrison   nfs: replace rema...
869
870
  	dprintk("%s: done, status = %u
  ", __func__, ntohl(status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  	return rpc_success;
  }
  
  /*
   * Define NFS4 callback COMPOUND ops.
   */
  static struct callback_op callback_ops[] = {
  	[0] = {
  		.res_maxsize = CB_OP_HDR_RES_MAXSZ,
  	},
  	[OP_CB_GETATTR] = {
  		.process_op = (callback_process_op_t)nfs4_callback_getattr,
  		.decode_args = (callback_decode_arg_t)decode_getattr_args,
  		.encode_res = (callback_encode_res_t)encode_getattr_res,
  		.res_maxsize = CB_OP_GETATTR_RES_MAXSZ,
  	},
  	[OP_CB_RECALL] = {
  		.process_op = (callback_process_op_t)nfs4_callback_recall,
  		.decode_args = (callback_decode_arg_t)decode_recall_args,
  		.res_maxsize = CB_OP_RECALL_RES_MAXSZ,
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
891
892
  	},
  #if defined(CONFIG_NFS_V4_1)
f2a625616   Fred Isaman   pnfs: CB_LAYOUTRE...
893
894
895
896
897
898
  	[OP_CB_LAYOUTRECALL] = {
  		.process_op = (callback_process_op_t)nfs4_callback_layoutrecall,
  		.decode_args =
  			(callback_decode_arg_t)decode_layoutrecall_args,
  		.res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
  	},
1be5683b0   Marc Eshel   pnfs: CB_NOTIFY_D...
899
900
901
902
903
904
  	[OP_CB_NOTIFY_DEVICEID] = {
  		.process_op = (callback_process_op_t)nfs4_callback_devicenotify,
  		.decode_args =
  			(callback_decode_arg_t)decode_devicenotify_args,
  		.res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
  	},
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
905
906
907
908
909
910
  	[OP_CB_SEQUENCE] = {
  		.process_op = (callback_process_op_t)nfs4_callback_sequence,
  		.decode_args = (callback_decode_arg_t)decode_cb_sequence_args,
  		.encode_res = (callback_encode_res_t)encode_cb_sequence_res,
  		.res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ,
  	},
31f096077   Alexandros Batsakis   nfs41: V2 initial...
911
912
913
914
915
  	[OP_CB_RECALL_ANY] = {
  		.process_op = (callback_process_op_t)nfs4_callback_recallany,
  		.decode_args = (callback_decode_arg_t)decode_recallany_args,
  		.res_maxsize = CB_OP_RECALLANY_RES_MAXSZ,
  	},
b9efa1b27   Andy Adamson   nfs41: implement ...
916
917
918
919
920
  	[OP_CB_RECALL_SLOT] = {
  		.process_op = (callback_process_op_t)nfs4_callback_recallslot,
  		.decode_args = (callback_decode_arg_t)decode_recallslot_args,
  		.res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ,
  	},
4aece6a19   Benny Halevy   nfs41: cb_sequenc...
921
  #endif /* CONFIG_NFS_V4_1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  };
  
  /*
   * Define NFS4 callback procedures
   */
  static struct svc_procedure nfs4_callback_procedures1[] = {
  	[CB_NULL] = {
  		.pc_func = nfs4_callback_null,
  		.pc_decode = (kxdrproc_t)nfs4_decode_void,
  		.pc_encode = (kxdrproc_t)nfs4_encode_void,
  		.pc_xdrressize = 1,
  	},
  	[CB_COMPOUND] = {
  		.pc_func = nfs4_callback_compound,
  		.pc_encode = (kxdrproc_t)nfs4_encode_void,
  		.pc_argsize = 256,
  		.pc_ressize = 256,
  		.pc_xdrressize = NFS4_CALLBACK_BUFSIZE,
  	}
  };
  
  struct svc_version nfs4_callback_version1 = {
  	.vs_vers = 1,
  	.vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
  	.vs_proc = nfs4_callback_procedures1,
  	.vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
  	.vs_dispatch = NULL,
49697ee79   Steve Dickson   nfs4: Make the v4...
949
  	.vs_hidden = 1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  };
07bccc2dd   Alexandros Batsakis   nfs41: add suppor...
951
952
953
954
955
956
  struct svc_version nfs4_callback_version4 = {
  	.vs_vers = 4,
  	.vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
  	.vs_proc = nfs4_callback_procedures1,
  	.vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
  	.vs_dispatch = NULL,
6070295ef   Jeff Layton   nfs: set vs_hidde...
957
  	.vs_hidden = 1,
07bccc2dd   Alexandros Batsakis   nfs41: add suppor...
958
  };