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