/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include #include #ifdef KERNEL #include #include #else #ifdef AFS_NT40_ENV #include #include #else #include #endif #include #include #include "xdr.h" #ifdef AFS_PTHREAD_ENV #include "rx.h" #endif /* AFS_PTHREAD_ENV */ #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef AFS_NT40_ENV #ifndef EDQUOT #define EDQUOT WSAEDQUOT #endif /* EDQUOT */ #endif /* AFS_NT40_ENV */ #endif /* * We currently only include below the errors that * affect us the most. We should add to this list * more code mappings, as necessary. */ /* * Convert from the local (host) to the standard * (network) system error code. */ int hton_syserr_conv(afs_int32 code) { afs_int32 err; if (code == ENOSPC) err = VDISKFULL; #ifdef EDQUOT else if (code == EDQUOT) err = VOVERQUOTA; #endif else err = code; return err; } /* * Convert from the standard (Network) format to the * local (host) system error code. */ int ntoh_syserr_conv(int code) { afs_int32 err; if (code == VDISKFULL) err = ENOSPC; else if (code == VOVERQUOTA) #ifndef EDQUOT err = ENOSPC; #else err = EDQUOT; #endif else err = code; return err; } #ifndef KERNEL /* * We provide the following because some systems (like aix) would fail if we pass * 0 as length. */ #ifndef osi_alloc #ifdef AFS_PTHREAD_ENV /* * This mutex protects the following global variables: * osi_alloccnt * osi_allocsize */ #include afs_kmutex_t osi_malloc_mutex; #define LOCK_MALLOC_STATS MUTEX_ENTER(&osi_malloc_mutex); #define UNLOCK_MALLOC_STATS MUTEX_EXIT(&osi_malloc_mutex); #else #define LOCK_MALLOC_STATS #define UNLOCK_MALLOC_STATS #endif /* AFS_PTHREAD_ENV */ long osi_alloccnt = 0, osi_allocsize = 0; static const char memZero; char * osi_alloc(afs_int32 x) { /* * 0-length allocs may return NULL ptr from osi_kalloc, so we special-case * things so that NULL returned iff an error occurred */ if (x == 0) return (char *)&memZero; LOCK_MALLOC_STATS; osi_alloccnt++; osi_allocsize += x; UNLOCK_MALLOC_STATS; return (char *)(mem_alloc(x)); } int osi_free(char *x, afs_int32 size) { if ((x == &memZero) || !x) return 0; LOCK_MALLOC_STATS; osi_alloccnt--; osi_allocsize -= size; UNLOCK_MALLOC_STATS; mem_free(x, size); return 0; } #endif #endif /* KERNEL */ #if defined(RX_ENABLE_LOCKS) && defined(RX_REFCOUNT_CHECK) int rx_callHoldType = 0; #endif #ifdef RX_LOCKS_DB /* What follows is a lock database for RX. There is currently room for 400 * locks to be held. Routines panic if there is an error. To port, add * RX_LOCKS_DB versions of MUTEX_{ENTER, EXIT, TRYENTER} and CV_*WAIT to * rx_kmutex.h and define lock macros below. */ #if (defined(AFS_AIX41_ENV) || (defined(AFS_SGI53_ENV) && defined(MP))) && defined(KERNEL) #ifdef AFS_AIX41_ENV Simple_lock rxdb_lock; #define RXDB_LOCK_INIT() lock_alloc(&rxdb_lock, LOCK_ALLOC_PIN, 1, 0), \ simple_lock_init(&rxdb_lock) #define RXDB_LOCK_ENTER() simple_lock(&rxdb_lock) #define RXDB_LOCK_EXIT() simple_unlock(&rxdb_lock) #else /* AFS_AIX41_ENV */ #ifdef AFS_SGI53_ENV afs_kmutex_t rxdb_lock; #define RXDB_LOCK_INIT() mutex_init(&rxdb_lock, "rxdb lock", 0, 0) #define RXDB_LOCK_ENTER() AFS_MUTEX_ENTER(&rxdb_lock) #define RXDB_LOCK_EXIT() mutex_exit(&rxdb_lock) #endif /* AFS_SGI53_ENV */ #endif /* AFS_AIX41_ENV */ int RXDB_LockPos = 0; #define RXDB_NLOCKS 32 struct rxdb_lock_t { afs_int32 id; /* id of lock holder. */ void *a; /* address of lock. */ u_short fileId; /* fileID# of RX file. */ u_short line; u_short next; u_short prev; }; #define RXDB_HASHSIZE 8 struct rxdb_lock_t rxdb_lockList[RXDB_NLOCKS]; short rxdb_idHash[RXDB_HASHSIZE]; #define RXDB_IDHASH(id) ((((u_long)id)>>1) & (RXDB_HASHSIZE-1)) /* Record locations of all locks we enter/exit. */ struct rxdb_lockloc_t { u_short fileId; /* fileID# of RX file. */ u_short line; u_short next; u_short prev; }; #ifdef RX_LOCKS_COVERAGE #define RXDB_NlockLocs 512 #define RXDB_LOCHASHSIZE 256 struct rxdb_lockloc_t rxdb_lockLocs[RXDB_NlockLocs]; short rxdb_lockLocHash[RXDB_LOCHASHSIZE]; #define RXDB_LOCHASH(a) ((((u_long)a)) & (RXDB_LOCHASHSIZE-1)) #endif /* RX_LOCKS_COVERAGE */ /* Element 0 of each of the above arrays serves as the pointer to the list of * free elements. */ void rxdb_init(void) { static int initted = 0; int i; if (initted) return; initted = 1; RXDB_LOCK_INIT(); RXDB_LOCK_ENTER(); for (i = 1; i < RXDB_NLOCKS - 1; i++) { rxdb_lockList[i].next = i + 1; rxdb_lockList[i].prev = i - 1; } rxdb_lockList[0].next = 1; rxdb_lockList[0].prev = 0; rxdb_lockList[RXDB_NLOCKS - 1].next = 0; rxdb_lockList[RXDB_NLOCKS - 1].prev = RXDB_NLOCKS - 2; #ifdef RX_LOCKS_COVERAGE for (i = 1; i < RXDB_NlockLocs - 1; i++) { rxdb_lockLocs[i].next = i + 1; rxdb_lockLocs[i].prev = i - 1; } rxdb_lockLocs[0].next = 1; rxdb_lockLocs[0].prev = 0; rxdb_lockLocs[RXDB_NlockLocs - 1].next = 0; rxdb_lockLocs[RXDB_NlockLocs - 1].prev = RXDB_NlockLocs - 2; #endif /* RX_LOCKS_COVERAGE */ RXDB_LOCK_EXIT(); } #ifdef RX_LOCKS_COVERAGE void rxdb_RecordLockLocation(fileId, line) afs_int32 fileId, line; { u_short i, j; i = RXDB_LOCHASH(line); /* Only enter lock location into list once. */ for (j = rxdb_lockLocHash[i]; j; j = rxdb_lockLocs[j].next) { if ((rxdb_lockLocs[j].line == line) && (rxdb_lockLocs[j].fileId == fileId)) return; } /* Add lock to list. */ j = rxdb_lockLocs[0].next; if (j == 0) { osi_Panic("rxdb_initLock: used up all the lock locations.\n"); } /* Fix up free list. */ rxdb_lockLocs[0].next = rxdb_lockLocs[j].next; /* Put new element at head of list. */ rxdb_lockLocs[j].next = rxdb_lockLocHash[i]; rxdb_lockLocs[j].prev = 0; if (rxdb_lockLocHash[i]) { rxdb_lockLocs[rxdb_lockLocHash[i]].prev = j; } rxdb_lockLocHash[i] = j; /* Set data in element. */ rxdb_lockLocs[j].fileId = fileId; rxdb_lockLocs[j].line = line; } #endif /* RX_LOCKS_COVERAGE */ /* Set lock as possessed by me. */ void rxdb_grablock(a, id, fileId, line) void *a; afs_int32 id; afs_int32 fileId; afs_int32 line; { int i, j, k; RXDB_LOCK_ENTER(); #ifdef RX_LOCKS_COVERAGE rxdb_RecordLockLocation(fileId, line); #endif /* RX_LOCKS_COVERAGE */ /* Is lock already held by anyone? */ for (i = 0; i < RXDB_HASHSIZE; i++) { for (j = rxdb_idHash[i]; j; j = rxdb_lockList[j].next) { if (rxdb_lockList[j].a == a) { RXDB_LockPos = j; osi_Panic("rxdb_grablock: lock already held."); } } } i = RXDB_IDHASH(id); j = rxdb_lockList[0].next; if (j == 0) { osi_Panic("rxdb_grablock: rxdb_lockList is full."); } rxdb_lockList[0].next = rxdb_lockList[j].next; /* Put element at head of list. */ rxdb_lockList[j].next = rxdb_idHash[i]; rxdb_lockList[j].prev = 0; if (rxdb_idHash[i]) { rxdb_lockList[rxdb_idHash[i]].prev = j; } rxdb_idHash[i] = j; /* Set data into element. */ rxdb_lockList[j].a = a; rxdb_lockList[j].id = id; rxdb_lockList[j].fileId = fileId; rxdb_lockList[j].line = line; RXDB_LOCK_EXIT(); } /* unlock */ rxdb_droplock(a, id, fileId, line) void *a; afs_int32 id; int fileId; int line; { int i, j; int found; RXDB_LOCK_ENTER(); #ifdef RX_LOCKS_COVERAGE rxdb_RecordLockLocation(fileId, line); #endif /* RX_LOCKS_COVERAGE */ found = 0; /* Do I have the lock? */ i = rxdb_idHash[RXDB_IDHASH(id)]; for (j = i; j; j = rxdb_lockList[j].next) { if (rxdb_lockList[j].a == a) { found = 1; break; } } if (!found) { osi_Panic("rxdb_unlock: lock not held by me.\n"); } /* delete lock from queue. */ if (i == j) { /* head of list. */ i = RXDB_IDHASH(id); rxdb_idHash[i] = rxdb_lockList[j].next; rxdb_lockList[rxdb_lockList[j].next].prev = 0; } else { if (rxdb_lockList[j].next) rxdb_lockList[rxdb_lockList[j].next].prev = rxdb_lockList[j].prev; rxdb_lockList[rxdb_lockList[j].prev].next = rxdb_lockList[j].next; } /* Put back on free list. */ rxdb_lockList[j].next = rxdb_lockList[0].next; rxdb_lockList[j].prev = 0; rxdb_lockList[0].next = j; RXDB_LOCK_EXIT(); } #endif /* (AIX41 || SGI53) && KERNEL */ #endif /* RX_LOCKS_DB */