Merge branch 'wip-prepare'

Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Reviewed-by: Alexandre Marangone <alexandre.marangone@inktank.com>
Tested-by: Tamil Muthamizhan <tamil.muthamizhan@inktank.com>
This commit is contained in:
Sage Weil 2013-03-05 13:33:05 -08:00
commit 8184b68c37

View File

@ -4,6 +4,7 @@ import argparse
import logging
import os
import os.path
import re
import subprocess
import stat
import sys
@ -70,28 +71,82 @@ class UnmountError(PrepareError):
Unmounting filesystem failed
"""
def list_partitions(disk):
"""
Return a list of partitions on the given device
"""
disk = os.path.realpath(disk)
assert not is_partition(disk)
assert disk.startswith('/dev/')
base = disk[5:]
ls = []
with file('/proc/partitions', 'rb') as f:
for line in f.read().split('\n')[2:]:
fields = re.split('\s+', line)
if len(fields) < 5:
continue
(_, major, minor, blocks, name) = fields
if name != base and name.startswith(base):
ls.append('/dev/' + name)
return ls
def is_partition(dev):
"""
Check whether a given device is a partition or a full disk.
"""
# resolve symlink(s)
max = 10
while stat.S_ISLNK(os.lstat(dev).st_mode):
dev = os.readlink(dev)
max -= 1
if max == 0:
raise PrepareError('%s is a rats nest of symlinks' % dev)
dev = os.path.realpath(dev)
if not stat.S_ISBLK(os.lstat(dev).st_mode):
raise PrepareError('not a block device', dev)
# if the device ends in a number, it is a partition (e.g., /dev/sda3)
# ugh i have no internet.. how do you do a python regex?
if dev.endswith('0') or dev.endswith('1') or dev.endswith('2') or dev.endswith('3') or dev.endswith('4') or dev.endswith('4') or dev.endswith('6') or dev.endswith('7') or dev.endswith('8') or dev.endswith('9'):
if dev[-1].isdigit():
return True
return False
def is_mounted(dev):
"""
Check if the given device is mounted.
"""
dev = os.path.realpath(dev)
with file('/proc/mounts') as f:
for line in f.read().split('\n'):
d = line.split(' ')[0]
if os.path.exists(d):
d = os.path.realpath(d)
if dev == d:
return True
return False
def is_held(dev):
"""
Check if a device is held by another device (e.g., a dm-crypt mapping)
"""
assert os.path.exists(dev)
dev = os.path.realpath(dev)
base = dev[5:]
disk = base
while disk[-1].isdigit():
disk = disk[:-1]
dir = '/sys/block/{disk}/{base}/holders'.format(disk=disk, base=base)
if not os.path.exists(dir):
return []
return os.listdir(dir)
def verify_not_in_use(dev):
assert os.path.exists(dev)
if is_partition(dev):
if is_mounted(dev):
raise PrepareError('Device is mounted', dev)
holders = is_held(dev)
if holders:
raise PrepareError('Device is in use by a device-mapper mapping (dm-crypt?)' % dev, ','.join(holders))
else:
for p in list_partitions(dev):
if is_mounted(p):
raise PrepareError('Device is mounted', p)
holders = is_held(p)
if holders:
raise PrepareError('Device %s is in use by a device-mapper mapping (dm-crypt?)' % p, ','.join(holders))
def write_one_line(parent, name, text):
"""
@ -804,12 +859,18 @@ def main():
if not os.path.exists(args.data):
raise PrepareError('data path does not exist', args.data)
# FIXME: verify disk/partitions is not in use
# in use?
dmode = os.stat(args.data).st_mode
if stat.S_ISBLK(dmode):
verify_not_in_use(args.data)
if args.journal and os.path.exists(args.journal):
jmode = os.stat(args.journal).st_mode
if stat.S_ISBLK(jmode):
verify_not_in_use(args.journal)
if args.zap_disk is not None:
if not os.path.exists(args.data):
raise PrepareError('does not exist', args.data)
mode = os.stat(args.data).st_mode
if stat.S_ISBLK(mode) and not is_partition(args.data):
if stat.S_ISBLK(dmode) and not is_partition(args.data):
zap(args.data)
else:
raise PrepareError('not full block device; cannot zap', args.data)
@ -869,7 +930,6 @@ def main():
journal_size = int(journal_size)
# colocate journal with data?
dmode = os.stat(args.data).st_mode
if stat.S_ISBLK(dmode) and not is_partition(args.data) and args.journal is None and args.journal_file is None:
log.info('Will colocate journal with data on %s', args.data)
args.journal = args.data