From: Gui Chen Date: Thu, 15 Mar 2012 10:07:47 +0000 (+0800) Subject: New mechanism for loop device allocation X-Git-Tag: 0.8~14 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d35ca289aa5adf749451b58f1bc49b1ee995f717;p=platform%2Fupstream%2Fmic.git New mechanism for loop device allocation 1. get loopdev id, 10100) 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 --- diff --git a/mic/utils/fs_related.py b/mic/utils/fs_related.py index c71ea40..1063763 100644 --- a/mic/utils/fs_related.py +++ b/mic/utils/fs_related.py @@ -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 + +