Creating a LVM backed XFS SR: Difference between revisions

From Xen
Jump to navigationJump to search
No edit summary
m (added a link to a place to get XFSSR.py ... thanks for the howto)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
LVM backed XFS SR
LVM-backed XFS SR
----
Ive created a Logical Volume under Kubuntu 11.10 with XFS and Kronos installed

These instructions were fist tested on a Kubuntu 11.10 system, but should work with any Ubuntu/Debian Kronos-based system to create an LVM-backed XFS SR

The following is what was required:
The following is what was required:


install lvm2 and xfstools
Install lvm2 and xfstools.


"apt-get install lvm2 xfstools"
<pre>apt-get install lvm2 xfstools</pre>


create a logical volume
Create a logical volume
(If you need help in doing this, there are many tutorials for LVM on the net)
(If you need help in doing this, there are many tutorials for LVM on the net)
Line 14: Line 17:
Then you must copy the XFSSR.py
Then you must copy the XFSSR.py


(Get XFSSR.py [http://www.gossamer-threads.com/lists/xen/api/228524 here])
"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')


<pre>cp XFSSR.py /usr/lib/xcp/sm/</pre>
# 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


Create a symlink to XFSSR
# 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)


<pre>cd /usr/lib/xcp/sm/</pre>
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)


<pre>ln -s XFSSR.py XFSSR</pre>
try:
util.pread2(["mkfs.xfs", self.remotepath])
except util.CommandException, inst:
raise xs_errors.XenError('LVMFilesystem', \
opterr='mkfs failed error %d' % inst.code)


Once the logical volume is created, restart xapi
#Update serial number string
scsiutil.add_serial_record(self.session, self.sr_ref, \
scsiutil.devlist_to_serialstring(self.root.split(',')))


<pre>service xcp-xapi restart</pre>
def vdi(self, uuid, loadLocked = False):
if not loadLocked:
return EXTFileVDI(self, uuid)
return EXTFileVDI(self, uuid)


To create the SR, run
def _checkmount(self):
return self.path and os.path.ismount(self.path)


<pre>SR=`xe sr-create type=xfs device-config:device=/dev/mapper/test-builder name-label=xfs`</pre>
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


Change '/dev/mapper/test-builder' to your lvm device to match your system
return super(EXTFileVDI, self).attach(sr_uuid, vdi_uuid)


After that is done, you'll be able to use the XFS LVM filesystem as the default SR


Enjoy!
if __name__ == '__main__':
SRCommand.run(EXTSR, DRIVER_INFO)
else:
SR.registerSR(EXTSR)
------------SNIP-----------------------

Latest revision as of 15:00, 29 June 2012

LVM-backed XFS SR


These instructions were fist tested on a Kubuntu 11.10 system, but should work with any Ubuntu/Debian Kronos-based system to create an LVM-backed XFS SR

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

(Get XFSSR.py here)

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 that is done, you'll be able to use the XFS LVM filesystem as the default SR

Enjoy!