Bugs: afs_xvcache locked before afs_xdcache in afs_remove, afs_symlink,
etc in the file afs_vnodeops.c
+5.1. unixusers. unixuser structs are locked before afs_xvcache in PSetTokens
+via afs_NotifyUser and via afs_ResetUserConns. They are also locked before
+afs_xvcache in afs_Analyze via afs_BlackListOnce.
+
6. afs_xvcache. Must be able to load new cache entries while holding
locks on others. Note this means you can't lock a cache entry while
holding either of this lock, unless, as in afs_create, the cache entry
return 0;
}
+ tu->refCount++;
+ ReleaseReadLock(&afs_xuser);
+
+ afs_LockUser(tu, READ_LOCK, 0);
+
if (tu->cell == -1) {
cellname = "<default>";
} else {
}
seq_printf(m, "\n");
+ afs_PutUser(tu, READ_LOCK);
+ ObtainReadLock(&afs_xuser);
+
return 0;
}
return 0;
}
+ tu->refCount++;
+ ReleaseReadLock(&afs_xuser);
+
+ afs_LockUser(tu, READ_LOCK, 0);
+
if (tu->cell == -1) {
cellname = "<default>";
} else {
}
seq_printf(m, "\n");
+ afs_PutUser(tu, READ_LOCK);
+ ObtainReadLock(&afs_xuser);
+
return 0;
}
if (!afs_nfsexporter)
strcpy(bufp, (*sysnamelist)[0]);
else {
- au = afs_GetUser(areq->uid, adp->f.fid.Cell, 0);
+ au = afs_GetUser(areq->uid, adp->f.fid.Cell, READ_LOCK);
if (au->exporter) {
error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
if (error) {
strcpy(bufp, "@sys");
- afs_PutUser(au, 0);
+ afs_PutUser(au, READ_LOCK);
return -1;
} else {
strcpy(bufp, (*sysnamelist)[0]);
}
} else
strcpy(bufp, afs_sysname);
- afs_PutUser(au, 0);
+ afs_PutUser(au, READ_LOCK);
}
return 0;
}
*sysnamelist = afs_sysnamelist;
if (afs_nfsexporter) {
- au = afs_GetUser(areq->uid, avc->f.fid.Cell, 0);
+ au = afs_GetUser(areq->uid, avc->f.fid.Cell, READ_LOCK);
if (au->exporter) {
error =
EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, &num, 0);
if (error) {
- afs_PutUser(au, 0);
+ afs_PutUser(au, READ_LOCK);
return 0;
}
}
- afs_PutUser(au, 0);
+ afs_PutUser(au, READ_LOCK);
}
if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
return 0; /* end of list */
struct tokenJar *tokens;
struct afs_exporter *exporter; /* more info about the exporter for the remote user */
void *cellinfo; /* pointer to cell info (PAG manager only) */
+ afs_rwlock_t lock;
};
#define CVEC_LEN 3 /* per-user connection pool */
}
if (au)
afs_PutUser(au, READ_LOCK);
- au = afs_GetUser(pag, -1, WRITE_LOCK);
+ /* do not get a lock on au; afs_nfsclient_getcreds may write-lock the
+ * same unixuser */
+ au = afs_GetUser(pag, -1, 0);
if (!(au->exporter)) { /* Created new unixuser struct */
np->refCount++; /* so it won't disappear */
au->exporter = (struct afs_exporter *)np;
}
*pagparam = pag;
*outexporter = (struct afs_exporter *)np;
- afs_PutUser(au, WRITE_LOCK);
+ afs_PutUser(au, 0);
/* ReleaseWriteLock(&afs_xnfsreq); */
return 0;
}
ObtainWriteLock(&afs_xuser, 823);
for (tu = afs_users[i]; tu; tu = tu->next) {
if (tu->uid == uid) {
+ tu->refCount++;
+ ReleaseWriteLock(&afs_xuser);
+
+ afs_LockUser(tu, WRITE_LOCK, 368);
+
tu->states &= ~UHasTokens;
tu->viceId = UNDEFVID;
afs_FreeTokens(&tu->tokens);
*/
tu->tokenTime = 0;
#endif /* UKERNEL */
+
+ afs_PutUser(tu, WRITE_LOCK);
+
+ ObtainWriteLock(&afs_xuser, 369);
}
}
ReleaseWriteLock(&afs_xuser);
if (tu->uid == a_uid && tu->cellinfo &&
(tu->states & UHasTokens) && !(tu->states & UTokensBad)) {
+ tu->refCount++;
+ ReleaseWriteLock(&afs_xuser);
+
+ afs_LockUser(tu, READ_LOCK, 0);
+
token = afs_FindToken(tu->tokens, RX_SECIDX_KAD);
tci = &a_creds->CredInfos_val[i];
cellname = ((struct afspag_cell *)(tu->cellinfo))->cellname;
clen = strlen(cellname) + 1;
tci->cellname = afs_osi_Alloc(clen);
- if (!tci->cellname)
+ if (!tci->cellname) {
+ afs_PutUser(tu, READ_LOCK);
+ ObtainWriteLock(&afs_xuser, 370);
goto out;
+ }
memcpy(tci->cellname, cellname, clen);
tci->st.st_len = token->rxkad.ticketLen;
tci->st.st_val = afs_osi_Alloc(token->rxkad.ticketLen);
if (!tci->st.st_val) {
+ afs_PutUser(tu, READ_LOCK);
afs_osi_Free(tci->cellname, clen);
+ ObtainWriteLock(&afs_xuser, 371);
goto out;
}
memcpy(tci->st.st_val,
token->rxkad.ticket, token->rxkad.ticketLen);
if (tu->states & UPrimary)
tci->states |= UPrimary;
+
+ afs_PutUser(tu, READ_LOCK);
+ ObtainWriteLock(&afs_xuser, 372);
}
}
if (tu->uid == areq->uid && (tu->states & UPrimary)) {
tu->refCount++;
ReleaseWriteLock(&afs_xuser);
+ afs_LockUser(tu, READ_LOCK, 0);
break;
}
}
if (tu) {
tcell = afs_GetCell(tu->cell, READ_LOCK);
- afs_PutUser(tu, WRITE_LOCK);
+ afs_PutUser(tu, READ_LOCK);
if (!tcell)
return ESRCH;
else {
tu->refCount++;
}
ReleaseReadLock(&afs_xuser);
+ if (tu) {
+ afs_LockUser(tu, READ_LOCK, 0);
+ }
+
return tu;
}
ObtainWriteLock(&afs_xuser, 227);
for (tu = afs_users[i]; tu; tu = tu->next) {
if (tu->uid == areq->uid) {
- tu->states &= ~UHasTokens;
- afs_FreeTokens(&tu->tokens);
tu->refCount++;
ReleaseWriteLock(&afs_xuser);
+
+ afs_LockUser(tu, WRITE_LOCK, 366);
+
+ tu->states &= ~UHasTokens;
+ afs_FreeTokens(&tu->tokens);
afs_NotifyUser(tu, UTokensDropped);
/* We have to drop the lock over the call to afs_ResetUserConns,
* since it obtains the afs_xvcache lock. We could also keep
* every user conn that existed when we began this call.
*/
afs_ResetUserConns(tu);
- tu->refCount--;
+ afs_PutUser(tu, WRITE_LOCK);
ObtainWriteLock(&afs_xuser, 228);
#ifdef UKERNEL
/* set the expire times to 0, causes
for (i = 0; i < NUSERS; i++) {
for (tu = afs_users[i]; tu; tu = tu->next) {
if (tu->exporter && EXP_CHECKHOST(tu->exporter, addr)) {
- tu->states &= ~UHasTokens;
- afs_FreeTokens(&tu->tokens);
tu->refCount++;
ReleaseWriteLock(&afs_xuser);
+
+ afs_LockUser(tu, WRITE_LOCK, 367);
+
+ tu->states &= ~UHasTokens;
+ afs_FreeTokens(&tu->tokens);
afs_ResetUserConns(tu);
- tu->refCount--;
+ afs_PutUser(tu, WRITE_LOCK);
ObtainWriteLock(&afs_xuser, 228);
#ifdef UKERNEL
/* set the expire times to 0, causes
afs_int32 locktype);
extern struct unixuser *afs_GetUser(afs_int32 auid, afs_int32 acell,
afs_int32 locktype);
+extern void afs_LockUser(struct unixuser *au, afs_int32 locktype,
+ unsigned int src_indicator);
extern void afs_NotifyUser(struct unixuser *auser, int event);
#if AFS_GCPAGS
if (tu->uid == auid && ((tu->cell == acell) || (acell == -1))) {
tu->refCount++;
ReleaseWriteLock(&afs_xuser);
+ afs_LockUser(tu, locktype, 365);
return tu;
}
}
/* Here we setup the real cell for the client */
tu->cell = acell;
tu->refCount++;
- ReleaseWriteLock(&afs_xuser);
- return tu;
+ goto done;
} else if (tu->cell == acell || acell == -1) {
tu->refCount++;
- ReleaseWriteLock(&afs_xuser);
- return tu;
+ goto done;
}
}
}
afs_stats_cmfullperf.authent.PAGCreations++;
#endif /* AFS_NOSTATS */
memset(tu, 0, sizeof(struct unixuser));
+ AFS_RWLOCK_INIT(&tu->lock, "unixuser lock");
tu->next = afs_users[i];
afs_users[i] = tu;
if (RmtUser) {
tu->viceId = UNDEFVID;
tu->refCount = 1;
tu->tokenTime = osi_Time();
+
+ done:
ReleaseWriteLock(&afs_xuser);
+ afs_LockUser(tu, locktype, 364);
return tu;
} /*afs_GetUser */
+void
+afs_LockUser(struct unixuser *au, afs_int32 locktype,
+ unsigned int src_indicator)
+{
+ switch (locktype) {
+ case READ_LOCK:
+ ObtainReadLock(&au->lock);
+ break;
+ case WRITE_LOCK:
+ ObtainWriteLock(&au->lock, src_indicator);
+ break;
+ case SHARED_LOCK:
+ ObtainSharedLock(&au->lock, src_indicator);
+ break;
+ default:
+ /* noop */
+ break;
+ }
+}
void
afs_PutUser(struct unixuser *au, afs_int32 locktype)
{
AFS_STATCNT(afs_PutUser);
+
+ switch (locktype) {
+ case READ_LOCK:
+ ReleaseReadLock(&au->lock);
+ break;
+ case WRITE_LOCK:
+ ReleaseWriteLock(&au->lock);
+ break;
+ case SHARED_LOCK:
+ ReleaseSharedLock(&au->lock);
+ break;
+ default:
+ /* noop */
+ break;
+ }
+
--au->refCount;
} /*afs_PutUser */
for (i = 0; i < NUSERS; i++) {
for (tu = afs_users[i]; tu; tu = tu->next) {
+ if (CheckLock(&tu->lock))
+ afs_warn("user at %p is locked\n", tu);
if (tu->refCount)
afs_warn("user at %lx is held\n", (unsigned long)tu);
}