| @@ -29,15 +29,18 @@ · 28 unmodified lines |
| 29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
| 30 | #include <linux/miscdevice.h> | 30 | #include <linux/miscdevice.h> |
| 31 | #include <linux/moduleparam.h> | 31 | #include <linux/moduleparam.h> |
| | 32 | #include <linux/virtio_mmio.h> |
| 32 | | 33 | |
| 33 | #include <asm/xen/hypervisor.h> | 34 | #include <asm/xen/hypervisor.h> |
| 34 | #include <asm/xen/hypercall.h> | 35 | #include <asm/xen/hypercall.h> |
| 35 | | 36 | |
| 36 | #include <xen/xen.h> | 37 | #include <xen/xen.h> |
| | 38 | #include <xen/events.h> |
| 37 | #include <xen/privcmd.h> | 39 | #include <xen/privcmd.h> |
| 38 | #include <xen/interface/xen.h> | 40 | #include <xen/interface/xen.h> |
| 39 | #include <xen/interface/memory.h> | 41 | #include <xen/interface/memory.h> |
| 40 | #include <xen/interface/hvm/dm_op.h> | 42 | #include <xen/interface/hvm/dm_op.h> |
| | 43 | #include <xen/interface/hvm/ioreq.h> |
| 41 | #include <xen/features.h> | 44 | #include <xen/features.h> |
| 42 | #include <xen/page.h> | 45 | #include <xen/page.h> |
| 43 | #include <xen/xen-ops.h> | 46 | #include <xen/xen-ops.h> |
| @@ -782,6 +785,7 @@ static long privcmd_ioctl_mmap_resource(struct file *file, · 738 unmodified lines |
| 782 | goto out; | 785 | goto out; |
| 783 | | 786 | |
| 784 | pages = vma->vm_private_data; | 787 | pages = vma->vm_private_data; |
| | 788 | |
| 785 | for (i = 0; i < kdata.num; i++) { | 789 | for (i = 0; i < kdata.num; i++) { |
| 786 | xen_pfn_t pfn = | 790 | xen_pfn_t pfn = |
| 787 | page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]); | 791 | page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]); |
| @@ -838,7 +842,7 @@ out: · 50 unmodified lines |
| 838 | return rc; | 842 | return rc; |
| 839 | } | 843 | } |
| 840 | | 844 | |
| 841 | #ifdef CONFIG_XEN_PRIVCMD_IRQFD | 845 | #ifdef CONFIG_XEN_PRIVCMD_EVENTFD |
| 842 | /* Irqfd support */ | 846 | /* Irqfd support */ |
| 843 | static struct workqueue_struct *irqfd_cleanup_wq; | 847 | static struct workqueue_struct *irqfd_cleanup_wq; |
| 844 | static DEFINE_MUTEX(irqfds_lock); | 848 | static DEFINE_MUTEX(irqfds_lock); |
| @@ -935,7 +939,7 @@ static int privcmd_irqfd_assign(struct privcmd_irqfd *irqfd) · 90 unmodified lines |
| 935 | return -ENOMEM; | 939 | return -ENOMEM; |
| 936 | dm_op = kirqfd + 1; | 940 | dm_op = kirqfd + 1; |
| 937 | | 941 | |
| 938 | if (copy_from_user(dm_op, irqfd->dm_op, irqfd->size)) { | 942 | if (copy_from_user(dm_op, u64_to_user_ptr(irqfd->dm_op), irqfd->size)) { |
| 939 | ret = -EFAULT; | 943 | ret = -EFAULT; |
| 940 | goto error_kfree; | 944 | goto error_kfree; |
| 941 | } | 945 | } |
| @@ -1079,6 +1083,389 @@ static void privcmd_irqfd_exit(void) · 137 unmodified lines |
| 1079 | | 1083 | |
| 1080 | destroy_workqueue(irqfd_cleanup_wq); | 1084 | destroy_workqueue(irqfd_cleanup_wq); |
| 1081 | } | 1085 | } |
| | 1086 | |
| | 1087 | /* Ioeventfd Support */ |
| | 1088 | #define QUEUE_NOTIFY_VQ_MASK 0xFFFF |
| | 1089 | |
| | 1090 | static DEFINE_MUTEX(ioreq_lock); |
| | 1091 | static LIST_HEAD(ioreq_list); |
| | 1092 | |
| | 1093 | /* per-eventfd structure */ |
| | 1094 | struct privcmd_kernel_ioeventfd { |
| | 1095 | struct eventfd_ctx *eventfd; |
| | 1096 | struct list_head list; |
| | 1097 | u64 addr; |
| | 1098 | unsigned int addr_len; |
| | 1099 | unsigned int vq; |
| | 1100 | }; |
| | 1101 | |
| | 1102 | /* per-guest CPU / port structure */ |
| | 1103 | struct ioreq_port { |
| | 1104 | int vcpu; |
| | 1105 | unsigned int port; |
| | 1106 | struct privcmd_kernel_ioreq *kioreq; |
| | 1107 | }; |
| | 1108 | |
| | 1109 | /* per-guest structure */ |
| | 1110 | struct privcmd_kernel_ioreq { |
| | 1111 | domid_t dom; |
| | 1112 | unsigned int vcpus; |
| | 1113 | u64 uioreq; |
| | 1114 | struct ioreq *ioreq; |
| | 1115 | spinlock_t lock; /* Protects ioeventfds list */ |
| | 1116 | struct list_head ioeventfds; |
| | 1117 | struct list_head list; |
| | 1118 | struct ioreq_port ports[0]; |
| | 1119 | }; |
| | 1120 | |
| | 1121 | static irqreturn_t ioeventfd_interrupt(int irq, void *dev_id) |
| | 1122 | { |
| | 1123 | struct ioreq_port *port = dev_id; |
| | 1124 | struct privcmd_kernel_ioreq *kioreq = port->kioreq; |
| | 1125 | struct ioreq *ioreq = &kioreq->ioreq[port->vcpu]; |
| | 1126 | struct privcmd_kernel_ioeventfd *kioeventfd; |
| | 1127 | unsigned int state = STATE_IOREQ_READY; |
| | 1128 | |
| | 1129 | if (ioreq->state != STATE_IOREQ_READY || |
| | 1130 | ioreq->type != IOREQ_TYPE_COPY || ioreq->dir != IOREQ_WRITE) |
| | 1131 | return IRQ_NONE; |
| | 1132 | |
| | 1133 | /* |
| | 1134 | * We need a barrier, smp_mb(), here to ensure reads are finished before |
| | 1135 | * `state` is updated. Since the lock implementation ensures that |
| | 1136 | * appropriate barrier will be added anyway, we can avoid adding |
| | 1137 | * explicit barrier here. |
| | 1138 | * |
| | 1139 | * Ideally we don't need to update `state` within the locks, but we do |
| | 1140 | * that here to avoid adding explicit barrier. |
| | 1141 | */ |
| | 1142 | |
| | 1143 | spin_lock(&kioreq->lock); |
| | 1144 | ioreq->state = STATE_IOREQ_INPROCESS; |
| | 1145 | |
| | 1146 | list_for_each_entry(kioeventfd, &kioreq->ioeventfds, list) { |
| | 1147 | if (ioreq->addr == kioeventfd->addr + VIRTIO_MMIO_QUEUE_NOTIFY && |
| | 1148 | ioreq->size == kioeventfd->addr_len && |
| | 1149 | (ioreq->data & QUEUE_NOTIFY_VQ_MASK) == kioeventfd->vq) { |
| | 1150 | eventfd_signal(kioeventfd->eventfd, 1); |
| | 1151 | state = STATE_IORESP_READY; |
| | 1152 | break; |
| | 1153 | } |
| | 1154 | } |
| | 1155 | spin_unlock(&kioreq->lock); |
| | 1156 | |
| | 1157 | /* |
| | 1158 | * We need a barrier, smp_mb(), here to ensure writes are finished |
| | 1159 | * before `state` is updated. Since the lock implementation ensures that |
| | 1160 | * appropriate barrier will be added anyway, we can avoid adding |
| | 1161 | * explicit barrier here. |
| | 1162 | */ |
| | 1163 | |
| | 1164 | ioreq->state = state; |
| | 1165 | |
| | 1166 | if (state == STATE_IORESP_READY) { |
| | 1167 | notify_remote_via_evtchn(port->port); |
| | 1168 | return IRQ_HANDLED; |
| | 1169 | } |
| | 1170 | |
| | 1171 | return IRQ_NONE; |
| | 1172 | } |
| | 1173 | |
| | 1174 | static void ioreq_free(struct privcmd_kernel_ioreq *kioreq) |
| | 1175 | { |
| | 1176 | struct ioreq_port *ports = kioreq->ports; |
| | 1177 | int i; |
| | 1178 | |
| | 1179 | lockdep_assert_held(&ioreq_lock); |
| | 1180 | |
| | 1181 | list_del(&kioreq->list); |
| | 1182 | |
| | 1183 | for (i = kioreq->vcpus - 1; i >= 0; i--) |
| | 1184 | unbind_from_irqhandler(irq_from_evtchn(ports[i].port), &ports[i]); |
| | 1185 | |
| | 1186 | kfree(kioreq); |
| | 1187 | } |
| | 1188 | |
| | 1189 | static |
| | 1190 | struct privcmd_kernel_ioreq *alloc_ioreq(struct privcmd_ioeventfd *ioeventfd) |
| | 1191 | { |
| | 1192 | struct privcmd_kernel_ioreq *kioreq; |
| | 1193 | struct mm_struct *mm = current->mm; |
| | 1194 | struct vm_area_struct *vma; |
| | 1195 | struct page **pages; |
| | 1196 | unsigned int *ports; |
| | 1197 | int ret, size, i; |
| | 1198 | |
| | 1199 | lockdep_assert_held(&ioreq_lock); |
| | 1200 | |
| | 1201 | size = struct_size(kioreq, ports, ioeventfd->vcpus); |
| | 1202 | kioreq = kzalloc(size, GFP_KERNEL); |
| | 1203 | if (!kioreq) |
| | 1204 | return ERR_PTR(-ENOMEM); |
| | 1205 | |
| | 1206 | kioreq->dom = ioeventfd->dom; |
| | 1207 | kioreq->vcpus = ioeventfd->vcpus; |
| | 1208 | kioreq->uioreq = ioeventfd->ioreq; |
| | 1209 | spin_lock_init(&kioreq->lock); |
| | 1210 | INIT_LIST_HEAD(&kioreq->ioeventfds); |
| | 1211 | |
| | 1212 | /* The memory for ioreq server must have been mapped earlier */ |
| | 1213 | mmap_write_lock(mm); |
| | 1214 | vma = find_vma(mm, (unsigned long)ioeventfd->ioreq); |
| | 1215 | if (!vma) { |
| | 1216 | pr_err("Failed to find vma for ioreq page!\n"); |
| | 1217 | mmap_write_unlock(mm); |
| | 1218 | ret = -EFAULT; |
| | 1219 | goto error_kfree; |
| | 1220 | } |
| | 1221 | |
| | 1222 | pages = vma->vm_private_data; |
| | 1223 | kioreq->ioreq = (struct ioreq *)(page_to_virt(pages[0])); |
| | 1224 | mmap_write_unlock(mm); |
| | 1225 | |
| | 1226 | size = sizeof(*ports) * kioreq->vcpus; |
| | 1227 | ports = kzalloc(size, GFP_KERNEL); |
| | 1228 | if (!ports) { |
| | 1229 | ret = -ENOMEM; |
| | 1230 | goto error_kfree; |
| | 1231 | } |
| | 1232 | |
| | 1233 | if (copy_from_user(ports, u64_to_user_ptr(ioeventfd->ports), size)) { |
| | 1234 | ret = -EFAULT; |
| | 1235 | goto error_kfree_ports; |
| | 1236 | } |
| | 1237 | |
| | 1238 | for (i = 0; i < kioreq->vcpus; i++) { |
| | 1239 | kioreq->ports[i].vcpu = i; |
| | 1240 | kioreq->ports[i].port = ports[i]; |
| | 1241 | kioreq->ports[i].kioreq = kioreq; |
| | 1242 | |
| | 1243 | ret = bind_evtchn_to_irqhandler_lateeoi(ports[i], |
| | 1244 | ioeventfd_interrupt, IRQF_SHARED, "ioeventfd", |
| | 1245 | &kioreq->ports[i]); |
| | 1246 | if (ret < 0) |
| | 1247 | goto error_unbind; |
| | 1248 | } |
| | 1249 | |
| | 1250 | kfree(ports); |
| | 1251 | |
| | 1252 | list_add_tail(&kioreq->list, &ioreq_list); |
| | 1253 | |
| | 1254 | return kioreq; |
| | 1255 | |
| | 1256 | error_unbind: |
| | 1257 | while (--i >= 0) |
| | 1258 | unbind_from_irqhandler(irq_from_evtchn(ports[i]), &kioreq->ports[i]); |
| | 1259 | error_kfree_ports: |
| | 1260 | kfree(ports); |
| | 1261 | error_kfree: |
| | 1262 | kfree(kioreq); |
| | 1263 | return ERR_PTR(ret); |
| | 1264 | } |
| | 1265 | |
| | 1266 | static struct privcmd_kernel_ioreq * |
| | 1267 | get_ioreq(struct privcmd_ioeventfd *ioeventfd, struct eventfd_ctx *eventfd) |
| | 1268 | { |
| | 1269 | struct privcmd_kernel_ioreq *kioreq; |
| | 1270 | unsigned long flags; |
| | 1271 | |
| | 1272 | list_for_each_entry(kioreq, &ioreq_list, list) { |
| | 1273 | struct privcmd_kernel_ioeventfd *kioeventfd; |
| | 1274 | |
| | 1275 | /* |
| | 1276 | * kioreq fields can be accessed here without a lock as they are |
| | 1277 | * never updated after being added to the ioreq_list. |
| | 1278 | */ |
| | 1279 | if (kioreq->uioreq != ioeventfd->ioreq) { |
| | 1280 | continue; |
| | 1281 | } else if (kioreq->dom != ioeventfd->dom || |
| | 1282 | kioreq->vcpus != ioeventfd->vcpus) { |
| | 1283 | pr_err("Invalid ioeventfd configuration mismatch, dom (%u vs %u), vcpus (%u vs %u)\n", |
| | 1284 | kioreq->dom, ioeventfd->dom, kioreq->vcpus, |
| | 1285 | ioeventfd->vcpus); |
| | 1286 | return ERR_PTR(-EINVAL); |
| | 1287 | } |
| | 1288 | |
| | 1289 | /* Look for a duplicate eventfd for the same guest */ |
| | 1290 | spin_lock_irqsave(&kioreq->lock, flags); |
| | 1291 | list_for_each_entry(kioeventfd, &kioreq->ioeventfds, list) { |
| | 1292 | if (eventfd == kioeventfd->eventfd) { |
| | 1293 | spin_unlock_irqrestore(&kioreq->lock, flags); |
| | 1294 | return ERR_PTR(-EBUSY); |
| | 1295 | } |
| | 1296 | } |
| | 1297 | spin_unlock_irqrestore(&kioreq->lock, flags); |
| | 1298 | |
| | 1299 | return kioreq; |
| | 1300 | } |
| | 1301 | |
| | 1302 | /* Matching kioreq isn't found, allocate a new one */ |
| | 1303 | return alloc_ioreq(ioeventfd); |
| | 1304 | } |
| | 1305 | |
| | 1306 | static void ioeventfd_free(struct privcmd_kernel_ioeventfd *kioeventfd) |
| | 1307 | { |
| | 1308 | list_del(&kioeventfd->list); |
| | 1309 | eventfd_ctx_put(kioeventfd->eventfd); |
| | 1310 | kfree(kioeventfd); |
| | 1311 | } |
| | 1312 | |
| | 1313 | static int privcmd_ioeventfd_assign(struct privcmd_ioeventfd *ioeventfd) |
| | 1314 | { |
| | 1315 | struct privcmd_kernel_ioeventfd *kioeventfd; |
| | 1316 | struct privcmd_kernel_ioreq *kioreq; |
| | 1317 | unsigned long flags; |
| | 1318 | struct fd f; |
| | 1319 | int ret; |
| | 1320 | |
| | 1321 | /* Check for range overflow */ |
| | 1322 | if (ioeventfd->addr + ioeventfd->addr_len < ioeventfd->addr) |
| | 1323 | return -EINVAL; |
| | 1324 | |
| | 1325 | /* Vhost requires us to support length 1, 2, 4, and 8 */ |
| | 1326 | if (!(ioeventfd->addr_len == 1 || ioeventfd->addr_len == 2 || |
| | 1327 | ioeventfd->addr_len == 4 || ioeventfd->addr_len == 8)) |
| | 1328 | return -EINVAL; |
| | 1329 | |
| | 1330 | /* 4096 vcpus limit enough ? */ |
| | 1331 | if (!ioeventfd->vcpus || ioeventfd->vcpus > 4096) |
| | 1332 | return -EINVAL; |
| | 1333 | |
| | 1334 | kioeventfd = kzalloc(sizeof(*kioeventfd), GFP_KERNEL); |
| | 1335 | if (!kioeventfd) |
| | 1336 | return -ENOMEM; |
| | 1337 | |
| | 1338 | f = fdget(ioeventfd->event_fd); |
| | 1339 | if (!f.file) { |
| | 1340 | ret = -EBADF; |
| | 1341 | goto error_kfree; |
| | 1342 | } |
| | 1343 | |
| | 1344 | kioeventfd->eventfd = eventfd_ctx_fileget(f.file); |
| | 1345 | fdput(f); |
| | 1346 | |
| | 1347 | if (IS_ERR(kioeventfd->eventfd)) { |
| | 1348 | ret = PTR_ERR(kioeventfd->eventfd); |
| | 1349 | goto error_kfree; |
| | 1350 | } |
| | 1351 | |
| | 1352 | kioeventfd->addr = ioeventfd->addr; |
| | 1353 | kioeventfd->addr_len = ioeventfd->addr_len; |
| | 1354 | kioeventfd->vq = ioeventfd->vq; |
| | 1355 | |
| | 1356 | mutex_lock(&ioreq_lock); |
| | 1357 | kioreq = get_ioreq(ioeventfd, kioeventfd->eventfd); |
| | 1358 | if (IS_ERR(kioreq)) { |
| | 1359 | mutex_unlock(&ioreq_lock); |
| | 1360 | ret = PTR_ERR(kioreq); |
| | 1361 | goto error_eventfd; |
| | 1362 | } |
| | 1363 | |
| | 1364 | spin_lock_irqsave(&kioreq->lock, flags); |
| | 1365 | list_add_tail(&kioeventfd->list, &kioreq->ioeventfds); |
| | 1366 | spin_unlock_irqrestore(&kioreq->lock, flags); |
| | 1367 | |
| | 1368 | mutex_unlock(&ioreq_lock); |
| | 1369 | |
| | 1370 | return 0; |
| | 1371 | |
| | 1372 | error_eventfd: |
| | 1373 | eventfd_ctx_put(kioeventfd->eventfd); |
| | 1374 | |
| | 1375 | error_kfree: |
| | 1376 | kfree(kioeventfd); |
| | 1377 | return ret; |
| | 1378 | } |
| | 1379 | |
| | 1380 | static int privcmd_ioeventfd_deassign(struct privcmd_ioeventfd *ioeventfd) |
| | 1381 | { |
| | 1382 | struct privcmd_kernel_ioreq *kioreq, *tkioreq; |
| | 1383 | struct eventfd_ctx *eventfd; |
| | 1384 | unsigned long flags; |
| | 1385 | int ret = 0; |
| | 1386 | |
| | 1387 | eventfd = eventfd_ctx_fdget(ioeventfd->event_fd); |
| | 1388 | if (IS_ERR(eventfd)) |
| | 1389 | return PTR_ERR(eventfd); |
| | 1390 | |
| | 1391 | mutex_lock(&ioreq_lock); |
| | 1392 | list_for_each_entry_safe(kioreq, tkioreq, &ioreq_list, list) { |
| | 1393 | struct privcmd_kernel_ioeventfd *kioeventfd, *tmp; |
| | 1394 | /* |
| | 1395 | * kioreq fields can be accessed here without a lock as they are |
| | 1396 | * never updated after being added to the ioreq_list. |
| | 1397 | */ |
| | 1398 | if (kioreq->dom != ioeventfd->dom || |
| | 1399 | kioreq->uioreq != ioeventfd->ioreq || |
| | 1400 | kioreq->vcpus != ioeventfd->vcpus) |
| | 1401 | continue; |
| | 1402 | |
| | 1403 | spin_lock_irqsave(&kioreq->lock, flags); |
| | 1404 | list_for_each_entry_safe(kioeventfd, tmp, &kioreq->ioeventfds, list) { |
| | 1405 | if (eventfd == kioeventfd->eventfd) { |
| | 1406 | ioeventfd_free(kioeventfd); |
| | 1407 | spin_unlock_irqrestore(&kioreq->lock, flags); |
| | 1408 | |
| | 1409 | if (list_empty(&kioreq->ioeventfds)) |
| | 1410 | ioreq_free(kioreq); |
| | 1411 | goto unlock; |
| | 1412 | } |
| | 1413 | } |
| | 1414 | spin_unlock_irqrestore(&kioreq->lock, flags); |
| | 1415 | break; |
| | 1416 | } |
| | 1417 | |
| | 1418 | pr_err("Ioeventfd isn't already assigned, dom: %u, addr: %llu\n", |
| | 1419 | ioeventfd->dom, ioeventfd->addr); |
| | 1420 | ret = -ENODEV; |
| | 1421 | |
| | 1422 | unlock: |
| | 1423 | mutex_unlock(&ioreq_lock); |
| | 1424 | eventfd_ctx_put(eventfd); |
| | 1425 | |
| | 1426 | return ret; |
| | 1427 | } |
| | 1428 | |
| | 1429 | static long privcmd_ioctl_ioeventfd(struct file *file, void __user *udata) |
| | 1430 | { |
| | 1431 | struct privcmd_data *data = file->private_data; |
| | 1432 | struct privcmd_ioeventfd ioeventfd; |
| | 1433 | |
| | 1434 | if (copy_from_user(&ioeventfd, udata, sizeof(ioeventfd))) |
| | 1435 | return -EFAULT; |
| | 1436 | |
| | 1437 | /* No other flags should be set */ |
| | 1438 | if (ioeventfd.flags & ~PRIVCMD_IOEVENTFD_FLAG_DEASSIGN) |
| | 1439 | return -EINVAL; |
| | 1440 | |
| | 1441 | /* If restriction is in place, check the domid matches */ |
| | 1442 | if (data->domid != DOMID_INVALID && data->domid != ioeventfd.dom) |
| | 1443 | return -EPERM; |
| | 1444 | |
| | 1445 | if (ioeventfd.flags & PRIVCMD_IOEVENTFD_FLAG_DEASSIGN) |
| | 1446 | return privcmd_ioeventfd_deassign(&ioeventfd); |
| | 1447 | |
| | 1448 | return privcmd_ioeventfd_assign(&ioeventfd); |
| | 1449 | } |
| | 1450 | |
| | 1451 | static void privcmd_ioeventfd_exit(void) |
| | 1452 | { |
| | 1453 | struct privcmd_kernel_ioreq *kioreq, *tmp; |
| | 1454 | unsigned long flags; |
| | 1455 | |
| | 1456 | mutex_lock(&ioreq_lock); |
| | 1457 | list_for_each_entry_safe(kioreq, tmp, &ioreq_list, list) { |
| | 1458 | struct privcmd_kernel_ioeventfd *kioeventfd, *tmp; |
| | 1459 | |
| | 1460 | spin_lock_irqsave(&kioreq->lock, flags); |
| | 1461 | list_for_each_entry_safe(kioeventfd, tmp, &kioreq->ioeventfds, list) |
| | 1462 | ioeventfd_free(kioeventfd); |
| | 1463 | spin_unlock_irqrestore(&kioreq->lock, flags); |
| | 1464 | |
| | 1465 | ioreq_free(kioreq); |
| | 1466 | } |
| | 1467 | mutex_unlock(&ioreq_lock); |
| | 1468 | } |
| 1082 | #else | 1469 | #else |
| 1083 | static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata) | 1470 | static inline long privcmd_ioctl_irqfd(struct file *file, void __user *udata) |
| 1084 | { | 1471 | { |
| @@ -1093,7 +1480,16 @@ static inline int privcmd_irqfd_init(void) · 8 unmodified lines |
| 1093 | static inline void privcmd_irqfd_exit(void) | 1480 | static inline void privcmd_irqfd_exit(void) |
| 1094 | { | 1481 | { |
| 1095 | } | 1482 | } |
| 1096 | #endif /* CONFIG_XEN_PRIVCMD_IRQFD */ | 1483 | |
| | 1484 | static inline long privcmd_ioctl_ioeventfd(struct file *file, void __user *udata) |
| | 1485 | { |
| | 1486 | return -EOPNOTSUPP; |
| | 1487 | } |
| | 1488 | |
| | 1489 | static inline void privcmd_ioeventfd_exit(void) |
| | 1490 | { |
| | 1491 | } |
| | 1492 | #endif /* CONFIG_XEN_PRIVCMD_EVENTFD */ |
| 1097 | | 1493 | |
| 1098 | static long privcmd_ioctl(struct file *file, | 1494 | static long privcmd_ioctl(struct file *file, |
| 1099 | unsigned int cmd, unsigned long data) | 1495 | unsigned int cmd, unsigned long data) |
| @@ -1134,6 +1530,10 @@ static long privcmd_ioctl(struct file *file, · 34 unmodified lines |
| 1134 | ret = privcmd_ioctl_irqfd(file, udata); | 1530 | ret = privcmd_ioctl_irqfd(file, udata); |
| 1135 | break; | 1531 | break; |
| 1136 | | 1532 | |
| | 1533 | case IOCTL_PRIVCMD_IOEVENTFD: |
| | 1534 | ret = privcmd_ioctl_ioeventfd(file, udata); |
| | 1535 | break; |
| | 1536 | |
| 1137 | default: | 1537 | default: |
| 1138 | break; | 1538 | break; |
| 1139 | } | 1539 | } |
| @@ -1278,6 +1678,7 @@ err_privcmdbuf: · 138 unmodified lines |
| 1278 | | 1678 | |
| 1279 | static void __exit privcmd_exit(void) | 1679 | static void __exit privcmd_exit(void) |
| 1280 | { | 1680 | { |
| | 1681 | privcmd_ioeventfd_exit(); |
| 1281 | privcmd_irqfd_exit(); | 1682 | privcmd_irqfd_exit(); |
| 1282 | misc_deregister(&privcmd_dev); | 1683 | misc_deregister(&privcmd_dev); |
| 1283 | misc_deregister(&xen_privcmdbuf_dev); | 1684 | misc_deregister(&xen_privcmdbuf_dev); |