1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002 Cluster File Systems, Inc.
5 * Author: Phil Schwan <phil@clusterfs.com>
7 * This file is part of the Lustre file system, http://www.lustre.org
8 * Lustre is a trademark of Cluster File Systems, Inc.
10 * You may have signed or agreed to another license before downloading
11 * this software. If so, you are bound by the terms and conditions
12 * of that agreement, and the following does not apply to you. See the
13 * LICENSE file included with this distribution for more information.
15 * If you did not agree to a different license, then this copy of Lustre
16 * is open source software; you can redistribute it and/or modify it
17 * under the terms of version 2 of the GNU General Public License as
18 * published by the Free Software Foundation.
20 * In either case, Lustre is distributed in the hope that it will be
21 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * license text for more details.
26 #define DEBUG_SUBSYSTEM S_CLASS
28 # include <liblustre.h>
31 #include <obd_support.h>
32 #include <lustre_handles.h>
34 spinlock_t handle_lock;
35 static __u64 handle_base;
37 static struct list_head *handle_hash = NULL;
38 static int handle_count = 0;
40 #define HANDLE_HASH_SIZE (1 << 14)
41 #define HANDLE_HASH_MASK (HANDLE_HASH_SIZE - 1)
44 * Generate a unique 64bit cookie (hash) for a handle and insert it into
45 * global (per-node) hash-table.
47 void class_handle_hash(struct portals_handle *h, portals_handle_addref_cb cb)
49 struct list_head *bucket;
53 LASSERT(list_empty(&h->h_link));
55 spin_lock(&handle_lock);
58 * This is fast, but simplistic cookie generation algorithm, it will
59 * need a re-do at some point in the future for security.
61 h->h_cookie = handle_base;
62 handle_base += HANDLE_INCR;
64 bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK);
65 list_add(&h->h_link, bucket);
68 if (unlikely(handle_base == 0)) {
70 * Cookie of zero is "dangerous", because in many places it's
71 * assumed that 0 means "unassigned" handle, not bound to any
74 CWARN("The universe has been exhausted: cookie wrap-around.\n");
75 handle_base += HANDLE_INCR;
78 spin_unlock(&handle_lock);
81 CDEBUG(D_INFO, "added object %p with handle "LPX64" to hash\n",
86 static void class_handle_unhash_nolock(struct portals_handle *h)
88 if (list_empty(&h->h_link)) {
89 CERROR("removing an already-removed handle ("LPX64")\n",
94 CDEBUG(D_INFO, "removing object %p with handle "LPX64" from hash\n",
98 list_del_init(&h->h_link);
101 void class_handle_unhash(struct portals_handle *h)
103 spin_lock(&handle_lock);
104 class_handle_unhash_nolock(h);
105 spin_unlock(&handle_lock);
108 void class_handle_hash_back(struct portals_handle *h)
110 struct list_head *bucket;
113 spin_lock(&handle_lock);
114 bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK);
115 list_add(&h->h_link, bucket);
117 spin_unlock(&handle_lock);
122 void *class_handle2object(__u64 cookie)
124 struct list_head *bucket, *tmp;
128 LASSERT(handle_hash != NULL);
130 bucket = handle_hash + (cookie & HANDLE_HASH_MASK);
132 spin_lock(&handle_lock);
133 list_for_each(tmp, bucket) {
134 struct portals_handle *h;
135 h = list_entry(tmp, struct portals_handle, h_link);
137 if (h->h_cookie == cookie) {
143 spin_unlock(&handle_lock);
148 int class_handle_init(void)
150 struct list_head *bucket;
152 LASSERT(handle_hash == NULL);
154 OBD_VMALLOC(handle_hash, sizeof(*handle_hash) * HANDLE_HASH_SIZE);
155 if (handle_hash == NULL)
158 for (bucket = handle_hash + HANDLE_HASH_SIZE - 1; bucket >= handle_hash;
160 CFS_INIT_LIST_HEAD(bucket);
162 get_random_bytes(&handle_base, sizeof(handle_base));
163 LASSERT(handle_base != 0ULL);
168 static void cleanup_all_handles(void)
172 spin_lock(&handle_lock);
173 for (i = 0; i < HANDLE_HASH_SIZE; i++) {
174 struct list_head *tmp, *pos;
175 list_for_each_safe(tmp, pos, &(handle_hash[i])) {
176 struct portals_handle *h;
177 h = list_entry(tmp, struct portals_handle, h_link);
179 CERROR("force clean handle "LPX64" addr %p addref %p\n",
180 h->h_cookie, h, h->h_addref);
182 class_handle_unhash_nolock(h);
185 spin_unlock(&handle_lock);
188 void class_handle_cleanup(void)
190 LASSERT(handle_hash != NULL);
192 if (handle_count != 0) {
193 CERROR("handle_count at cleanup: %d\n", handle_count);
194 cleanup_all_handles();
197 OBD_VFREE(handle_hash, sizeof(*handle_hash) * HANDLE_HASH_SIZE);
201 CERROR("leaked %d handles\n", handle_count);