Skip to content

Commit

Permalink
New mechanism for loop device allocation
Browse files Browse the repository at this point in the history
1. get loopdev id, 10<id<100, considered raw image would use symlink (id>100)
2. create loopdev, if exists, use when free, or raise when used
3. return loopdev name, used by the caller
4. cleanup when mic exit, including dm table, losetup list

Signed-off-by: Gui Chen <gui.chen@intel.com>
  • Loading branch information
Gui Chen committed Mar 15, 2012
1 parent de6e1e0 commit d35ca28
Showing 1 changed file with 103 additions and 35 deletions.
138 changes: 103 additions & 35 deletions mic/utils/fs_related.py
Expand Up @@ -810,54 +810,122 @@ def load_module(module):
msger.info("Loading %s..." % module)
runner.quiet(['modprobe', module])

def get_loop_device(losetupcmd, lofile):
""" Get a lock to synchronize getting a loopback device """
class LoopDevice(object):
def __init__(self, loopid=None):
self.device = None
self.loopid = loopid
self.created = False
self.kpartxcmd = find_binary_path("kpartx")
self.losetupcmd = find_binary_path("losetup")

# internal class for simple lock
class FileLock(object):
def __init__(self, filename):
self.filename = filename
self.fd = None
import atexit
atexit.register(self.close)

import atexit
atexit.register(self.release)
def _genloopid(self):
import glob
maxid = 1 + max(filter(lambda x: x<100,
map(lambda x: int(x[9:]),
glob.glob("/dev/loop[0-9]*"))))
if maxid < 10: maxid = 10
if maxid >= 100: raise
return maxid

def acquire(self):
try:
self.fd = os.open(self.filename, os.O_CREAT | os.O_EXCL)
def _kpseek(self, device):
rc, out = runner.runtool([self.kpartxcmd, '-l', '-v', device])
if rc != 0:
raise MountError("Can't query dm snapshot on %s" % device)
for line in out.splitlines():
if line and line.startswith("loop"):
return True
return False

def _loseek(self, device):
import re
rc, out = runner.runtool([self.losetupcmd, '-a'])
if rc != 0:
raise MountError("Failed to run 'losetup -a'")
for line in out.splitlines():
m = re.match("([^:]+): .*", line)
if m and m.group(1) == device:
return True
except OSError:
self.fd = None
return False
return False

def release(self):
def create(self):
if not self.created:
if not self.loopid:
self.loopid = self._genloopid()
self.device = "/dev/loop%d" % self.loopid
if os.path.exists(self.device):
if self._loseek(self.device):
raise MountError("Device busy: %s" % self.device)
else:
self.created = True
return
try:
if self.fd is not None:
os.close(self.fd)
os.remove(self.filename)
os.mknod(self.device,
0664 | stat.S_IFBLK,
os.makedev(7, self.loopid))
except:
pass
raise MountError("Failed to create device %s" % self.device)
else:
self.created = True

lock = FileLock("/var/lock/._mic_loopdev.lock")
timeout = 30
while not lock.acquire():
if timeout == 0:
raise MountError("Timeout! Failed to find a free loop device")
time.sleep(2)
timeout -= 2
def close(self):
if self.created:
try:
self.cleanup()
self.device = None
except MountError, e:
msger.error("%s" % e)

rc, losetupOutput = runner.runtool([losetupcmd, "-f"])
def cleanup(self):

if rc != 0:
lock.release()
raise MountError("Failed to allocate loop device for '%s'" % lofile)
if self.device is None:
return

loopdev = losetupOutput.split()[0]

rc = runner.show([losetupcmd, loopdev, lofile])
lock.release()
if self._kpseek(self.device):
if self.created:
for i in range(3, os.sysconf("SC_OPEN_MAX")):
try:
os.close(i)
except:
pass
runner.quiet([self.kpartxcmd, "-d", self.device])
if self._loseek(self.device):
runner.quiet([self.losetupcmd, "-d", self.device])
# FIXME: should sleep a while between two loseek
if self._loseek(self.device):
msger.warning("Can't cleanup loop device %s" % self.device)
else:
os.unlink(self.device)

def get_loop_device(losetupcmd, lofile):
import fcntl
fp = open("/var/lock/__mic_loopdev.lock", 'w')
fcntl.flock(fp, fcntl.LOCK_EX)
try:
devinst = LoopDevice()
devinst.create()
except:
rc, out = runner.runtool([losetupcmd, "-f"])
if rc != 0:
raise MountError("1-Failed to allocate loop device for '%s'" % lofile)
loopdev = out.split()[0]
else:
loopdev = devinst.device
finally:
try:
fcntl.flock(fp, fcntl.LOCK_UN)
fp.close()
os.unlink('/var/lock/__mic_loopdev.lock')
except:
pass

rc = runner.show([losetupcmd, loopdev, lofile])
if rc != 0:
raise MountError("Failed to allocate loop device for '%s'" % lofile)
raise MountError("2-Failed to allocate loop device for '%s'" % lofile)

return loopdev


0 comments on commit d35ca28

Please sign in to comment.