4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2011, 2012, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/obdclass/lustre_handles.c
38 * Author: Phil Schwan <phil@clusterfs.com>
41 #define DEBUG_SUBSYSTEM S_CLASS
43 #include <obd_support.h>
44 #include <lustre_handles.h>
45 #include <lustre_lib.h>
48 static __u64 handle_base
;
50 static spinlock_t handle_base_lock
;
52 static struct handle_bucket
{
54 struct list_head head
;
57 #define HANDLE_HASH_SIZE (1 << 16)
58 #define HANDLE_HASH_MASK (HANDLE_HASH_SIZE - 1)
61 * Generate a unique 64bit cookie (hash) for a handle and insert it into
62 * global (per-node) hash-table.
64 void class_handle_hash(struct portals_handle
*h
,
65 struct portals_handle_ops
*ops
)
67 struct handle_bucket
*bucket
;
71 LASSERT(list_empty(&h
->h_link
));
74 * This is fast, but simplistic cookie generation algorithm, it will
75 * need a re-do at some point in the future for security.
77 spin_lock(&handle_base_lock
);
78 handle_base
+= HANDLE_INCR
;
80 if (unlikely(handle_base
== 0)) {
82 * Cookie of zero is "dangerous", because in many places it's
83 * assumed that 0 means "unassigned" handle, not bound to any
86 CWARN("The universe has been exhausted: cookie wrap-around.\n");
87 handle_base
+= HANDLE_INCR
;
89 h
->h_cookie
= handle_base
;
90 spin_unlock(&handle_base_lock
);
93 spin_lock_init(&h
->h_lock
);
95 bucket
= &handle_hash
[h
->h_cookie
& HANDLE_HASH_MASK
];
96 spin_lock(&bucket
->lock
);
97 list_add_rcu(&h
->h_link
, &bucket
->head
);
99 spin_unlock(&bucket
->lock
);
101 CDEBUG(D_INFO
, "added object %p with handle "LPX64
" to hash\n",
105 EXPORT_SYMBOL(class_handle_hash
);
107 static void class_handle_unhash_nolock(struct portals_handle
*h
)
109 if (list_empty(&h
->h_link
)) {
110 CERROR("removing an already-removed handle ("LPX64
")\n",
115 CDEBUG(D_INFO
, "removing object %p with handle "LPX64
" from hash\n",
118 spin_lock(&h
->h_lock
);
120 spin_unlock(&h
->h_lock
);
124 spin_unlock(&h
->h_lock
);
125 list_del_rcu(&h
->h_link
);
128 void class_handle_unhash(struct portals_handle
*h
)
130 struct handle_bucket
*bucket
;
131 bucket
= handle_hash
+ (h
->h_cookie
& HANDLE_HASH_MASK
);
133 spin_lock(&bucket
->lock
);
134 class_handle_unhash_nolock(h
);
135 spin_unlock(&bucket
->lock
);
137 EXPORT_SYMBOL(class_handle_unhash
);
139 void class_handle_hash_back(struct portals_handle
*h
)
141 struct handle_bucket
*bucket
;
144 bucket
= handle_hash
+ (h
->h_cookie
& HANDLE_HASH_MASK
);
146 spin_lock(&bucket
->lock
);
147 list_add_rcu(&h
->h_link
, &bucket
->head
);
149 spin_unlock(&bucket
->lock
);
153 EXPORT_SYMBOL(class_handle_hash_back
);
155 void *class_handle2object(__u64 cookie
)
157 struct handle_bucket
*bucket
;
158 struct portals_handle
*h
;
162 LASSERT(handle_hash
!= NULL
);
164 /* Be careful when you want to change this code. See the
165 * rcu_read_lock() definition on top this file. - jxiong */
166 bucket
= handle_hash
+ (cookie
& HANDLE_HASH_MASK
);
169 list_for_each_entry_rcu(h
, &bucket
->head
, h_link
) {
170 if (h
->h_cookie
!= cookie
)
173 spin_lock(&h
->h_lock
);
174 if (likely(h
->h_in
!= 0)) {
175 h
->h_ops
->hop_addref(h
);
178 spin_unlock(&h
->h_lock
);
185 EXPORT_SYMBOL(class_handle2object
);
187 void class_handle_free_cb(cfs_rcu_head_t
*rcu
)
189 struct portals_handle
*h
= RCU2HANDLE(rcu
);
190 void *ptr
= (void *)(unsigned long)h
->h_cookie
;
192 if (h
->h_ops
->hop_free
!= NULL
)
193 h
->h_ops
->hop_free(ptr
, h
->h_size
);
195 OBD_FREE(ptr
, h
->h_size
);
197 EXPORT_SYMBOL(class_handle_free_cb
);
199 int class_handle_init(void)
201 struct handle_bucket
*bucket
;
205 LASSERT(handle_hash
== NULL
);
207 OBD_ALLOC_LARGE(handle_hash
, sizeof(*bucket
) * HANDLE_HASH_SIZE
);
208 if (handle_hash
== NULL
)
211 spin_lock_init(&handle_base_lock
);
212 for (bucket
= handle_hash
+ HANDLE_HASH_SIZE
- 1; bucket
>= handle_hash
;
214 INIT_LIST_HEAD(&bucket
->head
);
215 spin_lock_init(&bucket
->lock
);
218 /** bug 21430: add randomness to the initial base */
219 cfs_get_random_bytes(seed
, sizeof(seed
));
220 do_gettimeofday(&tv
);
221 cfs_srand(tv
.tv_sec
^ seed
[0], tv
.tv_usec
^ seed
[1]);
223 cfs_get_random_bytes(&handle_base
, sizeof(handle_base
));
224 LASSERT(handle_base
!= 0ULL);
229 static int cleanup_all_handles(void)
234 for (rc
= i
= 0; i
< HANDLE_HASH_SIZE
; i
++) {
235 struct portals_handle
*h
;
237 spin_lock(&handle_hash
[i
].lock
);
238 list_for_each_entry_rcu(h
, &(handle_hash
[i
].head
), h_link
) {
239 CERROR("force clean handle "LPX64
" addr %p ops %p\n",
240 h
->h_cookie
, h
, h
->h_ops
);
242 class_handle_unhash_nolock(h
);
245 spin_unlock(&handle_hash
[i
].lock
);
251 void class_handle_cleanup(void)
254 LASSERT(handle_hash
!= NULL
);
256 count
= cleanup_all_handles();
258 OBD_FREE_LARGE(handle_hash
, sizeof(*handle_hash
) * HANDLE_HASH_SIZE
);
262 CERROR("handle_count at cleanup: %d\n", count
);