]> err.no Git - linux-2.6/blob - net/tipc/ref.c
[TIPC] License header update
[linux-2.6] / net / tipc / ref.c
1 /*
2  * net/tipc/ref.c: TIPC object registry code
3  * 
4  * Copyright (c) 2003-2005, Ericsson Research Canada
5  * Copyright (c) 2004-2005, Wind River Systems
6  * Copyright (c) 2005-2006, Ericsson AB
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the names of the copyright holders nor the names of its
18  *    contributors may be used to endorse or promote products derived from
19  *    this software without specific prior written permission.
20  *
21  * Alternatively, this software may be distributed under the terms of the
22  * GNU General Public License ("GPL") version 2 as published by the Free
23  * Software Foundation.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37
38 #include "core.h"
39 #include "ref.h"
40 #include "port.h"
41 #include "subscr.h"
42 #include "name_distr.h"
43 #include "name_table.h"
44 #include "config.h"
45 #include "discover.h"
46 #include "bearer.h"
47 #include "node.h"
48 #include "bcast.h"
49
50 /*
51  * Object reference table consists of 2**N entries.
52  *
53  * A used entry has object ptr != 0, reference == XXXX|own index
54  *                                   (XXXX changes each time entry is acquired) 
55  * A free entry has object ptr == 0, reference == YYYY|next free index
56  *                                   (YYYY is one more than last used XXXX)
57  *
58  * Free list is initially chained from entry (2**N)-1 to entry 1. 
59  * Entry 0 is not used to allow index 0 to indicate the end of the free list.
60  *
61  * Note: Any accidental reference of the form XXXX|0--0 won't match entry 0
62  * because entry 0's reference field has the form XXXX|1--1.
63  */
64
65 struct ref_table ref_table = { 0 };
66
67 rwlock_t reftbl_lock = RW_LOCK_UNLOCKED;
68
69 /**
70  * ref_table_init - create reference table for objects
71  */
72
73 int ref_table_init(u32 requested_size, u32 start)
74 {
75         struct reference *table;
76         u32 sz = 1 << 4;
77         u32 index_mask;
78         int i;
79
80         while (sz < requested_size) {
81                 sz <<= 1;
82         }
83         table = (struct reference *)vmalloc(sz * sizeof(struct reference));
84         if (table == NULL)
85                 return -ENOMEM;
86
87         write_lock_bh(&reftbl_lock);
88         index_mask = sz - 1;
89         for (i = sz - 1; i >= 0; i--) {
90                 table[i].object = 0;
91                 table[i].lock = SPIN_LOCK_UNLOCKED;
92                 table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
93         }
94         ref_table.entries = table;
95         ref_table.index_mask = index_mask;
96         ref_table.first_free = sz - 1;
97         ref_table.last_free = 1;
98         write_unlock_bh(&reftbl_lock);
99         return TIPC_OK;
100 }
101
102 /**
103  * ref_table_stop - destroy reference table for objects
104  */
105
106 void ref_table_stop(void)
107 {
108         if (!ref_table.entries)
109                 return;
110
111         vfree(ref_table.entries);
112         ref_table.entries = 0;
113 }
114
115 /**
116  * ref_acquire - create reference to an object
117  * 
118  * Return a unique reference value which can be translated back to the pointer
119  * 'object' at a later time.  Also, pass back a pointer to the lock protecting 
120  * the object, but without locking it.
121  */
122
123 u32 ref_acquire(void *object, spinlock_t **lock)
124 {
125         struct reference *entry;
126         u32 index;
127         u32 index_mask;
128         u32 next_plus_upper;
129         u32 reference = 0;
130
131         assert(ref_table.entries && object);
132
133         write_lock_bh(&reftbl_lock);
134         if (ref_table.first_free) {
135                 index = ref_table.first_free;
136                 entry = &(ref_table.entries[index]);
137                 index_mask = ref_table.index_mask;
138                 /* take lock in case a previous user of entry still holds it */ 
139                 spin_lock_bh(&entry->lock);  
140                 next_plus_upper = entry->data.next_plus_upper;
141                 ref_table.first_free = next_plus_upper & index_mask;
142                 reference = (next_plus_upper & ~index_mask) + index;
143                 entry->data.reference = reference;
144                 entry->object = object;
145                 if (lock != 0)
146                         *lock = &entry->lock;
147                 spin_unlock_bh(&entry->lock);
148         }
149         write_unlock_bh(&reftbl_lock);
150         return reference;
151 }
152
153 /**
154  * ref_discard - invalidate references to an object
155  * 
156  * Disallow future references to an object and free up the entry for re-use.
157  * Note: The entry's spin_lock may still be busy after discard
158  */
159
160 void ref_discard(u32 ref)
161 {
162         struct reference *entry;
163         u32 index; 
164         u32 index_mask;
165
166         assert(ref_table.entries);
167         assert(ref != 0);
168
169         write_lock_bh(&reftbl_lock);
170         index_mask = ref_table.index_mask;
171         index = ref & index_mask;
172         entry = &(ref_table.entries[index]);
173         assert(entry->object != 0);
174         assert(entry->data.reference == ref);
175
176         /* mark entry as unused */
177         entry->object = 0;
178         if (ref_table.first_free == 0)
179                 ref_table.first_free = index;
180         else
181                 /* next_plus_upper is always XXXX|0--0 for last free entry */
182                 ref_table.entries[ref_table.last_free].data.next_plus_upper 
183                         |= index;
184         ref_table.last_free = index;
185
186         /* increment upper bits of entry to invalidate subsequent references */
187         entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1);
188         write_unlock_bh(&reftbl_lock);
189 }
190