Hi list:
This is my second attempt at a striped lvm installation. The first one
was a maze of misunderstanding in the gui and I don't want to see that
again :) I think that this one is an improvement. The --grow and
--percent options do not work, to make a striped lv the total size must
be specified (In case someone tries to specify --grow or --percent some
error messages pop up during installation). lvm partitions on RAID do
not work (If this is tried I think the it will break. its on my todo
list :) . I changed stuff on anaconda and on pykickstart packages. The
diffs are attached. I am going to post additional information on bug
#134638
Comments on the code are greatly appreciated.
While testing the functionality of the patch with the --recommended
option I noticed that that option broke the installation. I tried a lot
of combinations with this options and could not get it to work. Keep on
looking to see what can be done. Any one have any idea on this issue????
Regards
diff -ubBr ../FC-D/fsset.py ./fsset.py
--- ../FC-D/fsset.py 2007-02-28 17:14:48.000000000 +0100
+++ ./fsset.py 2007-03-15 17:46:07.000000000 +0100
@@ -1633,12 +1633,20 @@
vgs[entry.device.name] = entry.device
# then set up the logical volumes
+ # Striped volumes first.
+ tempDevs = []
for entry in self.entries:
if isinstance(entry.device, LogicalVolumeDevice):
vg = None
if vgs.has_key(entry.device.vgname):
vg = vgs[entry.device.vgname]
+ if len(entry.device.stripedevs) > 1:# its stiped set it up.
entry.device.setupDevice(chroot, vgdevice = vg)
+ else:# not striped append in in temp
+ tempDevs.append((entry.device,vg))
+ for device in tempDevs:# set up the linear lvs.
+ device[0].setupDevice(chroot, vgdevice = device[1])
+
self.volumesCreated = 1
@@ -2277,7 +2285,8 @@
class LogicalVolumeDevice(Device):
# note that size is in megabytes!
- def __init__(self, vgname, size, lvname, vg, existing = 0):
+ def __init__(self, vgname, size, lvname, vg, existing = 0,
+ stripedevs={}, stripesize=0):
Device.__init__(self)
self.vgname = vgname
self.size = size
@@ -2289,14 +2298,19 @@
# these are attributes we might want to expose. or maybe not.
# self.chunksize
- # self.stripes
- # self.stripesize
+ """Dictionary containing the request id and the dev file."""
+ self.stripedevs = stripedevs
+
+ """Stripe size in KB."""
+ self.stripesize = stripesize
# self.extents
# self.readaheadsectors
def setupDevice(self, chroot="/", devPrefix='/tmp', vgdevice = None):
if not self.isSetup:
- lvm.lvcreate(self.name, self.vgname, self.size)
+ lvm.lvcreate(self.name, self.vgname, self.size,
+ stripedevs=self.stripedevs,
+ stripesize=self.stripesize)
self.isSetup = 1
if vgdevice and vgdevice.isNetdev():
diff -ubBr ../FC-D/kickstart.py ./kickstart.py
--- ../FC-D/kickstart.py 2007-03-05 19:29:58.000000000 +0100
+++ ./kickstart.py 2007-03-14 13:17:16.000000000 +0100
@@ -210,9 +210,9 @@
self.handler.id.instClass.setLanguage(self.handler.id, self.lang)
self.handler.skipSteps.append("language")
-class LogVol(commands.logvol.FC4_LogVol):
+class LogVol(commands.logvol.FC7_LogVol):
def parse(self, args):
- commands.logvol.FC4_LogVol.parse(self, args)
+ commands.logvol.FC7_LogVol.parse(self, args)
lvd = self.lvList[-1]
@@ -231,31 +231,56 @@
# sanity check mountpoint
if lvd.mountpoint != "" and lvd.mountpoint[0] != '/':
- raise KickstartValueError, formatErrorMsg(self.lineno, msg="The mount point \"%s\" is not valid." % (lvd.mountpoint,))
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg="The mount point \"%s\" is not valid." % (lvd.mountpoint,))
try:
vgid = self.handler.ksVGMapping[lvd.vgname]
except KeyError:
- raise KickstartValueError, formatErrorMsg(self.lineno, msg="No volume group exists with the name '%s'. Specify volume groups before logical volumes." % lvd.vgname)
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg="No volume group exists with the name '%s'. "
+ "Specify volume groups before logical volumes." % lvd.vgname)
for areq in self.handler.id.partitions.autoPartitionRequests:
if areq.type == REQUEST_LV:
if areq.volumeGroup == vgid and areq.logicalVolumeName == lvd.name:
- raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume name already used in volume group %s" % lvd.vgname)
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg="Logical volume name already used in volume group %s" % lvd.vgname)
elif areq.type == REQUEST_VG and areq.uniqueID == vgid:
# Store a reference to the VG so we can do the PE size check.
vg = areq
if not self.handler.ksVGMapping.has_key(lvd.vgname):
- raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume specifies a non-existent volume group" % lvd.name)
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg="Logical volume specifies a non-existent volume group" % lvd.name)
if lvd.percent == 0 and not lvd.preexist:
if lvd.size == 0:
raise KickstartValueError, formatErrorMsg(self.lineno, msg="Size required")
elif not lvd.grow and lvd.size*1024 < vg.pesize:
- raise KickstartValueError, formatErrorMsg(self.lineno, msg="Logical volume size must be larger than the volume group physical extent size.")
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg="Logical volume size must be larger than the volume group physical extent size.")
elif (lvd.percent <= 0 or lvd.percent > 100) and not lvd.preexist:
- raise KickstartValueError, formatErrorMsg(self.lineno, msg="Percentage must be between 0 and 100")
+ raise KickstartValueError, formatErrorMsg(self.lineno,
+ msg="Percentage must be between 0 and 100")
+
+ # If it is striped do some striped stuff:
+ devnames = {}
+ if len(lvd.stripedevs) > 1:
+ for devname in lvd.stripedevs:
+ # We have the id, it will be enough for now.
+ # At getDevice we'll have the device name.
+ devid = self.handler.ksPVMapping[devname]
+ devnames[devid] = ""
+
+ # Now lets do some sanity checking.
+ if len(devnames) < 2:
+ raise KickstartValueError, formatErrormsg(self.lineo,
+ msg="For striping functionality must specify more than 1 device.")
+ if lvd.stripesize > vg.pesize:
+ raise KickstartValueError, formatErrormsg(self.lineo,
+ msg="The stripe size must not exceed the size of the physical extent.")
+ # COMMENT: Maybe there is more checking to do????
request = partRequests.LogicalVolumeRequestSpec(filesystem,
format = lvd.format,
@@ -267,7 +292,9 @@
grow = lvd.grow,
maxSizeMB = lvd.maxSizeMB,
preexist = lvd.preexist,
- bytesPerInode = lvd.bytesPerInode)
+ bytesPerInode = lvd.bytesPerInode,
+ stripedevs = devnames,
+ stripesize = lvd.stripesize)
if lvd.fsopts != "":
request.fsopts = lvd.fsopts
diff -ubBr ../FC-D/lvm.py ./lvm.py
--- ../FC-D/lvm.py 2007-02-07 20:44:37.000000000 +0100
+++ ./lvm.py 2007-03-15 17:46:49.000000000 +0100
@@ -129,12 +129,14 @@
log.error("running vgchange failed: %s" %(rc,))
# lvmDevicePresent = 0
-def lvcreate(lvname, vgname, size):
+def lvcreate(lvname, vgname, size, stripedevs={}, stripesize=0):
"""Creates a new logical volume.
lvname - name of logical volume to create.
vgname - name of volume group lv will be in.
size - size of lv, in megabytes.
+ stripedevs - the device list for striped lvs
+ stripesize - the stripe size for striped lvs
"""
global lvmDevicePresent
if flags.test or lvmDevicePresent == 0:
@@ -142,7 +144,15 @@
writeForceConf()
vgscan()
- args = ["lvcreate", "-v", "-L", "%dM" %(size,), "-n", lvname, "-An", vgname]
+ stripeargs = []
+ stripedevsargs = []
+ if len(stripedevs) > 0:
+ stripeargs = [ "-i%d" % len(stripedevs), "-I%d" % stripesize]
+ # have no idea if this is generic :/
+ for id,dev in stripedevs.iteritems():
+ stripedevsargs.append("/dev/"+dev)
+ # The stripeargs and stripedevs should be void when no stripes.
+ args = ["lvcreate", "-v"] + stripeargs + ["-L", "%dM" %(size,), "-n", lvname, "-An", vgname] + stripedevsargs
try:
rc = lvmExec(*args)
except:
diff -ubBr ../FC-D/partitions.py ./partitions.py
--- ../FC-D/partitions.py 2006-08-02 00:13:08.000000000 +0200
+++ ./partitions.py 2007-03-15 16:11:37.000000000 +0100
@@ -35,6 +35,7 @@
from rhpl.translate import _
import logging
+import math
log = logging.getLogger("anaconda")
class Partitions:
@@ -584,6 +585,37 @@
raidcounter = raidcounter + 1
return rc
+ def getAvailPEForSLVIPV(self, lvRequest, pvRequest):
+ """Get available PEs for Striped logical volume in physical request.
+
+ Will analyze only striped lvs since this function is used
+ only in the sanity check for striped lvs.
+
+ lvRequest - The local volume request.
+ pvRequest - The physical volume rquest.
+ """
+ usedPEs = 0
+ vg = self.getRequestByID(lvRequest.volumeGroup)
+ pesize = vg.pesize
+ # make a list of all the lvs in the vg contained in lvRequest.
+ lvList = self.getLVMLVForVGID(lvRequest.volumeGroup)
+ for lv in lvList:
+ if lv.uniqueID == lvRequest.uniqueID or \
+ len(lvRequest.stripedevs) < 2:continue # Dont count the lvRequest
+ # We must add the used PEs to get a real sens of used size.
+ for id in lv.stripedevs:
+ if id == pvRequest.uniqueID:
+ # The lv has a part of the pv, but how much??
+ # The required space in spacelv / numdevslv
+ sizeInEachPV = lv.requestSize / len(lv.stripedevs)
+ # For this size to be possible it must fit inside a space
+ # defined by PE. calculate the number of PE to contain
+ # this size.
+ usedPEs += math.ceil((sizeInEachPV*1024L)/pesize)
+ break
+ totalPEinPV = math.floor((pvRequest.requestSize*1024L)/pesize)
+ return totalPEinPV - usedPEs
+
def getLVMVolumeGroupMemberParent(self, request):
"""Return parent volume group of a physical volume"""
volgroups = self.getLVMVGRequests()
@@ -1006,6 +1038,42 @@
"could negatively impact performance.")
%(swapSize, mem))
+ # Sanity check for striped logcial volumes
+ for lvRequest in self.requests:
+ if isinstance(lvRequest, partRequests.LogicalVolumeRequestSpec) and \
+ len(lvRequest.stripedevs) > 1:
+ if lvRequest.percent:
+ # Striped lvs do not support percentage.
+ errors.append(_("Currently, striped logical volumes cannot be "
+ "created using the percentage option. Please "
+ "try to specify total size."))
+ break
+ if lvRequest.grow:
+ # Striped lvs do not support grow.
+ errors.append(_("Currently, striped logical volumes cannot be "
+ "created using the grow option. Please try to "
+ "specify total size."))
+ break
+
+ # How much of each pv does the striped lv need?
+ vg = self.getRequestByID(lvRequest.volumeGroup)
+ pesize = vg.pesize
+ NPEForLV = math.ceil((lvRequest.requestSize*1024L)/pesize)# Needed PEs for lv
+ # Number of PE must be a multiple of the number of devs in lv
+ # If not multiple, roundup.
+ NPEForLV = math.ceil(NPEForLV / len(lvRequest.stripedevs)) * len(lvRequest.stripedevs)
+ NPEForPV = NPEForLV / len(lvRequest.stripedevs)
+ # Make sure that all the pv in lv have the needed pvs.
+ for id in lvRequest.stripedevs:
+ devRequest = self.getRequestByID(id)
+ availPV = self.getAvailPEForSLVIPV(lvRequest, devRequest)
+ if availPV < NPEForPV:
+ errors.append(_("The current configuration does not allow to stripe "
+ "the logical volume %s. To solve this problem try reducing "
+ "the logical volumes.")
+ % lvRequest.logicalVolumeName )
+ break
+
if warnings == []:
warnings = None
if errors == []:
diff -ubBr ../FC-D/partRequests.py ./partRequests.py
--- ../FC-D/partRequests.py 2007-02-28 17:14:48.000000000 +0100
+++ ./partRequests.py 2007-03-15 15:53:20.000000000 +0100
@@ -477,6 +477,7 @@
def doSizeSanityCheck(self):
"""Sanity check that the size of the partition is sane."""
+ log.debug("doSizeSanityCheck: partition request sanitycheck")
if not self.fstype:
return None
if not self.format:
@@ -814,7 +815,8 @@
def __init__(self, fstype, format = None, mountpoint = None,
size = None, volgroup = None, lvname = None,
preexist = 0, percent = None, grow=0, maxSizeMB=0,
- bytesPerInode = 4096, fslabel = None):
+ bytesPerInode = 4096, fslabel = None, stripedevs = {},
+ stripesize = 0):
"""Create a new VolumeGroupRequestSpec object.
fstype is the fsset filesystem type.
@@ -829,6 +831,8 @@
maxSizeMB is max size to grow to.
bytesPerInode is the size of the inodes on the partition.
fslabel is the label of the filesystem on the logical volume.
+ stripedevs The dictionary of the devices in which each stripe will reside.
+ stripesize The size in kilobytes, default is 0 to signify no stripes.
"""
# if it's preexisting, the original fstype should be set
@@ -855,13 +859,17 @@
self.grow = grow
self.maxSizeMB = maxSizeMB
self.startSize = size
+ self.stripedevs = stripedevs
+ self.stripesize = stripesize
if not percent and not size and not preexist:
- raise RuntimeError, "Error with Volume Group:Logical Volume %s:%s - Logical Volume must specify either percentage of vgsize or size" % (volgroup, lvname)
-
+ raise RuntimeError, "Error with Volume Group:Logical Volume %s:%s "\
+ "- Logical Volume must specify either "\
+ "percentage of vgsize or size" % (volgroup, lvname)
if percent and grow:
- raise RuntimeError, "Error with Volume Group:Logical Volume %s:%s - Logical Volume cannot grow if percentage given" % (volgroup, lvname)
-
+ raise RuntimeError, "Error with Volume Group:Logical Volume %s:%s "\
+ "- Logical Volume cannot grow if percentage "\
+ "given" % (volgroup, lvname)
def __str__(self):
if self.fstype:
@@ -874,37 +882,61 @@
else:
size = "%s percent" %(self.percent,)
+ if len(self.stripedevs) < 2:
+ strStripeSize = "N/A"
+ strStripeDev = "N/A"
+ else:
+ strStripeSize = str(self.stripesize)
+ strStripeDev = ""
+ for id, dev in self.stripedevs.iteritems():strStripeDev += dev+","
+ strStripeDev = strStripeDev.strip(",")
+
str = ("LV Request -- mountpoint: %(mount)s uniqueID: %(id)s\n"
" type: %(fstype)s format: %(format)s badblocks: %(bb)s\n"
" size: %(size)s lvname: %(lvname)s volgroup: %(vgid)s\n"
- " bytesPerInode: %(bytesPerInode)s options: '%(fsopts)s'" %
+ " bytesPerInode: %(bytesPerInode)s options: '%(fsopts)s'\n"
+ " stripedevs: %(stripedevs) stripesize: %(stripesize) "%
{"mount": self.mountpoint, "id": self.uniqueID,
"fstype": fsname, "format": self.format, "bb": self.badblocks,
"lvname": self.logicalVolumeName, "vgid": self.volumeGroup,
"size": size, "bytesPerInode": self.bytesPerInode,
- "fsopts": self.fsopts})
+ "fsopts": self.fsopts, "stripedevs": strStripeDev,
+ "stripesize":strStripeSize})
return str
def getDevice(self, partitions):
"""Return a device which can be solidified."""
vg = partitions.getRequestByID(self.volumeGroup)
vgname = vg.volumeGroupName
+ # If it is striped it is the time to look for the device files.
+ for id, dev in self.stripedevs.iteritems():
+ devreq = partitions.getRequestByID(id)
+ self.stripedevs[id] = devreq.device
+
self.dev = fsset.LogicalVolumeDevice(vgname, self.size,
self.logicalVolumeName,
vg = vg,
- existing = self.preexist)
+ existing = self.preexist,
+ stripedevs = self.stripedevs,
+ stripesize = self.stripesize)
return self.dev
def getActualSize(self, partitions, diskset):
"""Return the actual size allocated for the request in megabytes."""
- if self.percent:
+ retval = 0
vgreq = partitions.getRequestByID(self.volumeGroup)
+ if self.percent:
vgsize = vgreq.getActualSize(partitions, diskset)
- lvsize = int(self.percent * 0.01 * vgsize)
- #lvsize = lvm.clampLVSizeRequest(lvsize, vgreq.pesize)
- return lvsize
+ retval = int(self.percent * 0.01 * vgsize)
else:
- return self.size
+ retval = self.size
+
+ # Lets make sure that the size is less than or equals to the requiered size.
+ if len(self.stripedevs) > 1:
+ # It is striped.
+ pe = vgreq.pesize
+ retval = math.floor((retval*1024L) / len(self.stripedevs) / pe) * (pe*len(self.stripedevs)) / 1024
+ return retval
def getStartSize(self):
"""Return the starting size allocated for the request in megabytes."""
@@ -925,5 +957,8 @@
if not self.grow and not self.percent and self.size*1024 < pesize:
return _("Logical volume size must be larger than the volume "
"group's physical extent size.")
+ if self.stripesize > pesize and len(self.stripedevs) > 1:
+ return _("The stripe size must be less than or equal to "
+ "the physical volume extent size.")
return RequestSpec.sanityCheckRequest(self, partitions, skipMntPtExistCheck)
diff -ubBr ../PYKS-D/commands/logvol.py pykickstart/commands/logvol.py
--- ../PYKS-D/commands/logvol.py 2007-02-19 19:54:57.000000000 +0100
+++ pykickstart/commands/logvol.py 2007-03-15 16:25:45.000000000 +0100
@@ -82,6 +82,31 @@
return retval + "\n"
+class FC7_LogVolData(FC4_LogVolData):
+ def __init__(self, bytesPerInode=4096, fsopts="", fstype="", grow=False,
+ maxSizeMB=0, name="", format=True, percent=0,
+ recommended=False, size=None, preexist=False, vgname="",
+ mountpoint="", stripedevs=[], stripesize=4):
+ FC4_LogVolData.__init__(self, bytesPerInode=bytesPerInode, fsopts=fsopts,
+ fstype=fstype, grow=grow, maxSizeMB=maxSizeMB,
+ name=name, format=format, percent=percent,
+ recommended=recommended, size=size,
+ preexist=preexist, vgname=vgname,
+ mountpoint=mountpoint)
+ self.stripedevs = stripedevs
+ self.stripesize = stripesize
+
+ def __str__(self):
+ retval = FC4_LogVolData.__str__(self).strip()
+
+ if len(self.stripedevs) > 1:
+ devstring = ""
+ for dev in self.stripedevs:devstring += dev+","
+ devstring = devstring.strip(",")
+ retval += " --stripeon=%s --stripesize=%d" % (devstring, self.stripesize)
+
+ return retval + "\n"
+
class FC3_LogVol(KickstartCommand):
def __init__(self, writePriority=132, lvList=None):
KickstartCommand.__init__(self, writePriority)
@@ -176,3 +201,56 @@
self._setToObj(op, opts, lvd)
lvd.mountpoint=extra[0]
self.add(lvd)
+
+class FC7_LogVol(FC4_LogVol):
+ def __init__(self, writePriority=132, lvList=None):
+ FC4_LogVol.__init__(self, writePriority, lvList)
+
+ def parse(self, args):
+ def lv_cb (option, opt_str, value, parser):
+ parser.values.format = False
+ parser.values.preexist = True
+ def makedevs(option, opt_str, value, parser):
+ parser.values.stripedevs = []
+ temp = value.strip(",").split(",")
+ for elem in temp:
+ if elem != "":parser.values.stripedevs.append(elem)
+ def asignStripeSize(option, opt_str, value, parser):
+ if len(parser.values.stripedevs) < 2:parser.values.stripesize = 0
+ else : parser.values.stripesize = value
+
+ op = KSOptionParser(lineno=self.lineno)
+ op.add_option("--bytes-per-inode", dest="bytesPerInode", action="store",
+ type="int", nargs=1)
+ op.add_option("--fsoptions", dest="fsopts")
+ op.add_option("--fstype", dest="fstype")
+ op.add_option("--grow", dest="grow", action="store_true",
+ default=False)
+ op.add_option("--maxsize", dest="maxSizeMB", action="store", type="int",
+ nargs=1)
+ op.add_option("--name", dest="name", required=1)
+ op.add_option("--noformat", action="callback", callback=lv_cb,
+ dest="format", default=True, nargs=0)
+ op.add_option("--percent", dest="percent", action="store", type="int",
+ nargs=1)
+ op.add_option("--recommended", dest="recommended", action="store_true",
+ default=False)
+ op.add_option("--size", dest="size", action="store", type="int",
+ nargs=1)
+ op.add_option("--useexisting", dest="preexist", action="store_true",
+ default=False)
+ op.add_option("--vgname", dest="vgname", required=1)
+ op.add_option("--stripedevs", dest="stripedevs", type="string", action="callback",
+ callback=makedevs, nargs=1, default=[])
+ op.add_option("--stripesize", dest="stripesize", type="int", action="callback",
+ callback=asignStripeSize, nargs=1)
+
+
+ (opts, extra) = op.parse_args(args=args)
+
+ if len(extra) == 0:
+ raise KickstartValueError, formatErrorMsg(self.lineno, msg=_("Mount point required for %s") % "logvol")
+ lvd = FC7_LogVolData()
+ self._setToObj(op, opts, lvd)
+ lvd.mountpoint=extra[0]
+ self.add(lvd)