mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
blktap2: Port Xend to the tap-ctl interface.
Signed-off-by: Jake Wires <jake.wires@citrix.com>
This commit is contained in:
1 parent
4b1af8b188
commit
9622dc5498
2 files changed
+120
-76
No files matched your search
@@ -63,7 +63,7 @@ from xen.xend.XendConstants import *
|
||||
from xen.xend.XendAPIConstants import *
|
||||
from xen.xend.XendCPUPool import XendCPUPool
|
||||
from xen.xend.server.DevConstants import xenbusState
|
||||
from xen.xend.server.BlktapController import TAPDISK_DEVICE, parseDeviceString
|
||||
from xen.xend.server.BlktapController import TapdiskController
|
||||
|
||||
from xen.xend.XendVMMetrics import XendVMMetrics
|
||||
|
||||
@@ -549,15 +549,8 @@ class XendDomainInfo:
|
||||
dev = xstransact.List(self.vmpath + '/device/tap2')
|
||||
for x in dev:
|
||||
path = self.getDeviceController('tap2').readBackend(x, 'params')
|
||||
if path and path.startswith(TAPDISK_DEVICE):
|
||||
try:
|
||||
_minor, _dev, ctrl = parseDeviceString(path)
|
||||
#pause the disk
|
||||
f = open(ctrl + '/pause', 'w')
|
||||
f.write('pause');
|
||||
f.close()
|
||||
except:
|
||||
pass
|
||||
if path and path.startswith(TapdiskController.TAP_DEV):
|
||||
TapdiskController.pause(path)
|
||||
except Exception, ex:
|
||||
log.warn('Could not pause blktap disk.');
|
||||
|
||||
@@ -578,17 +571,8 @@ class XendDomainInfo:
|
||||
dev = xstransact.List(self.vmpath + '/device/tap2')
|
||||
for x in dev:
|
||||
path = self.getDeviceController('tap2').readBackend(x, 'params')
|
||||
if path and path.startswith(TAPDISK_DEVICE):
|
||||
try:
|
||||
#Figure out the sysfs path.
|
||||
_minor, _dev, ctrl = parseDeviceString(path)
|
||||
#unpause the disk
|
||||
if(os.path.exists(ctrl + '/resume')):
|
||||
f = open(ctrl + '/resume', 'w');
|
||||
f.write('resume');
|
||||
f.close();
|
||||
except:
|
||||
pass
|
||||
if path and path.startswith(TapdiskController.TAP_DEV):
|
||||
TapdiskController.unpause(path)
|
||||
|
||||
except Exception, ex:
|
||||
log.warn('Could not unpause blktap disk: %s' % str(ex));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Copyright (c) 2005, XenSource Ltd.
|
||||
import string, re
|
||||
import string, re, os
|
||||
|
||||
from xen.xend.server.blkif import BlkifController
|
||||
from xen.xend.XendLogging import log
|
||||
@@ -8,11 +8,6 @@ from xen.util.xpopen import xPopen3
|
||||
phantomDev = 0;
|
||||
phantomId = 0;
|
||||
|
||||
TAPDISK_SYSFS = '/sys/class/blktap2'
|
||||
TAPDISK_BINARY = '/usr/sbin/tapdisk2'
|
||||
TAPDISK_DEVICE = '/dev/xen/blktap-2/tapdev'
|
||||
TAPDISK_CONTROL = TAPDISK_SYSFS + '/blktap'
|
||||
|
||||
blktap1_disk_types = [
|
||||
'aio',
|
||||
'sync',
|
||||
@@ -43,20 +38,6 @@ def doexec(args, inputtext=None):
|
||||
rc = proc.wait()
|
||||
return (rc,stdout,stderr)
|
||||
|
||||
def parseDeviceString(device):
|
||||
if device.find('/dev') == -1:
|
||||
raise Exception, 'invalid tap device: ' + device
|
||||
|
||||
pattern = re.compile(TAPDISK_DEVICE + '(\d+)$')
|
||||
groups = pattern.search(device)
|
||||
if not groups:
|
||||
raise Exception, 'malformed tap device: ' + device
|
||||
|
||||
minor = groups.group(1)
|
||||
control = TAPDISK_CONTROL + minor
|
||||
|
||||
return minor, device, control
|
||||
|
||||
# blktap1 device controller
|
||||
class BlktapController(BlkifController):
|
||||
def __init__(self, vm):
|
||||
@@ -179,18 +160,10 @@ class Blktap2Controller(BlktapController):
|
||||
(typ, params, file) = string.split(uname, ':', 2)
|
||||
subtyp = 'tapdisk'
|
||||
|
||||
#check for blktap2 installation.
|
||||
blktap2_installed=0;
|
||||
(rc,stdout, stderr) = doexec("cat /proc/devices");
|
||||
out = stdout.read();
|
||||
stdout.close();
|
||||
stderr.close();
|
||||
if( out.find("blktap2") >= 0 ):
|
||||
blktap2_installed=1;
|
||||
|
||||
if typ in ('tap'):
|
||||
if subtyp in ('tapdisk', 'ioemu'):
|
||||
if params not in blktap2_disk_types or not blktap2_installed:
|
||||
if params not in blktap2_disk_types or \
|
||||
TapdiskController.check():
|
||||
# pass this device off to BlktapController
|
||||
log.warn('WARNING: using deprecated blktap module')
|
||||
self.deviceClass = 'tap'
|
||||
@@ -198,22 +171,7 @@ class Blktap2Controller(BlktapController):
|
||||
self.deviceClass = 'tap2'
|
||||
return devid
|
||||
|
||||
if self.vm.image and self.vm.image.memory_sharing:
|
||||
cmd = [ TAPDISK_BINARY, '-n', '%s:%s' % (params, file), '-s', '%d' % self.vm.getDomid() ]
|
||||
else:
|
||||
cmd = [ TAPDISK_BINARY, '-n', '%s:%s' % (params, file) ]
|
||||
(rc,stdout,stderr) = doexec(cmd)
|
||||
|
||||
if rc != 0:
|
||||
err = stderr.read();
|
||||
out = stdout.read();
|
||||
stdout.close();
|
||||
stderr.close();
|
||||
raise Exception, 'Failed to create device.\n stdout: %s\n stderr: %s\nCheck that target \"%s\" exists and that blktap2 driver installed in dom0.' % (out.rstrip(), err.rstrip(), file);
|
||||
|
||||
minor, device, control = parseDeviceString(stdout.readline())
|
||||
stdout.close();
|
||||
stderr.close();
|
||||
device = TapdiskController.create(params, file)
|
||||
|
||||
# modify the configutration to create a blkback for the underlying
|
||||
# blktap2 device. Note: we need to preserve the original tapdisk uname
|
||||
@@ -226,8 +184,7 @@ class Blktap2Controller(BlktapController):
|
||||
config.pop('tapdisk_uname')
|
||||
return devid
|
||||
|
||||
# The new blocktap implementation requires a sysfs signal to close
|
||||
# out disks. This function is called from a thread when the
|
||||
# This function is called from a thread when the
|
||||
# domain is detached from the disk.
|
||||
def finishDeviceCleanup(self, backpath, path):
|
||||
"""Perform any device specific cleanup
|
||||
@@ -239,14 +196,117 @@ class Blktap2Controller(BlktapController):
|
||||
|
||||
#Figure out what we're going to wait on.
|
||||
self.waitForBackend_destroy(backpath)
|
||||
TapdiskController.destroy(path)
|
||||
|
||||
#Figure out the sysfs path.
|
||||
minor, dev, ctrl = parseDeviceString(path)
|
||||
class TapdiskException(Exception):
|
||||
pass
|
||||
|
||||
#Close out the disk
|
||||
f = open(ctrl + '/remove', 'w')
|
||||
f.write('remove');
|
||||
f.close()
|
||||
class TapdiskController(object):
|
||||
'''class which encapsulates all tapdisk control operations'''
|
||||
|
||||
return
|
||||
TAP_CTL = 'tap-ctl'
|
||||
TAP_DEV = '/dev/xen/blktap-2/tapdev'
|
||||
|
||||
class Tapdisk(object):
|
||||
def __init__(self, pid=None, minor=-1, state=None,
|
||||
dtype='', image=None, device=None):
|
||||
self.pid = pid
|
||||
self.minor = minor
|
||||
self.state = state
|
||||
self.dtype = dtype
|
||||
self.image = image
|
||||
self.device = device
|
||||
|
||||
def __str__(self):
|
||||
return 'image=%s pid=%s minor=%s state=%s type=%s device=%s' \
|
||||
% (self.image, self.pid, self.minor, self.state, self.dtype,
|
||||
self.device)
|
||||
|
||||
@staticmethod
|
||||
def exc(*args):
|
||||
rc, stdout, stderr = doexec([TapdiskController.TAP_CTL] + list(args))
|
||||
out, err = stdout.read().strip(), stderr.read().strip()
|
||||
stdout.close()
|
||||
stderr.close()
|
||||
if rc:
|
||||
raise TapdiskException('%s failed (%s %s %s)' % \
|
||||
(args, rc, out, err))
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def check():
|
||||
try:
|
||||
TapdiskController.exc('check')
|
||||
return 0
|
||||
except Exception, e:
|
||||
log.warn("tapdisk2 check failed: %s" % e)
|
||||
return -1
|
||||
|
||||
@staticmethod
|
||||
def list():
|
||||
tapdisks = []
|
||||
|
||||
_list = TapdiskController.exc('list')
|
||||
if not _list: return []
|
||||
|
||||
for line in _list.split('\n'):
|
||||
tapdisk = TapdiskController.Tapdisk()
|
||||
|
||||
for pair in line.split():
|
||||
key, value = pair.split('=')
|
||||
if key == 'pid':
|
||||
tapdisk.pid = value
|
||||
elif key == 'minor':
|
||||
tapdisk.minor = int(value)
|
||||
if tapdisk.minor >= 0:
|
||||
tapdisk.device = '%s%s' % \
|
||||
(TapdiskController.TAP_DEV, tapdisk.minor)
|
||||
elif key == 'state':
|
||||
tapdisk.state = value
|
||||
elif key == 'args' and value.find(':') != -1:
|
||||
tapdisk.dtype, tapdisk.image = value.split(':')
|
||||
|
||||
tapdisks.append(tapdisk)
|
||||
|
||||
return tapdisks
|
||||
|
||||
@staticmethod
|
||||
def fromDevice(device):
|
||||
if device.startswith(TapdiskController.TAP_DEV):
|
||||
minor = os.minor(os.stat(device).st_rdev)
|
||||
tapdisks = filter(lambda x: x.minor == minor,
|
||||
TapdiskController.list())
|
||||
if len(tapdisks) == 1:
|
||||
return tapdisks[0]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def create(dtype, image):
|
||||
return TapdiskController.exc('create', '-a%s:%s' % (dtype, image))
|
||||
|
||||
@staticmethod
|
||||
def destroy(device):
|
||||
tapdisk = TapdiskController.fromDevice(device)
|
||||
if tapdisk:
|
||||
if tapdisk.pid:
|
||||
TapdiskController.exc('destroy',
|
||||
'-p%s' % tapdisk.pid,
|
||||
'-m%s' % tapdisk.minor)
|
||||
else:
|
||||
TapdiskController.exc('free', '-m%s' % tapdisk.minor)
|
||||
|
||||
@staticmethod
|
||||
def pause(device):
|
||||
tapdisk = TapdiskController.fromDevice(device)
|
||||
if tapdisk and tapdisk.pid:
|
||||
TapdiskController.exc('pause',
|
||||
'-p%s' % tapdisk.pid,
|
||||
'-m%s' % tapdisk.minor)
|
||||
|
||||
@staticmethod
|
||||
def unpause(device):
|
||||
tapdisk = TapdiskController.fromDevice(device)
|
||||
if tapdisk and tapdisk.pid:
|
||||
TapdiskController.exc('unpause',
|
||||
'-p%s' % tapdisk.pid,
|
||||
'-m%s' % tapdisk.minor)
|
||||