dcache-fix-alen-miscalculation-bug-20020805
[openafs.git] / src / afs / lock.h
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 #ifndef __AFSLOCK_INCLUDE__
11 #define __AFSLOCK_INCLUDE__         1
12
13 /*
14  * (C) COPYRIGHT IBM CORPORATION 1987
15  * LICENSED MATERIALS - PROPERTY OF IBM
16  */
17
18 /* The following macros allow multi statement macros to be defined safely, i.e.
19    - the multi statement macro can be the object of an if statement;
20    - the call to the multi statement macro may be legally followed by a semi-colon.
21    BEGINMAC and ENDMAC have been tested with both the portable C compiler and
22    Hi-C.  Both compilers were from the Palo Alto 4.2BSD software releases, and
23    both optimized out the constant loop code.  For an example of the use
24    of BEGINMAC and ENDMAC, see the definition for ReleaseWriteLock, below.
25    An alternative to this, using "if(1)" for BEGINMAC is not used because it
26    may generate worse code with pcc, and may generate warning messages with hi-C.
27 */
28
29 #if     (defined(AFS_SUN5_ENV)) || defined(AFS_OSF_ENV)
30 #define AFS_NOBOZO_LOCK
31 #endif
32
33 #if !defined(AFS_OSF20_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_OSF32_ENV)
34     /* We do not instrument locks on osf20 because the vcache structure
35     ** exceeds the maximim possible limit for a vnode.
36     */
37 #define INSTRUMENT_LOCKS
38 /* This is the max lock number in use. Please update it if you add any new
39  * lock numbers.
40  */
41 #define MAX_LOCK_NUMBER 700
42 #endif 
43
44 struct afs_bozoLock {
45     short count;    /* count of excl locks */
46     char flags;     /* bit 1: is anyone waiting? */
47     char spare;     /* for later */
48     char *proc;     /* process holding the lock, really a struct proc * */
49 };
50 #ifndef AFS_NOBOZO_LOCK
51 typedef struct afs_bozoLock afs_bozoLock_t;
52 #else
53 #ifdef  AFS_SUN5_ENV
54 typedef kmutex_t afs_bozoLock_t;
55 #else
56 typedef struct afs_bozoLock afs_bozoLock_t;
57 #endif
58 #define afs_BozonLock(lock, avc)
59 #define afs_BozonUnlock(lock, avc)
60 #define afs_BozonInit(lock, nm)
61 #define afs_CheckBozonLock(lock)                0
62 #define afs_CheckBozonLockBlocking(lock)        0
63 #endif
64
65 #define AFS_BOZONWAITING    1       /* someone is waiting for this lock */
66
67 #undef MObtainWriteLock         /* Defined also in ../rx/rx_machdep.h" */
68 #undef MReleaseWriteLock
69 #ifndef RXObtainWriteLock
70 #define RXObtainWriteLock(lock) ObtainWriteLock(lock)
71 #define RXReleaseWriteLock(lock) ReleaseWriteLock(lock)
72 #endif
73 #define MObtainReadLock(lock)   ObtainReadLock(lock)
74 #define MObtainWriteLock(lock,src)      ObtainWriteLock(lock,src)
75 #define MObtainSharedLock(lock,src)     ObtainSharedLock(lock,src)
76 #define MUpgradeSToWLock(lock,src)      UpgradeSToWLock(lock,src)
77 #define MConvertWToSLock(lock)  ConvertWToSLock(lock)
78 #define MReleaseReadLock(lock)  ReleaseReadLock(lock)
79 #define MReleaseWriteLock(lock) ReleaseWriteLock(lock)
80 #define MReleaseSharedLock(lock) ReleaseSharedLock(lock)
81
82 #define RWLOCK_INIT(lock, nm)   Lock_Init(lock)
83 #undef  LOCK_INIT
84 #define LOCK_INIT(lock, nm)     Lock_Init(lock)
85
86 #define BEGINMAC do {
87 #define ENDMAC   } while (0)
88
89 #if defined(AFS_SUN5_ENV) || defined(AFS_OBSD_ENV)
90 #define MyPidxx (curproc->p_pid)
91 #else
92 #if defined(AFS_AIX41_ENV)
93 extern tid_t thread_self();
94 #define MyPidxx thread_self()
95 #else /* AFS_AIX41_ENV */
96 #if defined(AFS_HPUX101_ENV)
97 #define MyPidxx ((int)p_pid(u.u_procp))
98 #else
99 #if defined(AFS_SGI64_ENV)
100 #if defined(AFS_SGI65_ENV)
101 #define MyPidxx proc_pid(curproc())
102 #else
103 #define MyPidxx current_pid()
104 #endif
105 #else /* AFS_SGI64_ENV */
106 #ifdef AFS_LINUX20_ENV
107 #define MyPidxx current->pid
108 #else
109 #if defined(AFS_DARWIN_ENV)
110 #define MyPidxx (current_proc()->p_pid )
111 #else
112 #if defined(AFS_FBSD_ENV)
113 #define MyPidxx (curproc->p_pid )
114 #else
115 #define MyPidxx (u.u_procp->p_pid )
116 #endif /* AFS_FBSD_ENV */
117 #endif /* AFS_DARWIN_ENV */
118 #endif /* AFS_LINUX20_ENV */
119 #endif /* AFS_SGI64_ENV */
120 #endif /* AFS_HPUX101_ENV */
121 #endif /* AFS_AIX41_ENV */
122 #endif 
123
124 /* all locks wait on excl_locked except for READ_LOCK, which waits on readers_reading */
125 struct afs_lock {
126     unsigned char       wait_states;    /* type of lockers waiting */
127     unsigned char       excl_locked;    /* anyone have boosted, shared or write lock? */
128     unsigned short      readers_reading;/* # readers actually with read locks */
129     unsigned short      num_waiting;    /* probably need this soon */
130     unsigned short      spare;          /* not used now */
131     osi_timeval_t       time_waiting;   /* for statistics gathering */
132 #if defined(INSTRUMENT_LOCKS)
133     /* the following are useful for debugging 
134     ** the field 'src_indicator' is updated only by ObtainLock() and
135     ** only for writes/shared  locks. Hence, it indictes where in the
136     ** source code the shared/write lock was set.
137     */
138     unsigned int        pid_last_reader;/* proceess id of last reader */
139     unsigned int        pid_writer;     /* process id of writer, else 0 */
140     unsigned int        src_indicator;  /* third param to ObtainLock()*/
141 #endif /* INSTRUMENT_LOCKS */
142 };
143 typedef struct afs_lock afs_lock_t;
144 typedef struct afs_lock afs_rwlock_t;
145
146 #define READ_LOCK       1
147 #define WRITE_LOCK      2
148 #define SHARED_LOCK     4
149 /* this next is not a flag, but rather a parameter to Afs_Lock_Obtain */
150 #define BOOSTED_LOCK 6
151
152 /* next defines wait_states for which we wait on excl_locked */
153 #define EXCL_LOCKS (WRITE_LOCK|SHARED_LOCK)
154
155 #ifdef KERNEL
156 #include "icl.h"
157
158 extern int afs_trclock;
159
160 #define AFS_LOCK_TRACE_ENABLE 0
161 #if AFS_LOCK_TRACE_ENABLE
162 #define AFS_LOCK_TRACE(op, lock, type) \
163         if (afs_trclock) Afs_Lock_Trace(op, lock, type, __FILE__, __LINE__);
164 #else
165 #define AFS_LOCK_TRACE(op, lock, type)
166 #endif
167
168 #if defined(INSTRUMENT_LOCKS)
169
170 #define ObtainReadLock(lock)\
171   BEGINMAC  \
172         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\
173         if (!((lock)->excl_locked & WRITE_LOCK)) \
174             ((lock)->readers_reading)++; \
175         else \
176             Afs_Lock_Obtain(lock, READ_LOCK); \
177         (lock)->pid_last_reader = MyPidxx; \
178    ENDMAC
179
180 #define ObtainWriteLock(lock, src)\
181   BEGINMAC  \
182         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\
183         if (!(lock)->excl_locked && !(lock)->readers_reading)\
184             (lock) -> excl_locked = WRITE_LOCK;\
185         else\
186             Afs_Lock_Obtain(lock, WRITE_LOCK); \
187         (lock)->pid_writer = MyPidxx; \
188         (lock)->src_indicator = src;\
189    ENDMAC
190
191 #define NBObtainWriteLock(lock, src) (((lock)->excl_locked || (lock)->readers_reading) ? EWOULDBLOCK : (((lock) -> excl_locked = WRITE_LOCK), ((lock)->pid_writer = MyPidxx), ((lock)->src_indicator = src), 0))
192
193 #define ObtainSharedLock(lock, src)\
194   BEGINMAC  \
195         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\
196         if (!(lock)->excl_locked)\
197             (lock) -> excl_locked = SHARED_LOCK;\
198         else\
199             Afs_Lock_Obtain(lock, SHARED_LOCK); \
200         (lock)->pid_writer = MyPidxx; \
201         (lock)->src_indicator = src;\
202    ENDMAC
203
204 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), ((lock)->pid_writer = MyPidxx), ((lock)->src_indicator = src), 0))
205
206 #define UpgradeSToWLock(lock, src)\
207   BEGINMAC  \
208         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\
209         if (!(lock)->readers_reading)\
210             (lock)->excl_locked = WRITE_LOCK;\
211         else\
212             Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
213         (lock)->pid_writer = MyPidxx; \
214         (lock)->src_indicator = src;\
215    ENDMAC
216
217 /* this must only be called with a WRITE or boosted SHARED lock! */
218 #define ConvertWToSLock(lock)\
219         BEGINMAC\
220         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\
221             (lock)->excl_locked = SHARED_LOCK; \
222             if((lock)->wait_states) \
223                 Afs_Lock_ReleaseR(lock); \
224         ENDMAC
225
226 #define ConvertWToRLock(lock) \
227         BEGINMAC\
228         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
229             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
230             ((lock)->readers_reading)++;\
231             (lock)->pid_last_reader = MyPidxx ; \
232             (lock)->pid_writer = 0;\
233             Afs_Lock_ReleaseR(lock);\
234         ENDMAC
235
236 #define ConvertSToRLock(lock) \
237         BEGINMAC\
238         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
239             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
240             ((lock)->readers_reading)++;\
241             (lock)->pid_last_reader = MyPidxx ; \
242             (lock)->pid_writer = 0;\
243             Afs_Lock_ReleaseR(lock);\
244         ENDMAC
245
246 #define ReleaseReadLock(lock)\
247         BEGINMAC\
248         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\
249             if (!(--((lock)->readers_reading)) && (lock)->wait_states)\
250                 Afs_Lock_ReleaseW(lock) ; \
251         if ( (lock)->pid_last_reader == MyPidxx ) \
252                 (lock)->pid_last_reader =0;\
253         ENDMAC
254
255 #define ReleaseWriteLock(lock)\
256         BEGINMAC\
257         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\
258             (lock)->excl_locked &= ~WRITE_LOCK;\
259             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
260             (lock)->pid_writer=0; \
261         ENDMAC
262
263 /* can be used on shared or boosted (write) locks */
264 #define ReleaseSharedLock(lock)\
265         BEGINMAC\
266         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\
267             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
268             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
269             (lock)->pid_writer=0; \
270         ENDMAC
271
272 #else /* INSTRUMENT_LOCKS */
273
274 #define ObtainReadLock(lock)\
275   BEGINMAC  \
276         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\
277         if (!((lock)->excl_locked & WRITE_LOCK)) \
278             ((lock)->readers_reading)++; \
279         else \
280             Afs_Lock_Obtain(lock, READ_LOCK); \
281    ENDMAC
282
283 #define ObtainWriteLock(lock, src)\
284   BEGINMAC  \
285         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\
286         if (!(lock)->excl_locked && !(lock)->readers_reading)\
287             (lock) -> excl_locked = WRITE_LOCK;\
288         else\
289             Afs_Lock_Obtain(lock, WRITE_LOCK); \
290    ENDMAC
291
292 #define NBObtainWriteLock(lock, src) (((lock)->excl_locked || (lock)->readers_reading) ? EWOULDBLOCK : (((lock) -> excl_locked = WRITE_LOCK),  0))
293
294 #define ObtainSharedLock(lock, src)\
295   BEGINMAC  \
296         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\
297         if (!(lock)->excl_locked)\
298             (lock) -> excl_locked = SHARED_LOCK;\
299         else\
300             Afs_Lock_Obtain(lock, SHARED_LOCK); \
301    ENDMAC
302
303 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), 0))
304    
305 #define UpgradeSToWLock(lock, src)\
306   BEGINMAC  \
307         AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\
308         if (!(lock)->readers_reading)\
309             (lock)->excl_locked = WRITE_LOCK;\
310         else\
311             Afs_Lock_Obtain(lock, BOOSTED_LOCK); \
312    ENDMAC
313
314 /* this must only be called with a WRITE or boosted SHARED lock! */
315 #define ConvertWToSLock(lock)\
316         BEGINMAC\
317         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\
318             (lock)->excl_locked = SHARED_LOCK; \
319             if((lock)->wait_states) \
320                 Afs_Lock_ReleaseR(lock); \
321         ENDMAC
322
323 #define ConvertWToRLock(lock) \
324         BEGINMAC\
325         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
326             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
327             ((lock)->readers_reading)++;\
328             Afs_Lock_ReleaseR(lock);\
329         ENDMAC
330
331 #define ConvertSToRLock(lock) \
332         BEGINMAC\
333         AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\
334             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
335             ((lock)->readers_reading)++;\
336             Afs_Lock_ReleaseR(lock);\
337         ENDMAC
338
339 #define ReleaseReadLock(lock)\
340         BEGINMAC\
341         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\
342             if (!(--((lock)->readers_reading)) && (lock)->wait_states)\
343                 Afs_Lock_ReleaseW(lock) ; \
344         ENDMAC
345
346 #define ReleaseWriteLock(lock)\
347         BEGINMAC\
348         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\
349             (lock)->excl_locked &= ~WRITE_LOCK;\
350             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
351         ENDMAC
352
353 /* can be used on shared or boosted (write) locks */
354 #define ReleaseSharedLock(lock)\
355         BEGINMAC\
356         AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\
357             (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\
358             if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\
359         ENDMAC
360
361 #endif /* INSTRUMENT_LOCKS */
362
363 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */
364 #define LockWaiters(lock)\
365         ((int) ((lock)->num_waiting))
366
367 #define CheckLock(lock)\
368         ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading)
369
370 #define WriteLocked(lock)\
371         ((lock)->excl_locked & WRITE_LOCK)
372 #endif
373
374 /*
375
376 You can also use the lock package for handling parent locks for independently-lockable sets of
377 small objects.  The concept here is that the parent lock is at the same level in the
378 locking hierarchy as the little locks, but certain restrictions apply.
379
380 The general usage pattern is as follows.  You have a set of entries to search.  When searching it, you
381 have a "scan" lock on the table.  If you find what you're looking for, you drop the lock down
382 to a "hold" lock, lock the entry, and release the parent lock.  If you don't find what
383 you're looking for, you create the entry, downgrade the "scan" lock to a "hold" lock,
384 lock the entry and unlock the parent.
385
386 To delete an item from the table, you initially obtain a "purge" lock on the parent.  Unlike all
387 of the other parent lock modes described herein, in order to obtain a "purge" lock mode, you
388 must have released all locks on any items in the table.  Once you have obtained the parent
389 lock in "purge" mode, you should check to see if the entry is locked.  If its not locked, you
390 are free to delete the entry, knowing that no one else can attempt to obtain a lock
391 on the entry while you have the purge lock held on the parent.  Unfortunately, if it *is* locked,
392 you can not lock it yourself and wait for the other dude to release it, since the entry's locker
393 may need to lock another entry before unlocking the entry you want (which would result in
394 deadlock).  Instead, then, you must release the parent lock, and try again "later" (see Lock_Wait
395 for assistance in waiting until later). Unfortunately, this is the best locking paradigm I've yet
396 come up with.
397
398 What are the advantages to this scheme?  First, the use of the parent lock ensures that
399 two people don't try to add the same entry at the same time or delete an entry while someone
400 else is adding it.  It also ensures that when one process is deleting an entry, no one else is
401 preparing to lock the entry.  Furthermore, when obtaining a lock on a little entry, you
402 are only holding a "hold" lock on the parent lock, so that others may come in and search
403 the table during this time.  Thus it will not hold up the system if a little entry takes
404 a great deal of time to free up.
405
406 Here's how to compute the compatibility matrix:
407
408 The invariants are:
409
410 add     no deletions, additions allowed, additions will be performed, will obtain little locks
411 hold    no deletions, additions allowed, no additions will be performed, will obtain little locks
412 purge   no deletions or additions allowed, deletions will be performed, don't obtain little locks
413
414 When we compute the locking matrix, we note that hold is compatible with hold and add.
415 Add is compatible only with hold.  purge is not compatible with anything.  This is the same
416 matrix as obtained by mapping add->S, hold->read and purge->write locks.  Thus we
417 can use the locks above to solve this problem, and we do.
418
419 */
420
421 #endif /* __AFSLOCK_INCLUDE__ */