aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/callback_xdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/callback_xdr.c')
-rw-r--r--fs/nfs/callback_xdr.c96
1 files changed, 95 insertions, 1 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 00ecf62ce7c1..c6c86a77e043 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -25,6 +25,7 @@
25 25
26#if defined(CONFIG_NFS_V4_1) 26#if defined(CONFIG_NFS_V4_1)
27#define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 27#define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
28#define CB_OP_DEVICENOTIFY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
28#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ 29#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
29 4 + 1 + 3) 30 4 + 1 + 3)
30#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 31#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
@@ -284,6 +285,93 @@ out:
284 return status; 285 return status;
285} 286}
286 287
288static
289__be32 decode_devicenotify_args(struct svc_rqst *rqstp,
290 struct xdr_stream *xdr,
291 struct cb_devicenotifyargs *args)
292{
293 __be32 *p;
294 __be32 status = 0;
295 u32 tmp;
296 int n, i;
297 args->ndevs = 0;
298
299 /* Num of device notifications */
300 p = read_buf(xdr, sizeof(uint32_t));
301 if (unlikely(p == NULL)) {
302 status = htonl(NFS4ERR_BADXDR);
303 goto out;
304 }
305 n = ntohl(*p++);
306 if (n <= 0)
307 goto out;
308
309 args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
310 if (!args->devs) {
311 status = htonl(NFS4ERR_DELAY);
312 goto out;
313 }
314
315 /* Decode each dev notification */
316 for (i = 0; i < n; i++) {
317 struct cb_devicenotifyitem *dev = &args->devs[i];
318
319 p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE);
320 if (unlikely(p == NULL)) {
321 status = htonl(NFS4ERR_BADXDR);
322 goto err;
323 }
324
325 tmp = ntohl(*p++); /* bitmap size */
326 if (tmp != 1) {
327 status = htonl(NFS4ERR_INVAL);
328 goto err;
329 }
330 dev->cbd_notify_type = ntohl(*p++);
331 if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE &&
332 dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) {
333 status = htonl(NFS4ERR_INVAL);
334 goto err;
335 }
336
337 tmp = ntohl(*p++); /* opaque size */
338 if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) &&
339 (tmp != NFS4_DEVICEID4_SIZE + 8)) ||
340 ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) &&
341 (tmp != NFS4_DEVICEID4_SIZE + 4))) {
342 status = htonl(NFS4ERR_INVAL);
343 goto err;
344 }
345 dev->cbd_layout_type = ntohl(*p++);
346 memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE);
347 p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
348
349 if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
350 p = read_buf(xdr, sizeof(uint32_t));
351 if (unlikely(p == NULL)) {
352 status = htonl(NFS4ERR_BADXDR);
353 goto err;
354 }
355 dev->cbd_immediate = ntohl(*p++);
356 } else {
357 dev->cbd_immediate = 0;
358 }
359
360 args->ndevs++;
361
362 dprintk("%s: type %d layout 0x%x immediate %d\n",
363 __func__, dev->cbd_notify_type, dev->cbd_layout_type,
364 dev->cbd_immediate);
365 }
366out:
367 dprintk("%s: status %d ndevs %d\n",
368 __func__, ntohl(status), args->ndevs);
369 return status;
370err:
371 kfree(args->devs);
372 goto out;
373}
374
287static __be32 decode_sessionid(struct xdr_stream *xdr, 375static __be32 decode_sessionid(struct xdr_stream *xdr,
288 struct nfs4_sessionid *sid) 376 struct nfs4_sessionid *sid)
289{ 377{
@@ -639,10 +727,10 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
639 case OP_CB_RECALL_ANY: 727 case OP_CB_RECALL_ANY:
640 case OP_CB_RECALL_SLOT: 728 case OP_CB_RECALL_SLOT:
641 case OP_CB_LAYOUTRECALL: 729 case OP_CB_LAYOUTRECALL:
730 case OP_CB_NOTIFY_DEVICEID:
642 *op = &callback_ops[op_nr]; 731 *op = &callback_ops[op_nr];
643 break; 732 break;
644 733
645 case OP_CB_NOTIFY_DEVICEID:
646 case OP_CB_NOTIFY: 734 case OP_CB_NOTIFY:
647 case OP_CB_PUSH_DELEG: 735 case OP_CB_PUSH_DELEG:
648 case OP_CB_RECALLABLE_OBJ_AVAIL: 736 case OP_CB_RECALLABLE_OBJ_AVAIL:
@@ -849,6 +937,12 @@ static struct callback_op callback_ops[] = {
849 (callback_decode_arg_t)decode_layoutrecall_args, 937 (callback_decode_arg_t)decode_layoutrecall_args,
850 .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ, 938 .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
851 }, 939 },
940 [OP_CB_NOTIFY_DEVICEID] = {
941 .process_op = (callback_process_op_t)nfs4_callback_devicenotify,
942 .decode_args =
943 (callback_decode_arg_t)decode_devicenotify_args,
944 .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
945 },
852 [OP_CB_SEQUENCE] = { 946 [OP_CB_SEQUENCE] = {
853 .process_op = (callback_process_op_t)nfs4_callback_sequence, 947 .process_op = (callback_process_op_t)nfs4_callback_sequence,
854 .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, 948 .decode_args = (callback_decode_arg_t)decode_cb_sequence_args,