1// SPDX-License-Identifier: GPL-2.0 2/* 3 * GPL HEADER START 4 * 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 only, 9 * as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License version 2 for more details (a copy is included 15 * in the LICENSE file that accompanied this code). 16 * 17 * GPL HEADER END 18 */ 19/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 20 * Copyright (c) 2012, 2015 Intel Corporation. 21 */ 22/* 23 * This file is part of Lustre, http://www.lustre.org/ 24 * Lustre is a trademark of Sun Microsystems, Inc. 25 * 26 * Author: liang@whamcloud.com 27 */ 28 29#define DEBUG_SUBSYSTEM S_LNET 30 31#include <linux/libcfs/libcfs.h> 32 33/** destroy cpu-partition lock, see libcfs_private.h for more detail */ 34void 35cfs_percpt_lock_free(struct cfs_percpt_lock *pcl) 36{ 37 LASSERT(pcl->pcl_locks); 38 LASSERT(!pcl->pcl_locked); 39 40 cfs_percpt_free(pcl->pcl_locks); 41 kfree(pcl); 42} 43EXPORT_SYMBOL(cfs_percpt_lock_free); 44 45/** 46 * create cpu-partition lock, see libcfs_private.h for more detail. 47 * 48 * cpu-partition lock is designed for large-scale SMP system, so we need to 49 * reduce cacheline conflict as possible as we can, that's the 50 * reason we always allocate cacheline-aligned memory block. 51 */ 52struct cfs_percpt_lock * 53cfs_percpt_lock_create(struct cfs_cpt_table *cptab, 54 struct lock_class_key *keys) 55{ 56 struct cfs_percpt_lock *pcl; 57 spinlock_t *lock; 58 int i; 59 60 /* NB: cptab can be NULL, pcl will be for HW CPUs on that case */ 61 pcl = kzalloc(sizeof(*pcl), GFP_NOFS); 62 if (!pcl) 63 return NULL; 64 65 pcl->pcl_cptab = cptab; 66 pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock)); 67 if (!pcl->pcl_locks) { 68 kfree(pcl); 69 return NULL; 70 } 71 72 if (!keys) 73 CWARN("Cannot setup class key for percpt lock, you may see recursive locking warnings which are actually fake.\n"); 74 75 cfs_percpt_for_each(lock, i, pcl->pcl_locks) { 76 spin_lock_init(lock); 77 if (keys) 78 lockdep_set_class(lock, &keys[i]); 79 } 80 81 return pcl; 82} 83EXPORT_SYMBOL(cfs_percpt_lock_create); 84 85/** 86 * lock a CPU partition 87 * 88 * \a index != CFS_PERCPT_LOCK_EX 89 * hold private lock indexed by \a index 90 * 91 * \a index == CFS_PERCPT_LOCK_EX 92 * exclusively lock @pcl and nobody can take private lock 93 */ 94void 95cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index) 96 __acquires(pcl->pcl_locks) 97{ 98 int ncpt = cfs_cpt_number(pcl->pcl_cptab); 99 int i; 100 101 LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt); 102 103 if (ncpt == 1) { 104 index = 0; 105 } else { /* serialize with exclusive lock */ 106 while (pcl->pcl_locked) 107 cpu_relax(); 108 } 109 110 if (likely(index != CFS_PERCPT_LOCK_EX)) { 111 spin_lock(pcl->pcl_locks[index]); 112 return; 113 } 114 115 /* exclusive lock request */ 116 for (i = 0; i < ncpt; i++) { 117 spin_lock(pcl->pcl_locks[i]); 118 if (!i) { 119 LASSERT(!pcl->pcl_locked); 120 /* nobody should take private lock after this 121 * so I wouldn't starve for too long time 122 */ 123 pcl->pcl_locked = 1; 124 } 125 } 126} 127EXPORT_SYMBOL(cfs_percpt_lock); 128 129/** unlock a CPU partition */ 130void 131cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index) 132 __releases(pcl->pcl_locks) 133{ 134 int ncpt = cfs_cpt_number(pcl->pcl_cptab); 135 int i; 136 137 index = ncpt == 1 ? 0 : index; 138 139 if (likely(index != CFS_PERCPT_LOCK_EX)) { 140 spin_unlock(pcl->pcl_locks[index]); 141 return; 142 } 143 144 for (i = ncpt - 1; i >= 0; i--) { 145 if (!i) { 146 LASSERT(pcl->pcl_locked); 147 pcl->pcl_locked = 0; 148 } 149 spin_unlock(pcl->pcl_locks[i]); 150 } 151} 152EXPORT_SYMBOL(cfs_percpt_unlock); 153