mirror of
git://git.yoctoproject.org/poky
synced 2026-04-02 02:49:11 +00:00
runqemu: add lockfile for port used when slirp enabled
There is race condition when multi qemu starting with slirp, add lockfile for each port to avoid problem like: runqemu - ERROR - Failed to run qemu: qemu-system-x86_64: Could not set up host forwarding rule 'tcp::2323-:23' [YOCTO #13364] (From OE-Core rev: ceb3555a40ba06e58914465376aaf41392c12a7c) (From OE-Core rev: 9f9657683df90c18c1dfc7e65715b134a44a9d5a) Signed-off-by: Changqing Li <changqing.li@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
8117b6b195
commit
030b0223aa
128
scripts/runqemu
128
scripts/runqemu
@ -157,19 +157,6 @@ def get_first_file(cmds):
|
|||||||
return f
|
return f
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def check_free_port(host, port):
|
|
||||||
""" Check whether the port is free or not """
|
|
||||||
import socket
|
|
||||||
from contextlib import closing
|
|
||||||
|
|
||||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
|
|
||||||
if sock.connect_ex((host, port)) == 0:
|
|
||||||
# Port is open, so not free
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
# Port is not open, so free
|
|
||||||
return True
|
|
||||||
|
|
||||||
class BaseConfig(object):
|
class BaseConfig(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# The self.d saved vars from self.set(), part of them are from qemuboot.conf
|
# The self.d saved vars from self.set(), part of them are from qemuboot.conf
|
||||||
@ -218,8 +205,9 @@ class BaseConfig(object):
|
|||||||
self.audio_enabled = False
|
self.audio_enabled = False
|
||||||
self.tcpserial_portnum = ''
|
self.tcpserial_portnum = ''
|
||||||
self.custombiosdir = ''
|
self.custombiosdir = ''
|
||||||
self.lock = ''
|
self.taplock = ''
|
||||||
self.lock_descriptor = None
|
self.taplock_descriptor = None
|
||||||
|
self.portlocks = {}
|
||||||
self.bitbake_e = ''
|
self.bitbake_e = ''
|
||||||
self.snapshot = False
|
self.snapshot = False
|
||||||
self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs',
|
self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs',
|
||||||
@ -240,30 +228,81 @@ class BaseConfig(object):
|
|||||||
# avoid cleanup twice
|
# avoid cleanup twice
|
||||||
self.cleaned = False
|
self.cleaned = False
|
||||||
|
|
||||||
def acquire_lock(self, error=True):
|
def acquire_taplock(self, error=True):
|
||||||
logger.debug("Acquiring lockfile %s..." % self.lock)
|
logger.debug("Acquiring lockfile %s..." % self.taplock)
|
||||||
try:
|
try:
|
||||||
self.lock_descriptor = open(self.lock, 'w')
|
self.taplock_descriptor = open(self.taplock, 'w')
|
||||||
fcntl.flock(self.lock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB)
|
fcntl.flock(self.taplock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = "Acquiring lockfile %s failed: %s" % (self.lock, e)
|
msg = "Acquiring lockfile %s failed: %s" % (self.taplock, e)
|
||||||
if error:
|
if error:
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
else:
|
else:
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
if self.lock_descriptor:
|
if self.taplock_descriptor:
|
||||||
self.lock_descriptor.close()
|
self.taplock_descriptor.close()
|
||||||
self.lock_descriptor = None
|
self.taplock_descriptor = None
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def release_lock(self):
|
def release_taplock(self):
|
||||||
if self.lock_descriptor:
|
if self.taplock_descriptor:
|
||||||
logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
|
logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
|
||||||
fcntl.flock(self.lock_descriptor, fcntl.LOCK_UN)
|
fcntl.flock(self.taplock_descriptor, fcntl.LOCK_UN)
|
||||||
self.lock_descriptor.close()
|
self.taplock_descriptor.close()
|
||||||
os.remove(self.lock)
|
os.remove(self.taplock)
|
||||||
self.lock_descriptor = None
|
self.taplock_descriptor = None
|
||||||
|
|
||||||
|
def check_free_port(self, host, port, lockdir):
|
||||||
|
""" Check whether the port is free or not """
|
||||||
|
import socket
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
|
lockfile = os.path.join(lockdir, str(port) + '.lock')
|
||||||
|
if self.acquire_portlock(lockfile):
|
||||||
|
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
|
||||||
|
if sock.connect_ex((host, port)) == 0:
|
||||||
|
# Port is open, so not free
|
||||||
|
self.release_portlock(lockfile)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# Port is not open, so free
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def acquire_portlock(self, lockfile, error=True):
|
||||||
|
logger.debug("Acquiring lockfile %s..." % lockfile)
|
||||||
|
try:
|
||||||
|
portlock_descriptor = open(lockfile, 'w')
|
||||||
|
self.portlocks.update({lockfile: portlock_descriptor})
|
||||||
|
fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_EX|fcntl.LOCK_NB)
|
||||||
|
except Exception as e:
|
||||||
|
msg = "Acquiring lockfile %s failed: %s" % (lockfile, e)
|
||||||
|
if error:
|
||||||
|
logger.error(msg)
|
||||||
|
else:
|
||||||
|
logger.info(msg)
|
||||||
|
if self.portlocks[lockfile]:
|
||||||
|
self.portlocks[lockfile].close()
|
||||||
|
del self.portlocks[lockfile]
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def release_portlock(self, lockfile=None):
|
||||||
|
if lockfile != None:
|
||||||
|
logger.debug("Releasing lockfile '%s'" % lockfile)
|
||||||
|
fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_UN)
|
||||||
|
self.portlocks[lockfile].close()
|
||||||
|
os.remove(lockfile)
|
||||||
|
del self.portlocks[lockfile]
|
||||||
|
elif len(self.portlocks):
|
||||||
|
for lockfile, descriptor in self.portlocks.items():
|
||||||
|
logger.debug("Releasing lockfile '%s'" % lockfile)
|
||||||
|
fcntl.flock(descriptor, fcntl.LOCK_UN)
|
||||||
|
descriptor.close()
|
||||||
|
os.remove(lockfile)
|
||||||
|
self.portlocks = {}
|
||||||
|
|
||||||
def get(self, key):
|
def get(self, key):
|
||||||
if key in self.d:
|
if key in self.d:
|
||||||
@ -923,10 +962,21 @@ class BaseConfig(object):
|
|||||||
ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
|
ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
|
||||||
ports = [int(i) for i in ports]
|
ports = [int(i) for i in ports]
|
||||||
mac = 2
|
mac = 2
|
||||||
|
|
||||||
|
lockdir = "/tmp/qemu-port-locks"
|
||||||
|
if not os.path.exists(lockdir):
|
||||||
|
# There might be a race issue when multi runqemu processess are
|
||||||
|
# running at the same time.
|
||||||
|
try:
|
||||||
|
os.mkdir(lockdir)
|
||||||
|
os.chmod(lockdir, 0o777)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
|
||||||
# Find a free port to avoid conflicts
|
# Find a free port to avoid conflicts
|
||||||
for p in ports[:]:
|
for p in ports[:]:
|
||||||
p_new = p
|
p_new = p
|
||||||
while not check_free_port('localhost', p_new):
|
while not self.check_free_port('localhost', p_new, lockdir):
|
||||||
p_new += 1
|
p_new += 1
|
||||||
mac += 1
|
mac += 1
|
||||||
while p_new in ports:
|
while p_new in ports:
|
||||||
@ -981,8 +1031,8 @@ class BaseConfig(object):
|
|||||||
if os.path.exists('%s.skip' % lockfile):
|
if os.path.exists('%s.skip' % lockfile):
|
||||||
logger.info('Found %s.skip, skipping %s' % (lockfile, p))
|
logger.info('Found %s.skip, skipping %s' % (lockfile, p))
|
||||||
continue
|
continue
|
||||||
self.lock = lockfile + '.lock'
|
self.taplock = lockfile + '.lock'
|
||||||
if self.acquire_lock(error=False):
|
if self.acquire_taplock(error=False):
|
||||||
tap = p
|
tap = p
|
||||||
logger.info("Using preconfigured tap device %s" % tap)
|
logger.info("Using preconfigured tap device %s" % tap)
|
||||||
logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
|
logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
|
||||||
@ -1000,8 +1050,8 @@ class BaseConfig(object):
|
|||||||
cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
|
cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
|
||||||
tap = subprocess.check_output(cmd).decode('utf-8').strip()
|
tap = subprocess.check_output(cmd).decode('utf-8').strip()
|
||||||
lockfile = os.path.join(lockdir, tap)
|
lockfile = os.path.join(lockdir, tap)
|
||||||
self.lock = lockfile + '.lock'
|
self.taplock = lockfile + '.lock'
|
||||||
self.acquire_lock()
|
self.acquire_taplock()
|
||||||
self.cleantap = True
|
self.cleantap = True
|
||||||
logger.debug('Created tap: %s' % tap)
|
logger.debug('Created tap: %s' % tap)
|
||||||
|
|
||||||
@ -1233,8 +1283,11 @@ class BaseConfig(object):
|
|||||||
cmds = shlex.split(cmd)
|
cmds = shlex.split(cmd)
|
||||||
logger.info('Running %s\n' % cmd)
|
logger.info('Running %s\n' % cmd)
|
||||||
pass_fds = []
|
pass_fds = []
|
||||||
if self.lock_descriptor:
|
if self.taplock_descriptor:
|
||||||
pass_fds = [self.lock_descriptor.fileno()]
|
pass_fds = [self.taplock_descriptor.fileno()]
|
||||||
|
if len(self.portlocks):
|
||||||
|
for descriptor in self.portlocks.values():
|
||||||
|
pass_fds.append(descriptor.fileno())
|
||||||
process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
|
process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
|
||||||
self.qemupid = process.pid
|
self.qemupid = process.pid
|
||||||
retcode = process.wait()
|
retcode = process.wait()
|
||||||
@ -1256,7 +1309,8 @@ class BaseConfig(object):
|
|||||||
cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
|
cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
|
||||||
logger.debug('Running %s' % str(cmd))
|
logger.debug('Running %s' % str(cmd))
|
||||||
subprocess.check_call(cmd)
|
subprocess.check_call(cmd)
|
||||||
self.release_lock()
|
self.release_taplock()
|
||||||
|
self.release_portlock()
|
||||||
|
|
||||||
if self.nfs_running:
|
if self.nfs_running:
|
||||||
logger.info("Shutting down the userspace NFS server...")
|
logger.info("Shutting down the userspace NFS server...")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user