Nir Soffer has uploaded a new change for review.
Change subject: sdc: Rename method to make it less confusing
......................................................................
sdc: Rename method to make it less confusing
StorageCache.refresh() does not do any refresh, but clearing the domain
cahce and invlidating lvm cache (actually clearing it). Rename to
clear() to reflect what it does.
Change-Id: I2c67ae0ddc98857e406fec62be0cbcf817213236
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/storage/sdc.py
M vdsm/storage/sp.py
2 files changed, 3 insertions(+), 3 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/16/47916/1
diff --git a/vdsm/storage/sdc.py b/vdsm/storage/sdc.py
index ecb9708..a26c05a 100644
--- a/vdsm/storage/sdc.py
+++ b/vdsm/storage/sdc.py
@@ -181,7 +181,7 @@
return uuids
- def refresh(self):
+ def clear(self):
with self._syncroot:
lvm.invalidateCache()
self.__domainCache.clear()
diff --git a/vdsm/storage/sp.py b/vdsm/storage/sp.py
index b8fd8f3..6ecaf8d 100644
--- a/vdsm/storage/sp.py
+++ b/vdsm/storage/sp.py
@@ -627,7 +627,7 @@
self.id = hostID
# Make sure SDCache doesn't have stale data (it can be in case of FC)
sdCache.invalidateStorage()
- sdCache.refresh()
+ sdCache.clear()
# Rebuild whole Pool
self.__rebuild(msdUUID=msdUUID, masterVersion=masterVersion)
self.__createMailboxMonitor()
@@ -1245,7 +1245,7 @@
'msdUUID' - master storage domain UUID
"""
sdCache.invalidateStorage()
- sdCache.refresh()
+ sdCache.clear()
self.__rebuild(msdUUID=msdUUID, masterVersion=masterVersion)
def updateVM(self, vmList, sdUUID):
--
To view, visit https://gerrit.ovirt.org/47916
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I2c67ae0ddc98857e406fec62be0cbcf817213236
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: scsi: Scan only the required domain type
......................................................................
scsi: Scan only the required domain type
We used to perform both iSCSI and FCP rescan when creating or editing a
storage domain, connecting to storage server, getting vg and storage
domain list and more.
The unneeded rescan is typically fast, but if a storage server or device
is not accessible, a SCSI rescan may block for couple of minutes,
leading to unwanted blocking of unrelated storage threads. This is
particularly bad when you are interested only in one domain type, but
the host get stuck scanning the other type.
To improve storage domain isolation, we use the specified storage type
to perform a rescan only of the relevant type. If storage type was not
specified, we scan both ISCSI and FCP keeping the old behavior.
Change-Id: Ic32cd683020e94df016dd77b19ae3eb7317c5554
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M vdsm/storage/hsm.py
M vdsm/storage/multipath.py
M vdsm/storage/sdc.py
3 files changed, 25 insertions(+), 17 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/24/45824/1
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 1b8c064..541b699 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -1984,15 +1984,16 @@
return dict(devList=devices)
def _getDeviceList(self, storageType=None, guids=(), checkStatus=True):
- sdCache.refreshStorage()
- typeFilter = lambda dev: True
- if storageType:
- if sd.storageType(storageType) == sd.type2name(sd.ISCSI_DOMAIN):
- typeFilter = \
- lambda dev: multipath.devIsiSCSI(dev.get("devtype"))
- elif sd.storageType(storageType) == sd.type2name(sd.FCP_DOMAIN):
- typeFilter = \
- lambda dev: multipath.devIsFCP(dev.get("devtype"))
+ domType = sd.storageType(storageType) if storageType else None
+
+ sdCache.refreshStorage(domType)
+
+ if domType == sd.ISCSI_DOMAIN:
+ typeFilter = lambda dev: multipath.devIsiSCSI(dev.get("devtype"))
+ elif domType == sd.FCP_DOMAIN:
+ typeFilter = lambda dev: multipath.devIsFCP(dev.get("devtype"))
+ else:
+ typeFilter = lambda dev: True
devices = []
pvs = {}
@@ -2470,7 +2471,7 @@
# while the VDSM was not connected, we need to
# call refreshStorage.
if domType in (sd.FCP_DOMAIN, sd.ISCSI_DOMAIN):
- sdCache.refreshStorage()
+ sdCache.refreshStorage(domType)
try:
doms = self.__prefetchDomains(domType, conObj)
except:
@@ -2864,7 +2865,8 @@
"""
vars.task.setDefaultException(
se.StorageDomainActionError("spUUID: %s" % spUUID))
- sdCache.refreshStorage()
+ domType = sd.storageType(storageType) if storageType else None
+ sdCache.refreshStorage(domType)
if spUUID and spUUID != volume.BLANK_UUID:
domList = self.getPool(spUUID).getDomains()
domains = domList.keys()
@@ -2925,7 +2927,8 @@
:rtype: dict
"""
vars.task.setDefaultException(se.VolumeGroupActionError())
- sdCache.refreshStorage()
+ domType = sd.storageType(storageType) if storageType else None
+ sdCache.refreshStorage(domType)
# getSharedLock(connectionsResource...)
vglist = []
vgs = self.__getVGsInfo()
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index ad81d2d..32deb98 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -39,6 +39,7 @@
import misc
import iscsi
import devicemapper
+import sd
DEV_ISCSI = "iSCSI"
DEV_FCP = "FCP"
@@ -61,7 +62,7 @@
""" multipath operation failed """
-def rescan():
+def rescan(domType=None):
"""
Forces multipath daemon to rescan the list of available devices and
refresh the mapping table. New devices can be found under /dev/mapper
@@ -70,8 +71,12 @@
"""
# First rescan iSCSI and FCP connections
- iscsi.rescan()
- hba.rescan()
+
+ if domType in (None, sd.ISCSI_DOMAIN):
+ iscsi.rescan()
+
+ if domType in (None, sd.FCP_DOMAIN):
+ hba.rescan()
# Now let multipath daemon pick up new devices
misc.execCmd([constants.EXT_MULTIPATH], sudo=True)
diff --git a/vdsm/storage/sdc.py b/vdsm/storage/sdc.py
index ecb9708..273c5c0 100644
--- a/vdsm/storage/sdc.py
+++ b/vdsm/storage/sdc.py
@@ -77,10 +77,10 @@
self.__staleStatus = self.STORAGE_STALE
@misc.samplingmethod
- def refreshStorage(self):
+ def refreshStorage(self, domType=None):
self.__staleStatus = self.STORAGE_REFRESHING
- multipath.rescan()
+ multipath.rescan(domType)
multipath.resize_devices()
lvm.invalidateCache()
--
To view, visit https://gerrit.ovirt.org/45824
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic32cd683020e94df016dd77b19ae3eb7317c5554
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Yeela Kaplan has uploaded a new change for review.
Change subject: [WIP]fencenode: split fenceNode into its own module
......................................................................
[WIP]fencenode: split fenceNode into its own module
Change-Id: I7bd5e7246cf6da21e355849014a8fc71d5edbde6
Signed-off-by: Yeela Kaplan <ykaplan(a)redhat.com>
---
M debian/vdsm-python.install
M lib/vdsm/Makefile.am
A lib/vdsm/fencenode.py
M vdsm.spec.in
M vdsm/API.py
5 files changed, 120 insertions(+), 80 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/97/43597/1
diff --git a/debian/vdsm-python.install b/debian/vdsm-python.install
index d9402c3..901edb6 100644
--- a/debian/vdsm-python.install
+++ b/debian/vdsm-python.install
@@ -10,6 +10,7 @@
./usr/lib/python2.7/dist-packages/vdsm/exception.py
./usr/lib/python2.7/dist-packages/vdsm/executor.py
./usr/lib/python2.7/dist-packages/vdsm/ipwrapper.py
+./usr/lib/python2.7/dist-packages/vdsm/fencenode.py
./usr/lib/python2.7/dist-packages/vdsm/jsonrpcvdscli.py
./usr/lib/python2.7/dist-packages/vdsm/libvirtconnection.py
./usr/lib/python2.7/dist-packages/vdsm/netconfpersistence.py
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index 95e236f..875507c 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -30,6 +30,7 @@
exception.py \
executor.py \
ipwrapper.py \
+ fencenode.py \
jsonrpcvdscli.py \
libvirtconnection.py \
netconfpersistence.py \
diff --git a/lib/vdsm/fencenode.py b/lib/vdsm/fencenode.py
new file mode 100644
index 0000000..3456b2f
--- /dev/null
+++ b/lib/vdsm/fencenode.py
@@ -0,0 +1,100 @@
+#
+# Copyright 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import logging
+import os
+import signal
+
+import utils
+import constants
+from define import doneCode, errCode
+
+
+(a)utils.traceback(on=logging.name)
+def fence(script, data):
+ # non-status actions are sent asyncronously. deathSignal is set to
+ # make sure that no stray fencing scripts are left behind if Vdsm
+ # crashes.
+ rc, out, err = utils.execCmd(
+ [script], deathSignal=signal.SIGTERM, data=data)
+ logging.debug('rc %s data %s out %s err %s', rc,
+ hidePasswd(data), out, err)
+ return rc, out, err
+
+
+def hidePasswd(text):
+ cleantext = ''
+ for line in text.splitlines(True):
+ if line.startswith('passwd='):
+ line = 'passwd=XXXX\n'
+ cleantext += line
+ return cleantext
+
+
+def fenceNode(addr, port, agent, username, password, action,
+ secure=False, options='', policy=None):
+
+ logging.debug('fenceNode(addr=%s,port=%s,agent=%s,user=%s,passwd=%s,'
+ 'action=%s,secure=%s,options=%s,policy=%s)',
+ addr, port, agent, username, password, action, secure,
+ options, policy)
+
+ if action not in ('status', 'on', 'off', 'reboot'):
+ raise ValueError('illegal action ' + action)
+
+ script = constants.EXT_FENCE_PREFIX + agent
+
+ data = ('agent=fence_%s\nipaddr=%s\nlogin=%s\naction=%s\n'
+ 'passwd=%s\n') % (agent, addr, username, action, password.value)
+ if port != '':
+ data += 'port=%s\n' % (port,)
+ if utils.tobool(secure):
+ data += 'secure=yes\n'
+ data += options
+
+ try:
+ rc, out, err = fence(script, data)
+ except OSError as e:
+ if e.errno == os.errno.ENOENT:
+ return errCode['fenceAgent']
+ raise
+
+ logging.debug('rc %s data %s out %s err %s',
+ rc, hidePasswd(data), out, err)
+
+ if not 0 <= rc <= 2:
+ return {'status': {'code': 1,
+ 'message': out + err}}
+
+ message = doneCode['message']
+ if action == 'status':
+ if rc == 0:
+ power = 'on'
+ elif rc == 2:
+ power = 'off'
+ else:
+ power = 'unknown'
+ message = out + err
+ return {'status': {'code': 0, 'message': message},
+ 'power': power}
+ if rc != 0:
+ message = out + err
+ return {'status': {'code': rc, 'message': message},
+ 'power': 'unknown', 'operationStatus': 'initiated'}
diff --git a/vdsm.spec.in b/vdsm.spec.in
index 966a974..9e69162 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1071,6 +1071,7 @@
%{python_sitelib}/%{vdsm_name}/exception.py*
%{python_sitelib}/%{vdsm_name}/executor.py*
%{python_sitelib}/%{vdsm_name}/ipwrapper.py*
+%{python_sitelib}/%{vdsm_name}/fencenode.py*
%{python_sitelib}/%{vdsm_name}/jsonrpcvdscli.py*
%{python_sitelib}/%{vdsm_name}/libvirtconnection.py*
%{python_sitelib}/%{vdsm_name}/netinfo.py*
diff --git a/vdsm/API.py b/vdsm/API.py
index 0a93d2a..0719926 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -21,8 +21,6 @@
# pylint: disable=R0904
from contextlib import contextmanager
-import os
-import signal
import six
import sys
import time
@@ -38,6 +36,7 @@
from clientIF import clientIF
from vdsm import netinfo
from vdsm import constants
+from vdsm import fencenode
import storage.misc
import storage.clusterlock
import storage.volume
@@ -1187,6 +1186,11 @@
APIBase.__init__(self)
# General Host functions
+ def ping(self):
+ "Ping the server. Useful for tests"
+ updateTimestamp()
+ return {'status': doneCode}
+
def fenceNode(self, addr, port, agent, username, password, action,
secure=False, options='', policy=None):
"""Send a fencing command to a remote node.
@@ -1194,44 +1198,24 @@
agent is one of (rsa, ilo, drac5, ipmilan, etc)
action can be one of (status, on, off, reboot)."""
- @utils.traceback(on=self.log.name)
- def fence(script, inp):
- # non-status actions are sent asyncronously. deathSignal is set to
- # make sure that no stray fencing scripts are left behind if Vdsm
- # crashes.
- rc, out, err = utils.execCmd(
- [script], deathSignal=signal.SIGTERM,
- data=inp)
- self.log.debug('rc %s inp %s out %s err %s', rc,
- hidePasswd(inp), out, err)
- return rc, out, err
-
- def hidePasswd(text):
- cleantext = ''
- for line in text.splitlines(True):
- if line.startswith('passwd='):
- line = 'passwd=XXXX\n'
- cleantext += line
- return cleantext
-
def should_fence(policy):
# skip fence execution if map of storage domains with host id is
# entered and at least one storage domain connection from host is
# alive
if policy is None:
- self.log.debug('No policy specified')
+ logging.debug('No policy specified')
return True
hostIdMap = policy.get('storageDomainHostIdMap')
if not hostIdMap:
- self.log.warning('Invalid policy specified')
+ logging.warning('Invalid policy specified')
return True
result = self._irs.getHostLeaseStatus(hostIdMap)
- if result['status']['code'] != 0:
- self.log.error(
- "Error getting host lease status, error code '%s'",
- result['status']['code'])
+ rc = result['status']['code']
+ if rc != 0:
+ logging.error(
+ "Error getting host lease status, error code '%s'", rc)
return True
# HOST_STATUS_LIVE means that host renewed its lease in last 80
@@ -1239,65 +1223,18 @@
# fencing, even when it's unreachable from engine
for sd, status in result['domains'].iteritems():
if status == storage.clusterlock.HOST_STATUS_LIVE:
- self.log.debug("Host has live lease on '%s'", sd)
+ logging.debug("Host has live lease on '%s'", sd)
return False
- self.log.debug("Host doesn't have any live lease")
+ logging.debug("Host doesn't have any live lease")
return True
- self.log.debug('fenceNode(addr=%s,port=%s,agent=%s,user=%s,passwd=%s,'
- 'action=%s,secure=%s,options=%s,policy=%s)',
- addr, port, agent, username, password, action, secure,
- options, policy)
-
- if action not in ('status', 'on', 'off', 'reboot'):
- raise ValueError('illegal action ' + action)
-
if action != 'status' and not should_fence(policy):
- self.log.debug("Skipping execution of action '%s'", action)
+ logging.debug("Skipping execution of action '%s'", action)
return {'status': doneCode, 'operationStatus': 'skipped'}
- script = constants.EXT_FENCE_PREFIX + agent
-
- inp = ('agent=fence_%s\nipaddr=%s\nlogin=%s\naction=%s\n'
- 'passwd=%s\n') % (agent, addr, username, action, password.value)
- if port != '':
- inp += 'port=%s\n' % (port,)
- if utils.tobool(secure):
- inp += 'secure=yes\n'
- inp += options
-
- try:
- rc, out, err = fence(script, inp)
- except OSError as e:
- if e.errno == os.errno.ENOENT:
- return errCode['fenceAgent']
- raise
- self.log.debug('rc %s in %s out %s err %s', rc,
- hidePasswd(inp), out, err)
- if not 0 <= rc <= 2:
- return {'status': {'code': 1,
- 'message': out + err}}
- message = doneCode['message']
- if action == 'status':
- if rc == 0:
- power = 'on'
- elif rc == 2:
- power = 'off'
- else:
- power = 'unknown'
- message = out + err
- return {'status': {'code': 0, 'message': message},
- 'power': power}
- if rc != 0:
- message = out + err
- return {'status': {'code': rc, 'message': message},
- 'power': 'unknown', 'operationStatus': 'initiated'}
-
- def ping(self):
- "Ping the server. Useful for tests"
- updateTimestamp()
- return {'status': doneCode}
+ return fencenode.fenceNode(addr, port, agent, username, password,
+ action, secure, options, policy)
def getCapabilities(self):
"""
--
To view, visit https://gerrit.ovirt.org/43597
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7bd5e7246cf6da21e355849014a8fc71d5edbde6
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yeela Kaplan <ykaplan(a)redhat.com>
Nir Soffer has uploaded a new change for review.
Change subject: qemuimg: Memoize _supports_qcow2_compat
......................................................................
qemuimg: Memoize _supports_qcow2_compat
We used to run qemu-img twice when creating or converting qcow2 images.
The first run check if qemu-img supports the qcow2 "comapt" option, and
the second run uses the result to format the qemu-img command.
Now we run qemu-img once for "create" and "convert" to learn about its
capabilities, and use the cached value on the next runs. If qemu-img
executable is modified, we drop the cache, in case a new version was
installed with different capabilities.
Change-Id: Ic63f5e8c06993df8e4066bf7ac2dabfb4b4bdbfb
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
M lib/vdsm/qemuimg.py
M tests/qemuimgTests.py
2 files changed, 8 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/11/34711/1
diff --git a/lib/vdsm/qemuimg.py b/lib/vdsm/qemuimg.py
index cf428b2..f295acc 100644
--- a/lib/vdsm/qemuimg.py
+++ b/lib/vdsm/qemuimg.py
@@ -23,6 +23,7 @@
import signal
from . import utils
+from . import cache
_qemuimg = utils.CommandPath("qemu-img",
"/usr/bin/qemu-img",) # Fedora, EL6
@@ -221,6 +222,7 @@
raise QImgError(rc, out, err)
+(a)cache.memoized(cache.file_validator(_qemuimg.cmd))
def _supports_qcow2_compat(command):
"""
qemu-img "create" and "convert" commands support a "compat" option in
diff --git a/tests/qemuimgTests.py b/tests/qemuimgTests.py
index 813a497..a642374 100644
--- a/tests/qemuimgTests.py
+++ b/tests/qemuimgTests.py
@@ -118,6 +118,9 @@
class CreateTests(TestCaseBase):
+ def setUp(self):
+ qemuimg._supports_qcow2_compat.invalidate()
+
def test_no_format(self):
def create(cmd, **kw):
expected = [QEMU_IMG, 'create', 'image']
@@ -161,6 +164,9 @@
class ConvertTests(TestCaseBase):
+ def setUp(self):
+ qemuimg._supports_qcow2_compat.invalidate()
+
def test_no_format(self):
def convert(cmd, **kw):
expected = [QEMU_IMG, 'convert', '-t', 'none', 'src', 'dst']
--
To view, visit http://gerrit.ovirt.org/34711
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic63f5e8c06993df8e4066bf7ac2dabfb4b4bdbfb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <nsoffer(a)redhat.com>
Federico Simoncelli has uploaded a new change for review.
Change subject: vdsm: add eventfd and EventFile synchronization
......................................................................
vdsm: add eventfd and EventFile synchronization
Change-Id: I0d237f13c42b1f4505c90d30c6d3c3ecbd1e9fa7
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
---
M lib/vdsm/Makefile.am
A lib/vdsm/eventfd.py
M tests/Makefile.am
A tests/eventfdTests.py
4 files changed, 251 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/87/33687/1
diff --git a/lib/vdsm/Makefile.am b/lib/vdsm/Makefile.am
index 4bebf28..e712cad 100644
--- a/lib/vdsm/Makefile.am
+++ b/lib/vdsm/Makefile.am
@@ -25,6 +25,7 @@
__init__.py \
compat.py \
define.py \
+ eventfd.py \
exception.py \
ipwrapper.py \
libvirtconnection.py \
diff --git a/lib/vdsm/eventfd.py b/lib/vdsm/eventfd.py
new file mode 100644
index 0000000..b2a7084
--- /dev/null
+++ b/lib/vdsm/eventfd.py
@@ -0,0 +1,140 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+"""\
+This module provides the support for eventfd(2).
+
+More information about eventfd and usage examples can be found in the
+eventfd(2) man page.
+
+The EventFile class provides a single synchronization object exposing
+the python Event interface and associated eventfds.
+
+The eventfd() context manager returns a file descriptor that can be
+used to provide the event notice to select, poll and epoll, e.g.
+
+ import os
+ import sys
+ import select
+ import threading
+ import time
+ from vdsm.eventfd import EventFile, DATASIZE
+
+ e = EventFile()
+ p = select.epoll()
+
+ threading.Timer(5, e.set).start()
+
+ with e.eventfd() as efd:
+ p.register(efd, select.EPOLLIN)
+ p.register(sys.stdin.fileno(), select.EPOLLIN)
+
+ print "Echoing lines until event is received"
+ event_received = False
+
+ while not event_received:
+ for fileno, event in p.poll():
+ if not event & select.EPOLLIN:
+ continue
+
+ if fileno == efd:
+ os.read(efd, DATASIZE)
+ event_received = True
+ elif fileno == sys.stdin.fileno():
+ print os.read(sys.stdin.fileno(), 1024),
+
+ print "Event received!"
+
+
+The Event set() semantic is preserved in the eventfd context manager:
+if the event is set then the eventfd already contains the notification.
+This is both to maintain the semantic and to avoid possible races as:
+
+ if not e.is_set():
+ with e.eventfd() as efd:
+ ...
+"""
+
+import os
+import ctypes
+import threading
+
+from contextlib import contextmanager
+
+_libc = ctypes.CDLL('libc.so.6', use_errno=True)
+
+EFD_NONBLOCK = os.O_NONBLOCK
+EFD_CLOEXEC = 02000000 # os.O_CLOEXEC in python 3.3
+EFD_SEMAPHORE = 00000001
+
+DATASIZE = ctypes.sizeof(ctypes.c_ulonglong)
+
+
+def eventfd(initval, flags):
+ return _libc.eventfd(initval, flags)
+
+
+class EventFile(object):
+ def __init__(self, event=None):
+ self.__lock = threading.Lock()
+ self.__fds = set()
+ self.__event = event or threading.Event()
+
+ @staticmethod
+ def __fire_event(fd):
+ os.write(fd, ctypes.c_ulonglong(1))
+
+ def open_eventfd(self):
+ with self.__lock:
+ fd = eventfd(0, 0)
+
+ self.__fds.add(fd)
+
+ if self.__event.is_set():
+ self.__fire_event(fd)
+
+ return fd
+
+ @contextmanager
+ def eventfd(self):
+ fd = self.open_eventfd()
+
+ yield fd
+
+ with self.__lock:
+ self.__fds.remove(fd)
+ os.close(fd)
+
+ def isSet(self):
+ return self.__event.isSet()
+
+ is_set = isSet
+
+ def set(self):
+ with self.__lock:
+ self.__event.set()
+ for fd in self.__fds:
+ self.__fire_event(fd)
+
+ def clear(self):
+ self.__event.clear()
+
+ def wait(self, timeout=None, balancing=True):
+ self.__event.wait(timeout)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 449d7b1..120712e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -31,6 +31,7 @@
clientifTests.py \
configNetworkTests.py \
domainMonitorTests.py \
+ eventfdTests.py \
fileVolumeTests.py \
fileUtilTests.py \
fuserTests.py \
diff --git a/tests/eventfdTests.py b/tests/eventfdTests.py
new file mode 100644
index 0000000..be15248
--- /dev/null
+++ b/tests/eventfdTests.py
@@ -0,0 +1,109 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import os
+import select
+from vdsm.eventfd import EventFile, DATASIZE
+from nose.tools import timed, raises, TimeExpired
+
+TEST_TIMEOUT = 1
+WAIT_TIMEOUT = 2
+
+
+def test_set():
+ e = EventFile()
+ e.set()
+ assert e.is_set()
+ assert e.isSet()
+
+
+def text_clear():
+ e = EventFile()
+ e.set()
+ assert e.is_set()
+ e.clear()
+ assert not e.is_set()
+
+
+@timed(TEST_TIMEOUT)
+def test_wait_set():
+ e = EventFile()
+ e.set()
+ e.wait(WAIT_TIMEOUT)
+
+
+@raises(TimeExpired)
+@timed(TEST_TIMEOUT)
+def test_wait_noset():
+ e = EventFile()
+ e.wait(WAIT_TIMEOUT)
+
+
+@timed(TEST_TIMEOUT)
+def test_eventfd_earlyset():
+ e = EventFile()
+ e.set()
+ with e.eventfd() as fd:
+ assert len(__select_and_read(fd)) == DATASIZE
+
+
+@timed(TEST_TIMEOUT)
+def test_eventfd_lateset():
+ e = EventFile()
+ with e.eventfd() as fd:
+ e.set()
+ assert len(__select_and_read(fd)) == DATASIZE
+
+
+@raises(TimeExpired)
+@timed(TEST_TIMEOUT)
+def test_eventfd_noset():
+ e = EventFile()
+ with e.eventfd() as fd:
+ assert len(__select_and_read(fd)) != DATASIZE
+
+
+@timed(TEST_TIMEOUT)
+def test_eventfd_multiple():
+ e = EventFile()
+ e.set()
+ with e.eventfd() as fd1:
+ assert len(__select_and_read(fd1)) == DATASIZE
+ with e.eventfd() as fd2:
+ assert len(__select_and_read(fd2)) == DATASIZE
+ with e.eventfd() as fd3:
+ assert len(__select_and_read(fd3)) == DATASIZE
+
+
+@raises(TimeExpired)
+@timed(TEST_TIMEOUT)
+def test_eventfd_clear():
+ e = EventFile()
+ e.set()
+ e.clear()
+ with e.eventfd() as fd:
+ assert len(__select_and_read(fd)) != DATASIZE
+
+
+def __select_and_read(fd):
+ rd, wr, ex = select.select((fd,), (), (), WAIT_TIMEOUT)
+ if fd in rd:
+ return os.read(fd, DATASIZE)
+ return ''
--
To view, visit http://gerrit.ovirt.org/33687
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0d237f13c42b1f4505c90d30c6d3c3ecbd1e9fa7
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Federico Simoncelli <fsimonce(a)redhat.com>
Hello Fred Rolland,
I'd like you to do a code review. Please visit
https://gerrit.ovirt.org/59865
to review the following change.
Change subject: storage: Remove unneeded multipath call
......................................................................
storage: Remove unneeded multipath call
As part of multipath rescan, we call iscsi and hba rescan.
These operations are sufficient to discover new devices and
detect changes in size.
Therefore, the multipath call is not needed and can be removed
improving the overall performance of GetDeviceList verb.
Detailed profiling :
time filename:lineno(function)
3.178 |hsm.py:1948(HSM._getDeviceList)
1.546 |--> sdc.py:80(StorageDomainCache.refreshStorage)
1.489 |--> multipath.py:65(rescan)
0.481 |--> iscsi.py:431(rescan) iscsi scan
0.076 |--> storage/hba.py:53(rescan) fc scan
0.912 |--> multipath.py:88(multipath) multipath
0.056 |--> multipath.py:92(resize_devices)
0.756 |--> lvm.py:843(getAllPVs)
0.756 |--> lvm.py:317(LVMCache._reloadpvs)
0.755 |--> lvm.py:290(LVMCache.cmd) pvs
0.871 |--> multipath.py:213(pathListIter)
0.029 |-->devicemapper.py:176(getPathsStatus) dmsetup status
Change-Id: Ie99da5ad7ec46f4a69a3d09a811e875d5e3a5b44
Bug-Url: https://bugzilla.redhat.com/1303578
Signed-off-by: Fred Rolland <frolland(a)redhat.com>
---
M vdsm/storage/multipath.py
1 file changed, 0 insertions(+), 4 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/65/59865/1
diff --git a/vdsm/storage/multipath.py b/vdsm/storage/multipath.py
index 77c54a7..03fcb57 100644
--- a/vdsm/storage/multipath.py
+++ b/vdsm/storage/multipath.py
@@ -30,7 +30,6 @@
from collections import namedtuple
from vdsm import commands
-from vdsm import constants
from vdsm import supervdsm
from vdsm import udevadm
from vdsm import utils
@@ -73,9 +72,6 @@
# First rescan iSCSI and FCP connections
iscsi.rescan()
hba.rescan()
-
- # Now let multipath daemon pick up new devices
- misc.execCmd([constants.EXT_MULTIPATH], sudo=True)
# Scanning SCSI interconnects starts a storm of udev events. Wait until all
# events are processed, ensuring detection of new devices and creation or
--
To view, visit https://gerrit.ovirt.org/59865
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie99da5ad7ec46f4a69a3d09a811e875d5e3a5b44
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Freddy Rolland <frolland(a)redhat.com>
Gerrit-Reviewer: Fred Rolland <frolland(a)redhat.com>
Irit Goihman has uploaded a new change for review.
Change subject: wip: py3: port storage misc.py file to python3
......................................................................
wip: py3: port storage misc.py file to python3
Change-Id: I1adec40146967965329024718c6ff48d0fa089fb
Signed-off-by: Irit Goihman <igoihman(a)redhat.com>
---
M lib/vdsm/storage/misc.py
1 file changed, 7 insertions(+), 7 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/01/60001/1
diff --git a/lib/vdsm/storage/misc.py b/lib/vdsm/storage/misc.py
index 173d608..162570e 100644
--- a/lib/vdsm/storage/misc.py
+++ b/lib/vdsm/storage/misc.py
@@ -33,7 +33,6 @@
import inspect
import logging
import os
-import Queue
import random
import re
import signal
@@ -46,7 +45,8 @@
from array import array
from collections import defaultdict
from functools import wraps, partial
-from itertools import chain, imap
+from itertools import chain
+from six.moves import queue, map, range
from vdsm import commands
from vdsm import concurrent
@@ -69,7 +69,7 @@
def namedtuple2dict(nt):
- return dict(imap(lambda f: (f, getattr(nt, f)), nt._fields))
+ return dict(map(lambda f: (f, getattr(nt, f)), nt._fields))
class _LogSkip(object):
@@ -95,7 +95,7 @@
def logskip(var):
- if isinstance(var, types.StringTypes):
+ if isinstance(var, (str,)):
return lambda func: _LogSkip.wrap(func, var)
return _LogSkip.wrap(var, None)
@@ -423,7 +423,7 @@
Raises InvalidParameterException if value is not a string or if it could
not be converted to integer.
"""
- if not isinstance(size, basestring):
+ if not isinstance(size, six.string_types):
log.error("Number of sectors as int is not supported, use size in "
"bytes as string")
raise se.InvalidParameterException("size", size)
@@ -669,7 +669,7 @@
if maxthreads < 1 and maxthreads != UNLIMITED_THREADS:
raise ValueError("Wrong input to function itmap: %s", maxthreads)
- respQueue = Queue.Queue()
+ respQueue = queue.Queue()
def wrapper(value):
try:
@@ -699,7 +699,7 @@
maxthreads -= 1
# waiting for rest threads to end
- for i in xrange(threadsCount):
+ for i in range(threadsCount):
yield respQueue.get()
--
To view, visit https://gerrit.ovirt.org/60001
To unsubscribe, visit https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1adec40146967965329024718c6ff48d0fa089fb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Irit Goihman <igoihman(a)redhat.com>