1 /* 2 * vhost-backend 3 * 4 * Copyright (c) 2013 Virtual Open Systems Sarl. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include "hw/virtio/vhost.h" 12 #include "hw/virtio/vhost-backend.h" 13 #include "qemu/error-report.h" 14 #include "linux/vhost.h" 15 16 #include <sys/ioctl.h> 17 18 static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request, 19 void *arg) 20 { 21 int fd = (uintptr_t) dev->opaque; 22 23 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 24 25 return ioctl(fd, request, arg); 26 } 27 28 static int vhost_kernel_init(struct vhost_dev *dev, void *opaque) 29 { 30 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 31 32 dev->opaque = opaque; 33 34 return 0; 35 } 36 37 static int vhost_kernel_cleanup(struct vhost_dev *dev) 38 { 39 int fd = (uintptr_t) dev->opaque; 40 41 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL); 42 43 return close(fd); 44 } 45 46 static int vhost_kernel_memslots_limit(struct vhost_dev *dev) 47 { 48 int limit = 64; 49 char *s; 50 51 if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions", 52 &s, NULL, NULL)) { 53 uint64_t val = g_ascii_strtoull(s, NULL, 10); 54 if (!((val == G_MAXUINT64 || !val) && errno)) { 55 return val; 56 } 57 error_report("ignoring invalid max_mem_regions value in vhost module:" 58 " %s", s); 59 } 60 return limit; 61 } 62 63 static int vhost_kernel_net_set_backend(struct vhost_dev *dev, 64 struct vhost_vring_file *file) 65 { 66 return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file); 67 } 68 69 static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev, 70 struct vhost_scsi_target *target) 71 { 72 return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target); 73 } 74 75 static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev, 76 struct vhost_scsi_target *target) 77 { 78 return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target); 79 } 80 81 static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version) 82 { 83 return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version); 84 } 85 86 static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base, 87 struct vhost_log *log) 88 { 89 return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base); 90 } 91 92 static int vhost_kernel_set_mem_table(struct vhost_dev *dev, 93 struct vhost_memory *mem) 94 { 95 return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem); 96 } 97 98 static int vhost_kernel_set_vring_addr(struct vhost_dev *dev, 99 struct vhost_vring_addr *addr) 100 { 101 return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr); 102 } 103 104 static int vhost_kernel_set_vring_endian(struct vhost_dev *dev, 105 struct vhost_vring_state *ring) 106 { 107 return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring); 108 } 109 110 static int vhost_kernel_set_vring_num(struct vhost_dev *dev, 111 struct vhost_vring_state *ring) 112 { 113 return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring); 114 } 115 116 static int vhost_kernel_set_vring_base(struct vhost_dev *dev, 117 struct vhost_vring_state *ring) 118 { 119 return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring); 120 } 121 122 static int vhost_kernel_get_vring_base(struct vhost_dev *dev, 123 struct vhost_vring_state *ring) 124 { 125 return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring); 126 } 127 128 static int vhost_kernel_set_vring_kick(struct vhost_dev *dev, 129 struct vhost_vring_file *file) 130 { 131 return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file); 132 } 133 134 static int vhost_kernel_set_vring_call(struct vhost_dev *dev, 135 struct vhost_vring_file *file) 136 { 137 return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file); 138 } 139 140 static int vhost_kernel_set_features(struct vhost_dev *dev, 141 uint64_t features) 142 { 143 return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features); 144 } 145 146 static int vhost_kernel_get_features(struct vhost_dev *dev, 147 uint64_t *features) 148 { 149 return vhost_kernel_call(dev, VHOST_GET_FEATURES, features); 150 } 151 152 static int vhost_kernel_set_owner(struct vhost_dev *dev) 153 { 154 return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL); 155 } 156 157 static int vhost_kernel_reset_device(struct vhost_dev *dev) 158 { 159 return vhost_kernel_call(dev, VHOST_RESET_DEVICE, NULL); 160 } 161 162 static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx) 163 { 164 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs); 165 166 return idx - dev->vq_index; 167 } 168 169 static const VhostOps kernel_ops = { 170 .backend_type = VHOST_BACKEND_TYPE_KERNEL, 171 .vhost_backend_init = vhost_kernel_init, 172 .vhost_backend_cleanup = vhost_kernel_cleanup, 173 .vhost_backend_memslots_limit = vhost_kernel_memslots_limit, 174 .vhost_net_set_backend = vhost_kernel_net_set_backend, 175 .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint, 176 .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint, 177 .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version, 178 .vhost_set_log_base = vhost_kernel_set_log_base, 179 .vhost_set_mem_table = vhost_kernel_set_mem_table, 180 .vhost_set_vring_addr = vhost_kernel_set_vring_addr, 181 .vhost_set_vring_endian = vhost_kernel_set_vring_endian, 182 .vhost_set_vring_num = vhost_kernel_set_vring_num, 183 .vhost_set_vring_base = vhost_kernel_set_vring_base, 184 .vhost_get_vring_base = vhost_kernel_get_vring_base, 185 .vhost_set_vring_kick = vhost_kernel_set_vring_kick, 186 .vhost_set_vring_call = vhost_kernel_set_vring_call, 187 .vhost_set_features = vhost_kernel_set_features, 188 .vhost_get_features = vhost_kernel_get_features, 189 .vhost_set_owner = vhost_kernel_set_owner, 190 .vhost_reset_device = vhost_kernel_reset_device, 191 .vhost_get_vq_index = vhost_kernel_get_vq_index, 192 }; 193 194 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) 195 { 196 int r = 0; 197 198 switch (backend_type) { 199 case VHOST_BACKEND_TYPE_KERNEL: 200 dev->vhost_ops = &kernel_ops; 201 break; 202 case VHOST_BACKEND_TYPE_USER: 203 dev->vhost_ops = &user_ops; 204 break; 205 default: 206 error_report("Unknown vhost backend type"); 207 r = -1; 208 } 209 210 return r; 211 } 212