From 4e55e30f5b2c149b350b6d6875793adf722fdc21 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 13 Feb 2006 17:10:15 +0000 Subject: [PATCH] STABLE14-viced-fix-check-rights-race-20060213 FIXES 25869 acl_CheckRights() was generating core dumps because the client's prlist was being invalidated by h_TossStuff_r() as part of freeing the associated host. This patch fixes the problem in probably redundant ways. A missing hold on the host is now obtained. refCounts on the client are now preserved as part of GetClient()/PutClient(). Read/Write locks are now obtained on the client when accessing/manipulating the prlist. This patch adds the client parameter to GetVolumePackage() and PutVolumePackage() and adds the new function PutClient(). This patch removes the need for the client X had conn Y stolen by X messages. This is replaced by "deleted client X already had conn Y stolen by X. If we see this there is definitely a logic problem as the client should not be deleted at this point. We a no longer allowing the race condition that would have resulted in the original message. In addition, this patch fixes a problem with UAEs caused by the inappropriate translation of VICE error into UAEs when there is overlap between VICE error values and those in sys/errno.h. (cherry picked from commit 6c7a2901b00ae2f7df0bdff23b19fdd3b7f35156) --- src/viced/afsfileprocs.c | 172 ++++++++++++++++++++++++--------------- src/viced/host.c | 114 +++++++++++++++++++------- src/viced/host.h | 2 + 3 files changed, 194 insertions(+), 94 deletions(-) diff --git a/src/viced/afsfileprocs.c b/src/viced/afsfileprocs.c index bd73fe7d3..ebddafa0c 100644 --- a/src/viced/afsfileprocs.c +++ b/src/viced/afsfileprocs.c @@ -575,6 +575,32 @@ SetAccessList(Vnode ** targetptr, Volume ** volume, } /*SetAccessList */ +/* Must not be called with H_LOCK held */ +static void +client_CheckRights(struct client *client, struct acl_accessList *ACL, + afs_int32 *rights) +{ + *rights = 0; + ObtainReadLock(&client->lock); + if (client->CPS.prlist_len > 0 && !client->deleted && + client->host && !(client->host->hostFlags & HOSTDELETED)) + acl_CheckRights(ACL, &client->CPS, rights); + ReleaseReadLock(&client->lock); +} + +/* Must not be called with H_LOCK held */ +static afs_int32 +client_HasAsMember(struct client *client, afs_int32 id) +{ + afs_int32 code = 0; + + ObtainReadLock(&client->lock); + if (client->CPS.prlist_len > 0 && !client->deleted && + client->host && !(client->host->hostFlags & HOSTDELETED)) + ReleaseReadLock(&client->lock); + return code; +} + /* * Compare the directory's ACL with the user's access rights in the client * connection and return the user's and everybody else's access permissions @@ -591,15 +617,12 @@ GetRights(struct client *client, struct acl_accessList *ACL, #endif if (acl_CheckRights(ACL, &SystemAnyUserCPS, anyrights) != 0) { - ViceLog(0, ("CheckRights failed\n")); *anyrights = 0; } *rights = 0; - ObtainWriteLock(&client->lock); - acl_CheckRights(ACL, &client->CPS, rights); - ReleaseWriteLock(&client->lock); + client_CheckRights(client, ACL, rights); /* wait if somebody else is already doing the getCPS call */ H_LOCK; @@ -622,8 +645,9 @@ GetRights(struct client *client, struct acl_accessList *ACL, acl_CheckRights(ACL, &client->host->hcps, &hrights); H_UNLOCK; /* Allow system:admin the rights given with the -implicit option */ - if (acl_IsAMember(SystemId, &client->CPS)) + if (client_HasAsMember(client, SystemId)) *rights |= implicitAdminRights; + *rights |= hrights; *anyrights |= hrights; @@ -638,7 +662,7 @@ GetRights(struct client *client, struct acl_accessList *ACL, static afs_int32 VanillaUser(struct client *client) { - if (acl_IsAMember(SystemId, &client->CPS)) + if (client_HasAsMember(client, SystemId)) return (0); /* not a system administrator, then you're "vanilla" */ return (1); @@ -677,11 +701,13 @@ GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr, return (errorCode); if (chkforDir == MustBeDIR) assert((*parent) == 0); - if ((errorCode = GetClient(tcon, client)) != 0) - return (errorCode); - if (!(*client)) - return (EINVAL); - assert(GetRights(*client, aCL, rights, anyrights) == 0); + if (!(*client)) { + if ((errorCode = GetClient(tcon, client)) != 0) + return (errorCode); + if (!(*client)) + return (EINVAL); + } + GetRights(*client, aCL, rights, anyrights); /* ok, if this is not a dir, set the PRSFS_ADMINISTER bit iff we're the owner */ if ((*targetptr)->disk.type != vDirectory) { /* anyuser can't be owner, so only have to worry about rights, not anyrights */ @@ -706,7 +732,7 @@ GetVolumePackage(struct rx_connection *tcon, AFSFid * Fid, Volume ** volptr, */ static void PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr, - Vnode * parentptr, Volume * volptr) + Vnode * parentptr, Volume * volptr, struct client **client) { int fileCode = 0; /* Error code returned by the volume package */ @@ -725,6 +751,9 @@ PutVolumePackage(Vnode * parentwhentargetnotdir, Vnode * targetptr, if (volptr) { VPutVolume(volptr); } + if (*client) { + PutClient(client); + } } /*PutVolumePackage */ static int @@ -739,7 +768,7 @@ VolumeOwner(register struct client *client, register Vnode * targetptr) * We don't have to check for host's cps since only regular * viceid are volume owners. */ - return (acl_IsAMember(owner, &client->CPS)); + return (client_HasAsMember(client, owner)); } } /*VolumeOwner */ @@ -793,7 +822,7 @@ Check_PermissionRights(Vnode * targetptr, struct client *client, && targetptr->disk.type == vFile) #ifdef USE_GROUP_PERMS if (!OWNSp(client, targetptr) - && !acl_IsAMember(targetptr->disk.owner, &client->CPS)) { + && !client_HasAsMember(client, targetptr->disk.owner)) { errorCode = (((GROUPREAD | GROUPEXEC) & targetptr->disk.modeBits) ? 0 : EACCES); @@ -897,8 +926,7 @@ Check_PermissionRights(Vnode * targetptr, struct client *client, if ((targetptr->disk.type == vFile) && VanillaUser(client)) { if (!OWNSp(client, targetptr) - && !acl_IsAMember(targetptr->disk.owner, - &client->CPS)) { + && !client_HasAsMember(client, targetptr->disk.owner)) { errorCode = ((GROUPWRITE & targetptr->disk.modeBits) ? 0 : EACCES); @@ -2080,7 +2108,7 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid, int errorCode = 0; /* return code to caller */ int fileCode = 0; /* return code from vol package */ Volume *volptr = 0; /* pointer to the volume */ - struct client *client; /* pointer to the client data */ + struct client *client = 0; /* pointer to the client data */ struct rx_connection *tcon; /* the connection we're part of */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client = NULL; /* tmp ptr to client data */ @@ -2268,7 +2296,7 @@ common_FetchData64(struct rx_call *acall, struct AFSFid *Fid, Bad_FetchData: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); ViceLog(2, ("SRXAFS_FetchData returns %d\n", errorCode)); errorCode = CallPostamble(tcon, errorCode); @@ -2343,7 +2371,7 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid, Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */ int errorCode = 0; /* return error code to caller */ Volume *volptr = 0; /* pointer to the volume */ - struct client *client; /* pointer to the client data */ + struct client *client = 0; /* pointer to the client data */ afs_int32 rights, anyrights; /* rights for this and any user */ struct rx_connection *tcon = rx_ConnectionOf(acall); struct client *t_client = NULL; /* tmp ptr to client data */ @@ -2417,7 +2445,7 @@ SRXAFS_FetchACL(struct rx_call * acall, struct AFSFid * Fid, Bad_FetchACL: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); ViceLog(2, ("SAFS_FetchACL returns %d (ACL=%s)\n", errorCode, AccessList->AFSOpaque_val)); @@ -2463,7 +2491,7 @@ SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid, Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */ int errorCode = 0; /* return code to caller */ Volume *volptr = 0; /* pointer to the volume */ - struct client *client; /* pointer to the client data */ + struct client *client = 0; /* pointer to the client data */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client = NULL; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -2520,7 +2548,7 @@ SAFSS_FetchStatus(struct rx_call *acall, struct AFSFid *Fid, Bad_FetchStatus: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); ViceLog(2, ("SAFS_FetchStatus returns %d\n", errorCode)); return errorCode; @@ -2538,7 +2566,7 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids, Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */ int errorCode = 0; /* return code to caller */ Volume *volptr = 0; /* pointer to the volume */ - struct client *client; /* pointer to the client data */ + struct client *client = 0; /* pointer to the client data */ afs_int32 rights, anyrights; /* rights for this and any user */ register struct AFSFid *tfid; /* file id we're dealing with now */ struct rx_connection *tcon = rx_ConnectionOf(acall); @@ -2632,16 +2660,17 @@ SRXAFS_BulkStatus(struct rx_call * acall, struct AFSCBFids * Fids, /* put back the file ID and volume */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); parentwhentargetnotdir = (Vnode *) 0; targetptr = (Vnode *) 0; volptr = (Volume *) 0; + client = (struct client *)0; } Bad_BulkStatus: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); errorCode = CallPostamble(tcon, errorCode); t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key); @@ -2685,7 +2714,7 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids, Vnode *parentwhentargetnotdir = 0; /* parent vnode if targetptr is a file */ int errorCode = 0; /* return code to caller */ Volume *volptr = 0; /* pointer to the volume */ - struct client *client; /* pointer to the client data */ + struct client *client = 0; /* pointer to the client data */ afs_int32 rights, anyrights; /* rights for this and any user */ register struct AFSFid *tfid; /* file id we're dealing with now */ struct rx_connection *tcon; @@ -2749,10 +2778,12 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids, &rights, &anyrights))) { tstatus = &OutStats->AFSBulkStats_val[i]; tstatus->errorCode = errorCode; - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, + volptr, &client); parentwhentargetnotdir = (Vnode *) 0; targetptr = (Vnode *) 0; volptr = (Volume *) 0; + client = (struct client *)0; continue; } @@ -2768,10 +2799,11 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids, tstatus = &OutStats->AFSBulkStats_val[i]; tstatus->errorCode = errorCode; (void)PutVolumePackage(parentwhentargetnotdir, targetptr, - (Vnode *) 0, volptr); + (Vnode *) 0, volptr, &client); parentwhentargetnotdir = (Vnode *) 0; targetptr = (Vnode *) 0; volptr = (Volume *) 0; + client = (struct client *)0; continue; } } @@ -2795,16 +2827,17 @@ SRXAFS_InlineBulkStatus(struct rx_call * acall, struct AFSCBFids * Fids, /* put back the file ID and volume */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); parentwhentargetnotdir = (Vnode *) 0; targetptr = (Vnode *) 0; volptr = (Volume *) 0; + client = (struct client *)0; } Bad_InlineBulkStatus: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); errorCode = CallPostamble(tcon, errorCode); t_client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key); @@ -2909,7 +2942,7 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid, int errorCode = 0; /* return code for caller */ int fileCode = 0; /* return code from vol package */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client = NULL; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -3088,7 +3121,7 @@ common_StoreData64(struct rx_call *acall, struct AFSFid *Fid, Bad_StoreData: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); ViceLog(2, ("SAFS_StoreData returns %d\n", errorCode)); errorCode = CallPostamble(tcon, errorCode); @@ -3170,7 +3203,7 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid, int errorCode = 0; /* return code for caller */ struct AFSStoreStatus InStatus; /* Input status for fid */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct rx_connection *tcon; struct client *t_client = NULL; /* tmp ptr to client data */ @@ -3245,7 +3278,8 @@ SRXAFS_StoreACL(struct rx_call * acall, struct AFSFid * Fid, Bad_StoreACL: /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, + volptr, &client); ViceLog(2, ("SAFS_StoreACL returns %d\n", errorCode)); errorCode = CallPostamble(tcon, errorCode); @@ -3288,7 +3322,7 @@ SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid, Vnode *parentwhentargetnotdir = 0; /* parent of Fid to get ACL */ int errorCode = 0; /* return code for caller */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client = NULL; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -3351,7 +3385,8 @@ SAFSS_StoreStatus(struct rx_call *acall, struct AFSFid *Fid, Bad_StoreStatus: /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, + volptr, &client); ViceLog(2, ("SAFS_StoreStatus returns %d\n", errorCode)); return errorCode; @@ -3434,7 +3469,7 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name, AFSFid fileFid; /* area for Fid from the directory */ int errorCode = 0; /* error code */ DirHandle dir; /* Handle for dir package I/O */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -3512,7 +3547,8 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Bad_RemoveFile: /* Update and store volume/vnode and parent vnodes back */ - PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, volptr); + PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, + volptr, &client); FidZap(&dir); ViceLog(2, ("SAFS_RemoveFile returns %d\n", errorCode)); return errorCode; @@ -3597,7 +3633,7 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Volume *volptr = 0; /* pointer to the volume header */ int errorCode = 0; /* error code */ DirHandle dir; /* Handle for dir package I/O */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -3676,7 +3712,7 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Bad_CreateFile: /* Update and store volume/vnode and parent vnodes back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, - volptr); + volptr, &client); FidZap(&dir); ViceLog(2, ("SAFS_CreateFile returns %d\n", errorCode)); return errorCode; @@ -3776,7 +3812,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName, DirHandle filedir; /* Handle for dir package I/O */ DirHandle newfiledir; /* Handle for dir package I/O */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ afs_int32 newrights; /* rights for this user */ afs_int32 newanyrights; /* rights for any user */ @@ -4161,10 +4197,8 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName, VPutVnode(&fileCode, newfileptr); assert(fileCode == 0); } - (void)PutVolumePackage(fileptr, - (newvptr - && newvptr != oldvptr ? newvptr : 0), oldvptr, - volptr); + (void)PutVolumePackage(fileptr, (newvptr && newvptr != oldvptr ? + newvptr : 0), oldvptr, volptr, &client); FidZap(&olddir); FidZap(&newdir); FidZap(&filedir); @@ -4257,7 +4291,7 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name, int len, code = 0; DirHandle dir; /* Handle for dir package I/O */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -4366,7 +4400,7 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Bad_SymLink: /* Write the all modified vnodes (parent, new files) and volume back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, - volptr); + volptr, &client); FidZap(&dir); ViceLog(2, ("SAFS_Symlink returns %d\n", errorCode)); return ( errorCode ? errorCode : code ); @@ -4461,7 +4495,7 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Volume *volptr = 0; /* pointer to the volume header */ int errorCode = 0; /* error code */ DirHandle dir; /* Handle for dir package I/O */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -4575,7 +4609,7 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Bad_Link: /* Write the all modified vnodes (parent, new files) and volume back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, - volptr); + volptr, &client); FidZap(&dir); ViceLog(2, ("SAFS_Link returns %d\n", errorCode)); return errorCode; @@ -4666,7 +4700,7 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name, int newACLSize; /* Size of access list */ DirHandle dir; /* Handle for dir package I/O */ DirHandle parentdir; /* Handle for dir package I/O */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -4772,7 +4806,7 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Bad_MakeDir: /* Write the all modified vnodes (parent, new files) and volume back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, - volptr); + volptr, &client); FidZap(&dir); FidZap(&parentdir); ViceLog(2, ("SAFS_MakeDir returns %d\n", errorCode)); @@ -4860,7 +4894,7 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name, int errorCode = 0; /* error code */ DirHandle dir; /* Handle for dir package I/O */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ Vnode debugvnode1, debugvnode2; struct client *t_client; /* tmp ptr to client data */ @@ -4937,7 +4971,7 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name, Bad_RemoveDir: /* Write the all modified vnodes (parent, new files) and volume back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, parentptr, - volptr); + volptr, &client); FidZap(&dir); ViceLog(2, ("SAFS_RemoveDir returns %d\n", errorCode)); return errorCode; @@ -5017,7 +5051,7 @@ SAFSS_SetLock(struct rx_call *acall, struct AFSFid *Fid, ViceLockType type, Vnode *parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ int errorCode = 0; /* error code */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -5058,7 +5092,7 @@ SAFSS_SetLock(struct rx_call *acall, struct AFSFid *Fid, ViceLockType type, Bad_SetLock: /* Write the all modified vnodes (parent, new files) and volume back */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); if ((errorCode == VREADONLY) && (type == LockRead)) errorCode = 0; /* allow read locks on RO volumes without saving state */ @@ -5147,7 +5181,7 @@ SAFSS_ExtendLock(struct rx_call *acall, struct AFSFid *Fid, Vnode *parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ int errorCode = 0; /* error code */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -5183,7 +5217,7 @@ SAFSS_ExtendLock(struct rx_call *acall, struct AFSFid *Fid, Bad_ExtendLock: /* Put back file's vnode and volume */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */ errorCode = 0; /* under our generous policy re RO vols */ @@ -5273,7 +5307,7 @@ SAFSS_ReleaseLock(struct rx_call *acall, struct AFSFid *Fid, Vnode *parentwhentargetnotdir = 0; /* parent for use in SetAccessList */ int errorCode = 0; /* error code */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client structure */ + struct client *client = 0; /* pointer to client structure */ afs_int32 rights, anyrights; /* rights for this and any user */ struct client *t_client; /* tmp ptr to client data */ struct in_addr logHostAddr; /* host ip holder for inet_ntoa */ @@ -5318,7 +5352,7 @@ SAFSS_ReleaseLock(struct rx_call *acall, struct AFSFid *Fid, Bad_ReleaseLock: /* Put back file's vnode and volume */ (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); if ((errorCode == VREADONLY)) /* presumably, we already granted this lock */ errorCode = 0; /* under our generous policy re RO vols */ @@ -5917,7 +5951,7 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray, { afs_int32 errorCode = 0; register int i; - struct client *client; + struct client *client = 0; struct rx_connection *tcon; #if FS_STATS_DETAILED struct fs_stats_opTimingData *opP; /* Ptr to this op's timing struct */ @@ -5952,8 +5986,10 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray, ("SAFS_GiveUpAllCallBacks: host=%x\n", (tcon->peer ? tcon->peer->host : 0))); errorCode = GetClient(tcon, &client); - if (!errorCode) + if (!errorCode) { DeleteAllCallBacks_r(client->host, 1); + PutClient(&client); + } } else { if (FidArray->AFSCBFids_len < CallBackArray->AFSCBs_len) { ViceLog(0, @@ -5970,6 +6006,7 @@ common_GiveUpCallBacks(struct rx_call *acall, struct AFSCBFids *FidArray, register struct AFSFid *fid = &(FidArray->AFSCBFids_val[i]); DeleteCallBack(client->host, fid); } + PutClient(&client); } } @@ -6107,7 +6144,7 @@ SRXAFS_FlushCPS(struct rx_call * acall, struct ViceIds * vids, afs_int32 nids, naddrs; afs_int32 *vd, *addr; int errorCode = 0; /* return code to caller */ - struct client *client; + struct client *client = 0; struct rx_connection *tcon = rx_ConnectionOf(acall); ViceLog(1, ("SRXAFS_FlushCPS\n")); @@ -6346,7 +6383,7 @@ SRXAFS_GetVolumeStatus(struct rx_call * acall, afs_int32 avolid, Vnode *parentwhentargetnotdir = 0; /* vnode of parent */ int errorCode = 0; /* error code */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client entry */ + struct client *client = 0; /* pointer to client entry */ afs_int32 rights, anyrights; /* rights for this and any user */ AFSFid dummyFid; struct rx_connection *tcon; @@ -6396,7 +6433,7 @@ SRXAFS_GetVolumeStatus(struct rx_call * acall, afs_int32 avolid, Bad_GetVolumeStatus: (void)PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, - volptr); + volptr, &client); ViceLog(2, ("SAFS_GetVolumeStatus returns %d\n", errorCode)); /* next is to guarantee out strings exist for stub */ if (*Name == 0) { @@ -6450,7 +6487,7 @@ SRXAFS_SetVolumeStatus(struct rx_call * acall, afs_int32 avolid, Vnode *parentwhentargetnotdir = 0; /* vnode of parent */ int errorCode = 0; /* error code */ Volume *volptr = 0; /* pointer to the volume header */ - struct client *client; /* pointer to client entry */ + struct client *client = 0; /* pointer to client entry */ afs_int32 rights, anyrights; /* rights for this and any user */ AFSFid dummyFid; struct rx_connection *tcon = rx_ConnectionOf(acall); @@ -6505,7 +6542,8 @@ SRXAFS_SetVolumeStatus(struct rx_call * acall, afs_int32 avolid, RXUpdate_VolumeStatus(volptr, StoreVolStatus, Name, OfflineMsg, Motd); Bad_SetVolumeStatus: - PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, volptr); + PutVolumePackage(parentwhentargetnotdir, targetptr, (Vnode *) 0, + volptr, &client); ViceLog(2, ("SAFS_SetVolumeStatus returns %d\n", errorCode)); errorCode = CallPostamble(tcon, errorCode); @@ -7452,6 +7490,8 @@ sys_error_to_et(afs_int32 in) return 0; if (in < 0 || in > 511) return in; + if (in >= VICE_SPECIAL_ERRORS && in <= VIO || in == VRESTRICTED) + return in; if (sys2et[in] != 0) return sys2et[in]; return in; diff --git a/src/viced/host.c b/src/viced/host.c index 352344934..0dd0311e2 100644 --- a/src/viced/host.c +++ b/src/viced/host.c @@ -88,6 +88,7 @@ struct CEBlock { /* block of CESPERBLOCK file entries */ }; static void h_TossStuff_r(register struct host *host); +static int hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *host); /* * Make sure the subnet macros have been defined. @@ -710,15 +711,18 @@ h_TossStuff_r(register struct host *host) if (client->refCount) { char hoststr[16]; ViceLog(0, - ("Warning: Host %s:%d client %x refcount %d while deleting.\n", + ("Warning: Host %s:%d client %x refcount %d while deleting, failing.\n", afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port), client, client->refCount)); + /* This is the same thing we do if the host is locked */ + return; } + /* We can't protect this without dropping the H_LOCK */ + client->CPS.prlist_len = 0; if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) { free(client->CPS.prlist_val); client->CPS.prlist_val = NULL; } - client->CPS.prlist_len = 0; if (client->tcon) { rx_SetSpecific(client->tcon, rxcon_client_key, (void *)0); } @@ -1308,11 +1312,15 @@ h_GetHost_r(struct rx_connection *tcon) afsUUID uuid = oldHost->interface->uuid; cb_conn = oldHost->callback_rxcon; rx_GetConnection(cb_conn); + rx_SetConnDeadTime(cb_conn, 2); + rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME); H_UNLOCK; code = RXAFSCB_ProbeUuid(cb_conn, &uuid); + H_LOCK; + rx_SetConnDeadTime(cb_conn, 50); + rx_SetConnHardDeadTime(cb_conn, AFS_HARDDEADTIME); rx_PutConnection(cb_conn); cb_conn=NULL; - H_LOCK; if (code && MultiProbeAlternateAddress_r(oldHost)) { probefail = 1; } @@ -1339,12 +1347,12 @@ h_GetHost_r(struct rx_connection *tcon) * the list of interfaces for the existing host and * delete the host structure we just allocated. */ if (oldHost->host != haddr || oldHost->port != hport) { - ViceLog(25, - ("CB: new addr %s:%d for old host %s:%d\n", - afs_inet_ntoa_r(host->host, hoststr), - ntohs(host->port), - afs_inet_ntoa_r(oldHost->host, hoststr2), - ntohs(oldHost->port))); + ViceLog(25, + ("CB: new addr %s:%d for old host %s:%d\n", + afs_inet_ntoa_r(haddr, hoststr), + ntohs(hport), + afs_inet_ntoa_r(oldHost->host, hoststr2), + ntohs(oldHost->port))); if (oldHost->host == haddr) { /* We have just been contacted by a client behind a NAT */ removeInterfaceAddr_r(oldHost, oldHost->host, oldHost->port); @@ -1366,7 +1374,7 @@ h_GetHost_r(struct rx_connection *tcon) removeInterfaceAddr_r(oldHost, haddr, interface->interface[i].port); } } - addInterfaceAddr_r(oldHost, haddr, hport); + addInterfaceAddr_r(oldHost, haddr, hport); oldHost->host = haddr; oldHost->port = hport; } @@ -1578,12 +1586,14 @@ h_FindClient_r(struct rx_connection *tcon) char uname[PR_MAXNAMELEN]; char tcell[MAXKTCREALMLEN]; int fail = 0; + int created = 0; client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key); - if (client && !client->deleted) { + if (client) { client->refCount++; h_Hold_r(client->host); - if (client->prfail != 2) { /* Could add shared lock on client here */ + if (!client->deleted && client->prfail != 2) { + /* Could add shared lock on client here */ /* note that we don't have to lock entry in this path to * ensure CPS is initialized, since we don't call rx_SetSpecific * until initialization is done, and we only get here if @@ -1594,8 +1604,6 @@ h_FindClient_r(struct rx_connection *tcon) H_UNLOCK; ObtainWriteLock(&client->lock); /* released at end */ H_LOCK; - } else if (client) { - client->refCount++; } authClass = rx_SecurityClassOf((struct rx_connection *)tcon); @@ -1646,7 +1654,7 @@ h_FindClient_r(struct rx_connection *tcon) expTime = 0x7fffffff; } - if (!client) { + if (!client) { /* loop */ host = h_GetHost_r(tcon); /* Returns it h_Held */ retryfirstclient: @@ -1692,12 +1700,11 @@ h_FindClient_r(struct rx_connection *tcon) goto retryfirstclient; } } + created = 1; client = GetCE(); ObtainWriteLock(&client->lock); client->refCount = 1; client->host = host; - client->next = host->FirstClient; - host->FirstClient = client; #if FS_STATS_DETAILED client->InSameNetwork = host->InSameNetwork; #endif /* FS_STATS_DETAILED */ @@ -1709,7 +1716,6 @@ h_FindClient_r(struct rx_connection *tcon) client->CPS.prlist_val = 0; client->CPS.prlist_len = 0; h_Unlock_r(host); - CurrentConnections++; /* increment number of connections */ } } client->prfail = fail; @@ -1770,13 +1776,50 @@ h_FindClient_r(struct rx_connection *tcon) oldClient = (struct client *)rx_GetSpecific(tcon, rxcon_client_key); if (oldClient && oldClient->tcon == tcon) { char hoststr[16]; - oldClient->tcon = (struct rx_connection *)0; - ViceLog(0, ("FindClient: client %x(%x) already had conn %x (host %s:%d), stolen by client %x(%x)\n", - oldClient, oldClient->sid, tcon, - afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr), - ntohs(rxr_PortOf(tcon)), - client, client->sid)); - /* rx_SetSpecific will be done immediately below */ + if (!oldClient->deleted) { + /* if we didn't create it, it's not ours to put back */ + if (created) { + ViceLog(0, ("FindClient: stillborn client %x(%x); conn %x (host %s:%d) had client %x(%x)\n", + client, client->sid, tcon, + afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr), + ntohs(rxr_PortOf(tcon)), + oldClient, oldClient->sid)); + if ((client->ViceId != ANONYMOUSID) && client->CPS.prlist_val) { + free(client->CPS.prlist_val); + client->CPS.prlist_val = NULL; + } + client->CPS.prlist_len = 0; + if (client->tcon) { + rx_SetSpecific(client->tcon, rxcon_client_key, (void *)0); + } + } + /* We should perhaps check for 0 here */ + client->refCount--; + ReleaseWriteLock(&client->lock); + if (created) { + FreeCE(client); + created = 0; + } + ObtainWriteLock(&oldClient->lock); + oldClient->refCount++; + client = oldClient; + } else { + oldClient->tcon = (struct rx_connection *)0; + ViceLog(0, ("FindClient: deleted client %x(%x) already had conn %x (host %s:%d), stolen by client %x(%x)\n", + oldClient, oldClient->sid, tcon, + afs_inet_ntoa_r(rxr_HostOf(tcon), hoststr), + ntohs(rxr_PortOf(tcon)), + client, client->sid)); + /* rx_SetSpecific will be done immediately below */ + } + } + /* Avoid chaining in more than once. */ + if (created) { + h_Lock_r(host); + client->next = host->FirstClient; + host->FirstClient = client; + h_Unlock_r(host); + CurrentConnections++; /* increment number of connections */ } client->tcon = tcon; rx_SetSpecific(tcon, rxcon_client_key, client); @@ -1808,7 +1851,8 @@ GetClient(struct rx_connection *tcon, struct client **cp) register struct client *client; H_LOCK; - *cp = client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key); + *cp = NULL; + client = (struct client *)rx_GetSpecific(tcon, rxcon_client_key); if (client == NULL || client->tcon == NULL) { ViceLog(0, ("GetClient: no client in conn %x (host %x:%d), VBUSYING\n", @@ -1843,11 +1887,25 @@ GetClient(struct rx_connection *tcon, struct client **cp) return VICETOKENDEAD; } + client->refCount++; + *cp = client; H_UNLOCK; return 0; - } /*GetClient */ +int +PutClient(struct client **cp) +{ + if (*cp == NULL) + return -1; + + H_LOCK; + h_ReleaseClient_r(*cp); + *cp = NULL; + H_UNLOCK; + return 0; +} /*PutClient */ + /* Client user name for short term use. Note that this is NOT inexpensive */ char * @@ -2491,7 +2549,7 @@ initInterfaceAddr_r(struct host *host, struct interfaceAddr *interf) /* deleted a HashChain structure for this address and host */ /* returns 1 on success */ -int +static int hashDelete_r(afs_uint32 addr, afs_uint16 port, struct host *host) { int flag; diff --git a/src/viced/host.h b/src/viced/host.h index 7fe5ab1e1..73ee45be9 100644 --- a/src/viced/host.h +++ b/src/viced/host.h @@ -197,6 +197,7 @@ extern int h_Lock_r(register struct host *host); (h)->prev ? ((h)->prev->next = (h)->next):0;\ ( h == hostList )? (hostList = h->next):0; +extern int DeleteAllCallBacks_r(struct host *host, int deletefe); extern struct host *h_Alloc(register struct rx_connection *r_con); extern struct host *h_Alloc_r(register struct rx_connection *r_con); extern struct host *h_Lookup_r(afs_uint32 hostaddr, afs_uint32 hport, @@ -209,6 +210,7 @@ extern struct client *h_FindClient_r(struct rx_connection *tcon); extern int h_ReleaseClient_r(struct client *client); extern struct client *h_ID2Client(afs_int32 vid); extern int GetClient(struct rx_connection *tcon, struct client **cp); +extern int PutClient(struct client **cp); extern void h_PrintStats(); extern void h_PrintClients(); extern void h_GetWorkStats(); -- 2.39.5