Creating a LVM backed XFS SR
LVM backed XFS SR Ive created a Logical Volume under Kubuntu 11.10 with XFS and Kronos installed The following is what was required:
install lvm2 and xfstools
"apt-get install lvm2 xfstools"
create a logical volume
(If you need help in doing this, there are many tutorials for LVM on the net) ( see [1] )
Then you must copy the XFSSR.py
"cp XFSSR.py /usr/lib/xcp/sm/"
create a symlink to XFSSR
"cd /usr/lib/xcp/sm/"
"ln -s XFSSR.py XFSSR"
once the logical volume is created restart xapi
"service xcp-xapi restart"
to create the SR, run
"SR=`xe sr-create type=xfs device-config:device=/dev/mapper/test-builder name-label=xfs`"
change '/dev/mapper/test-builder' to your lvm device to match your system
after its done, youll be able to use the XFS LVM filesystem as the default SR
Enjoy
SNIP XFSSR.py------------------
- !/usr/bin/env python
- Copyright (C) 2006-2007 XenSource Ltd.
- Copyright (C) 2008-2009 Citrix Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published
- by the Free Software Foundation; version 2.1 only.
- This program 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.
- Modified for XFS by Scott V. Kamp (outbackdingo@gmail.com)
- XFSSR: Based on local-file storage repository, mounts xfs partition
- EXTSR: Based on local-file storage repository, mounts ext partition
import SR, SRCommand, FileSR, util, lvutil, scsiutil
import os import tempfile import errno import xs_errors import vhdutil from lock import Lock import cleanup
CAPABILITIES = ["SR_PROBE","SR_UPDATE", "SR_SUPPORTS_LOCAL_CACHING", \
"VDI_CREATE","VDI_DELETE","VDI_ATTACH","VDI_DETACH", \ "VDI_UPDATE","VDI_CLONE","VDI_SNAPSHOT","VDI_RESIZE", \ "VDI_RESET_ON_BOOT","ATOMIC_PAUSE"]
CONFIGURATION = [ [ 'device', 'local device path (required) (e.g. /dev/sda3)' ] ]
DRIVER_INFO = {
'name': 'Local EXT3 VHD', 'description': 'SR plugin which represents disks as VHD files stored on a local EXT3 filesystem, created inside an LVM volume', 'vendor': 'Citrix Systems Inc', 'copyright': '(C) 2008 Citrix Systems Inc', 'driver_version': '1.0', 'required_api_version': '1.0', 'capabilities': CAPABILITIES, 'configuration': CONFIGURATION }
EXT_PREFIX = 'XSLocalEXT-'
class EXTSR(FileSR.FileSR):
"""EXT3 Local file storage repository""" def handles(srtype): return srtype == 'xfs' handles = staticmethod(handles)
def load(self, sr_uuid): self.ops_exclusive = FileSR.OPS_EXCLUSIVE self.lock = Lock(vhdutil.LOCK_TYPE_SR, self.uuid) self.sr_vditype = SR.DEFAULT_TAP if not self.dconf.has_key('device') or not self.dconf['device']: raise xs_errors.XenError('ConfigDeviceMissing')
self.root = self.dconf['device'] for dev in self.root.split(','): if not self._isvalidpathstring(dev): raise xs_errors.XenError('ConfigDeviceInvalid', \ opterr='path is %s' % dev) self.path = os.path.join(SR.MOUNT_BASE, sr_uuid) self.vgname = EXT_PREFIX + sr_uuid self.remotepath = os.path.join("/dev",self.vgname,sr_uuid) self.attached = self._checkmount()
def delete(self, sr_uuid): self.attach(sr_uuid) super(EXTSR, self).delete(sr_uuid) self.detach(sr_uuid)
# Check PVs match VG try: for dev in self.root.split(','): cmd = ["pvs", dev] txt = util.pread2(cmd) if txt.find(self.vgname) == -1: raise xs_errors.XenError('VolNotFound', \ opterr='volume is %s' % self.vgname) except util.CommandException, inst: raise xs_errors.XenError('PVSfailed', \ opterr='error is %d' % inst.code)
# Remove LV, VG and pv try: cmd = ["lvremove", "-f", self.remotepath] util.pread2(cmd) cmd = ["vgremove", self.vgname] util.pread2(cmd)
for dev in self.root.split(','): cmd = ["pvremove", dev] util.pread2(cmd) except util.CommandException, inst: raise xs_errors.XenError('LVMDelete', \ opterr='errno is %d' % inst.code) def attach(self, sr_uuid): if not self._checkmount(): try: #Activate LV cmd = ['lvchange','-ay',self.remotepath] util.pread2(cmd) # make a mountpoint: if not os.path.isdir(self.path): os.makedirs(self.path) except util.CommandException, inst: raise xs_errors.XenError('LVMMount', \ opterr='Unable to activate LV. Errno is %d' % inst.code) try: util.pread(["fsck", "-a", self.remotepath]) except util.CommandException, inst: if inst.code == 1: util.SMlog("FSCK detected and corrected FS errors. Not fatal.") else: raise xs_errors.XenError('LVMMount', \ opterr='FSCK failed on %s. Errno is %d' % (self.remotepath,inst.code))
try: util.pread(["mount", self.remotepath, self.path])
FileSR.FileSR.attach(self, sr_uuid)
self.attached = True except util.CommandException, inst: raise xs_errors.XenError('LVMMount', \ opterr='Failed to mount FS. Errno is %d' % inst.code) #Update SCSIid string scsiutil.add_serial_record(self.session, self.sr_ref, \ scsiutil.devlist_to_serialstring(self.root.split(','))) # Set the block scheduler for dev in self.root.split(','): self.block_setscheduler(dev)
def detach(self, sr_uuid): if not self._checkmount(): return cleanup.abort(self.uuid) try: # Change directory to avoid unmount conflicts os.chdir(SR.MOUNT_BASE) # unmount the device util.pread(["umount", self.path])
# remove the mountpoint os.rmdir(self.path) self.path = None
# deactivate SR try: cmd = ["lvchange", "-an", self.remotepath] util.pread2(cmd) except util.CommandException, inst: raise xs_errors.XenError('LVMUnMount', \ opterr='lvm -an failed errno is %d' % inst.code)
self.attached = False except util.CommandException, inst: raise xs_errors.XenError('LVMUnMount', \ opterr='errno is %d' % inst.code) except: raise xs_errors.XenError('LVMUnMount')
def probe(self): return lvutil.srlist_toxml(lvutil.scan_srlist(EXT_PREFIX, self.root))
def create(self, sr_uuid, size): if self._checkmount(): raise xs_errors.XenError('SRExists')
# Check none of the devices already in use by other PBDs if util.test_hostPBD_devs(self.session, self.root): raise xs_errors.XenError('SRInUse')
# Check serial number entry in SR records for dev in self.root.split(','): if util.test_scsiserial(self.session, dev): raise xs_errors.XenError('SRInUse')
if not lvutil._checkVG(self.vgname): systemroot = util.getrootdev() rootdev = self.root.split(',')[0] # Create PVs for each device for dev in self.root.split(','): if dev in [systemroot, '%s1'%systemroot, '%s2'%systemroot]: raise xs_errors.XenError('Rootdev', \ opterr=('Device %s contains core system files, ' \ + 'please use another device') % dev)
if not os.path.exists(dev): raise xs_errors.XenError('InvalidDev', \ opterr=('Device %s does not exist') % dev)
try: f = os.open("%s" % dev, os.O_RDWR | os.O_EXCL) except: raise xs_errors.XenError('SRInUse') os.close(f) try: # Overwrite the disk header, try direct IO first cmd = ["dd","if=/dev/zero","of=%s" % dev,"bs=1M", \ "count=100","oflag=direct"] util.pread2(cmd) except util.CommandException, inst: if inst.code == errno.EPERM: try: cmd = ["dd","if=/dev/zero","of=%s" % dev,"bs=1M", \ "count=100"] util.pread2(cmd) except util.CommandException, inst: raise xs_errors.XenError('LVMWrite', opterr='disk %s, error %d' % (dev, inst.code)) else: raise xs_errors.XenError('LVMWrite', opterr='disk %s, error %d' % (dev, inst.code)) if not lvutil._checkPV(dev): try: cmd = ["pvcreate", "--metadatasize", "10M", dev] util.pread2(cmd) except util.CommandException, inst: raise xs_errors.XenError('LVMPartCreate', opterr='disk %s, error %d' % (dev, inst.code)) else: raise xs_errors.XenError('LVMPartInUse', opterr='disk %s' % dev)
# Create VG on first device try: cmd = ["vgcreate", self.vgname, rootdev] util.pread2(cmd) except : raise xs_errors.XenError('LVMGroupCreate')
# Then add any additional devs into the VG for dev in self.root.split(',')[1:]: try: cmd = ["vgextend", self.vgname, dev] util.pread2(cmd) except util.CommandException, inst: # One of the PV args failed, delete SR try: cmd = ["vgremove", self.vgname] util.pread2(cmd) except: pass raise xs_errors.XenError('LVMGroupCreate') if lvutil._checkLV(self.remotepath): raise xs_errors.XenError('SRExists') try: numdevs = len(self.root.split(',')) cmd = ["lvcreate", "-n", sr_uuid] if numdevs > 1: lowest = -1 for dev in self.root.split(','): stats = lvutil._getPVstats(dev) if lowest < 0 or stats['freespace'] < lowest: lowest = stats['freespace'] size_mb = (lowest / (1024 * 1024)) * numdevs
# Add stripe parameter to command cmd += ["-i", str(numdevs), "-I", "2048"] else: stats = lvutil._getVGstats(self.vgname) size_mb = stats['freespace'] / (1024 * 1024) assert(size_mb > 0) cmd += ["-L", str(size_mb), self.vgname] text = util.pread(cmd)
cmd = ["lvchange", "-ay", self.remotepath] text = util.pread(cmd) except util.CommandException, inst: raise xs_errors.XenError('LVMCreate', \ opterr='lv operation, error %d' % inst.code) except AssertionError: raise xs_errors.XenError('SRNoSpace', \ opterr='Insufficient space in VG %s' % self.vgname)
try: util.pread2(["mkfs.xfs", self.remotepath]) except util.CommandException, inst: raise xs_errors.XenError('LVMFilesystem', \ opterr='mkfs failed error %d' % inst.code)
#Update serial number string scsiutil.add_serial_record(self.session, self.sr_ref, \ scsiutil.devlist_to_serialstring(self.root.split(',')))
def vdi(self, uuid, loadLocked = False): if not loadLocked: return EXTFileVDI(self, uuid) return EXTFileVDI(self, uuid)
def _checkmount(self): return self.path and os.path.ismount(self.path)
class EXTFileVDI(FileSR.FileVDI):
def attach(self, sr_uuid, vdi_uuid): try: vdi_ref = self.sr.srcmd.params['vdi_ref'] self.session.xenapi.VDI.remove_from_xenstore_data(vdi_ref, \ "vdi-type") self.session.xenapi.VDI.remove_from_xenstore_data(vdi_ref, \ "storage-type") self.session.xenapi.VDI.add_to_xenstore_data(vdi_ref, \ "storage-type", "xfs") except: util.logException("EXTSR:attach") pass
return super(EXTFileVDI, self).attach(sr_uuid, vdi_uuid)
if __name__ == '__main__':
SRCommand.run(EXTSR, DRIVER_INFO)
else:
SR.registerSR(EXTSR)
SNIP-----------------------