OpenAFS
OpenAFS distributed network file system
|
00001 /* 00002 * Copyright 2000, International Business Machines Corporation and others. 00003 * All Rights Reserved. 00004 * 00005 * This software has been released under the terms of the IBM Public 00006 * License. For details, see the LICENSE file in the top-level source 00007 * directory or online at http://www.openafs.org/dl/license10.html 00008 */ 00009 00010 #ifndef __AFSLOCK_INCLUDE__ 00011 #define __AFSLOCK_INCLUDE__ 1 00012 00013 #if !defined(KERNEL) && !defined(KDUMP_KERNEL) 00014 #error Do not include afs/lock.h except for kernel code. 00015 #endif 00016 00017 /* 00018 * (C) COPYRIGHT IBM CORPORATION 1987 00019 * LICENSED MATERIALS - PROPERTY OF IBM 00020 */ 00021 00022 #define INSTRUMENT_LOCKS 00023 /* This is the max lock number in use. Please update it if you add any new 00024 * lock numbers. 00025 */ 00026 #define MAX_LOCK_NUMBER 780 00027 00028 #ifdef AFS_BOZONLOCK_ENV 00029 struct afs_bozoLock { 00030 short count; /* count of excl locks */ 00031 char flags; /* bit 1: is anyone waiting? */ 00032 char spare; /* for later */ 00033 char *proc; /* process holding the lock, really an afs_proc_t * */ 00034 }; 00035 typedef struct afs_bozoLock afs_bozoLock_t; 00036 00037 #define AFS_BOZONWAITING 1 /* someone is waiting for this lock */ 00038 #endif 00039 00040 #define AFS_RWLOCK_INIT(lock, nm) Lock_Init(lock) 00041 #undef LOCK_INIT 00042 #define LOCK_INIT(lock, nm) Lock_Init(lock) 00043 00044 /* The following macros allow multi statement macros to be defined safely, i.e. 00045 - the multi statement macro can be the object of an if statement; 00046 - the call to the multi statement macro may be legally followed by a semi-colon. 00047 BEGINMAC and ENDMAC have been tested with both the portable C compiler and 00048 Hi-C. Both compilers were from the Palo Alto 4.2BSD software releases, and 00049 both optimized out the constant loop code. For an example of the use 00050 of BEGINMAC and ENDMAC, see the definition for ReleaseWriteLock, below. 00051 An alternative to this, using "if(1)" for BEGINMAC is not used because it 00052 may generate worse code with pcc, and may generate warning messages with hi-C. 00053 */ 00054 00055 #define BEGINMAC do { 00056 #define ENDMAC } while (0) 00057 00058 #if defined(UKERNEL) 00059 typedef unsigned int afs_lock_tracker_t; 00060 # define MyPidxx (get_user_struct()->u_procp->p_pid ) 00061 # define MyPidxx2Pid(x) (x) 00062 #elif defined(AFS_SUN5_ENV) 00063 typedef kthread_t * afs_lock_tracker_t; 00064 # define MyPidxx (curthread) 00065 # define MyPidxx2Pid(x) (x ? ttoproc(x)->p_pid : 0) 00066 #elif defined(AFS_SUN5_ENV) || defined(AFS_OBSD_ENV) 00067 typedef unsigned int afs_lock_tracker_t; 00068 # define MyPidxx (curproc->p_pid) 00069 # define MyPidxx2Pid(x) (x) 00070 #elif defined(AFS_AIX41_ENV) 00071 typedef tid_t afs_lock_tracker_t; 00072 extern tid_t thread_self(); 00073 # define MyPidxx (thread_self()) 00074 # define MyPidxx2Pid(x) ((afs_int32)(x)) 00075 #elif defined(AFS_HPUX101_ENV) 00076 # if defined(AFS_HPUX1111_ENV) 00077 typedef struct kthread * afs_lock_tracker_t; 00078 # define MyPidxx (u.u_kthreadp) 00079 # define MyPidxx2Pid(x) (x ? kt_tid(x) : 0) 00080 # else 00081 typedef afs_proc_t * afs_lock_tracker_t; 00082 # define MyPidxx (u.u_procp) 00083 # define MyPidxx2Pid(x) (x ? (afs_int32)p_pid(x) : 0) 00084 # endif 00085 #elif defined(AFS_SGI64_ENV) 00086 # if defined(AFS_SGI65_ENV) 00087 typedef unsigned int afs_lock_tracker_t; 00088 # define MyPidxx proc_pid(curproc()) 00089 # define MyPidxx2Pid(x) (x) 00090 # else 00091 typedef unsigned int afs_lock_tracker_t; 00092 # define MyPidxx current_pid() 00093 # define MyPidxx2Pid(x) (x) 00094 # endif 00095 #elif defined(AFS_LINUX20_ENV) 00096 typedef struct task_struct * afs_lock_tracker_t; 00097 # define MyPidxx (current) 00098 # define MyPidxx2Pid(x) (x? (x)->pid : 0) 00099 #elif defined(AFS_DARWIN_ENV) 00100 # if defined(AFS_DARWIN80_ENV) 00101 typedef unsigned int afs_lock_tracker_t; 00102 # define MyPidxx (proc_selfpid()) 00103 # define MyPidxx2Pid(x) (x) 00104 # else 00105 typedef unsigned int afs_lock_tracker_t; 00106 # define MyPidxx (current_proc()->p_pid ) 00107 # define MyPidxx2Pid(x) (x) 00108 # endif 00109 #elif defined(AFS_FBSD_ENV) 00110 typedef unsigned int afs_lock_tracker_t; 00111 # define MyPidxx (curproc->p_pid ) 00112 # define MyPidxx2Pid(x) (x) 00113 #elif defined(AFS_NBSD40_ENV) 00114 typedef unsigned int afs_lock_tracker_t; 00115 #define MyPidxx osi_getpid() /* XXX could generalize this (above) */ 00116 #define MyPidxx2Pid(x) (x) 00117 #else 00118 typedef unsigned int afs_lock_tracker_t; 00119 # define MyPidxx (u.u_procp->p_pid ) 00120 # define MyPidxx2Pid(x) (x) 00121 #endif 00122 00123 /* all locks wait on excl_locked except for READ_LOCK, which waits on readers_reading */ 00124 struct afs_lock { 00125 unsigned char wait_states; /* type of lockers waiting */ 00126 unsigned char excl_locked; /* anyone have boosted, shared or write lock? */ 00127 unsigned short readers_reading; /* # readers actually with read locks */ 00128 unsigned short num_waiting; /* probably need this soon */ 00129 unsigned short spare; /* not used now */ 00130 osi_timeval_t time_waiting; /* for statistics gathering */ 00131 #if defined(INSTRUMENT_LOCKS) 00132 /* the following are useful for debugging 00133 ** the field 'src_indicator' is updated only by ObtainLock() and 00134 ** only for writes/shared locks. Hence, it indictes where in the 00135 ** source code the shared/write lock was set. 00136 */ 00137 afs_lock_tracker_t pid_last_reader; /* proceess id of last reader */ 00138 afs_lock_tracker_t pid_writer; /* process id of writer, else 0 */ 00139 unsigned int src_indicator; /* third param to ObtainLock() */ 00140 #endif /* INSTRUMENT_LOCKS */ 00141 }; 00142 typedef struct afs_lock afs_lock_t; 00143 typedef struct afs_lock afs_rwlock_t; 00144 00145 #define READ_LOCK 1 00146 #define WRITE_LOCK 2 00147 #define SHARED_LOCK 4 00148 /* this next is not a flag, but rather a parameter to Afs_Lock_Obtain */ 00149 #define BOOSTED_LOCK 6 00150 00151 /* next defines wait_states for which we wait on excl_locked */ 00152 #define EXCL_LOCKS (WRITE_LOCK|SHARED_LOCK) 00153 00154 #ifdef KERNEL 00155 #include "icl.h" 00156 00157 extern int afs_trclock; 00158 00159 #define AFS_LOCK_TRACE_ENABLE 0 00160 #if AFS_LOCK_TRACE_ENABLE 00161 #define AFS_LOCK_TRACE(op, lock, type) \ 00162 if (afs_trclock) Afs_Lock_Trace(op, lock, type, __FILE__, __LINE__); 00163 #else 00164 #define AFS_LOCK_TRACE(op, lock, type) 00165 #endif 00166 00167 #if defined(INSTRUMENT_LOCKS) 00168 00169 #define ObtainReadLock(lock)\ 00170 BEGINMAC \ 00171 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\ 00172 if (!((lock)->excl_locked & WRITE_LOCK)) \ 00173 ((lock)->readers_reading)++; \ 00174 else \ 00175 Afs_Lock_Obtain(lock, READ_LOCK); \ 00176 (lock)->pid_last_reader = MyPidxx; \ 00177 ENDMAC 00178 00179 #define NBObtainReadLock(lock) \ 00180 (((lock)->excl_locked & WRITE_LOCK) ? EWOULDBLOCK : (((lock)->readers_reading++), ((lock)->pid_last_reader = MyPidxx), 0)) 00181 00182 #define ObtainWriteLock(lock, src)\ 00183 BEGINMAC \ 00184 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\ 00185 if (!(lock)->excl_locked && !(lock)->readers_reading)\ 00186 (lock) -> excl_locked = WRITE_LOCK;\ 00187 else\ 00188 Afs_Lock_Obtain(lock, WRITE_LOCK); \ 00189 (lock)->pid_writer = MyPidxx; \ 00190 (lock)->src_indicator = src;\ 00191 ENDMAC 00192 00193 #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)) 00194 00195 #define ObtainSharedLock(lock, src)\ 00196 BEGINMAC \ 00197 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\ 00198 if (!(lock)->excl_locked)\ 00199 (lock) -> excl_locked = SHARED_LOCK;\ 00200 else\ 00201 Afs_Lock_Obtain(lock, SHARED_LOCK); \ 00202 (lock)->pid_writer = MyPidxx; \ 00203 (lock)->src_indicator = src;\ 00204 ENDMAC 00205 00206 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), ((lock)->pid_writer = MyPidxx), ((lock)->src_indicator = src), 0)) 00207 00208 #define UpgradeSToWLock(lock, src)\ 00209 BEGINMAC \ 00210 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\ 00211 if (!(lock)->readers_reading)\ 00212 (lock)->excl_locked = WRITE_LOCK;\ 00213 else\ 00214 Afs_Lock_Obtain(lock, BOOSTED_LOCK); \ 00215 (lock)->pid_writer = MyPidxx; \ 00216 (lock)->src_indicator = src;\ 00217 ENDMAC 00218 00219 /* this must only be called with a WRITE or boosted SHARED lock! */ 00220 #define ConvertWToSLock(lock)\ 00221 BEGINMAC\ 00222 AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\ 00223 (lock)->excl_locked = SHARED_LOCK; \ 00224 if((lock)->wait_states) \ 00225 Afs_Lock_ReleaseR(lock); \ 00226 ENDMAC 00227 00228 #define ConvertWToRLock(lock) \ 00229 BEGINMAC\ 00230 AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\ 00231 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\ 00232 ((lock)->readers_reading)++;\ 00233 (lock)->pid_last_reader = MyPidxx ; \ 00234 (lock)->pid_writer = 0;\ 00235 Afs_Lock_ReleaseR(lock);\ 00236 ENDMAC 00237 00238 #define ConvertSToRLock(lock) \ 00239 BEGINMAC\ 00240 AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\ 00241 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\ 00242 ((lock)->readers_reading)++;\ 00243 (lock)->pid_last_reader = MyPidxx ; \ 00244 (lock)->pid_writer = 0;\ 00245 Afs_Lock_ReleaseR(lock);\ 00246 ENDMAC 00247 00248 #define ReleaseReadLock(lock)\ 00249 BEGINMAC\ 00250 AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\ 00251 if (!(--((lock)->readers_reading)) && (lock)->wait_states)\ 00252 Afs_Lock_ReleaseW(lock) ; \ 00253 if ( (lock)->pid_last_reader == MyPidxx ) \ 00254 (lock)->pid_last_reader =0;\ 00255 ENDMAC 00256 00257 #define ReleaseWriteLock(lock)\ 00258 BEGINMAC\ 00259 AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\ 00260 (lock)->excl_locked &= ~WRITE_LOCK;\ 00261 if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\ 00262 (lock)->pid_writer=0; \ 00263 ENDMAC 00264 00265 /* can be used on shared or boosted (write) locks */ 00266 #define ReleaseSharedLock(lock)\ 00267 BEGINMAC\ 00268 AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\ 00269 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\ 00270 if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\ 00271 (lock)->pid_writer=0; \ 00272 ENDMAC 00273 00274 #else /* INSTRUMENT_LOCKS */ 00275 00276 #define ObtainReadLock(lock)\ 00277 BEGINMAC \ 00278 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, READ_LOCK);\ 00279 if (!((lock)->excl_locked & WRITE_LOCK)) \ 00280 ((lock)->readers_reading)++; \ 00281 else \ 00282 Afs_Lock_Obtain(lock, READ_LOCK); \ 00283 ENDMAC 00284 00285 #define NBObtainReadLock(lock) \ 00286 (((lock)->excl_locked & WRITE_LOCK) ? EWOULDBLOCK : (((lock)->readers_reading++), 0)) 00287 00288 #define ObtainWriteLock(lock, src)\ 00289 BEGINMAC \ 00290 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, WRITE_LOCK);\ 00291 if (!(lock)->excl_locked && !(lock)->readers_reading)\ 00292 (lock) -> excl_locked = WRITE_LOCK;\ 00293 else\ 00294 Afs_Lock_Obtain(lock, WRITE_LOCK); \ 00295 ENDMAC 00296 00297 #define NBObtainWriteLock(lock, src) (((lock)->excl_locked || (lock)->readers_reading) ? EWOULDBLOCK : (((lock) -> excl_locked = WRITE_LOCK), 0)) 00298 00299 #define ObtainSharedLock(lock, src)\ 00300 BEGINMAC \ 00301 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, SHARED_LOCK);\ 00302 if (!(lock)->excl_locked)\ 00303 (lock) -> excl_locked = SHARED_LOCK;\ 00304 else\ 00305 Afs_Lock_Obtain(lock, SHARED_LOCK); \ 00306 ENDMAC 00307 00308 #define NBObtainSharedLock(lock, src) (((lock)->excl_locked) ? EWOULDBLOCK : (((lock) -> excl_locked = SHARED_LOCK), 0)) 00309 00310 #define UpgradeSToWLock(lock, src)\ 00311 BEGINMAC \ 00312 AFS_LOCK_TRACE(CM_TRACE_LOCKOBTAIN, lock, BOOSTED_LOCK);\ 00313 if (!(lock)->readers_reading)\ 00314 (lock)->excl_locked = WRITE_LOCK;\ 00315 else\ 00316 Afs_Lock_Obtain(lock, BOOSTED_LOCK); \ 00317 ENDMAC 00318 00319 /* this must only be called with a WRITE or boosted SHARED lock! */ 00320 #define ConvertWToSLock(lock)\ 00321 BEGINMAC\ 00322 AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, SHARED_LOCK);\ 00323 (lock)->excl_locked = SHARED_LOCK; \ 00324 if((lock)->wait_states) \ 00325 Afs_Lock_ReleaseR(lock); \ 00326 ENDMAC 00327 00328 #define ConvertWToRLock(lock) \ 00329 BEGINMAC\ 00330 AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\ 00331 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\ 00332 ((lock)->readers_reading)++;\ 00333 Afs_Lock_ReleaseR(lock);\ 00334 ENDMAC 00335 00336 #define ConvertSToRLock(lock) \ 00337 BEGINMAC\ 00338 AFS_LOCK_TRACE(CM_TRACE_LOCKDOWN, lock, READ_LOCK);\ 00339 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\ 00340 ((lock)->readers_reading)++;\ 00341 Afs_Lock_ReleaseR(lock);\ 00342 ENDMAC 00343 00344 #define ReleaseReadLock(lock)\ 00345 BEGINMAC\ 00346 AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, READ_LOCK);\ 00347 if (!(--((lock)->readers_reading)) && (lock)->wait_states)\ 00348 Afs_Lock_ReleaseW(lock) ; \ 00349 ENDMAC 00350 00351 #define ReleaseWriteLock(lock)\ 00352 BEGINMAC\ 00353 AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, WRITE_LOCK);\ 00354 (lock)->excl_locked &= ~WRITE_LOCK;\ 00355 if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\ 00356 ENDMAC 00357 00358 /* can be used on shared or boosted (write) locks */ 00359 #define ReleaseSharedLock(lock)\ 00360 BEGINMAC\ 00361 AFS_LOCK_TRACE(CM_TRACE_LOCKDONE, lock, SHARED_LOCK);\ 00362 (lock)->excl_locked &= ~(SHARED_LOCK | WRITE_LOCK);\ 00363 if ((lock)->wait_states) Afs_Lock_ReleaseR(lock);\ 00364 ENDMAC 00365 00366 #endif /* INSTRUMENT_LOCKS */ 00367 00368 /* I added this next macro to make sure it is safe to nuke a lock -- Mike K. */ 00369 #define LockWaiters(lock)\ 00370 ((int) ((lock)->num_waiting)) 00371 00372 #define CheckLock(lock)\ 00373 ((lock)->excl_locked? (int) -1 : (int) (lock)->readers_reading) 00374 00375 #define WriteLocked(lock)\ 00376 ((lock)->excl_locked & WRITE_LOCK) 00377 #endif 00378 00379 /* 00380 00381 You can also use the lock package for handling parent locks for independently-lockable sets of 00382 small objects. The concept here is that the parent lock is at the same level in the 00383 locking hierarchy as the little locks, but certain restrictions apply. 00384 00385 The general usage pattern is as follows. You have a set of entries to search. When searching it, you 00386 have a "scan" lock on the table. If you find what you're looking for, you drop the lock down 00387 to a "hold" lock, lock the entry, and release the parent lock. If you don't find what 00388 you're looking for, you create the entry, downgrade the "scan" lock to a "hold" lock, 00389 lock the entry and unlock the parent. 00390 00391 To delete an item from the table, you initially obtain a "purge" lock on the parent. Unlike all 00392 of the other parent lock modes described herein, in order to obtain a "purge" lock mode, you 00393 must have released all locks on any items in the table. Once you have obtained the parent 00394 lock in "purge" mode, you should check to see if the entry is locked. If its not locked, you 00395 are free to delete the entry, knowing that no one else can attempt to obtain a lock 00396 on the entry while you have the purge lock held on the parent. Unfortunately, if it *is* locked, 00397 you can not lock it yourself and wait for the other dude to release it, since the entry's locker 00398 may need to lock another entry before unlocking the entry you want (which would result in 00399 deadlock). Instead, then, you must release the parent lock, and try again "later" (see Lock_Wait 00400 for assistance in waiting until later). Unfortunately, this is the best locking paradigm I've yet 00401 come up with. 00402 00403 What are the advantages to this scheme? First, the use of the parent lock ensures that 00404 two people don't try to add the same entry at the same time or delete an entry while someone 00405 else is adding it. It also ensures that when one process is deleting an entry, no one else is 00406 preparing to lock the entry. Furthermore, when obtaining a lock on a little entry, you 00407 are only holding a "hold" lock on the parent lock, so that others may come in and search 00408 the table during this time. Thus it will not hold up the system if a little entry takes 00409 a great deal of time to free up. 00410 00411 Here's how to compute the compatibility matrix: 00412 00413 The invariants are: 00414 00415 add no deletions, additions allowed, additions will be performed, will obtain little locks 00416 hold no deletions, additions allowed, no additions will be performed, will obtain little locks 00417 purge no deletions or additions allowed, deletions will be performed, don't obtain little locks 00418 00419 When we compute the locking matrix, we note that hold is compatible with hold and add. 00420 Add is compatible only with hold. purge is not compatible with anything. This is the same 00421 matrix as obtained by mapping add->S, hold->read and purge->write locks. Thus we 00422 can use the locks above to solve this problem, and we do. 00423 00424 */ 00425 00426 #endif /* __AFSLOCK_INCLUDE__ */