|
25 | 25 |
|
26 | 26 | #if defined(CONFIG_NFS_V4_1) |
27 | 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 | 29 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
29 | 30 | 4 + 1 + 3) |
30 | 31 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
@@ -284,6 +285,93 @@ static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, |
284 | 285 | return status; |
285 | 286 | } |
286 | 287 |
|
| 288 | +static |
| 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 | + } |
| 366 | +out: |
| 367 | + dprintk("%s: status %d ndevs %d\n", |
| 368 | + __func__, ntohl(status), args->ndevs); |
| 369 | + return status; |
| 370 | +err: |
| 371 | + kfree(args->devs); |
| 372 | + goto out; |
| 373 | +} |
| 374 | + |
287 | 375 | static __be32 decode_sessionid(struct xdr_stream *xdr, |
288 | 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 | 727 | case OP_CB_RECALL_ANY: |
640 | 728 | case OP_CB_RECALL_SLOT: |
641 | 729 | case OP_CB_LAYOUTRECALL: |
| 730 | + case OP_CB_NOTIFY_DEVICEID: |
642 | 731 | *op = &callback_ops[op_nr]; |
643 | 732 | break; |
644 | 733 |
|
645 | | - case OP_CB_NOTIFY_DEVICEID: |
646 | 734 | case OP_CB_NOTIFY: |
647 | 735 | case OP_CB_PUSH_DELEG: |
648 | 736 | case OP_CB_RECALLABLE_OBJ_AVAIL: |
@@ -849,6 +937,12 @@ static struct callback_op callback_ops[] = { |
849 | 937 | (callback_decode_arg_t)decode_layoutrecall_args, |
850 | 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 | 946 | [OP_CB_SEQUENCE] = { |
853 | 947 | .process_op = (callback_process_op_t)nfs4_callback_sequence, |
854 | 948 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, |
|
0 commit comments