Whamcloud - gitweb
b=3031
[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 Lustre, http://www.lustre.org/
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #define DEBUG_SUBSYSTEM S_CLASS
24 #ifdef __KERNEL__
25 # include <linux/types.h>
26 # include <linux/random.h>
27 #else 
28 # include <liblustre.h>
29 #endif 
30
31 #include <linux/obd_support.h>
32 #include <linux/lustre_handles.h>
33
34 static spinlock_t handle_lock = SPIN_LOCK_UNLOCKED;
35 static __u64 handle_base;
36 #define HANDLE_INCR 7
37 static struct list_head *handle_hash = NULL;
38 static int handle_count = 0;
39
40 #define HANDLE_HASH_SIZE (1 << 14)
41 #define HANDLE_HASH_MASK (HANDLE_HASH_SIZE - 1)
42
43 void class_handle_hash(struct portals_handle *h, portals_handle_addref_cb cb)
44 {
45         struct list_head *bucket;
46         ENTRY;
47
48         LASSERT(h != NULL);
49         LASSERT(list_empty(&h->h_link));
50
51         spin_lock(&handle_lock);
52         h->h_cookie = handle_base;
53         handle_base += HANDLE_INCR;
54         spin_unlock(&handle_lock);
55
56         h->h_addref = cb;
57         bucket = handle_hash + (h->h_cookie & HANDLE_HASH_MASK);
58         CDEBUG(D_INFO, "adding object %p with handle "LPX64" to hash\n",
59                h, h->h_cookie);
60
61         spin_lock(&handle_lock);
62         list_add(&h->h_link, bucket);
63         handle_count++;
64         spin_unlock(&handle_lock);
65         EXIT;
66 }
67
68 static void class_handle_unhash_nolock(struct portals_handle *h)
69 {
70         if (list_empty(&h->h_link)) {
71                 CERROR("removing an already-removed handle ("LPX64")\n",
72                        h->h_cookie);
73                 return;
74         }
75
76         CDEBUG(D_INFO, "removing object %p with handle "LPX64" from hash\n",
77                h, h->h_cookie);
78
79         handle_count--;
80         list_del_init(&h->h_link);
81 }
82
83 void class_handle_unhash(struct portals_handle *h)
84 {
85         spin_lock(&handle_lock);
86         class_handle_unhash_nolock(h);
87         spin_unlock(&handle_lock);
88 }
89
90 void *class_handle2object(__u64 cookie)
91 {
92         struct list_head *bucket, *tmp;
93         void *retval = NULL;
94         ENTRY;
95
96         LASSERT(handle_hash != NULL);
97
98         bucket = handle_hash + (cookie & HANDLE_HASH_MASK);
99
100         spin_lock(&handle_lock);
101         list_for_each(tmp, bucket) {
102                 struct portals_handle *h;
103                 h = list_entry(tmp, struct portals_handle, h_link);
104
105                 if (h->h_cookie == cookie) {
106                         h->h_addref(h);
107                         retval = h;
108                         break;
109                 }
110         }
111         spin_unlock(&handle_lock);
112
113         RETURN(retval);
114 }
115
116 int class_handle_init(void)
117 {
118         struct list_head *bucket;
119
120         LASSERT(handle_hash == NULL);
121
122         OBD_VMALLOC(handle_hash, sizeof(*handle_hash) * HANDLE_HASH_SIZE);
123         if (handle_hash == NULL)
124                 return -ENOMEM;
125
126         for (bucket = handle_hash + HANDLE_HASH_SIZE - 1; bucket >= handle_hash;
127              bucket--)
128                 INIT_LIST_HEAD(bucket);
129
130         get_random_bytes(&handle_base, sizeof(handle_base));
131         LASSERT(handle_base != 0ULL);
132
133         return 0;
134 }
135
136 static void cleanup_all_handles(void)
137 {
138         int i;
139
140         spin_lock(&handle_lock);
141         for (i = 0; i < HANDLE_HASH_SIZE; i++) {
142                 struct list_head *tmp, *pos;
143                 list_for_each_safe(tmp, pos, &(handle_hash[i])) {
144                         struct portals_handle *h;
145                         h = list_entry(tmp, struct portals_handle, h_link);
146
147                         CERROR("force clean handle "LPX64" addr %p addref %p\n",
148                                h->h_cookie, h, h->h_addref);
149
150                         class_handle_unhash_nolock(h);
151                 }
152         }
153         spin_unlock(&handle_lock);
154 }
155
156 void class_handle_cleanup(void)
157 {
158         LASSERT(handle_hash != NULL);
159
160         if (handle_count != 0) {
161                 CERROR("handle_count at cleanup: %d\n", handle_count);
162                 cleanup_all_handles();
163         }
164
165         OBD_VFREE(handle_hash, sizeof(*handle_hash) * HANDLE_HASH_SIZE);
166         handle_hash = NULL;
167
168         if (handle_count)
169                 CERROR("leaked %d handles\n", handle_count);
170 }