[go: nahoru, domu]

1/*
2 * GPL HEADER START
3 *
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 021110-1307, USA
20 *
21 * GPL HEADER END
22 */
23/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, Intel Corporation.
25 */
26/*
27 * This file is part of Lustre, http://www.lustre.org/
28 * Lustre is a trademark of Sun Microsystems, Inc.
29 *
30 * Author: liang@whamcloud.com
31 */
32
33#define DEBUG_SUBSYSTEM S_LNET
34
35#include "../../include/linux/libcfs/libcfs.h"
36
37
38/** destroy cpu-partition lock, see libcfs_private.h for more detail */
39void
40cfs_percpt_lock_free(struct cfs_percpt_lock *pcl)
41{
42	LASSERT(pcl->pcl_locks != NULL);
43	LASSERT(!pcl->pcl_locked);
44
45	cfs_percpt_free(pcl->pcl_locks);
46	LIBCFS_FREE(pcl, sizeof(*pcl));
47}
48EXPORT_SYMBOL(cfs_percpt_lock_free);
49
50/**
51 * create cpu-partition lock, see libcfs_private.h for more detail.
52 *
53 * cpu-partition lock is designed for large-scale SMP system, so we need to
54 * reduce cacheline conflict as possible as we can, that's the
55 * reason we always allocate cacheline-aligned memory block.
56 */
57struct cfs_percpt_lock *
58cfs_percpt_lock_alloc(struct cfs_cpt_table *cptab)
59{
60	struct cfs_percpt_lock	*pcl;
61	spinlock_t		*lock;
62	int			i;
63
64	/* NB: cptab can be NULL, pcl will be for HW CPUs on that case */
65	LIBCFS_ALLOC(pcl, sizeof(*pcl));
66	if (pcl == NULL)
67		return NULL;
68
69	pcl->pcl_cptab = cptab;
70	pcl->pcl_locks = cfs_percpt_alloc(cptab, sizeof(*lock));
71	if (pcl->pcl_locks == NULL) {
72		LIBCFS_FREE(pcl, sizeof(*pcl));
73		return NULL;
74	}
75
76	cfs_percpt_for_each(lock, i, pcl->pcl_locks)
77		spin_lock_init(lock);
78
79	return pcl;
80}
81EXPORT_SYMBOL(cfs_percpt_lock_alloc);
82
83/**
84 * lock a CPU partition
85 *
86 * \a index != CFS_PERCPT_LOCK_EX
87 *     hold private lock indexed by \a index
88 *
89 * \a index == CFS_PERCPT_LOCK_EX
90 *     exclusively lock @pcl and nobody can take private lock
91 */
92void
93cfs_percpt_lock(struct cfs_percpt_lock *pcl, int index)
94{
95	int	ncpt = cfs_cpt_number(pcl->pcl_cptab);
96	int	i;
97
98	LASSERT(index >= CFS_PERCPT_LOCK_EX && index < ncpt);
99
100	if (ncpt == 1) {
101		index = 0;
102	} else { /* serialize with exclusive lock */
103		while (pcl->pcl_locked)
104			cpu_relax();
105	}
106
107	if (likely(index != CFS_PERCPT_LOCK_EX)) {
108		spin_lock(pcl->pcl_locks[index]);
109		return;
110	}
111
112	/* exclusive lock request */
113	for (i = 0; i < ncpt; i++) {
114		spin_lock(pcl->pcl_locks[i]);
115		if (i == 0) {
116			LASSERT(!pcl->pcl_locked);
117			/* nobody should take private lock after this
118			 * so I wouldn't starve for too long time */
119			pcl->pcl_locked = 1;
120		}
121	}
122}
123EXPORT_SYMBOL(cfs_percpt_lock);
124
125/** unlock a CPU partition */
126void
127cfs_percpt_unlock(struct cfs_percpt_lock *pcl, int index)
128{
129	int	ncpt = cfs_cpt_number(pcl->pcl_cptab);
130	int	i;
131
132	index = ncpt == 1 ? 0 : index;
133
134	if (likely(index != CFS_PERCPT_LOCK_EX)) {
135		spin_unlock(pcl->pcl_locks[index]);
136		return;
137	}
138
139	for (i = ncpt - 1; i >= 0; i--) {
140		if (i == 0) {
141			LASSERT(pcl->pcl_locked);
142			pcl->pcl_locked = 0;
143		}
144		spin_unlock(pcl->pcl_locks[i]);
145	}
146}
147EXPORT_SYMBOL(cfs_percpt_unlock);
148
149
150/** free cpu-partition refcount */
151void
152cfs_percpt_atomic_free(atomic_t **refs)
153{
154	cfs_percpt_free(refs);
155}
156EXPORT_SYMBOL(cfs_percpt_atomic_free);
157
158/** allocate cpu-partition refcount with initial value @init_val */
159atomic_t **
160cfs_percpt_atomic_alloc(struct cfs_cpt_table *cptab, int init_val)
161{
162	atomic_t	**refs;
163	atomic_t	*ref;
164	int		i;
165
166	refs = cfs_percpt_alloc(cptab, sizeof(*ref));
167	if (refs == NULL)
168		return NULL;
169
170	cfs_percpt_for_each(ref, i, refs)
171		atomic_set(ref, init_val);
172	return refs;
173}
174EXPORT_SYMBOL(cfs_percpt_atomic_alloc);
175
176/** return sum of cpu-partition refs */
177int
178cfs_percpt_atomic_summary(atomic_t **refs)
179{
180	atomic_t	*ref;
181	int		i;
182	int		val = 0;
183
184	cfs_percpt_for_each(ref, i, refs)
185		val += atomic_read(ref);
186
187	return val;
188}
189EXPORT_SYMBOL(cfs_percpt_atomic_summary);
190