diff options
Diffstat (limited to 'drivers/xen/pvcalls-front.c')
| -rw-r--r-- | drivers/xen/pvcalls-front.c | 104 |
1 files changed, 75 insertions, 29 deletions
diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 77224d8f3e6f..8a249c95c193 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c | |||
| @@ -31,6 +31,12 @@ | |||
| 31 | #define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE) | 31 | #define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE) |
| 32 | #define PVCALLS_FRONT_MAX_SPIN 5000 | 32 | #define PVCALLS_FRONT_MAX_SPIN 5000 |
| 33 | 33 | ||
| 34 | static struct proto pvcalls_proto = { | ||
| 35 | .name = "PVCalls", | ||
| 36 | .owner = THIS_MODULE, | ||
| 37 | .obj_size = sizeof(struct sock), | ||
| 38 | }; | ||
| 39 | |||
| 34 | struct pvcalls_bedata { | 40 | struct pvcalls_bedata { |
| 35 | struct xen_pvcalls_front_ring ring; | 41 | struct xen_pvcalls_front_ring ring; |
| 36 | grant_ref_t ref; | 42 | grant_ref_t ref; |
| @@ -335,6 +341,42 @@ int pvcalls_front_socket(struct socket *sock) | |||
| 335 | return ret; | 341 | return ret; |
| 336 | } | 342 | } |
| 337 | 343 | ||
| 344 | static void free_active_ring(struct sock_mapping *map) | ||
| 345 | { | ||
| 346 | if (!map->active.ring) | ||
| 347 | return; | ||
| 348 | |||
| 349 | free_pages((unsigned long)map->active.data.in, | ||
| 350 | map->active.ring->ring_order); | ||
| 351 | free_page((unsigned long)map->active.ring); | ||
| 352 | } | ||
| 353 | |||
| 354 | static int alloc_active_ring(struct sock_mapping *map) | ||
| 355 | { | ||
| 356 | void *bytes; | ||
| 357 | |||
| 358 | map->active.ring = (struct pvcalls_data_intf *) | ||
| 359 | get_zeroed_page(GFP_KERNEL); | ||
| 360 | if (!map->active.ring) | ||
| 361 | goto out; | ||
| 362 | |||
| 363 | map->active.ring->ring_order = PVCALLS_RING_ORDER; | ||
| 364 | bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
| 365 | PVCALLS_RING_ORDER); | ||
| 366 | if (!bytes) | ||
| 367 | goto out; | ||
| 368 | |||
| 369 | map->active.data.in = bytes; | ||
| 370 | map->active.data.out = bytes + | ||
| 371 | XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); | ||
| 372 | |||
| 373 | return 0; | ||
| 374 | |||
| 375 | out: | ||
| 376 | free_active_ring(map); | ||
| 377 | return -ENOMEM; | ||
| 378 | } | ||
| 379 | |||
| 338 | static int create_active(struct sock_mapping *map, int *evtchn) | 380 | static int create_active(struct sock_mapping *map, int *evtchn) |
| 339 | { | 381 | { |
| 340 | void *bytes; | 382 | void *bytes; |
| @@ -343,15 +385,7 @@ static int create_active(struct sock_mapping *map, int *evtchn) | |||
| 343 | *evtchn = -1; | 385 | *evtchn = -1; |
| 344 | init_waitqueue_head(&map->active.inflight_conn_req); | 386 | init_waitqueue_head(&map->active.inflight_conn_req); |
| 345 | 387 | ||
| 346 | map->active.ring = (struct pvcalls_data_intf *) | 388 | bytes = map->active.data.in; |
| 347 | __get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
| 348 | if (map->active.ring == NULL) | ||
| 349 | goto out_error; | ||
| 350 | map->active.ring->ring_order = PVCALLS_RING_ORDER; | ||
| 351 | bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
| 352 | PVCALLS_RING_ORDER); | ||
| 353 | if (bytes == NULL) | ||
| 354 | goto out_error; | ||
| 355 | for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) | 389 | for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) |
| 356 | map->active.ring->ref[i] = gnttab_grant_foreign_access( | 390 | map->active.ring->ref[i] = gnttab_grant_foreign_access( |
| 357 | pvcalls_front_dev->otherend_id, | 391 | pvcalls_front_dev->otherend_id, |
| @@ -361,10 +395,6 @@ static int create_active(struct sock_mapping *map, int *evtchn) | |||
| 361 | pvcalls_front_dev->otherend_id, | 395 | pvcalls_front_dev->otherend_id, |
| 362 | pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0); | 396 | pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0); |
| 363 | 397 | ||
| 364 | map->active.data.in = bytes; | ||
| 365 | map->active.data.out = bytes + | ||
| 366 | XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); | ||
| 367 | |||
| 368 | ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn); | 398 | ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn); |
| 369 | if (ret) | 399 | if (ret) |
| 370 | goto out_error; | 400 | goto out_error; |
| @@ -385,8 +415,6 @@ static int create_active(struct sock_mapping *map, int *evtchn) | |||
| 385 | out_error: | 415 | out_error: |
| 386 | if (*evtchn >= 0) | 416 | if (*evtchn >= 0) |
| 387 | xenbus_free_evtchn(pvcalls_front_dev, *evtchn); | 417 | xenbus_free_evtchn(pvcalls_front_dev, *evtchn); |
| 388 | free_pages((unsigned long)map->active.data.in, PVCALLS_RING_ORDER); | ||
| 389 | free_page((unsigned long)map->active.ring); | ||
| 390 | return ret; | 418 | return ret; |
| 391 | } | 419 | } |
| 392 | 420 | ||
| @@ -406,17 +434,24 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, | |||
| 406 | return PTR_ERR(map); | 434 | return PTR_ERR(map); |
| 407 | 435 | ||
| 408 | bedata = dev_get_drvdata(&pvcalls_front_dev->dev); | 436 | bedata = dev_get_drvdata(&pvcalls_front_dev->dev); |
| 437 | ret = alloc_active_ring(map); | ||
| 438 | if (ret < 0) { | ||
| 439 | pvcalls_exit_sock(sock); | ||
| 440 | return ret; | ||
| 441 | } | ||
| 409 | 442 | ||
| 410 | spin_lock(&bedata->socket_lock); | 443 | spin_lock(&bedata->socket_lock); |
| 411 | ret = get_request(bedata, &req_id); | 444 | ret = get_request(bedata, &req_id); |
| 412 | if (ret < 0) { | 445 | if (ret < 0) { |
| 413 | spin_unlock(&bedata->socket_lock); | 446 | spin_unlock(&bedata->socket_lock); |
| 447 | free_active_ring(map); | ||
| 414 | pvcalls_exit_sock(sock); | 448 | pvcalls_exit_sock(sock); |
| 415 | return ret; | 449 | return ret; |
| 416 | } | 450 | } |
| 417 | ret = create_active(map, &evtchn); | 451 | ret = create_active(map, &evtchn); |
| 418 | if (ret < 0) { | 452 | if (ret < 0) { |
| 419 | spin_unlock(&bedata->socket_lock); | 453 | spin_unlock(&bedata->socket_lock); |
| 454 | free_active_ring(map); | ||
| 420 | pvcalls_exit_sock(sock); | 455 | pvcalls_exit_sock(sock); |
| 421 | return ret; | 456 | return ret; |
| 422 | } | 457 | } |
| @@ -469,8 +504,10 @@ static int __write_ring(struct pvcalls_data_intf *intf, | |||
| 469 | virt_mb(); | 504 | virt_mb(); |
| 470 | 505 | ||
| 471 | size = pvcalls_queued(prod, cons, array_size); | 506 | size = pvcalls_queued(prod, cons, array_size); |
| 472 | if (size >= array_size) | 507 | if (size > array_size) |
| 473 | return -EINVAL; | 508 | return -EINVAL; |
| 509 | if (size == array_size) | ||
| 510 | return 0; | ||
| 474 | if (len > array_size - size) | 511 | if (len > array_size - size) |
| 475 | len = array_size - size; | 512 | len = array_size - size; |
| 476 | 513 | ||
| @@ -560,15 +597,13 @@ static int __read_ring(struct pvcalls_data_intf *intf, | |||
| 560 | error = intf->in_error; | 597 | error = intf->in_error; |
| 561 | /* get pointers before reading from the ring */ | 598 | /* get pointers before reading from the ring */ |
| 562 | virt_rmb(); | 599 | virt_rmb(); |
| 563 | if (error < 0) | ||
| 564 | return error; | ||
| 565 | 600 | ||
| 566 | size = pvcalls_queued(prod, cons, array_size); | 601 | size = pvcalls_queued(prod, cons, array_size); |
| 567 | masked_prod = pvcalls_mask(prod, array_size); | 602 | masked_prod = pvcalls_mask(prod, array_size); |
| 568 | masked_cons = pvcalls_mask(cons, array_size); | 603 | masked_cons = pvcalls_mask(cons, array_size); |
| 569 | 604 | ||
| 570 | if (size == 0) | 605 | if (size == 0) |
| 571 | return 0; | 606 | return error ?: size; |
| 572 | 607 | ||
| 573 | if (len > size) | 608 | if (len > size) |
| 574 | len = size; | 609 | len = size; |
| @@ -780,25 +815,36 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) | |||
| 780 | } | 815 | } |
| 781 | } | 816 | } |
| 782 | 817 | ||
| 783 | spin_lock(&bedata->socket_lock); | 818 | map2 = kzalloc(sizeof(*map2), GFP_KERNEL); |
| 784 | ret = get_request(bedata, &req_id); | 819 | if (map2 == NULL) { |
| 785 | if (ret < 0) { | ||
| 786 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, | 820 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, |
| 787 | (void *)&map->passive.flags); | 821 | (void *)&map->passive.flags); |
| 788 | spin_unlock(&bedata->socket_lock); | 822 | pvcalls_exit_sock(sock); |
| 823 | return -ENOMEM; | ||
| 824 | } | ||
| 825 | ret = alloc_active_ring(map2); | ||
| 826 | if (ret < 0) { | ||
| 827 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, | ||
| 828 | (void *)&map->passive.flags); | ||
| 829 | kfree(map2); | ||
| 789 | pvcalls_exit_sock(sock); | 830 | pvcalls_exit_sock(sock); |
| 790 | return ret; | 831 | return ret; |
| 791 | } | 832 | } |
| 792 | map2 = kzalloc(sizeof(*map2), GFP_ATOMIC); | 833 | spin_lock(&bedata->socket_lock); |
| 793 | if (map2 == NULL) { | 834 | ret = get_request(bedata, &req_id); |
| 835 | if (ret < 0) { | ||
| 794 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, | 836 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, |
| 795 | (void *)&map->passive.flags); | 837 | (void *)&map->passive.flags); |
| 796 | spin_unlock(&bedata->socket_lock); | 838 | spin_unlock(&bedata->socket_lock); |
| 839 | free_active_ring(map2); | ||
| 840 | kfree(map2); | ||
| 797 | pvcalls_exit_sock(sock); | 841 | pvcalls_exit_sock(sock); |
| 798 | return -ENOMEM; | 842 | return ret; |
| 799 | } | 843 | } |
| 844 | |||
| 800 | ret = create_active(map2, &evtchn); | 845 | ret = create_active(map2, &evtchn); |
| 801 | if (ret < 0) { | 846 | if (ret < 0) { |
| 847 | free_active_ring(map2); | ||
| 802 | kfree(map2); | 848 | kfree(map2); |
| 803 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, | 849 | clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, |
| 804 | (void *)&map->passive.flags); | 850 | (void *)&map->passive.flags); |
| @@ -839,7 +885,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) | |||
| 839 | 885 | ||
| 840 | received: | 886 | received: |
| 841 | map2->sock = newsock; | 887 | map2->sock = newsock; |
| 842 | newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL); | 888 | newsock->sk = sk_alloc(sock_net(sock->sk), PF_INET, GFP_KERNEL, &pvcalls_proto, false); |
| 843 | if (!newsock->sk) { | 889 | if (!newsock->sk) { |
| 844 | bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; | 890 | bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; |
| 845 | map->passive.inflight_req_id = PVCALLS_INVALID_ID; | 891 | map->passive.inflight_req_id = PVCALLS_INVALID_ID; |
| @@ -1032,8 +1078,8 @@ int pvcalls_front_release(struct socket *sock) | |||
| 1032 | spin_lock(&bedata->socket_lock); | 1078 | spin_lock(&bedata->socket_lock); |
| 1033 | list_del(&map->list); | 1079 | list_del(&map->list); |
| 1034 | spin_unlock(&bedata->socket_lock); | 1080 | spin_unlock(&bedata->socket_lock); |
| 1035 | if (READ_ONCE(map->passive.inflight_req_id) != | 1081 | if (READ_ONCE(map->passive.inflight_req_id) != PVCALLS_INVALID_ID && |
| 1036 | PVCALLS_INVALID_ID) { | 1082 | READ_ONCE(map->passive.inflight_req_id) != 0) { |
| 1037 | pvcalls_front_free_map(bedata, | 1083 | pvcalls_front_free_map(bedata, |
| 1038 | map->passive.accept_map); | 1084 | map->passive.accept_map); |
| 1039 | } | 1085 | } |
