1 /*
2 * node_device_driver.c: node device enumeration
3 *
4 * Copyright (C) 2010-2015 Red Hat, Inc.
5 * Copyright (C) 2008 Virtual Iron Software, Inc.
6 * Copyright (C) 2008 David F. Lively
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see
20 * <http://www.gnu.org/licenses/>.
21 */
22
23 #include <config.h>
24
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <time.h>
28
29 #include "virerror.h"
30 #include "datatypes.h"
31 #include "domain_addr.h"
32 #include "viralloc.h"
33 #include "virfile.h"
34 #include "virjson.h"
35 #include "virstring.h"
36 #include "node_device_conf.h"
37 #include "node_device_event.h"
38 #include "node_device_driver.h"
39 #include "node_device_util.h"
40 #include "virvhba.h"
41 #include "viraccessapicheck.h"
42 #include "virnetdev.h"
43 #include "virutil.h"
44 #include "vircommand.h"
45 #include "virlog.h"
46
47 #define VIR_FROM_THIS VIR_FROM_NODEDEV
48
49 VIR_LOG_INIT("node_device.node_device_driver");
50
51 virNodeDeviceDriverState *driver;
52
53
54 VIR_ENUM_IMPL(virMdevctlCommand,
55 MDEVCTL_CMD_LAST,
56 "start", "stop", "define", "undefine", "create"
57 );
58
59
60 #define MDEVCTL_ERROR(msg) (msg && msg[0] != '\0' ? msg : _("Unknown error"))
61
62
63 virDrvOpenStatus
nodeConnectOpen(virConnectPtr conn,virConnectAuthPtr auth G_GNUC_UNUSED,virConf * conf G_GNUC_UNUSED,unsigned int flags)64 nodeConnectOpen(virConnectPtr conn,
65 virConnectAuthPtr auth G_GNUC_UNUSED,
66 virConf *conf G_GNUC_UNUSED,
67 unsigned int flags)
68 {
69 virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
70
71 if (driver == NULL) {
72 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
73 _("nodedev state driver is not active"));
74 return VIR_DRV_OPEN_ERROR;
75 }
76
77 if (!virConnectValidateURIPath(conn->uri->path,
78 "nodedev",
79 driver->privileged))
80 return VIR_DRV_OPEN_ERROR;
81
82 if (virConnectOpenEnsureACL(conn) < 0)
83 return VIR_DRV_OPEN_ERROR;
84
85 return VIR_DRV_OPEN_SUCCESS;
86 }
87
nodeConnectClose(virConnectPtr conn G_GNUC_UNUSED)88 int nodeConnectClose(virConnectPtr conn G_GNUC_UNUSED)
89 {
90 return 0;
91 }
92
93
nodeConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)94 int nodeConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
95 {
96 /* Trivially secure, since always inside the daemon */
97 return 1;
98 }
99
100
nodeConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)101 int nodeConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
102 {
103 /* Not encrypted, but remote driver takes care of that */
104 return 0;
105 }
106
107
nodeConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)108 int nodeConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
109 {
110 return 1;
111 }
112
113 #if defined (__linux__) && defined(WITH_UDEV)
114 /* NB: It was previously believed that changes in driver name were
115 * relayed to libvirt as "change" events by udev, and the udev event
116 * notification is setup to recognize such events and effectively
117 * recreate the device entry in the cache. However, neither the kernel
118 * nor udev sends such an event, so it is necessary to manually update
119 * the driver name for a device each time its entry is used.
120 */
121 static int
nodeDeviceUpdateDriverName(virNodeDeviceDef * def)122 nodeDeviceUpdateDriverName(virNodeDeviceDef *def)
123 {
124 g_autofree char *driver_link = NULL;
125 g_autofree char *devpath = NULL;
126 char *p;
127
128 VIR_FREE(def->driver);
129
130 driver_link = g_strdup_printf("%s/driver", def->sysfs_path);
131
132 /* Some devices don't have an explicit driver, so just return
133 without a name */
134 if (access(driver_link, R_OK) < 0)
135 return 0;
136
137 if (virFileResolveLink(driver_link, &devpath) < 0) {
138 virReportSystemError(errno,
139 _("cannot resolve driver link %s"), driver_link);
140 return -1;
141 }
142
143 p = strrchr(devpath, '/');
144 if (p)
145 def->driver = g_strdup(p + 1);
146
147 return 0;
148 }
149 #else
150 /* XXX: Implement me for non-linux */
151 static int
nodeDeviceUpdateDriverName(virNodeDeviceDef * def G_GNUC_UNUSED)152 nodeDeviceUpdateDriverName(virNodeDeviceDef *def G_GNUC_UNUSED)
153 {
154 return 0;
155 }
156 #endif
157
158
159 void
nodeDeviceLock(void)160 nodeDeviceLock(void)
161 {
162 virMutexLock(&driver->lock);
163 }
164
165
166 void
nodeDeviceUnlock(void)167 nodeDeviceUnlock(void)
168 {
169 virMutexUnlock(&driver->lock);
170 }
171
172
173 static int
nodeDeviceInitWait(void)174 nodeDeviceInitWait(void)
175 {
176 nodeDeviceLock();
177 while (!driver->initialized) {
178 if (virCondWait(&driver->initCond, &driver->lock) < 0) {
179 virReportSystemError(errno, "%s",
180 _("failed to wait on condition"));
181 nodeDeviceUnlock();
182 return -1;
183 }
184 }
185 nodeDeviceUnlock();
186 return 0;
187 }
188
189 int
nodeNumOfDevices(virConnectPtr conn,const char * cap,unsigned int flags)190 nodeNumOfDevices(virConnectPtr conn,
191 const char *cap,
192 unsigned int flags)
193 {
194 if (virNodeNumOfDevicesEnsureACL(conn) < 0)
195 return -1;
196
197 virCheckFlags(0, -1);
198
199 if (nodeDeviceInitWait() < 0)
200 return -1;
201
202 return virNodeDeviceObjListNumOfDevices(driver->devs, conn, cap,
203 virNodeNumOfDevicesCheckACL);
204 }
205
206
207 int
nodeListDevices(virConnectPtr conn,const char * cap,char ** const names,int maxnames,unsigned int flags)208 nodeListDevices(virConnectPtr conn,
209 const char *cap,
210 char **const names,
211 int maxnames,
212 unsigned int flags)
213 {
214 if (virNodeListDevicesEnsureACL(conn) < 0)
215 return -1;
216
217 virCheckFlags(0, -1);
218
219 if (nodeDeviceInitWait() < 0)
220 return -1;
221
222 return virNodeDeviceObjListGetNames(driver->devs, conn,
223 virNodeListDevicesCheckACL,
224 cap, names, maxnames);
225 }
226
227
228 int
nodeConnectListAllNodeDevices(virConnectPtr conn,virNodeDevicePtr ** devices,unsigned int flags)229 nodeConnectListAllNodeDevices(virConnectPtr conn,
230 virNodeDevicePtr **devices,
231 unsigned int flags)
232 {
233 virCheckFlags(VIR_CONNECT_LIST_NODE_DEVICES_FILTERS_ALL, -1);
234
235 if (virConnectListAllNodeDevicesEnsureACL(conn) < 0)
236 return -1;
237
238 if (nodeDeviceInitWait() < 0)
239 return -1;
240
241 return virNodeDeviceObjListExport(conn, driver->devs, devices,
242 virConnectListAllNodeDevicesCheckACL,
243 flags);
244 }
245
246
247 static virNodeDeviceObj *
nodeDeviceObjFindByName(const char * name)248 nodeDeviceObjFindByName(const char *name)
249 {
250 virNodeDeviceObj *obj;
251
252 if (!(obj = virNodeDeviceObjListFindByName(driver->devs, name))) {
253 virReportError(VIR_ERR_NO_NODE_DEVICE,
254 _("no node device with matching name '%s'"),
255 name);
256 }
257
258 return obj;
259 }
260
261
262 virNodeDevicePtr
nodeDeviceLookupByName(virConnectPtr conn,const char * name)263 nodeDeviceLookupByName(virConnectPtr conn,
264 const char *name)
265 {
266 virNodeDeviceObj *obj;
267 virNodeDeviceDef *def;
268 virNodeDevicePtr device = NULL;
269
270 if (nodeDeviceInitWait() < 0)
271 return NULL;
272
273 if (!(obj = nodeDeviceObjFindByName(name)))
274 return NULL;
275 def = virNodeDeviceObjGetDef(obj);
276
277 if (virNodeDeviceLookupByNameEnsureACL(conn, def) < 0)
278 goto cleanup;
279
280 if ((device = virGetNodeDevice(conn, name)))
281 device->parentName = g_strdup(def->parent);
282
283 cleanup:
284 virNodeDeviceObjEndAPI(&obj);
285 return device;
286 }
287
288
289 virNodeDevicePtr
nodeDeviceLookupSCSIHostByWWN(virConnectPtr conn,const char * wwnn,const char * wwpn,unsigned int flags)290 nodeDeviceLookupSCSIHostByWWN(virConnectPtr conn,
291 const char *wwnn,
292 const char *wwpn,
293 unsigned int flags)
294 {
295 virNodeDeviceObj *obj = NULL;
296 virNodeDeviceDef *def;
297 virNodeDevicePtr device = NULL;
298
299 virCheckFlags(0, NULL);
300
301 if (nodeDeviceInitWait() < 0)
302 return NULL;
303
304 if (!(obj = virNodeDeviceObjListFindSCSIHostByWWNs(driver->devs,
305 wwnn, wwpn)))
306 return NULL;
307
308 def = virNodeDeviceObjGetDef(obj);
309
310 if (virNodeDeviceLookupSCSIHostByWWNEnsureACL(conn, def) < 0)
311 goto cleanup;
312
313 if ((device = virGetNodeDevice(conn, def->name)))
314 device->parentName = g_strdup(def->parent);
315
316 cleanup:
317 virNodeDeviceObjEndAPI(&obj);
318 return device;
319 }
320
321 static virNodeDevicePtr
nodeDeviceLookupMediatedDeviceByUUID(virConnectPtr conn,const char * uuid,const char * parent_addr,unsigned int flags)322 nodeDeviceLookupMediatedDeviceByUUID(virConnectPtr conn,
323 const char *uuid,
324 const char *parent_addr,
325 unsigned int flags)
326 {
327 virNodeDeviceObj *obj = NULL;
328 virNodeDeviceDef *def;
329 virNodeDevicePtr device = NULL;
330
331 virCheckFlags(0, NULL);
332
333 if (!(obj = virNodeDeviceObjListFindMediatedDeviceByUUID(driver->devs,
334 uuid, parent_addr)))
335 return NULL;
336
337 def = virNodeDeviceObjGetDef(obj);
338
339 if ((device = virGetNodeDevice(conn, def->name)))
340 device->parentName = g_strdup(def->parent);
341
342 virNodeDeviceObjEndAPI(&obj);
343 return device;
344 }
345
346
347 char *
nodeDeviceGetXMLDesc(virNodeDevicePtr device,unsigned int flags)348 nodeDeviceGetXMLDesc(virNodeDevicePtr device,
349 unsigned int flags)
350 {
351 virNodeDeviceObj *obj;
352 virNodeDeviceDef *def;
353 char *ret = NULL;
354
355 virCheckFlags(0, NULL);
356
357 if (nodeDeviceInitWait() < 0)
358 return NULL;
359
360 if (!(obj = nodeDeviceObjFindByName(device->name)))
361 return NULL;
362 def = virNodeDeviceObjGetDef(obj);
363
364 if (virNodeDeviceGetXMLDescEnsureACL(device->conn, def) < 0)
365 goto cleanup;
366
367 if (nodeDeviceUpdateDriverName(def) < 0)
368 goto cleanup;
369
370 if (virNodeDeviceUpdateCaps(def) < 0)
371 goto cleanup;
372
373 ret = virNodeDeviceDefFormat(def);
374
375 cleanup:
376 virNodeDeviceObjEndAPI(&obj);
377 return ret;
378 }
379
380
381 char *
nodeDeviceGetParent(virNodeDevicePtr device)382 nodeDeviceGetParent(virNodeDevicePtr device)
383 {
384 virNodeDeviceObj *obj;
385 virNodeDeviceDef *def;
386 char *ret = NULL;
387
388 if (nodeDeviceInitWait() < 0)
389 return NULL;
390
391 if (!(obj = nodeDeviceObjFindByName(device->name)))
392 return NULL;
393 def = virNodeDeviceObjGetDef(obj);
394
395 if (virNodeDeviceGetParentEnsureACL(device->conn, def) < 0)
396 goto cleanup;
397
398 if (def->parent) {
399 ret = g_strdup(def->parent);
400 } else {
401 virReportError(VIR_ERR_INTERNAL_ERROR,
402 "%s", _("no parent for this device"));
403 }
404
405 cleanup:
406 virNodeDeviceObjEndAPI(&obj);
407 return ret;
408 }
409
410
411 int
nodeDeviceNumOfCaps(virNodeDevicePtr device)412 nodeDeviceNumOfCaps(virNodeDevicePtr device)
413 {
414 virNodeDeviceObj *obj;
415 virNodeDeviceDef *def;
416 int ret = -1;
417
418 if (nodeDeviceInitWait() < 0)
419 return -1;
420
421 if (!(obj = nodeDeviceObjFindByName(device->name)))
422 return -1;
423 def = virNodeDeviceObjGetDef(obj);
424
425 if (virNodeDeviceNumOfCapsEnsureACL(device->conn, def) < 0)
426 goto cleanup;
427
428 ret = virNodeDeviceCapsListExport(def, NULL);
429
430 cleanup:
431 virNodeDeviceObjEndAPI(&obj);
432 return ret;
433 }
434
435
436
437 int
nodeDeviceListCaps(virNodeDevicePtr device,char ** const names,int maxnames)438 nodeDeviceListCaps(virNodeDevicePtr device,
439 char **const names,
440 int maxnames)
441 {
442 virNodeDeviceObj *obj;
443 virNodeDeviceDef *def;
444 virNodeDevCapType *list = NULL;
445 int ncaps = 0;
446 int ret = -1;
447 size_t i = 0;
448
449 if (nodeDeviceInitWait() < 0)
450 return -1;
451
452 if (!(obj = nodeDeviceObjFindByName(device->name)))
453 return -1;
454 def = virNodeDeviceObjGetDef(obj);
455
456 if (virNodeDeviceListCapsEnsureACL(device->conn, def) < 0)
457 goto cleanup;
458
459 if ((ncaps = virNodeDeviceCapsListExport(def, &list)) < 0)
460 goto cleanup;
461
462 if (ncaps > maxnames)
463 ncaps = maxnames;
464
465 for (i = 0; i < ncaps; i++)
466 names[i] = g_strdup(virNodeDevCapTypeToString(list[i]));
467
468 ret = ncaps;
469
470 cleanup:
471 virNodeDeviceObjEndAPI(&obj);
472 if (ret < 0) {
473 size_t j;
474 for (j = 0; j < i; j++)
475 VIR_FREE(names[j]);
476 }
477
478 VIR_FREE(list);
479 return ret;
480 }
481
482
483 static int
nodeDeviceGetTime(time_t * t)484 nodeDeviceGetTime(time_t *t)
485 {
486 int ret = 0;
487
488 *t = time(NULL);
489 if (*t == (time_t)-1) {
490 virReportError(VIR_ERR_INTERNAL_ERROR,
491 "%s", _("Could not get current time"));
492
493 *t = 0;
494 ret = -1;
495 }
496
497 return ret;
498 }
499
500
501 typedef virNodeDevicePtr (*nodeDeviceFindNewDeviceFunc)(virConnectPtr conn,
502 const void* opaque);
503
504
505 /* When large numbers of devices are present on the host, it's
506 * possible for udev not to realize that it has work to do before we
507 * get here. We thus keep trying to find the new device we just
508 * created for up to LINUX_NEW_DEVICE_WAIT_TIME. Note that udev's
509 * default settle time is 180 seconds, so once udev realizes that it
510 * has work to do, it might take that long for the udev wait to
511 * return. Thus the total maximum time for this function to return is
512 * the udev settle time plus LINUX_NEW_DEVICE_WAIT_TIME.
513 *
514 * This whole area is a race, but if we retry the udev wait for
515 * LINUX_NEW_DEVICE_WAIT_TIME seconds and there's still no device,
516 * it's probably safe to assume it's not going to appear.
517 */
518 static virNodeDevicePtr
nodeDeviceFindNewDevice(virConnectPtr conn,nodeDeviceFindNewDeviceFunc func,const void * opaque)519 nodeDeviceFindNewDevice(virConnectPtr conn,
520 nodeDeviceFindNewDeviceFunc func,
521 const void *opaque)
522 {
523 virNodeDevicePtr device = NULL;
524 time_t start = 0, now = 0;
525
526 nodeDeviceGetTime(&start);
527
528 while ((now - start) < LINUX_NEW_DEVICE_WAIT_TIME) {
529
530 virWaitForDevices();
531
532 device = func(conn, opaque);
533
534 if (device != NULL)
535 break;
536
537 sleep(5);
538 if (nodeDeviceGetTime(&now) == -1)
539 break;
540 }
541
542 return device;
543 }
544
545
546 typedef struct {
547 const char *uuid;
548 const char *parent_addr;
549 } NewMediatedDeviceData;
550
551 static virNodeDevicePtr
nodeDeviceFindNewMediatedDeviceFunc(virConnectPtr conn,const void * opaque)552 nodeDeviceFindNewMediatedDeviceFunc(virConnectPtr conn,
553 const void *opaque)
554 {
555 const NewMediatedDeviceData *data = opaque;
556
557 return nodeDeviceLookupMediatedDeviceByUUID(conn, data->uuid, data->parent_addr, 0);
558 }
559
560
561 static virNodeDevicePtr
nodeDeviceFindNewMediatedDevice(virConnectPtr conn,const char * mdev_uuid,const char * parent_addr)562 nodeDeviceFindNewMediatedDevice(virConnectPtr conn,
563 const char *mdev_uuid,
564 const char *parent_addr)
565 {
566 NewMediatedDeviceData data = {mdev_uuid, parent_addr};
567 return nodeDeviceFindNewDevice(conn, nodeDeviceFindNewMediatedDeviceFunc,
568 &data);
569 }
570
571
572 typedef struct _NewSCSIHostFuncData NewSCSIHostFuncData;
573 struct _NewSCSIHostFuncData
574 {
575 const char *wwnn;
576 const char *wwpn;
577 };
578
579
580 static virNodeDevicePtr
nodeDeviceFindNewSCSIHostFunc(virConnectPtr conn,const void * opaque)581 nodeDeviceFindNewSCSIHostFunc(virConnectPtr conn,
582 const void *opaque)
583 {
584 const NewSCSIHostFuncData *data = opaque;
585
586 return nodeDeviceLookupSCSIHostByWWN(conn, data->wwnn, data->wwpn, 0);
587 }
588
589
590 static virNodeDevicePtr
nodeDeviceFindNewSCSIHost(virConnectPtr conn,const char * wwnn,const char * wwpn)591 nodeDeviceFindNewSCSIHost(virConnectPtr conn,
592 const char *wwnn,
593 const char *wwpn)
594 {
595 NewSCSIHostFuncData data = { .wwnn = wwnn, .wwpn = wwpn};
596
597 return nodeDeviceFindNewDevice(conn, nodeDeviceFindNewSCSIHostFunc, &data);
598 }
599
600
601 static bool
nodeDeviceHasCapability(virNodeDeviceDef * def,virNodeDevCapType type)602 nodeDeviceHasCapability(virNodeDeviceDef *def, virNodeDevCapType type)
603 {
604 virNodeDevCapsDef *cap = def->caps;
605
606 while (cap != NULL) {
607 if (cap->data.type == type)
608 return true;
609 cap = cap->next;
610 }
611
612 return false;
613 }
614
615
616 /* format a json string that provides configuration information about this mdev
617 * to the mdevctl utility */
618 static int
nodeDeviceDefToMdevctlConfig(virNodeDeviceDef * def,char ** buf)619 nodeDeviceDefToMdevctlConfig(virNodeDeviceDef *def, char **buf)
620 {
621 size_t i;
622 virNodeDevCapMdev *mdev = &def->caps->data.mdev;
623 g_autoptr(virJSONValue) json = virJSONValueNewObject();
624 const char *startval = mdev->autostart ? "auto" : "manual";
625
626 if (virJSONValueObjectAppendString(json, "mdev_type", mdev->type) < 0)
627 return -1;
628
629 if (virJSONValueObjectAppendString(json, "start", startval) < 0)
630 return -1;
631
632 if (mdev->attributes) {
633 g_autoptr(virJSONValue) attributes = virJSONValueNewArray();
634
635 for (i = 0; i < mdev->nattributes; i++) {
636 virMediatedDeviceAttr *attr = mdev->attributes[i];
637 g_autoptr(virJSONValue) jsonattr = virJSONValueNewObject();
638
639 if (virJSONValueObjectAppendString(jsonattr, attr->name, attr->value) < 0)
640 return -1;
641
642 if (virJSONValueArrayAppend(attributes, &jsonattr) < 0)
643 return -1;
644 }
645
646 if (virJSONValueObjectAppend(json, "attrs", &attributes) < 0)
647 return -1;
648 }
649
650 *buf = virJSONValueToString(json, false);
651 if (!*buf)
652 return -1;
653
654 return 0;
655 }
656
657
658 static char *
nodeDeviceObjFormatAddress(virNodeDeviceObj * obj)659 nodeDeviceObjFormatAddress(virNodeDeviceObj *obj)
660 {
661 virNodeDevCapsDef *caps = NULL;
662 char *addr = NULL;
663 virNodeDeviceDef *def = virNodeDeviceObjGetDef(obj);
664 for (caps = def->caps; caps != NULL; caps = caps->next) {
665 switch (caps->data.type) {
666 case VIR_NODE_DEV_CAP_PCI_DEV: {
667 virPCIDeviceAddress pci_addr = {
668 .domain = caps->data.pci_dev.domain,
669 .bus = caps->data.pci_dev.bus,
670 .slot = caps->data.pci_dev.slot,
671 .function = caps->data.pci_dev.function
672 };
673
674 addr = virPCIDeviceAddressAsString(&pci_addr);
675 break;
676 }
677
678 case VIR_NODE_DEV_CAP_CSS_DEV: {
679 virDomainDeviceCCWAddress ccw_addr = {
680 .cssid = caps->data.ccw_dev.cssid,
681 .ssid = caps->data.ccw_dev.ssid,
682 .devno = caps->data.ccw_dev.devno
683 };
684
685 addr = virDomainCCWAddressAsString(&ccw_addr);
686 break;
687 }
688
689 case VIR_NODE_DEV_CAP_AP_MATRIX:
690 addr = g_strdup(caps->data.ap_matrix.addr);
691 break;
692
693 case VIR_NODE_DEV_CAP_SYSTEM:
694 case VIR_NODE_DEV_CAP_USB_DEV:
695 case VIR_NODE_DEV_CAP_USB_INTERFACE:
696 case VIR_NODE_DEV_CAP_NET:
697 case VIR_NODE_DEV_CAP_SCSI_HOST:
698 case VIR_NODE_DEV_CAP_SCSI_TARGET:
699 case VIR_NODE_DEV_CAP_SCSI:
700 case VIR_NODE_DEV_CAP_STORAGE:
701 case VIR_NODE_DEV_CAP_FC_HOST:
702 case VIR_NODE_DEV_CAP_VPORTS:
703 case VIR_NODE_DEV_CAP_SCSI_GENERIC:
704 case VIR_NODE_DEV_CAP_DRM:
705 case VIR_NODE_DEV_CAP_MDEV_TYPES:
706 case VIR_NODE_DEV_CAP_MDEV:
707 case VIR_NODE_DEV_CAP_CCW_DEV:
708 case VIR_NODE_DEV_CAP_VDPA:
709 case VIR_NODE_DEV_CAP_AP_CARD:
710 case VIR_NODE_DEV_CAP_AP_QUEUE:
711 case VIR_NODE_DEV_CAP_VPD:
712 case VIR_NODE_DEV_CAP_LAST:
713 break;
714 }
715
716 if (addr)
717 break;
718 }
719
720 return addr;
721 }
722
723
724 virCommand *
nodeDeviceGetMdevctlCommand(virNodeDeviceDef * def,virMdevctlCommand cmd_type,char ** outbuf,char ** errbuf)725 nodeDeviceGetMdevctlCommand(virNodeDeviceDef *def,
726 virMdevctlCommand cmd_type,
727 char **outbuf,
728 char **errbuf)
729 {
730 g_autoptr(virCommand) cmd = NULL;
731 const char *subcommand = virMdevctlCommandTypeToString(cmd_type);
732 g_autofree char *inbuf = NULL;
733
734 switch (cmd_type) {
735 case MDEVCTL_CMD_CREATE:
736 /* now is the time to make sure "create" is replaced with "start" on
737 * mdevctl cmdline */
738 cmd = virCommandNewArgList(MDEVCTL, "start", NULL);
739 break;
740 case MDEVCTL_CMD_STOP:
741 case MDEVCTL_CMD_START:
742 case MDEVCTL_CMD_DEFINE:
743 case MDEVCTL_CMD_UNDEFINE:
744 cmd = virCommandNewArgList(MDEVCTL, subcommand, NULL);
745 break;
746 case MDEVCTL_CMD_LAST:
747 default:
748 /* SHOULD NEVER HAPPEN */
749 virReportError(VIR_ERR_INTERNAL_ERROR,
750 _("Unknown Command '%i'"), cmd_type);
751 return NULL;
752 }
753
754 switch (cmd_type) {
755 case MDEVCTL_CMD_CREATE:
756 case MDEVCTL_CMD_DEFINE:
757 if (!def->caps->data.mdev.parent_addr) {
758 virReportError(VIR_ERR_INTERNAL_ERROR,
759 _("unable to find parent device '%s'"), def->parent);
760 return NULL;
761 }
762
763 if (nodeDeviceDefToMdevctlConfig(def, &inbuf) < 0) {
764 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
765 _("couldn't convert node device def to mdevctl JSON"));
766 return NULL;
767 }
768
769 virCommandAddArgPair(cmd, "--parent", def->caps->data.mdev.parent_addr);
770 virCommandAddArgPair(cmd, "--jsonfile", "/dev/stdin");
771
772 virCommandSetInputBuffer(cmd, inbuf);
773 virCommandSetOutputBuffer(cmd, outbuf);
774 break;
775
776 case MDEVCTL_CMD_UNDEFINE:
777 case MDEVCTL_CMD_STOP:
778 case MDEVCTL_CMD_START:
779 /* No special handling here, we only need to pass UUID with these */
780 break;
781 case MDEVCTL_CMD_LAST:
782 default:
783 /* SHOULD NEVER HAPPEN */
784 break;
785 }
786
787 /* Fill in UUID for commands that need it */
788 if (def->caps->data.mdev.uuid)
789 virCommandAddArgPair(cmd, "--uuid", def->caps->data.mdev.uuid);
790
791 virCommandSetErrorBuffer(cmd, errbuf);
792
793 return g_steal_pointer(&cmd);
794 }
795
796
797 static int
virMdevctlCreate(virNodeDeviceDef * def,char ** uuid)798 virMdevctlCreate(virNodeDeviceDef *def, char **uuid)
799 {
800 int status;
801 g_autofree char *errmsg = NULL;
802 g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlCommand(def,
803 MDEVCTL_CMD_CREATE,
804 uuid,
805 &errmsg);
806
807 if (!cmd)
808 return -1;
809
810 /* an auto-generated uuid is returned via stdout if no uuid is specified in
811 * the mdevctl args */
812 if (virCommandRun(cmd, &status) < 0)
813 return -1;
814
815 if (status != 0) {
816 virReportError(VIR_ERR_INTERNAL_ERROR,
817 _("Unable to start mediated device: %s"),
818 MDEVCTL_ERROR(errmsg));
819 return -1;
820 }
821
822 /* remove newline */
823 *uuid = g_strstrip(*uuid);
824 return 0;
825 }
826
827
828 static int
virMdevctlDefine(virNodeDeviceDef * def,char ** uuid)829 virMdevctlDefine(virNodeDeviceDef *def, char **uuid)
830 {
831 int status;
832 g_autofree char *errmsg = NULL;
833 g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlCommand(def,
834 MDEVCTL_CMD_DEFINE,
835 uuid, &errmsg);
836
837 if (!cmd)
838 return -1;
839
840 /* an auto-generated uuid is returned via stdout if no uuid is specified in
841 * the mdevctl args */
842 if (virCommandRun(cmd, &status) < 0)
843 return -1;
844
845 if (status != 0) {
846 virReportError(VIR_ERR_INTERNAL_ERROR,
847 _("Unable to define mediated device: %s"),
848 MDEVCTL_ERROR(errmsg));
849 return -1;
850 }
851
852 /* remove newline */
853 *uuid = g_strstrip(*uuid);
854 return 0;
855 }
856
857
858 static virNodeDevicePtr
nodeDeviceCreateXMLMdev(virConnectPtr conn,virNodeDeviceDef * def)859 nodeDeviceCreateXMLMdev(virConnectPtr conn,
860 virNodeDeviceDef *def)
861 {
862 g_autofree char *uuid = NULL;
863
864 if (!def->parent) {
865 virReportError(VIR_ERR_XML_ERROR, "%s",
866 _("cannot create a mediated device without a parent"));
867 return NULL;
868 }
869
870 if (virMdevctlCreate(def, &uuid) < 0) {
871 return NULL;
872 }
873
874 if (uuid && uuid[0]) {
875 g_free(def->caps->data.mdev.uuid);
876 def->caps->data.mdev.uuid = g_steal_pointer(&uuid);
877 }
878
879 return nodeDeviceFindNewMediatedDevice(conn, def->caps->data.mdev.uuid,
880 def->caps->data.mdev.parent_addr);
881 }
882
883
884 virNodeDevicePtr
nodeDeviceCreateXML(virConnectPtr conn,const char * xmlDesc,unsigned int flags)885 nodeDeviceCreateXML(virConnectPtr conn,
886 const char *xmlDesc,
887 unsigned int flags)
888 {
889 g_autoptr(virNodeDeviceDef) def = NULL;
890 g_autofree char *wwnn = NULL;
891 g_autofree char *wwpn = NULL;
892 virNodeDevicePtr device = NULL;
893 const char *virt_type = NULL;
894
895 virCheckFlags(0, NULL);
896
897 if (nodeDeviceInitWait() < 0)
898 return NULL;
899
900 virt_type = virConnectGetType(conn);
901
902 if (!(def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, virt_type,
903 &driver->parserCallbacks, NULL)))
904 return NULL;
905
906 if (virNodeDeviceCreateXMLEnsureACL(conn, def) < 0)
907 return NULL;
908
909 if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_SCSI_HOST)) {
910 int parent_host;
911
912 if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) == -1)
913 return NULL;
914
915 if ((parent_host = virNodeDeviceObjListGetParentHost(driver->devs, def)) < 0)
916 return NULL;
917
918 if (virVHBAManageVport(parent_host, wwpn, wwnn, VPORT_CREATE) < 0)
919 return NULL;
920
921 device = nodeDeviceFindNewSCSIHost(conn, wwnn, wwpn);
922 /* We don't check the return value, because one way or another,
923 * we're returning what we get... */
924
925 if (device == NULL)
926 virReportError(VIR_ERR_NO_NODE_DEVICE,
927 _("no node device for '%s' with matching "
928 "wwnn '%s' and wwpn '%s'"),
929 def->name, wwnn, wwpn);
930 } else if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
931 device = nodeDeviceCreateXMLMdev(conn, def);
932 } else {
933 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
934 _("Unsupported device type"));
935 }
936
937 return device;
938 }
939
940
941 static int
virMdevctlStop(virNodeDeviceDef * def)942 virMdevctlStop(virNodeDeviceDef *def)
943 {
944 int status;
945 g_autoptr(virCommand) cmd = NULL;
946 g_autofree char *errmsg = NULL;
947
948 cmd = nodeDeviceGetMdevctlCommand(def, MDEVCTL_CMD_STOP, NULL, &errmsg);
949
950 if (!cmd)
951 return -1;
952
953 if (virCommandRun(cmd, &status) < 0)
954 return -1;
955
956 if (status != 0) {
957 virReportError(VIR_ERR_INTERNAL_ERROR,
958 _("Unable to destroy '%s': %s"), def->name,
959 MDEVCTL_ERROR(errmsg));
960 return -1;
961 }
962
963 return 0;
964 }
965
966
967 static int
virMdevctlUndefine(virNodeDeviceDef * def)968 virMdevctlUndefine(virNodeDeviceDef *def)
969 {
970 int status;
971 g_autoptr(virCommand) cmd = NULL;
972 g_autofree char *errmsg = NULL;
973
974 cmd = nodeDeviceGetMdevctlCommand(def, MDEVCTL_CMD_UNDEFINE, NULL, &errmsg);
975
976 if (!cmd)
977 return -1;
978
979 if (virCommandRun(cmd, &status) < 0)
980 return -1;
981
982 if (status != 0) {
983 virReportError(VIR_ERR_INTERNAL_ERROR,
984 _("Unable to undefine mediated device: %s"),
985 MDEVCTL_ERROR(errmsg));
986 return -1;
987 }
988
989 return 0;
990 }
991
992
993 static int
virMdevctlStart(virNodeDeviceDef * def)994 virMdevctlStart(virNodeDeviceDef *def)
995 {
996 int status;
997 g_autoptr(virCommand) cmd = NULL;
998 g_autofree char *errmsg = NULL;
999
1000 cmd = nodeDeviceGetMdevctlCommand(def, MDEVCTL_CMD_START, NULL, &errmsg);
1001
1002 if (!cmd)
1003 return -1;
1004
1005 if (virCommandRun(cmd, &status) < 0)
1006 return -1;
1007
1008 if (status != 0) {
1009 virReportError(VIR_ERR_INTERNAL_ERROR,
1010 _("Unable to create mediated device: %s"),
1011 MDEVCTL_ERROR(errmsg));
1012 return -1;
1013 }
1014
1015 return 0;
1016 }
1017
1018
1019 /* gets a virCommand object that executes a mdevctl command to set the
1020 * 'autostart' property of the device to the specified value
1021 */
1022 virCommand*
nodeDeviceGetMdevctlSetAutostartCommand(virNodeDeviceDef * def,bool autostart,char ** errmsg)1023 nodeDeviceGetMdevctlSetAutostartCommand(virNodeDeviceDef *def,
1024 bool autostart,
1025 char **errmsg)
1026 {
1027 virCommand *cmd = virCommandNewArgList(MDEVCTL,
1028 "modify",
1029 "--uuid",
1030 def->caps->data.mdev.uuid,
1031 NULL);
1032
1033 if (autostart)
1034 virCommandAddArg(cmd, "--auto");
1035 else
1036 virCommandAddArg(cmd, "--manual");
1037
1038 virCommandSetErrorBuffer(cmd, errmsg);
1039
1040 return cmd;
1041 }
1042
1043
1044 static int
virMdevctlSetAutostart(virNodeDeviceDef * def,bool autostart,char ** errmsg)1045 virMdevctlSetAutostart(virNodeDeviceDef *def, bool autostart, char **errmsg)
1046 {
1047 int status;
1048 g_autoptr(virCommand) cmd = NULL;
1049
1050 cmd = nodeDeviceGetMdevctlSetAutostartCommand(def, autostart, errmsg);
1051
1052 if (virCommandRun(cmd, &status) < 0 || status != 0)
1053 return -1;
1054
1055 return 0;
1056 }
1057
1058
1059 virCommand*
nodeDeviceGetMdevctlListCommand(bool defined,char ** output,char ** errmsg)1060 nodeDeviceGetMdevctlListCommand(bool defined,
1061 char **output,
1062 char **errmsg)
1063 {
1064 virCommand *cmd = virCommandNewArgList(MDEVCTL,
1065 "list",
1066 "--dumpjson",
1067 NULL);
1068
1069 if (defined)
1070 virCommandAddArg(cmd, "--defined");
1071
1072 virCommandSetOutputBuffer(cmd, output);
1073 virCommandSetErrorBuffer(cmd, errmsg);
1074
1075 return cmd;
1076 }
1077
1078
mdevGenerateDeviceName(virNodeDeviceDef * dev)1079 static void mdevGenerateDeviceName(virNodeDeviceDef *dev)
1080 {
1081 nodeDeviceGenerateName(dev, "mdev", dev->caps->data.mdev.uuid,
1082 dev->caps->data.mdev.parent_addr);
1083 }
1084
1085
1086 static bool
matchDeviceAddress(virNodeDeviceObj * obj,const void * opaque)1087 matchDeviceAddress(virNodeDeviceObj *obj,
1088 const void *opaque)
1089 {
1090 g_autofree char *addr = NULL;
1091 bool want = false;
1092
1093 virObjectLock(obj);
1094 addr = nodeDeviceObjFormatAddress(obj);
1095 want = STREQ_NULLABLE(addr, opaque);
1096 virObjectUnlock(obj);
1097 return want;
1098 }
1099
1100
1101 static virNodeDeviceDef*
nodeDeviceParseMdevctlChildDevice(const char * parent,virJSONValue * json)1102 nodeDeviceParseMdevctlChildDevice(const char *parent,
1103 virJSONValue *json)
1104 {
1105 virNodeDevCapMdev *mdev;
1106 const char *uuid;
1107 virJSONValue *props;
1108 virJSONValue *attrs;
1109 g_autoptr(virNodeDeviceDef) child = g_new0(virNodeDeviceDef, 1);
1110 virNodeDeviceObj *parent_obj;
1111 const char *start = NULL;
1112
1113 /* the child object should have a single key equal to its uuid.
1114 * The value is an object describing the properties of the mdev */
1115 if (virJSONValueObjectKeysNumber(json) != 1)
1116 return NULL;
1117
1118 uuid = virJSONValueObjectGetKey(json, 0);
1119 props = virJSONValueObjectGetValue(json, 0);
1120
1121 /* Look up id of parent device. mdevctl supports defining mdevs for parent
1122 * devices that are not present on the system (to support starting mdevs on
1123 * hotplug, etc) so the parent may not actually exist. */
1124 if ((parent_obj = virNodeDeviceObjListFind(driver->devs, matchDeviceAddress,
1125 (void *)parent))) {
1126 virNodeDeviceDef *parentdef = virNodeDeviceObjGetDef(parent_obj);
1127 child->parent = g_strdup(parentdef->name);
1128 virNodeDeviceObjEndAPI(&parent_obj);
1129 };
1130 if (!child->parent)
1131 child->parent = g_strdup("computer");
1132 child->caps = g_new0(virNodeDevCapsDef, 1);
1133 child->caps->data.type = VIR_NODE_DEV_CAP_MDEV;
1134
1135 mdev = &child->caps->data.mdev;
1136 mdev->uuid = g_strdup(uuid);
1137 mdev->parent_addr = g_strdup(parent);
1138 mdev->type =
1139 g_strdup(virJSONValueObjectGetString(props, "mdev_type"));
1140 start = virJSONValueObjectGetString(props, "start");
1141 mdev->autostart = STREQ_NULLABLE(start, "auto");
1142
1143 attrs = virJSONValueObjectGet(props, "attrs");
1144
1145 if (attrs && virJSONValueIsArray(attrs)) {
1146 size_t i;
1147 int nattrs = virJSONValueArraySize(attrs);
1148
1149 mdev->attributes = g_new0(virMediatedDeviceAttr*, nattrs);
1150 mdev->nattributes = nattrs;
1151
1152 for (i = 0; i < nattrs; i++) {
1153 virJSONValue *attr = virJSONValueArrayGet(attrs, i);
1154 virMediatedDeviceAttr *attribute;
1155 virJSONValue *value;
1156
1157 if (!virJSONValueIsObject(attr) ||
1158 virJSONValueObjectKeysNumber(attr) != 1)
1159 return NULL;
1160
1161 attribute = g_new0(virMediatedDeviceAttr, 1);
1162 attribute->name = g_strdup(virJSONValueObjectGetKey(attr, 0));
1163 value = virJSONValueObjectGetValue(attr, 0);
1164 attribute->value = g_strdup(virJSONValueGetString(value));
1165 mdev->attributes[i] = attribute;
1166 }
1167 }
1168 mdevGenerateDeviceName(child);
1169
1170 return g_steal_pointer(&child);
1171 }
1172
1173
1174 int
nodeDeviceParseMdevctlJSON(const char * jsonstring,virNodeDeviceDef *** devs)1175 nodeDeviceParseMdevctlJSON(const char *jsonstring,
1176 virNodeDeviceDef ***devs)
1177 {
1178 int n;
1179 g_autoptr(virJSONValue) json_devicelist = NULL;
1180 virNodeDeviceDef **outdevs = NULL;
1181 size_t noutdevs = 0;
1182 size_t i;
1183 size_t j;
1184 virJSONValue *obj;
1185
1186 json_devicelist = virJSONValueFromString(jsonstring);
1187
1188 if (!json_devicelist || !virJSONValueIsArray(json_devicelist)) {
1189 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1190 _("mdevctl JSON response contains no devices"));
1191 goto error;
1192 }
1193
1194 if (virJSONValueArraySize(json_devicelist) == 0) {
1195 VIR_DEBUG("mdevctl has no defined mediated devices");
1196 *devs = NULL;
1197 return 0;
1198 }
1199
1200 /* mdevctl list --dumpjson produces an output that is an array that
1201 * contains only a single object which contains a property for each parent
1202 * device */
1203 if (virJSONValueArraySize(json_devicelist) != 1) {
1204 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1205 _("Unexpected format for mdevctl response"));
1206 goto error;
1207 }
1208
1209 obj = virJSONValueArrayGet(json_devicelist, 0);
1210
1211 if (!virJSONValueIsObject(obj)) {
1212 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1213 _("device list is not an object"));
1214 goto error;
1215 }
1216
1217 n = virJSONValueObjectKeysNumber(obj);
1218 for (i = 0; i < n; i++) {
1219 const char *parent;
1220 virJSONValue *child_array;
1221 int nchildren;
1222
1223 /* The key of each object property is the name of a parent device
1224 * which maps to an array of child devices */
1225 parent = virJSONValueObjectGetKey(obj, i);
1226 child_array = virJSONValueObjectGetValue(obj, i);
1227
1228 if (!virJSONValueIsArray(child_array)) {
1229 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1230 _("Parent device's JSON object data is not an array"));
1231 goto error;
1232 }
1233
1234 nchildren = virJSONValueArraySize(child_array);
1235
1236 for (j = 0; j < nchildren; j++) {
1237 g_autoptr(virNodeDeviceDef) child = NULL;
1238 virJSONValue *child_obj = virJSONValueArrayGet(child_array, j);
1239
1240 if (!(child = nodeDeviceParseMdevctlChildDevice(parent, child_obj))) {
1241 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1242 _("Unable to parse child device"));
1243 goto error;
1244 }
1245
1246 VIR_APPEND_ELEMENT(outdevs, noutdevs, child);
1247 }
1248 }
1249
1250 *devs = outdevs;
1251 return noutdevs;
1252
1253 error:
1254 for (i = 0; i < noutdevs; i++)
1255 virNodeDeviceDefFree(outdevs[i]);
1256 VIR_FREE(outdevs);
1257 return -1;
1258 }
1259
1260
1261 int
nodeDeviceDestroy(virNodeDevicePtr device)1262 nodeDeviceDestroy(virNodeDevicePtr device)
1263 {
1264 int ret = -1;
1265 virNodeDeviceObj *obj = NULL;
1266 virNodeDeviceDef *def;
1267 g_autofree char *parent = NULL;
1268 g_autofree char *wwnn = NULL;
1269 g_autofree char *wwpn = NULL;
1270 unsigned int parent_host;
1271
1272 if (nodeDeviceInitWait() < 0)
1273 return -1;
1274
1275 if (!(obj = nodeDeviceObjFindByName(device->name)))
1276 return -1;
1277 def = virNodeDeviceObjGetDef(obj);
1278
1279 if (virNodeDeviceDestroyEnsureACL(device->conn, def) < 0)
1280 goto cleanup;
1281
1282 if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_SCSI_HOST)) {
1283 if (virNodeDeviceGetWWNs(def, &wwnn, &wwpn) < 0)
1284 goto cleanup;
1285
1286 /* Because we're about to release the lock and thus run into a race
1287 * possibility (however improbable) with a udevAddOneDevice change
1288 * event which would essentially free the existing @def (obj->def) and
1289 * replace it with something new, we need to grab the parent field
1290 * and then find the parent obj in order to manage the vport */
1291 parent = g_strdup(def->parent);
1292
1293 virNodeDeviceObjEndAPI(&obj);
1294
1295 if (!(obj = virNodeDeviceObjListFindByName(driver->devs, parent))) {
1296 virReportError(VIR_ERR_INTERNAL_ERROR,
1297 _("cannot find parent '%s' definition"), parent);
1298 goto cleanup;
1299 }
1300
1301 if (virSCSIHostGetNumber(parent, &parent_host) < 0)
1302 goto cleanup;
1303
1304 if (virVHBAManageVport(parent_host, wwpn, wwnn, VPORT_DELETE) < 0)
1305 goto cleanup;
1306
1307 ret = 0;
1308 } else if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
1309 g_autofree char *vfiogroup = NULL;
1310 VIR_AUTOCLOSE fd = -1;
1311
1312 if (!virNodeDeviceObjIsActive(obj)) {
1313 virReportError(VIR_ERR_OPERATION_INVALID,
1314 _("Device '%s' is not active"), def->name);
1315 goto cleanup;
1316 }
1317
1318 /* If this mediated device is in use by a vm, attempting to stop it
1319 * will block until the vm closes the device. The nodedev driver
1320 * cannot query the hypervisor driver to determine whether the device
1321 * is in use by any active domains, since that would introduce circular
1322 * dependencies between daemons and add a risk of deadlocks. So we need
1323 * to resort to a workaround. vfio only allows the group for a device
1324 * to be opened by one user at a time. So if we get EBUSY when opening
1325 * the group, we infer that the device is in use and therefore we
1326 * shouldn't try to remove the device. */
1327 vfiogroup = virMediatedDeviceGetIOMMUGroupDev(def->caps->data.mdev.uuid);
1328 if (!vfiogroup)
1329 goto cleanup;
1330
1331 fd = open(vfiogroup, O_RDONLY);
1332
1333 if (fd < 0 && errno == EBUSY) {
1334 virReportError(VIR_ERR_INTERNAL_ERROR,
1335 _("Unable to destroy '%s': device in use"),
1336 def->name);
1337 goto cleanup;
1338 }
1339
1340 if (virMdevctlStop(def) < 0)
1341 goto cleanup;
1342
1343 ret = 0;
1344 } else {
1345 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1346 _("Unsupported device type"));
1347 }
1348
1349 cleanup:
1350 virNodeDeviceObjEndAPI(&obj);
1351 return ret;
1352 }
1353
1354
1355 /* takes ownership of @def and potentially frees it. @def should not be used
1356 * after returning from this function */
1357 static int
nodeDeviceUpdateMediatedDevice(virNodeDeviceDef * def)1358 nodeDeviceUpdateMediatedDevice(virNodeDeviceDef *def)
1359 {
1360 virNodeDeviceObj *obj;
1361 virObjectEvent *event;
1362 bool defined = false;
1363 g_autoptr(virNodeDeviceDef) owned = def;
1364 g_autofree char *name = g_strdup(owned->name);
1365
1366 owned->driver = g_strdup("vfio_mdev");
1367
1368 if (!(obj = virNodeDeviceObjListFindByName(driver->devs, owned->name))) {
1369 virNodeDeviceDef *d = g_steal_pointer(&owned);
1370 if (!(obj = virNodeDeviceObjListAssignDef(driver->devs, d))) {
1371 virNodeDeviceDefFree(d);
1372 return -1;
1373 }
1374 } else {
1375 bool changed;
1376 virNodeDeviceDef *olddef = virNodeDeviceObjGetDef(obj);
1377
1378 defined = virNodeDeviceObjIsPersistent(obj);
1379 /* Active devices contain some additional information (e.g. sysfs
1380 * path) that is not provided by mdevctl, so re-use the existing
1381 * definition and copy over new mdev data */
1382 changed = nodeDeviceDefCopyFromMdevctl(olddef, owned);
1383
1384 if (defined && !changed) {
1385 /* if this device was already defined and the definition
1386 * hasn't changed, there's nothing to do for this device */
1387 virNodeDeviceObjEndAPI(&obj);
1388 return 0;
1389 }
1390 }
1391
1392 /* all devices returned by virMdevctlListDefined() are persistent */
1393 virNodeDeviceObjSetPersistent(obj, true);
1394 virNodeDeviceObjSetAutostart(obj, def->caps->data.mdev.autostart);
1395
1396 if (!defined)
1397 event = virNodeDeviceEventLifecycleNew(name,
1398 VIR_NODE_DEVICE_EVENT_DEFINED,
1399 0);
1400 else
1401 event = virNodeDeviceEventUpdateNew(name);
1402
1403 virNodeDeviceObjEndAPI(&obj);
1404 virObjectEventStateQueue(driver->nodeDeviceEventState, event);
1405
1406 return 0;
1407 }
1408
1409
1410 virNodeDevice*
nodeDeviceDefineXML(virConnect * conn,const char * xmlDesc,unsigned int flags)1411 nodeDeviceDefineXML(virConnect *conn,
1412 const char *xmlDesc,
1413 unsigned int flags)
1414 {
1415 g_autoptr(virNodeDeviceDef) def = NULL;
1416 const char *virt_type = NULL;
1417 g_autofree char *uuid = NULL;
1418 g_autofree char *name = NULL;
1419
1420 virCheckFlags(0, NULL);
1421
1422 if (nodeDeviceInitWait() < 0)
1423 return NULL;
1424
1425 virt_type = virConnectGetType(conn);
1426
1427 if (!(def = virNodeDeviceDefParseString(xmlDesc, CREATE_DEVICE, virt_type,
1428 &driver->parserCallbacks, NULL)))
1429 return NULL;
1430
1431 if (virNodeDeviceDefineXMLEnsureACL(conn, def) < 0)
1432 return NULL;
1433
1434 if (!nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
1435 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1436 _("Unsupported device type"));
1437 return NULL;
1438 }
1439
1440 if (!def->parent) {
1441 virReportError(VIR_ERR_XML_ERROR, "%s",
1442 _("cannot define a mediated device without a parent"));
1443 return NULL;
1444 }
1445
1446 if (virMdevctlDefine(def, &uuid) < 0) {
1447 return NULL;
1448 }
1449
1450 if (uuid && uuid[0]) {
1451 g_free(def->caps->data.mdev.uuid);
1452 def->caps->data.mdev.uuid = g_steal_pointer(&uuid);
1453 }
1454
1455 mdevGenerateDeviceName(def);
1456 name = g_strdup(def->name);
1457
1458 /* Normally we would call nodeDeviceFindNewMediatedDevice() here to wait
1459 * for the new device to appear. But mdevctl can take a while to query
1460 * devices, and if nodeDeviceFindNewMediatedDevice() doesn't find the new
1461 * device immediately it will wait for 5s before checking again. Since we
1462 * have already received the uuid from virMdevctlDefine(), we can simply
1463 * add the provisional device to the list and return it immediately and
1464 * avoid this long delay. */
1465 if (nodeDeviceUpdateMediatedDevice(g_steal_pointer(&def)) < 0)
1466 return NULL;
1467
1468 return virGetNodeDevice(conn, name);
1469 }
1470
1471
1472 int
nodeDeviceUndefine(virNodeDevice * device,unsigned int flags)1473 nodeDeviceUndefine(virNodeDevice *device,
1474 unsigned int flags)
1475 {
1476 int ret = -1;
1477 virNodeDeviceObj *obj = NULL;
1478 virNodeDeviceDef *def;
1479
1480 virCheckFlags(0, -1);
1481
1482 if (nodeDeviceInitWait() < 0)
1483 return -1;
1484
1485 if (!(obj = nodeDeviceObjFindByName(device->name)))
1486 return -1;
1487
1488 def = virNodeDeviceObjGetDef(obj);
1489
1490 if (virNodeDeviceUndefineEnsureACL(device->conn, def) < 0)
1491 goto cleanup;
1492
1493 if (!virNodeDeviceObjIsPersistent(obj)) {
1494 virReportError(VIR_ERR_OPERATION_INVALID,
1495 _("Node device '%s' is not defined"),
1496 def->name);
1497 goto cleanup;
1498 }
1499
1500 if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
1501 if (virMdevctlUndefine(def) < 0)
1502 goto cleanup;
1503
1504 ret = 0;
1505 } else {
1506 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1507 _("Unsupported device type"));
1508 }
1509
1510 cleanup:
1511 virNodeDeviceObjEndAPI(&obj);
1512 return ret;
1513 }
1514
1515
1516 int
nodeDeviceCreate(virNodeDevice * device,unsigned int flags)1517 nodeDeviceCreate(virNodeDevice *device,
1518 unsigned int flags)
1519 {
1520 int ret = -1;
1521 virNodeDeviceObj *obj = NULL;
1522 virNodeDeviceDef *def = NULL;
1523
1524 virCheckFlags(0, -1);
1525
1526 if (nodeDeviceInitWait() < 0)
1527 return -1;
1528
1529 if (!(obj = nodeDeviceObjFindByName(device->name)))
1530 return -1;
1531
1532 if (virNodeDeviceObjIsActive(obj)) {
1533 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
1534 _("Device is already active"));
1535 goto cleanup;
1536 }
1537 def = virNodeDeviceObjGetDef(obj);
1538
1539 if (virNodeDeviceCreateEnsureACL(device->conn, def) < 0)
1540 goto cleanup;
1541
1542 if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
1543 if (virMdevctlStart(def) < 0)
1544 goto cleanup;
1545
1546 ret = 0;
1547 } else {
1548 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1549 _("Unsupported device type"));
1550 }
1551
1552 cleanup:
1553 virNodeDeviceObjEndAPI(&obj);
1554 return ret;
1555 }
1556
1557
1558 int
nodeConnectNodeDeviceEventRegisterAny(virConnectPtr conn,virNodeDevicePtr device,int eventID,virConnectNodeDeviceEventGenericCallback callback,void * opaque,virFreeCallback freecb)1559 nodeConnectNodeDeviceEventRegisterAny(virConnectPtr conn,
1560 virNodeDevicePtr device,
1561 int eventID,
1562 virConnectNodeDeviceEventGenericCallback callback,
1563 void *opaque,
1564 virFreeCallback freecb)
1565 {
1566 int callbackID = -1;
1567
1568 if (virConnectNodeDeviceEventRegisterAnyEnsureACL(conn) < 0)
1569 return -1;
1570
1571 if (nodeDeviceInitWait() < 0)
1572 return -1;
1573
1574 if (virNodeDeviceEventStateRegisterID(conn, driver->nodeDeviceEventState,
1575 device, eventID, callback,
1576 opaque, freecb, &callbackID) < 0)
1577 callbackID = -1;
1578
1579 return callbackID;
1580 }
1581
1582
1583 int
nodeConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,int callbackID)1584 nodeConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
1585 int callbackID)
1586 {
1587 if (virConnectNodeDeviceEventDeregisterAnyEnsureACL(conn) < 0)
1588 return -1;
1589
1590 if (nodeDeviceInitWait() < 0)
1591 return -1;
1592
1593 if (virObjectEventStateDeregisterID(conn,
1594 driver->nodeDeviceEventState,
1595 callbackID, true) < 0)
1596 return -1;
1597
1598 return 0;
1599 }
1600
1601 int
nodedevRegister(void)1602 nodedevRegister(void)
1603 {
1604 #ifdef WITH_UDEV
1605 return udevNodeRegister();
1606 #endif
1607 }
1608
1609
1610 void
nodeDeviceGenerateName(virNodeDeviceDef * def,const char * subsystem,const char * sysname,const char * s)1611 nodeDeviceGenerateName(virNodeDeviceDef *def,
1612 const char *subsystem,
1613 const char *sysname,
1614 const char *s)
1615 {
1616 size_t i;
1617 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
1618
1619 virBufferAsprintf(&buf, "%s_%s",
1620 subsystem,
1621 sysname);
1622
1623 if (s != NULL)
1624 virBufferAsprintf(&buf, "_%s", s);
1625
1626 g_free(def->name);
1627 def->name = virBufferContentAndReset(&buf);
1628
1629 for (i = 0; i < strlen(def->name); i++) {
1630 if (!(g_ascii_isalnum(*(def->name + i))))
1631 *(def->name + i) = '_';
1632 }
1633 }
1634
1635
1636 static int
virMdevctlListDefined(virNodeDeviceDef *** devs,char ** errmsg)1637 virMdevctlListDefined(virNodeDeviceDef ***devs, char **errmsg)
1638 {
1639 int status;
1640 g_autofree char *output = NULL;
1641 g_autoptr(virCommand) cmd = nodeDeviceGetMdevctlListCommand(true, &output, errmsg);
1642
1643 if (virCommandRun(cmd, &status) < 0 || status != 0) {
1644 return -1;
1645 }
1646
1647 if (!output)
1648 return -1;
1649
1650 return nodeDeviceParseMdevctlJSON(output, devs);
1651 }
1652
1653
1654 typedef struct _virMdevctlForEachData virMdevctlForEachData;
1655 struct _virMdevctlForEachData {
1656 int ndefs;
1657 virNodeDeviceDef **defs;
1658 };
1659
1660
1661 /* This function keeps the list of persistent mediated devices consistent
1662 * between the nodedev driver and mdevctl.
1663 * @obj is a device that is currently known by the nodedev driver, and @opaque
1664 * contains the most recent list of devices defined by mdevctl. If @obj is no
1665 * longer defined in mdevctl, mark it as undefined and possibly remove it from
1666 * the driver as well. Returning 'true' from this function indicates that the
1667 * device should be removed from the nodedev driver list. */
1668 static bool
removeMissingPersistentMdev(virNodeDeviceObj * obj,const void * opaque)1669 removeMissingPersistentMdev(virNodeDeviceObj *obj,
1670 const void *opaque)
1671 {
1672 bool remove = false;
1673 const virMdevctlForEachData *data = opaque;
1674 size_t i;
1675 virNodeDeviceDef *def = virNodeDeviceObjGetDef(obj);
1676 virObjectEvent *event;
1677
1678 if (def->caps->data.type != VIR_NODE_DEV_CAP_MDEV)
1679 return false;
1680
1681 /* transient mdevs are populated via udev, so don't remove them from the
1682 * nodedev driver just because they are not reported by by mdevctl */
1683 if (!virNodeDeviceObjIsPersistent(obj))
1684 return false;
1685
1686 for (i = 0; i < data->ndefs; i++) {
1687 /* OK, this mdev is still defined by mdevctl */
1688 if (STREQ(data->defs[i]->name, def->name))
1689 return false;
1690 }
1691
1692 event = virNodeDeviceEventLifecycleNew(def->name,
1693 VIR_NODE_DEVICE_EVENT_UNDEFINED,
1694 0);
1695
1696 /* The device is active, but no longer defined by mdevctl. Keep the device
1697 * in the list, but mark it as non-persistent */
1698 if (virNodeDeviceObjIsActive(obj)) {
1699 virNodeDeviceObjSetAutostart(obj, false);
1700 virNodeDeviceObjSetPersistent(obj, false);
1701 } else {
1702 remove = true;
1703 }
1704
1705 virObjectEventStateQueue(driver->nodeDeviceEventState, event);
1706
1707 return remove;
1708 }
1709
1710
1711 int
nodeDeviceUpdateMediatedDevices(void)1712 nodeDeviceUpdateMediatedDevices(void)
1713 {
1714 g_autofree virNodeDeviceDef **defs = NULL;
1715 g_autofree char *errmsg = NULL;
1716 g_autofree char *mdevctl = NULL;
1717 virMdevctlForEachData data = { 0, };
1718 size_t i;
1719
1720 if (!(mdevctl = virFindFileInPath(MDEVCTL))) {
1721 VIR_DEBUG(MDEVCTL " not found. Skipping update of mediated devices.");
1722 return 0;
1723 }
1724
1725 if ((data.ndefs = virMdevctlListDefined(&defs, &errmsg)) < 0) {
1726 virReportError(VIR_ERR_INTERNAL_ERROR,
1727 _("failed to query mdevs from mdevctl: %s"), errmsg);
1728 return -1;
1729 }
1730
1731 /* Any mdevs that were previously defined but were not returned in the
1732 * latest mdevctl query should be removed from the device list */
1733 data.defs = defs;
1734 virNodeDeviceObjListForEachRemove(driver->devs,
1735 removeMissingPersistentMdev, &data);
1736
1737 for (i = 0; i < data.ndefs; i++)
1738 if (nodeDeviceUpdateMediatedDevice(defs[i]) < 0)
1739 return -1;
1740
1741 return 0;
1742 }
1743
1744
1745 /* returns true if any attributes were copied, else returns false */
1746 static bool
virMediatedDeviceAttrsCopy(virNodeDevCapMdev * dst,virNodeDevCapMdev * src)1747 virMediatedDeviceAttrsCopy(virNodeDevCapMdev *dst,
1748 virNodeDevCapMdev *src)
1749 {
1750 bool ret = false;
1751 size_t i;
1752
1753 if (src->nattributes != dst->nattributes) {
1754 ret = true;
1755 for (i = 0; i < dst->nattributes; i++)
1756 virMediatedDeviceAttrFree(dst->attributes[i]);
1757 g_free(dst->attributes);
1758
1759 dst->nattributes = src->nattributes;
1760 dst->attributes = g_new0(virMediatedDeviceAttr*,
1761 src->nattributes);
1762 for (i = 0; i < dst->nattributes; i++)
1763 dst->attributes[i] = virMediatedDeviceAttrNew();
1764 }
1765
1766 for (i = 0; i < src->nattributes; i++) {
1767 if (STRNEQ_NULLABLE(src->attributes[i]->name,
1768 dst->attributes[i]->name)) {
1769 ret = true;
1770 g_free(dst->attributes[i]->name);
1771 dst->attributes[i]->name =
1772 g_strdup(src->attributes[i]->name);
1773 }
1774 if (STRNEQ_NULLABLE(src->attributes[i]->value,
1775 dst->attributes[i]->value)) {
1776 ret = true;
1777 g_free(dst->attributes[i]->value);
1778 dst->attributes[i]->value =
1779 g_strdup(src->attributes[i]->value);
1780 }
1781 }
1782
1783 return ret;
1784 }
1785
1786
1787 /* A mediated device definitions from mdevctl contains additional info that is
1788 * not available from udev. Transfer this data to the new definition.
1789 * Returns true if anything was copied, else returns false */
1790 bool
nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef * dst,virNodeDeviceDef * src)1791 nodeDeviceDefCopyFromMdevctl(virNodeDeviceDef *dst,
1792 virNodeDeviceDef *src)
1793 {
1794 bool ret = false;
1795 virNodeDevCapMdev *srcmdev = &src->caps->data.mdev;
1796 virNodeDevCapMdev *dstmdev = &dst->caps->data.mdev;
1797
1798 if (STRNEQ_NULLABLE(dstmdev->type, srcmdev->type)) {
1799 ret = true;
1800 g_free(dstmdev->type);
1801 dstmdev->type = g_strdup(srcmdev->type);
1802 }
1803
1804 if (STRNEQ_NULLABLE(dstmdev->uuid, srcmdev->uuid)) {
1805 ret = true;
1806 g_free(dstmdev->uuid);
1807 dstmdev->uuid = g_strdup(srcmdev->uuid);
1808 }
1809
1810 if (virMediatedDeviceAttrsCopy(dstmdev, srcmdev))
1811 ret = true;
1812
1813 if (dstmdev->autostart != srcmdev->autostart) {
1814 ret = true;
1815 dstmdev->autostart = srcmdev->autostart;
1816 }
1817
1818 return ret;
1819 }
1820
1821
1822 int
nodeDeviceSetAutostart(virNodeDevice * device,int autostart)1823 nodeDeviceSetAutostart(virNodeDevice *device,
1824 int autostart)
1825 {
1826 int ret = -1;
1827 virNodeDeviceObj *obj = NULL;
1828 virNodeDeviceDef *def = NULL;
1829
1830 if (nodeDeviceInitWait() < 0)
1831 return -1;
1832
1833 if (!(obj = nodeDeviceObjFindByName(device->name)))
1834 return -1;
1835 def = virNodeDeviceObjGetDef(obj);
1836
1837 if (virNodeDeviceSetAutostartEnsureACL(device->conn, def) < 0)
1838 goto cleanup;
1839
1840 if (nodeDeviceHasCapability(def, VIR_NODE_DEV_CAP_MDEV)) {
1841 if (!virNodeDeviceObjIsPersistent(obj)) {
1842 virReportError(VIR_ERR_OPERATION_INVALID,
1843 "%s", _("cannot set autostart for transient device"));
1844 goto cleanup;
1845 }
1846
1847 if (autostart != virNodeDeviceObjIsAutostart(obj)) {
1848 g_autofree char *errmsg = NULL;
1849
1850 if (virMdevctlSetAutostart(def, autostart, &errmsg) < 0) {
1851 virReportError(VIR_ERR_INTERNAL_ERROR,
1852 _("Unable to set autostart on '%s': %s"),
1853 def->name,
1854 errmsg && errmsg[0] != '\0' ? errmsg : _("Unknown Error"));
1855 goto cleanup;
1856 }
1857 /* Due to mdevctl performance issues, it may take several seconds
1858 * to re-query mdevctl for the defined devices. Because the mdevctl
1859 * command returned without an error status, assume it was
1860 * successful and set the object status directly here rather than
1861 * waiting for the next query */
1862 virNodeDeviceObjSetAutostart(obj, autostart);
1863 }
1864 ret = 0;
1865 } else {
1866 virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
1867 _("Unsupported device type"));
1868 }
1869
1870 cleanup:
1871 virNodeDeviceObjEndAPI(&obj);
1872 return ret;
1873 }
1874
1875
1876 int
nodeDeviceGetAutostart(virNodeDevice * device,int * autostart)1877 nodeDeviceGetAutostart(virNodeDevice *device,
1878 int *autostart)
1879 {
1880 virNodeDeviceObj *obj = NULL;
1881 virNodeDeviceDef *def = NULL;
1882 int ret = -1;
1883
1884 if (nodeDeviceInitWait() < 0)
1885 return -1;
1886
1887 if (!(obj = nodeDeviceObjFindByName(device->name)))
1888 return -1;
1889 def = virNodeDeviceObjGetDef(obj);
1890
1891 if (virNodeDeviceGetAutostartEnsureACL(device->conn, def) < 0)
1892 goto cleanup;
1893
1894 *autostart = virNodeDeviceObjIsAutostart(obj);
1895 ret = 0;
1896
1897 cleanup:
1898 virNodeDeviceObjEndAPI(&obj);
1899 return ret;
1900 }
1901
1902
nodeDeviceDefPostParse(virNodeDeviceDef * def,G_GNUC_UNUSED void * opaque)1903 int nodeDeviceDefPostParse(virNodeDeviceDef *def,
1904 G_GNUC_UNUSED void *opaque)
1905 {
1906 virNodeDevCapsDef *caps = NULL;
1907 for (caps = def->caps; caps != NULL; caps = caps->next) {
1908 if (caps->data.type == VIR_NODE_DEV_CAP_MDEV) {
1909 virNodeDeviceObj *obj = NULL;
1910
1911 if (def->parent)
1912 obj = virNodeDeviceObjListFindByName(driver->devs, def->parent);
1913
1914 if (obj) {
1915 caps->data.mdev.parent_addr = nodeDeviceObjFormatAddress(obj);
1916 virNodeDeviceObjEndAPI(&obj);
1917 }
1918 }
1919 }
1920 return 0;
1921 }
1922
1923
1924 /* validate that parent exists */
nodeDeviceDefValidateMdev(virNodeDeviceDef * def,virNodeDevCapMdev * mdev,G_GNUC_UNUSED void * opaque)1925 static int nodeDeviceDefValidateMdev(virNodeDeviceDef *def,
1926 virNodeDevCapMdev *mdev,
1927 G_GNUC_UNUSED void *opaque)
1928 {
1929 virNodeDeviceObj *obj = NULL;
1930 if (!def->parent) {
1931 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1932 _("missing parent device"));
1933 return -1;
1934 }
1935 obj = virNodeDeviceObjListFindByName(driver->devs, def->parent);
1936 if (!obj) {
1937 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1938 _("invalid parent device '%s'"),
1939 def->parent);
1940 return -1;
1941 }
1942 virNodeDeviceObjEndAPI(&obj);
1943
1944 /* the post-parse callback should have found the address of the parent
1945 * device and stored it in the mdev caps */
1946 if (!mdev->parent_addr) {
1947 virReportError(VIR_ERR_PARSE_FAILED,
1948 _("Unable to find address for parent device '%s'"),
1949 def->parent);
1950 return -1;
1951 }
1952
1953 return 0;
1954 }
1955
nodeDeviceDefValidate(virNodeDeviceDef * def,G_GNUC_UNUSED void * opaque)1956 int nodeDeviceDefValidate(virNodeDeviceDef *def,
1957 G_GNUC_UNUSED void *opaque)
1958 {
1959 virNodeDevCapsDef *caps = NULL;
1960 for (caps = def->caps; caps != NULL; caps = caps->next) {
1961 switch (caps->data.type) {
1962 case VIR_NODE_DEV_CAP_MDEV:
1963 if (nodeDeviceDefValidateMdev(def, &caps->data.mdev, opaque) < 0)
1964 return -1;
1965 break;
1966
1967 case VIR_NODE_DEV_CAP_SYSTEM:
1968 case VIR_NODE_DEV_CAP_PCI_DEV:
1969 case VIR_NODE_DEV_CAP_USB_DEV:
1970 case VIR_NODE_DEV_CAP_USB_INTERFACE:
1971 case VIR_NODE_DEV_CAP_NET:
1972 case VIR_NODE_DEV_CAP_SCSI_HOST:
1973 case VIR_NODE_DEV_CAP_SCSI_TARGET:
1974 case VIR_NODE_DEV_CAP_SCSI:
1975 case VIR_NODE_DEV_CAP_STORAGE:
1976 case VIR_NODE_DEV_CAP_FC_HOST:
1977 case VIR_NODE_DEV_CAP_VPORTS:
1978 case VIR_NODE_DEV_CAP_SCSI_GENERIC:
1979 case VIR_NODE_DEV_CAP_DRM:
1980 case VIR_NODE_DEV_CAP_MDEV_TYPES:
1981 case VIR_NODE_DEV_CAP_CCW_DEV:
1982 case VIR_NODE_DEV_CAP_CSS_DEV:
1983 case VIR_NODE_DEV_CAP_VDPA:
1984 case VIR_NODE_DEV_CAP_AP_CARD:
1985 case VIR_NODE_DEV_CAP_AP_QUEUE:
1986 case VIR_NODE_DEV_CAP_AP_MATRIX:
1987 case VIR_NODE_DEV_CAP_VPD:
1988 case VIR_NODE_DEV_CAP_LAST:
1989 break;
1990 }
1991 }
1992 return 0;
1993 }
1994
1995
1996 int
nodeDeviceIsPersistent(virNodeDevice * device)1997 nodeDeviceIsPersistent(virNodeDevice *device)
1998 {
1999 virNodeDeviceObj *obj = NULL;
2000 virNodeDeviceDef *def = NULL;
2001 int ret = -1;
2002
2003 if (nodeDeviceInitWait() < 0)
2004 return -1;
2005
2006 if (!(obj = nodeDeviceObjFindByName(device->name)))
2007 return -1;
2008 def = virNodeDeviceObjGetDef(obj);
2009
2010 if (virNodeDeviceIsPersistentEnsureACL(device->conn, def) < 0)
2011 goto cleanup;
2012
2013 ret = virNodeDeviceObjIsPersistent(obj);
2014
2015 cleanup:
2016 virNodeDeviceObjEndAPI(&obj);
2017 return ret;
2018 }
2019
2020
2021 int
nodeDeviceIsActive(virNodeDevice * device)2022 nodeDeviceIsActive(virNodeDevice *device)
2023 {
2024 virNodeDeviceObj *obj = NULL;
2025 virNodeDeviceDef *def = NULL;
2026 int ret = -1;
2027
2028 if (nodeDeviceInitWait() < 0)
2029 return -1;
2030
2031 if (!(obj = nodeDeviceObjFindByName(device->name)))
2032 return -1;
2033 def = virNodeDeviceObjGetDef(obj);
2034
2035 if (virNodeDeviceIsActiveEnsureACL(device->conn, def) < 0)
2036 goto cleanup;
2037
2038 ret = virNodeDeviceObjIsActive(obj);
2039
2040 cleanup:
2041 virNodeDeviceObjEndAPI(&obj);
2042 return ret;
2043 }
2044