From b2d4e71226f857b495b680c481cd697edd054186 Mon Sep 17 00:00:00 2001 From: Chrysostomos Nanakos Date: Wed, 19 Feb 2014 15:46:47 +0200 Subject: [PATCH] Remove xsegbd support. Add blktap support Remove completely xsegbd support from vlmc commands and add blktap block device support concerning map, unmap and showmapped subcommands. --- python/archipelago/blktap.py | 178 ++++++++++++++++++++++++++++++++++++++++++ python/archipelago/vlmc.py | 124 ++++++++++------------------- 2 files changed, 220 insertions(+), 82 deletions(-) create mode 100644 python/archipelago/blktap.py diff --git a/python/archipelago/blktap.py b/python/archipelago/blktap.py new file mode 100644 index 0000000..0b44d72 --- /dev/null +++ b/python/archipelago/blktap.py @@ -0,0 +1,178 @@ +# Copyright 2014 GRNET S.A. All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and +# documentation are those of the authors and should not be +# interpreted as representing official policies, either expressed +# or implied, of GRNET S.A. +# +import os +import subprocess + + +def cmd_open(cmd, bufsize=-1, env=None): + inst = subprocess.Popen(cmd, shell=True, bufsize=bufsize, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=True) + return inst + +def doexec(args, inputtext=None): + proc = cmd_open(" ".join(args)) + if inputtext != None: + proc.stdin.write(inputtext) + stdout = proc.stdout + stderr = proc.stderr + rc = proc.wait() + return (rc, stdout, stderr) + +class VlmcTapdiskException(Exception): + pass + +class VlmcTapdisk(object): + '''Tapdisk operations''' + TAP_CTL = 'tap-ctl' + TAP_DEV = '/dev/xen/blktap-2/tapdev' + + class Tapdisk(object): + def __init__(self, pid=None, minor=-1, state=None, volume=None, + device=None): + self.pid = pid + self.minor = minor + self.state = state + self.volume = volume + self.device = device + + def __str__(self): + return 'volume=%s pid=%s minor=%s state=%s device=%s' \ + % (self.volume, self.pid, self.minor, self.state, self.device) + + @staticmethod + def exc(*args): + rc, stdout, stderr = doexec([VlmcTapdisk.TAP_CTL] + list(args)) + out, err = stdout.read().strip(), stderr.read().strip() + stdout.close() + stderr.close() + if rc: + raise VlmcTapdiskException('%s failed (%s %s %s)' % \ + (args, rc, out, err)) + return out + + @staticmethod + def check(): + try: + VlmcTapdisk.exc('check') + return 0 + except Exception, e: + print "'tap-ctl check' failed: %s" % e + return -1 + + @staticmethod + def list(): + tapdisks = [] + _list = VlmcTapdisk.exc('list') + if not _list: + return [] + + for line in _list.split('\n'): + tapdisk = VlmcTapdisk.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' % \ + (VlmcTapdisk.TAP_DEV, tapdisk.minor) + elif key == 'state': + tapdisk.state = value + elif key == 'args' and value.find(':') != -1: + _, tapdisk.volume = value.split(':') + + tapdisks.append(tapdisk) + + return tapdisks + + @staticmethod + def fromDevice(device): + if device.startswith(VlmcTapdisk.TAP_DEV): + minor = os.minor(os.stat(device).st_rdev) + tapdisks = filter(lambda x: x.minor == minor, VlmcTapdisk.list()) + if len(tapdisks) == 1: + return tapdisks[0] + return None + + @staticmethod + def create(volume): + return VlmcTapdisk.exc('create', '-a%s:%s' % ('archipelago', volume)) + + @staticmethod + def destroy(device): + tapdisk = VlmcTapdisk.fromDevice(device) + if tapdisk: + if tapdisk.pid: + VlmcTapdisk.exc('destroy', + '-p%s' % tapdisk.pid, + '-m%s' % tapdisk.minor) + else: + VlmcTapdisk.exc('free', '-m%s' % tapdisk.minor) + + @staticmethod + def pause(device): + tapdisk = VlmcTapdisk.fromDevice(device) + if tapdisk and tapdisk.pid: + VlmcTapdisk.exc('pause', + '-p%s' % tapdisk.pid, + '-m%s' % tapdisk.minor) + + @staticmethod + def unpause(device): + tapdisk = VlmcTapdisk.fromDevice(device) + if tapdisk and tapdisk.pid: + VlmcTapdisk.exc('pause', + '-p%s' % tapdisk.pid, + '-m%s' % tapdisk.minor) + + @staticmethod + def busy_pid(device): + rc, stdout, stderr = doexec(['fuser', device]) + out = stdout.read().strip() + stderr.close() + stdout.close() + return out + + @staticmethod + def is_mounted(device): + fd = open("/proc/mounts", "r") + for line in fd.readlines(): + if device == line.split()[0]: + return True + fd.close() + return False diff --git a/python/archipelago/vlmc.py b/python/archipelago/vlmc.py index d131408..697e322 100755 --- a/python/archipelago/vlmc.py +++ b/python/archipelago/vlmc.py @@ -42,30 +42,12 @@ from binascii import hexlify from ctypes import c_uint32, c_uint64 from .common import * +from blktap import VlmcTapdisk @exclusive() def get_mapped(): - try: - devices = os.listdir(os.path.join(XSEGBD_SYSFS, "devices/")) - except: - if loaded_module(xsegbd): - raise Error("Cannot list %s/devices/" % XSEGBD_SYSFS) - else: - return None - try: - mapped = [] - for f in devices: - d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id") - d_id = d_id.read().strip() - target = open(XSEGBD_SYSFS + "devices/" + f + "/target") - target = target.read().strip() - mapped.append((d_id, target)) - - except Exception, reason: - raise Error(reason) - - return mapped + return VlmcTapdisk.list() def showmapped(): @@ -77,7 +59,7 @@ def showmapped(): print "id\timage\t\tdevice" for m in mapped: - print "%s\t%s\t%s" % (m[0], m[1], DEVICE_PREFIX + m[0]) + print "%s\t%s\t%s" % (m.minor, m.volume, m.device) return len(mapped) @@ -92,12 +74,24 @@ def is_mapped(volume): return None for m in mapped: - d_id = m[0] - target = m[1] + d_id = m.minor + target = m.volume if target == volume: return d_id return None +def is_device_mapped(device): + mapped = get_mapped() + if not mapped: + return None + + for m in mapped: + d_id = m.minor + target = m.device + if target == device: + return d_id + return None + def create(name, size=None, snap=None, cont_addr=False, **kwargs): if len(name) < 6: @@ -204,83 +198,49 @@ def remove(name, **kwargs): @exclusive() def map_volume(name, **kwargs): - vport = peers['vlmcd'].portno_start - if not loaded_module(xsegbd): - raise Error("Xsegbd module not loaded") + if not loaded_module("blktap"): + raise Error("blktap module not loaded") device = is_mapped(name) if device is not None: raise Error("Volume %s already mapped on device %s%s" % (name, - DEVICE_PREFIX, device)) + '/dev/xen/blktap-2/tapdev', device)) - prev = config['XSEGBD_START'] try: - result = [int(open(XSEGBD_SYSFS + "devices/" + f + "/srcport").read(). - strip()) for f in os.listdir(XSEGBD_SYSFS + "devices/")] - result.sort() - - for p in result: - if p - prev > 1: - break - else: - prev = p - - port = prev + 1 - if port > config['XSEGBD_END']: - raise Error("Max xsegbd devices reached") - fd = os.open(XSEGBD_SYSFS + "add", os.O_WRONLY) - print >> sys.stderr, "write to %s : %s %d:%d:%d" % (XSEGBD_SYSFS + - "add", name, port, port - config['XSEGBD_START'] + - vport, REQS) - os.write(fd, "%s %d:%d:%d" % (name, port, port - config['XSEGBD_START'] - + vport, REQS)) - os.close(fd) - return port + device = VlmcTapdisk.create(name) + if device: + sys.stderr.write(device + '\n') + return + raise Error("Cannot map volume '%s'.\n" % name) except Exception, reason: raise Error(name + ': ' + str(reason)) @exclusive() def unmap_volume(name, **kwargs): - if not loaded_module(xsegbd): - raise Error("Xsegbd module not loaded") + if not loaded_module("blktap"): + raise Error("blktap module not loaded") device = name try: - for f in os.listdir(XSEGBD_SYSFS + "devices/"): - d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id") - d_id = d_id.read().strip() - target = open(XSEGBD_SYSFS + "devices/" + f + "/target") - target = target.read().strip() - if device == DEVICE_PREFIX + d_id: - fd = os.open(XSEGBD_SYSFS + "remove", os.O_WRONLY) - os.write(fd, d_id) - os.close(fd) - return - raise Error("Device %s doesn't exist" % device) + if is_device_mapped(device) is not None: + busy = VlmcTapdisk.busy_pid(device) + mounted = VlmcTapdisk.is_mounted(device) + if not busy and not mounted: + VlmcTapdisk.destroy(device) + else: + if busy: + raise Error("Device is busy (PID: %s)." % busy) + elif mounted: + raise Error("Device is mounted. Cannot unmap device.") + return + raise Error("Device doesn't exist") except Exception, reason: raise Error(device + ': ' + str(reason)) # FIXME: def resize(name, size, **kwargs): - if not loaded_module(xsegbd): - raise Error("Xsegbd module not loaded") - - try: - - for f in os.listdir(XSEGBD_SYSFS + "devices/"): - d_id = open(XSEGBD_SYSFS + "devices/" + f + "/id") - d_id = d_id.read().strip() - target = open(XSEGBD_SYSFS + "devices/" + f + "/target") - target = target.read().strip() - if name == target: - fd = os.open(XSEGBD_SYSFS + "devices/" + d_id + "/refresh", - os.O_WRONLY) - os.write(fd, "1") - os.close(fd) - - except Exception, reason: - raise Error(name + ': ' + str(reason)) + raise NotImplementedError() def lock(name, cli=False, **kwargs): @@ -407,11 +367,11 @@ def mapinfo(name, verbose=False, **kwargs): print "Version: " + str(version) print "Size: " + str(size) for i in range(blocks): - exists = bool(unpack("B", mapdata[pos:pos+1])[0]) + exists = bool(unpack("B", mapdata[pos:pos + 1])[0]) if exists: nr_exists += 1 pos += 1 - block = hexlify(mapdata[pos:pos+32]) + block = hexlify(mapdata[pos:pos + 32]) pos += 32 if verbose: print block, exists -- 1.7.10.4