afs_int32 SDISK_Abort(struct rx_call *rxcall, struct ubik_tid *atid) { afs_int32 code; if ((code = ubik_CheckAuth(rxcall))) { return code; } DBHOLD(ubik_dbase); if (!ubik_currentTrans) { code = USYNC; goto done; } /* sanity check to make sure only write trans appear here */ if (ubik_currentTrans->type != UBIK_WRITETRANS) { code = UBADTYPE; goto done; } urecovery_CheckTid(atid, 0); if (!ubik_currentTrans) { code = USYNC; goto done; } code = udisk_abort(ubik_currentTrans); /* If the thread is not waiting for lock - ok to end it */ if (ubik_currentTrans->locktype != LOCKWAIT) { udisk_end(ubik_currentTrans); } ubik_currentTrans = (struct ubik_trans *)0; done: DBRELE(ubik_dbase); return code; }
/* apos and alen are not used */ afs_int32 SDISK_Lock(struct rx_call *rxcall, struct ubik_tid *atid, afs_int32 index, afs_int32 afile, afs_int32 apos, afs_int32 alen, afs_int32 atype) { afs_int32 code; struct ubik_dbase *dbase; struct ubik_trans *ubik_thisTrans; if ((code = ubik_CheckAuth(rxcall))) { return code; } if (!ubik_currentTrans[index]) { return USYNC; } if (!ubik_dbase[index]) { return ENOENT; } /* sanity check to make sure only write trans appear here */ if (ubik_currentTrans[index]->type != UBIK_WRITETRANS) { return UBADTYPE; } if (alen != 1) { return UBADLOCK; } dbase = ubik_currentTrans[index]->dbase; DBHOLD(dbase); urecovery_CheckTid(atid, index); if (!ubik_currentTrans[index]) { DBRELE(dbase); return USYNC; } ubik_thisTrans = ubik_currentTrans[index]; code = ulock_getLock(ubik_currentTrans[index], atype, 1); /* While waiting, the transaction may have been ended/ * aborted from under us (urecovery_CheckTid). In that * case, end the transaction here. */ if (!code && (ubik_currentTrans[index] != ubik_thisTrans)) { udisk_end(ubik_thisTrans); code = USYNC; } DBRELE(dbase); return code; }
/*! * \brief this routine aborts the current remote transaction, if any, if the tid is wrong */ int urecovery_CheckTid(struct ubik_tid *atid, int abortalways) { if (ubik_currentTrans) { /* there is remote write trans, see if we match, see if this * is a new transaction */ if (atid->epoch != ubik_currentTrans->tid.epoch || atid->counter > ubik_currentTrans->tid.counter || abortalways) { /* don't match, abort it */ /* If the thread is not waiting for lock - ok to end it */ if (ubik_currentTrans->locktype != LOCKWAIT) { udisk_end(ubik_currentTrans); } ubik_currentTrans = (struct ubik_trans *)0; } } return 0; }
afs_int32 SDISK_Abort(struct rx_call *rxcall, struct ubik_tid *atid, afs_int32 index) { afs_int32 code; struct ubik_dbase *dbase; if ((code = ubik_CheckAuth(rxcall))) { return code; } if (!ubik_currentTrans[index]) { return USYNC; } /* sanity check to make sure only write trans appear here */ if (ubik_currentTrans[index]->type != UBIK_WRITETRANS) { return UBADTYPE; } if (!ubik_dbase[index]) { return ENOENT; } dbase = ubik_currentTrans[index]->dbase; DBHOLD(dbase); urecovery_CheckTid(atid, index); if (!ubik_currentTrans[index]) { DBRELE(dbase); return USYNC; } code = udisk_abort(ubik_currentTrans[index]); /* If the thread is not waiting for lock - ok to end it */ #if !defined(UBIK_PAUSE) if (ubik_currentTrans[index]->locktype != LOCKWAIT) { #endif /* UBIK_PAUSE */ udisk_end(ubik_currentTrans[index]); #if !defined(UBIK_PAUSE) } #endif /* UBIK_PAUSE */ ubik_currentTrans[index] = (struct ubik_trans *)0; DBRELE(dbase); return code; }
/*! * \brief this routine aborts the current remote transaction, if any, if the tid is wrong */ int urecovery_CheckTid(register struct ubik_tid *atid) { if (ubik_currentTrans) { /* there is remote write trans, see if we match, see if this * is a new transaction */ if (atid->epoch != ubik_currentTrans->tid.epoch || atid->counter > ubik_currentTrans->tid.counter) { /* don't match, abort it */ /* If the thread is not waiting for lock - ok to end it */ #if !defined(UBIK_PAUSE) if (ubik_currentTrans->locktype != LOCKWAIT) { #endif /* UBIK_PAUSE */ udisk_end(ubik_currentTrans); #if !defined(UBIK_PAUSE) } #endif /* UBIK_PAUSE */ ubik_currentTrans = (struct ubik_trans *)0; } } return 0; }
/* the rest of these guys handle remote execution of write * transactions: this is the code executed on the other servers when a * sync site is executing a write transaction. */ afs_int32 SDISK_Begin(struct rx_call *rxcall, struct ubik_tid *atid, afs_int32 index) { afs_int32 code; if ((code = ubik_CheckAuth(rxcall))) { return code; } if (!ubik_dbase[index]) { return ENOENT; } DBHOLD(ubik_dbase[index]); if (urecovery_AllBetter(ubik_dbase[index], 0) == 0) { code = UNOQUORUM; goto out; } urecovery_CheckTid(atid, index); if (ubik_currentTrans[index]) { /* If the thread is not waiting for lock - ok to end it */ #if !defined(UBIK_PAUSE) if (ubik_currentTrans[index]->locktype != LOCKWAIT) { #endif /* UBIK_PAUSE */ udisk_end(ubik_currentTrans[index]); #if !defined(UBIK_PAUSE) } #endif /* UBIK_PAUSE */ ubik_currentTrans[index] = (struct ubik_trans *)0; } code = udisk_begin(ubik_dbase[index], UBIK_WRITETRANS, &ubik_currentTrans[index]); if (!code && ubik_currentTrans[index]) { /* label this trans with the right trans id */ ubik_currentTrans[index]->tid.epoch = atid->epoch; ubik_currentTrans[index]->tid.counter = atid->counter; } out: DBRELE(ubik_dbase[index]); return code; }
/*! * \brief Set a transaction lock. * \param atype is #LOCKREAD or #LOCKWRITE. * \param await is TRUE if you want to wait for the lock instead of returning * #EWOULDBLOCK. * * \note The #DBHOLD lock must be held. */ extern int ulock_getLock(struct ubik_trans *atrans, int atype, int await) { struct ubik_dbase *dbase = atrans->dbase; /* On first pass, initialize the lock */ if (rwlockinit) { Lock_Init(&rwlock); rwlockinit = 0; } if ((atype != LOCKREAD) && (atype != LOCKWRITE)) return EINVAL; if (atrans->flags & TRDONE) return UDONE; if (atype != LOCKREAD && (atrans->flags & TRREADWRITE)) { return EINVAL; } if (atrans->locktype != 0) { ubik_print("Ubik: Internal Error: attempted to take lock twice\n"); abort(); } /* *ubik_print("Ubik: DEBUG: Thread 0x%x request %s lock\n", lwp_cpptr, * ((atype == LOCKREAD) ? "READ" : "WRITE")); */ /* Check if the lock would would block */ if (!await && !(atrans->flags & TRREADWRITE)) { if (atype == LOCKREAD) { if (WouldReadBlock(&rwlock)) return EAGAIN; } else { if (WouldWriteBlock(&rwlock)) return EAGAIN; } } /* Create new lock record and add to spec'd transaction: * #if defined(UBIK_PAUSE) * * locktype. Before doing that, set TRSETLOCK, * * to tell udisk_end that another thread (us) is waiting. * #else * * locktype. This field also tells us if the thread is * * waiting for a lock: It will be equal to LOCKWAIT. * #endif */ #if defined(UBIK_PAUSE) if (atrans->flags & TRSETLOCK) { printf("Ubik: Internal Error: TRSETLOCK already set?\n"); return EBUSY; } atrans->flags |= TRSETLOCK; #else atrans->locktype = LOCKWAIT; #endif /* UBIK_PAUSE */ DBRELE(dbase); if (atrans->flags & TRREADWRITE) { /* noop; don't actually lock anything for TRREADWRITE */ } else if (atype == LOCKREAD) { ObtainReadLock(&rwlock); } else { ObtainWriteLock(&rwlock); } DBHOLD(dbase); atrans->locktype = atype; #if defined(UBIK_PAUSE) atrans->flags &= ~TRSETLOCK; #if 0 /* We don't do this here, because this can only happen in SDISK_Lock, * and there's already code there to catch this condition. */ if (atrans->flags & TRSTALE) { udisk_end(atrans); return UINTERNAL; } #endif #endif /* UBIK_PAUSE */ /* *ubik_print("Ubik: DEBUG: Thread 0x%x took %s lock\n", lwp_cpptr, * ((atype == LOCKREAD) ? "READ" : "WRITE")); */ return 0; }