Whamcloud - gitweb
Move random uuid functions to prng.c
[fs/lustre-release.git] / lustre / obdclass / lustre_handles.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Phil Schwan <phil@clusterfs.com>
6  *
7  *   This file is part of the Lustre file system, http://www.lustre.org
8  *   Lustre is a trademark of Cluster File Systems, Inc.
9  *
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.
14  *
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.
19  *
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.
24  */
25
26 #define DEBUG_SUBSYSTEM S_CLASS
27 #ifndef __KERNEL__
28 # include <liblustre.h>
29 #endif
30
31 #include <obd_support.h>
32 #include <lustre_handles.h>
33 #include <lustre_lib.h>
34
35 spinlock_t handle_lock;
36 static __u64 handle_base;
37 #define HANDLE_INCR 7
38 static struct list_head *handle_hash = NULL;
39 static int handle_count = 0;
40
41 #define HANDLE_HASH_SIZE (1 << 14)
42 #define HANDLE_HASH_MASK (HANDLE_HASH_SIZE - 1)
43
44 /*
45  * Generate a unique 64bit cookie (hash) for a handle and insert it into
46  * global (per-node) hash-table.
47  */
48 void class_handle_hash(struct portals_handle *h, portals_handle_addref_cb cb)
49 {
50         struct list_head *bucket;
51         ENTRY;
52
53         LASSERT(h != NULL);
54         LASSERT(list_empty(&h->h_link));
55
56         spin_lock(&handle_lock);
57
58         /*
59          * This is fast, but simplistic cookie generation algorithm, it will
60          * need a re-do at some point in the future for security.
61          */
62         h->h_cookie = handle_base;
63         handle_base += HANDLE_INCR;
64
65         bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK);
66         list_add(&h->h_link, bucket);
67         handle_count++;
68
69         if (unlikely(handle_base == 0)) {
70                 /*
71                  * Cookie of zero is "dangerous", because in many places it's
72                  * assumed that 0 means "unassigned" handle, not bound to any
73                  * object.
74                  */
75                 CWARN("The universe has been exhausted: cookie wrap-around.\n");
76                 handle_base += HANDLE_INCR;
77         }
78
79         spin_unlock(&handle_lock);
80
81         h->h_addref = cb;
82         CDEBUG(D_INFO, "added object %p with handle "LPX64" to hash\n",
83                h, h->h_cookie);
84         EXIT;
85 }
86
87 static void class_handle_unhash_nolock(struct portals_handle *h)
88 {
89         if (list_empty(&h->h_link)) {
90                 CERROR("removing an already-removed handle ("LPX64")\n",
91                        h->h_cookie);
92                 return;
93         }
94
95         CDEBUG(D_INFO, "removing object %p with handle "LPX64" from hash\n",
96                h, h->h_cookie);
97
98         handle_count--;
99         list_del_init(&h->h_link);
100 }
101
102 void class_handle_unhash(struct portals_handle *h)
103 {
104         spin_lock(&handle_lock);
105         class_handle_unhash_nolock(h);
106         spin_unlock(&handle_lock);
107 }
108
109 void *class_handle2object(__u64 cookie)
110 {
111         struct list_head *bucket, *tmp;
112         void *retval = NULL;
113         ENTRY;
114
115         LASSERT(handle_hash != NULL);
116
117         bucket = handle_hash + (cookie & HANDLE_HASH_MASK);
118
119         spin_lock(&handle_lock);
120         list_for_each(tmp, bucket) {
121                 struct portals_handle *h;
122                 h = list_entry(tmp, struct portals_handle, h_link);
123
124                 if (h->h_cookie == cookie) {
125                         h->h_addref(h);
126                         retval = h;
127                         break;
128                 }
129         }
130         spin_unlock(&handle_lock);
131
132         RETURN(retval);
133 }
134
135 int class_handle_init(void)
136 {
137         struct list_head *bucket;
138
139         LASSERT(handle_hash == NULL);
140
141         OBD_VMALLOC(handle_hash, sizeof(*handle_hash) * HANDLE_HASH_SIZE);
142         if (handle_hash == NULL)
143                 return -ENOMEM;
144
145         for (bucket = handle_hash + HANDLE_HASH_SIZE - 1; bucket >= handle_hash;
146              bucket--)
147                 CFS_INIT_LIST_HEAD(bucket);
148
149         ll_get_random_bytes(&handle_base, sizeof(handle_base));
150         LASSERT(handle_base != 0ULL);
151
152         return 0;
153 }
154
155 static void cleanup_all_handles(void)
156 {
157         int i;
158
159         spin_lock(&handle_lock);
160         for (i = 0; i < HANDLE_HASH_SIZE; i++) {
161                 struct list_head *tmp, *pos;
162                 list_for_each_safe(tmp, pos, &(handle_hash[i])) {
163                         struct portals_handle *h;
164                         h = list_entry(tmp, struct portals_handle, h_link);
165
166                         CERROR("force clean handle "LPX64" addr %p addref %p\n",
167                                h->h_cookie, h, h->h_addref);
168
169                         class_handle_unhash_nolock(h);
170                 }
171         }
172         spin_unlock(&handle_lock);
173 }
174
175 void class_handle_cleanup(void)
176 {
177         LASSERT(handle_hash != NULL);
178
179         if (handle_count != 0) {
180                 CERROR("handle_count at cleanup: %d\n", handle_count);
181                 cleanup_all_handles();
182         }
183
184         OBD_VFREE(handle_hash, sizeof(*handle_hash) * HANDLE_HASH_SIZE);
185         handle_hash = NULL;
186
187         if (handle_count)
188                 CERROR("leaked %d handles\n", handle_count);
189 }