/* * 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 */ /* * Module: Voltrans.c * System: Volser * Instituition: ITC, CMU * Date: December, 88 */ #include #include #ifdef AFS_NT40_ENV #include #else #include #endif #include #include #include #include #ifdef AFS_NT40_ENV #include #include #else #include #include #include #endif #include #include #include #include #ifdef AFS_PTHREAD_ENV #include #else /* AFS_PTHREAD_ENV */ #include #endif /* AFS_PTHREAD_ENV */ #include #include #include #include #include #include #include #include #include #ifdef AFS_NT40_ENV #include #endif #include #include #include "volint.h" #include "volser.h" #include "volser_internal.h" static struct volser_trans *allTrans = 0; static afs_int32 transCounter = 1; /* create a new transaction, returning ptr to same with high ref count */ struct volser_trans * NewTrans(afs_uint32 avol, afs_int32 apart) { /* set volid, next, partition */ struct volser_trans *tt, *newtt; struct timeval tp; struct timezone tzp; newtt = (struct volser_trans *)malloc(sizeof(struct volser_trans)); VTRANS_LOCK; /* don't allow the same volume to be attached twice */ for (tt = allTrans; tt; tt = tt->next) { if ((tt->volid == avol) && (tt->partition == apart)) { VTRANS_UNLOCK; free(newtt); return (struct volser_trans *)0; /* volume busy */ } } tt = newtt; memset(tt, 0, sizeof(struct volser_trans)); tt->volid = avol; tt->partition = apart; tt->refCount = 1; tt->rxCallPtr = (struct rx_call *)0; strcpy(tt->lastProcName, ""); gettimeofday(&tp, &tzp); tt->creationTime = tp.tv_sec; tt->time = FT_ApproxTime(); tt->tid = transCounter++; tt->next = allTrans; VTRANS_OBJ_LOCK_INIT(tt); allTrans = tt; VTRANS_UNLOCK; return tt; } /* find a trans, again returning with high ref count */ struct volser_trans * FindTrans(register afs_int32 atrans) { register struct volser_trans *tt; VTRANS_LOCK; for (tt = allTrans; tt; tt = tt->next) { if (tt->tid == atrans) { tt->time = FT_ApproxTime(); tt->refCount++; VTRANS_UNLOCK; return tt; } } VTRANS_UNLOCK; return (struct volser_trans *)0; } /* delete transaction if refcount == 1, otherwise queue delete for later. Does implicit TRELE */ afs_int32 DeleteTrans(register struct volser_trans *atrans, afs_int32 lock) { register struct volser_trans *tt, **lt; Error error; if (lock) VTRANS_LOCK; if (atrans->refCount > 1) { /* someone else is using it now */ atrans->refCount--; atrans->tflags |= TTDeleted; if (lock) VTRANS_UNLOCK; return 0; } /* otherwise we zap it ourselves */ lt = &allTrans; for (tt = *lt; tt; lt = &tt->next, tt = *lt) { if (tt == atrans) { if (tt->volume) VDetachVolume(&error, tt->volume); tt->volume = NULL; if (tt->rxCallPtr) rxi_CallError(tt->rxCallPtr, RX_CALL_DEAD); *lt = tt->next; VTRANS_OBJ_LOCK_DESTROY(tt); free(tt); if (lock) VTRANS_UNLOCK; return 0; } } if (lock) VTRANS_UNLOCK; return -1; /* failed to find the transaction in the generic list */ } /* THOLD is a macro defined in volser.h */ /* put a transaction back */ afs_int32 TRELE(register struct volser_trans *at) { VTRANS_LOCK; if (at->refCount == 0) { Log("TRELE: bad refcount\n"); VTRANS_UNLOCK; return VOLSERTRELE_ERROR; } at->time = FT_ApproxTime(); /* we're still using it */ if (at->refCount == 1 && (at->tflags & TTDeleted)) { DeleteTrans(at, 0); VTRANS_UNLOCK; return 0; } /* otherwise simply drop refcount */ at->refCount--; VTRANS_UNLOCK; return 0; } /* look for old transactions and delete them */ #define OLDTRANSTIME 600 /* seconds */ #define OLDTRANSWARN 300 /* seconds */ static int GCDeletes = 0; afs_int32 GCTrans(void) { register struct volser_trans *tt, *nt; afs_int32 now; now = FT_ApproxTime(); VTRANS_LOCK; for (tt = allTrans; tt; tt = nt) { nt = tt->next; /* remember in case we zap it */ if (tt->time + OLDTRANSWARN < now) { Log("trans %u on volume %u %s than %d seconds\n", tt->tid, tt->volid, ((tt->refCount > 0) ? "is older" : "has been idle for more"), (((now - tt->time) / GCWAKEUP) * GCWAKEUP)); } if (tt->refCount > 0) continue; if (tt->time + OLDTRANSTIME < now) { Log("trans %u on volume %u has timed out\n", tt->tid, tt->volid); tt->refCount++; /* we're using it now */ DeleteTrans(tt, 0); /* drops refCount or deletes it */ GCDeletes++; } } VTRANS_UNLOCK; return 0; } /*return the head of the transaction list */ struct volser_trans * TransList(void) { return (allTrans); }