File 0009-Fix-overflowing-journel-partitions.patch of Package ceph.2107
From: Owen Synge <osynge@suse.com>
Date: Wed, 3 Dec 2014 12:32:34 +0100
Subject: [PATCH] Fix overflowing journel partitions.
This fixes #896406. When useing ceph-disk to create a journel parititon
in the next available partition and thier is not enough space ceph-disk
did not provide a clear error message.
Signed-off-by: Owen Synge <osynge@suse.com>
(cherry picked from commit 05a4347f745f9d648acf67e25736d8d70cdc8f80)
---
src/ceph-disk | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 72 insertions(+), 3 deletions(-)
diff --git a/src/ceph-disk b/src/ceph-disk
index 6264d53..7d0a298 100755
--- a/src/ceph-disk
+++ b/src/ceph-disk
@@ -29,6 +29,7 @@ import stat
import sys
import tempfile
import uuid
+import math
"""
Prepare:
@@ -923,7 +924,7 @@ def extract_parted_partition_numbers(partitions):
numbers_as_strings = re.findall('^\d+', partitions, re.MULTILINE)
return map(int, numbers_as_strings)
-def get_free_partition_index(dev):
+def get_free_partition_index(dev, size='megabytes'):
"""
Get the next free partition index on a given device.
@@ -960,6 +961,71 @@ def get_free_partition_index(dev):
else:
return 1
+def get_free_partition_space(dev, size='megabytes'):
+ """
+ Attempt to get the free partition space on a given device.
+
+ :param dev: the device to calculate the size
+ :param size: bytes or megabytes
+ :return: size
+
+ Finds total space and removes space for each partition.
+ Better would be to find largest free contiguous space.
+ """
+ def size_str_as_bytes(totalsize_str, tunc = False):
+ output = -1
+ found_size = float(totalsize_str[:-2])
+ if tunc:
+ found_size = math.trunc(found_size)
+ else:
+ found_size = math.ceil(found_size)
+ if totalsize_str[-2:] == "GB":
+ output = int(1024*1024*1024*found_size)
+ if totalsize_str[-2:] == "MB":
+ output = int(1024*1024*found_size)
+ return output
+ try:
+ lines = _check_output(
+ args=[
+ 'parted',
+ '--machine',
+ '--',
+ dev,
+ 'print',
+ ],
+ )
+ except subprocess.CalledProcessError as e:
+ print 'cannot read partition index; assume it isn\'t present\n (Error: %s)' % e
+ return 1
+
+ if not lines:
+ raise Error('parted failed to output anything')
+ lines = str(lines).splitlines(True)
+
+ # work around buggy libreadline(?) library in rhel/centos.
+ idiot_prefix = '\x1b\x5b\x3f\x31\x30\x33\x34\x68'
+ if lines[0].startswith(idiot_prefix):
+ lines[0] = lines[0][8:]
+
+ if lines[0] not in ['CHS;\n', 'CYL;\n', 'BYT;\n']:
+ raise Error('weird parted units', lines[0])
+ del lines[0]
+ if not lines[0].startswith('/dev/'):
+ raise Error('weird parted disk entry', lines[0])
+ # We want to truncate the full size to avoid rounding up errors.
+ size_free = size_str_as_bytes(lines[0].split(':')[1], True)
+ del lines[0]
+
+ seen = set()
+ for line in lines:
+ partused = size_str_as_bytes(line.split(':')[3])
+ size_free -= partused
+
+ dividers = {'bytes': 1, 'megabytes': 1024*1024}
+ divider = dividers.get(size, 1024*1024) # default to megabytes
+ return size_free/divider
+
+
def update_partition(action, dev, description):
# try to make sure the kernel refreshes the table. note
@@ -1078,6 +1144,7 @@ def prepare_journal_dev(
# it is a whole disk. create a partition!
num = None
+ dev_size = None
if journal == data:
# we're sharing the disk between osd data and journal;
# make journal be partition number 2, so it's pretty
@@ -1086,6 +1153,8 @@ def prepare_journal_dev(
num=num,
size=journal_size,
)
+ # now get dev_size
+ dev_size = get_dev_size(journal)
else:
# sgdisk has no way for me to say "whatever is the next
# free index number" when setting type guids etc, so we
@@ -1099,8 +1168,8 @@ def prepare_journal_dev(
size=journal_size,
)
LOG.warning('OSD will not be hot-swappable if journal is not the same device as the osd data')
-
- dev_size = get_dev_size(journal)
+ # now get dev_size
+ dev_size = get_free_partition_space(journal)
if journal_size > dev_size:
LOG.error('refusing to create journal on %s' % journal)