| /* |
| * GPL HEADER START |
| * |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 only, |
| * as published by the Free Software Foundation. |
| * |
| * 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 version 2 for more details (a copy is included |
| * in the LICENSE file that accompanied this code). |
| * |
| * GPL HEADER END |
| */ |
| /* 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/ |
| * Lustre is a trademark of Sun Microsystems, Inc. |
| * |
| * Author: liang@whamcloud.com |
| */ |
| |
| #define DEBUG_SUBSYSTEM S_LNET |
| |
| #include <linux/libcfs/libcfs.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); |
| LASSERT(!pcl->pcl_locked); |
| |
| cfs_percpt_free(pcl->pcl_locks); |
| LIBCFS_FREE(pcl, sizeof(*pcl)); |
| } |
| EXPORT_SYMBOL(cfs_percpt_lock_free); |
| |
| /** |
| * create cpu-partition lock, see libcfs_private.h for more detail. |
| * |
| * 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. |
| */ |
| 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) |
| return NULL; |
| |
| pcl->pcl_cptab = cptab; |
| pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock)); |
| if (!pcl->pcl_locks) { |
| LIBCFS_FREE(pcl, sizeof(*pcl)); |
| return NULL; |
| } |
| |
| if (!keys) |
| 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) |
| lockdep_set_class(lock, &keys[i]); |
| } |
| |
| return pcl; |
| } |
| EXPORT_SYMBOL(cfs_percpt_lock_create); |
| |
| /** |
| * lock a CPU partition |
| * |
| * \a index != CFS_PERCPT_LOCK_EX |
| * hold private lock indexed by \a index |
| * |
| * \a 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) { |
| 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) { |
| LASSERT(pcl->pcl_locked); |
| pcl->pcl_locked = 0; |
| } |
| spin_unlock(pcl->pcl_locks[i]); |
| } |
| } |
| EXPORT_SYMBOL(cfs_percpt_unlock); |