Viewing: lock.c
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015, Intel Corporation.
*/
/* This file is part of Lustre, http://www.lustre.org/
*
* Author: liang@whamcloud.com
*/
#define DEBUG_SUBSYSTEM S_LNET
#include <linux/lnet/lib-lnet.h>
/** destroy cpu-partition lock, see libcfs_private.h for more detail */
void
cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
{
LASSERT(pcl->pcl_locks != NULL);
LASSERT(!pcl->pcl_locked);
cfs_percpt_free(pcl->pcl_locks);
LIBCFS_FREE(pcl, sizeof(*pcl));
}
EXPORT_SYMBOL(cfs_percpt_lock_free);
/**
* cfs_percpt_lock_create() - create cpu-partition lock
* @cptab: CPU Partitioning Table
* @keys: lock class key for lockdep
*
* cpu-partition lock is designed for large-scale SMP system, so we need to
* reduce cacheline conflict as possible as we can, that's the
* reason we always allocate cacheline-aligned memory block.
*
* reate cpu-partition lock, see libcfs_private.h for more detail.
*
* Return Pointer to struct cfs_percpt_lock or %NULL on error
*/
struct cfs_percpt_lock *
cfs_percpt_lock_create(struct cfs_cpt_table *cptab,
struct lock_class_key *keys)
{
struct cfs_percpt_lock *pcl;
spinlock_t *lock;
int i;
/* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
LIBCFS_ALLOC(pcl, sizeof(*pcl));
if (pcl == NULL)
return NULL;
pcl->pcl_cptab = cptab;
pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
if (pcl->pcl_locks == NULL) {
LIBCFS_FREE(pcl, sizeof(*pcl));
return NULL;
}
if (keys == NULL) {
CWARN("Cannot setup class key for percpt lock, you may see recursive locking warnings which are actually fake.\n");
}
cfs_percpt_for_each(lock, i, pcl->pcl_locks) {
spin_lock_init(lock);
if (keys != NULL)
lockdep_set_class(lock, &keys[i]);
}
return pcl;
}
EXPORT_SYMBOL(cfs_percpt_lock_create);
/**
* cfs_percpt_lock() - lock a CPU partition
* @pcl: Per-CPT lock structure
* @index: Which CPT partition to lock
* @index != CFS_PERCPT_LOCK_EX
* hold private lock indexed by @index
*
* @index == CFS_PERCPT_LOCK_EX
* exclusively lock @pcl and nobody can take private lock
*/
void
cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
__acquires(pcl->pcl_locks)
{
int ncpt = cfs_cpt_number(pcl->pcl_cptab);
int i;
LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt);
if (ncpt == 1) {
index = 0;
} else { /* serialize with exclusive lock */
while (pcl->pcl_locked)
cpu_relax();
}
if (likely(index != CFS_PERCPT_LOCK_EX)) {
spin_lock(pcl->pcl_locks[index]);
return;
}
/* exclusive lock request */
for (i = 0; i < ncpt; i++) {
spin_lock(pcl->pcl_locks[i]);
if (i == 0) {
LASSERT(!pcl->pcl_locked);
/* nobody should take private lock after this
* so I wouldn't starve for too long time
*/
pcl->pcl_locked = 1;
}
}
}
EXPORT_SYMBOL(cfs_percpt_lock);
/** unlock a CPU partition */
void
cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
__releases(pcl->pcl_locks)
{
int ncpt = cfs_cpt_number(pcl->pcl_cptab);
int i;
index = ncpt == 1 ? 0 : index;
if (likely(index != CFS_PERCPT_LOCK_EX)) {
spin_unlock(pcl->pcl_locks[index]);
return;
}
for (i = ncpt - 1; i >= 0; i--) {
if (i == 0) {
LASSERT(pcl->pcl_locked);
pcl->pcl_locked = 0;
}
spin_unlock(pcl->pcl_locks[i]);
}
}
EXPORT_SYMBOL(cfs_percpt_unlock);