mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
pvSCSI: xend changes
Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com> Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
This commit is contained in:
1 parent
d2831c8ba9
commit
08a42ca0b5
14 files changed
+773
-6
No files matched your search
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2007, FUJITSU Limited
|
||||
# Based on the block scripts code.
|
||||
#
|
||||
|
||||
dir=$(dirname "$0")
|
||||
. "$dir/xen-hotplug-common.sh"
|
||||
|
||||
findCommand "$@"
|
||||
|
||||
case "$command" in
|
||||
add)
|
||||
success
|
||||
;;
|
||||
remove)
|
||||
# TODO
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -19,6 +19,9 @@ case "$XENBUS_TYPE" in
|
||||
vif)
|
||||
[ -n "$script" ] && $script "$ACTION"
|
||||
;;
|
||||
vscsi)
|
||||
/etc/xen/scripts/vscsi "$ACTION"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$ACTION" in
|
||||
|
||||
@@ -3,6 +3,7 @@ SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTI
|
||||
SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
|
||||
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} online"
|
||||
SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline", RUN+="$env{script} offline"
|
||||
SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
|
||||
SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
|
||||
KERNEL=="evtchn", NAME="xen/%k"
|
||||
KERNEL=="blktap[0-9]*", NAME="xen/%k"
|
||||
@@ -282,3 +282,26 @@ serial='pty'
|
||||
# '0' -> the bit must be '0'
|
||||
# 'x' -> we don't care (do not check)
|
||||
# 's' -> the bit must be the same as on the host that started this VM
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Configure PVSCSI devices:
|
||||
#
|
||||
#vscsi=[ 'PDEV, VDEV' ]
|
||||
#
|
||||
# PDEV gives physical SCSI device to be attached to specified guest
|
||||
# domain by one of the following identifier format.
|
||||
# - XX:XX:XX:XX (4-tuples with decimal notation which shows
|
||||
# "host:channel:target:lun")
|
||||
# - /dev/sdxx or sdx
|
||||
# - /dev/stxx or stx
|
||||
# - /dev/sgxx or sgx
|
||||
# - result of 'scsi_id -gu -s'.
|
||||
# ex. # scsi_id -gu -s /block/sdb
|
||||
# 36000b5d0006a0000006a0257004c0000
|
||||
#
|
||||
# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
|
||||
# which the specified guest domain recognize.
|
||||
#
|
||||
|
||||
#vscsi = [ '/dev/sdx, 0:0:0:0' ]
|
||||
@@ -161,3 +161,25 @@ serial='pty'
|
||||
# 'windows' - All Windows variants (Windows Server 2003/2008)
|
||||
#
|
||||
#guest_os_type='default'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Configure PVSCSI devices:
|
||||
#
|
||||
#vscsi=[ 'PDEV, VDEV' ]
|
||||
#
|
||||
# PDEV gives physical SCSI device to be attached to specified guest
|
||||
# domain by one of the following identifier format.
|
||||
# - XX:XX:XX:XX (4-tuples with decimal notation which shows
|
||||
# "host:channel:target:lun")
|
||||
# - /dev/sdxx or sdx
|
||||
# - /dev/stxx or stx
|
||||
# - /dev/sgxx or sgx
|
||||
# - result of 'scsi_id -gu -s'.
|
||||
# ex. # scsi_id -gu -s /block/sdb
|
||||
# 36000b5d0006a0000006a0257004c0000
|
||||
#
|
||||
# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
|
||||
# which the specified guest domain recognize.
|
||||
#
|
||||
|
||||
#vscsi = [ '/dev/sdx, 0:0:0:0' ]
|
||||
@@ -185,4 +185,27 @@ extra = "4"
|
||||
#on_reboot = 'restart'
|
||||
#on_crash = 'restart'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Configure PVSCSI devices:
|
||||
#
|
||||
#vscsi=[ 'PDEV, VDEV' ]
|
||||
#
|
||||
# PDEV gives physical SCSI device to be attached to specified guest
|
||||
# domain by one of the following identifier format.
|
||||
# - XX:XX:XX:XX (4-tuples with decimal notation which shows
|
||||
# "host:channel:target:lun")
|
||||
# - /dev/sdxx or sdx
|
||||
# - /dev/stxx or stx
|
||||
# - /dev/sgxx or sgx
|
||||
# - result of 'scsi_id -gu -s'.
|
||||
# ex. # scsi_id -gu -s /block/sdb
|
||||
# 36000b5d0006a0000006a0257004c0000
|
||||
#
|
||||
# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
|
||||
# which the specified guest domain recognize.
|
||||
#
|
||||
|
||||
#vscsi = [ '/dev/sdx, 0:0:0:0' ]
|
||||
|
||||
#============================================================================
|
||||
|
||||
@@ -221,4 +221,26 @@ extra = "4 VMID=%d usr=/dev/sda6" % vmid
|
||||
#on_reboot = 'restart'
|
||||
#on_crash = 'restart'
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Configure PVSCSI devices:
|
||||
#
|
||||
#vscsi=[ 'PDEV, VDEV' ]
|
||||
#
|
||||
# PDEV gives physical SCSI device to be attached to specified guest
|
||||
# domain by one of the following identifier format.
|
||||
# - XX:XX:XX:XX (4-tuples with decimal notation which shows
|
||||
# "host:channel:target:lun")
|
||||
# - /dev/sdxx or sdx
|
||||
# - /dev/stxx or stx
|
||||
# - /dev/sgxx or sgx
|
||||
# - result of 'scsi_id -gu -s'.
|
||||
# ex. # scsi_id -gu -s /block/sdb
|
||||
# 36000b5d0006a0000006a0257004c0000
|
||||
#
|
||||
# VDEV gives virtual SCSI device by 4-tuples (XX:XX:XX:XX) as
|
||||
# which the specified guest domain recognize.
|
||||
#
|
||||
|
||||
#vscsi = [ '/dev/sdx, 0:0:0:0' ]
|
||||
|
||||
#============================================================================
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- mode: python; -*-
|
||||
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2008 FUJITSU Limited
|
||||
# Based on the blkif.py
|
||||
#============================================================================
|
||||
|
||||
|
||||
"""Support for VSCSI Devices.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import string
|
||||
|
||||
def _vscsi_hctl_block(name, scsi_devices):
|
||||
""" block-device name is convert into hctl. (e.g., '/dev/sda',
|
||||
'0:0:0:0')"""
|
||||
try:
|
||||
search = re.compile(r'' + name + '$', re.DOTALL)
|
||||
except Exception, e:
|
||||
raise VmError("vscsi: invalid expression. " + str(e))
|
||||
chk = 0
|
||||
for hctl, block, sg, scsi_id in scsi_devices:
|
||||
if search.match(hctl):
|
||||
chk = 1
|
||||
break
|
||||
|
||||
if chk:
|
||||
return (hctl, block)
|
||||
else:
|
||||
return (None, None)
|
||||
|
||||
|
||||
def _vscsi_block_scsiid_to_hctl(phyname, scsi_devices):
|
||||
""" block-device name is convert into hctl. (e.g., '/dev/sda',
|
||||
'0:0:0:0')"""
|
||||
|
||||
if re.match('/dev/sd[a-z]+([1-9]|1[0-5])?$', phyname):
|
||||
# sd driver
|
||||
name = re.sub('(^/dev/)|([1-9]|1[0-5])?$', '', phyname)
|
||||
elif re.match('/dev/sg[0-9]+$', phyname):
|
||||
# sg driver
|
||||
name = re.sub('^/dev/', '', phyname)
|
||||
elif re.match('/dev/st[0-9]+$', phyname):
|
||||
# st driver
|
||||
name = re.sub('^/dev/', '', phyname)
|
||||
else:
|
||||
# scsi_id -gu
|
||||
name = phyname
|
||||
|
||||
chk = 0
|
||||
for hctl, block, sg, scsi_id in scsi_devices:
|
||||
if block == name:
|
||||
chk = 1
|
||||
break
|
||||
elif sg == name:
|
||||
chk = 1
|
||||
break
|
||||
elif scsi_id == name:
|
||||
chk = 1
|
||||
break
|
||||
|
||||
if chk:
|
||||
return (hctl, block)
|
||||
else:
|
||||
return (None, None)
|
||||
|
||||
|
||||
def vscsi_get_scsidevices():
|
||||
""" get all scsi devices"""
|
||||
|
||||
SERCH_SCSI_PATH = "/sys/bus/scsi/devices"
|
||||
devices = []
|
||||
|
||||
for dirpath, dirnames, files in os.walk(SERCH_SCSI_PATH):
|
||||
for hctl in dirnames:
|
||||
paths = os.path.join(dirpath, hctl)
|
||||
block = "-"
|
||||
for f in os.listdir(paths):
|
||||
if re.match('^block', f):
|
||||
os.chdir(os.path.join(paths, f))
|
||||
block = os.path.basename(os.getcwd())
|
||||
elif re.match('^tape', f):
|
||||
os.chdir(os.path.join(paths, f))
|
||||
block = os.path.basename(os.getcwd())
|
||||
elif re.match('^scsi_changer', f):
|
||||
os.chdir(os.path.join(paths, f))
|
||||
block = os.path.basename(os.getcwd())
|
||||
elif re.match('^onstream_tape', f):
|
||||
os.chdir(os.path.join(paths, f))
|
||||
block = os.path.basename(os.getcwd())
|
||||
|
||||
if re.match('^scsi_generic', f):
|
||||
os.chdir(os.path.join(paths, f))
|
||||
sg = os.path.basename(os.getcwd())
|
||||
lines = os.popen('/sbin/scsi_id -gu -s /class/scsi_generic/' + sg).read().split()
|
||||
if len(lines) == 0:
|
||||
scsi_id = '-'
|
||||
else:
|
||||
scsi_id = lines[0]
|
||||
|
||||
devices.append([hctl, block, sg, scsi_id])
|
||||
|
||||
return devices
|
||||
|
||||
|
||||
def vscsi_search_hctl_and_block(device):
|
||||
|
||||
scsi_devices = vscsi_get_scsidevices()
|
||||
|
||||
tmp = device.split(':')
|
||||
if len(tmp) == 4:
|
||||
(hctl, block) = _vscsi_hctl_block(device, scsi_devices)
|
||||
else:
|
||||
(hctl, block) = _vscsi_block_scsiid_to_hctl(device, scsi_devices)
|
||||
|
||||
return (hctl, block)
|
||||
|
||||
@@ -1216,7 +1216,7 @@ class XendConfig(dict):
|
||||
dev_type = sxp.name(config)
|
||||
dev_info = {}
|
||||
|
||||
if dev_type == 'pci':
|
||||
if dev_type == 'pci' or dev_type == 'vscsi':
|
||||
pci_devs_uuid = sxp.child_value(config, 'uuid',
|
||||
uuid.createString())
|
||||
|
||||
@@ -1625,7 +1625,7 @@ class XendConfig(dict):
|
||||
|
||||
dev_type, dev_info = self['devices'][dev_uuid]
|
||||
|
||||
if dev_type == 'pci': # Special case for pci
|
||||
if dev_type == 'pci' or dev_type == 'vscsi': # Special case for pci
|
||||
pci_dict = self.pci_convert_sxp_to_dict(config)
|
||||
pci_devs = pci_dict['devs']
|
||||
|
||||
@@ -1739,8 +1739,11 @@ class XendConfig(dict):
|
||||
ordered_refs = self.ordered_device_refs(target = target)
|
||||
for dev_uuid in ordered_refs:
|
||||
dev_type, dev_info = target['devices'][dev_uuid]
|
||||
if dev_type == 'pci': # special case for pci devices
|
||||
sxpr = ['pci', ['uuid', dev_info['uuid']]]
|
||||
if dev_type == 'pci' or dev_type == 'vscsi': # special case for pci devices
|
||||
if dev_type == 'pci':
|
||||
sxpr = ['pci', ['uuid', dev_info['uuid']]]
|
||||
elif dev_type == 'vscsi':
|
||||
sxpr = ['vscsi', ['uuid', dev_info['uuid']]]
|
||||
for pci_dev_info in dev_info['devs']:
|
||||
pci_dev_sxpr = ['dev']
|
||||
for opt, val in pci_dev_info.items():
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# A collection of DevControllers
|
||||
#
|
||||
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif
|
||||
from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif
|
||||
from xen.xend.server.BlktapController import BlktapController
|
||||
from xen.xend.server.ConsoleController import ConsoleController
|
||||
|
||||
@@ -45,6 +45,7 @@ class XendDevices:
|
||||
'vfb': vfbif.VfbifController,
|
||||
'vkbd': vfbif.VkbdifController,
|
||||
'console': ConsoleController,
|
||||
'vscsi': vscsiif.VSCSIController,
|
||||
}
|
||||
|
||||
#@classmethod
|
||||
|
||||
@@ -750,6 +750,52 @@ class XendDomainInfo:
|
||||
|
||||
return True
|
||||
|
||||
def vscsi_device_configure(self, dev_sxp):
|
||||
"""Configure an existing vscsi device.
|
||||
quoted pci funciton
|
||||
"""
|
||||
dev_class = sxp.name(dev_sxp)
|
||||
if dev_class != 'vscsi':
|
||||
return False
|
||||
|
||||
dev_config = self.pci_convert_sxp_to_dict(dev_sxp)
|
||||
dev = dev_config['devs'][0]
|
||||
req_devid = sxp.child_value(dev_sxp, 'devid')
|
||||
req_devid = int(req_devid)
|
||||
existing_dev_info = self._getDeviceInfo_vscsi(req_devid, dev['v-dev'])
|
||||
state = sxp.child_value(dev_sxp, 'state')
|
||||
|
||||
if state == 'Initialising':
|
||||
# new create
|
||||
# If request devid does not exist, create and exit.
|
||||
if existing_dev_info is None:
|
||||
self.device_create(dev_sxp)
|
||||
return True
|
||||
elif existing_dev_info == "exists":
|
||||
raise XendError("The virtual device %s is already defined" % dev['v-dev'])
|
||||
|
||||
elif state == 'Closing':
|
||||
if existing_dev_info is None:
|
||||
raise XendError("Cannot detach vscsi device does not exist")
|
||||
|
||||
# use DevController.reconfigureDevice to change device config
|
||||
dev_control = self.getDeviceController(dev_class)
|
||||
dev_uuid = dev_control.reconfigureDevice(req_devid, dev_config)
|
||||
dev_control.waitForDevice_reconfigure(req_devid)
|
||||
num_devs = dev_control.cleanupDevice(req_devid)
|
||||
|
||||
# update XendConfig with new device info
|
||||
if dev_uuid:
|
||||
new_dev_sxp = dev_control.configuration(req_devid)
|
||||
self.info.device_update(dev_uuid, new_dev_sxp)
|
||||
|
||||
# If there is no device left, destroy vscsi and remove config.
|
||||
if num_devs == 0:
|
||||
self.destroyDevice('vscsi', req_devid)
|
||||
del self.info['devices'][dev_uuid]
|
||||
|
||||
return True
|
||||
|
||||
def device_configure(self, dev_sxp, devid = None):
|
||||
"""Configure an existing device.
|
||||
|
||||
@@ -768,6 +814,9 @@ class XendDomainInfo:
|
||||
if dev_class == 'pci':
|
||||
return self.pci_device_configure(dev_sxp)
|
||||
|
||||
if dev_class == 'vscsi':
|
||||
return self.vscsi_device_configure(dev_sxp)
|
||||
|
||||
for opt_val in dev_sxp[1:]:
|
||||
try:
|
||||
dev_config[opt_val[0]] = opt_val[1]
|
||||
@@ -942,6 +991,25 @@ class XendDomainInfo:
|
||||
return dev_info
|
||||
return None
|
||||
|
||||
def _getDeviceInfo_vscsi(self, devid, vdev):
|
||||
devid = int(devid)
|
||||
for dev_type, dev_info in self.info.all_devices_sxpr():
|
||||
if dev_type != 'vscsi':
|
||||
continue
|
||||
existing_dev_uuid = sxp.child_value(dev_info, 'uuid')
|
||||
existing_conf = self.info['devices'][existing_dev_uuid][1]
|
||||
existing_dev = existing_conf['devs'][0]
|
||||
existing_devid = int(existing_dev['devid'])
|
||||
existing_vdev = existing_dev['v-dev']
|
||||
|
||||
if vdev == existing_vdev:
|
||||
return "exists"
|
||||
|
||||
if devid == existing_devid:
|
||||
return dev_info
|
||||
|
||||
return None
|
||||
|
||||
def setMemoryTarget(self, target):
|
||||
"""Set the memory target of this domain.
|
||||
@param target: In MiB.
|
||||
@@ -1811,10 +1879,12 @@ class XendDomainInfo:
|
||||
if self.image:
|
||||
self.image.prepareEnvironment()
|
||||
|
||||
vscsi_uuidlist = {}
|
||||
vscsi_devidlist = []
|
||||
ordered_refs = self.info.ordered_device_refs()
|
||||
for dev_uuid in ordered_refs:
|
||||
devclass, config = self.info['devices'][dev_uuid]
|
||||
if devclass in XendDevices.valid_devices():
|
||||
if devclass in XendDevices.valid_devices() and devclass != 'vscsi':
|
||||
log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
|
||||
dev_uuid = config.get('uuid')
|
||||
devid = self._createDevice(devclass, config)
|
||||
@@ -1823,6 +1893,27 @@ class XendDomainInfo:
|
||||
if dev_uuid in self.info['devices']:
|
||||
self.info['devices'][dev_uuid][1]['devid'] = devid
|
||||
|
||||
elif devclass == 'vscsi':
|
||||
vscsi_config = config.get('devs', [])[0]
|
||||
devid = vscsi_config.get('devid', '')
|
||||
dev_uuid = config.get('uuid')
|
||||
vscsi_uuidlist[devid] = dev_uuid
|
||||
vscsi_devidlist.append(devid)
|
||||
|
||||
#It is necessary to sorted it for /dev/sdxx in guest.
|
||||
if len(vscsi_uuidlist) > 0:
|
||||
vscsi_devidlist.sort()
|
||||
for vscsiid in vscsi_devidlist:
|
||||
dev_uuid = vscsi_uuidlist[vscsiid]
|
||||
devclass, config = self.info['devices'][dev_uuid]
|
||||
log.info("createDevice: %s : %s" % (devclass, scrub_password(config)))
|
||||
dev_uuid = config.get('uuid')
|
||||
devid = self._createDevice(devclass, config)
|
||||
# store devid in XendConfig for caching reasons
|
||||
if dev_uuid in self.info['devices']:
|
||||
self.info['devices'][dev_uuid][1]['devid'] = devid
|
||||
|
||||
|
||||
if self.image:
|
||||
self.image.createDeviceModel()
|
||||
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2007 FUJITSU Limited
|
||||
# Based on the blkif.py
|
||||
#============================================================================
|
||||
|
||||
|
||||
"""Support for VSCSI Devices.
|
||||
"""
|
||||
import re
|
||||
import string
|
||||
|
||||
import types
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend.XendError import VmError
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
from xen.xend.server.DevController import DevController, xenbusState
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
|
||||
class VSCSIController(DevController):
|
||||
"""VSCSI Devices.
|
||||
"""
|
||||
def __init__(self, vm):
|
||||
"""Create a VSCSI Devices.
|
||||
"""
|
||||
DevController.__init__(self, vm)
|
||||
|
||||
|
||||
def sxprs(self):
|
||||
"""@see DevController.sxprs"""
|
||||
devslist = []
|
||||
for devid in self.deviceIDs():
|
||||
vscsi_devs = self.readBackendList(devid, "vscsi-devs")
|
||||
vscsipath = "vscsi-devs/"
|
||||
devs = []
|
||||
vscsi_config = []
|
||||
for dev in vscsi_devs:
|
||||
devpath = vscsipath + dev
|
||||
backstate = self.readBackend(devid, devpath + '/state')
|
||||
pdev = self.readBackend(devid, devpath + '/p-dev')
|
||||
pdevname = self.readBackend(devid, devpath + '/p-devname')
|
||||
vdev = self.readBackend(devid, devpath + '/v-dev')
|
||||
localdevid = self.readBackend(devid, devpath + '/devid')
|
||||
frontstate = self.readFrontend(devid, devpath + '/state')
|
||||
devs.append(['dev', \
|
||||
['state', backstate], \
|
||||
['devid', localdevid], \
|
||||
['p-dev', pdev], \
|
||||
['p-devname', pdevname], \
|
||||
['v-dev', vdev], \
|
||||
['frontstate', frontstate] ])
|
||||
|
||||
vscsi_config.append(['devs', devs])
|
||||
state = self.readFrontend(devid, 'state')
|
||||
vscsi_config.append(['state', state])
|
||||
backid = self.readFrontend(devid, 'backend-id')
|
||||
vscsi_config.append(['backend-id', backid])
|
||||
backpath = self.readFrontend(devid, 'backend')
|
||||
vscsi_config.append(['backend', backpath])
|
||||
|
||||
devslist.append([devid, vscsi_config])
|
||||
|
||||
return devslist
|
||||
|
||||
|
||||
def getDeviceDetails(self, config):
|
||||
"""@see DevController.getDeviceDetails"""
|
||||
back = {}
|
||||
vscsipath = "vscsi-devs/"
|
||||
for vscsi_config in config.get('devs', []):
|
||||
localdevid = self.allocateDeviceID()
|
||||
# vscsi-devs/dev-0
|
||||
devpath = vscsipath + 'dev-%i' % localdevid
|
||||
back[devpath] = ""
|
||||
pdev = vscsi_config.get('p-dev', '')
|
||||
back[devpath + '/p-dev'] = pdev
|
||||
pdevname = vscsi_config.get('p-devname', '')
|
||||
back[devpath + '/p-devname'] = pdevname
|
||||
vdev = vscsi_config.get('v-dev', '')
|
||||
back[devpath + '/v-dev'] = vdev
|
||||
state = vscsi_config.get('state', '')
|
||||
back[devpath + '/state'] = str(xenbusState[state])
|
||||
devid = vscsi_config.get('devid', '')
|
||||
back[devpath + '/devid'] = str(devid)
|
||||
|
||||
back['uuid'] = config.get('uuid','')
|
||||
devid = int(devid)
|
||||
return (devid, back, {})
|
||||
|
||||
|
||||
def readBackendList(self, devid, *args):
|
||||
frontpath = self.frontendPath(devid)
|
||||
backpath = xstransact.Read(frontpath + "/backend")
|
||||
if backpath:
|
||||
paths = map(lambda x: backpath + "/" + x, args)
|
||||
return xstransact.List(*paths)
|
||||
|
||||
|
||||
def getDeviceConfiguration(self, devid, transaction = None):
|
||||
config = DevController.getDeviceConfiguration(self, devid, transaction)
|
||||
|
||||
vscsi_devs = []
|
||||
|
||||
devs = self.readBackendList(devid, "vscsi-devs")
|
||||
vscsipath = "vscsi-devs/"
|
||||
for dev in devs:
|
||||
devpath = vscsipath + dev
|
||||
pdev = self.readBackend(devid, devpath + '/p-dev')
|
||||
pdevname = self.readBackend(devid, devpath + '/p-devname')
|
||||
vdev = self.readBackend(devid, devpath + '/v-dev')
|
||||
state = self.readBackend(devid, devpath + '/state')
|
||||
localdevid = self.readBackend(devid, devpath + '/devid')
|
||||
dev_dict = {'p-dev': pdev,
|
||||
'p-devname': pdevname,
|
||||
'v-dev': pdevname,
|
||||
'state': state,
|
||||
'devid': localdevid }
|
||||
vscsi_devs.append(dev_dict)
|
||||
|
||||
config['devs'] = vscsi_devs
|
||||
config['uuid'] = self.readBackend(devid, 'uuid')
|
||||
return config
|
||||
|
||||
|
||||
def configuration(self, devid, transaction = None):
|
||||
"""Returns SXPR for devices on domain.
|
||||
@note: we treat this dict especially to convert to
|
||||
SXP because it is not a straight dict of strings."""
|
||||
|
||||
configDict = self.getDeviceConfiguration(devid, transaction)
|
||||
sxpr = [self.deviceClass]
|
||||
|
||||
# remove devs
|
||||
devs = configDict.pop('devs', [])
|
||||
|
||||
for dev in devs:
|
||||
dev_sxpr = ['dev']
|
||||
for dev_item in dev.items():
|
||||
dev_sxpr.append(list(dev_item))
|
||||
sxpr.append(dev_sxpr)
|
||||
|
||||
for key, val in configDict.items():
|
||||
if type(val) == type(list()):
|
||||
for v in val:
|
||||
sxpr.append([key, v])
|
||||
else:
|
||||
sxpr.append([key, val])
|
||||
|
||||
return sxpr
|
||||
|
||||
|
||||
def reconfigureDevice(self, _, config):
|
||||
"""@see DevController.reconfigureDevice"""
|
||||
(devid, back, front) = self.getDeviceDetails(config)
|
||||
devid = int(devid)
|
||||
vscsi_config = config['devs'][0]
|
||||
states = config.get('states', [])
|
||||
uuid = self.readBackend(devid, 'uuid')
|
||||
if states[0] == 'Initialising':
|
||||
back['uuid'] = uuid
|
||||
self.writeBackend(devid, back)
|
||||
|
||||
elif states[0] == 'Closing':
|
||||
found = False
|
||||
devs = self.readBackendList(devid, "vscsi-devs")
|
||||
vscsipath = "vscsi-devs/"
|
||||
vdev = vscsi_config.get('v-dev', '')
|
||||
|
||||
for dev in devs:
|
||||
devpath = vscsipath + dev
|
||||
old_vdev = self.readBackend(devid, devpath + '/v-dev')
|
||||
if vdev == old_vdev:
|
||||
found = True
|
||||
self.writeBackend(devid, devpath + '/state', \
|
||||
str(xenbusState['Closing']))
|
||||
break
|
||||
|
||||
if not found:
|
||||
raise VmError("Device %s not connected" % vdev)
|
||||
|
||||
else:
|
||||
raise XendError('Error configuring device invalid state %s'
|
||||
% state)
|
||||
|
||||
self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring']))
|
||||
return self.readBackend(devid, 'uuid')
|
||||
|
||||
|
||||
def cleanupDevice(self, devid):
|
||||
devs = self.readBackendList(devid, "vscsi-devs")
|
||||
vscsipath = "vscsi-devs/"
|
||||
new_num_devs = 0
|
||||
|
||||
for dev in devs:
|
||||
new_num_devs = new_num_devs + 1
|
||||
devpath = vscsipath + dev
|
||||
devstate = self.readBackend(devid, devpath + '/state')
|
||||
|
||||
if str(xenbusState['Closed']) == devstate:
|
||||
self.removeBackend(devid, devpath)
|
||||
frontpath = self.frontendPath(devid)
|
||||
xstransact.Remove(frontpath + '/' + devpath)
|
||||
new_num_devs = new_num_devs - 1
|
||||
|
||||
frontpath = self.frontendPath(devid)
|
||||
front_devstate = xstransact.Read(frontpath + '/' + devpath)
|
||||
if front_devstate is not None:
|
||||
if str(xenbusState['Closed']) == front_devstate:
|
||||
self.removeBackend(devid, devpath)
|
||||
xstransact.Remove(frontpath + '/' + devpath)
|
||||
new_num_devs = new_num_devs - 1
|
||||
|
||||
return new_num_devs
|
||||
|
||||
@@ -33,6 +33,7 @@ from xen.xend import osdep
|
||||
import xen.xend.XendClient
|
||||
from xen.xend.XendBootloader import bootloader
|
||||
from xen.util import blkif
|
||||
from xen.util import vscsi_util
|
||||
import xen.util.xsm.xsm as security
|
||||
from xen.xm.main import serverType, SERVER_XEN_API, get_single_vm
|
||||
|
||||
@@ -307,6 +308,11 @@ gopts.var('pci', val='BUS:DEV.FUNC',
|
||||
For example 'pci=c0:02.1'.
|
||||
The option may be repeated to add more than one pci device.""")
|
||||
|
||||
gopts.var('vscsi', val='PDEV,VDEV[,DOM]',
|
||||
fn=append_value, default=[],
|
||||
use="""Add a SCSI device to a domain. The physical device is PDEV,
|
||||
which is exported to the domain as VDEV(X:X:X:X).""")
|
||||
|
||||
gopts.var('ioports', val='FROM[-TO]',
|
||||
fn=append_value, default=[],
|
||||
use="""Add a legacy I/O range to a domain, using given params (in hex).
|
||||
@@ -638,6 +644,73 @@ def configure_pci(config_devs, vals):
|
||||
config_pci.insert(0, 'pci')
|
||||
config_devs.append(['device', config_pci])
|
||||
|
||||
def vscsi_convert_sxp_to_dict(dev_sxp):
|
||||
dev_dict = {}
|
||||
for opt_val in dev_sxp[1:]:
|
||||
try:
|
||||
opt, val = opt_val
|
||||
dev_dict[opt] = val
|
||||
except TypeError:
|
||||
pass
|
||||
return dev_dict
|
||||
|
||||
def vscsi_lookup_devid(devlist, req_devid):
|
||||
if len(devlist) == 0:
|
||||
return 0
|
||||
else:
|
||||
for devid, backend in devlist:
|
||||
if devid == req_devid:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def configure_vscsis(config_devs, vals):
|
||||
"""Create the config for vscsis (virtual scsi devices).
|
||||
"""
|
||||
devidlist = []
|
||||
config_scsi = []
|
||||
if len(vals.vscsi) == 0:
|
||||
return 0
|
||||
|
||||
scsi_devices = vscsi_util.vscsi_get_scsidevices()
|
||||
for (p_dev, v_dev, backend) in vals.vscsi:
|
||||
tmp = p_dev.split(':')
|
||||
if len(tmp) == 4:
|
||||
(p_hctl, block) = vscsi_util._vscsi_hctl_block(p_dev, scsi_devices)
|
||||
else:
|
||||
(p_hctl, block) = vscsi_util._vscsi_block_scsiid_to_hctl(p_dev, scsi_devices)
|
||||
|
||||
if p_hctl == None:
|
||||
raise ValueError("Cannot find device \"%s\"" % p_dev)
|
||||
|
||||
for config in config_scsi:
|
||||
dev = vscsi_convert_sxp_to_dict(config)
|
||||
if dev['v-dev'] == v_dev:
|
||||
raise ValueError('The virtual device "%s" is already defined' % v_dev)
|
||||
|
||||
v_hctl = v_dev.split(':')
|
||||
devid = int(v_hctl[0])
|
||||
config_scsi.append(['dev', \
|
||||
['state', 'Initialising'], \
|
||||
['devid', devid], \
|
||||
['p-dev', p_hctl], \
|
||||
['p-devname', block], \
|
||||
['v-dev', v_dev] ])
|
||||
|
||||
if vscsi_lookup_devid(devidlist, devid) == 0:
|
||||
devidlist.append([devid, backend])
|
||||
|
||||
for devid, backend in devidlist:
|
||||
tmp = []
|
||||
for config in config_scsi:
|
||||
dev = vscsi_convert_sxp_to_dict(config)
|
||||
if dev['devid'] == devid:
|
||||
tmp.append(config)
|
||||
|
||||
tmp.insert(0, 'vscsi')
|
||||
if backend:
|
||||
tmp.append(['backend', backend])
|
||||
config_devs.append(['device', tmp])
|
||||
|
||||
def configure_ioports(config_devs, vals):
|
||||
"""Create the config for legacy i/o ranges.
|
||||
"""
|
||||
@@ -829,6 +902,7 @@ def make_config(vals):
|
||||
config_devs = []
|
||||
configure_disks(config_devs, vals)
|
||||
configure_pci(config_devs, vals)
|
||||
configure_vscsis(config_devs, vals)
|
||||
configure_ioports(config_devs, vals)
|
||||
configure_irq(config_devs, vals)
|
||||
configure_vifs(config_devs, vals)
|
||||
@@ -896,6 +970,25 @@ def preprocess_pci(vals):
|
||||
err('Error in PCI slot syntax "%s"'%(pci_dev_str))
|
||||
vals.pci = pci
|
||||
|
||||
def preprocess_vscsi(vals):
|
||||
if not vals.vscsi: return
|
||||
scsi = []
|
||||
for scsi_str in vals.vscsi:
|
||||
d = scsi_str.split(',')
|
||||
n = len(d)
|
||||
if n == 2:
|
||||
tmp = d[1].split(':')
|
||||
if len(tmp) != 4:
|
||||
err('vscsi syntax error "%s"' % d[1])
|
||||
else:
|
||||
d.append(None)
|
||||
elif n == 3:
|
||||
pass
|
||||
else:
|
||||
err('vscsi syntax error "%s"' % scsi_str)
|
||||
scsi.append(d)
|
||||
vals.vscsi = scsi
|
||||
|
||||
def preprocess_ioports(vals):
|
||||
if not vals.ioports: return
|
||||
ioports = []
|
||||
@@ -1075,6 +1168,7 @@ def preprocess_vnc(vals):
|
||||
def preprocess(vals):
|
||||
preprocess_disk(vals)
|
||||
preprocess_pci(vals)
|
||||
preprocess_vscsi(vals)
|
||||
preprocess_ioports(vals)
|
||||
preprocess_ip(vals)
|
||||
preprocess_nfs(vals)
|
||||
|
||||
@@ -37,6 +37,7 @@ import datetime
|
||||
from select import select
|
||||
import xml.dom.minidom
|
||||
from xen.util.blkif import blkdev_name_to_number
|
||||
from xen.util import vscsi_util
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore', category=FutureWarning)
|
||||
@@ -182,6 +183,12 @@ SUBCOMMAND_HELP = {
|
||||
'Remove a domain\'s pass-through pci device.'),
|
||||
'pci-list' : ('<Domain>',
|
||||
'List pass-through pci devices for a domain.'),
|
||||
'scsi-attach' : ('<Domain> <PhysDevice> <VirtDevice> [BackDomain]',
|
||||
'Attach a new SCSI device.'),
|
||||
'scsi-detach' : ('<Domain> <VirtDevice>',
|
||||
'Detach a specified SCSI device.'),
|
||||
'scsi-list' : ('<Domain> [--long]',
|
||||
'List all SCSI devices currently attached.'),
|
||||
|
||||
# security
|
||||
|
||||
@@ -348,6 +355,9 @@ device_commands = [
|
||||
"pci-attach",
|
||||
"pci-detach",
|
||||
"pci-list",
|
||||
"scsi-attach",
|
||||
"scsi-detach",
|
||||
"scsi-list",
|
||||
]
|
||||
|
||||
vnet_commands = [
|
||||
@@ -2106,6 +2116,40 @@ def xm_pci_list(args):
|
||||
hdr = 1
|
||||
print ( fmt_str % x )
|
||||
|
||||
def vscsi_convert_sxp_to_dict(dev_sxp):
|
||||
dev_dict = {}
|
||||
for opt_val in dev_sxp[1:]:
|
||||
try:
|
||||
opt, val = opt_val
|
||||
dev_dict[opt] = val
|
||||
except TypeError:
|
||||
pass
|
||||
return dev_dict
|
||||
|
||||
def xm_scsi_list(args):
|
||||
xenapi_unsupported()
|
||||
(use_long, params) = arg_check_for_resource_list(args, "scsi-list")
|
||||
|
||||
dom = params[0]
|
||||
|
||||
devs = server.xend.domain.getDeviceSxprs(dom, 'vscsi')
|
||||
|
||||
if use_long:
|
||||
map(PrettyPrint.prettyprint, devs)
|
||||
else:
|
||||
hdr = 0
|
||||
for x in devs:
|
||||
if hdr == 0:
|
||||
print "%-3s %-3s %-5s %-10s %-5s %-10s %-4s" \
|
||||
% ('Idx', 'BE', 'state', 'phy-hctl', 'phy', 'vir-hctl', 'devstate')
|
||||
hdr = 1
|
||||
ni = parse_dev_info(x[1])
|
||||
ni['idx'] = int(x[0])
|
||||
for dev in x[1][0][1]:
|
||||
mi = vscsi_convert_sxp_to_dict(dev)
|
||||
print "%(idx)-3d %(backend-id)-3d %(state)-5d " % ni,
|
||||
print "%(p-dev)-10s %(p-devname)-5s %(v-dev)-10s %(frontstate)-4s" % mi
|
||||
|
||||
def parse_block_configuration(args):
|
||||
dom = args[0]
|
||||
|
||||
@@ -2285,6 +2329,38 @@ def xm_pci_attach(args):
|
||||
(dom, pci) = parse_pci_configuration(args, 'Initialising')
|
||||
server.xend.domain.device_configure(dom, pci)
|
||||
|
||||
def xm_scsi_attach(args):
|
||||
xenapi_unsupported()
|
||||
|
||||
arg_check(args, 'scsi-attach', 3, 4)
|
||||
p_devname = args[1]
|
||||
v_dev = args[2]
|
||||
|
||||
v_hctl = v_dev.split(':')
|
||||
if len(v_hctl) != 4:
|
||||
raise OptionError("Invalid argument: %s" % v_dev)
|
||||
|
||||
(p_hctl, block) = vscsi_util.vscsi_search_hctl_and_block(p_devname)
|
||||
|
||||
if p_hctl == None:
|
||||
raise OptionError("Cannot find device \"%s\"" % p_devname)
|
||||
|
||||
dom = args[0]
|
||||
vscsi = ['vscsi']
|
||||
vscsi.append(['dev', \
|
||||
['state', 'Initialising'], \
|
||||
['devid', v_hctl[0]], \
|
||||
['p-dev', p_hctl], \
|
||||
['p-devname', block], \
|
||||
['v-dev', v_dev] ])
|
||||
|
||||
if len(args) == 4:
|
||||
vscsi.append(['backend', args[3]])
|
||||
|
||||
vscsi.append(['state', 'Initialising'])
|
||||
vscsi.append(['devid', v_hctl[0]])
|
||||
server.xend.domain.device_configure(dom, vscsi)
|
||||
|
||||
def detach(args, deviceClass):
|
||||
rm_cfg = True
|
||||
dom = args[0]
|
||||
@@ -2353,6 +2429,27 @@ def xm_pci_detach(args):
|
||||
(dom, pci) = parse_pci_configuration(args, 'Closing')
|
||||
server.xend.domain.device_configure(dom, pci)
|
||||
|
||||
def xm_scsi_detach(args):
|
||||
xenapi_unsupported()
|
||||
arg_check(args, 'scsi-detach', 2)
|
||||
|
||||
v_dev = args[1]
|
||||
v_hctl = v_dev.split(':')
|
||||
if len(v_hctl) != 4:
|
||||
raise OptionError("Invalid argument: %s" % v_dev)
|
||||
|
||||
dom = args[0]
|
||||
vscsi = ['vscsi']
|
||||
vscsi.append(['dev', \
|
||||
['state', 'Closing'], \
|
||||
['devid', v_hctl[0]], \
|
||||
['p-dev', ''], \
|
||||
['p-devname', ''], \
|
||||
['v-dev', v_dev] ])
|
||||
|
||||
vscsi.append(['state', 'Closing'])
|
||||
vscsi.append(['devid', v_hctl[0]])
|
||||
server.xend.domain.device_configure(dom, vscsi)
|
||||
|
||||
def xm_vnet_list(args):
|
||||
xenapi_unsupported()
|
||||
@@ -2548,6 +2645,10 @@ commands = {
|
||||
"pci-attach": xm_pci_attach,
|
||||
"pci-detach": xm_pci_detach,
|
||||
"pci-list": xm_pci_list,
|
||||
# vscsi
|
||||
"scsi-attach": xm_scsi_attach,
|
||||
"scsi-detach": xm_scsi_detach,
|
||||
"scsi-list": xm_scsi_list,
|
||||
}
|
||||
|
||||
## The commands supported by a separate argument parser in xend.xm.
|
||||
|
||||