Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rx / rx_misc.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #ifdef KERNEL
14 # include <afs/sysincludes.h>
15 # include <afsincludes.h>
16 #else
17 # include <roken.h>
18 # include <afs/opr.h>
19
20 # include <afs/errors.h>
21 # include "xdr.h"
22 # ifdef AFS_PTHREAD_ENV
23 # include "rx.h"
24 # endif /* AFS_PTHREAD_ENV */
25 # ifdef AFS_NT40_ENV
26 # ifndef EDQUOT
27 # define EDQUOT WSAEDQUOT
28 # endif /* EDQUOT */
29 # endif /* AFS_NT40_ENV */
30 #endif
31
32 /*
33 * We currently only include below the errors that
34 * affect us the most. We should add to this list
35 * more code mappings, as necessary.
36 */
37
38 /*
39 * Convert from the local (host) to the standard
40 * (network) system error code.
41 */
42 int
43 hton_syserr_conv(afs_int32 code)
44 {
45 afs_int32 err;
46
47 if (code == ENOSPC)
48 err = VDISKFULL;
49 #ifdef EDQUOT
50 else if (code == EDQUOT)
51 err = VOVERQUOTA;
52 #endif
53 else
54 err = code;
55 return err;
56 }
57
58
59 /*
60 * Convert from the standard (Network) format to the
61 * local (host) system error code.
62 */
63 int
64 ntoh_syserr_conv(int code)
65 {
66 afs_int32 err;
67
68 if (code == VDISKFULL)
69 err = ENOSPC;
70 else if (code == VOVERQUOTA)
71 #ifndef EDQUOT
72 err = ENOSPC;
73 #else
74 err = EDQUOT;
75 #endif
76 else
77 err = code;
78 return err;
79 }
80
81
82 #ifndef KERNEL
83 /*
84 * We provide the following because some systems (like aix) would fail if we pass
85 * 0 as length.
86 */
87
88 #ifndef osi_alloc
89 static const char memZero;
90 char *
91 osi_alloc(afs_int32 x)
92 {
93 /*
94 * 0-length allocs may return NULL ptr from osi_kalloc, so we special-case
95 * things so that NULL returned iff an error occurred
96 */
97 if (x == 0)
98 return (char *)&memZero;
99 return (char *)(mem_alloc(x));
100 }
101
102 int
103 osi_free(char *x, afs_int32 size)
104 {
105 if ((x == &memZero) || !x)
106 return 0;
107 mem_free(x, size);
108 return 0;
109 }
110 #endif
111 #endif /* KERNEL */
112
113 #if defined(RX_ENABLE_LOCKS) && defined(RX_REFCOUNT_CHECK)
114 int rx_callHoldType = 0;
115 #endif
116
117
118 #ifdef RX_LOCKS_DB
119 /* What follows is a lock database for RX. There is currently room for 400
120 * locks to be held. Routines panic if there is an error. To port, add
121 * RX_LOCKS_DB versions of MUTEX_{ENTER, EXIT, TRYENTER} and CV_*WAIT to
122 * rx_kmutex.h and define lock macros below.
123 */
124 #if (defined(AFS_AIX41_ENV) || (defined(AFS_SGI53_ENV) && defined(MP))) && defined(KERNEL)
125
126 #ifdef AFS_AIX41_ENV
127 Simple_lock rxdb_lock;
128 #define RXDB_LOCK_INIT() lock_alloc(&rxdb_lock, LOCK_ALLOC_PIN, 1, 0), \
129 simple_lock_init(&rxdb_lock)
130 #define RXDB_LOCK_ENTER() simple_lock(&rxdb_lock)
131 #define RXDB_LOCK_EXIT() simple_unlock(&rxdb_lock)
132 #else /* AFS_AIX41_ENV */
133 #ifdef AFS_SGI53_ENV
134 afs_kmutex_t rxdb_lock;
135 #define RXDB_LOCK_INIT() mutex_init(&rxdb_lock, "rxdb lock", 0, 0)
136 #define RXDB_LOCK_ENTER() AFS_MUTEX_ENTER(&rxdb_lock)
137 #define RXDB_LOCK_EXIT() mutex_exit(&rxdb_lock)
138 #endif /* AFS_SGI53_ENV */
139 #endif /* AFS_AIX41_ENV */
140
141
142 int RXDB_LockPos = 0;
143
144 #define RXDB_NLOCKS 32
145 struct rxdb_lock_t {
146 afs_int32 id; /* id of lock holder. */
147 void *a; /* address of lock. */
148 u_short fileId; /* fileID# of RX file. */
149 u_short line;
150 u_short next;
151 u_short prev;
152 };
153
154 #define RXDB_HASHSIZE 8
155
156
157 struct rxdb_lock_t rxdb_lockList[RXDB_NLOCKS];
158 short rxdb_idHash[RXDB_HASHSIZE];
159 #define RXDB_IDHASH(id) ((((u_long)id)>>1) & (RXDB_HASHSIZE-1))
160
161 /* Record locations of all locks we enter/exit. */
162 struct rxdb_lockloc_t {
163 u_short fileId; /* fileID# of RX file. */
164 u_short line;
165 u_short next;
166 u_short prev;
167 };
168 #ifdef RX_LOCKS_COVERAGE
169 #define RXDB_NlockLocs 512
170 #define RXDB_LOCHASHSIZE 256
171 struct rxdb_lockloc_t rxdb_lockLocs[RXDB_NlockLocs];
172 short rxdb_lockLocHash[RXDB_LOCHASHSIZE];
173 #define RXDB_LOCHASH(a) ((((u_long)a)) & (RXDB_LOCHASHSIZE-1))
174 #endif /* RX_LOCKS_COVERAGE */
175
176 /* Element 0 of each of the above arrays serves as the pointer to the list of
177 * free elements.
178 */
179 void
180 rxdb_init(void)
181 {
182 static int initted = 0;
183 int i;
184
185 if (initted)
186 return;
187
188 initted = 1;
189
190 RXDB_LOCK_INIT();
191 RXDB_LOCK_ENTER();
192
193 for (i = 1; i < RXDB_NLOCKS - 1; i++) {
194 rxdb_lockList[i].next = i + 1;
195 rxdb_lockList[i].prev = i - 1;
196 }
197 rxdb_lockList[0].next = 1;
198 rxdb_lockList[0].prev = 0;
199 rxdb_lockList[RXDB_NLOCKS - 1].next = 0;
200 rxdb_lockList[RXDB_NLOCKS - 1].prev = RXDB_NLOCKS - 2;
201
202 #ifdef RX_LOCKS_COVERAGE
203 for (i = 1; i < RXDB_NlockLocs - 1; i++) {
204 rxdb_lockLocs[i].next = i + 1;
205 rxdb_lockLocs[i].prev = i - 1;
206 }
207 rxdb_lockLocs[0].next = 1;
208 rxdb_lockLocs[0].prev = 0;
209 rxdb_lockLocs[RXDB_NlockLocs - 1].next = 0;
210 rxdb_lockLocs[RXDB_NlockLocs - 1].prev = RXDB_NlockLocs - 2;
211 #endif /* RX_LOCKS_COVERAGE */
212
213 RXDB_LOCK_EXIT();
214 }
215
216 #ifdef RX_LOCKS_COVERAGE
217 void
218 rxdb_RecordLockLocation(fileId, line)
219 afs_int32 fileId, line;
220 {
221 u_short i, j;
222
223 i = RXDB_LOCHASH(line);
224
225 /* Only enter lock location into list once. */
226 for (j = rxdb_lockLocHash[i]; j; j = rxdb_lockLocs[j].next) {
227 if ((rxdb_lockLocs[j].line == line)
228 && (rxdb_lockLocs[j].fileId == fileId))
229 return;
230 }
231
232 /* Add lock to list. */
233 j = rxdb_lockLocs[0].next;
234 if (j == 0) {
235 osi_Panic("rxdb_initLock: used up all the lock locations.\n");
236 }
237
238 /* Fix up free list. */
239 rxdb_lockLocs[0].next = rxdb_lockLocs[j].next;
240
241 /* Put new element at head of list. */
242 rxdb_lockLocs[j].next = rxdb_lockLocHash[i];
243 rxdb_lockLocs[j].prev = 0;
244 if (rxdb_lockLocHash[i]) {
245 rxdb_lockLocs[rxdb_lockLocHash[i]].prev = j;
246 }
247 rxdb_lockLocHash[i] = j;
248
249 /* Set data in element. */
250 rxdb_lockLocs[j].fileId = fileId;
251 rxdb_lockLocs[j].line = line;
252
253 }
254 #endif /* RX_LOCKS_COVERAGE */
255
256
257 /* Set lock as possessed by me. */
258 void
259 rxdb_grablock(a, id, fileId, line)
260 void *a;
261 afs_int32 id;
262 afs_int32 fileId;
263 afs_int32 line;
264 {
265 int i, j, k;
266
267 RXDB_LOCK_ENTER();
268 #ifdef RX_LOCKS_COVERAGE
269 rxdb_RecordLockLocation(fileId, line);
270 #endif /* RX_LOCKS_COVERAGE */
271 /* Is lock already held by anyone? */
272 for (i = 0; i < RXDB_HASHSIZE; i++) {
273 for (j = rxdb_idHash[i]; j; j = rxdb_lockList[j].next) {
274 if (rxdb_lockList[j].a == a) {
275 RXDB_LockPos = j;
276 osi_Panic("rxdb_grablock: lock already held.");
277 }
278 }
279 }
280
281 i = RXDB_IDHASH(id);
282 j = rxdb_lockList[0].next;
283 if (j == 0) {
284 osi_Panic("rxdb_grablock: rxdb_lockList is full.");
285 }
286 rxdb_lockList[0].next = rxdb_lockList[j].next;
287
288 /* Put element at head of list. */
289 rxdb_lockList[j].next = rxdb_idHash[i];
290 rxdb_lockList[j].prev = 0;
291 if (rxdb_idHash[i]) {
292 rxdb_lockList[rxdb_idHash[i]].prev = j;
293 }
294 rxdb_idHash[i] = j;
295
296 /* Set data into element. */
297 rxdb_lockList[j].a = a;
298 rxdb_lockList[j].id = id;
299 rxdb_lockList[j].fileId = fileId;
300 rxdb_lockList[j].line = line;
301
302 RXDB_LOCK_EXIT();
303 }
304
305 /* unlock */
306 rxdb_droplock(a, id, fileId, line)
307 void *a;
308 afs_int32 id;
309 int fileId;
310 int line;
311 {
312 int i, j;
313 int found;
314
315 RXDB_LOCK_ENTER();
316 #ifdef RX_LOCKS_COVERAGE
317 rxdb_RecordLockLocation(fileId, line);
318 #endif /* RX_LOCKS_COVERAGE */
319 found = 0;
320
321 /* Do I have the lock? */
322 i = rxdb_idHash[RXDB_IDHASH(id)];
323 for (j = i; j; j = rxdb_lockList[j].next) {
324 if (rxdb_lockList[j].a == a) {
325 found = 1;
326 break;
327 }
328 }
329
330 if (!found) {
331 osi_Panic("rxdb_unlock: lock not held by me.\n");
332 }
333
334 /* delete lock from queue. */
335 if (i == j) {
336 /* head of list. */
337 i = RXDB_IDHASH(id);
338 rxdb_idHash[i] = rxdb_lockList[j].next;
339 rxdb_lockList[rxdb_lockList[j].next].prev = 0;
340 } else {
341 if (rxdb_lockList[j].next)
342 rxdb_lockList[rxdb_lockList[j].next].prev = rxdb_lockList[j].prev;
343 rxdb_lockList[rxdb_lockList[j].prev].next = rxdb_lockList[j].next;
344 }
345 /* Put back on free list. */
346 rxdb_lockList[j].next = rxdb_lockList[0].next;
347 rxdb_lockList[j].prev = 0;
348 rxdb_lockList[0].next = j;
349
350 RXDB_LOCK_EXIT();
351 }
352
353 #endif /* (AIX41 || SGI53) && KERNEL */
354
355 #endif /* RX_LOCKS_DB */