.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * VMware vSockets Driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2007-2013 VMware, Inc. All rights reserved. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License as published by the Free |
---|
8 | | - * Software Foundation version 2 and no later version. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
11 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
12 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
13 | | - * more details. |
---|
14 | 6 | */ |
---|
15 | 7 | |
---|
16 | 8 | /* Implementation notes: |
---|
.. | .. |
---|
134 | 126 | */ |
---|
135 | 127 | #define VSOCK_DEFAULT_CONNECT_TIMEOUT (2 * HZ) |
---|
136 | 128 | |
---|
137 | | -static const struct vsock_transport *transport; |
---|
| 129 | +#define VSOCK_DEFAULT_BUFFER_SIZE (1024 * 256) |
---|
| 130 | +#define VSOCK_DEFAULT_BUFFER_MAX_SIZE (1024 * 256) |
---|
| 131 | +#define VSOCK_DEFAULT_BUFFER_MIN_SIZE 128 |
---|
| 132 | + |
---|
| 133 | +/* Transport used for host->guest communication */ |
---|
| 134 | +static const struct vsock_transport *transport_h2g; |
---|
| 135 | +/* Transport used for guest->host communication */ |
---|
| 136 | +static const struct vsock_transport *transport_g2h; |
---|
| 137 | +/* Transport used for DGRAM communication */ |
---|
| 138 | +static const struct vsock_transport *transport_dgram; |
---|
| 139 | +/* Transport used for local communication */ |
---|
| 140 | +static const struct vsock_transport *transport_local; |
---|
138 | 141 | static DEFINE_MUTEX(vsock_register_mutex); |
---|
139 | | - |
---|
140 | | -/**** EXPORTS ****/ |
---|
141 | | - |
---|
142 | | -/* Get the ID of the local context. This is transport dependent. */ |
---|
143 | | - |
---|
144 | | -int vm_sockets_get_local_cid(void) |
---|
145 | | -{ |
---|
146 | | - return transport->get_local_cid(); |
---|
147 | | -} |
---|
148 | | -EXPORT_SYMBOL_GPL(vm_sockets_get_local_cid); |
---|
149 | 142 | |
---|
150 | 143 | /**** UTILS ****/ |
---|
151 | 144 | |
---|
.. | .. |
---|
196 | 189 | return __vsock_bind(sk, &local_addr); |
---|
197 | 190 | } |
---|
198 | 191 | |
---|
199 | | -static int __init vsock_init_tables(void) |
---|
| 192 | +static void vsock_init_tables(void) |
---|
200 | 193 | { |
---|
201 | 194 | int i; |
---|
202 | 195 | |
---|
.. | .. |
---|
205 | 198 | |
---|
206 | 199 | for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) |
---|
207 | 200 | INIT_LIST_HEAD(&vsock_connected_table[i]); |
---|
208 | | - return 0; |
---|
209 | 201 | } |
---|
210 | 202 | |
---|
211 | 203 | static void __vsock_insert_bound(struct list_head *list, |
---|
.. | .. |
---|
238 | 230 | { |
---|
239 | 231 | struct vsock_sock *vsk; |
---|
240 | 232 | |
---|
241 | | - list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table) |
---|
242 | | - if (addr->svm_port == vsk->local_addr.svm_port) |
---|
| 233 | + list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table) { |
---|
| 234 | + if (vsock_addr_equals_addr(addr, &vsk->local_addr)) |
---|
243 | 235 | return sk_vsock(vsk); |
---|
| 236 | + |
---|
| 237 | + if (addr->svm_port == vsk->local_addr.svm_port && |
---|
| 238 | + (vsk->local_addr.svm_cid == VMADDR_CID_ANY || |
---|
| 239 | + addr->svm_cid == VMADDR_CID_ANY)) |
---|
| 240 | + return sk_vsock(vsk); |
---|
| 241 | + } |
---|
244 | 242 | |
---|
245 | 243 | return NULL; |
---|
246 | 244 | } |
---|
.. | .. |
---|
390 | 388 | } |
---|
391 | 389 | EXPORT_SYMBOL_GPL(vsock_enqueue_accept); |
---|
392 | 390 | |
---|
| 391 | +static bool vsock_use_local_transport(unsigned int remote_cid) |
---|
| 392 | +{ |
---|
| 393 | + if (!transport_local) |
---|
| 394 | + return false; |
---|
| 395 | + |
---|
| 396 | + if (remote_cid == VMADDR_CID_LOCAL) |
---|
| 397 | + return true; |
---|
| 398 | + |
---|
| 399 | + if (transport_g2h) { |
---|
| 400 | + return remote_cid == transport_g2h->get_local_cid(); |
---|
| 401 | + } else { |
---|
| 402 | + return remote_cid == VMADDR_CID_HOST; |
---|
| 403 | + } |
---|
| 404 | +} |
---|
| 405 | + |
---|
| 406 | +static void vsock_deassign_transport(struct vsock_sock *vsk) |
---|
| 407 | +{ |
---|
| 408 | + if (!vsk->transport) |
---|
| 409 | + return; |
---|
| 410 | + |
---|
| 411 | + vsk->transport->destruct(vsk); |
---|
| 412 | + module_put(vsk->transport->module); |
---|
| 413 | + vsk->transport = NULL; |
---|
| 414 | +} |
---|
| 415 | + |
---|
| 416 | +/* Assign a transport to a socket and call the .init transport callback. |
---|
| 417 | + * |
---|
| 418 | + * Note: for stream socket this must be called when vsk->remote_addr is set |
---|
| 419 | + * (e.g. during the connect() or when a connection request on a listener |
---|
| 420 | + * socket is received). |
---|
| 421 | + * The vsk->remote_addr is used to decide which transport to use: |
---|
| 422 | + * - remote CID == VMADDR_CID_LOCAL or g2h->local_cid or VMADDR_CID_HOST if |
---|
| 423 | + * g2h is not loaded, will use local transport; |
---|
| 424 | + * - remote CID <= VMADDR_CID_HOST will use guest->host transport; |
---|
| 425 | + * - remote CID > VMADDR_CID_HOST will use host->guest transport; |
---|
| 426 | + */ |
---|
| 427 | +int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk) |
---|
| 428 | +{ |
---|
| 429 | + const struct vsock_transport *new_transport; |
---|
| 430 | + struct sock *sk = sk_vsock(vsk); |
---|
| 431 | + unsigned int remote_cid = vsk->remote_addr.svm_cid; |
---|
| 432 | + int ret; |
---|
| 433 | + |
---|
| 434 | + switch (sk->sk_type) { |
---|
| 435 | + case SOCK_DGRAM: |
---|
| 436 | + new_transport = transport_dgram; |
---|
| 437 | + break; |
---|
| 438 | + case SOCK_STREAM: |
---|
| 439 | + if (vsock_use_local_transport(remote_cid)) |
---|
| 440 | + new_transport = transport_local; |
---|
| 441 | + else if (remote_cid <= VMADDR_CID_HOST || !transport_h2g) |
---|
| 442 | + new_transport = transport_g2h; |
---|
| 443 | + else |
---|
| 444 | + new_transport = transport_h2g; |
---|
| 445 | + break; |
---|
| 446 | + default: |
---|
| 447 | + return -ESOCKTNOSUPPORT; |
---|
| 448 | + } |
---|
| 449 | + |
---|
| 450 | + if (vsk->transport) { |
---|
| 451 | + if (vsk->transport == new_transport) |
---|
| 452 | + return 0; |
---|
| 453 | + |
---|
| 454 | + /* transport->release() must be called with sock lock acquired. |
---|
| 455 | + * This path can only be taken during vsock_stream_connect(), |
---|
| 456 | + * where we have already held the sock lock. |
---|
| 457 | + * In the other cases, this function is called on a new socket |
---|
| 458 | + * which is not assigned to any transport. |
---|
| 459 | + */ |
---|
| 460 | + vsk->transport->release(vsk); |
---|
| 461 | + vsock_deassign_transport(vsk); |
---|
| 462 | + } |
---|
| 463 | + |
---|
| 464 | + /* We increase the module refcnt to prevent the transport unloading |
---|
| 465 | + * while there are open sockets assigned to it. |
---|
| 466 | + */ |
---|
| 467 | + if (!new_transport || !try_module_get(new_transport->module)) |
---|
| 468 | + return -ENODEV; |
---|
| 469 | + |
---|
| 470 | + ret = new_transport->init(vsk, psk); |
---|
| 471 | + if (ret) { |
---|
| 472 | + module_put(new_transport->module); |
---|
| 473 | + return ret; |
---|
| 474 | + } |
---|
| 475 | + |
---|
| 476 | + vsk->transport = new_transport; |
---|
| 477 | + |
---|
| 478 | + return 0; |
---|
| 479 | +} |
---|
| 480 | +EXPORT_SYMBOL_GPL(vsock_assign_transport); |
---|
| 481 | + |
---|
| 482 | +bool vsock_find_cid(unsigned int cid) |
---|
| 483 | +{ |
---|
| 484 | + if (transport_g2h && cid == transport_g2h->get_local_cid()) |
---|
| 485 | + return true; |
---|
| 486 | + |
---|
| 487 | + if (transport_h2g && cid == VMADDR_CID_HOST) |
---|
| 488 | + return true; |
---|
| 489 | + |
---|
| 490 | + if (transport_local && cid == VMADDR_CID_LOCAL) |
---|
| 491 | + return true; |
---|
| 492 | + |
---|
| 493 | + return false; |
---|
| 494 | +} |
---|
| 495 | +EXPORT_SYMBOL_GPL(vsock_find_cid); |
---|
| 496 | + |
---|
393 | 497 | static struct sock *vsock_dequeue_accept(struct sock *listener) |
---|
394 | 498 | { |
---|
395 | 499 | struct vsock_sock *vlistener; |
---|
.. | .. |
---|
426 | 530 | |
---|
427 | 531 | static int vsock_send_shutdown(struct sock *sk, int mode) |
---|
428 | 532 | { |
---|
429 | | - return transport->shutdown(vsock_sk(sk), mode); |
---|
| 533 | + struct vsock_sock *vsk = vsock_sk(sk); |
---|
| 534 | + |
---|
| 535 | + if (!vsk->transport) |
---|
| 536 | + return -ENODEV; |
---|
| 537 | + |
---|
| 538 | + return vsk->transport->shutdown(vsk, mode); |
---|
430 | 539 | } |
---|
431 | 540 | |
---|
432 | 541 | static void vsock_pending_work(struct work_struct *work) |
---|
.. | .. |
---|
447 | 556 | if (vsock_is_pending(sk)) { |
---|
448 | 557 | vsock_remove_pending(listener, sk); |
---|
449 | 558 | |
---|
450 | | - listener->sk_ack_backlog--; |
---|
| 559 | + sk_acceptq_removed(listener); |
---|
451 | 560 | } else if (!vsk->rejected) { |
---|
452 | 561 | /* We are not on the pending list and accept() did not reject |
---|
453 | 562 | * us, so we must have been accepted by our user process. We |
---|
.. | .. |
---|
481 | 590 | static int __vsock_bind_stream(struct vsock_sock *vsk, |
---|
482 | 591 | struct sockaddr_vm *addr) |
---|
483 | 592 | { |
---|
484 | | - static u32 port = 0; |
---|
| 593 | + static u32 port; |
---|
485 | 594 | struct sockaddr_vm new_addr; |
---|
486 | 595 | |
---|
487 | 596 | if (!port) |
---|
.. | .. |
---|
536 | 645 | static int __vsock_bind_dgram(struct vsock_sock *vsk, |
---|
537 | 646 | struct sockaddr_vm *addr) |
---|
538 | 647 | { |
---|
539 | | - return transport->dgram_bind(vsk, addr); |
---|
| 648 | + return vsk->transport->dgram_bind(vsk, addr); |
---|
540 | 649 | } |
---|
541 | 650 | |
---|
542 | 651 | static int __vsock_bind(struct sock *sk, struct sockaddr_vm *addr) |
---|
543 | 652 | { |
---|
544 | 653 | struct vsock_sock *vsk = vsock_sk(sk); |
---|
545 | | - u32 cid; |
---|
546 | 654 | int retval; |
---|
547 | 655 | |
---|
548 | 656 | /* First ensure this socket isn't already bound. */ |
---|
.. | .. |
---|
552 | 660 | /* Now bind to the provided address or select appropriate values if |
---|
553 | 661 | * none are provided (VMADDR_CID_ANY and VMADDR_PORT_ANY). Note that |
---|
554 | 662 | * like AF_INET prevents binding to a non-local IP address (in most |
---|
555 | | - * cases), we only allow binding to the local CID. |
---|
| 663 | + * cases), we only allow binding to a local CID. |
---|
556 | 664 | */ |
---|
557 | | - cid = transport->get_local_cid(); |
---|
558 | | - if (addr->svm_cid != cid && addr->svm_cid != VMADDR_CID_ANY) |
---|
| 665 | + if (addr->svm_cid != VMADDR_CID_ANY && !vsock_find_cid(addr->svm_cid)) |
---|
559 | 666 | return -EADDRNOTAVAIL; |
---|
560 | 667 | |
---|
561 | 668 | switch (sk->sk_socket->type) { |
---|
.. | .. |
---|
579 | 686 | |
---|
580 | 687 | static void vsock_connect_timeout(struct work_struct *work); |
---|
581 | 688 | |
---|
582 | | -struct sock *__vsock_create(struct net *net, |
---|
583 | | - struct socket *sock, |
---|
584 | | - struct sock *parent, |
---|
585 | | - gfp_t priority, |
---|
586 | | - unsigned short type, |
---|
587 | | - int kern) |
---|
| 689 | +static struct sock *__vsock_create(struct net *net, |
---|
| 690 | + struct socket *sock, |
---|
| 691 | + struct sock *parent, |
---|
| 692 | + gfp_t priority, |
---|
| 693 | + unsigned short type, |
---|
| 694 | + int kern) |
---|
588 | 695 | { |
---|
589 | 696 | struct sock *sk; |
---|
590 | 697 | struct vsock_sock *psk; |
---|
.. | .. |
---|
628 | 735 | vsk->trusted = psk->trusted; |
---|
629 | 736 | vsk->owner = get_cred(psk->owner); |
---|
630 | 737 | vsk->connect_timeout = psk->connect_timeout; |
---|
| 738 | + vsk->buffer_size = psk->buffer_size; |
---|
| 739 | + vsk->buffer_min_size = psk->buffer_min_size; |
---|
| 740 | + vsk->buffer_max_size = psk->buffer_max_size; |
---|
631 | 741 | security_sk_clone(parent, sk); |
---|
632 | 742 | } else { |
---|
633 | 743 | vsk->trusted = ns_capable_noaudit(&init_user_ns, CAP_NET_ADMIN); |
---|
634 | 744 | vsk->owner = get_current_cred(); |
---|
635 | 745 | vsk->connect_timeout = VSOCK_DEFAULT_CONNECT_TIMEOUT; |
---|
| 746 | + vsk->buffer_size = VSOCK_DEFAULT_BUFFER_SIZE; |
---|
| 747 | + vsk->buffer_min_size = VSOCK_DEFAULT_BUFFER_MIN_SIZE; |
---|
| 748 | + vsk->buffer_max_size = VSOCK_DEFAULT_BUFFER_MAX_SIZE; |
---|
636 | 749 | } |
---|
637 | | - |
---|
638 | | - if (transport->init(vsk, psk) < 0) { |
---|
639 | | - sk_free(sk); |
---|
640 | | - return NULL; |
---|
641 | | - } |
---|
642 | | - |
---|
643 | | - if (sock) |
---|
644 | | - vsock_insert_unbound(vsk); |
---|
645 | 750 | |
---|
646 | 751 | return sk; |
---|
647 | 752 | } |
---|
648 | | -EXPORT_SYMBOL_GPL(__vsock_create); |
---|
649 | 753 | |
---|
650 | 754 | static void __vsock_release(struct sock *sk, int level) |
---|
651 | 755 | { |
---|
652 | 756 | if (sk) { |
---|
653 | | - struct sk_buff *skb; |
---|
654 | 757 | struct sock *pending; |
---|
655 | 758 | struct vsock_sock *vsk; |
---|
656 | 759 | |
---|
657 | 760 | vsk = vsock_sk(sk); |
---|
658 | 761 | pending = NULL; /* Compiler warning. */ |
---|
659 | | - |
---|
660 | | - /* The release call is supposed to use lock_sock_nested() |
---|
661 | | - * rather than lock_sock(), if a sock lock should be acquired. |
---|
662 | | - */ |
---|
663 | | - transport->release(vsk); |
---|
664 | 762 | |
---|
665 | 763 | /* When "level" is SINGLE_DEPTH_NESTING, use the nested |
---|
666 | 764 | * version to avoid the warning "possible recursive locking |
---|
.. | .. |
---|
668 | 766 | * is the same as lock_sock(sk). |
---|
669 | 767 | */ |
---|
670 | 768 | lock_sock_nested(sk, level); |
---|
| 769 | + |
---|
| 770 | + if (vsk->transport) |
---|
| 771 | + vsk->transport->release(vsk); |
---|
| 772 | + else if (sk->sk_type == SOCK_STREAM) |
---|
| 773 | + vsock_remove_sock(vsk); |
---|
| 774 | + |
---|
671 | 775 | sock_orphan(sk); |
---|
672 | 776 | sk->sk_shutdown = SHUTDOWN_MASK; |
---|
673 | 777 | |
---|
674 | | - while ((skb = skb_dequeue(&sk->sk_receive_queue))) |
---|
675 | | - kfree_skb(skb); |
---|
| 778 | + skb_queue_purge(&sk->sk_receive_queue); |
---|
676 | 779 | |
---|
677 | 780 | /* Clean up any sockets that never were accepted. */ |
---|
678 | 781 | while ((pending = vsock_dequeue_accept(sk)) != NULL) { |
---|
.. | .. |
---|
689 | 792 | { |
---|
690 | 793 | struct vsock_sock *vsk = vsock_sk(sk); |
---|
691 | 794 | |
---|
692 | | - transport->destruct(vsk); |
---|
| 795 | + vsock_deassign_transport(vsk); |
---|
693 | 796 | |
---|
694 | 797 | /* When clearing these addresses, there's no need to set the family and |
---|
695 | 798 | * possibly register the address family with the kernel. |
---|
.. | .. |
---|
711 | 814 | return err; |
---|
712 | 815 | } |
---|
713 | 816 | |
---|
| 817 | +struct sock *vsock_create_connected(struct sock *parent) |
---|
| 818 | +{ |
---|
| 819 | + return __vsock_create(sock_net(parent), NULL, parent, GFP_KERNEL, |
---|
| 820 | + parent->sk_type, 0); |
---|
| 821 | +} |
---|
| 822 | +EXPORT_SYMBOL_GPL(vsock_create_connected); |
---|
| 823 | + |
---|
714 | 824 | s64 vsock_stream_has_data(struct vsock_sock *vsk) |
---|
715 | 825 | { |
---|
716 | | - return transport->stream_has_data(vsk); |
---|
| 826 | + return vsk->transport->stream_has_data(vsk); |
---|
717 | 827 | } |
---|
718 | 828 | EXPORT_SYMBOL_GPL(vsock_stream_has_data); |
---|
719 | 829 | |
---|
720 | 830 | s64 vsock_stream_has_space(struct vsock_sock *vsk) |
---|
721 | 831 | { |
---|
722 | | - return transport->stream_has_space(vsk); |
---|
| 832 | + return vsk->transport->stream_has_space(vsk); |
---|
723 | 833 | } |
---|
724 | 834 | EXPORT_SYMBOL_GPL(vsock_stream_has_space); |
---|
725 | 835 | |
---|
.. | .. |
---|
890 | 1000 | mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND; |
---|
891 | 1001 | |
---|
892 | 1002 | } else if (sock->type == SOCK_STREAM) { |
---|
| 1003 | + const struct vsock_transport *transport; |
---|
| 1004 | + |
---|
893 | 1005 | lock_sock(sk); |
---|
| 1006 | + |
---|
| 1007 | + transport = vsk->transport; |
---|
894 | 1008 | |
---|
895 | 1009 | /* Listening sockets that have connections in their accept |
---|
896 | 1010 | * queue can be read. |
---|
.. | .. |
---|
900 | 1014 | mask |= EPOLLIN | EPOLLRDNORM; |
---|
901 | 1015 | |
---|
902 | 1016 | /* If there is something in the queue then we can read. */ |
---|
903 | | - if (transport->stream_is_active(vsk) && |
---|
| 1017 | + if (transport && transport->stream_is_active(vsk) && |
---|
904 | 1018 | !(sk->sk_shutdown & RCV_SHUTDOWN)) { |
---|
905 | 1019 | bool data_ready_now = false; |
---|
906 | 1020 | int ret = transport->notify_poll_in( |
---|
.. | .. |
---|
924 | 1038 | } |
---|
925 | 1039 | |
---|
926 | 1040 | /* Connected sockets that can produce data can be written. */ |
---|
927 | | - if (sk->sk_state == TCP_ESTABLISHED) { |
---|
| 1041 | + if (transport && sk->sk_state == TCP_ESTABLISHED) { |
---|
928 | 1042 | if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { |
---|
929 | 1043 | bool space_avail_now = false; |
---|
930 | 1044 | int ret = transport->notify_poll_out( |
---|
.. | .. |
---|
965 | 1079 | struct sock *sk; |
---|
966 | 1080 | struct vsock_sock *vsk; |
---|
967 | 1081 | struct sockaddr_vm *remote_addr; |
---|
| 1082 | + const struct vsock_transport *transport; |
---|
968 | 1083 | |
---|
969 | 1084 | if (msg->msg_flags & MSG_OOB) |
---|
970 | 1085 | return -EOPNOTSUPP; |
---|
.. | .. |
---|
975 | 1090 | vsk = vsock_sk(sk); |
---|
976 | 1091 | |
---|
977 | 1092 | lock_sock(sk); |
---|
| 1093 | + |
---|
| 1094 | + transport = vsk->transport; |
---|
978 | 1095 | |
---|
979 | 1096 | err = vsock_auto_bind(vsk); |
---|
980 | 1097 | if (err) |
---|
.. | .. |
---|
1057 | 1174 | if (err) |
---|
1058 | 1175 | goto out; |
---|
1059 | 1176 | |
---|
1060 | | - if (!transport->dgram_allow(remote_addr->svm_cid, |
---|
1061 | | - remote_addr->svm_port)) { |
---|
| 1177 | + if (!vsk->transport->dgram_allow(remote_addr->svm_cid, |
---|
| 1178 | + remote_addr->svm_port)) { |
---|
1062 | 1179 | err = -EINVAL; |
---|
1063 | 1180 | goto out; |
---|
1064 | 1181 | } |
---|
.. | .. |
---|
1074 | 1191 | static int vsock_dgram_recvmsg(struct socket *sock, struct msghdr *msg, |
---|
1075 | 1192 | size_t len, int flags) |
---|
1076 | 1193 | { |
---|
1077 | | - return transport->dgram_dequeue(vsock_sk(sock->sk), msg, len, flags); |
---|
| 1194 | + struct vsock_sock *vsk = vsock_sk(sock->sk); |
---|
| 1195 | + |
---|
| 1196 | + return vsk->transport->dgram_dequeue(vsk, msg, len, flags); |
---|
1078 | 1197 | } |
---|
1079 | 1198 | |
---|
1080 | 1199 | static const struct proto_ops vsock_dgram_ops = { |
---|
.. | .. |
---|
1090 | 1209 | .ioctl = sock_no_ioctl, |
---|
1091 | 1210 | .listen = sock_no_listen, |
---|
1092 | 1211 | .shutdown = vsock_shutdown, |
---|
1093 | | - .setsockopt = sock_no_setsockopt, |
---|
1094 | | - .getsockopt = sock_no_getsockopt, |
---|
1095 | 1212 | .sendmsg = vsock_dgram_sendmsg, |
---|
1096 | 1213 | .recvmsg = vsock_dgram_recvmsg, |
---|
1097 | 1214 | .mmap = sock_no_mmap, |
---|
.. | .. |
---|
1100 | 1217 | |
---|
1101 | 1218 | static int vsock_transport_cancel_pkt(struct vsock_sock *vsk) |
---|
1102 | 1219 | { |
---|
1103 | | - if (!transport->cancel_pkt) |
---|
| 1220 | + const struct vsock_transport *transport = vsk->transport; |
---|
| 1221 | + |
---|
| 1222 | + if (!transport || !transport->cancel_pkt) |
---|
1104 | 1223 | return -EOPNOTSUPP; |
---|
1105 | 1224 | |
---|
1106 | 1225 | return transport->cancel_pkt(vsk); |
---|
.. | .. |
---|
1118 | 1237 | if (sk->sk_state == TCP_SYN_SENT && |
---|
1119 | 1238 | (sk->sk_shutdown != SHUTDOWN_MASK)) { |
---|
1120 | 1239 | sk->sk_state = TCP_CLOSE; |
---|
| 1240 | + sk->sk_socket->state = SS_UNCONNECTED; |
---|
1121 | 1241 | sk->sk_err = ETIMEDOUT; |
---|
1122 | 1242 | sk->sk_error_report(sk); |
---|
1123 | 1243 | vsock_transport_cancel_pkt(vsk); |
---|
.. | .. |
---|
1133 | 1253 | int err; |
---|
1134 | 1254 | struct sock *sk; |
---|
1135 | 1255 | struct vsock_sock *vsk; |
---|
| 1256 | + const struct vsock_transport *transport; |
---|
1136 | 1257 | struct sockaddr_vm *remote_addr; |
---|
1137 | 1258 | long timeout; |
---|
1138 | 1259 | DEFINE_WAIT(wait); |
---|
.. | .. |
---|
1169 | 1290 | goto out; |
---|
1170 | 1291 | } |
---|
1171 | 1292 | |
---|
| 1293 | + /* Set the remote address that we are connecting to. */ |
---|
| 1294 | + memcpy(&vsk->remote_addr, remote_addr, |
---|
| 1295 | + sizeof(vsk->remote_addr)); |
---|
| 1296 | + |
---|
| 1297 | + err = vsock_assign_transport(vsk, NULL); |
---|
| 1298 | + if (err) |
---|
| 1299 | + goto out; |
---|
| 1300 | + |
---|
| 1301 | + transport = vsk->transport; |
---|
| 1302 | + |
---|
1172 | 1303 | /* The hypervisor and well-known contexts do not have socket |
---|
1173 | 1304 | * endpoints. |
---|
1174 | 1305 | */ |
---|
1175 | | - if (!transport->stream_allow(remote_addr->svm_cid, |
---|
| 1306 | + if (!transport || |
---|
| 1307 | + !transport->stream_allow(remote_addr->svm_cid, |
---|
1176 | 1308 | remote_addr->svm_port)) { |
---|
1177 | 1309 | err = -ENETUNREACH; |
---|
1178 | 1310 | goto out; |
---|
1179 | 1311 | } |
---|
1180 | | - |
---|
1181 | | - /* Set the remote address that we are connecting to. */ |
---|
1182 | | - memcpy(&vsk->remote_addr, remote_addr, |
---|
1183 | | - sizeof(vsk->remote_addr)); |
---|
1184 | 1312 | |
---|
1185 | 1313 | err = vsock_auto_bind(vsk); |
---|
1186 | 1314 | if (err) |
---|
.. | .. |
---|
1215 | 1343 | * timeout fires. |
---|
1216 | 1344 | */ |
---|
1217 | 1345 | sock_hold(sk); |
---|
1218 | | - schedule_delayed_work(&vsk->connect_work, timeout); |
---|
| 1346 | + |
---|
| 1347 | + /* If the timeout function is already scheduled, |
---|
| 1348 | + * reschedule it, then ungrab the socket refcount to |
---|
| 1349 | + * keep it balanced. |
---|
| 1350 | + */ |
---|
| 1351 | + if (mod_delayed_work(system_wq, &vsk->connect_work, |
---|
| 1352 | + timeout)) |
---|
| 1353 | + sock_put(sk); |
---|
1219 | 1354 | |
---|
1220 | 1355 | /* Skip ahead to preserve error code set above. */ |
---|
1221 | 1356 | goto out_wait; |
---|
.. | .. |
---|
1232 | 1367 | vsock_transport_cancel_pkt(vsk); |
---|
1233 | 1368 | vsock_remove_connected(vsk); |
---|
1234 | 1369 | goto out_wait; |
---|
1235 | | - } else if (timeout == 0) { |
---|
| 1370 | + } else if ((sk->sk_state != TCP_ESTABLISHED) && (timeout == 0)) { |
---|
1236 | 1371 | err = -ETIMEDOUT; |
---|
1237 | 1372 | sk->sk_state = TCP_CLOSE; |
---|
1238 | 1373 | sock->state = SS_UNCONNECTED; |
---|
.. | .. |
---|
1312 | 1447 | err = -listener->sk_err; |
---|
1313 | 1448 | |
---|
1314 | 1449 | if (connected) { |
---|
1315 | | - listener->sk_ack_backlog--; |
---|
| 1450 | + sk_acceptq_removed(listener); |
---|
1316 | 1451 | |
---|
1317 | 1452 | lock_sock_nested(connected, SINGLE_DEPTH_NESTING); |
---|
1318 | 1453 | vconnected = vsock_sk(connected); |
---|
.. | .. |
---|
1377 | 1512 | return err; |
---|
1378 | 1513 | } |
---|
1379 | 1514 | |
---|
| 1515 | +static void vsock_update_buffer_size(struct vsock_sock *vsk, |
---|
| 1516 | + const struct vsock_transport *transport, |
---|
| 1517 | + u64 val) |
---|
| 1518 | +{ |
---|
| 1519 | + if (val > vsk->buffer_max_size) |
---|
| 1520 | + val = vsk->buffer_max_size; |
---|
| 1521 | + |
---|
| 1522 | + if (val < vsk->buffer_min_size) |
---|
| 1523 | + val = vsk->buffer_min_size; |
---|
| 1524 | + |
---|
| 1525 | + if (val != vsk->buffer_size && |
---|
| 1526 | + transport && transport->notify_buffer_size) |
---|
| 1527 | + transport->notify_buffer_size(vsk, &val); |
---|
| 1528 | + |
---|
| 1529 | + vsk->buffer_size = val; |
---|
| 1530 | +} |
---|
| 1531 | + |
---|
1380 | 1532 | static int vsock_stream_setsockopt(struct socket *sock, |
---|
1381 | 1533 | int level, |
---|
1382 | 1534 | int optname, |
---|
1383 | | - char __user *optval, |
---|
| 1535 | + sockptr_t optval, |
---|
1384 | 1536 | unsigned int optlen) |
---|
1385 | 1537 | { |
---|
1386 | 1538 | int err; |
---|
1387 | 1539 | struct sock *sk; |
---|
1388 | 1540 | struct vsock_sock *vsk; |
---|
| 1541 | + const struct vsock_transport *transport; |
---|
1389 | 1542 | u64 val; |
---|
1390 | 1543 | |
---|
1391 | 1544 | if (level != AF_VSOCK) |
---|
.. | .. |
---|
1397 | 1550 | err = -EINVAL; \ |
---|
1398 | 1551 | goto exit; \ |
---|
1399 | 1552 | } \ |
---|
1400 | | - if (copy_from_user(&_v, optval, sizeof(_v)) != 0) { \ |
---|
| 1553 | + if (copy_from_sockptr(&_v, optval, sizeof(_v)) != 0) { \ |
---|
1401 | 1554 | err = -EFAULT; \ |
---|
1402 | 1555 | goto exit; \ |
---|
1403 | 1556 | } \ |
---|
.. | .. |
---|
1409 | 1562 | |
---|
1410 | 1563 | lock_sock(sk); |
---|
1411 | 1564 | |
---|
| 1565 | + transport = vsk->transport; |
---|
| 1566 | + |
---|
1412 | 1567 | switch (optname) { |
---|
1413 | 1568 | case SO_VM_SOCKETS_BUFFER_SIZE: |
---|
1414 | 1569 | COPY_IN(val); |
---|
1415 | | - transport->set_buffer_size(vsk, val); |
---|
| 1570 | + vsock_update_buffer_size(vsk, transport, val); |
---|
1416 | 1571 | break; |
---|
1417 | 1572 | |
---|
1418 | 1573 | case SO_VM_SOCKETS_BUFFER_MAX_SIZE: |
---|
1419 | 1574 | COPY_IN(val); |
---|
1420 | | - transport->set_max_buffer_size(vsk, val); |
---|
| 1575 | + vsk->buffer_max_size = val; |
---|
| 1576 | + vsock_update_buffer_size(vsk, transport, vsk->buffer_size); |
---|
1421 | 1577 | break; |
---|
1422 | 1578 | |
---|
1423 | 1579 | case SO_VM_SOCKETS_BUFFER_MIN_SIZE: |
---|
1424 | 1580 | COPY_IN(val); |
---|
1425 | | - transport->set_min_buffer_size(vsk, val); |
---|
| 1581 | + vsk->buffer_min_size = val; |
---|
| 1582 | + vsock_update_buffer_size(vsk, transport, vsk->buffer_size); |
---|
1426 | 1583 | break; |
---|
1427 | 1584 | |
---|
1428 | 1585 | case SO_VM_SOCKETS_CONNECT_TIMEOUT: { |
---|
1429 | | - struct timeval tv; |
---|
| 1586 | + struct __kernel_old_timeval tv; |
---|
1430 | 1587 | COPY_IN(tv); |
---|
1431 | 1588 | if (tv.tv_sec >= 0 && tv.tv_usec < USEC_PER_SEC && |
---|
1432 | 1589 | tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1)) { |
---|
.. | .. |
---|
1489 | 1646 | |
---|
1490 | 1647 | switch (optname) { |
---|
1491 | 1648 | case SO_VM_SOCKETS_BUFFER_SIZE: |
---|
1492 | | - val = transport->get_buffer_size(vsk); |
---|
| 1649 | + val = vsk->buffer_size; |
---|
1493 | 1650 | COPY_OUT(val); |
---|
1494 | 1651 | break; |
---|
1495 | 1652 | |
---|
1496 | 1653 | case SO_VM_SOCKETS_BUFFER_MAX_SIZE: |
---|
1497 | | - val = transport->get_max_buffer_size(vsk); |
---|
| 1654 | + val = vsk->buffer_max_size; |
---|
1498 | 1655 | COPY_OUT(val); |
---|
1499 | 1656 | break; |
---|
1500 | 1657 | |
---|
1501 | 1658 | case SO_VM_SOCKETS_BUFFER_MIN_SIZE: |
---|
1502 | | - val = transport->get_min_buffer_size(vsk); |
---|
| 1659 | + val = vsk->buffer_min_size; |
---|
1503 | 1660 | COPY_OUT(val); |
---|
1504 | 1661 | break; |
---|
1505 | 1662 | |
---|
1506 | 1663 | case SO_VM_SOCKETS_CONNECT_TIMEOUT: { |
---|
1507 | | - struct timeval tv; |
---|
| 1664 | + struct __kernel_old_timeval tv; |
---|
1508 | 1665 | tv.tv_sec = vsk->connect_timeout / HZ; |
---|
1509 | 1666 | tv.tv_usec = |
---|
1510 | 1667 | (vsk->connect_timeout - |
---|
.. | .. |
---|
1530 | 1687 | { |
---|
1531 | 1688 | struct sock *sk; |
---|
1532 | 1689 | struct vsock_sock *vsk; |
---|
| 1690 | + const struct vsock_transport *transport; |
---|
1533 | 1691 | ssize_t total_written; |
---|
1534 | 1692 | long timeout; |
---|
1535 | 1693 | int err; |
---|
.. | .. |
---|
1546 | 1704 | |
---|
1547 | 1705 | lock_sock(sk); |
---|
1548 | 1706 | |
---|
| 1707 | + transport = vsk->transport; |
---|
| 1708 | + |
---|
1549 | 1709 | /* Callers should not provide a destination with stream sockets. */ |
---|
1550 | 1710 | if (msg->msg_namelen) { |
---|
1551 | 1711 | err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; |
---|
.. | .. |
---|
1559 | 1719 | goto out; |
---|
1560 | 1720 | } |
---|
1561 | 1721 | |
---|
1562 | | - if (sk->sk_state != TCP_ESTABLISHED || |
---|
| 1722 | + if (!transport || sk->sk_state != TCP_ESTABLISHED || |
---|
1563 | 1723 | !vsock_addr_bound(&vsk->local_addr)) { |
---|
1564 | 1724 | err = -ENOTCONN; |
---|
1565 | 1725 | goto out; |
---|
.. | .. |
---|
1669 | 1829 | { |
---|
1670 | 1830 | struct sock *sk; |
---|
1671 | 1831 | struct vsock_sock *vsk; |
---|
| 1832 | + const struct vsock_transport *transport; |
---|
1672 | 1833 | int err; |
---|
1673 | 1834 | size_t target; |
---|
1674 | 1835 | ssize_t copied; |
---|
.. | .. |
---|
1683 | 1844 | |
---|
1684 | 1845 | lock_sock(sk); |
---|
1685 | 1846 | |
---|
1686 | | - if (sk->sk_state != TCP_ESTABLISHED) { |
---|
| 1847 | + transport = vsk->transport; |
---|
| 1848 | + |
---|
| 1849 | + if (!transport || sk->sk_state != TCP_ESTABLISHED) { |
---|
1687 | 1850 | /* Recvmsg is supposed to return 0 if a peer performs an |
---|
1688 | 1851 | * orderly shutdown. Differentiate between that case and when a |
---|
1689 | 1852 | * peer has not connected or a local shutdown occured with the |
---|
.. | .. |
---|
1857 | 2020 | static int vsock_create(struct net *net, struct socket *sock, |
---|
1858 | 2021 | int protocol, int kern) |
---|
1859 | 2022 | { |
---|
| 2023 | + struct vsock_sock *vsk; |
---|
| 2024 | + struct sock *sk; |
---|
| 2025 | + int ret; |
---|
| 2026 | + |
---|
1860 | 2027 | if (!sock) |
---|
1861 | 2028 | return -EINVAL; |
---|
1862 | 2029 | |
---|
.. | .. |
---|
1876 | 2043 | |
---|
1877 | 2044 | sock->state = SS_UNCONNECTED; |
---|
1878 | 2045 | |
---|
1879 | | - return __vsock_create(net, sock, NULL, GFP_KERNEL, 0, kern) ? 0 : -ENOMEM; |
---|
| 2046 | + sk = __vsock_create(net, sock, NULL, GFP_KERNEL, 0, kern); |
---|
| 2047 | + if (!sk) |
---|
| 2048 | + return -ENOMEM; |
---|
| 2049 | + |
---|
| 2050 | + vsk = vsock_sk(sk); |
---|
| 2051 | + |
---|
| 2052 | + if (sock->type == SOCK_DGRAM) { |
---|
| 2053 | + ret = vsock_assign_transport(vsk, NULL); |
---|
| 2054 | + if (ret < 0) { |
---|
| 2055 | + sock_put(sk); |
---|
| 2056 | + return ret; |
---|
| 2057 | + } |
---|
| 2058 | + } |
---|
| 2059 | + |
---|
| 2060 | + vsock_insert_unbound(vsk); |
---|
| 2061 | + |
---|
| 2062 | + return 0; |
---|
1880 | 2063 | } |
---|
1881 | 2064 | |
---|
1882 | 2065 | static const struct net_proto_family vsock_family_ops = { |
---|
.. | .. |
---|
1889 | 2072 | unsigned int cmd, void __user *ptr) |
---|
1890 | 2073 | { |
---|
1891 | 2074 | u32 __user *p = ptr; |
---|
| 2075 | + u32 cid = VMADDR_CID_ANY; |
---|
1892 | 2076 | int retval = 0; |
---|
1893 | 2077 | |
---|
1894 | 2078 | switch (cmd) { |
---|
1895 | 2079 | case IOCTL_VM_SOCKETS_GET_LOCAL_CID: |
---|
1896 | | - if (put_user(transport->get_local_cid(), p) != 0) |
---|
| 2080 | + /* To be compatible with the VMCI behavior, we prioritize the |
---|
| 2081 | + * guest CID instead of well-know host CID (VMADDR_CID_HOST). |
---|
| 2082 | + */ |
---|
| 2083 | + if (transport_g2h) |
---|
| 2084 | + cid = transport_g2h->get_local_cid(); |
---|
| 2085 | + else if (transport_h2g) |
---|
| 2086 | + cid = transport_h2g->get_local_cid(); |
---|
| 2087 | + |
---|
| 2088 | + if (put_user(cid, p) != 0) |
---|
1897 | 2089 | retval = -EFAULT; |
---|
1898 | 2090 | break; |
---|
1899 | 2091 | |
---|
.. | .. |
---|
1933 | 2125 | .fops = &vsock_device_ops, |
---|
1934 | 2126 | }; |
---|
1935 | 2127 | |
---|
1936 | | -int __vsock_core_init(const struct vsock_transport *t, struct module *owner) |
---|
| 2128 | +static int __init vsock_init(void) |
---|
1937 | 2129 | { |
---|
1938 | | - int err = mutex_lock_interruptible(&vsock_register_mutex); |
---|
| 2130 | + int err = 0; |
---|
1939 | 2131 | |
---|
1940 | | - if (err) |
---|
1941 | | - return err; |
---|
| 2132 | + vsock_init_tables(); |
---|
1942 | 2133 | |
---|
1943 | | - if (transport) { |
---|
1944 | | - err = -EBUSY; |
---|
1945 | | - goto err_busy; |
---|
1946 | | - } |
---|
1947 | | - |
---|
1948 | | - /* Transport must be the owner of the protocol so that it can't |
---|
1949 | | - * unload while there are open sockets. |
---|
1950 | | - */ |
---|
1951 | | - vsock_proto.owner = owner; |
---|
1952 | | - transport = t; |
---|
1953 | | - |
---|
| 2134 | + vsock_proto.owner = THIS_MODULE; |
---|
1954 | 2135 | vsock_device.minor = MISC_DYNAMIC_MINOR; |
---|
1955 | 2136 | err = misc_register(&vsock_device); |
---|
1956 | 2137 | if (err) { |
---|
.. | .. |
---|
1971 | 2152 | goto err_unregister_proto; |
---|
1972 | 2153 | } |
---|
1973 | 2154 | |
---|
1974 | | - mutex_unlock(&vsock_register_mutex); |
---|
1975 | 2155 | return 0; |
---|
1976 | 2156 | |
---|
1977 | 2157 | err_unregister_proto: |
---|
.. | .. |
---|
1979 | 2159 | err_deregister_misc: |
---|
1980 | 2160 | misc_deregister(&vsock_device); |
---|
1981 | 2161 | err_reset_transport: |
---|
1982 | | - transport = NULL; |
---|
| 2162 | + return err; |
---|
| 2163 | +} |
---|
| 2164 | + |
---|
| 2165 | +static void __exit vsock_exit(void) |
---|
| 2166 | +{ |
---|
| 2167 | + misc_deregister(&vsock_device); |
---|
| 2168 | + sock_unregister(AF_VSOCK); |
---|
| 2169 | + proto_unregister(&vsock_proto); |
---|
| 2170 | +} |
---|
| 2171 | + |
---|
| 2172 | +const struct vsock_transport *vsock_core_get_transport(struct vsock_sock *vsk) |
---|
| 2173 | +{ |
---|
| 2174 | + return vsk->transport; |
---|
| 2175 | +} |
---|
| 2176 | +EXPORT_SYMBOL_GPL(vsock_core_get_transport); |
---|
| 2177 | + |
---|
| 2178 | +int vsock_core_register(const struct vsock_transport *t, int features) |
---|
| 2179 | +{ |
---|
| 2180 | + const struct vsock_transport *t_h2g, *t_g2h, *t_dgram, *t_local; |
---|
| 2181 | + int err = mutex_lock_interruptible(&vsock_register_mutex); |
---|
| 2182 | + |
---|
| 2183 | + if (err) |
---|
| 2184 | + return err; |
---|
| 2185 | + |
---|
| 2186 | + t_h2g = transport_h2g; |
---|
| 2187 | + t_g2h = transport_g2h; |
---|
| 2188 | + t_dgram = transport_dgram; |
---|
| 2189 | + t_local = transport_local; |
---|
| 2190 | + |
---|
| 2191 | + if (features & VSOCK_TRANSPORT_F_H2G) { |
---|
| 2192 | + if (t_h2g) { |
---|
| 2193 | + err = -EBUSY; |
---|
| 2194 | + goto err_busy; |
---|
| 2195 | + } |
---|
| 2196 | + t_h2g = t; |
---|
| 2197 | + } |
---|
| 2198 | + |
---|
| 2199 | + if (features & VSOCK_TRANSPORT_F_G2H) { |
---|
| 2200 | + if (t_g2h) { |
---|
| 2201 | + err = -EBUSY; |
---|
| 2202 | + goto err_busy; |
---|
| 2203 | + } |
---|
| 2204 | + t_g2h = t; |
---|
| 2205 | + } |
---|
| 2206 | + |
---|
| 2207 | + if (features & VSOCK_TRANSPORT_F_DGRAM) { |
---|
| 2208 | + if (t_dgram) { |
---|
| 2209 | + err = -EBUSY; |
---|
| 2210 | + goto err_busy; |
---|
| 2211 | + } |
---|
| 2212 | + t_dgram = t; |
---|
| 2213 | + } |
---|
| 2214 | + |
---|
| 2215 | + if (features & VSOCK_TRANSPORT_F_LOCAL) { |
---|
| 2216 | + if (t_local) { |
---|
| 2217 | + err = -EBUSY; |
---|
| 2218 | + goto err_busy; |
---|
| 2219 | + } |
---|
| 2220 | + t_local = t; |
---|
| 2221 | + } |
---|
| 2222 | + |
---|
| 2223 | + transport_h2g = t_h2g; |
---|
| 2224 | + transport_g2h = t_g2h; |
---|
| 2225 | + transport_dgram = t_dgram; |
---|
| 2226 | + transport_local = t_local; |
---|
| 2227 | + |
---|
1983 | 2228 | err_busy: |
---|
1984 | 2229 | mutex_unlock(&vsock_register_mutex); |
---|
1985 | 2230 | return err; |
---|
1986 | 2231 | } |
---|
1987 | | -EXPORT_SYMBOL_GPL(__vsock_core_init); |
---|
| 2232 | +EXPORT_SYMBOL_GPL(vsock_core_register); |
---|
1988 | 2233 | |
---|
1989 | | -void vsock_core_exit(void) |
---|
| 2234 | +void vsock_core_unregister(const struct vsock_transport *t) |
---|
1990 | 2235 | { |
---|
1991 | 2236 | mutex_lock(&vsock_register_mutex); |
---|
1992 | 2237 | |
---|
1993 | | - misc_deregister(&vsock_device); |
---|
1994 | | - sock_unregister(AF_VSOCK); |
---|
1995 | | - proto_unregister(&vsock_proto); |
---|
| 2238 | + if (transport_h2g == t) |
---|
| 2239 | + transport_h2g = NULL; |
---|
1996 | 2240 | |
---|
1997 | | - /* We do not want the assignment below re-ordered. */ |
---|
1998 | | - mb(); |
---|
1999 | | - transport = NULL; |
---|
| 2241 | + if (transport_g2h == t) |
---|
| 2242 | + transport_g2h = NULL; |
---|
| 2243 | + |
---|
| 2244 | + if (transport_dgram == t) |
---|
| 2245 | + transport_dgram = NULL; |
---|
| 2246 | + |
---|
| 2247 | + if (transport_local == t) |
---|
| 2248 | + transport_local = NULL; |
---|
2000 | 2249 | |
---|
2001 | 2250 | mutex_unlock(&vsock_register_mutex); |
---|
2002 | 2251 | } |
---|
2003 | | -EXPORT_SYMBOL_GPL(vsock_core_exit); |
---|
| 2252 | +EXPORT_SYMBOL_GPL(vsock_core_unregister); |
---|
2004 | 2253 | |
---|
2005 | | -const struct vsock_transport *vsock_core_get_transport(void) |
---|
2006 | | -{ |
---|
2007 | | - /* vsock_register_mutex not taken since only the transport uses this |
---|
2008 | | - * function and only while registered. |
---|
2009 | | - */ |
---|
2010 | | - return transport; |
---|
2011 | | -} |
---|
2012 | | -EXPORT_SYMBOL_GPL(vsock_core_get_transport); |
---|
2013 | | - |
---|
2014 | | -static void __exit vsock_exit(void) |
---|
2015 | | -{ |
---|
2016 | | - /* Do nothing. This function makes this module removable. */ |
---|
2017 | | -} |
---|
2018 | | - |
---|
2019 | | -module_init(vsock_init_tables); |
---|
| 2254 | +module_init(vsock_init); |
---|
2020 | 2255 | module_exit(vsock_exit); |
---|
2021 | 2256 | |
---|
2022 | 2257 | MODULE_AUTHOR("VMware, Inc."); |
---|