Revision 02d7b9ae

b/lib/hypervisor/hv_kvm.py
37 37
import socket
38 38
import stat
39 39
import StringIO
40
from bitarray import bitarray
40 41
try:
41 42
  import affinity   # pylint: disable=F0401
42 43
except ImportError:
......
79 80
  constants.HV_KVM_SPICE_USE_TLS,
80 81
  ])
81 82

  
83
# Constant bitarray that reflects to a free pci slot
84
# Use it with bitarray.search()
85
_AVAILABLE_PCI_SLOT = bitarray("0")
86

  
82 87
# below constants show the format of runtime file
83 88
# the nics are in second possition, while the disks in 4th (last)
84 89
# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
......
105 110
  }
106 111

  
107 112

  
113
def _GenerateDeviceKVMId(dev_type, dev):
114
  """Helper function to generate a unique device name used by KVM
115

  
116
  QEMU monitor commands use names to identify devices. Here we use their pci
117
  slot and a part of their UUID to name them. dev.pci might be None for old
118
  devices in the cluster.
119

  
120
  @type dev_type: sting
121
  @param dev_type: device type of param dev
122
  @type dev: L{objects.Disk} or L{objects.NIC}
123
  @param dev: the device object for which we generate a kvm name
124
  @raise errors.HotplugError: in case a device has no pci slot (old devices)
125

  
126
  """
127

  
128
  if not dev.pci:
129
    raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" %
130
                              (dev_type, dev.uuid))
131

  
132
  return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
133

  
134

  
135
def _UpdatePCISlots(dev, pci_reservations):
136
  """Update pci configuration for a stopped instance
137

  
138
  If dev has a pci slot then reserve it, else find first available
139
  in pci_reservations bitarray. It acts on the same objects passed
140
  as params so there is no need to return anything.
141

  
142
  @type dev: L{objects.Disk} or L{objects.NIC}
143
  @param dev: the device object for which we update its pci slot
144
  @type pci_reservations: bitarray
145
  @param pci_reservations: existing pci reservations for an instance
146
  @raise errors.HotplugError: in case an instance has all its slot occupied
147

  
148
  """
149
  if dev.pci:
150
    free = dev.pci
151
  else: # pylint: disable=E1103
152
    [free] = pci_reservations.search(_AVAILABLE_PCI_SLOT, 1)
153
    if not free:
154
      raise errors.HypervisorError("All PCI slots occupied")
155
    dev.pci = int(free)
156

  
157
  pci_reservations[free] = True
158

  
159

  
108 160
def _GetExistingDeviceInfo(dev_type, device, runtime):
109 161
  """Helper function to get an existing device inside the runtime file
110 162

  
......
649 701
  # different than -drive is starting)
650 702
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
651 703

  
704
  _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*')
705
  _INFO_PCI_CMD = "info pci"
706
  _INFO_VERSION_RE = \
707
    re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M)
708
  _INFO_VERSION_CMD = "info version"
709

  
710
  _DEFAULT_PCI_RESERVATIONS = "11110000000000000000000000000000"
711

  
652 712
  ANCILLARY_FILES = [
653 713
    _KVM_NETWORK_SCRIPT,
654 714
    ]
......
1820 1880

  
1821 1881
    return result
1822 1882

  
1883
  def _GetFreePCISlot(self, instance, dev):
1884
    """Get the first available pci slot of a runnung instance.
1885

  
1886
    """
1887
    slots = bitarray(32)
1888
    slots.setall(False) # pylint: disable=E1101
1889
    output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD)
1890
    for line in output.stdout.splitlines():
1891
      match = self._INFO_PCI_RE.search(line)
1892
      if match:
1893
        slot = int(match.group(1))
1894
        slots[slot] = True
1895

  
1896
    [free] = slots.search(_AVAILABLE_PCI_SLOT, 1) # pylint: disable=E1101
1897
    if not free:
1898
      raise errors.HypervisorError("All PCI slots occupied")
1899

  
1900
    dev.pci = int(free)
1901

  
1823 1902
  @classmethod
1824 1903
  def _ParseKVMVersion(cls, text):
1825 1904
    """Parse the KVM version from the --help output.

Also available in: Unified diff