Hide lock_prefix argument using synchronized_with_prefix()

The lockfile module has a new convenience API which sets the lockfile prefix.
Using this API, the prefix is not required everytime synchronized is used.

Change-Id: Iac1cfcc83b59108164de924d20127c1cf4dd7dcd
This commit is contained in:
Zhongyue Luo
2013-05-11 21:25:16 +08:00
parent 966c6fbdfc
commit 3c36cbdbc8
16 changed files with 86 additions and 66 deletions

View File

@@ -25,9 +25,9 @@ from oslo.config import cfg
from nova.cells import rpc_driver
from nova import context
from nova.db import base
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
from nova import utils
cell_state_manager_opts = [
cfg.IntOpt('db_check_interval',
@@ -258,7 +258,7 @@ class CellStateManager(base.Base):
'units_by_mb': disk_mb_free_units}}
self.my_cell_state.update_capacities(capacities)
@lockutils.synchronized('cell-db-sync', 'nova-')
@utils.synchronized('cell-db-sync')
def _cell_db_sync(self):
"""Update status for all cells if it's time. Most calls to
this are from the check_for_update() decorator that checks

View File

@@ -62,7 +62,6 @@ from nova.network import model as network_model
from nova.network.security_group import openstack_driver
from nova.openstack.common import excutils
from nova.openstack.common import jsonutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common.notifier import api as notifier
from nova.openstack.common import periodic_task
@@ -699,7 +698,7 @@ class ComputeManager(manager.SchedulerDependentManager):
Synchronise the call beacuse we may still be in the middle of
creating the instance.
"""
@lockutils.synchronized(instance['uuid'], 'nova-')
@utils.synchronized(instance['uuid'])
def _sync_refresh():
return self.driver.refresh_instance_security_rules(instance)
return _sync_refresh()
@@ -1313,7 +1312,7 @@ class ComputeManager(manager.SchedulerDependentManager):
if filter_properties is None:
filter_properties = {}
@lockutils.synchronized(instance['uuid'], 'nova-')
@utils.synchronized(instance['uuid'])
def do_run_instance():
self._run_instance(context, request_spec,
filter_properties, requested_networks, injected_files,
@@ -1465,7 +1464,7 @@ class ComputeManager(manager.SchedulerDependentManager):
if not bdms:
bdms = self._get_instance_volume_bdms(context, instance)
@lockutils.synchronized(instance['uuid'], 'nova-')
@utils.synchronized(instance['uuid'])
def do_terminate_instance(instance, bdms):
try:
self._delete_instance(context, instance, bdms,
@@ -2928,7 +2927,7 @@ class ComputeManager(manager.SchedulerDependentManager):
def reserve_block_device_name(self, context, instance, device,
volume_id=None):
@lockutils.synchronized(instance['uuid'], 'nova-')
@utils.synchronized(instance['uuid'])
def do_reserve():
bdms = self.conductor_api.block_device_mapping_get_all_by_instance(
context, instance)

View File

@@ -30,8 +30,8 @@ from nova import context
from nova import exception
from nova.openstack.common import importutils
from nova.openstack.common import jsonutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova import utils
resource_tracker_opts = [
cfg.IntOpt('reserved_host_disk_mb', default=0,
@@ -65,7 +65,7 @@ class ResourceTracker(object):
self.tracked_migrations = {}
self.conductor_api = conductor.API()
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def instance_claim(self, context, instance_ref, limits=None):
"""Indicate that some resources are needed for an upcoming compute
instance build operation.
@@ -115,7 +115,7 @@ class ResourceTracker(object):
else:
raise exception.ComputeResourcesUnavailable()
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def resize_claim(self, context, instance_ref, instance_type, limits=None):
"""Indicate that resources are needed for a resize operation to this
compute host.
@@ -183,7 +183,7 @@ class ResourceTracker(object):
instance_ref['launched_on'] = self.host
instance_ref['node'] = self.nodename
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def abort_instance_claim(self, instance):
"""Remove usage from the given instance."""
# flag the instance as deleted to revert the resource usage
@@ -194,7 +194,7 @@ class ResourceTracker(object):
ctxt = context.get_admin_context()
self._update(ctxt, self.compute_node)
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def drop_resize_claim(self, instance, instance_type=None, prefix='new_'):
"""Remove usage for an incoming/outgoing migration."""
if instance['uuid'] in self.tracked_migrations:
@@ -212,7 +212,7 @@ class ResourceTracker(object):
ctxt = context.get_admin_context()
self._update(ctxt, self.compute_node)
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def update_usage(self, context, instance):
"""Update the resource usage and stats after a change in an
instance
@@ -232,7 +232,7 @@ class ResourceTracker(object):
def disabled(self):
return self.compute_node is None
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
@utils.synchronized(COMPUTE_RESOURCE_SEMAPHORE)
def update_available_resource(self, context):
"""Override in-memory calculations of compute node resource usage based
on data audited from the hypervisor layer.

View File

@@ -25,7 +25,6 @@ from nova import exception
from nova.network import rpcapi as network_rpcapi
from nova.openstack.common import excutils
from nova.openstack.common import importutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common.notifier import api as notifier
from nova.openstack.common import processutils
@@ -33,6 +32,7 @@ from nova.openstack.common.rpc import common as rpc_common
from nova.openstack.common import uuidutils
from nova import quota
from nova import servicegroup
from nova import utils
LOG = logging.getLogger(__name__)
@@ -354,7 +354,7 @@ class FloatingIP(object):
"""Performs db and driver calls to associate floating ip & fixed ip."""
interface = CONF.public_interface or interface
@lockutils.synchronized(unicode(floating_address), 'nova-')
@utils.synchronized(unicode(floating_address))
def do_associate():
# associate floating ip
fixed = self.db.floating_ip_fixed_ip_associate(context,
@@ -443,7 +443,7 @@ class FloatingIP(object):
"""Performs db and driver calls to disassociate floating ip."""
interface = CONF.public_interface or interface
@lockutils.synchronized(unicode(address), 'nova-')
@utils.synchronized(unicode(address))
def do_disassociate():
# NOTE(vish): Note that we are disassociating in the db before we
# actually remove the ip address on the host. We are

View File

@@ -33,7 +33,6 @@ from nova.openstack.common import excutils
from nova.openstack.common import fileutils
from nova.openstack.common import importutils
from nova.openstack.common import jsonutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import processutils
from nova.openstack.common import timeutils
@@ -397,7 +396,7 @@ class IptablesManager(object):
self._apply()
@lockutils.synchronized('iptables', 'nova-', external=True)
@utils.synchronized('iptables', external=True)
def _apply(self):
"""Apply the current in-memory set of iptables rules.
@@ -980,7 +979,7 @@ def kill_dhcp(dev):
# NOTE(ja): Sending a HUP only reloads the hostfile, so any
# configuration options (like dchp-range, vlan, ...)
# aren't reloaded.
@lockutils.synchronized('dnsmasq_start', 'nova-')
@utils.synchronized('dnsmasq_start')
def restart_dhcp(context, dev, network_ref):
"""(Re)starts a dnsmasq server for a given network.
@@ -1068,7 +1067,7 @@ def restart_dhcp(context, dev, network_ref):
_add_dnsmasq_accept_rules(dev)
@lockutils.synchronized('radvd_start', 'nova-')
@utils.synchronized('radvd_start')
def update_ra(context, dev, network_ref):
conffile = _ra_file(dev, 'conf')
conf_str = """
@@ -1393,7 +1392,7 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
LinuxBridgeInterfaceDriver.remove_vlan(vlan_num)
@classmethod
@lockutils.synchronized('lock_vlan', 'nova-', external=True)
@utils.synchronized('lock_vlan', external=True)
def ensure_vlan(_self, vlan_num, bridge_interface, mac_address=None):
"""Create a vlan unless it already exists."""
interface = 'vlan%s' % vlan_num
@@ -1418,14 +1417,14 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
return interface
@classmethod
@lockutils.synchronized('lock_vlan', 'nova-', external=True)
@utils.synchronized('lock_vlan', external=True)
def remove_vlan(cls, vlan_num):
"""Delete a vlan."""
vlan_interface = 'vlan%s' % vlan_num
delete_net_dev(vlan_interface)
@classmethod
@lockutils.synchronized('lock_bridge', 'nova-', external=True)
@utils.synchronized('lock_bridge', external=True)
def ensure_bridge(_self, bridge, interface, net_attrs=None, gateway=True,
filtering=True):
"""Create a bridge unless it already exists.
@@ -1510,7 +1509,7 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
% (bridge, CONF.iptables_drop_action)))
@classmethod
@lockutils.synchronized('lock_bridge', 'nova-', external=True)
@utils.synchronized('lock_bridge', external=True)
def remove_bridge(cls, bridge, gateway=True, filtering=True):
"""Delete a bridge."""
if not device_exists(bridge):
@@ -1536,7 +1535,7 @@ class LinuxBridgeInterfaceDriver(LinuxNetInterfaceDriver):
delete_net_dev(bridge)
@lockutils.synchronized('ebtables', 'nova-', external=True)
@utils.synchronized('ebtables', external=True)
def ensure_ebtables_rules(rules, table='filter'):
for rule in rules:
cmd = ['ebtables', '-t', table, '-D'] + rule.split()
@@ -1545,7 +1544,7 @@ def ensure_ebtables_rules(rules, table='filter'):
_execute(*cmd, run_as_root=True)
@lockutils.synchronized('ebtables', 'nova-', external=True)
@utils.synchronized('ebtables', external=True)
def remove_ebtables_rules(rules, table='filter'):
for rule in rules:
cmd = ['ebtables', '-t', table, '-D'] + rule.split()

View File

@@ -66,7 +66,6 @@ from nova.network.security_group import openstack_driver
from nova.openstack.common import excutils
from nova.openstack.common import importutils
from nova.openstack.common import jsonutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import periodic_task
from nova.openstack.common.rpc import common as rpc_common
@@ -313,7 +312,7 @@ class NetworkManager(manager.Manager):
def _import_ipam_lib(self, ipam_lib):
self.ipam = importutils.import_module(ipam_lib).get_ipam_lib(self)
@lockutils.synchronized('get_dhcp', 'nova-')
@utils.synchronized('get_dhcp')
def _get_dhcp_ip(self, context, network_ref, host=None):
"""Get the proper dhcp address to listen on."""
# NOTE(vish): this is for compatibility
@@ -1807,7 +1806,7 @@ class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager):
return NetworkManager.create_networks(
self, context, vpn=True, **kwargs)
@lockutils.synchronized('setup_network', 'nova-', external=True)
@utils.synchronized('setup_network', external=True)
def _setup_network_on_host(self, context, network):
"""Sets up network on this host."""
if not network['vpn_public_address']:
@@ -1841,7 +1840,7 @@ class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager):
self.db.network_update(context, network['id'],
{'gateway_v6': gateway})
@lockutils.synchronized('setup_network', 'nova-', external=True)
@utils.synchronized('setup_network', external=True)
def _teardown_network_on_host(self, context, network):
if not CONF.fake_network:
network['dhcp_server'] = self._get_dhcp_ip(context, network)

View File

@@ -49,6 +49,10 @@ CONF = cfg.CONF
CONF.register_opts(util_opts)
def set_defaults(lock_path):
cfg.set_defaults(util_opts, lock_path=lock_path)
class _InterProcessLock(object):
"""Lock implementation which allows multiple locks, working around
issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does
@@ -247,3 +251,28 @@ def synchronized(name, lock_file_prefix, external=False, lock_path=None):
return retval
return inner
return wrap
def synchronized_with_prefix(lock_file_prefix):
"""Partial object generator for the synchronization decorator.
Redefine @synchronized in each project like so::
(in nova/utils.py)
from nova.openstack.common import lockutils
synchronized = lockutils.synchronized_with_prefix('nova-')
(in nova/foo.py)
from nova import utils
@utils.synchronized('mylock')
def bar(self, *args):
...
The lock_file_prefix argument is used to provide lock files on disk with a
meaningful prefix. The prefix should end with a hyphen ('-') if specified.
"""
return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)

View File

@@ -161,7 +161,7 @@ class RawTestCase(_ImageTestCase, test.TestCase):
def prepare_mocks(self):
fn = self.mox.CreateMockAnything()
self.mox.StubOutWithMock(imagebackend.lockutils.synchronized,
self.mox.StubOutWithMock(imagebackend.utils.synchronized,
'__call__')
self.mox.StubOutWithMock(imagebackend.libvirt_utils, 'copy_image')
self.mox.StubOutWithMock(imagebackend.disk, 'extend')
@@ -230,7 +230,7 @@ class Qcow2TestCase(_ImageTestCase, test.TestCase):
def prepare_mocks(self):
fn = self.mox.CreateMockAnything()
self.mox.StubOutWithMock(imagebackend.lockutils.synchronized,
self.mox.StubOutWithMock(imagebackend.utils.synchronized,
'__call__')
self.mox.StubOutWithMock(imagebackend.libvirt_utils,
'create_cow_image')

View File

@@ -59,10 +59,10 @@ import sqlalchemy.exc
from nova.db.sqlalchemy import api as db
import nova.db.sqlalchemy.migrate_repo
from nova.db.sqlalchemy import utils as db_utils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
from nova import test
from nova import utils
import nova.virt.baremetal.db.sqlalchemy.migrate_repo
@@ -246,7 +246,7 @@ class BaseMigrationTestCase(test.TestCase):
self.assertEqual(0, status,
"Failed to run: %s\n%s" % (cmd, output))
@lockutils.synchronized('pgadmin', 'nova-', external=True)
@utils.synchronized('pgadmin', external=True)
def _reset_pg(self, conn_pieces):
(user, password, database, host) = \
get_pgsql_connection_info(conn_pieces)

View File

@@ -44,6 +44,7 @@ from oslo.config import cfg
from nova import exception
from nova.openstack.common import excutils
from nova.openstack.common import importutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import processutils
from nova.openstack.common.rpc import common as rpc_common
@@ -97,6 +98,8 @@ BYTE_MULTIPLIERS = {
'k': 1024,
}
synchronized = lockutils.synchronized_with_prefix('nova-')
def vpn_ping(address, port, timeout=0.05, session_id=None):
"""Sends a vpn negotiation packet and returns the server session.

View File

@@ -24,8 +24,8 @@ from nova import context
from nova import network
from nova.network import linux_net
from nova.openstack.common import importutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova import utils
from nova.virt import netutils
LOG = logging.getLogger(__name__)
@@ -453,7 +453,7 @@ class IptablesFirewallDriver(FirewallDriver):
self.do_refresh_instance_rules(instance)
self.iptables.apply()
@lockutils.synchronized('iptables', 'nova-', external=True)
@utils.synchronized('iptables', external=True)
def _inner_do_refresh_rules(self, instance, ipv4_rules,
ipv6_rules):
self.remove_filters_for_instance(instance)
@@ -476,7 +476,7 @@ class IptablesFirewallDriver(FirewallDriver):
self._do_refresh_provider_fw_rules()
self.iptables.apply()
@lockutils.synchronized('iptables', 'nova-', external=True)
@utils.synchronized('iptables', external=True)
def _do_refresh_provider_fw_rules(self):
"""Internal, synchronized version of refresh_provider_fw_rules."""
self._purge_provider_fw_rules()

View File

@@ -19,15 +19,16 @@ Image caching and management.
"""
import os
from oslo.config import cfg
from nova.compute import flavors
from nova.openstack.common import excutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova import utils
from nova.virt.hyperv import pathutils
from nova.virt.hyperv import vhdutils
from nova.virt.hyperv import vmutils
from nova.virt import images
from oslo.config import cfg
LOG = logging.getLogger(__name__)
@@ -76,7 +77,7 @@ class ImageCache(object):
root_vhd_size_gb,
path_parts[1])
@lockutils.synchronized(resized_vhd_path, 'nova-')
@utils.synchronized(resized_vhd_path)
def copy_and_resize_vhd():
if not self._pathutils.exists(resized_vhd_path):
try:
@@ -101,7 +102,7 @@ class ImageCache(object):
base_vhd_dir = self._pathutils.get_base_vhd_dir()
vhd_path = os.path.join(base_vhd_dir, image_id + ".vhd")
@lockutils.synchronized(vhd_path, 'nova-')
@utils.synchronized(vhd_path)
def fetch_image_if_not_existing():
if not self._pathutils.exists(vhd_path):
try:

View File

@@ -24,7 +24,6 @@ from oslo.config import cfg
from nova import exception
from nova.openstack.common import excutils
from nova.openstack.common import fileutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova import utils
from nova.virt.disk import api as disk
@@ -139,8 +138,7 @@ class Image(object):
:filename: Name of the file in the image directory
:size: Size of created image in bytes (optional)
"""
@lockutils.synchronized(filename, 'nova-', external=True,
lock_path=self.lock_path)
@utils.synchronized(filename, external=True, lock_path=self.lock_path)
def call_if_not_exists(target, *args, **kwargs):
if not os.path.exists(target):
fetch_func(target=target, *args, **kwargs)
@@ -204,8 +202,7 @@ class Raw(Image):
self.driver_format = data.file_format or 'raw'
def create_image(self, prepare_template, base, size, *args, **kwargs):
@lockutils.synchronized(base, 'nova-', external=True,
lock_path=self.lock_path)
@utils.synchronized(base, external=True, lock_path=self.lock_path)
def copy_raw_image(base, target, size):
libvirt_utils.copy_image(base, target)
if size:
@@ -244,8 +241,7 @@ class Qcow2(Image):
self.preallocate = CONF.preallocate_images != 'none'
def create_image(self, prepare_template, base, size, *args, **kwargs):
@lockutils.synchronized(base, 'nova-', external=True,
lock_path=self.lock_path)
@utils.synchronized(base, external=True, lock_path=self.lock_path)
def copy_qcow2_image(base, target, size):
# TODO(pbrady): Consider copying the cow image here
# with preallocation=metadata set for performance reasons.
@@ -317,8 +313,7 @@ class Lvm(Image):
return False
def create_image(self, prepare_template, base, size, *args, **kwargs):
@lockutils.synchronized(base, 'nova-', external=True,
lock_path=self.lock_path)
@utils.synchronized(base, external=True, lock_path=self.lock_path)
def create_lvm_image(base, size):
base_size = disk.get_disk_size(base)
resize = size > base_size

View File

@@ -34,7 +34,6 @@ from nova.compute import task_states
from nova.compute import vm_states
from nova.openstack.common import fileutils
from nova.openstack.common import jsonutils
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova import utils
from nova.virt.libvirt import utils as virtutils
@@ -174,8 +173,7 @@ def read_stored_info(target, field=None, timestamped=False):
lock_name = 'info-%s' % os.path.split(target)[-1]
lock_path = os.path.join(CONF.instances_path, 'locks')
@lockutils.synchronized(lock_name, 'nova-', external=True,
lock_path=lock_path)
@utils.synchronized(lock_name, external=True, lock_path=lock_path)
def read_file(info_file):
LOG.debug(_('Reading image info file: %s'), info_file)
with open(info_file, 'r') as f:
@@ -205,8 +203,7 @@ def write_stored_info(target, field=None, value=None):
lock_name = 'info-%s' % os.path.split(target)[-1]
lock_path = os.path.join(CONF.instances_path, 'locks')
@lockutils.synchronized(lock_name, 'nova-', external=True,
lock_path=lock_path)
@utils.synchronized(lock_name, external=True, lock_path=lock_path)
def write_file(info_file, field, value):
d = {}
@@ -399,8 +396,7 @@ class ImageCacheManager(object):
# Protect against other nova-computes performing checksums at the same
# time if we are using shared storage
@lockutils.synchronized(lock_name, 'nova-', external=True,
lock_path=self.lock_path)
@utils.synchronized(lock_name, external=True, lock_path=self.lock_path)
def inner_verify_checksum():
(stored_checksum, stored_timestamp) = read_stored_checksum(
base_file, timestamped=True)

View File

@@ -27,7 +27,6 @@ import urlparse
from oslo.config import cfg
from nova import exception
from nova.openstack.common import lockutils
from nova.openstack.common import log as logging
from nova.openstack.common import loopingcall
from nova.openstack.common import processutils
@@ -192,7 +191,7 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
def _get_target_portals_from_iscsiadm_output(self, output):
return [line.split()[0] for line in output.splitlines()]
@lockutils.synchronized('connect_volume', 'nova-')
@utils.synchronized('connect_volume')
def connect_volume(self, connection_info, disk_info):
"""Attach the volume to instance_name."""
conf = super(LibvirtISCSIVolumeDriver,
@@ -266,7 +265,7 @@ class LibvirtISCSIVolumeDriver(LibvirtBaseVolumeDriver):
conf.source_path = host_device
return conf
@lockutils.synchronized('connect_volume', 'nova-')
@utils.synchronized('connect_volume')
def disconnect_volume(self, connection_info, disk_dev):
"""Detach the volume from instance_name."""
super(LibvirtISCSIVolumeDriver,
@@ -654,7 +653,7 @@ class LibvirtFibreChannelVolumeDriver(LibvirtBaseVolumeDriver):
return pci_num
@lockutils.synchronized('connect_volume', 'nova-')
@utils.synchronized('connect_volume')
def connect_volume(self, connection_info, disk_info):
"""Attach the volume to instance_name."""
fc_properties = connection_info['data']
@@ -750,7 +749,7 @@ class LibvirtFibreChannelVolumeDriver(LibvirtBaseVolumeDriver):
conf.source_path = device_path
return conf
@lockutils.synchronized('connect_volume', 'nova-')
@utils.synchronized('connect_volume')
def disconnect_volume(self, connection_info, mount_device):
"""Detach the volume from instance_name."""
super(LibvirtFibreChannelVolumeDriver,

View File

@@ -19,13 +19,13 @@ import json
import os
import time
from nova.openstack.common import lockutils
from nova import utils
TWENTY_FOUR_HOURS = 3600 * 24
@lockutils.synchronized('storage-registry-lock', 'nova-', external=True)
@utils.synchronized('storage-registry-lock', external=True)
def register_storage_use(storage_path, hostname):
"""Idenfity the id of this instance storage."""
@@ -45,7 +45,7 @@ def register_storage_use(storage_path, hostname):
f.write(json.dumps(d))
@lockutils.synchronized('storage-registry-lock', 'nova-', external=True)
@utils.synchronized('storage-registry-lock', external=True)
def get_storage_users(storage_path):
"""Get a list of all the users of this storage path."""